Khi xây dựng hệ thống điều khiển bằng cử chỉ, bước đầu tiên và quan trọng nhất là giúp máy tính hiểu được hình dạng bàn tay người dùng. Dưới đây là hướng dẫn triển khai một hệ thống nhận diện cử chỉ đơn giản (như kéo-búa-bao) hoàn toàn trong môi trường MATLAB.
Tiền xử lý và phân đoạn bàn tay
Thay vì chuyển ảnh RGB sang grayscale thông thường, ta sử dụng không gian màu YCbCr để tách vùng da hiệu quả hơn:
is_skin = @(img) ...
(img(:,:,1) > 90) & ...
(img(:,:,2) > 85) & ...
(img(:,:,3) > 140) & ...
(abs(img(:,:,2) - img(:,:,3)) > 12) & ...
(img(:,:,1) > img(:,:,2)) & ...
(img(:,:,1) > img(:,:,3));
Sau khi thu được ảnh nhị phân, áp dụng phép toán hình thái học: phép mở (erosion → dilation) để loại bỏ nhiễu nhỏ, phép đóng (dilation → erosion) để lấp đầy lỗ hổng trong vùng bàn tay.
Trích xuất đặc trưng nổi bật
Ba đặc trưng chính được sử dụng để biểu diễn hình dáng cử chỉ:
- Moment bất biến Hu: Sử dụng hàm
regionprops(..., 'HuMoments')để trích xuất 7 moment bất biến — giúp hệ thống không bị ảnh hưởng bởi phép xoay hay co giãn. - Histogram gradient định hướng (HOG): Gọi
extractHOGFeaturesđể thu thập thông tin về hướng cạnh và kết cấu bề mặt. - Độ lồi và điểm khuyết: Dùng
bwconvhullvàbwdistgeodesicđể xác định số ngón tay đang mở dựa vào các điểm lõm trên biên.
So sánh hiệu năng các bộ phân loại
Thử nghiệm trên tập dữ liệu 200 mẫu cử chỉ với ba mô hình phổ biến:
% SVM với kernel RBF
classifier_svm = fitcsvm(X_train, y_train, ...
'KernelFunction', 'rbf', ...
'Standardize', true);
% KNN với khoảng cách cosine
classifier_knn = fitcknn(X_train, y_train, ...
'NumNeighbors', 7, ...
'Distance', 'cosine');
% Rừng ngẫu nhiên với 60 cây quyết định
classifier_rf = TreeBagger(60, X_train, y_train, ...
'Method', 'classification');
Kết quả thực nghiệm cho thấy:
- SVM có độ ổn định cao dưới điều kiện ánh sáng thay đổi nhưng tốc độ huấn luyện chậm.
- KNN dễ triển khai nhưng dễ bị ảnh hưởng bởi nền phức tạp.
- Rừng ngẫu nhiên đạt độ chính xác ~93% và cân bằng tốt giữa tốc độ và độ tin cậy.
Xử lý video thời gian thực
Sử dụng VideoReader và vision.DeployableVideoPlayer để xử lý luồng video:
vid = VideoReader('input.mp4');
player = vision.DeployableVideoPlayer;
while hasFrame(vid)
frame = readFrame(vid);
% Phát hiện ROI chứa bàn tay (giả sử đã có bbox từ detector)
hand_roi = imcrop(frame, [x y w h]);
% Tiền xử lý + trích đặc trưng
features = extract_hand_features(hand_roi);
% Dự đoán nhãn
gesture_label = predict(classifier_rf, features);
% Hiển thị kết quả
annotated = insertText(frame, [x y-10], gesture_label, ...
'FontSize', 16, 'BoxColor', 'green');
step(player, annotated);
end
Lưu ý giới hạn FPS (~15 khung/giây ở độ phân giải 720p) để tránh quá tải CPU.