스마트폰의 카메라를 사용해 보셨다면 한번쯤은 얼굴 인식 기능을 경험해 보셨을 겁니다. 최근 카메라의 얼굴 인식 기능은 매우 중요한 기능이 되었습니다. 얼굴을 자동으로 인식하고 초점을 맞추거나 태그를 만들어 주기도 합니다.

얼굴 인식 기술은 여러 가지 모델이 제안되었는데 OpenCV의 Harr Cascades와 dlib의 HOG (Histogram of Oriented Gradients) 가 대표적인 모델입니다. 여기서는 dlib의 HOG 방식을 사용 할 것입니다.

참고

이미지에서 얼굴을 찾기 위해 이미지를 Grayscale로 바꾸는 것부터 시작합니다. 왜냐하면 얼굴을 찾는데 색상 데이터는 필요 없기 때문입니다.

모든 단일 픽셀에 대해 이를 직접 둘러싸고 있는 픽셀을 살펴봅니다.

단일 픽셀을 둘러싸고 있는 픽셀들과 비교해서 얼마나 어두운지 알아낸 다음 이미지가 어두워지는 방향을 나타내는 화살표를 그려 나갑니다.

이미지의 모든 픽셀에 대해 이 프로세스를 반복하면 결국 모든 픽셀이 화살표로 바뀌게 됩니다. 이러한 화살표들을 그래디언트 (gradients)라고 부르고, 이를 통해 전체 이미지에서 밝은 부분으로부터 어두운 부분으로의 흐름을 알 수 있습니다.

모든 단일 픽셀에 대해 그래디언트를 저장하면 너무 자세하기 때문에 이미지를 16X16 픽셀의 작은 정사각형으로 분해하여 기본 패턴을 알 수 있도록 합니다. 결과적으로, 우리는 원본 이미지를 얼굴의 기본 구조가 심플한 방법으로 표시되는 매우 간단한 표현(representation)으로 변환되게 됩니다.

이 HOG 이미지에서 얼굴을 찾기위해 많은 훈련 얼굴 이미지로부터 추출 된 HOG 패턴과 가장 유사하게 보이는 부분을 이미지에서 찾는 것입니다.

 

이미지에서 얼굴의 위치를 찾아 냈지만 얼굴이 다른 방향을 보고 있으면 전혀 다르게 판단하기 때문에 이미지에서 비틀어 눈과 입술이 항상 표준 위치에 올 수 있도록 해야 합니다.

그렇게 하기 위해서, face landmark estimation이라고 하는 알고리즘을 사용합니다. 모든 얼굴에 존재하는 68개의 랜드마크(landmarks)라 부르는 특정 포인트(턱의 상단, 눈 바깥의 가장자리, 눈썹 안쪽의 가장자리, 등)를 찾아 내는 것입니다. (68개의 랜드마크 이외에도 여러 포인트로 정의된 랜드마크 방식이 존재함)

 

[ 참고 ] Machine Learning is Fun! Part 4: Modern Face Recognition with Deep Learning


Python과 dlib을 이용하여 간단하게 얼굴 검출(face detection) 기능을 구현하는 방법을 소개하도록 하겠습니다. 직접적으로 dlib을 사용해도 되지만 여기서는 Python의 face recognition 라이브러리를 이용하도록 하겠습니다. face recognition은 간단한 얼굴 인식 라이브러리로 dlib기반으로 구축되었습니다. face recognition에서 사용되는 모델은 Labeled Faces in the Wild 기준으로 99.38%의 정확도를 가진다고 소개하고 있네요.

전체 Source는 Github에 확인 하실 수 있습니다.

우선, dlib이 이미 설치가 되어 있어야 합니다. 만약 설치되어 있지 않다면 dlib 설치가이드를 참고하시여 설치를 진행하시기 바랍니다.

1. Install

pip install face_recognition

2. Import Packages

from imutils import face_utils
import matplotlib.pyplot as plt
import numpy as np
import argparse
import imutils
import dlib
import cv2

import face_recognition

3. Function

Colab 또는 Jupyter Notebook에서 이미지를 확인하기 위한 Function입니다.

def plt_imshow(title='image', img=None, figsize=(8 ,5)):
    plt.figure(figsize=figsize)

    if type(img) == list:
        if type(title) == list:
            titles = title
        else:
            titles = []

            for i in range(len(img)):
                titles.append(title)

        for i in range(len(img)):
            if len(img[i].shape) <= 2:
                rgbImg = cv2.cvtColor(img[i], cv2.COLOR_GRAY2RGB)
            else:
                rgbImg = cv2.cvtColor(img[i], cv2.COLOR_BGR2RGB)

            plt.subplot(1, len(img), i + 1), plt.imshow(rgbImg)
            plt.title(titles[i])
            plt.xticks([]), plt.yticks([])

        plt.show()
    else:
        if len(img.shape) < 3:
            rgbImg = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        else:
            rgbImg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

        plt.imshow(rgbImg)
        plt.title(title)
        plt.xticks([]), plt.yticks([])
        plt.show()

4. Declare a face detector

# face_landmark_path = 'lib/landmark/shape_predictor_68_face_landmarks.dat'
# predictor = dlib.shape_predictor(face_landmark_path)
detector = dlib.get_frontal_face_detector()
predictor = face_recognition.api.pose_predictor_68_point

5. Load Image

image_path = 'asset/images/2021_g7.jpg' 
org_image = cv2.imread(image_path) 
image = org_image.copy() 
image = imutils.resize(image, width=500) 
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 

rects = detector(gray, 1)

6. Face detection

for (i, rect) in enumerate(rects):
    # 얼굴 영역의 얼굴 랜드마크를 결정한 다음 
    # 얼굴 랜드마크(x, y) 좌표를 NumPy Array로 변환합니다.
    shape = predictor(gray, rect)
    shape = face_utils.shape_to_np(shape)
    
    # dlib의 사각형을 OpenCV bounding box로 변환(x, y, w, h)
    (x, y, w, h) = face_utils.rect_to_bb(rect)
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    cv2.putText(image, "Face #{}".format(i + 1), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
    
    # 얼굴 랜드마크에 포인트를 그립니다.
    for (i, (x, y)) in enumerate(shape):
        cv2.circle(image, (x, y), 1, (0, 255, 255), -1)
        # cv2.putText(image, str(i + 1), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.2, (255, 255, 255), 1)
        
plt_imshow("Output", image, figsize=(16,10))

얼굴 검출은 매우 잘되는 것 같습니다. 다만 옆모습이거나 얼굴이 일부 가려진 경우에는 인식을 못하는 경우도 있습니다.


갑자기 여기 이 사진 속 사람들 몇명일까..? 하는 생각이 들어서 수행해 보았습니다. (와..많네요..@.@)

수행 결과 입니다. 112명...이라고 나오네요. 물론 고개를 숙이고 있거나 얼굴이 가려진 사람들은 인식을 하지 못했습니다. 하지만 이 결과를 보면서 사람이 하는일을 편하게 하거나 손쉽게 하는 방법이 있을거라는 생각은 드네요.


조금 더 나아가서..

위에 결과를 확인 할 수 있듯이 옆모습이거나 얼굴이 가려진 경우에는 인식이 안된다는 걸 알 수 있습니다. 다음 글에는 dlib보다 좀 더 나은 방법을 소개 하도록 하겠습니다.

반응형