MediaPipe는 Google에서 개발한 오픈 소스 라이브러리로, 컴퓨터 비전 및 머신 러닝 기반 애플리케이션을 개발하는 데 사용됩니다. 여러 신체 부위의 특성을 손 쉽게 뽑아주기 때문에 아주 유용합니다!
저는 이번에 face 인식을 할 예정입니다.
다른 신체부위는 랜드마크(포인트 위치좌표)의 갯수가 적고 정확한 정보도 많지만 얼굴의 경우 각 포인트 별 좌표 번호가 없어 먼저 해당 좌표를 출력했습니다. 우클릭해서 새탭에서 열거나 다운로드 받아 보시면 됩니다! 고화질로 했어요!
아래는 좌표 추출코드 입니다
import cv2
import mediapipe as mp
from IPython.display import Image, display
# MediaPipe FaceMesh 초기화
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh()
# OpenCV 이미지 불러오기
image_path = 'face.png' # 얼굴 이미지 파일 경로 설정
image = cv2.imread(image_path)
image = cv2.resize(image, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR) # 이미지를 2배로 확대
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 얼굴 특성 추출
results = face_mesh.process(image_rgb)
# 랜드마크 그리기 및 번호 표시
if results.multi_face_landmarks:
for face_landmarks in results.multi_face_landmarks:
for idx, landmark in enumerate(face_landmarks.landmark):
x = int(landmark.x * image.shape[1])
y = int(landmark.y * image.shape[0])
cv2.circle(image, (x, y), 2, (0, 255, 0), -1) # 랜드마크를 초록색 점으로 표시
cv2.putText(image, str(idx), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 1) # 랜드마크 번호 표시
# 이미지 저장
output_image_path = 'output_face.png'
cv2.imwrite(output_image_path, image)
# 이미지 출력
display(Image(filename=output_image_path))
이제 추출된 랜드마크를 사용하여 얼굴의 특성을 뽑아보자
def capture(self):
# 웹캠에서 프레임 읽기
ret, frame = self.cap.read()
if not ret:
return
# 좌우반전
frame = cv2.flip(frame, 1)
# 이미지 크기 얻기
image_height, image_width, _ = frame.shape
# 이미지를 RGB 형식으로 변환
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 얼굴 특성 추출
results = self.face_mesh.process(image_rgb)
# 추출된 얼굴 랜드마크를 리스트로 변환합니다.
landmarks = []
for face_landmarks in results.multi_face_landmarks:
for landmark in face_landmarks.landmark:
landmarks.append((landmark.x, landmark.y, landmark.z))
# landmarks 리스트를 NumPy 배열로 변환합니다.
landmarks_array = np.array(landmarks, dtype=np.float32)
# 필요한 랜드마크 인덱스를 정의합니다.
# 눈
left_eye = [
133,
173,
157,
158,
159,
160,
161,
246,
33,
130,
7,
163,
144,
145,
153,
154,
155,
]
right_eye = [
362,
382,
381,
380,
374,
373,
390,
249,
359,
263,
466,
388,
387,
386,
385,
384,
398,
]
# 코
nose_tip = [
168,
245,
128,
114,
217,
198,
209,
49,
64,
98,
97,
2,
326,
327,
278,
360,
420,
399,
351,
]
# 입
top_lip = [61, 185, 40, 39, 37, 0, 267, 270]
bottom_lip = [146, 91, 181, 84, 17, 314, 405, 321]
# 눈썹
left_eyebrow = [336, 296, 334, 293, 276, 283, 282, 295, 285]
right_eyebrow = [107, 66, 105, 63, 70, 53, 52, 65, 66]
# 얼굴 윤곽
face_contour = [
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
]
# 눈 간의 거리와 눈 높이의 비율 계산
left_eye_x = landmarks_array[left_eye, 0]
left_eye_y = landmarks_array[left_eye, 1]
right_eye_x = landmarks_array[right_eye, 0]
right_eye_y = landmarks_array[right_eye, 1]
eye_distance = np.linalg.norm(left_eye_x - right_eye_x)
eye_height = np.linalg.norm(left_eye_y - right_eye_y)
eye_ratio = eye_distance / eye_height
# 코의 좌우 길이 계산
leftmost_nose_x = landmarks_array[nose_tip[0], 0]
rightmost_nose_x = landmarks_array[nose_tip[8], 0]
nose_width = np.linalg.norm(leftmost_nose_x - rightmost_nose_x)
# 코의 위아래 길이 계산
top_nose_y = landmarks_array[nose_tip[12], 1]
bottom_nose_y = landmarks_array[nose_tip[0], 1]
nose_height = np.linalg.norm(top_nose_y - bottom_nose_y)
# 얼굴 폭과 얼굴 높이의 비율 계산
face_width = np.linalg.norm(landmarks_array[16] - landmarks_array[0])
face_height = np.linalg.norm(landmarks_array[8] - landmarks_array[27])
face_ratio = face_width / face_height
# 눈썹 간의 거리와 얼굴 높이의 비율 계산
left_eyebrow_x = landmarks_array[left_eyebrow, 0]
left_eyebrow_y = landmarks_array[left_eyebrow, 1]
right_eyebrow_x = landmarks_array[right_eyebrow, 0]
right_eyebrow_y = landmarks_array[right_eyebrow, 1]
eyebrow_distance = np.linalg.norm(left_eyebrow_x - right_eyebrow_x)
eyebrow_height = np.linalg.norm(left_eyebrow_y - right_eyebrow_y)
eyebrow_ratio = eyebrow_distance / eyebrow_height
# 입술 좌우 길이 계산 (하나의 길이로 표현)
lip_width = np.linalg.norm(
landmarks_array[top_lip[0]] - landmarks_array[top_lip[6]]
)
caption = ""
if eye_ratio < 6.096545581817628:
caption += "대눈,"
elif eye_ratio > 9.090017929077149:
caption += "소눈,"
else:
caption += "중눈,"
if face_ratio < 0.32334879755973817:
caption += "대얼굴,"
elif face_ratio > 0.3679878675937653:
caption += "소얼굴,"
else:
caption += "중얼굴,"
if eyebrow_ratio < 17.789510231018067:
caption += "대눈썹,"
elif eyebrow_ratio > 21.317358169555668:
caption += "소눈썹,"
else:
caption += "중눈썹,"
if lip_width < 0.04647548146545887:
caption += "대입,"
elif lip_width > 0.0533718939870596:
caption += "소입,"
else:
caption += "중입,"
if nose_width < 0.021084710955619812:
caption += "대코,"
elif nose_width > 0.025440793633461:
caption += "소코,"
else:
caption += "중코,"
# 캡션을 텍스트 박스에 표시
self.text_box.setPlainText(caption)
qt5로 결과를 만들었다. 이제 스테이블 티퓨전 모델을 학습시켜 닮은 캐릭터 생성을 할 계획이다.
requirement
PyQt5==5.15.9
PyQt5-Qt5==5.15.2
PyQt5-sip==12.12.2
rembg==2.0.50
pooch==1.7.0
opencv-contrib-python==4.8.0.76
opencv-python==4.8.0.76
opencv-python-headless==4.8.1.78
댓글