[python-numpy] 인물사진에서 턱 각도 구하기

[python-numpy] 인물사진에서 턱 각도 구하기

2015, Oct 25    

(이미지 출처: theqoo)

##[python-numpy] 인물사진에서 턱 각도 구하기</h2> 요새 패캠의 머신러닝을 이용한 추천엔진제작 CAMP를 듣고 있습니다. 첫 2주동안 유사도 관련 이론 학습 및 실습을 진행하면서 인물 얼굴간 유사도를 구해봤습니다. 실습에서는 얼굴 길이, 너비, 코 크기 등을 변수로 활용했는데, 턱 각도를 구할 수 있다면 하나의 유의미한 변수로 쓸 수 있지 않을까 싶었습니다. 갸름한 턱, 사각턱, 오각형턱 등 턱의 종류도 다양하니까요. 문제를 단순화해서 2차원 평면 상에 3가지 점(2개의 선)이 주어졌을 때 이들이 만드는 교차각을 구해봤습니다.

##3개 점이 만드는 교차각 구하기 단순화한 문제는 정말 단순해보였지만, 실제로 그것을 일반화한 공식을 쉽게 떠올리지 못했습니다. 3개의 점이 깔끔하게 x축, y축 위에 있지 않고 중구난방으로 퍼져있다면 어떻게 모든 경우에 대응할 수 있을까. 파이썬으로 구현하는 방식도 쉽게 떠오르지 않아 결국 관련된 기본 수학을 다시 찾아보기로 했습니다 ㅠㅠ. 요새 머신러닝 관련 글이나 수업을 들으면서 벡터라는 단어를 정말 많이 들어보는데, 이것 역시 정확한 정의를 알 수 없어 같이 찾아봤습니다.

벡터에도 여러 정의가 있고 물리학적, 수학적 정의가 조금씩 달랐습니다. 초보적인 수준에서 이해의 편의를 위해 사이즈와 방향을 동시에 가지는 값으로 벡터를 정의하고, 스칼라는 사이즈(magnitude)만을 가진 값으로 알고 당장은 넘어가기로 합니다. 여기서 개략적인 개념을 찾아볼 수 있었습니다.

3개 점이 만드는 교차각을 구하는 방식은 아래와 같이 요약할 수 있습니다.

  1. 3개 점을 기반으로 한 2개 선을 만들고, 각각의 기울기를 구합니다.
  2. 기울기1 - 기울기2 / (1 + 기울기1 * 기울기2)를 구하고 x라 명명합니다.
  3. x의 arctan을 구합니다.

##재료 준비 - 인물 사진 이번 튜토리얼에서 사용할 인물 사진을 구해봅니다. 요새 자주보는 개그맨 정성호님의 성대모사 영상 중 하나를 구해봤습니다. 턱의 각도는 시선에 따라 달라질 수 있으므로 되도록 정면샷을 준비해봅시다.

재료 - 조철왕 코스프레를 하는 정성호님 / 출처: SNL KOREA

이 이미지를 웹에서 사용하기 위해 imgur같은 서비스에 올려 direct link를 땁니다. ‘http://i.imgur.com/zaX7Sbr.jpg’

##face++에서 인물 랜드마크를 JSON 파일로 저장하기 face++는 인물 사진에서 주요 키포인트를 뽑아주는 아주 유용한 사이트입니다. Demo > Face Landmark 메뉴로 이동합니다.

face++ 화면

아까 땄던 direct link를 url입력창에 넣고 랜드마크를 뽑아봅니다.

face++ 정성호님 랜드마크

눈 양쪽 끝에서 시작해서 턱선을 따라 라인이 잡힙니다. 그리고 눈썹, 눈, 코, 입에도 주요 키포인트가 잡혔습니다. 우측 RESPONSE JSON에 보면 2차원 벡터값으로 주요 키포인트가 정량화되서 출력됩니다. {부터 끝까지 드래그해서 텍스트에디터에 JSON(jsh.json)파일로 저장합니다. 이제 자료 준비가 끝났습니다.

##ipython notebook 개발환경 세팅 먼저 개발환경을 구축합니다. 예전에는 그냥 터미널에서 파이썬을 돌렸는데, ipython notebook을 사용하면 훨씬 더 편하고 간결하게 파이썬을 사용할 수 있습니다.

맥에서의 설치는 아래와 같이 하면 됩니다.

###1. 인스톨러 파일 다운받기

Anaconda사이트에서 원하는 버전의 파이썬 설치를 위한 파일을 다운받습니다. 이번 튜토리얼부터는 파이썬 3.4를 사용했습니다. 인스톨러 파일을 다운받고 바로 밑에 표시된 OS X Anaconda Installation를 따라가면 설치가 완료됩니다.
###2. 필요한 라이브러리 설치하기

아나콘다를 통해 파이썬을 설치하면 과학계산을 위한 기본적인 라이브러리가 다 설치된다고 하지만 아닌 경우 아래와 같은 명령어를 터미널에서 돌리면 됩니다.

conda install numpy #numpy 라이브러리 설치
conda install pandas #pandas 라이브러리 설치


###3. ipython 실행하고 콘솔 열기

터미널에서 ipython notebook 명령어를 입력하면, 웹브라우져에 로컬환경의 ipython notebook이 실행됩니다. 우측 상단의 New를 누르고 Python 3을 눌러 콘솔 창을 활성화시킵니다.

ipython notebook 실행화면

##데이터프레임 잡기

###1. 필요한 라이브러리 불러오기

일단 JSON 파일을 읽어오기 위한 json, 그리고 분석을 위해 numpy, pandas를 import합니다.

import json #json 라이브러리 불러오기
import numpy as np #numpy를 불러와서 np로 이름붙임(기니까)
import pandas as pd #pandas 불러오기
from pandas import DataFrame, Series #pandas 세부 모듈을 더 쉽게 불러오기


###2. json 파일 불러오기

with open('jsh.json') as data_file:
	data = json.load(data_file)


###3. DataFrame으로 저장하기

landmark_data = data['result'][0]['landmark'] #json파일에서 랜드마크 데이터가 있는 곳을 찾아 내려갑니다.
ldf = DataFrame.from_dict(landmark_data) #pandas의 DataFrame 형태로 dict를 불러와서 ldf로 저장합니다.
ldf_T = ldf.T #ldf는 columns가 랜드마크로 되어있으므로, 이를 index로 돌리기 위해 trasnpose를 합니다.
ldf_T.head() #뽑은 데이터의 상위 5개 row를 확인합니다.

ldf_T 상위 5개 row

##턱 각도 계산하기

###1. angle 함수 정의하기

def angle(topPoint, midPoint, botPoint):
	topLineSlope = (midPoint.y - topPoint.y) / (midPoint.x - topPoint.x) #기울기1 구하기
	botLineSlope = (midPoint.y - botPoint.y) / (midPoint.x - botPoint.x) #기울기2 구하기
	x = (abs(topLineSlope - botLineSlope)) / (1 + topLineSlope * botLineSlope) #x 구하기
	angle_rad = np.arctan(x) #x의 arctan값 구하기 / 구하면 radian값이 나옵니다.
	angle_deg = np.degrees(angle_rad) #radian값을 degree값으로 바꿔줍니다.
	if angle_deg < 90: #교차각이 2개 나오므로, 90도보다 작은 각이 나오면 180도에서 이를 뺀 각을 교차각 최종값으로 정의합니다.
		angle_result = 180 - angle_deg
	else:
		angle_result = angle_deg
	return angle_result #함수의 리턴값을 정의합니다.


###2. 양측 턱의 평균값 함수의 정의하기

def avg__angle(df):
	#6개의 점을 잡아줍니다. 
	#left1은 왼편 눈 근처 턱 끝, left9은 턱 중심점 왼편의 턱 끝입니다.
	#여기서는 편의를 위해 1, 5, 9점을 잡았지만,
	#얼마든지 값을 변경하여 원하는 각도를 잴 수 있습니다.
	l_pt1 = df_loc['contour_left1']
	l_pt2 = df_loc['contour_left5']
	l_pt3 = df_loc['contour_left9']
	r_pt1 = df_loc['contour_right1']
	r_pt2 = df_loc['contour_right5']
	r_pt3 = df_loc['contour_right9']
	#위에서 정의한 함수를 불러옵니다.
	l_angle = angle(l_pt1, l_pt2, l_pt3)
	r_angle = angle(r_pt1, r_pt2, r_pt3)
	print ("왼쪽 턱 각도: %f | 오른쪽 턱 각도: %f" %(l_angle, r_angle))
	result = (l_angle + r_angle) / 2
	return result
	


###3. 함수 실행하기

avg_angle(ldf_T)

턱 각도 최종 아웃풋 조철왕 코스프레를 한 정성호의 턱 각도는 평균 152도로 나왔네요. 원래 사진과 비교해보면 각도가 달라질까요? 다음에 더 자세히 얼굴간 유사도를 비교해보겠습니다.

##완료! 전체 코드 및 샘플에 사용한 json 파일은 여기 링크에서 확인할 수 있습니다.