본문 바로가기

기타

opencv - 얼굴 각 부위 인식하기

dlib, imutils 패키지를 사용하면 얼굴 사진에서 각 부위를 인식할 수 있다.

나의 경우 눈, 눈썹, 피부색이 필요했는데 이를 한번 추출해보자.

 

0. 준비

pip로 dlib, imutils, opencv를 설치한다. 그리고 shape_predictor_68_face_landmarks.dat 파일을 다운받는다.

http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2

 

1. 이미지 불러와서 얼굴에 68개의 점 찍기

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

img = cv2.imread(image)
rect = self.detector(cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY), 1)[0]

shape = predictor(cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY), rect)#68개의 점 찍기
shape = face_utils.shape_to_np(shape)

opencv는 RGB가 아닌 BGR로 이미지를 다루므로 후에 헷갈릴 것 같아서 Gray Scale로 교체하였다.

 

 

2. 찍은 점 사용하기

shape_predictor_68_face_landmarks.dat 으로 찍은 점의 위치는 다음과 같다.

68개의 점 index

사용하고 싶은 점의 위치를 index로 가져와서 사용하면 된다.

left_cheek = self.img[shape[29][1]:shape[33][1], shape[4][0]:shape[48][0]]
right_cheek = self.img[shape[29][1]:shape[33][1], shape[54][0]:shape[12][0]]

 

3. 쉽게 가져오기

face_utils.FACIAL_LANDMARKS_IDXS 을 사용하면 더 쉽게 좌표를 가져올 수 있다.

(eyeStartLeft, eyeEndLeft) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
(eyeStartRight, eyeEndRight) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]
(eyebrowStartLeft, eyebrowEndLeft) = face_utils.FACIAL_LANDMARKS_IDXS["left_eyebrow"]
(eyebrowStartRight, eyebrowEndRight) = face_utils.FACIAL_LANDMARKS_IDXS["right_eyebrow"]

FACIAL_LANDMARKS_IDXS는 mouth, right_eyebrow, left_eyebrow, right_eye, left_eye, nose, jaw로 구성되어 있고 이를 key로 불러오면 된다.

 

4. 클래스

관련 코드를 찾다보니 클래스로 만들어놓은 코드가 있어서 약간 수정해보았다.

class DetectFace:
    def __init__(self, image):
        self.detector = dlib.get_frontal_face_detector()
        self.predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

        #face detection part
        self.img = cv2.imread(image)
        if self.img.shape[0]>500:
            self.img = cv2.resize(self.img, dsize=(0,0), fx=0.8, fy=0.8)

        # init face parts
        self.right_eyebrow = []
        self.left_eyebrow = []
        self.right_eye = []
        self.left_eye = []
        self.left_cheek = []
        self.right_cheek = []
	
        # detect the face parts and set the variables
        self.detect_face_part()

    # return type : np.array
    def detect_face_part(self):
        face_parts = [[],[],[],[],[],[],[],[]]
        # detect faces in the grayscale image
        rect = self.detector(cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY), 1)[0]

        # determine the facial landmarks for the face region, then
        # convert the landmark (x, y)-coordinates to a NumPy array
        shape = self.predictor(cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY), rect)#68개의 점 찍기
        shape = face_utils.shape_to_np(shape)

        idx = 0
        # loop over the face parts individually
        for (name, (i, j)) in face_utils.FACIAL_LANDMARKS_IDXS.items():
            face_parts[idx] = shape[i:j]
            idx += 1
        face_parts = face_parts[1:5]
        # set the variables

        self.right_eyebrow = self.extract_face_part(face_parts[0])
        self.left_eyebrow = self.extract_face_part(face_parts[1])
        self.right_eye = self.extract_face_part(face_parts[2])
        self.left_eye = self.extract_face_part(face_parts[3])

        self.left_cheek = self.img[shape[29][1]:shape[33][1], shape[4][0]:shape[48][0]]
        self.right_cheek = self.img[shape[29][1]:shape[33][1], shape[54][0]:shape[12][0]]

    def extract_face_part(self, face_part_points):
        (x, y, w, h) = cv2.boundingRect(face_part_points)
        crop = self.img[y:y+h, x:x+w]
        adj_points = np.array([np.array([p[0]-x, p[1]-y]) for p in face_part_points])

        # Create an mask
        mask = np.zeros((crop.shape[0], crop.shape[1]))
        cv2.fillConvexPoly(mask, adj_points, 1)
        mask = mask.astype(np.bool)
        crop[np.logical_not(mask)] = [255, 0, 0]

        return crop

'기타' 카테고리의 다른 글

keras load_model함수 버전 오류  (0) 2020.09.26
[패키지]dlib 설치하기  (0) 2020.09.08