# 본 프로젝트는 유튜브 '빵형의 개발도상국'을 참고하였습니다.
https://www.youtube.com/watch?v=tpWVyJqehG4
새벽에 유튜브를 보다 어! 이거 재밌겠다! 하고 4시간정도 혼자 진행해본 프로젝트입니다. ( 빵형님 유튜브에 따라 해보고 싶은 프로젝트가 너무 많은 것... )
주제
가지고 있는 동영상에서 얼굴을 인식하여 캐릭터 이미지로 합성하기
1. 필요한 패키지 설치 및 영상 불러오기
# dlib 설치 : anaconda prompt 관리자 권한으로 실행 한후 "conda install -c conda-forge dlib"
from turtle import shape
import cv2, dlib, sys
import numpy as np
scaler = 0.7 # 크기 조절
detector = dlib.get_frontal_face_detector() # 얼굴 디텍터 모듈 초기화
# 기존에 머신러닝으로 학습된 모델 사용
# https://github.com/davisking/dlib-models/blob/master/shape_predictor_68_face_landmarks.dat.bz2
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 얼굴 특징점 모듈 초기화
# load video
cap = cv2.VideoCapture('변신전영상2.mp4')
# load overlay image
overlay = cv2.imread('yung_yammy.png', cv2.IMREAD_UNCHANGED) # 알파채널까지 읽어오기 (BGRA 타입)
# 위의 png 파일명 한글이면 못읽어옴..!!
- 이미지 처리를 위해 dlib 라이브러리를 설치해주어야 합니다.
- 얼굴 특징점을 찾을 때는 pre-trained model을 활용합니다.
https://github.com/davisking/dlib-models/blob/master/shape_predictor_68_face_landmarks.dat.bz2
- 적절한 크기로 사진이 얼굴에 합성될 수 있도록 scaler 값을 조절해야 합니다.
* 얼굴 overlay에 사용한 귀여운 융융이 사진
2. 영상 투영 함수 정의
# overlay function (투영해주는 코드)
def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None):
bg_img = background_img.copy()
# convert 3 channels to 4 channels
if bg_img.shape[2] == 3:
bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGR2BGRA)
if overlay_size is not None:
img_to_overlay_t = cv2.resize(img_to_overlay_t.copy(), overlay_size)
b, g, r, a = cv2.split(img_to_overlay_t)
mask = cv2.medianBlur(a, 5)
h, w, _ = img_to_overlay_t.shape
roi = bg_img[int(y-h/2):int(y+h/2), int(x-w/2):int(x+w/2)]
img1_bg = cv2.bitwise_and(roi.copy(), roi.copy(), mask=cv2.bitwise_not(mask))
img2_fg = cv2.bitwise_and(img_to_overlay_t, img_to_overlay_t, mask=mask)
bg_img[int(y-h/2):int(y+h/2), int(x-w/2):int(x+w/2)] = cv2.add(img1_bg, img2_fg)
# convert 4 channels to 4 channels
bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGRA2BGR)
return bg_img
- 유튜브와 깃허브를 보며 코드를 참고했습니다.
https://github.com/kairess/face_detector
3. 결과 출력 및 저장
# 동영상 저장
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
out = cv2.VideoWriter('output.avi', fourcc, 30.0, (int(width*scaler), int(height*scaler))) # VideoWriter 객체 생성
# 반복문 시작
while True: # 프레임이 없으면 break로 종료
ret, img = cap.read() # 동영상 파일에서 frame 단위로 읽기
if not ret:
break
img = cv2.resize(img, (int(img.shape[1]*scaler), int(img.shape[0]*scaler))) # 영상을 띄우기 전에 축소 (int 필수)
ori = img.copy() # 원본 이미지 복사
# 얼굴 인식
faces = detector(img)
# print("발견한 얼굴의 수 :", len(faces)) # 화면 안에 검출된 얼굴의 총개수
face = faces[0] # 찾은 모든 얼굴에서 첫번째 얼굴만 가져옴
# 얼굴의 특징점 찾기
dlib_shape = predictor(img, face)
shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()]) # dlib 객체를 numpy로 변환해서 저장
# 찾은 특징점을 바탕으로 얼굴의 좌상단, 우하단을 구함
top_left = np.min(shape_2d, axis=0)
bottom_right = np.max(shape_2d, axis=0)
face_size = int(max(bottom_right - top_left)*1.8) # 얼굴 크기 (그림이 작아서 곱해서 키움)
center_x, center_y = np.mean(shape_2d, axis=0).astype(int) # 특징점 평균으로 얼굴 중심 구하기
# 투영한 결과물
result = overlay_transparent(ori, overlay, center_x+10, center_y-10, overlay_size=(face_size, face_size))
# 보여주기
# 얼굴의 좌상단부터 우하단까지 rectangle
img = cv2.rectangle(img, pt1=(face.left(), face.top()), pt2 = (face.right(), face.bottom()),
color=(255,255,255), thickness=2, lineType=cv2.LINE_AA)
for s in shape_2d: # 얼굴 특징점의 개수는 68개! (하얀점)
cv2.circle(img, center=tuple(s), radius=1, color=(255,255,255), thickness=2, lineType=cv2.LINE_AA)
# 왼쪽위, 오른쪽 아래 (파란점)
cv2.circle(img, center=tuple(top_left), radius=1, color=(255,0,0), thickness=2, lineType=cv2.LINE_AA)
cv2.circle(img, center=tuple(bottom_right), radius=1, color=(255,0,0), thickness=2, lineType=cv2.LINE_AA)
# 중심점 (빨간점)
cv2.circle(img, center=tuple((center_x, center_y)), radius=1, color=(0,0,255), thickness=2, lineType=cv2.LINE_AA)
cv2.imshow('img', img) # img라는 이름의 윈도우에 img를 띄우기
cv2.imshow('result', result)
out.write(result) # 저장
# cv2.waitKey(1) # 대기
if cv2.waitKey(1) == ord('q'):
break
out.release()
결과영상을 저장하기 위한 코드를 추가해 주었고 합성하려는 이미지의 크기에 맞게 수치를 변경하며 최적의 결과물을 찾아보았습니다.
* 최종 결과물
( 얼굴 특징점에 점을 찍은 결과는 눈에 해로워서 스킵... )
- 작업할 때 가지고 있던 얼굴이 나오는 영상이 이것밖에 없어서 우선 위와 같이 작업하였는데 얼굴의 위치가 움직였다면 더 좋았을 것같다는 생각이 듭니다.
- 다음번에는 여러 사람이 나오는 영상을 합성해봐도 재밌을 것 같습니다!!
'프로젝트' 카테고리의 다른 글
[프로젝트] 서울시 대기오염의 주범은? (0) | 2023.01.24 |
---|---|
[프로젝트] 실시간 수어 번역 인식 모듈 생성 (0) | 2023.01.02 |
[프로젝트] 노래 가사 분석을 통한 인기차트 Top10 예측하기 (8) | 2022.07.29 |
댓글