Azure Functions: FaceAPIとOpenCVで顔検出をしてみた。③ -画像の加工-

スクリプトは以下のように作成しました。

coding: utf-8

01‐ライブラリのインポート

import os
import json
import requests
import imghdr
import cv2

def main():

inputimgpath = os.environ["triggerImage"]
result_path = os.environ["resultJson"]
outputimgpath = os.environ["retouchedImage"]

02‐Face API未対応フォーマット判定

print("Checking input image format")
imgformat = imghdr.what(inputimg_path)

if img_format not in ["jpeg", "png", "bmp", "gif"]:
status = {"status": "error"}

if img_format == None:
status["message"] = "Input file is not image."
else:
status["message"] = "Unsupported image format."

print(status)

with open(result_path, "w") as f:
json.dump(status, f, indent=4)

return

03‐Face APIで顔検出

print("Detecting faces")
faceapilocation = "westus"
faceapikey = "3acea513514b46c58f34ac0485e41d5b"

url = "https://{location}.api.cognitive.microsoft.com/face/v1.0/{function}".format(location=faceapilocation, function="detect")

headers = {
"Content-Type": "application/octet-stream",
"Ocp-Apim-Subscription-Key": faceapikey
}

params = {
"returnFaceId": True,
"returnFaceLandmarks": False,
"returnFaceAttributes": "age,gender,smile,emotion"
}

res = requests.request("POST", url, headers=headers, params=params, data=open(inputimgpath, "rb"))
detect_data = res.json()

04‐顔検出結果をJSONで出力

print("Output detect result as JSON.")
with open(result_path, "w") as f:
json.dump(detect_data, f, indent=4)

05‐画像の読み込み

img = cv2.imread(inputimgpath)

06‐検出した顔ごとに枠追加

for faceinfo in detectdata:
#
facerect = {key: value for key, value in faceinfo["faceRectangle"].items()}
facerect["right"] = facerect["left"] + face_rect["width"]
facerect["bottom"] = facerect["top"] + face_rect["height"]

性別で枠の色を変更

if face_info["faceAttributes"]["gender"] == 'female':
line_color = {"r":255,"g":63,"b":255}
elif face_info["faceAttributes"]["gender"] == 'male':
line_color = {"r":63,"g":255,"b":255}

顔の枠描画

cv2.rectangle(
img, (facerect["left"], facerect["top"]), (facerect["right"], facerect["bottom"]),
(linecolor["b"], linecolor["g"], line_color["r"]), 2, 16
)

07‐加工済み画像を保存

print("Save retouched image as {}.".format(img_format.upper()))
imgextention = "." + imgformat
cv2.imwrite(outputimgpath + img_extention, img)
os.rename(outputimgpath + imgextention, outputimg_path)

if _name == "main_":
main()

スクリプトの説明

スクリプトの内容は以下の通りです。「02‐Face API未対応フォーマット判定」~「04‐顔検出結果をJSONで出力」は前回と変わらないため、前回の記事を参照ください。

01‐ライブラリのインポート

処理に必要なライブラリを指定してインポートします。

今回はOpenCVを使って画像の加工を行うため、「cv2」を追加しています。

05‐画像の読み込み

アップロードされた画像をOpenCVで加工可能なNumPy配列として読み込みます。

06‐検出した顔ごとに枠追加

Face APIで検出した顔それぞれについて「faceRectangle」の情報をもとに、顔を検出した位置を示す枠を描画します。判定された性別ごとに異なる色の枠がつくように加工をしています。

07‐加工済み画像を一時保存

加工した画像をファイルに保存します。

OpenCVでは、画像フォーマットが保存する拡張子で決定されますが、Blob出力用のパスには拡張子がないため、直接指定するとエラーが発生します。

そこで、判定した画像フォーマットを拡張子として画像を保存し、画像のパスをBlob出力用にリネームすることでこの問題を回避します。

実行結果

テストとして、男性1人が写ったJPEG画像「face1-01.jpg」をBlobストレージにアップロードしてみます。

アップロードされるとAzure Functionsが起動し、JPEG画像を保存したログが出力されました

アップロードされるとAzure Functionsが起動し、JPEG画像を保存したログが出力されました

Blobストレージを見ると、関数が完了した同時刻に「face1-01result.json」とともに、「face1-01retouched.jpg」のJPEG画像が出力されていました。この画像には、男性を検出したことを示す水色の枠が顔に描画されており、OpenCVで正常に画像加工ができていることがわかりました。

続いて、5人の子供が写ったPNG画像「face5-02.png」をBlobストレージにアップロードしてみます。

Azure Functionsのログでは、PNG画像を保存したログが出力され、フォーマットごとに処理できていることがわかりました。

Azure Functionsのログでは、PNG画像を保存したログが出力され、フォーマットごとに処理できていることがわかりました。

Blobに出力された「face5-02_retouched.png」の画像を確認すると、5人それぞれの顔に枠が描画されていました。子供のため性別判定は甘いですが、性別ごとに色分けもできていることがわかりました。

まとめ

Azure FunctionsとOpenCVを組み合わせることで画像加工アプリケーションを簡単に構成することができました。OpenCVとFace APIの組み合わせでモザイク処理や黒目線処理も簡単にできるため、アップロードするだけで顔にマスク処理をするアプリケーションも作成できます。

この記事を書いた人

azure-recipe-user