본문 바로가기

인공지능

손 인식 인공지능 만들기

목표: 손모양을 인식하는 인공지능을 만들껍니다

개발언어 : 파이썬

언어는 파이썬을 사용하며

cv2 , mediapipe, numpy를 사용합니다

mediapipe는 얼굴인식, 다손추적, 헤어분할, 물체감지 및 추적등등 멀티 모달 (예 : 비디오, 오디오, 모든 시계열 데이터), 크로스 플랫폼 (예 : Android, iOS, 웹, 에지 장치) 적용 ML 파이프 라인을 구축하기위한 프레임 워크입니다.

https://google.github.io/mediapipe/solutions/hands

 

Hands

Cross-platform, customizable ML solutions for live and streaming media.

google.github.io

 

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import cv2
import mediapipe as mp
import numpy as np
 
#인식하는 손 갯수
max_num_hands = 2
 
gesture = {
    0:'fist'1:'one'2:'two'3:'three'4:'four'5:'five',
    6:'six'7:'rock'8:'spiderman'9:'yeah'10:'ok',
}
 
# MediaPipe 손 모델
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
hands = mp_hands.Hands(
    max_num_hands=max_num_hands,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5)
 
# 제스처 인식 모델
file = np.genfromtxt('data/gesture_train.csv', delimiter=',')
angle = file[:,:-1].astype(np.float32)
label = file[:, -1].astype(np.float32)
knn = cv2.ml.KNearest_create()
knn.train(angle, cv2.ml.ROW_SAMPLE, label)
 
 
#카메라 해상도
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)
 
while cap.isOpened():
    ret, img = cap.read()
    if not ret:
        continue
 
    img = cv2.flip(img, 1)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 
    result = hands.process(img)
 
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
 
    if result.multi_hand_landmarks is not None:
        for res in result.multi_hand_landmarks:
            joint = np.zeros((213))
            for j, lm in enumerate(res.landmark):
                joint[j] = [lm.x, lm.y, lm.z]
 
            # 관절 사이의 각도 계산
            v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint
            v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint
            v = v2 - v1 # [20,3]
            # Normalize v
            v = v / np.linalg.norm(v, axis=1)[:, np.newaxis]
 
            # Get angle using arcos of dot product
            angle = np.arccos(np.einsum('nt,nt->n',
                v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:], 
                v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,]
 
            angle = np.degrees(angle) # Convert radian to degree
 
            # Inference gesture
            data = np.array([angle], dtype=np.float32)
            ret, results, neighbours, dist = knn.findNearest(data, 3)
            idx = int(results[0][0])
 
            # Draw gesture result
            if idx in gesture.keys():
                cv2.putText(img, text=gesture[idx].upper(), org=(int(res.landmark[0].x * img.shape[1]), int(res.landmark[0].y * img.shape[0+ 20)), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, color=(255255255), thickness=2)
 
            # Other gestures
            # cv2.putText(img, text=gesture[idx].upper(), org=(int(res.landmark[0].x * img.shape[1]), int(res.landmark[0].y * img.shape[0] + 20)), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, color=(255, 255, 255), thickness=2)
 
            mp_drawing.draw_landmarks(img, res, mp_hands.HAND_CONNECTIONS)
 
    cv2.imshow('Test', img)
    if cv2.waitKey(1== ord('q'):
        break
 
cs

* 인식하는 손 갯수

max_num_hands = 2

gesture = {

0:'fist', 1:'one', 2:'two', 3:'three', 4:'four', 5:'five',

6:'six', 7:'rock', 8:'spiderman', 9:'yeah', 10:'ok',

}

-> max_num_hands는 인식하는 손 갯수입니다 2라면 2개의 손을 인식합니다

gesture = {

0:'fist', 1:'one', 2:'two', 3:'three', 4:'four', 5:'five',

6:'six', 7:'rock', 8:'spiderman', 9:'yeah', 10:'ok',

}

인공지능이 손 모양을 감지했을때 텍스트로 표현할 문자입니다

v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint

v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint

v = v2 - v1 # [20,3]

# Normalize v

v = v / np.linalg.norm(v, axis=1)[:, np.newaxis]

# Get angle using arcos of dot product

angle = np.arccos(np.einsum('nt,nt->n',

v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:],

v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,]

-> # 관절 사이의 각도 계산을 하여 손 모양을 인식합니다

예: 0과 1의 각도 1과 2의 각도등등을 계산하여 손 모양 인식