MoreBeerMorePower

Power Platform中心だけど、ノーコード/ローコード系を書いてます。

写真から表情を読み取って最適なスタンプを合成するLogic Appsをつくる

今回はこのブログではよく紹介しているCloudmersive の画像処理APIと、写真から顔の検出や表情の読み取りをAIが行ってくれるMicrosoft AzureのFace API を利用して、XXXXに写真を保存すると自動的に人物の顔に表情を表すスタンプを押した画像を保存するLogic Appsを紹介します。

プライバシーの点から、「顔出しはちょっと・・・」な場合の写真を投稿するのにも使えるかも!

0. 目次

  1. Cloudmersive の登録とAPIキー取得
  2. Face API設定
  3. Logic Apps作成

まずは仕組みのカギである「Cloudmersive」の登録とAPIキーの取得をご紹介します。今回はLogic Appsにはまだ追加されていないAPIを利用するので、HTTPアクションでAPIを呼び出しします。

次に「Face API」の設定をしていきます。Cloudmersiveにも顔の位置を検出するAPIはあるのですが、表情までは読み取ってくれないので今回はMicrosoft Azureにあるサービス「Face API」を採用しました。

最後に、メインである顔検出&表情読み取り→スタンプ合成のLogic Appsを紹介します。ここ、今回は本当にノーコードです!!いつもは数式結構使っていますが、今回は本当にノーコードです!!(大事なことなので)

1. Cloudmersive の登録とAPIキー取得

はじめに、「Cloudmersive」の利用登録を行います。Cloudmersiveのサイト (https://cloudmersive.com/) 右上に表示されている「Sign up」をクリックします。作成するアカウント情報の入力が促されますが、ここではGmailMicrosoftアカウントでの登録も可能です。

今回はMicrosoftアカウントでセットアップしていきます。「Sign in with Microsoft」をクリックするとアカウントへのアクセスを求める画面が表示されるので、「Accept」(または「はい」)をクリックします。

f:id:mofumofu_dance:20201003112245p:plain
Cloudmersiveのサイト。Microsoftアカウントでの登録も可能

続いてプランの選択画面です。月間で利用できるAPIコール数や秒間のコール数、画像加工・ファイル操作に利用するファイルサイズの上限に応じてプランが分かれています。今回紹介する処理程度であればフリープランで問題ない範囲ですので、「Free Tier」を選びます。

f:id:mofumofu_dance:20201003112910p:plain
プランの選択。今回はFree Planで進めます。

プランを選択すると、「あなたのロールは?」「どのAPIを使う?」「何で作り始める?」という具合にいろいろ質問されます。Cloudmersiveの各サービスでAPIキーは共通ですし、どこで使うかも影響しませんので適当なものを回答してください。

質問に答え終わるとAPIキーの作成画面が表示されます。この画面で「Create Key」を押すとAPIキーが発行されるので、これを後で出てくるLogic AppsのHTTPアクションに利用します。

以上でCloudmersiveのセットアップは完了です。

f:id:mofumofu_dance:20201003114650p:plain
APIキーの発行。いつでも左のメニュー「API Key」から取得できます。

2. Face API設定

保存された画像の顔検出と表情の分析にはMicrosoft Azureの「Face API」を利用します。Logic Appsでもコネクターがありますし、非常に手軽に写真内の顔の座標と笑顔度を読み取ってデータ化してくれる機能を含んだサービスです。

まずMicrosoft Azure にログインします。アカウントがない場合にも無料アカウントを作成できます。 (https://azure.microsoft.com/ja-jp/free/)

画面上部の「Create Resource」をクリックしてサービス検索画面に移動します。

f:id:mofumofu_dance:20201003120152p:plain
Microsoft Azureトップ画面。「Create Resource」から新規リソースを追加する。

検索画面が表示されたら検索ボックスに「Face」と入力し、表示された候補から「Face」を選択します。 Face APIを利用するためのリソース作成画面が表示されるので、「Create」をクリックします。

f:id:mofumofu_dance:20201003120748p:plain
作成するリソースの検索画面。「Face」を選びリソースを作成する。

続いてリソースの詳細設定画面が表示されます。それぞれ以下のように指定してください。

  • Subscription : 手持ちのものをドロップダウンから選択。無料アカウントであれば「無料試用版」
  • Resource group : 今回は新規作成。名前は適当なもので。
  • Region : Japan East
  • Name : インスタンス名。ここはグローバルにユニークでないといけないので、被らなそうな名前を付けます。
  • Pricing Tier : 今回は無料の範囲で問題ないので、「Free F0」を選択。

入力結果に問題がなければ、画面下部の「Review+create」をクリックしてください。作成が完了すると「Your deployment is complete」と表示されるので、「Go to resource」をクリックして作成されたFace APIのリソースを確認します。

f:id:mofumofu_dance:20201003121157p:plain
リソースの詳細設定画面。Pricing TierはFreeを選ぶ。

リソースの情報画面の左に表示されたメニューから「Keys and Endpoint」をクリックすると、Face APIを実行するために必要なAPI キーとURLが表示されます。

これらの情報は後でLogic Appsのコネクターを設定する際に利用するので、別タブで残しておきましょう。

f:id:mofumofu_dance:20201003122907p:plain
Face APIAPIキーおよびEndpoint (URL) 表示。このページは別タブで残しておく。

以上でFace APIを実行するための準備は完了です。

3. Logic Apps作成

いよいよ本題のLogic Apps作成です。今回のLogic Appsでは、大きく3つの処理パートから構成されています。

  1. 保存した画像のURL取得とFace API実行
  2. 保存した画像と顔に押すスタンプ画像のコンテンツ取得
  3. 検出した顔へのスタンプ合成 (ループ処理)

今回はトリガーになる画像の置き場所としてAzure Blobストレージを利用しています。ここはDropboxやOneDriveでも問題ありませんが、Face APIを実行するためには認証なしで接続できるURLが必要だったので、ほかのストレージをトリガーにする場合でも、一度Blobにコピーするような処理を入れるとよいでしょう。

それぞれ解説していきますが、その前に Logic Appsを新規作成しておきます。 Face APIの場合と同様に、リソースを新規作成しますがその際検索ボックスには「Logic App」と入力してください。ほかの手順はFace APIと同様です。

f:id:mofumofu_dance:20201003172542p:plain
Logic Appsの全体像。大きく3つのパートで構成されている。

3-1. 保存した画像のURL取得とFace API実行

Logic Appsを作っていきます。最初はBlobストレージへのファイル登録をトリガーとします。トリガーの中から「Azure Blob Storage」コネクターの「When a blob is added or modified (properties only)」アクションを追加します。

このトリガーでは、ファイル追加・変更を検出する対象のフォルダーと、追加・変更をチェックする間隔を設定できます。 下図のようなフォルダー構成をBlobストレージに用意しておいて、トリガーには次のように設定します。

  • Container : /files/FaceIN/
  • Number of blobs... : 1 (トリガーの結果返すファイルは1つ)
  • How often... : 1 Minute (1分ごとに追加・変更をチェック)

これでトリガーの設定はできました。

f:id:mofumofu_dance:20201003141000p:plain
トリガーとBlobストレージの構成

Face APIを実行するためには、特別な認証を必要としないURL (ブラウザのアドレスバーに入れたらすぐ画像が表示されるようなURL) が必要になります。トリガーにより検出されたファイルに対して、このようなURLを発行するためにBlobストレージのアクション「Create SAS URI by path」を追加します。

「Blob path」にはトリガーで得られる結果「List of Files Path」を動的コンテンツから指定します。先ほど、トリガーの結果返すファイルを1つにしているので、これだけでファイルのパスが指定できます。

f:id:mofumofu_dance:20201003142612p:plain
Face APIに渡すためのURL作成

次にFace API をLogic Appsに追加します。アクションの追加から「Face API」コネクターの「Detect faces」アクションを追加します。初回はFace APIへの接続情報の入力(コネクション作成)が発生します。 #2 で開いておいたFace APIの接続情報から、APIキーとEndpointをコピーして貼り付けてください。

f:id:mofumofu_dance:20201003144014p:plain
Face API 初回追加時のコネクション作成

コネクションが作成されると、追加したアクション「Detect faces」の設定が表示されます。「Image Url」には前のアクションで作成された「Web Url」を指定します。

ここまでで、『Blobストレージの特定のフォルダーにファイルが追加されたら、その画像の顔検出・表情分析を行う』という処理が構成できました。なお、Face APIの結果としては主に以下の要素が得られます。

  • 顔を四角く囲った時の左上の座標
  • 顔の高さ・幅
  • 笑顔度 (0~1)

1枚の写真から複数の顔が検出されうるため、これが人数分入った配列がデータとして返却されます。

f:id:mofumofu_dance:20201003135256p:plain
Face APIの「Detect faces」アクションで取れる主な要素

以上で最初のブロックは完了です。

3-2. 保存した画像と顔に押すスタンプ画像のコンテンツ取得

ここでは保存された画像と顔に合成するスタンプ風画像の取得を行います。

まずは「スコープ」のアクションを追加し、その中にBlob ストレージのアクション「Get blob content」を追加します。入力にはトリガーで取得されたBlobのIdを指定してください。

f:id:mofumofu_dance:20201003155509p:plain
保存されたファイルコンテンツの取得。トリガーの結果のBlob Idを利用する。

続けて4つ、「Get blob content」のアクションを追加します。それぞれ、笑顔度が25%未満、50%未満、75%未満、それ以上(75~100%) の時の画像を指定します。

※ここで使った画像ファイルはGithubに置いてあります。ご自由にダウンロードして使ってください。

PowerApps365/Samples/smiles at master · mofumofu-dance/PowerApps365 · GitHub

すべて画像を指定しおえると、スコープの中は下図のような表示になります。

f:id:mofumofu_dance:20201003155833p:plain
スタンプ画像を含めた全画像コンテンツの取得。可読性のためにスコープでまとめておく。

以上で画像取得としては完了です。

最後のループ処理に入る前に、変数を2つ初期化しておきます。「Initialize variable」のアクションを2つ追加し、それぞれ以下のように設定します。

変数名 タイプ
updatedImage object @{body('Get_trigger_content')}
layeredImage object 空(カラ)

最初の変数はループの各回で元画像にスタンプを合成した結果を格納するための変数です。初期値としては元の画像のコンテンツを指定しておきます。 2つ目はループ内で笑顔度に応じた最適なスタンプを設定するための変数です。

f:id:mofumofu_dance:20201003160520p:plain
ループで使う変数2つの初期化。

3-3. 検出した顔へのスタンプ合成 (ループ処理)

大きな処理としてはこのループ処理が最後です。

「For each」のアクションを追加し、ループの対象として 「Detect faces」の「Body」を指定します。

For each 内ではまず「Set variable」を追加しm変数は先ほど初期化しておいた「layeredImage」を、値には 笑顔度75~100% の時の画像を指定します。

f:id:mofumofu_dance:20201003163649p:plain
For eachの最初のアクションは「layeredImage」変数のセット。

次に条件分岐のアクションを追加します。条件には「Smile が 0.25 より小さい」を指定してください。このときの「Smile」は動的コンテンツから選択できます。

判定がTrueの場合に限り、「layeredImage」を「Set variable」アクションで25%未満の時の画像で更新します。

f:id:mofumofu_dance:20201003163811p:plain
笑顔度に応じた条件分岐 (25%未満の判定)。Trueの場合のみ変数を更新

条件分岐の下に、さらに条件分岐を追加します。条件には「Smile が 0.25 以上 AND Smile が 0.50 より小さい」 を指定してください。先ほどと同様、判定がTrueの場合に限り、「layeredImage」を「Set variable」アクションを使い50%未満の時の画像に更新します。

f:id:mofumofu_dance:20201003164322p:plain
笑顔度に応じた条件分岐の全体 (For each内)。条件のどれにも当てはまらない場合には 75~100%のスタンプになる

例えば、笑顔度が0.3だったとします。その場合、最初の条件分岐ではFalseになり何も実行されません。次の条件分岐では0.25以上0.5未満に該当するため「layeredImage」が更新されます。さらに次の条件分岐では0.5以上0.75未満の条件を満たさず、変数の更新はされません。

という具合に、各条件分岐を排他的 (被らないように)して、True/Falseいずれかの場合にのみ処理を行うことで、条件分岐が入れ子になるようなフローを防ぐことができます。

ここまでで、元画像と、各人物の笑顔度に応じたスタンプ画像の設定ができました。あとはこの2つをCloudmersive の 画像合成APIで重ね合わせるだけです。この画像合成APIについては前回のブログで紹介していますので、詳細を知りたい場合には参照してください。

Cloudmersive の APIを実行するために、「HTTP」アクションを追加します。「Method」を「POST」にしたのち、ヘッダーの入力をテキストモードに変更します。

f:id:mofumofu_dance:20201003165817p:plain
HTTPアクションの「ヘッダー」をテキストモードに変更する。

テキストモードに変更したら、HTTPアクションの各パラメータを以下のように設定します。

URL

https://api.cloudmersive.com/image/edit/composite/precise

Headers

{
  "Apikey": "ここにCloudmersiveのAPIキー",
  "content-type": "multipart/form-data; boundary=--@{guid()}",
  "left": "@{items('For_each')?['Left']}",
  "top": "@{items('For_each')?['Top']}",
  "width": "@{items('For_each')?['Width']}"
}

Body

{
  "$content-type": "multipart/form-data",
  "$multipart": [
    {
      "body": @{variables('updatedImage')},
      "headers": {
        "Content-Disposition": "form-data; name=\"baseImage\""
      }
    },
    {
      "body": @{variables('layeredImage')},
      "headers": {
        "Content-Disposition": "form-data; name=\"layeredImage\""
      }
    }
  ]
}

それぞれをコピー&ペーストすれば自動的に動的コンテンツで置き換えられます。

Headers には、最初にセットアップしたCloudmersiveのAPIキーを入力してください。

すべて設定し終わると下図のようになります。

f:id:mofumofu_dance:20201003170509p:plain
HTTPアクションでCloudmersiveのAPIを実行する。 (完成後)

For eachループの最後の処理として、「updatedImage」の更新をします。

f:id:mofumofu_dance:20201003170623p:plain
合成画像 (HTTPの結果) で updatedImageを更新。

以上でFor eachのループ処理は完了です。

ここで注意!!!

このままだとFor eachが並列に走ってしまい、期待動作になりません。(最後に検出された人の顔にだけスタンプが押される)

For eachが並列実行されないように、For eachアクションの設定を変更しておきます。

右上の… をクリックし表示されたメニューから「Setting」を選択します。For eachの設定が表示されたら、「Concurrrency Control」のトグルをOnにし、さらに「Degree of Parallelism (並列度)」を 1 に設定します。

この設定により、For eachが並列実行されず、期待通りの動作になります。

f:id:mofumofu_dance:20201003174056p:plain
For eachの設定変更を忘れないように注意。

ループ処理が終わったあとは「updatedImage」に最終的な合成画像が格納されているので、Blobストレージのアクション「Create Blob」で所定のフォルダーに「updatedImage」を保存して完成です。

f:id:mofumofu_dance:20201003171559p:plain
合成した画像のBlobストレージへの保存

おわり

今回はCloudmersive の 画像加工API と Azure Face API の組み合わせで人物の顔にスタンプ画像を自動で押すLogic Appsをご紹介しました。

この方法を少し応用すれば、自分の顔だけは出して、ほかの人の顔にはスタンプを入れるというような、SNSでよく見る画像を自動で作ってくれるサービスがノンコーディングで作れます。

また、最初のトリガーをHTTPリクエストの受信にして、最後にHTTPレスポンスで合成画像を返せば、画像加工用のカスタムAPIもやはりノンコーディングでできてしまいます!(すごい!)

もちろんPower Automateで作っても問題ありません。いろいろとAzureのサービスやHTTPを使うので有償ライセンスをお持ちであれば、Power Automateでも同じ操作で作れます。

最後に、このLogic Appsを検証する際には友人の りなたむさんのりじさん にご協力(写真利用への同意)をいただきましたことお礼申し上げます。