2016년 8월 15일 월요일

PyCon APAC 2016 - '나의 사진은 내가 지난 과거에 한 일을 알고 있다' 구현


PyCon APAC 에서 들었던 나의 사진은 내가 지난 과거에 한 일을 알고 있다 를 시도해 보았습니다. 요약하면 사진에서 위치정보 및 사람의 표정정보를 추출하여 시각화 하는 내용입니다. 데이터 정제 과정에서 쉬고 있습니다..
순서
    1. 사진 선택
    2. 데이터 정제 - 데이터(위치정보, smile 정보)를 뽑아서 2차원 배열(Dataframe)으로 만든 다음
    3. 시각화 - 지도 상에서 보여주고, 누가 많이 웃었는지 판단한다.

1. 사진 선택

2. 데이터 정제 - 데이터(위치정보, smile 정보)를 뽑아서 2차원 배열(Dataframe)으로 만든 다음
    1) 위치 정보 - python image library 사용
    2) 안면 인식 정보 - Google vision api 사용(구글 계정에 api 사용 등록 필요)












3. 시각화 - 지도 상에서 보여주고, 누가 많이 웃었는지 판단한다.
작성 예정


자료1

Python Image Library 로 사진 로드

from PIL import Image
image = Image.open('C:\\ansan\\test\\160814_google_api_credential\\pycon_jeongwooLEE.JPG')

metadata 인 exif(Exchangeable Image File Format) 추출

exif_data = image._getexif()

import PIL.ExifTags
exif = {
    PIL.ExifTags.TAGS[k]: v
    for k, v in image._getexif().items()
    if k in PIL.ExifTags.TAGS
} 
print exif['GPSInfo']
{1: u'N', 2: ((37, 1), (30, 1), (3516, 100)), \
3: u'E', 4: ((127, 1), (3, 1), (2797, 100)), \
5: '\x00', \
6: (12997, 125), \
7: ((3, 1), (21, 1), (1636, 100)), \
12: u'K', \
13: (0, 1), \
16: u'T', \
17: (22049, 91), \
23: u'T', \
24: (22049, 91), \
29: u'2016:08:14', \
31: (1414, 1)\

자료2


안면 인식 필요 함수 선언

from googleapiclient import discovery
import httplib2
from oauth2client.client import GoogleCredentials
DISCOVERY_URL='https://{api}.googleapis.com/$discovery/rest?version={apiVersion}'


def get_vision_service():
    credentials = GoogleCredentials.get_application_default()
    return discovery.build('vision', 'v1', credentials=credentials,
                           discoveryServiceUrl=DISCOVERY_URL)
import base64
def detect_face(face_file, max_results=4):
    """Uses the Vision API to detect faces in the given file.

Args:
face_file: A file-like object containing an image with faces.

Returns:
An array of dicts with information about the faces in the picture.
"""
    image_content = face_file.read()
    batch_request = [{
        'image': {
            'content': base64.b64encode(image_content).decode('UTF-8')
            },
        'features': [{
            'type': 'FACE_DETECTION',
            'maxResults': max_results,
            }]
        }]

    service = get_vision_service()
    request = service.images().annotate(body={
        'requests': batch_request,
        })
    response = request.execute()
   
    print response['responses']

    return response['responses'][0]['faceAnnotations']
from PIL import Image
from PIL import ImageDraw
def highlight_faces(image, faces, output_filename):
    """Draws a polygon around the faces, then saves to output_filename.

Args:
image: a file containing the image with the faces.
faces: a list of faces found in the file. This should be in the format
returned by the Vision API.
output_filename: the name of the image file to be created, where the faces
have polygons drawn around them.
"""
    im = Image.open(image)
    draw = ImageDraw.Draw(im)

    for face in faces:
        box = [(v.get('x', 0.0), v.get('y', 0.0)) for v in face['fdBoundingPoly']['vertices']]
        draw.line(box + [box[0]], width=5, fill='#00ff00')

    del draw
    im.save(output_filename)


변수 선언 및 안면 인식 함수 사용

input_filename = 'C:\\ansan\\test\\160814_google_api_credential\\baby.JPG'
output_filename = 'baby_output.jpg'
max_results = 1
with open(input_filename, 'rb') as image:
    faces = detect_face(image, max_results)
    print('Found %s face%s' % (len(faces), '' if len(faces) == 1 else 's'))

    print('Writing to file %s' % output_filename)
    # Reset the file pointer, so we can read the file again
    image.seek(0)
    highlight_faces(image, faces, output_filename)

[{u'faceAnnotations': [{u'headwearLikelihood': u'VERY_UNLIKELY', u'panAngle': 1.4963547, u'underExposedLikelihood': u'VERY_UNLIKELY', u'landmarkingConfidence': 0.79059792, u'detectionConfidence': 0.94661051, u'joyLikelihood': u'VERY_UNLIKELY', u'landmarks': [{u'position': {u'y': 449.23465, u'x': 503.81613, u'z': 0.0022879611}, u'type': u'LEFT_EYE'}, {u'position': {u'y': 444.72894, u'x': 597.8515, u'z': 2.5756142}, u'type': u'RIGHT_EYE'}, {u'position': {u'y': 427.36865, u'x': 465.58545, u'z': 10.819963}, u'type': u'LEFT_OF_LEFT_EYEBROW'}, {u'position': {u'y': 418.03116, u'x': 527.02679, u'z': -16.505922}, u'type': u'RIGHT_OF_LEFT_EYEBROW'}, {u'position': {u'y': 416.18243, u'x': 574.16132, u'z': -15.198085}, u'type': u'LEFT_OF_RIGHT_EYEBROW'}, {u'position': {u'y': 420.84039, u'x': 634.37378, u'z': 15.168227}, u'type': u'RIGHT_OF_RIGHT_EYEBROW'}, {u'position': {u'y': 441.13019, u'x': 551.59546, u'z': -19.157124}, u'type': u'MIDPOINT_BETWEEN_EYES'}, {u'position': {u'y': 494.74512, u'x': 554.02673, u'z': -54.059292}, u'type': u'NOSE_TIP'}, {u'position': {u'y': 537.65369, u'x': 554.56073, u'z': -34.004246}, u'type': u'UPPER_LIP'}, {u'position': {u'y': 570.61206, u'x': 556.36188, u'z': -29.879833}, u'type': u'LOWER_LIP'}, {u'position': {u'y': 554.16223, u'x': 525.21643, u'z': -12.002233}, u'type': u'MOUTH_LEFT'}, {u'position': {u'y': 550.5498, u'x': 583.75055, u'z': -10.347378}, u'type': u'MOUTH_RIGHT'}, {u'position': {u'y': 552.26843, u'x': 555.49371, u'z': -27.938482}, u'type': u'MOUTH_CENTER'}, {u'position': {u'y': 505.1066, u'x': 580.81744, u'z': -15.702008}, u'type': u'NOSE_BOTTOM_RIGHT'}, {u'position': {u'y': 508.08328, u'x': 529.22644, u'z': -17.579397}, u'type': u'NOSE_BOTTOM_LEFT'}, {u'position': {u'y': 511.78284, u'x': 554.6908, u'z': -32.374538}, u'type': u'NOSE_BOTTOM_CENTER'}, {u'position': {u'y': 440.61633, u'x': 500.44702, u'z': -5.8014951}, u'type': u'LEFT_EYE_TOP_BOUNDARY'}, {u'position': {u'y': 450.32327, u'x': 519.41406, u'z': 1.0637592}, u'type': u'LEFT_EYE_RIGHT_CORNER'}, {u'position': {u'y': 456.37872, u'x': 503.15567, u'z': -1.3067288}, u'type': u'LEFT_EYE_BOTTOM_BOUNDARY'}, {u'position': {u'y': 451.12354, u'x': 481.49588, u'z': 8.6241531}, u'type': u'LEFT_EYE_LEFT_CORNER'}, {u'position': {u'y': 448.17688, u'x': 499.11456, u'z': -2.023515}, u'type': u'LEFT_EYE_PUPIL'}, {u'position': {u'y': 436.93719, u'x': 601.48419, u'z': -3.1675515}, u'type': u'RIGHT_EYE_TOP_BOUNDARY'}, {u'position': {u'y': 445.92825, u'x': 620.89386, u'z': 12.357953}, u'type': u'RIGHT_EYE_RIGHT_CORNER'}, {u'position': {u'y': 451.51987, u'x': 599.65509, u'z': 1.3407084}, u'type': u'RIGHT_EYE_BOTTOM_BOUNDARY'}, {u'position': {u'y': 447.55365, u'x': 583.93152, u'z': 2.7170076}, u'type': u'RIGHT_EYE_LEFT_CORNER'}, {u'position': {u'y': 444.38281, u'x': 602.76892, u'z': 0.62409711}, u'type': u'RIGHT_EYE_PUPIL'}, {u'position': {u'y': 410.63309, u'x': 495.11249, u'z': -8.0115509}, u'type': u'LEFT_EYEBROW_UPPER_MIDPOINT'}, {u'position': {u'y': 406.6604, u'x': 604.77936, u'z': -5.1472058}, u'type': u'RIGHT_EYEBROW_UPPER_MIDPOINT'}, {u'position': {u'y': 511.14343, u'x': 435.76889, u'z': 117.74801}, u'type': u'LEFT_EAR_TRAGION'}, {u'position': {u'y': 501.62064, u'x': 664.09039, u'z': 123.30409}, u'type': u'RIGHT_EAR_TRAGION'}, {u'position': {u'y': 418.33411, u'x': 550.64563, u'z': -19.225826}, u'type': u'FOREHEAD_GLABELLA'}, {u'position': {u'y': 617.22266, u'x': 557.89929, u'z': -19.451101}, u'type': u'CHIN_GNATHION'}, {u'position': {u'y': 571.94324, u'x': 449.85013, u'z': 70.965286}, u'type': u'CHIN_LEFT_GONION'}, {u'position': {u'y': 564.47369, u'x': 657.51605, u'z': 76.351753}, u'type': u'CHIN_RIGHT_GONION'}], u'sorrowLikelihood': u'VERY_UNLIKELY', u'surpriseLikelihood': u'VERY_UNLIKELY', u'tiltAngle': 5.3879409, u'angerLikelihood': u'VERY_UNLIKELY', u'boundingPoly': {u'vertices': [{u'y': 281, u'x': 385}, {u'y': 281, u'x': 716}, {u'y': 665, u'x': 716}, {u'y': 665, u'x': 385}]}, u'rollAngle': -2.2223928, u'blurredLikelihood': u'VERY_UNLIKELY', u'fdBoundingPoly': {u'vertices': [{u'y': 367, u'x': 429}, {u'y': 367, u'x': 670}, {u'y': 608, u'x': 670}, {u'y': 608, u'x': 429}]}}]}]
Found 1 face
Writing to file baby_output.jpg

댓글 없음:

댓글 쓰기