미디어파이프란 구글에서 제공하는 AI 오픈소스이다
미디어파이프 설치
pip install mediapipe
import cv2
from mediapipe.python.solutions import face_mesh as mp_face_mesh
import numpy as np
mp.solutions: 미디어파이프 솔루션들이 포함되어 쉽게 사용할 수 있다
- 얼굴 탐지
mp.solutions.face_detection
- 얼굴 매쉬
mp.solutions.face_mesh
- 손 추적
mp.solutions.hands
- 포즈 추정
mp.solutions.pose
- 신체 전체 추적
mp.solutions.holistic
- 랜드마크 시각화 툴
mp.solutions.drawing_utils
- 미리 정의된 스타일 툴
mp.solutions.drawing_styles
- 인물과 배경 분리
mp.solutions.selfie_segmentation
https://github.com/google-ai-edge/mediapipe/blob/master/docs/solutions/face_mesh.md
2024.09.02 - [분류 전체보기] - [MediaPipe] 얼굴 매쉬1
좌표 찾기
좌표를 확인해보겠습니다
dir()을 사용하면 그 안의 함수들을 볼 수 있습니다.
mp_face_mesh = mp.solutions.face_mesh
print(dir(mp_face_mesh))
'''
['FACEMESH_CONTOURS', 'FACEMESH_FACE_OVAL', 'FACEMESH_IRISES', 'FACEMESH_LEFT_EYE',
'FACEMESH_LEFT_EYEBROW', 'FACEMESH_LEFT_IRIS', 'FACEMESH_LIPS', 'FACEMESH_NOSE',
'FACEMESH_NUM_LANDMARKS', 'FACEMESH_NUM_LANDMARKS_WITH_IRISES', 'FACEMESH_RIGHT_EYE',
'FACEMESH_RIGHT_EYEBROW', 'FACEMESH_RIGHT_IRIS', 'FACEMESH_TESSELATION', 'FaceMesh',
'NamedTuple', 'SolutionBase', '_BINARYPB_FILE_PATH', '__builtins__', '__cached__', '__doc__',
'__file__', '__loader__', '__name__', '__package__', '__spec__', 'association_calculator_pb2',
'constant_side_packet_calculator_pb2', 'detections_to_rects_calculator_pb2',
'gate_calculator_pb2', 'image_to_tensor_calculator_pb2', 'inference_calculator_pb2',
'landmarks_refinement_calculator_pb2', 'logic_calculator_pb2', 'non_max_suppression_calculator_pb2',
'np', 'rect_transformation_calculator_pb2', 'split_vector_calculator_pb2',
'ssd_anchors_calculator_pb2', 'tensors_to_classification_calculator_pb2',
'tensors_to_detections_calculator_pb2', 'tensors_to_landmarks_calculator_pb2',
'thresholding_calculator_pb2']
''''
저 함수 중 입술을 가지고 해보겠습니다
print(mp_face_mesh.FACEMESH_LIPS)
'''
frozenset({(270, 409), (317, 402), (81, 82), (91, 181), (37, 0), (84, 17), (269, 270),
(321, 375), (318, 324), (312, 311), (415, 308), (17, 314), (61, 146), (78, 95), (0, 267),
(82, 13), (314, 405), (178, 87), (267, 269), (61, 185), (14, 317), (88, 178), (185, 40),
(405, 321), (13, 312), (324, 308), (409, 291), (146, 91), (87, 14), (78, 191), (95, 88),
(311, 310), (39, 37), (40, 39), (402, 318), (191, 80), (80, 81), (310, 415), (181, 84),
(375, 291)})
'''
이 숫자들은 인덱스인데 튜플로 인덱스끼리 연결하는 것입니다.
그럼 이 숫자들을 다 모으면 입술에 대한 인덱스가 되는 것입니다!
img_height, img_width, _ = img.shape
lip_index = set()
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
for idx1, idx2 in (mp_face_mesh.FACEMESH_LIPS): # index
lip_index.add(idx1)
lip_index.add(idx2)
for idx in lip_index:
x = face_landmarks.landmark[idx].x
y = face_landmarks.landmark[idx].y
real_x = int(x * img_width)
real_y = int(y * img_height)
cv2.circle(img, (real_x, real_y), 1, (0,0,255), 2)
cv2.putText(img, str(idx), (real_x, real_y), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0,0,0),1)
good~~
이제 입술 인덱스를 찾았으니 입술이 열리고 닫히는 걸 판단해볼게요.
그전에 두 벡터/행렬 사이의 거리를 구하는 함수를 만들겠습니다.
https://gr-st-dev.tistory.com/1292
np.linalg.norm() 예제
import numpy as np
point1 = np.array([1, 2])
point2 = np.array([4, 6])
distance = np.linalg.norm(point1 - point2)
print(distance)
두 벡터 사이의 거리를 구하는 함수를 만들겠습니다.
def return_distance(v1, v2):
v1 = np.array(v1)
v2 = np.array(v2)
return np.linalg.norm(v1-v2)
웹캠 구현하고, 페이스 매쉬 받기
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame.flags.writeable = False
results = face_mesh.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
frame.flags.writeable = True
cv2.imshow('', frame)
if cv2.waitKey(1) ==27:
break
cv2.destroyAllWindows()
일단 특정 좌표 인덱스를 찾습니다
저는 입술의 개폐 여부를 찾고 싶어 챗지피티에게 물어보겠습니다.
이제 결과 값을 이용해서 점 사이의 거리를 시각화하고 글로 출력하겠습니다.
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
# 실제 좌표 튜플로
upper_lip = (int(face_landmarks.landmark[13].x * img_width), int(face_landmarks.landmark[13].y * img_height)) # 인덱스 13
lower_lip = (int(face_landmarks.landmark[14].x * img_width), int(face_landmarks.landmark[14].y * img_height)) # 인덱스 14
# 시각화
cv2.circle(frame, upper_lip, 1, (0,0,255), 2)
cv2.circle(frame, lower_lip, 1, (0,0,255), 2)
# 거리 시각화
# cv2.putText(frame, str(return_distance(upper_lip, lower_lip)), (0, 100), cv2.FONT_HERSHEY_COMPLEX, 2, (255,0,0))
distance = return_distance(upper_lip, lower_lip)
if distance <= 5. : # close
cv2.putText(frame, 'Close', (0,100), cv2.FACE_RECOGNIZER_SF_FR_COSINE, 1, (255,0,0))
else:
cv2.putText(frame, 'Open', (0,100), cv2.FACE_RECOGNIZER_SF_FR_COSINE, 1, (0,0,255))
'비전' 카테고리의 다른 글
[MediaPipe] face_detection으로 얼굴 모자이크 (0) | 2024.09.04 |
---|---|
[MediaPipe] 얼굴 매쉬1 (1) | 2024.09.02 |
[MediaPipe] 포즈 인식 (0) | 2024.08.25 |
[MediaPipe] 얼굴 인식 (0) | 2024.08.23 |
[OpenCV] 특정 색 검출 (0) | 2024.08.20 |