얼굴추적

Sam (토론 | 기여)님의 2021년 9월 25일 (토) 21:27 판 (→‎준비)

1 개요

주 방법은 링크, 링크(얼굴인식 스노우 카메라 따라만들기)를 참고하였습니다.

단순히 찾는 것 뿐이라면 cv2만으로도 가능하지만, 매끄럽게 처리하려면 dlib이 있어야 좋다.

2 방법

2.1 준비

과정 코드 및 설명
model 디렉터리에 모델 준비하기 이후 이 디렉터리 안의 모델을 사용한다.
사용할 모듈 설치 및 불러오기 pip install CMake dlib opencv-python numpy
  • 윈도우에선 visual studio 설치가 선행되어야 한다.(설치 옵션에서 C++ 모듈을 포함하게 하면 관련 컴파일러 등이 함께 설치된다.)
cmake는 dlib를 설치하기 위해 필요하다.
import dlib  # 얼굴인식
import cv2  # 이미지처리
import numpy as np  # 연산
과정 코드 및 설명
모델객체 생성
detector = dlib.get_frontal_face_detector()  # 얼굴탐지모델
predictor = dlib.shape_predictor('models/shape_predictor_68_face_landmarks.dat')  # 얼굴 랜드마크 탐지 모델. 학습된 모델을 가져온다.

2.2 얼굴 찾기

# 영상 캡쳐
cap = cv2.VideoCapture('영상경로')  # 경로 대신 0을 넣으면 웹캠이 켜진다.

def find_face(cap)
    ret, img = cap.read()  # 캡처한 영상을 프레임 단위로 읽는다.  
    if not ret:
        break  # 프레임이 없다면 종료.
    faces = detector(img)  # 디텍터에 이미지를 넣어주어 얼굴을 찾는다.
    face = faces[0]  # 인식된 얼굴 중 첫번째.
    
    # 인식이 잘 되었는지 확인. 네모 그리기.
    # 기본 이미지에 덧씌워 보여준다.
    # 좌 상단과 우 하단을 잡아준다.
    img = cv2.rectangle(img, pt1=(face.left(), face.top()), pt2=(face.right(), face.bottom)
            color=(255,255,255),    # 색 지정이 가능하다.
            thickness=2,            # 두께지정
            lineType=cv2.LINE_AA    # 선의 타입 지정
            )
    
    
    
    cv2.imshow('창이름', img)  # 창에 해당하는 이미지를 띄운다.
    cv2.waitKey(1)  # 1ms만큼 대기 해야 창이 제대로 열린다.
    
    
    
    
while True:  # 기본적으로 계속 진행
    find_face(cap=cap)

2.3 얼굴 특징점 찾기

얼굴 찾기를 진행한 후 진행한다.

def find_shape(img, face)  # img가 꼭 필요할까?
    dlib_shape = predictor(img, face)  # 특징점을 리턴받는다.
    
    shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()])  # 연산을 위해 배열로 저장.
    for s in shape_2d:  # 해당 좌표에 원 그리기. 68개의 특징점을 찾는다.
        cv2.circle(img, center=tuple(s), radius=1, color=(255, 255, 255), thickness=2, lineType=cv2.LINE_AA)

2.4 얼굴을 특정 이미지로 가리기

def blind_face(img, address='파일경로.png')
    dlib_shape = predictor(img, face)  # 특징점을 리턴받는다.
    shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()])  # 연산을 위해 배열로 저장.
    
    center_x, center_y = np.mean(shape_2d, axis=0).astype(np.int)
    overlay = cv2.imread(address, cv2.IMREAD_UNCHANGED)  # 알파채널까지 읽기 위한 옵션.
    
    # compute face size
    face_size = max(max_coords - min_coords)
    face_sizes.append(face_size)
    if len(face_sizes) > 10:  # 덮을 이미지가 얼굴 인식에 따라 급격하게 변하기 때문에, 이를 중화하기 위한 코드.
        del face_sizes[0]
    mean_face_size = int(np.mean(face_sizes) * 1.8)  # 얼굴을 적절히 덮기 위한 보정.
    ori = img.copy()
    # 다음 사용하는 함수는 아랫쪽에 정의되어 있다.
    result = overlay_transparent(background_img=ori,    # 기존 이미지.
                    img_to_overlay_t=overlay,           # 덮을 이미지.
                    center_x + 8, center_y - 25,        # 얼굴의 중심을 찾고 숫자로 보정해준다.
                    overlay_size=(mean_face_size, mean_face_size))

    
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