728x90
원본 얼굴의 삼각형이 타겟 얼굴의 삼각형과 모양과 크기가 정확히 일치하도록 해당 삼각형을 선택하고 왜곡하는 방법을 입니다.
import cv2
import numpy as np
import dlib
def extract_index_nparray(nparray):
index = None
for num in nparray[0]:
index = num
break
return index
img = cv2.imread("bradley_cooper.jpg")
img2 = cv2.imread("jim_carrey.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
mask = np.zeros_like(img_gray)
# Loading Face landmarks detector
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
첫 번째 얼굴을 찾은 코드의 두 번째 부분에서는 이전 케이스에서 일부 변경을 수행합니다. 더 이상 표시할 필요가 없으므로 삼각형과 볼록 선체를 그린 모든 선을 제거하거나 주석을 달 것입니다.
# Face 1
faces = detector(img_gray)
for face in faces:
landmarks = predictor(img_gray, face)
landmarks_points = []
for n in range(0, 68):
x = landmarks.part(n).x
y = landmarks.part(n).y
landmarks_points.append((x, y))
#cv2.circle(img, (x, y), 3, (0, 0, 255), -1)
points = np.array(landmarks_points, np.int32)
convexhull = cv2.convexHull(points)
#cv2.polylines(img, [convexhull], True, (255, 0, 0), 3)
cv2.fillConvexPoly(mask, convexhull, 255)
face_image_1 = cv2.bitwise_and(img, img, mask=mask)
# Delaunay triangulation
rect = cv2.boundingRect(convexhull)
subdiv = cv2.Subdiv2D(rect)
subdiv.insert(landmarks_points)
triangles = subdiv.getTriangleList()
triangles = np.array(triangles, dtype=np.int32)
indexes_triangles = []
for t in triangles:
pt1 = (t[0], t[1])
pt2 = (t[2], t[3])
pt3 = (t[4], t[5])
index_pt1 = np.where((points == pt1).all(axis=1))
index_pt1 = extract_index_nparray(index_pt1)
index_pt2 = np.where((points == pt2).all(axis=1))
index_pt2 = extract_index_nparray(index_pt2)
index_pt3 = np.where((points == pt3).all(axis=1))
index_pt3 = extract_index_nparray(index_pt3)
if index_pt1 is not None and index_pt2 is not None and index_pt3 is not None:
triangle = [index_pt1, index_pt2, index_pt3]
indexes_triangles.append(triangle)
두 번째 얼굴의 랜드마크 포인트를 찾는 부분에서 변수 이름을 약간 변경하여 첫 번째 얼굴과 구별합니다.
# Face 2
faces2 = detector(img2_gray)
for face in faces2:
landmarks = predictor(img2_gray, face)
landmarks_points2 = []
for n in range(0, 68):
x = landmarks.part(n).x
y = landmarks.part(n).y
landmarks_points2.append((x, y))
#cv2.circle(img2, (x, y), 3, (0, 255, 0), -1)
삼각형 인덱스를 통해 루프를 돌고 두 면의 삼각형을 감지합니다.
구체적으로 작업하기 위해 각 삼각형의 영역을 자릅니다.
랜드마크 포인트를 볼 필요가 없기 때문에 cv2.circle 라인에 주석을 달았습니다.
# Triangulation of both faces
for triangle_index in indexes_triangles:
# Triangulation of the first face
tr1_pt1 = landmarks_points[triangle_index[0]]
tr1_pt2 = landmarks_points[triangle_index[1]]
tr1_pt3 = landmarks_points[triangle_index[2]]
triangle1 = np.array([tr1_pt1, tr1_pt2, tr1_pt3], np.int32)
rect1 = cv2.boundingRect(triangle1)
(x, y, w, h) = rect1
cropped_triangle = img[y: y + h, x: x + w]
cropped_tr1_mask = np.zeros((h, w), np.uint8)
points = np.array([[tr1_pt1[0] - x, tr1_pt1[1] - y],
[tr1_pt2[0] - x, tr1_pt2[1] - y],
[tr1_pt3[0] - x, tr1_pt3[1] - y]], np.int32)
cv2.fillConvexPoly(cropped_tr1_mask, points, 255)
cropped_triangle = cv2.bitwise_and(cropped_triangle, cropped_triangle,
mask=cropped_tr1_mask)
cv2.line(img, tr1_pt1, tr1_pt2, (0, 0, 255), 2)
cv2.line(img, tr1_pt3, tr1_pt2, (0, 0, 255), 2)
cv2.line(img, tr1_pt1, tr1_pt3, (0, 0, 255), 2)
두 번째 면에 대해서도 동일한 작업입니다.
# Triangulation of second face
tr2_pt1 = landmarks_points2[triangle_index[0]]
tr2_pt2 = landmarks_points2[triangle_index[1]]
tr2_pt3 = landmarks_points2[triangle_index[2]]
triangle2 = np.array([tr2_pt1, tr2_pt2, tr2_pt3], np.int32)
rect2 = cv2.boundingRect(triangle2)
(x, y, w, h) = rect2
cropped_triangle2 = img2[y: y + h, x: x + w]
cropped_tr2_mask = np.zeros((h, w), np.uint8)
points2 = np.array([[tr2_pt1[0] - x, tr2_pt1[1] - y],
[tr2_pt2[0] - x, tr2_pt2[1] - y],
[tr2_pt3[0] - x, tr2_pt3[1] - y]], np.int32)
cv2.fillConvexPoly(cropped_tr2_mask, points2, 255)
cropped_triangle2 = cv2.bitwise_and(cropped_triangle2, cropped_triangle2,
mask=cropped_tr2_mask)
cv2.line(img2, tr2_pt1, tr2_pt2, (0, 0, 255), 2)
cv2.line(img2, tr2_pt3, tr2_pt2, (0, 0, 255), 2)
cv2.line(img2, tr2_pt1, tr2_pt3, (0, 0, 255), 2)
마지막으로 삼각형을 추출한 후에는 삼각형을 뒤틀 수 있습니다.
# Warp triangles
points = np.float32(points)
points2 = np.float32(points2)
M = cv2.getAffineTransform(points, points2)
warped_triangle = cv2.warpAffine(cropped_triangle, M, (w, h))
break
그런 다음 화면에 모든 것을 표시할 수 있습니다.
cv2.imshow("Image 1", img)
cv2.imshow("image2", img2)
cv2.imshow("cropped triangle 1", cropped_triangle)
cv2.imshow("cropped triangle 2", cropped_triangle2)
cv2.imshow("Warped triangle", warped_triangle)
cv2.waitKey(0)
cv2.destroyAllWindows()
'영상처리 > 기초' 카테고리의 다른 글
Instance Segmentation MASK R-CNN (13) | 2023.01.07 |
---|---|
Face swapping-Swap faces(part 5) (6) | 2023.01.06 |
Face swapping-Matching the two faces triangulation(part 3) (0) | 2023.01.06 |
Face swapping-Delaunay Triangulation(part 2) 들로네 삼각분할 (19) | 2023.01.05 |
Face swapping (part1) 얼굴 교환 (5) | 2023.01.05 |