# 1. 손 동작중에서 spider or Rock을 인식 / Fist =
# 2. 얼굴을 인식
# 3. 얼굴에 스파이더맨 가면 씌우기
# 4. 손 동작이 Fist일 때는 호랑이 가면 씌우기
In [2]:
## 동영상과 mediapipe-hand를 연결하기
## 한손의 동작 인식하기
import cv2
import mediapipe as mp
gesture = {
0:'fist', 1:'one', 2:'two', 3:'three', 4:'four', 5:'five',
6:'six', 7:'rock', 8:'spiderman', 9:'yeah', 10:'ok',
}
# gesture_train를 머신러닝 모델에 학습
import numpy as np
file = np.genfromtxt('images/gesture_train.csv',delimiter = ',')
angle = file[:, :-1].astype(np.float32) # 문제데이터
label = file[:, -1].astype(np.float32) # 정답데이터
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(angle,label)
# 손을 찾는 기능 불러오기
mp_hands = mp.solutions.hands
# 특징점 그리기 설정
mp_drawing = mp.solutions.drawing_utils
# 손 특징점 찾기 관련 설정
hands = mp_hands.Hands(
max_num_hands = 1,
min_detection_confidence = 0.5, # 손 검출 확률(자체 판단) 50% 이상인것들만 출력하기
min_tracking_confidence = 0.5# 특징점 검출 확률(자체 판단) 50% 이상인것들만 출력하기
)
# 얼굴에서 특징점을 찾을 수 있는 기능 불러오기
mp_face_mesh = mp.solutions.face_mesh
# 찾은 특징점 표현하기
mp_drawing = mp.solutions.drawing_utils
# 특징점 그리기 속성
drawing_spec = mp_drawing.DrawingSpec(thickness = 1, color = (0,0,255))
# 얼굴에서 특징점 찾기 속성
face_mesh = mp_face_mesh.FaceMesh(
min_detection_confidence = 0.5, # 얼굴 검출 확률(자체 판단) 50% 이상인것들만 출력하기
min_tracking_confidence = 0.5 # 특징점 검출 확률(자체 판단) 50% 이상인것들만 출력하기
)
# 한번만 실행하면 되는 코드
spider = cv2.imread('images/spiderman.jpg')
spider = cv2.resize(spider, (300,300)) # 123,132 > 250,250으로 크기 변경
mask2gray_spider = cv2.cvtColor(spider , cv2.COLOR_BGR2GRAY)
_, mask_b_spider = cv2.threshold(mask2gray_spider, 220, 255, cv2.THRESH_BINARY)
mask_b_inv_spider = cv2.bitwise_not(mask_b_spider)
tiger = cv2.imread('images/tiger.png')
tiger = cv2.resize(tiger, (200,200)) # 123,132 > 250,250으로 크기 변경
mask2gray_tiger = cv2.cvtColor(tiger , cv2.COLOR_BGR2GRAY)
_, mask_b_tiger = cv2.threshold(mask2gray_tiger, 220, 255, cv2.THRESH_BINARY)
mask_b_inv_tiger = cv2.bitwise_not(mask_b_tiger)
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, img = cap.read()
img = cv2.flip(img, 1)
if not ret:
break
# 이미지에서 원하는 대상(손) 찾기
hand_result = hands.process(img)
# 손을 검출 했다면 표현하기(21개의 특징점을 찾음)
if hand_result.multi_hand_landmarks is not None:
# 21개 특징점을 하나씩 그려주기
for res in hand_result.multi_hand_landmarks:
# 21개의 특징점 위치 저장할 용도(x,y,z)
joint = np.zeros((21,3))
# 21개의 특징점 저장
# enumerate : 반복문의 순서를 알려줌, 추가적인 변수 하나가 더 필요
for j , lm in enumerate(res.landmark):
joint[j] = [lm.x, lm.y, lm.z]
# 특징점을 연결해서 뼈의 값 구하기(좌표값 기반-x,y,z)
v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:]
v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:]
v = v2 - v1 # [20,3]
# 뼈의 직선 구하기
v = v / np.linalg.norm(v, axis=1)[:, np.newaxis]
# 뼈의 직선을 통해서 각도(radian) 구하기(각도의 변화가 큰 15개만 사용)
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],:]))
# radian각도를 degree각도로 변경하기
angle = np.degrees(angle)
# 학습된 KNN 모델에 동작 예측시키기
# 예측시킬 데이터 전처리하기
data = np.array([angle], dtype=np.float32)
# 예측하기
results = knn.predict(data)
idx = int(results)
# cv2.putText : 이미지 위에 글씨 쓰기
# 사용할 이미지, 쓸 글씨(영어), 글씨 위치, 폰트, 글씨 크기, 글씨 색깔, 글씨 두께
mp_drawing.draw_landmarks(img, res, mp_hands.HAND_CONNECTIONS)
if idx == 7 or idx == 8: # Rock or Spiderman 동작일때 실행
cv2.putText(img, text='SpiderMan', 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)
# 손동작이 스파이더맨 동작일때만 얼굴 검출 후 얼굴 검출되면 가면 씌우기
# 사진에서 얼굴 검출하기
face_result = face_mesh.process(img)
if face_result.multi_face_landmarks is not None:
# print(results.multi_face_landmarks)
#for res in results.multi_face_landmarks:
# mp_drawing.draw_landmarks(img, res, mp_face_mesh.FACEMESH_TESSELATION)
# 478개 점을 사용하기가 편함
face_landmarks = face_result.multi_face_landmarks[0]
# 코의 좌표 찾기
x = int(face_landmarks.landmark[4].x * img.shape[1])
y = int(face_landmarks.landmark[4].y * img.shape[0])
# cv2.circle(img, (x,y) , 20, (0,0,255), cv2.FILLED)
# 이미지를 집어넣을 중심 좌표(코의 위치) > x,y
# 마스크 이미지의 크기 > 123,132(tiger.shape) > 200,200
try:
sub_img = img[y-150 : y+150 , x-150: x+150]
img_bg = cv2.bitwise_and(sub_img, sub_img, mask = mask_b_spider)
img_fg = cv2.bitwise_and(spider,spider, mask = mask_b_inv_spider)
bg_fg = cv2.add(img_bg,img_fg)
img[y-150 : y+150 , x-150: x+150] = bg_fg
except:
pass
elif idx == 0: # Fist 동작일때 실행
cv2.putText(img, text='Tiger', 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)
# 손동작이 스파이더맨 동작일때만 얼굴 검출 후 얼굴 검출되면 가면 씌우기
# 사진에서 얼굴 검출하기
face_result = face_mesh.process(img)
if face_result.multi_face_landmarks is not None:
# print(results.multi_face_landmarks)
#for res in results.multi_face_landmarks:
# mp_drawing.draw_landmarks(img, res, mp_face_mesh.FACEMESH_TESSELATION)
# 478개 점을 사용하기가 편함
face_landmarks = face_result.multi_face_landmarks[0]
# 코의 좌표 찾기
x = int(face_landmarks.landmark[4].x * img.shape[1])
y = int(face_landmarks.landmark[4].y * img.shape[0])
# cv2.circle(img, (x,y) , 20, (0,0,255), cv2.FILLED)
# 이미지를 집어넣을 중심 좌표(코의 위치) > x,y
# 마스크 이미지의 크기 > 123,132(tiger.shape) > 200,200
try:
sub_img = img[y-100 : y+100 , x-100: x+100]
img_bg = cv2.bitwise_and(sub_img, sub_img, mask = mask_b_tiger)
img_fg = cv2.bitwise_and(tiger,tiger, mask = mask_b_inv_tiger)
bg_fg = cv2.add(img_bg,img_fg)
img[y-100 : y+100 , x-100: x+100] = bg_fg
except:
pass
cv2.imshow('video',img)
if cv2.waitKey(33) == 49:
break
cap.release()
cv2.destroyAllWindows()
'Study > Python' 카테고리의 다른 글
[Python] OpenCV - 9 Mediapipe-Hand (0) | 2023.10.31 |
---|---|
[Python] OpenCV - 8 Mediapipe 사용하기 (0) | 2023.10.30 |
[Python] OpenCV - 7 이미지 합성하기 (0) | 2023.10.27 |
[Python] OpenCV - 6 템플릿 매칭 (0) | 2023.10.26 |
[Python]OpenCV - 5 이미지 처리 (0) | 2023.10.25 |