26
24

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 5 years have passed since last update.

年齢・性別判定APIを比較しました(その1)

Last updated at Posted at 2016-12-20

Nextremer Advent Calendar 2016の19日目の記事です。

はじめに

顔画像から年齢や性別を判定するAPIは多くありますが、どのAPIが良いか気になり試してみました(2016年12月時点)。

今回比較したのは次の4つです。APIではないですが、参考のためフリーの年齢・性別モデルも比較しました。

結論から言うと、FaceAPIが良かったです。

検証は下記サイトを参考に、有名人のInstagram画像と生年月日を用いました。

なお、今回は性別判定についての記事になります。

準備

各種APIのユーザ登録を行い、Pythonで実装しました。
ユーザ登録の方法は割愛します。

APIキーの準備

登録時に取得したAPIキーはconfigファイルにまとめました。
各APIキー取得のためにget_api_key()を定義しています。

cfg = ConfigParser.SafeConfigParser()
cfg.read('config/api.cfg')

def get_api_key(section):
    return cfg.get(section,'key') if cfg.has_section(section) and cfg.has_option(section, 'key') else {}

configファイルは以下の通りです。

[MSApi]
key = (Face APIのキー)

[IBMApi]
key =(Visual Recognitionのキー)

[PUXApi]
key =(PUX 評価版APIのキー)
domain = (PUX 評価版APIのドメイン)

Microsoft社: Face APIの使用

pathの画像について判定します。
判定結果をgender(性別), age(類推年齢)の2つに保存しています。
ageは小数点まで求まります。

def ms_predict(path):
    print("//// MS ////")
    # 該当のAPIキーを取得する
    ms_key = get_api_key('MSApi')
    if ms_key:
      CF.Key.set(ms_key)
      with open(path, 'rb') as image_file:
        result = CF.face.detect(image_file, landmarks=True, attributes='age,gender')
       # 顔画像を検出した場合に、gender,ageに値を入れる
       if len(result) > 0:
        target = result[0]["faceAttributes"]
        res["gender"] = target["gender"]
        res["age"] = target["age"]
        print(res)
      else:
        print("No Face")
    return res

IBM社: Visual Recognitionの使用

pathの画像について判定します。
判定結果をgender(性別), lo(類推年齢の下限), hi(類推年齢の上限)の3つに保存しています。
loやhiは必ずしも存在しない場合があり注意が必要です。

def ibm_predict(path):
    print("//// IBM ////")
    # 該当のAPIキーを取得する
    ibm_key = get_api_key('IBMApi')
    if ibm_key:
      # Visual Recognition 無料プランでは、イメージのタグ付けおよび顔検出に対して、Bluemix アカウント 1 つにつき 1 日あたり 250 個のイベント (イメージ) を利用できます。
      IBM_recognition = VisualRecognitionV3('2016-05-20', api_key=ibm_key)
      with open(path, 'rb') as image_file:
        result = IBM_recognition.detect_faces(images_file=image_file)
      # 顔画像を検出した場合に、gender,lo,hiに値を入れる
      if len(result["images"][0]["faces"]) > 0:
        target = result["images"][0]["faces"][0]
        res["gender"] = target["gender"]["gender"]
        if target["age"].has_key("min"):
          res["lo"] = target["age"]["min"]
        if target["age"].has_key("max"):
          res["hi"] = target["age"]["max"]
        print(res)
      else:
        print("No Face")
    return res

PUX社: 顔検出(評価版)の使用

pathの画像について判定します。
判定結果をgender(性別), age(類推年齢)の2つに保存しています。

#PUXのdetectFaceAPIを使用
def pux_predict(path):
    print("//// PUX ////")
    # 該当のAPIキーを取得する
    pux_key = get_api_key('PUXApi')
    if pux_key:
      url = 'http://eval.api.polestars.jp:8080/webapi/face.do'
      # APIの規約に合わせるために一時的にjpegに変換
      im = Image.open(path)
      im.save("/tmp/tmp.jpg", "JPEG")
      with open("/tmp/tmp.jpg", 'rb') as image_file:
        data = {
          'apiKey': pux_key,
          'inputBase64': base64.b64encode(image_file.read()).decode(),
          'response': 'json'
        }
        result = json.loads(requests.post(url, data, headers={'Content-Type': 'application/x-www-form-urlencoded'}).text)
      # 顔画像を検出した場合に、gender,ageに値を入れる
      if result["results"]["faceRecognition"].has_key("detectionFaceInfo"):
        target = result["results"]["faceRecognition"]["detectionFaceInfo"][0]
        res["gender"] = "Male" if str(target["genderJudge"]["genderResult"]) == "0" else "Female"
        res["age"] = target["ageJudge"]["ageResult"]
        print(res)
      else:
        print("No Face")
    return res

その他:フリーの年齢・性別モデルの使用

pathの画像について判定します。
判定結果をgender(性別), lo(類推年齢の下限), hi(類推年齢の上限)の3つに保存しています。
こちらを参考に、入出力を下記の形で実装しました。

def org_predict(path):
    print("//// Original ////")
    input_image = caffe.io.load_image(path)

    # 顔画像を検出した場合に、gender,lo,hiに値を入れる
    res["gender"] = _predict_gender(input_image)
    res["lo"], res["hi"] = _predict_age(input_image)
    print(res)
    return res

データの準備

Instagramより、本人のみ写った写真を1~10枚集めました。対象年齢は20歳〜83歳です。
175名分(男性:73名、女性:102名)で、計816枚集めました。
ちなみに、今回一番大変だったのは画像集めでした:frowning2:

対象者の年齢分布は次の通りです。

スクリーンショット 2016-12-20 13.26.34.png

実験結果(性別判定)

正解と不正解、非検出数

スクリーンショット 2016-12-20 9.38.27.png

  • 正解:男性を男性、女性を女性と判定した数
  • 不正解:男性を女性、女性を男性と判定した数
  • 非検出:顔の認識が出来なかった数(正解 + 不正解 + 非検出 = 816)
  • 正解率:顔を認識した場合の正解の割合(正解 / (正解 + 不正解))
  • 検出率:顔を認識した割合((正解 + 不正解)/(正解+不正解+ 非検出))

男性と女性の判定数

スクリーンショット 2016-12-20 10.37.56.png

  • 男性:男性だと判定した数
  • 女性:女性だと判定した数

考察

  • FaceAPI正解率が0.96と最も高く、検出率は0.86と最も低い。顔検出が厳密に行われ、高い正解率になったのかも。
  • Visual Recognition正解率が0.8と低く、検出率は0.99と非常に高い。顔認識が不正確な場合でもなんらかの値を返しているみたい。
  • PUXの顔検出(評価版)正解率が0.82で、検出率は0.87だった。日本製APIのため有利かと思ってましたが、意外な結果でした。
  • その他のフリーの年齢・性別モデル正解率が0.57と最も低く、検出率は1で最も高い。顔認識が不正確だと男性として判定してそうです(実装によりますが)

正解率と検出率はトレードオフかもしれません。

まとめ

  • 正解率で考えると、FaceAPIが最も性別判定に使える
  • 検出率で考えると、Visual Recognitionがバランスが良い

今回は、性別判定のみで記事にしました。個人的には、APIのコール数が月30,000回まで無料で、性能も良いFaceAPIが使いやすいと思います。
それと、は◯な愛さんの性別の真値に迷いました

(ちなみに、性別判定だけなら、Amazon Rekognitionもできるので、そのうち比較してみたいと思います)

今後

次回は年齢判定について記事にします。日本製のモデルであるPUXの性能が気になるところです。

※追記:その2を書きました(2017/12/19) 。

26
24
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
26
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?