Xây dựng Hệ thống điểm danh tự động bằng khuôn mặt (Face Recognition)

AI Hunter

Member
Chấm công bằng vân tay đã xưa rồi, đặc biệt là trong thời đại cần hạn chế tiếp xúc. Trong bài viết này, chúng ta sẽ xây dựng một hệ thống điểm danh "không chạm" (touchless) thông minh bằng Python:
  • Nhận diện khuôn mặt nhân viên qua Webcam.
  • Tự động ghi giờ check-in vào file Excel/CSV.
  • Đặc biệt: Máy tính sẽ chào tên nhân viên bằng giọng nói (như trong phim khoa học viễn tưởng).
Xây dựng Hệ thống điểm danh tự động bằng khuôn mặt (Face Recognition).jpg

1. Cài đặt môi trường (Quan trọng)​


Đây là bước "khó nhằn" nhất vì thư viện nhận diện khuôn mặt cần trình biên dịch C++. Hãy làm đúng thứ tự sau:

Bước 1: Cài đặt CMake (Bắt buộc để cài dlib).
Mã:
pip install cmake

Bước 2: Cài đặt các thư viện chính.
Mã:
pip install dlib face_recognition opencv-python pandas pyttsx3

2. Chuẩn bị dữ liệu​


Bạn hãy tạo một thư mục tên là images cùng cấp với file code.
Trong đó, hãy bỏ ảnh thẻ của những người cần điểm danh vào. Tên file chính là tên hiển thị.
Ví dụ:
  • `images/Elon_Musk.jpg`
  • `images/Son_Tung_MTP.jpg`

3. Triển khai Code (Full Source)​


Dưới đây là đoạn code Python hoàn chỉnh. Tôi đã thêm logic để tránh việc máy chấm công liên tục (Spam) và module giọng nói.

Python:
import cv2
import face_recognition
import os
import datetime
import pyttsx3
import pandas as pd

# --- CẤU HÌNH ---
path = 'images'         # Thư mục chứa ảnh mẫu
attendance_file = 'diem_danh.csv'

# Khởi tạo giọng nói
engine = pyttsx3.init()
engine.setProperty('rate', 150) # Tốc độ nói

def speak(text):
    """Máy phát âm thanh"""
    engine.say(text)
    engine.runAndWait()

def load_images(path):
    """Load ảnh và mã hóa khuôn mặt từ thư mục"""
    images = []
    classNames = []
    myList = os.listdir(path)
    print(f"📂 Đang load dữ liệu từ {path}...")
   
    for cl in myList:
        curImg = cv2.imread(f'{path}/{cl}')
        images.append(curImg)
        classNames.append(os.path.splitext(cl)[0]) # Lấy tên file bỏ đuôi .jpg
   
    encoded_list = []
    for img in images:
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # Mã hóa khuôn mặt (chuyển thành vector)
        try:
            encode = face_recognition.face_encodings(img)[0]
            encoded_list.append(encode)
        except IndexError:
            print(f"⚠️ Không tìm thấy mặt trong ảnh: {path}/{cl}")
           
    print(f"✅ Đã học xong {len(encoded_list)} khuôn mặt.")
    return encoded_list, classNames

def mark_attendance(name):
    """Ghi log vào file CSV"""
    # Nếu file chưa tồn tại thì tạo mới
    if not os.path.isfile(attendance_file):
        with open(attendance_file, 'w') as f:
            f.writelines('Name,Time,Date')

    # Đọc dữ liệu cũ để tránh trùng lặp trong cùng 1 ngày (hoặc phiên)
    with open(attendance_file, 'r+') as f:
        myDataList = f.readlines()
        nameList = []
        for line in myDataList:
            entry = line.split(',')
            nameList.append(entry[0])
           
        # Nếu chưa điểm danh thì ghi vào
        if name not in nameList:
            now = datetime.datetime.now()
            dtString = now.strftime('%H:%M:%S')
            dateString = now.strftime('%d/%m/%Y')
            f.writelines(f'\n{name},{dtString},{dateString}')
            print(f"✅ Đã điểm danh: {name}")
            speak(f"Xin chào {name}, chúc bạn một ngày tốt lành!")
            return True # Đánh dấu là mới điểm danh
    return False # Đã điểm danh rồi

# --- MAIN PROGRAM ---
encodeListKnown, classNames = load_images(path)
print("📷 Đang khởi động Webcam...")

cap = cv2.VideoCapture(0) # 0 là ID của Webcam

while True:
    success, img = cap.read()
    if not success:
        print("Không mở được Camera")
        break

    # Thu nhỏ ảnh còn 1/4 để xử lý nhanh hơn (Tăng FPS)
    imgS = cv2.resize(img, (0, 0), None, 0.25, 0.25)
    imgS = cv2.cvtColor(imgS, cv2.COLOR_BGR2RGB)

    # Tìm vị trí khuôn mặt trong khung hình hiện tại
    facesCurFrame = face_recognition.face_locations(imgS)
    encodesCurFrame = face_recognition.face_encodings(imgS, facesCurFrame)

    # So sánh từng khuôn mặt tìm thấy với dữ liệu đã học
    for encodeFace, faceLoc in zip(encodesCurFrame, facesCurFrame):
        matches = face_recognition.compare_faces(encodeListKnown, encodeFace, tolerance=0.5)
        faceDis = face_recognition.face_distance(encodeListKnown, encodeFace)
       
        # Lấy index của khuôn mặt giống nhất
        import numpy as np
        matchIndex = np.argmin(faceDis)

        if matches[matchIndex]:
            name = classNames[matchIndex].upper()
           
            # Vẽ khung hình chữ nhật quanh mặt
            y1, x2, y2, x1 = faceLoc
            y1, x2, y2, x1 = y1 * 4, x2 * 4, y2 * 4, x1 * 4 # Nhân 4 vì lúc nãy resize 0.25
            cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
            cv2.rectangle(img, (x1, y2 - 35), (x2, y2), (0, 255, 0), cv2.FILLED)
            cv2.putText(img, name, (x1 + 6, y2 - 6), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255), 2)
           
            # Thực hiện điểm danh & Chào
            mark_attendance(name)

    cv2.imshow('Webcam - Face Recognition', img)
   
    # Nhấn 'q' để thoát
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

4. Giải thích cơ chế​


  • Face Encoding: Máy tính sẽ đo đạc các tỉ lệ trên khuôn mặt (khoảng cách mắt, mũi, miệng...) và biến nó thành một chuỗi 128 con số.
  • Tolerance (Độ dung sai): Trong dòng code compare_faces(..., tolerance=0.5), số 0.5 là độ chính xác. Số càng nhỏ càng khắt khe, số càng lớn càng dễ nhận diện nhầm.
  • Resize 0.25: Mẹo nhỏ này giúp FPS của Camera mượt mà hơn, vì xử lý ảnh nhỏ tốn ít tài nguyên CPU hơn.

5. Kết quả​


Sau khi chạy chương trình:
1. Webcam bật lên.
2. Bạn đưa mặt vào, máy vẽ khung xanh và hiện tên.
3. Loa phát ra: "Xin chào Elon Musk...".
4. File diem_danh.csv xuất hiện dữ liệu chấm công.

Đây là nền tảng tuyệt vời để bạn phát triển thêm các tính năng như: Mở cửa tự động (kết nối Arduino), Gửi báo cáo về Telegram, v.v.
 
Back
Top