LoginSignup
11
8

More than 3 years have passed since last update.

Python で Microsoft Azure の FaceAPI とPCカメラをリアルタイム接続

Last updated at Posted at 2019-11-12

福岡で開催された学生ハッカソンにて発表した作品です。

概要

  • PCのカメラに映った映像をコマ送りでFaceAPIに送信
  • 判別結果とともにカメラの映像を出力するものとなっています。
  • 判別は性別、年齢、感情分析の結果を反映させています。
  • リアルタイムといいつつ、while文でその時その時の映像を
    写真として切り取っているため、コマ送りの出力結果となりました。
  • 作品と言っておいて、僭越ですがこちらをかなり参考にし、
    ミックスさせたものとなっています。

ソースコード

FaceApi.ipynb
write_file_name = './tmp.jpg'

import http.client, urllib.request, urllib.parse, urllib.error, base64
import json
import matplotlib.pyplot as plt

import cv2
cap = cv2.VideoCapture(0) # 内臓のカメラを取得

#### Request headers
#'Content-Type': APIに送るメディアのタイプ. 
#  'application/json'(URL指定の場合), 
#  'application/octet-stream' (Local ファイル転送の場合)
#'Ocp-Apim-Subscription-Key': APIキーを指定する
headers = {
#    'Content-Type': 'application/json',
    'Content-Type': 'application/octet-stream',
    'Ocp-Apim-Subscription-Key': '[APIキー]',
#APIキー 無料体験版のため、1分間あたりに20回のトランザクション制限
#当時、1週間の無料体験版でキーを2つ取得できた
}

#### Request parameters
# 取得したい情報について、パラメータを指定する
# 'returnFaceId': 入力した顔画像に付与されるIDを返すかどうか
# 'returnFaceLandmarks' : 目や口などの特徴となる部分の座標を返すかどうか
# 'returnFaceAttributes' : 認識した顔からわかる属性を返す
#   指定できるパラメータは以下で、コンマで分けて複数指定可能
#       age, gender, headPose, smile, facialHair, 
#       glasses, emotion, hair, makeup, occlusion, 
#       accessories, blur, exposure and noise
#   今回はage,gender,emotion
params = urllib.parse.urlencode({
    'returnFaceId': 'false',
    'returnFaceLandmarks': 'false',
    'returnFaceAttributes': 'age,gender,emotion'
})

#### Request body
# 入力したい画像の指定をする. 画像URLの指定, local ファイルの指定から選択
# 画像はJPEG, PNG, GIF, BMPに対応
# サイズの上限は4MB
# 認識可能な顔のサイズは 36x36 - 4096x4096 pixelsの範囲
# 最大64個の顔を認識可能

## URL 指定の場合以下のコメントアウトを外すし、image_urlを指定する
#image_url = 'https://XXXXX'
#body = { 'url': image_url }
#body = json.dumps(body)

## Local file指定の場合
# 以下の image_file_path に読み込むファイルのパスを指定する
# image_file_path = '0006601775396431-web.jpg'
# image_file = open(image_file_path,'rb')
# body = image_file.read()
# image_file.close()

#### API request
# 接続先リージョンによっては, 以下HTTPSConnection の "westus.api.cognitive.microsoft.com" 部分は変更する.
# この場合は「westus」なので北米西部リージョン
# なお "/face/v1.0/detect?%s" の部分が接続先APIの機能を指定している

while True:
    key = cv2.waitKey(1)
    # カメラはESCキーで終了できるように。
    if key == 27:
        print("stop!")
        break

    ret, frame = cap.read()
    cv2.imwrite(write_file_name, frame)
    with open(write_file_name, 'rb') as f:
        body = f.read()

# 僕の場合は'westcentralus'でのAPI取得でしたが、ここには自分がキーを取得したリージョンを入れてください
# DATUM STUDIO さんは「westus」なので北米西部リージョンとなっておりました。
    conn = http.client.HTTPSConnection('westcentralus.api.cognitive.microsoft.com')
    conn.request("POST", "/face/v1.0/detect?%s" % params, body, headers)
    response = conn.getresponse()
    data = json.loads(response.read())    #list型

    if len(data) > 0:
        for face in data:
            attr = face["faceAttributes"]
            rect = face['faceRectangle']
            left = rect['left']
            top = rect['top']
            right = left + rect['height']
            bottom = top + rect['width']
            text = attr['gender']+'/'+str(attr['age'])
            emots = attr['emotion']

            cv2.putText(
                    frame,
                    text,
                    (left, top - 10), # 位置を少し調整
                    cv2.FONT_HERSHEY_PLAIN,
                    2,
                    (0, 255,0),
                    2,
                    cv2.LINE_AA
                )

            i = 0
            for emot in emots:
                cv2.putText(
                        frame,
                        emot + ' : ' + str(emots[emot]),
                        (right + 10, top + i*40), # 位置を少し調整
                        cv2.FONT_HERSHEY_PLAIN,
                        2,
                        (225, 0, 225),
                        2,
                        cv2.LINE_AA
                    )
                i += 1

            if attr["gender"] == "male":
                cv2.rectangle(frame, (left, top), (right, bottom), (255, 0, 0), 2)    # male -> blue
            elif attr["gender"] == "female":
                cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 225), 2)    # female -> red

    conn.close()

    %matplotlib inline
    img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    plt.imshow(img)

    blur = cv2.GaussianBlur(frame, (0, 0), 1)
    cv2.imshow('camera capture', blur)

# 一旦画像削除の命令
cap.release()
# カメラが立ち上がっているので、全てのウィンドウを閉じる
cv2.destroyAllWindows()

結果 

年齢と性別の表示

pictures.gif

感情分析

emopic.png

自分の寄与

自分がやったことは、DATUM STUDIO さんの
持っている画像ファイルをFaceAPIに投げるという動作を、
qiitaの記事を参考にPCカメラの映像を随時FaceAPIに投げるへ変更です。

感想

  • まずは出来上がってよかった
  • ただ、もっとスラスラ動くようにしたい
  • 乃木坂の少女たちとバナナマンのおじさんたちの年齢はかなり精度の高い推定
  • 時効警察はいま放送中のものから拝借したのだが、二人とも若すぎる推定結果
  • 霧山修一朗は純度100%の無表情

今回のハッカソで初めてPythonでのHello! Worldの先まで来ましたが、
これを機にPythonの勉強も始めようと思いました!

11
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8