연예인 사진에 고양이수염을 합성하는 프로젝트를 진행해봤습니다. 기존에 수평으로 있는
코드는 다음과 같이 진행됩니다.
1. dlib.get_frontal_face_detector를 활용한 정면 얼굴 인식 (측면 사진은 인식하지 못할 수 있습니다.)
2. dlib.shape_predictor 함수를 활용하여 Facial Landmark(눈, 코, 입 등) 인식
3. 회전 각도 계산 후 회전
4. 이미지 부착
자세한 코드부는 깃헙에 상세히 설명되어 있으니 참고 바라겠습니다.
https://github.com/dldndyd01/AIFFEL/blob/master/Face_Detection/FaceDetection-rotation.ipynb
이번 글은 회전된 얼굴을 인식하고
1. 몇도가 회전되어 있는지 측정하는 방법과
2. 해당 각도만큼 이미지를 회전하고 부착하는 방법에 대해 작성하겠습니다.
여기서 저희가 사용할 좌표는 27번 좌표와 30번 좌표입니다.
그림실력이 엉망인 점은 양해 부탁드립니다.
θ(theta) 값을 구하기 위해서 삼각비의 활용을 이용할건데요.
※ x는 오른쪽으로 갈수록 값이 증가, y는 아래로 내려갈수록 값이 증가한다는 사실을 잊지 마세요!
import math
tan_theta = (landmark[30][0]-landmark[27][0])/(landmark[30][1]-landmark[27][1])
theta = np.arctan(tan_theta)
rotate_angle = theta *180/math.pi
print(rotate_angle)
==> -47.60256
theta는 저희가 흔히 알고 있는 각도(°) 로 변경하기 위해서는
각도 ° = θ
의 과정을 거쳐줘야 합니다.
해당 내용에 대한 이야기가 궁금하신 분들은 호도법(Radian) 을 공부해보셔도 좋을 것 같습니다!
def rotate_image(image, angle):
image_center = tuple(np.array(image.shape[1::-1]) / 2)
rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
result = cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR,borderValue=(255,255,255))
return result
img_rotate = rotate_image(img_sticker,rotate_angle)
print(img_rotate.shape)
plt.imshow(img_rotate)
plt.show()
회전된 각도를 rotate_angle에 저장하고 getRotationMatrix2D를 이용해 회전시켜주면 다음과 같이 회전된 고양이 수염이 나옵니다.
기본적으로 getRotationMatrix2D는 반시계방향으로 각도가 증가하기 때문에 위 사진에서는 -47도라는 값이 나온 것입니다.
refined_x = x[i] - w//2
refined_y = y[i]
sticker_area = img_bgr[refined_y:refined_y+img_rotate.shape[0],refined_x:refined_x+img_rotate.shape[1]]
img_show[refined_y:refined_y+img_rotate.shape[0], refined_x:refined_x+img_rotate.shape[1]] = np.where(img_rotate==255,sticker_area,img_rotate).astype(np.uint8)
여기서 np.where함수는 합성시 유용하게 쓰일 수 있는 함수이니 짚고 넘어가겠습니다.
np.where(조건, True, False)
라고 이해하시면 될 듯 합니다.
조건식에 만족하는 pixel은 True값으로 치환, 조건을 만족하지 못하는 pixel은 False에 기입된 값으로 치환하는 함수입니다.
위 코드에서는
np.where(img_rotate==255,sticker_area, img_rotate)라고 적혀있는데요.
회전된 이미지가 하얀색인 부분은 sticker_area로 변경, 하얀색이 아니라면 img_rotate를 그대로 출력하라는 뜻이겠지요.
결과적으로 배경 흰색이 날라가면서 연예인 사진에 합성된 다음과 같은 사진을 출력하게 됩니다.
깃헙에서 상세히 설명하지 못한 부분을 벨로그에 정리한 터라 깃헙의 코드를 따라가보고 이해가 안되시는 부분은 언제든 질문주셔도 됩니다!