Help us understand the problem. What is going on with this article?

写真を送ると顔を検出して、顔面偏差値まで教えてくれるFace++APIのご紹介

More than 1 year has passed since last update.

結構前なんですが、こんなLINE BOTを作りました。
IMB_HonMYj.GIF
人の顔が写っている写真をBOTに送ると、写真から顔を検出して、推定される年齢・性別・顔面偏差値を返します。人物画像はぱくたそさんからお借りしました。80点以上はかなり高いほうだと思います。肉の写真だらけなのは気にしないでください。

ここでの顔認識ですが、Face++というおそらく中国の会社?のAPIを使っています。顔認識といえば、GoogleやAmazon、Microsoftといった有名どころもAPIを公開しています(後述)。Face++はそれらに比べるとだいぶ知名度が低いのは否めず、日本語の解説記事が少ないです。なのですが、顔の美しさ(今風に言えば顔面偏差値でしょうか)といった他の顔認識APIサービスにはない属性を取得できたり、無料で利用できる枠が大きかったり魅力的な点が多いので、この記事で簡単に紹介していきたいと思います。

顔認識APIの比較

先述の通り、顔認識APIは他にもたくさんあるんですが、各APIについては、こちらの記事が非常によくまとまっているので参照してもらえればと思います。

顔認識APIについての個人的まとめ2017年秋版

無料枠の比較

こちらの記事にない情報として、無料でどれくらい利用できるのか?という話ですが、主要サービスを以下にまとめました。

API 無料枠
Face++ API 1クエリー/秒
Google Cloud Vision API(顔検出) 1000ユニット/月
Amazon Rekognition Image 5000枚/月
Microsoft Face API 20トランザクション/分、30000トランザクション/月

※Amazon Rekognition ImageはAWSの無料利用枠期間(最初の12ヶ月)以降は有料

各APIで単位が違いますが、大まかに1単位=1APIリクエストだと思ってもらって大丈夫です。各単位の詳細は公式ドキュメントを参照してください。Face++は1秒あたりの制限がゆるく、しかも月単位の制限がないので、かなり枠が大きいことがわかります。ある程度の規模までは無料枠で対応できそうなのでありがたいですね。

Face++を使って顔認識をやってみる

API Keyの取得

では、実際にFace++を使ってみましょう。まずはこちらから無料会員登録を行って、APIを叩くために必要になるAPI KeyとAPI Secretを取得します。
スクリーンショット 2018-10-03 22.02.59.png

curlでAPIを叩いてみる

API KeyとAPI Secretを取得できたら、プログラムを実装する前に(後ほどNode.jsで実装します)まずはHTTPリクエストツールであるcurlで試しにAPIを叩いてみましょう。レスポンスのjsonは見やすいようにjqコマンドにパイプで渡してパースします。jqコマンドはMacであればhomebrewでインストールできます。

brew install jq

ここまで「Face++のAPI」と言ってきましたが、実はFace++の中にもいろいろAPIの種類があります。その中でも顔認識を行って各属性を取得できるFace Detectionを利用します。公式ドキュメントは以下になります。

Detect API

リクエストの際のパラメータを見てみましょう。(※一部抜粋)

パラメータ 説明 必須
api_key API Key
api_secret API Secret
image_url 画像URL
image_file 画像のバイナリデータ
image_base64 base64エンコードされた画像データ
return_attributes 取得したい属性

image_url、image_file、image_base64に関してはどれか一つが指定されていれば大丈夫です。URLを指定するのが簡単なのでネットで適当な画像を探してimage_urlに指定してみましょう。エンドポイントはhttps://api-us.faceplusplus.com/facepp/v3/detectでPOSTでリクエストします。各リクエストパラメータはformデータとして指定します。

curl -X POST "https://api-us.faceplusplus.com/facepp/v3/detect" \
-F "api_key=<API Key>" \
-F "api_secret=<API Secret>" \
-F "image_url=<画像URL>" | jq .

レスポンスはこうなります。

{
  "image_id": "e2QcMZcFmhreeEdQwAW5yw==",
  "request_id": "1538571238,91a99159-9b97-4e25-a069-d7ec205585d2",
  "time_used": 171,
  "faces": [
    {
      "face_rectangle": {
        "width": 99,
        "top": 100,
        "left": 302,
        "height": 99
      },
      "face_token": "effc56800971d6922c870ddaa61c9dbd"
    },
    {
      "face_rectangle": {
        "width": 92,
        "top": 88,
        "left": 169,
        "height": 92
      },
      "face_token": "7c77410b8107531764d0792317c44d6d"
    }
  ]
}

facesというキーに認識された顔の情報が入ってきます。2人が写っている画像を指定したのでオブジェクトが2つありますね。face_rectangleといった顔認識された矩形の情報があるくらいで大した情報がありませんね...。そういえば、リクエストパラメータにreturn_attributesというものがありましたが、こちらで取得したい属性を指定しないとほとんど何の情報も取得できないのです。

では、return_attributesに指定できる属性はどんなものがあるんでしょう。

  • gender
  • age
  • smiling
  • headpose
  • facequality
  • blur
  • eyestatus
  • emotion
  • ethnicity
  • beauty
  • mouthstatus
  • eyegaze
  • skinstatus

emotion(感情)やethnicity(人種)など面白そうなのがありますね。今回は年齢と性別と美しさを取得したいです。複数の属性を指定する場合はカンマ区切りで指定します。今度は属性を指定するようにして再度リクエストしてみましょう。

curl -X POST "https://api-us.faceplusplus.com/facepp/v3/detect" \
-F "api_key=<API Key>" \
-F "api_secret=<API Secret>" \
-F "image_url=<画像URL>" \
-F "return_attributes=gender,age,beauty" | jq .

レスポンスはこうなります。

{
  "image_id": "e2QcMZcFmhreeEdQwAW5yw==",
  "request_id": "1538573298,d119de3d-14c1-4467-8887-2df9f0cd289a",
  "time_used": 1159,
  "faces": [
    {
      "attributes": {
        "gender": {
          "value": "Female"
        },
        "age": {
          "value": 27
        },
        "beauty": {
          "female_score": 74.495,
          "male_score": 77.818
        }
      },
      "face_rectangle": {
        "width": 99,
        "top": 100,
        "left": 302,
        "height": 99
      },
      "face_token": "ba6531b54f5034541dc4caf4dbe81621"
    },
    {
      "attributes": {
        "gender": {
          "value": "Female"
        },
        "age": {
          "value": 25
        },
        "beauty": {
          "female_score": 75.993,
          "male_score": 76.181
        }
      },
      "face_rectangle": {
        "width": 92,
        "top": 88,
        "left": 169,
        "height": 92
      },
      "face_token": "0fdad3347e706f0d788db353a70605d4"
    }
  ]
}

facesの各オブジェクトにattributesというキーが追加されましたね。ちゃんと指定した属性の情報が取得できています。年齢や性別といった情報はだいたい合っている気がします。beautyは100点満点でのスコアが返ってきています。女性と判定された場合でも、男性としてのスコア、女性としてのスコア両方が取得できます。

Node.jsで実装してみる

APIがどんな仕様かなんとなくつかめてきたところで、実際にNode.jsのプログラムとして実装していきます。Node.jsの経験がない方もいらっしゃるかと思いますが、細かいところは理解する必要はないので「ふーん」って感じで見てもらえればと思います。

冒頭に紹介したLINE BOTのソースコードから抜粋します。ソースコードはGitHubに公開していますので、興味のある方はご覧ください。

masaki-koide/facial-deviation-value-line-serverless

TypeScriptバージョンもあります。

masaki-koide/line-facial-deviation-value-ts

Face++ APIを叩く

// 省略

const request = require('request-promise-native')
const faceDetectUri = 'https://api-us.faceplusplus.com/facepp/v3/detect'

// 省略

function detectFace(image) {
  const options = {
    method: 'POST',
    uri: faceDetectUri,
    form: {
      api_key: process.env.faceApiKey,
      api_secret: process.env.faceApiSecret,
      image_base64: image,
      return_attributes: 'gender,age,beauty'
    },
    json: true
  }

  return request(options)
    .then(response => {
      if (response.error_message) {
          return Promise.reject(response.error_message)
      }

      return response.faces
    })
    .catch(err => {
      console.log(err)
      return Promise.reject(new Error(err))
    })
}

ユーザーからBOTに送信された画像データ(base64エンコード済み)を引数に受け取って、Face++のAPIを叩く関数です。optionsに各リクエストパラメータを指定しています。なお、APIがエラーを返した場合はレスポンスにerro_messageというキーが含まれますので、その場合はエラーとして扱っています。正常にレスポンスが帰ってきた場合はfacesを返します。

facesから属性情報を取り出す

function createFacesAnalysisResultMessages(faces) {
  // ①
  const sortedFaces = faces.sort((a, b) => {
    if (a.face_rectangle.left === b.face_rectangle.left) {
      return 0
    } else if (a.face_rectangle.left < b.face_rectangle.left) {
      return -1
    }
    return 1
  })

  // ②
  return sortedFaces.map((face, index) => {
    const attr = face.attributes
    const age = attr.age.value
    const gender = attr.gender.value === 'Male' ? '男性' : '女性'
    const beauty =
      gender === '男性'
        ? attr.beauty.male_score
        : attr.beauty.female_score
    const text = `${
      faces.length > 1 ? `左から${index + 1}人目\n` : ''
    }年齢: ${age}歳
性別: ${gender}
顔面偏差値: ${Math.round(beauty)}点(100点満点)`

    return {
      type: 'text',
      text: text
    }
  })
}

先程取得したfacesからLINE BOTとして返信するメッセージを組み立てる関数です。①ですが、複数の顔を検出した場合に「左からの○番目の人の解析結果」ということを教えたいので、face_rectangleの情報を使って、左からの順番にfacesの配列をソートしています。②ですが、実際に属性の情報を取り出しつつメッセージを組み立てています。beautyについては、男性の場合はmale_score、女性の場合はfemale_scoreを使いたいのでそのように条件分岐しています。最後に返信メッセージのオブジェクトを返します。

最後に

いかがでしたでしょうか。無料かつ登録も簡単ですしサクッと顔認識を体験できたと思います。いくつかの写真を試してみましたが、beautyについては、単純に顔が大きく写っていたり、画質が良ければ高いスコアを弾き出すような気がしなくもないです。そこらへんの制度が上がったり、さらに新しい属性が取得できるようになればさらに面白くなってくると思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away