1 Giới thiệu
Hôm nay, chúng ta sẽ cùng tìm hiểu một dự án tốt nghiệp liên quan đến thị giác máy tính, cụ thể là Hệ thống phát hiện sự tập trung trong lớp học trực tuyến.
Hiệu quả hoạt động của dự án:
Dự án tốt nghiệp: Hệ thống phát hiện sự tập trung trong lớp học trực tuyến
Chia sẻ dự án: Xem phần cuối bài viết!
2 Các công nghệ liên quan
2.1 Giới thiệu về Mạng nơ-ron tích chập (CNN)
Mạng nơ-ron tích chập (CNN) là loại mạng nơ-ron được cấu trúc từ nhiều lớp tích chập. Lớp tích chập giúp giảm thiểu bộ nhớ, số lượng tham số và hiện tượng quá khớp mô hình. CNN là thuật toán học sâu phổ biến, thường được ứng dụng trong xử lý hình ảnh và trí tuệ nhân tạo, đặc biệt trong nhận dạng hình ảnh và nhận diện khuôn mặt. So với mạng nơ-ron kết nối hoàn toàn, CNN sử dụng các tham số chia sẻ và khả năng cảm nhận cục bộ để trích xuất đặc trưng hình ảnh. CNN bao gồm năm lớp chính: lớp đầu vào, lớp tích chập, lớpPooling, lớp kết nối hoàn toàn và lớp đầu ra. Mô hình cụ thể được minh họa như sau.
(1) Lớp đầu vào (Input layer): Là điểm đầu vào của mạng nơ-ron, nhận dữ liệu đầu vào. Thường nhận ba kênh RGB từ hình ảnh. Dữ liệu đầu vào là ma trận đa chiều, trong đó giá trị từng phần tử đại diện cho độ sáng của điểm ảnh tương ứng.
(2) Lớp tích chập (Convolution layer): Lớp này chịu trách nhiệm trích xuất đặc trưng từ dữ liệu đầu vào.
(3) LớpPooling (Pooling layer): Giảm kích thước đặc trưng từ lớp tích chập, giúp giảm chi phí tính toán và tốc độ hội tụ, đồng thời ngăn ngừa hiện tượng quá khớp.
(4) Lớp kết nối hoàn toàn (Full connected layer): Kết hợp dữ liệu từ các lớp trước để thực hiện các phép tính suy luận cấp cao.
(5) Lớp đầu ra (Output layer): Là điểm ra cuối cùng của mạng nơ-ron, đưa ra kết quả sau khi xử lý dữ liệu.
2.2 Thuật toán nhận diện khuôn mặt
Sử dụng thư viện dlib để phát hiện và đánh dấu 68 điểm mốc trên khuôn mặt, đoạn mã chính:
import cv2
# Tải mô hình nhận diện khuôn mặt
face_rec_model_path = 'dlib_face_recognition_resnet_model_v1.dat'
facerec = dlib.face_recognition_model_v1(face_rec_model_path)
# Tải mô hình xác định điểm mốc
predictor_path = "shape_predictor_5_face_landmarks.dat"
predictor = dlib.shape_predictor(predictor_path)
# Đọc ảnh
img_path = "step1/image/face.jpg"
img = cv2.imread(img_path)
# Chuyển sang ảnh xám
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Bộ phát hiện khuôn mặt trước mặt
detector = dlib.get_frontal_face_detector()
# Phát hiện khuôn mặt trong ảnh
faces = detector(gray, 1)
# Phát hiện các điểm mốc trên khuôn mặt
for i, face in enumerate(faces):
# Lấy các điểm mốc
shape = predictor(img, face)
2.3 Nguyên lý phát hiện sự tập trung
Quy trình tổng thể
Dự án sử dụng webcam để chụp ảnh thời gian thực trạng thái và hành vi của học sinh, liên tục thu thập biểu cảm khuôn mặt và hướng nhìn của học sinh trong giờ học. Dữ liệu được truyền vào CNN để trích xuất đặc trưng và phân tích. Nếu giá trị đầu ra vượt ngưỡng quy định, hệ thống sẽ đánh giá học sinh đang mất tập trung. Đồng thời, hệ thống ghi lại thời gian học hiệu quả và tỷ lệ thời gian tập trung của học sinh, lưu trữ vào bảng dữ liệu.
Thuật toán phát hiện mắt
Dựa trên việc phát hiện 68 điểm mốc khuôn mặt bằng dlib, xác định chỉ số của các điểm mốc mắt trái và phải. Sử dụng OpenCV xử lý luồng video thành ảnh xám để xác định vị trí mắt. Hai hàm chính của dlib: dlib.get_frontal_face_detector() và dlib.shape_predictor(predictor_path).
Hàm đầu tiên dùng để phát hiện khuôn mặt dựa trên HOG pyramid. Hàm thứ hai dùng để xác định vị trí các điểm mốc trong khu vực đã phát hiện, cần có mô hình đã huấn luyện. Sử dụng mô hình shape_predictor_68_face_landmarks.dat để lấy tọa độ 68 điểm mốc, có thể vẽ kết quả như hình minh họa (đường đỏ là kết quả HOG, đường xanh lá là kết quả của shape_predictor, chỉ nối các điểm mốc cùng một cơ quan).
Tính toán tỷ lệ chiều cao và chiều rộng của mắt để xác định trạng thái chú ý.
Nguyên lý cơ bản: Tính toán chỉ số EAR (Eye Aspect Ratio). Khi mắt mở, EAR dao động quanh một mức nhất định; khi mắt nhắm, EAR giảm mạnh gần bằng 0. Do độ chính xác của mô hình nhận diện khuôn mặt chưa cao, nên ta xác định mắt đóng khi EAR nhỏ hơn ngưỡng nhất định. Cần thiết lập số khung hình liên tiếp để xác định hành động nháy mắt, thường là 1–3 khung. Hai ngưỡng này cần điều chỉnh phù hợp với thực tế.
Mã nguồn chính
# -*- coding: utf-8 -*-
# Nhập các thư viện cần thiết
from scipy.spatial import distance as dist
from imutils.video import FileVideoStream
from imutils.video import VideoStream
from imutils import face_utils
import numpy as np
import argparse
import imutils
import time
import dlib
import cv2
def eye_aspect_ratio(eye):
# Tính khoảng cách Euclid giữa các điểm mốc mắt
A = dist.euclidean(eye[1], eye[5])
B = dist.euclidean(eye[2], eye[4])
C = dist.euclidean(eye[0], eye[3])
# Tính tỷ lệ EAR
ear = (A + B) / (2.0 * C)
return ear
# Định nghĩa ngưỡng
EYE_AR_THRESH = 0.2
EYE_AR_CONSEC_FRAMES = 3
# Khởi tạo bộ đếm khung hình và số lần nháy mắt
COUNTER = 0
TOTAL = 0
# Tải mô hình phát hiện khuôn mặt và điểm mốc
print("[INFO] loading facial landmark predictor...")
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('D:/myworkspace/JupyterNotebook/fatigue_detecting/model/shape_predictor_68_face_landmarks.dat')
# Lấy chỉ số điểm mốc cho mắt trái và phải
(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
(rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]
# Mở webcam
cap = cv2.VideoCapture(0)
# Vòng lặp xử lý từng khung hình
while True:
ret, frame = cap.read()
frame = imutils.resize(frame, width=720)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Phát hiện khuôn mặt
rects = detector(gray, 0)
for rect in rects:
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
# Trích xuất điểm mốc mắt trái và phải
leftEye = shape[lStart:lEnd]
rightEye = shape[rStart:rEnd]
# Tính EAR cho cả hai mắt
leftEAR = eye_aspect_ratio(leftEye)
rightEAR = eye_aspect_ratio(rightEye)
ear = (leftEAR + rightEAR) / 2.0
# Vẽ khung mắt
leftEyeHull = cv2.convexHull(leftEye)
rightEyeHull = cv2.convexHull(rightEye)
cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)
# Vẽ khung khuôn mặt
left = rect.left()
top = rect.top()
right = rect.right()
bottom = rect.bottom()
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 3)
# Đếm số lần nháy mắt
if ear < EYE_AR_THRESH:
COUNTER += 1
else:
if COUNTER >= EYE_AR_CONSEC_FRAMES:
TOTAL += 1
COUNTER = 0
# Vẽ các điểm mốc
for (x, y) in shape:
cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)
# Hiển thị thông tin
cv2.putText(frame, "Faces: {}".format(len(rects)), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(frame, "Blinks: {}".format(TOTAL), (150, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(frame, "COUNTER: {}".format(COUNTER), (300, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(frame, "EAR: {:.2f}".format(ear), (450, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
print('Tỷ lệ mắt hiện tại: {:.2f}'.format(ear))
if TOTAL >= 50:
cv2.putText(frame, "NGHỈ NGƠI!", (200, 200),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
cv2.putText(frame, "Nhấn 'q' để thoát", (20, 500),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (84, 255, 159), 2)
# Hiển thị khung hình
cv2.imshow("Frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Giải phóng tài nguyên
cap.release()
cv2.destroyAllWindows()
2.4 OpenCV
OpenCV là thư viện nổi tiếng trong lĩnh vực xử lý ảnh và thị giác máy tính. Hỗ trợ nhiều ngôn ngữ, nền tảng và có chức năng mạnh mẽ. Cung cấp giao diện Python cho phép người dùng gọi các hàm C/C++ một cách dễ dàng. OpenCV là một thư viện xử lý hình ảnh đa nền tảng theo giấy phép BSD, chạy được trên Linux, Windows và macOS. Nó bao gồm các hàm C và một số lớp C++. Ngoài ra còn có các giao diện với các ngôn ngữ khác như Python, Ruby, MATLAB để thực hiện các thuật toán phổ biến trong xử lý ảnh và thị giác máy tính.
Trong dự án này, OpenCV được dùng chủ yếu trong việc xử lý ảnh từ webcam, như tiền xử lý ảnh, điều chỉnh kích thước và ánh sáng, sau đó gửi đến mạng nơ-ron để trích xuất đặc trưng.
3 Hiệu quả thực hiện
Hiệu quả hoạt động của dự án:
Dự án tốt nghiệp: Hệ thống phát hiện sự tập trung trong lớp học trực tuyến
Chia sẻ dự án: Xem phần cuối bài viết!