비전

[MediaPipe] 얼굴 매쉬2

왕초보코딩러 2024. 9. 3. 19:22
728x90

미디어파이프란 구글에서 제공하는 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

 

mediapipe/docs/solutions/face_mesh.md at master · google-ai-edge/mediapipe

Cross-platform, customizable ML solutions for live and streaming media. - google-ai-edge/mediapipe

github.com

 

 

2024.09.02 - [분류 전체보기] - [MediaPipe] 얼굴 매쉬1

 

[MediaPipe] 얼굴 매쉬1

미디어파이프란 구글에서 제공하는 AI 오픈소스이다  미디어파이프 설치pip install mediapipe  import mediapipe as mpimport cv2  mp.solutions: 미디어파이프 솔루션들이 포함되어 쉽게 사용할 수 있다  -

dogfoot1.tistory.com

 


좌표 찾기

 

좌표를 확인해보겠습니다

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

 

[Python] NumPy로 행렬 사이의 거리 계산 연산 예제

NumPy로 행렬 사이의 거리 계산 연산 예제 이 포스트에서는 NumPy를 사용하여 두 행렬 사이의 거리를 계산하는 방법에 대해 알아보겠습니다. NumPy는 파이썬에서 사용하는 수치 계산 라이브러리로,

gr-st-dev.tistory.com

 

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