[Python] Practice_OpenCV(활용편)

프로젝트 : 얼굴을 인식하여 캐릭터 씌우기

  • MediaPipe 검색 및 홈페이지 접근 후 Face Detection 이부분의 예제 코드를 사용

Face Detection vs Face Recognition

패키지 설치

pip install mediapipe

예제 동영상 : https://www.pexels.com/video/3256542/

크기 : Full HD (1920 x 1080)

파일명 : face_video.mp4

캐릭터 이미지 : https://www.freepik.com/free-vector/cute-animal-masks-video-chat-application-effect-filters-set_6380101.htm

파일명 : right_eye.png (100 x 100), left_eye.png (100 x 100), nose.png (300 x 100)

무료 이미지 편집 도구 : https://pixlr.com/kr/

(Pixlr E -Advanced Editor)

import cv2
import mediapipe as mp

def overlay(image, x, y, w, h, overlay_image): # 대상 이미지 (3채널), x, y 좌표, width, height, 덮어씌울 이미지 (4채널:투명도를 가짐)
    alpha = overlay_image[:, :, 3] # BGRA
    mask_image = alpha / 255 # 0 ~ 255 -> 255 로 나누면 0 ~ 1 사이의 값 (1: 불투명, 0: 완전투명)
    # (255, 255)  ->  (1, 1)
    # (255, 0)        (1, 0)
    
    # 1 - mask_image ? 위와 서로 반전된 값
    # (0, 0)
    # (0, 1)
    
    # 즉, 완전 투명(0)은 1-mask_image 곱해서 쓰고, 불투명(1)은 overlay_image를 가져다 쓴다라고 이해
    # 불투명(1)이면 image부분은 곱하면 0이 될테니까!!
    for c in range(0, 3): # channel BGR
        image[y-h:y+h, x-w:x+w, c] = (overlay_image[:, :, c] * mask_image) + (image[y-h:y+h, x-w:x+w, c] * (1 - mask_image))

# 얼굴을 찾고, 찾은 얼굴에 표시를 해주기 위한 변수 정의
mp_face_detection = mp.solutions.face_detection # 얼굴 검출을 위한 face_detection 모듈을 사용
mp_drawing = mp.solutions.drawing_utils # 얼굴의 특징을 그리기 위한 drawing_utils 모듈을 사용

# 동영상 파일 열기
cap = cv2.VideoCapture('face_video.mp4')

# 이미지 불러오기(참고 : 그림판으로 만든 이미지로 먼저 하고나서, 삭제하고 캐릭터 사진 다운받은걸로 함.(기존꺼 삭제한거라 제목 동일))
image_right_eye = cv2.imread('right_eye.png', cv2.IMREAD_UNCHANGED) # 100 x 100
image_left_eye = cv2.imread('left_eye.png', cv2.IMREAD_UNCHANGED) # 100 x 100
image_nose = cv2.imread('nose.png', cv2.IMREAD_UNCHANGED) # 300 x 100 (가로, 세로)

# model_selection은 근거리는 0, 조금 먼거리는 1로 설정
# min_detection_confidence는 얼굴 인식 신뢰도 설정(현재 70%)
with mp_face_detection.FaceDetection(model_selection=0, min_detection_confidence=0.7) as face_detection:
    while cap.isOpened():
        success, image = cap.read()
        if not success: # 영상 끝나면
            break # 탈출

        # To improve performance, optionally mark the image as not writeable to
        # pass by reference.
        image.flags.writeable = False
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # BGR을 RGB로 바꾸는 작업
        results = face_detection.process(image)

        # Draw the face detection annotations on the image.
        image.flags.writeable = True
        image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # RGB를 BGR로 바꾸는 작업
        
        if results.detections:
            # 6개 특징 : 오른쪽 눈, 왼쪽 눈, 코 끝부분, 입 중심, 오른쪽 귀, 왼쪽 귀 (귀구슬점, 이주)
            for detection in results.detections:
                # mp_drawing.draw_detection(image, detection) # 얼굴에 네모난 영역 그려줌
                # print(detection) # 6개의 위치를 좌표로 뽑아줌
                
                # 특정 위치 가져오기
                keypoints = detection.location_data.relative_keypoints # detection출력했을때 나오는 dict의 키값으로 접근하는것
                right_eye = keypoints[0] # 오른쪽 눈
                left_eye = keypoints[1] # 왼쪽 눈
                nose_tip = keypoints[2] # 코 끝부분
                
                # detection출력했을때 좌표가 x:0.39~~, y:0.35~~ 이런식으로 나오기 때문에(비율)
                # image에서의 실제 좌표를 구하는 것을 해야한다.
                h, w, _ = image.shape # height, width, channel : 이미지로부터 세로, 가로 크기 가져옴
                right_eye = (int(right_eye.x * w) - 20, int(right_eye.y * h) - 100) # 이미지 내에서 실제 좌표 (x, y) : 튜플로 저장
                left_eye = (int(left_eye.x * w) + 20, int(left_eye.y * h) - 100)
                nose_tip = (int(nose_tip.x * w), int(nose_tip.y * h))
                
                # 양 눈에 동그라미 그리기
                # cv2.circle(image, right_eye, 50, (255, 0, 0), 10, cv2.LINE_AA) # 파란색
                # cv2.circle(image, left_eye, 50, (0, 255, 0), 10, cv2.LINE_AA) # 초록색                
                # 코에 동그라미 그리기
                # cv2.circle(image, nose_tip, 75, (0, 255, 255), 10, cv2.LINE_AA) # 노란색
                
                # 각 특징에다가 이미지 그리기(직접 그림판의 그린 그림 넣는중)                
                #image[right_eye[1]-50:right_eye[1]+50, right_eye[0]-50:right_eye[0]+50] = image_right_eye
                #image[left_eye[1]-50:left_eye[1]+50, left_eye[0]-50:left_eye[0]+50] = image_left_eye
                #image[nose_tip[1]-50:nose_tip[1]+50, nose_tip[0]-150:nose_tip[0]+150] = image_nose
                
                # image, x, y, w, h, overlay_image(캐릭터 그림 넣는중, 영상의 image는 채널:4라서 3과 안맞아서 overlay함수 따로 만들어서 사용)
                overlay(image, *right_eye, 50, 50, image_right_eye)
                overlay(image, *left_eye, 50, 50, image_left_eye)
                overlay(image, *nose_tip, 150, 50, image_nose)
                
        # Flip the image horizontally for a selfie-view display.
        cv2.imshow('MediaPipe Face Detection', cv2.resize(image, None, fx=0.5, fy=0.5))
        
        if cv2.waitKey(1) == ord('q'):
            break
            
cap.release()
cv2.destroyAllWindows()

댓글남기기