[Python] 파이썬으로 얼굴의 특징값(Face Landmark) 가져오기

    랜드마크(Landmark)라는 것은 탐험가 혹은 여행가들이 원래의 장소를 돌아오기 위해서 표식을 해두는 것을 말하였지만 현대에 들어서는 유명한 장소를 랜드마크라고 한다. 예를 들어 서울의 랜드마크 중 하나로 63 빌딩, 롯데 타워, 남산 타워 등 다양한 랜드마크들이 있다.

     

    Face Landmark는 얼굴의 특징점을 말한다. 예를 들어 동공의 위치, 입술의 좌표, 눈썹의 좌표 등 이런 값들을 추출하여 x,y 값으로 리턴을 하는데 대표적으로 Python의 라이브러리 중 dlib, opencv로 랜드마크를 추출하는 방법이 있으며 본 포스팅에서는 opencv로 얼굴의 특징점들을 추출하는 것을 보여드리고자 한다.

     

    파이썬으로 얼굴 특징점(Face Landamrk) 가져오기

     

    라이브러리 설치

    pip install dlib
    pip install imutils
    pip install opencv-python

    만약 dlib를 설치하는 동안 에러가 발생한다면, cmake를 설치하도록 한다.

     

    dlib 설치 에러 발생 케이스

     Building wheel for dlib (setup.py) ... error
      ERROR: Command errored out with exit status 1:
       command: 'C:\Anaconda3\envs\face\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\Steel Stark\\AppData\\Local\\Temp\\pip-install-dqgu3zpd\\dlib_21bd53fa22aa4c48be11263b5e29b992\\setup.py'"'"'; __file__='"'"'C:\\Users\\Steel Stark\\AppData\\Local\\Temp\\pip-install-dqgu3zpd\\dlib_21bd53fa22aa4c48be11263b5e29b992\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d 'C:\Users\Steel Stark\AppData\Local\Temp\pip-wheel-97eo8lmv'
           cwd: C:\Users\Steel Stark\AppData\Local\Temp\pip-install-dqgu3zpd\dlib_21bd53fa22aa4c48be11263b5e29b992\
    (face) C:\project\face>pip install cmake
    Collecting cmake
      Downloading cmake-3.18.4.post1-py3-none-win_amd64.whl (34.7 MB)
         |████████████████████████████████| 34.7 MB 6.8 MB/s
    Installing collected packages: cmake
    Successfully installed cmake-3.18.4.post1

    cmake를 설치 후, 다시 dlib를 설치할 때 visual tool 이 설치가 되지 않아 에러가 발생할 수 있다. 이럴 경우 아래의 포스팅을 참고하여 visual tool을 설치한다.

     

    needneo.tistory.com/98

     

    [Python] you need to install visual studio for c++

    dlib를 설치하는 도중, 아래와 같은 에러가 발생하였음 C:\project>pip install dlib Collecting dlib Using cached dlib-19.21.1.tar.gz (3.6 MB) Building wheels for collected packages: dlib Building wheel..

    needneo.tistory.com

     

     

    68개의 얼굴의 특징점

    68개의 얼굴 특징점들

     

    본 포스팅에 사용하는 랜드마크 추출 알고리즘은 다음과 같이 68개의 특징점을 가지고 온다. python 기반의 랜드마크 추출 알고리즘의 아버지격의 포스팅은 

     

    www.pyimagesearch.com/2017/04/03/facial-landmarks-dlib-opencv-python/

     

    Facial landmarks with dlib, OpenCV, and Python - PyImageSearch

    Learn how to detect and extract facial landmarks from images using dlib, OpenCV, and Python.

    www.pyimagesearch.com

    이 포스팅이며 이것을 기반으로 수많은 OpenCV, dlib 랜드마크 프로젝트들이 탄생하고 있다. 

     

    github.com/nicoTrombon/facial-landmarks

     

    nicoTrombon/facial-landmarks

    Facial landmarks with dlib, OpenCV, and Python. Contribute to nicoTrombon/facial-landmarks development by creating an account on GitHub.

    github.com

    그리고 이 깃허브(Github) 프로젝트는 콘솔 기반으로 쉽게 사용하는 것을 보여주고 있다. 본 포스팅에는 argument 부분을 삭제하여 소스 코드 내에 직접 모델과 이미지 경로값을 입력하였다. 본 코드를 실행하기 전에 모델을 가져와야 하는데 [ 여기 ] 를 클릭하여 모델을 저장한 후, 압축을 해제한다. 만약 클릭해도 아무런 반응이 없을 경우 우클릭하여 "다른 이름으로 링크 저장"을 선택하여 저장한다.

     

     

    전체 소스코드

    # Facial landmarks with dlib, OpenCV, and PythonPython
    
    # import the necessary packages
    from imutils import face_utils
    import numpy as np
    import imutils
    import dlib
    import cv2
    
    
    def show_raw_detection(image, detector, predictor):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
        # detect faces in the grayscale image
        rects = detector(gray, 1)
    
        # loop over the face detections
        for (i, rect) in enumerate(rects):
            # determine the facial landmarks for the face region, then
            # convert the facial landmark (x, y)-coordinates to a NumPy
            # array
            shape = predictor(gray, rect)
            shape = face_utils.shape_to_np(shape)
    
            # convert dlib's rectangle to a OpenCV-style bounding box
            # [i.e., (x, y, w, h)], then draw the face bounding box
            (x, y, w, h) = face_utils.rect_to_bb(rect)
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    
            # show the face number
            cv2.putText(image, "Face #{}".format(i + 1), (x - 10, y - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
    
            # loop over the (x, y)-coordinates for the facial landmarks
            # and draw them on the image
            for (x, y) in shape:
                cv2.circle(image, (x, y), 1, (0, 0, 255), -1)
    
        # show the output image with the face detections + facial landmarks
        cv2.imshow("Output", image)
        cv2.waitKey(0)
    
    
    def draw_individual_detections(image, detector, predictor):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
        # detect faces in the grayscale image
        rects = detector(gray, 1)
    
        # loop over the face detections
        for (i, rect) in enumerate(rects):
            # determine the facial landmarks for the face region, then
            # convert the landmark (x, y)-coordinates to a NumPy array
            shape = predictor(gray, rect)
            shape = face_utils.shape_to_np(shape)
    
            # loop over the face parts individually
            for (name, (i, j)) in face_utils.FACIAL_LANDMARKS_IDXS.items():
                # clone the original image so we can draw on it, then
                # display the name of the face part on the image
                clone = image.copy()
                cv2.putText(clone, name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                            0.7, (0, 0, 255), 2)
    
                # loop over the subset of facial landmarks, drawing the
                # specific face part
                for (x, y) in shape[i:j]:
                    cv2.circle(clone, (x, y), 1, (0, 0, 255), -1)
    
                # extract the ROI of the face region as a separate image
                (x, y, w, h) = cv2.boundingRect(np.array([shape[i:j]]))
                roi = image[y:y + h, x:x + w]
                roi = imutils.resize(roi, width=250, inter=cv2.INTER_CUBIC)
    
                # show the particular face part
                cv2.imshow("ROI", roi)
                cv2.imshow("Image", clone)
                cv2.waitKey(0)
    
            # visualize all facial landmarks with a transparent overlay
            output = face_utils.visualize_facial_landmarks(image, shape)
            cv2.imshow("Image", output)
            cv2.waitKey(0)
    
    
    # initialize dlib's face detector (HOG-based) and then create
    # the facial landmark predictor
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
    
    # load the input image, resize it, and convert it to grayscale
    image = cv2.imread('image/tonystark.jpg')
    image = imutils.resize(image, width=500)
    show_raw_detection(image, detector, predictor)
    draw_individual_detections(image, detector, predictor)
    

     

    실행화면

    show_raw_detection

    위 코드는 show_raw_detection으로 한번에 값을 가져오는 것과, draw_individual_detections를 이용하여 개별적으로 가져오기도 한다. 

     

    입술을 가져온 화면

     

    소스가 워낙 쉽고, 필요한 것만 가져오기도 편리하기 때문에 이를 활용하여, 얼굴을 탐지하는 것이라던지 혹은 관상을 볼 수 있게 한다던지 등등 얼굴과 관련된 프로그램을 쉽게 제작할 수 있을 것이다.

     

     

    댓글

    Designed by JB FACTORY