Xin chào các bạn, hôm nay Ngô Tôn .IT sẽ chia sẻ một chủ đề là Nhận diện chuyển động cử chỉ bàn tay với OpenCV – Hand Tracking sử dụng MediaPipe Hands. Một chủ đề cũng khá hay làm nền tảng cho một số dự án trong series Tự học và phát triển ứng dụng thực tế AI, ML, DL, DS.
Ngày nay, khả năng nhận biết hình dạng và chuyển động của bàn tay có thể là một thành phần quan trọng trong việc cải thiện trải nghiệm người dùng trên nhiều lĩnh vực và nền tảng công nghệ khác nhau. Nó có thể tạo cơ sở cho việc hiểu ngôn ngữ ký hiệu và điều khiển cử chỉ tay, đồng thời cũng có thể cho phép phủ thông tin và nội dung kỹ thuật số lên trên thế giới vật lý trong thực tế tăng cường (Augmented reality – AR).
Khả năng nhận biết tay với thời gian thực là một nhiệm vụ khó khăn về thị giác máy tính (Computer Vision), vì hai bàn tay thường tự chạm vào nhau (ví dụ: khớp ngón tay / lòng bàn tay và lắc tay) và thiếu các kiểu tương phản cao.
MediaPipe
MediaPipe cung cấp các giải pháp ML đa nền tảng, có thể tùy chỉnh cho các phương tiện trực tiếp và phát trực tuyến (streaming).
MediaPipe Hands là giải pháp theo dõi ngón tay và bàn tay có độ trung thực cao. Nó sử dụng công nghệ máy học (ML) để suy ra 21 điểm mốc 3D của bàn tay chỉ từ một khung hình duy nhất.
Một số giải pháp ứng dụng:
- Face Detection
- Face Mesh
- Iris
- Hands
- Pose
- Holistic
- Hair Segmentation
- Object Detection
- Box Tracking
- Instant Motion Tracking
- Objectron
- KNIFT
- AutoFlip
- MediaSequence
- YouTube 8M
Nhận diện chuyển động cử chỉ bàn tay – Hand Tracking
Trong bài viết này, mình sẽ hướng dẫn các bạn viết một ứng dụng Nhận diện chuyển động cử chỉ bàn tay sử dụng OpenCV và MediaPipe trong Python.
Đầu tiên, chúng ta import một số package:
1 2 3 |
import cv2 import mediapipe as mp import time |
Tiếp theo, mở camera và load thư viện MediaPipe Hands
1 2 3 4 5 6 7 8 9 |
cap = cv2.VideoCapture(0) mpHands = mp.solutions.hands hands = mpHands.Hands() mpDraw = mp.solutions.drawing_utils success, img = cap.read() imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results = hands.process(imgRGB) |
Kế tiếp, chúng ta sẽ lấy ra các điểm trên bàn tay với hàm “multi_hand_landmarks”
Sau khi lấy được tọa độ các điểm, chúng ta sẽ tính toán với kích thước khung hình và vẽ điểm hình tròn với OpenCV.
Cuối cùng là kết nối các điểm đã vẽ lại với nhau với hàm “draw_landmarks”.
1 2 3 4 5 6 7 8 9 10 |
if results.multi_hand_landmarks: for handLms in results.multi_hand_landmarks: for id, lm in enumerate(handLms.landmark): h, w, c = img.shape cx, cy, = int(lm.x*w), int(lm.y*h) if id == 0: cv2.circle(img, (cx,cy), 25, (255,0,255), cv2.FILLED) else: cv2.circle(img, (cx,cy), 15, (255,0,255), cv2.FILLED) mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS) |
Ở đoạn code trên, có lệnh “if id == 0:”, mình vẽ điểm ở mu bàn tay (tương ứng với id 0) cho to nhất, còn lại vẽ kích thước nhỏ hơn. Với 21 điểm trên bàn tay sẽ có id từ 0 – 20.
Code chỉ ngắn gọn vậy thôi, nhưng bây giờ mình sẽ chuyển thành module Hand Tracking để tiện cho việc sử dụng sau này.
Tạo class Hand detector:
1 |
class handDetector(): |
Khởi tạo với một số tham số:
1 2 3 4 5 6 7 8 9 |
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5): self.mode = mode self.maxHands = maxHands self.detectionCon = detectionCon self.trackCon = trackCon self.mpHands = mp.solutions.hands self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.detectionCon, self.trackCon) self.mpDraw = mp.solutions.drawing_utils |
Phương thức nhận diện bàn tay và vẽ khung xương:
1 2 3 4 5 6 7 8 9 |
def findHands(self, img, draw=True): imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) self.results = self.hands.process(imgRGB) if self.results.multi_hand_landmarks: for handLms in self.results.multi_hand_landmarks: if draw: self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS) return img |
Phương thức tìm các điểm trên bàn tay:
1 2 3 4 5 6 7 8 9 10 11 12 |
def findPosition(self, img, handNo=0, draw=True): lmList = [] if self.results.multi_hand_landmarks: myHand = self.results.multi_hand_landmarks[handNo] for id, lm in enumerate(myHand.landmark): h, w, c = img.shape cx, cy, = int(lm.x*w), int(lm.y*h) lmList.append([id, cx, cy]) if draw: cv2.circle(img, (cx,cy), 15, (255,0,255), cv2.FILLED) return lmList |
Chạy và xem kết quả:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
def main(): pTime = 0 cTime = 0 cap = cv2.VideoCapture(0) detector = handDetector() while True: success, img = cap.read() img = detector.findHands(img) lmList = detector.findPosition(img) if len(lmList) != 0: print(lmList[4]) cTime = time.time() fps = 1/(cTime-pTime) pTime = cTime cv2.putText(img, str(int(fps)), (10,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,255), 3) cv2.imshow("Image", img) cv2.waitKey(1) if __name__ == "__main__": main() |
Chúc các bạn thành công!
Leave a Reply