こんにちは!AMDlabの掛田です。
今回はGoogle Cloudが提供するCloud Vision APIの一部の機能である顔の検出を触っていきます。
顔の検出は画像から人を検出し、感情に関する情報を解析できる機能です。
感情は可能性を表す以下の種類が返されます。
- UNKNOWN
- VERY UNLIKELY
- UNLIKELY
- POSSIBLE
- LIKELY
- VERY LIKELY
Cloud Vision APIを利用するために必要なこと
今回の記事では細かい下準備は省略しますが、ザッと以下の手順が必要になります。
- Google Cloudでプロジェクトの作成
- 作成したプロジェクトでCloud Vision APIの有効化
- 請求先情報の登録(無料で使用できる範囲を超えた場合の請求先情報)
- サービスアカウントの作成
- 秘密鍵の作成
Cloud Vision APIの料金ページには以下のように記載されており、少し使う程度なら無料で利用できそうですね。
課金は画像ごとに発生します。PDF ファイルなど、ファイルに複数のページがある場合、各ページがそれぞれ個別の画像として扱われます。
画像に対して適用される機能は、それぞれが請求対象となる「ユニット」です。たとえば、1 つの画像に対して顔検出とラベル検出を適用した場合、1 ユニットのラベル検出と 1 ユニットの顔検出に対して料金が請求されます。
以下の表は、各機能の 1,000 ユニット単位の料金を示しています。段階的料金体系となっており、毎月最初の 1,000 ユニットについては無料で、1,001~5,000,000 ユニット、およびそれ以上のユニットについては下記のように請求される仕組みになっています。
引用元: https://cloud.google.com/vision/pricing/
秘密鍵の作成
サービスアカウントを作成したら、APIとサービス画面に表示されるメールアドレス(画像では黒で塗りつぶしてる箇所)をクリック。
タブの「キー」をクリックし、「鍵を追加」>「新しい鍵を作成」を選択。
秘密鍵の形式を選択できるのでJSONを選択。
作成すると、自動的にお使いのパソコンにJSONファイルが保存されるので、コマンドで以下を実行します。
1 |
export GOOGLE_APPLICATION_CREDENTIALS=JSONファイルの絶対パス |
実際に触ってみる
今回はパソコンに保存されている画像のパスを.envファイルに記述し、プログラムから取得して使用します。
.env
1 |
IMAGE_PATH=画像ファイルの絶対パス |
コマンドで以下を実行し、必要なライブラリをインストールします。
1 2 |
pip install python-dotenv # 環境変数を使用する際に必要です pip install google-cloud-vision |
こちらのリンクに公式のサンプルコードがあるので、Pythonのコードを使用します。
.envから情報を取得する記述は自分で書いています。
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import os import io from dotenv import load_dotenv from google.cloud import vision def detect_faces(path): client = vision.ImageAnnotatorClient() with io.open(path, 'rb') as image_file: content = image_file.read() image = vision.Image(content=content) response = client.face_detection(image=image) faces = response.face_annotations likelihood_name = ('UNKNOWN', 'VERY_UNLIKELY', 'UNLIKELY', 'POSSIBLE', 'LIKELY', 'VERY_LIKELY') print('Faces:') for face in faces: print('anger: {}'.format(likelihood_name[face.anger_likelihood])) print('joy: {}'.format(likelihood_name[face.joy_likelihood])) print('surprise: {}'.format(likelihood_name[face.surprise_likelihood])) vertices = (['({},{})'.format(vertex.x, vertex.y) for vertex in face.bounding_poly.vertices]) print('face bounds: {}'.format(','.join(vertices))) if response.error.message: raise Exception( '{}\nFor more info on error messages, check: ' 'https://cloud.google.com/apis/design/errors'.format( response.error.message)) load_dotenv('.env') detect_faces(os.environ['IMAGE_PATH']) |
解析の対象とする画像
こちらのサービスでダウンロードできる画像を対象とします。
まず一枚目のネコの画像の方から。
実行結果
1 |
Faces: |
プログラム的にはFaces:の後ろに感情に関する情報が出力されるはずですが、ネコしか写っていないのでそもそも人が検出できなかったということですね。
それでは、二枚目の人が写っている画像で試してみます。
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Faces: anger: VERY_UNLIKELY joy: VERY_UNLIKELY surprise: VERY_UNLIKELY face bounds: (147,61),(253,61),(253,185),(147,185) anger: UNLIKELY joy: VERY_UNLIKELY surprise: VERY_LIKELY face bounds: (341,7),(466,7),(466,153),(341,153) |
二人分の感情と座標の情報が出力されました。
公式チュートリアルによると、この座標は顔を囲むための座標のようです。
二人のうちどちらの情報か分からないので、座標を使用して元画像の顔を囲ってみます。
顔を囲った画像を保存して、同階層に感情の情報を書き込んだJSONファイルを保存します。
画像を操作するために下記のコマンドでライブラリをインストールします。
1 |
pip install pillow |
顔を囲って画像を書き出すプログラム自体は先程の公式チュートリアルにあるので、それを使用します。
修正後のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
import os import io import json from dotenv import load_dotenv from PIL import Image, ImageDraw from google.cloud import vision def detect_faces(path, output_image_dir): client = vision.ImageAnnotatorClient() with io.open(path, 'rb') as image_file: content = image_file.read() image = vision.Image(content=content) response = client.face_detection(image=image) faces = response.face_annotations for index, face in enumerate(faces): image_file_name = os.path.basename(path) image_file_name_removed_ext = os.path.splitext(image_file_name)[0] # ファイル名から拡張子を除外 output_dir_contain_index = '{}/{}-{}'.format(output_image_dir, image_file_name_removed_ext, index) if not os.path.exists(output_dir_contain_index): # 保存先のディレクトリを作成 os.makedirs(output_dir_contain_index) # 顔を囲んだヒトの画像を書き出し output_image_path = '{}/{}'.format(output_dir_contain_index, image_file_name) highlight_face(path, face, output_image_path) # 感情のJSONファイルを書き出し json_file_name = '{}.json'.format(image_file_name_removed_ext) output_json_path = '{}/{}'.format(output_dir_contain_index, json_file_name) dump_emotion_json(face, output_json_path) if response.error.message: raise Exception( '{}\nFor more info on error messages, check: ' 'https://cloud.google.com/apis/design/errors'.format( response.error.message)) def highlight_face(image_path, face, output_path): im = Image.open(image_path) draw = ImageDraw.Draw(im) # Sepecify the font-family and the font-size box = [(vertex.x, vertex.y) for vertex in face.bounding_poly.vertices] draw.line(box + [box[0]], width=5, fill='#00ff00') # Place the confidence value/score of the detected faces above the # detection box in the output image draw.text(((face.bounding_poly.vertices)[0].x, (face.bounding_poly.vertices)[0].y - 30), str(format(face.detection_confidence, '.3f')) + '%', fill='#FF0000') im.save(output_path) def dump_emotion_json(face, output_path): likelihood_name = ('UNKNOWN', 'VERY_UNLIKELY', 'UNLIKELY', 'POSSIBLE', 'LIKELY', 'VERY_LIKELY') emotion_dict = { 'anger': likelihood_name[face.anger_likelihood], 'joy': likelihood_name[face.joy_likelihood], 'surprise': likelihood_name[face.surprise_likelihood], } with open(output_path, 'w') as f: json.dump(emotion_dict, f) load_dotenv('.env') detect_faces(os.environ['IMAGE_PATH'], os.environ['OUTPUT_IMAGE_DIR']) |
実行結果
出力された画像と感情のJSONファイル
1 2 3 4 5 |
{ "anger": "VERY_UNLIKELY", "joy": "VERY_UNLIKELY", "surprise": "VERY_UNLIKELY" } |
1 2 3 4 5 |
{ "anger": "UNLIKELY", "joy": "VERY_UNLIKELY", "surprise": "VERY_LIKELY" } |
男性の方はsurpriseがVERY_LIKELYなので画像の通りとてもビックリしてますね。
これで感情の情報が二人のうちどちらのものか分かるようになりました。
今回触ったのはCloud Vision APIの顔の検出のみですが、
画像やPDFからテキストを検出できたりと他にも機能があるので試してみたいですね。
COMMENTS