2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Microsoft Azure Cognitive ServicesAdvent Calendar 2020

Day 9

誰でも使えるAI:Azure Cognitive ServiceのFaceをWordPressに導入してみた

Last updated at Posted at 2020-12-09

#■はじめに:Azure Cognitive Service - Face
Azure Cognitive Service の中の Face という面白いクラウドAIサービスがあります。公式サイトの紹介文では、

アプリに顔認識を埋め込んで、高度なセキュリティで保護されたシームレスなユーザー エクスペリエンスを実現できます。機械学習に関する専門知識は不要です。画像内の顔と属性を認識する顔検出、最大 100 万人のプライベート リポジトリ内の人物と照合する個人識別、さまざまな表情 (喜び、軽蔑、中立、恐怖など) を検出する感情認識、画像内での似た顔の認識とグループ化などの機能があります。

とあります。

普段、WordPressでは、素材画像や記事作成時に画像を登録することが多く、結構、顔の画像もあったりするので、Faceサービスで登録された顔画像を解析してみると、結構、面白そうな感じがしたので、早速、WordPressに実装してみました。

注:WordPress環境は、既に構築済みという前提での記事となります。WordPressとは何ぞや?という方は、下記リンクをご参照ください。

 ・Wikipedia:WordPress
 ・WordPress公式サイト

#■類似のCognitive Service
Faceの公式ドキュメントには、

注意:顔検出機能は Computer Vision サービスでもご利用いただけます。 ただし、顔のデータを使ってさらに操作を行いたい場合は、代わりにこのサービスを使用する必要があります。

とあります。

●Computer Vision:こちらのサービスでも顔の検出は可能なのですが、

・年齢
・性別
・顔の位置

のみ検出してくれるのですが、Faceサービスは、顔画像から、

・メガネをかけているか
・笑顔 or 怒り顔

などなど、色々な特徴を検出してくれるスグレモノです。

●Content Moderator:こちらのサービスでも画像から色々と検出してくれるのですが、公式ドキュメントによると、

Content Moderator のコンピューター支援型画像モデレーションとレビュー ツールを使用して、成人向けコンテンツとわいせつなコンテンツの画像をモデレートします。 テキスト コンテンツの画像をスキャンしてそのテキストを抽出し、顔を検出します。 カスタム リストと画像を照合し、さらにアクションを実行できます。

と記載がありますが、こちらも試してみたいですが、xxxxxxxxな画像はストックしておりませんので・・・・・。

#■Face APIで検出してくれる項目
公式ドキュメントでは、Face APIで検出してくれる項目の一覧が記載されています。

項目 概要 詳細
年齢 特定の顔の推定年齢
ぼかし 画像内の顔のぼかしの程度 この属性は、0 から 1 までの間の値と、非公式の評価 (低、中、または高) を返します
感情 感情のリストと特定の顔に対する検出の信頼度 信頼度スコアは正規化され、すべての感情スコアの合計は 1 になります。返される感情は、喜び、悲しみ、中立、怒り、軽蔑、嫌悪感、驚き、恐怖です
露出 画像内の顔の露出の程度 この属性は、0 から 1 までの間の値と、非公式の評価 (underExposure、goodExposure、または overExposure) を返します
顔ひげ 特定の顔について推定される顔ひげの有無と長さ
性別 特定の顔について推定される性別 可能な値は、男性、女性、および性別なしです
眼鏡 特定の顔に眼鏡があるかどうか 可能な値は、NoGlasses、ReadingGlasses、Sunglasses、および Swimming Goggles です
髪の毛 顔の髪質 この属性は、髪の毛が見えるかどうか、はげが検出されたかどうか、どのような髪の色が検出されたかを示します
頭部姿勢 3次元空間での顔の向き この属性は、ピッチ、ロール、およびヨー角度 (度数) で表現されます。 値の範囲は、それぞれ -90 度から 90 度、- 90 度から 90 度、-90 度から 90 度です
化粧 顔に化粧があるかどうか この属性は eyeMakeup および lipMakeup についてのブール値を返します
ノイズ 顔の画像で検出された視覚ノイズ この属性は、0 から 1 までの間の値と、非公式の評価 (低、中、または高) を返します
オクルージョン 顔のパーツをブロックするオブジェクトがあるかどうか この属性は、eyeOccluded、foreheadOccluded、および mouthOccluded についてのブール値を返します
笑顔 特定の顔の笑顔表現 この値は、0 (笑顔なし) から 1 (鮮明な笑顔) までです

#■注意点
公式ドキュメントに注意点が記載されています。

重要:顔属性は統計的アルゴリズムを使用して予測されます。 必ずしも正確とは限りません。 属性データに基づいて意思決定を行う場合は、注意が必要です。

#■WordPress実装時の検討事項
FaceサービスをWordPressに実装するにあたり、WordPressからFace APIを叩く際の検討事項についてです。

●WordPress側
1.デザインテンプレートにFace APIを叩く処理を実装して固定ページに実装
2.WordPress管理画面に機能追加
3.プラグインを独自開発してWordPress上のどこでも使えるように実装

の選択肢がありますが、今回は1と2で実装することにしました。

●Face APIを叩く選択肢
1.公式サイトのクイックスタートで紹介されているPHPのサンプルを参考にFace APIを叩く
2.公式サイトのクイックスタートで紹介されているJavascriptのサンプルを参考にFace APIを叩く
3.cURLでFace APIを叩く

の選択肢がありますが、PHPのサンプルを見ると、PearのHTTP_Request2が必要だったり、JavascriptのサンプルだとJqueryが必要だったりするのと、1つの画像に対してFace APIを叩くだけのサンプルでしたので、今回は、WordPressに登録されている画像全部に対して、cURLでFace APIを叩くことにしました。

●Face APIに投げる画像
公式ドキュメントには、

・サポートされている入力画像形式は、JPEG、PNG、GIF (最初のフレーム)、BMP です。
・画像ファイル サイズは 6 MB 以内であることが必要です。
・検出可能な顔のサイズの範囲は、36 x 36 ~ 4096 x 4096 ピクセルです。 この範囲に含まれない顔は検出されません。
技術的な課題のために、一部の顔を検出できない場合があります。 顔の角度 (頭部姿勢) や顔のオクルージョン (顔のパーツをブロックするサングラスや手などの物体) が極端に大きい場合、検出に影響することがあります。 顔が正面または正面に近い方向を向いているときに、最善の結果が得られます。

と記載されていますので、画像ファイルのサイズや天地サイズに注意する必要があります。

#■作業手順01:Azureリソース作成
●Azure Faceのリソース作成
まずは、AzureポータルでFaceリソースを作成します。
azure-face-dashboard-00.png

●キーとエンドポイント
cURLで必要なのでメモしておきます。
azure-face-dashboard-02.png

●価格レベル
まずは、F0 Freeでやってみます。
azure-face-dashboard-03.png

#■作業手順02:WordPressに実装:1.デザインテンプレートにFace APIを叩く処理を実装して固定ページに実装
WordPressへの組み込み方法は、色々ありますが、今回は使っているデザインテーマにデザインテンプレートを1つ追加、そこにFace APIを叩くPHPコードを記述していきます。(2020/12/12:WordPress管理画面への追加方法を【追記】しました)

●デザインテンプレート作成:
最初に、azure-face-api.phpというファイル名で作成し、SFTPなどを使って、WordPressが稼働しているサーバの

・/wp-content/themes/xxxxxx/azure-face-api.php

にアップロードしておきます。なお、デザインテンプレートですので、下記の内容を記述しておきます。

azure-face-api.php
<?php
//Template Name:Azure Face API
/**
*
* The template for displaying all azure-face-api
*
*/
 get_header();
?>
//ここにコードを記述します
<?php
get_footer();

WordPress管理画面でテンプレートが読み込まれていることを確認します。
wordpress-dashboard-01-new.png

●固定ページを作成してデザインテンプレートを適用
次に、WordPress管理画面->固定ページ->新規追加で、固定ページを作成します。赤枠の[ページ属性]の設定ウィジェットで、作成したデザインテンプレートを適用します。
wordpress-pages-01.png

#■cURL書式
####●Request URL
基本の書式です。

書式
Request URL:
https://{endpoint}/face/v1.0/detect[?returnFaceId][&returnFaceLandmarks][&returnFaceAttributes][&recognitionModel][&returnRecognitionModel][&detectionModel]

####●cURL書式
公式サイトに掲載されています(エンドポイントが古いママです)。

公式サイトのサンプル
curl -v -X POST "https://xxxxxxxxxx.cognitive.microsoft.com/face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes={string}&recognitionModel=recognition_03&returnRecognitionModel=false&detectionModel=detection_02" -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription key}" --data-ascii "{body}" 

####●今回のFace APIに投げる予定のcURL

顔の情報取得
curl -H "Ocp-Apim-Subscription-Key: xxxxxxxxxxxxxxxxxxxxx" "https://xxxxxxxxxxxx.xxxxxxxxxx.azure.com/face/v1.0/detect?detectionModel=detection_02&returnFaceId=true&returnFaceLandmarks=false" -H "Content-Type: application/json" --data-ascii "{\"url\":\"https://xxxxxxxxxxx/xxxxxxxxxx.jpg\"}"
顔の属性抽出
curl -H "Ocp-Apim-Subscription-Key: xxxxxxxxxxxxxxxxxxxxx" "https://xxxxxxxxxxxx.xxxxxxxxxx.azure.com/face/v1.0/detect?detectionModel=detection_01&returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise" -H "Content-Type: application/json" --data-ascii "{\"url\":\"https://xxxxxxxxxxx/xxxxxxxxxx.jpg\"}"

#■PHPコード
●デザインテンプレート上にコーディング
次に、WordPress管理画面->外観->テーマエディタ画面に遷移、先程作成したデザインテンプレートにコードを埋め込みます。
wordpress-dashboard-01-neo.png

●PHPコード
今回、WordPressに実装したPHPのコードですが、

・Face APIのエンドポイントやキーを登録
・WordPressに登録されている画像をお好みの件数を取得
・ループで一覧表示
・各画像に対してFaceサービスAPIを叩く処理
・JSONを見やすく整形

という内容になっています。

azure-face-api.php
<?php
//Template Name:Azure Face API
/**
*
* The template for displaying all azure-face-api
*
*/
 get_header();
?>
<div id="content" class="site-content">
	<div class="container">

<?php 
$endpoint = "https://xxxxxxxxxxxxxxxxxxx.azure.com";
$baseurl01 = $endpoint . "/face/v1.0/detect?detectionModel=detection_02&returnFaceId=true&returnFaceLandmarks=false"; //顔の情報取得
$baseurl02 = $endpoint . "/face/v1.0/detect?detectionModel=detection_01&returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise"; //顔の属性抽出

$api_headers = array(
"Ocp-Apim-Subscription-Key: xxxxxxxxxxxxxxxxx",
"Content-Type: application/json; --data-ascii"
);

$args = array(
  'post_type' => 'attachment', 
  'post_status' =>'inherit', 
  'post_mime_type' => 'image', 
  'posts_per_page' => 4 //値を小さくします
);

$image = new WP_Query($args); 
?>

<h1>Face API Demo</h1>

<section>
<table border="1">

 <tr>
  <th>File Name</th><th>Image</th><th>Face API Response</th>
 </tr>

<?php if ($image->have_posts()) : ?>
  <?php while ($image->have_posts()) : $image->the_post(); ?>

     <tr>
      <td width="30%"><?php the_title(); ?></td>
      <td width="20%"><?php echo the_attachment_link(key($images)); ?></td>
      <td>
       <div align="left">
	 <?php
	  $image_url = wp_get_attachment_url(post_custom('image'));
	  $facecurl = curl_init();
	  $faceparams = array();
	  $faceparams["url"] = $image_url;
	  $json = json_encode($faceparams);
	  curl_setopt($facecurl, CURLOPT_URL, $baseurl01); 
	  curl_setopt($facecurl, CURLINFO_HEADER_OUT, true);
	  curl_setopt($facecurl, CURLOPT_HTTPHEADER, $api_headers);
	  curl_setopt($facecurl, CURLOPT_POSTFIELDS, $json);
	  curl_setopt($facecurl, CURLOPT_RETURNTRANSFER, true);
	  $res = curl_exec($facecurl);
	  curl_close($facecurl); 
	  echo "<pre>".json_encode(json_decode($res), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
	 ?>
       </div>
      </td>
     </tr>
  <?php endwhile; ?>
<?php endif; ?>
</table>
</section>
<?php wp_reset_postdata(); ?> 
	</div>
</div>

<?php
get_footer();


注:posts_per_pageの値を大きくし過ぎると、大量の画像に対して一気にFaceサービスAPIを叩くことになってしまい、怒られます(後述)

#■レスポンス01:顔検出
curl_setoptをbaseurl01にしてAPIを叩いています。いい感じに応答がありますね。

response-A-01.png

●レスポンスについて
一番上の画像(ポーズを決めた執刀医)の他、二番目の画像(歯の治療中の顔)は顔検出が難しそうですが、きちんとレスポンスが返却されますね。さらに、三番目の画像(歯科医と患者)の複数の人物が写っている画像も、きちんと人数分の顔検出のレスポンスが返却されますね。

3番目の画像のresponse
[
    {
        "faceId": "e58726bc-651d-421e-836a-b68e668590b5",
        "faceRectangle": {
            "top": 218,
            "left": 473,
            "width": 128,
            "height": 128
        }
    },
    {
        "faceId": "21e6477a-6ccb-41ad-bd83-5faa27ad4ece",
        "faceRectangle": {
            "top": 58,
            "left": 419,
            "width": 106,
            "height": 142
        }
    }
]

#■レスポンス02:顔の属性抽出
curl_setoptをbaseurl02に変更してAPIを叩いています。いい感じに応答がありますね。

response-B-01.png

response02

[
    {
        "faceId": "7c5ca8a0-fa5b-4440-9b3a-f81bd8806a47",
        "faceRectangle": {
            "top": 36,
            "left": 48,
            "width": 40,
            "height": 40
        },
        "faceAttributes": {
            "smile": 0.017,
            "headPose": {
                "pitch": 1,
                "roll": -2.1,
                "yaw": -39.9
            },
            "gender": "male",
            "age": 37,
            "facialHair": {
                "moustache": 0.4,
                "beard": 0.4,
                "sideburns": 0.1
            },
            "glasses": "NoGlasses",
            "emotion": {
                "anger": 0,
                "contempt": 0.001,
                "disgust": 0,
                "fear": 0,
                "happiness": 0.017,
                "neutral": 0.979,
                "sadness": 0.002,
                "surprise": 0
            },
            "blur": {
                "blurLevel": "low",
                "value": 0
            },
            "exposure": {
                "exposureLevel": "overExposure",
                "value": 0.9
            },
            "noise": {
                "noiseLevel": "low",
                "value": 0
            },
            "makeup": {
                "eyeMakeup": false,
                "lipMakeup": false
            },
            "accessories": [
                {
                    "type": "headwear",
                    "confidence": 0.99
                }
            ],
            "occlusion": {
                "foreheadOccluded": true,
                "eyeOccluded": false,
                "mouthOccluded": false
            },
            "hair": {
                "bald": 0,
                "invisible": true,
                "hairColor": []
            }
        }
    }
]			

#■レスポンス03:検出できない事象

問題発生です。一番目の執刀医の画像の顔の検出と特徴抽出はOKだったのですが、

・二番目の口を開けている歯の治療中の患者の画像:顔の検出と特徴抽出NG
・歯科医と患者の複数の人物の画像:顔の検出と特徴抽出NG
・ポーズを決めたベテラン医師の画像:顔の検出と特徴抽出NG

という結果になりました。

response-B-02-new.png

Facen 公式ドキュメントにも注意書きがありますが、

技術的な課題のために、一部の顔を検出できない場合があります。 顔の角度 (頭部姿勢) や顔のオクルージョン (顔のパーツをブロックするサングラスや手などの物体) が極端に大きい場合、検出に影響することがあります。 顔が正面または正面に近い方向を向いているときに、最善の結果が得られます。

ポーズを決めたベテラン医師の画像は、顔のパーツをブロックするサングラスや手などの物体なので、特徴抽出NGなのですね・・・・・。

#■怒られた

posts_per_pageの値を大きくして実行したところ、大量の画像に対して一気にFaceサービスAPIを叩いてしまい、怒られてしまいました。

error-response
Response 429
application/json
{
    "error": {
       "code": 429,
        "message": "Request to the Face - Detect Operation under Face API - v1.0 have exceeded rate limit of your current Face F0 pricing tier. Please retry after 14 seconds. To increase your rate limit switch to a paid tier."
    }
}

F0で稼働させているので、チビチビ消費しないと・・・・・。

azure-face-dashboard-01-new.png

#■まとめ
cURLでAPIを叩くことができるので、お手軽に実装出来ました。時間があれば、APIから返却されたJSONレスポンスから各種データを切り出して、CSSを生成して顔画像に顔位置の枠を表示させたりしたいですね。

つかいどころ:IoT関連
Raspberry Piに小型カメラをセットして、定期的に撮影して画像を投稿としてWordPressにrest apiで送信して、Face APIで解析できそうですね。

#■謝辞:顔検出に利用した画像について
顔検出に利用した画像はWordPressの無料デザインテーマに付属している画像を使用しました。この場を借りてお礼申し上げます。

WordPressテーマ:Gutener Medical
作者: keonthemes

#■追記:実装する場所(2020/12/12追記)

WordPressにFace APIを実装する場所ですが、

●公開エリアに実装する場合:
・WordPressの固定ページに実装:Ultimate Memberプラグインを利用して認証して、ログインした特定ユーザのみ実行可能としましょう

●非公開エリアに実装する場合:
・WordPressの管理画面内に実装、管理画面にアクセス可能なユーザのみ実行可能にしましょう。

こちらもやっておきましょう:エンドポイントへのアクセス制限:
[Cognitive Services のエンドポイントへのアクセス制限 ~ ファイアウォール機能を試す]
(https://qiita.com/annie/items/9dc39785a429d713327f)

#■追記:WordPress管理画面に機能追加(2020/12/12追記)
WordPress管理画面への追加方法ですが、利用しているデザインテーマのfunctions.phpにPHPコードを記述します。

●WordPress管理画面への実装結果:左メニューの赤枠の箇所に追加されています。
face-api-wp-adminpanel-01-new.png

●デザインテーマのfunctions.phpに実装:右メニューの赤枠のfunctions.phpを選択してPHPコードを記述します。
face-api-wp-adminpanel-03-new.png

functions.php
// add azure face api menu
add_action( 'admin_menu', 'azure_face_api_menu_page' );
function azure_face_api_menu_page() {
add_menu_page('Azure Face API', 'Azure Face API', 'manage_options', 'azurefaceapi', 'add_azure_face_api_page', 'dashicons-admin-generic','2');
}

// add azure face api page
function add_azure_face_api_page() {

$endpoint = "https://xxxxxxxxxx.azure.com";
$baseurl01 = $endpoint . "/face/v1.0/detect?detectionModel=detection_02&returnFaceId=true&returnFaceLandmarks=false"; //顔の情報取得
$baseurl02 = $endpoint . "/face/v1.0/detect?detectionModel=detection_01&returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise"; //顔の属性抽出

$api_headers = array(
"Ocp-Apim-Subscription-Key: xxxxxxxxxx",
"Content-Type: application/json; --data-ascii"
);
$args = array(
  'post_type' => 'attachment', 
  'post_status' =>'inherit', 
  'post_mime_type' => 'image', 
  'posts_per_page' => 4
);
$image = new WP_Query( $args ); 
	
echo '
<h1>Azure Face API</h1>
    <table border="1">
	<tr>
		<th>File Name</th><th>Image</th><th>Face API Response</th>';

if ( $image->have_posts() ) : 
 while ( $image->have_posts() ) : $image->the_post(); 

	echo '<tr>';
		echo '<td width="30%">'; the_title(); echo '</td>';
		echo '<td width="20%">'; echo the_attachment_link(key($images)); echo '</td>';
		echo '<td><div align="left">';
			
			$image_url = wp_get_attachment_url(post_custom('image'));
			$facecurl = curl_init();
			$faceparams = array();
			$faceparams["url"] = $image_url;
			$json = json_encode($faceparams);
			curl_setopt($facecurl, CURLOPT_URL, $baseurl02); // If you want to change ENDPOINT
			curl_setopt($facecurl, CURLINFO_HEADER_OUT, true);
			curl_setopt($facecurl, CURLOPT_HTTPHEADER, $api_headers);
			curl_setopt($facecurl, CURLOPT_POSTFIELDS, $json);
			curl_setopt($facecurl, CURLOPT_RETURNTRANSFER, true);
			$res = curl_exec($facecurl);
			curl_close($facecurl); 
			echo "<pre>".json_encode(json_decode($res), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
			
			echo '</div></td>';
	echo '</tr>';
  endwhile; 
endif;

echo '</table>';
	wp_reset_postdata();

}

#■リソース

・[クイック スタート:REST API と PHP を使用して画像内の顔を検出する]
(https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/php)
・[クイック スタート:REST API と JavaScript を使用して画像内の顔を検出する]
(https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/javascript)
・[クイック スタート :Face REST API と cURL を使用して画像から顔を検出する]
(https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/curl)
(何故かデッドリンクというか別ページにリダイレクトされます)
Cognitive Service API Reference:CURLのコードサンプル


2
0
0

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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?