LoginSignup
2
4

More than 3 years have passed since last update.

顔面偏差値No.1アイドルをAIに判定してもらおう!!~Face++ API~【検証】

Last updated at Posted at 2020-05-30

企画趣旨

「結局、顔面偏差値が一番高いアイドルは誰なのか?」

アイドル界隈ではよく耳にする話題です。

アイドルのヲタクに聞いたら、自分の推しているアイドルの名前が返ってくると思います。
たしかにそれは正しいと思います。

でもやっぱり客観的な意見も気になります。

客観的な意見を得るためにアンケートという形もありですが、
せっかく顔認識が発展しているのだからAIから意見をもらいたいなと思いました。

今回はその備忘録です。

私の顔で試したところスコアは100点満点56点でしたが(←ちょっと不服)、
果たしてNo.1アイドルとそのスコアは??

(結果は目次番号15にあります)

全体の流れ

今回の企画は大きく3部構成になっております。

  • [前編]画像ファイルのスクレイピング(目次番号1~6まで)
  • [中編]Face++のAPIによる判定(目次番号7~11まで)
  • [後編]DataFrameのビュー作成と可視化(目次番号12~16まで)

前編の目次

  • 1.前編のゴール
  • 2.利用する技術
  • 3.ホームページから画像をスクレイピング
  • 4.取得した情報をDataFrameに格納
  • 5.DataFramをCSV出力
  • 6.サンプルコード

1.前編のゴール

サイトから複数の画像ファイルをスクレイピングしDataFrameに格納します。

2.利用する技術

  • 顔認識(中編で使用します)
  • 言語
    • Python 38
  • 環境
    • Windows
  • 主なライブラリ
    • BeautifulSoup
    • Pandas
  • BIツール(後編で使用します)
    • MotionBoard

3.ホームページから画像をスクレイピング

今回はももいろクローバーZが所属することで有名な「スターダスト」という事務所のアイドルをターゲットとします。
所属するアイドルの数は65人です(調査時点)。

スクレイピング対象のホームページは下記です。
https://www.stardust.co.jp/stardustplanet/
alt

このホームページから下記2点を目指します
- 画像ファイルの取得
- 人物名の取得

画像ファイルの取得

まずは画像がどのタグの中に存在するのか確認します。
一番左上の「高城れに」さんでGoogleの検証をしてみます。
検証.PNG

これを見るとimg srcの部分と検討が付くと思います。

ただここで注意点があります。
このimgだけだと関係ない画像まで取得されてしまいます。

例えばアイドルの横にあるグループのロゴ。
これもimgタグで囲まれてます。
検証2.PNG

アイドルさんとロゴの区別する点として、imgの1つ外側のタグが違います。
・アイドル ⇒ div
・ロゴ ⇒ a

そのため今回は

divの中のimgという指定をしました。

人物名の取得

次に人物名を取得します。

と言ってもタグの指定は画像ファイルとまったく同じで今回のホームページは大丈夫でした。
これは画像ファイルと人物名が同じdivの中のimgに存在したからです。

つまり
divの中のimgという指定です。
検証.PNG

4.取得した情報をDataFrameに格納

以下のような3つのカラムを持つDataFrameを用意します。
そして取得した情報をフィールドにセットします。
for文を回してこのDataFrameに全員の情報を格納します。

name image_url file_path
高城れに http://img.stardust.co.jp/upload/talent/photo/2/238.L.jpg 保存先のファイルパス

5.DataFramをCSV出力

2次利用しやすいようにテーブルをCSVファイルとして出力します。

6.サンプルコード

今回の内容をコードに落とすと以下のようになります。

storeimages.py
import requests
from bs4 import BeautifulSoup
import os
import pandas as pd

# 取得したファイルを格納するローカルディレクトリ
images_dir = 'YOUR_LOCAL_DIRECTLY'

# 取得したデータフレームを格納するアウトプットディレクトリ
outputfiles_dir = 'YOUR_OUTPUT_DIRECTLY'

# スクレイピング対象のURL
url = 'https://www.stardust.co.jp/stardustplanet/'


headers = {'User-Agent': 'Mozilla/5.0'}
soup = BeautifulSoup(requests.get(url, headers=headers).content, 'lxml')

# 取得した情報を格納する変数
images = []
names = []
files_path = []


# 画像URLの取得
# <div>タグの中の<img>のsrcが画像のURL
for image_url in soup.select('div > img'):
    # imagesのリストに取得した画像URLを格納
    images.append('http:' + image_url.get('src'))

# 人物名の取得
# <div>タグの中の<img>のaltが人物名
for name in soup.select('div > img'):
    # namesのリストに取得した人物名を格納
    names.append(name.get('alt'))


for target in images:
    # files_pathのリストにローカルディレクトリと画像ファイル名を連結したパスを格納
    files_path.append(
        images_dir + target.split('/')[-1])
    # 画像URLをローカルファイルとして保存する
    re = requests.get(target)
    with open(images_dir + target.split('/')[-1], 'wb') as f:
        f.write(re.content)

# リストの値をテーブルのカラムへの格納
data = {
    'name': names,
    'image_url': images,
    'file_path': files_path
}
# テーブルを定義
df = pd.DataFrame(data)

# テーブルをCSVファイルとして出力する
df.to_csv(
    outputfiles_dir + 'storeimages.csv')

print('終了')

以上が[前編]です。

中編の目次

  • 7. 中編のゴール
  • 8. Face++とは?
  • 9. APIを利用する
  • 10. 判定結果を格納
  • 11 サンプルコード

7. 中編のゴール

画像ファイルをFace++を利用して顔面偏差値を判定し、結果をDataFrameへ格納します

8. Face++とは?

ホームページはこちらです。
https://www.faceplusplus.com/

私は最近知りました。
出会いは、「顔認識使ってみたいなー」「けど、有料サービスはちょっとハードル高いなー」
という思いから、「顔認識 無料」みたいなググり方。

こちらのサイトがFace++について詳しく勉強になりました。
ありがとうございます。

ひと言でまとめると、
「中国国家でも利用される顔認識システムの会社のサービス」
です。

そして今回の企画のカギ
「顔面偏差値」として解釈させていただいている「beauty」というスコアを取得することができます。
Face++のDetect APIを利用します。

公式ドキュメントによる「beauty」の説明は下記。

「美しさを100点満点で測定した値」だそうです。

Result of beauty analysis, including the following fields. The value of each field is a floating-point number with 3 decimal places between [0,100]. Higher beauty score indicates the detected face is more beautiful.

9. APIを利用する

ユーザーの登録が必要です。
登録の手順はこちらが参考になりました。
ありがとうございます。

ユーザー登録することでAPI KEYを取得できます。

大まかな流れは下記です。

画像ファイルをbase64 形式でエンコード

パラメーターをセット
ここでAPI KEY やReturnしてほしい属性を設定。
今回は「性別、年齢、beauty」を設定。

リクエスト

JSON形式でレスポンスが返ってくる

10. 判定結果を格納

パラメーターで設定した「性別、年齢、beauty」をリストに入れて、そのリストの値を下記のようなDataFrameに格納します。

beautyは male_scoreとfemale_scoreとして返ってきます。
そのためリストもカラムも2つずつ用意します。

input_file gender age beauty_male beauty_female
判定する画像ファイル 性別 年齢 男性としての顔面偏差値 女性としての顔面偏差値

11. サンプルコード

今回の内容をコードに落とすと以下のようになります。

detectapi.py
import requests
import json
import glob
import base64
import pandas as pd


# face++のURL
url = 'https://api-us.faceplusplus.com/facepp/v3/detect'


# 取得したイメージファイルを格納しているローカルディレクトリ
images = 'YOUR_IMAGE_FILES_DIRECTLY'

# 取得したデータフレームを格納するアウトプットディレクトリ
outputfiles_dir = 'YOUR_OUTPUT_DIRECTLY'

# 取得したJSONデータを格納リスト
gender = []
age = []
beauty_male = []
beauty_female = []

# ファイルパスを変数に格納
file_path = glob.glob(
    images)


list_df = pd.DataFrame(
    columns=['file_path', 'gender', 'age', 'beauty_male', 'beauty_female'])


# ファイル分繰り返して
for input_file in file_path:
    # バイナリファイルを開く。withはclose自動
    with open(input_file, 'rb') as f:
        img_file = base64.encodebytes(f.read())

    # パラメーターをセット
    param = {
        'api_key': 'YOUR_API_KEY',
        'api_secret': 'YOUR_API_SECRET',
        'image_base64': img_file,
        'return_landmark': 1,
        'return_attributes': 'gender,age,beauty'
    }

    # POSTする
    res = requests.post(url, data=param)

    # JSONファイルを読み込む
    data = json.loads(res.text)

    # JSON文字列として整形
    data_json = json.dumps(data, indent=4)

    # カラムにJSONデータを格納する
    for face in data['faces']:
        if 'attributes' in face:
            gender = face['attributes']['gender']['value']
            age = face['attributes']['age']['value']
            beauty_male = face['attributes']['beauty']['male_score']
            beauty_female = face['attributes']['beauty']['female_score']
        #顔認識できない場合はNoneをセット
        else:
            gender = None
            age = None
            beauty_male = None
            beauty_female = None
        # テーブルにレコードを追加
        temp_se = pd.Series(
            [input_file, gender, age, beauty_male, beauty_female], index=list_df.columns)
        list_df = list_df.append(temp_se, ignore_index=True)
# CSVファイルへ出力
list_df.to_csv(
    outputfiles_dir+'detectapi.csv')
print('finish')

以上が[中編]です。

さあラスト[後編]です。

後編の目次

  • 12. 後編のゴール
  • 13. キー項目の作成
  • 14. 左外部結合
  • 15. BIツールで可視化&結果発表
  • 16. サンプルコード

12. 後編のゴール

2つのDataFrameを結合し、BIツールで可視化します。

13. キー項目の作成

前編と中編でそれぞれ作成したテーブルを見てみましょう。

  • 前編で作ったDataFrame:storeimages.csv
name image_url file_path
高城れに http://img.stardust.co.jp/upload/talent/photo/2/238.L.jpg 保存先のファイルパス
  • 中編で作ったDataFrame:detectapi.csv
input_file gender age beauty_male beauty_female
判定する画像ファイル 性別 年齢 男性としての顔面偏差値 女性としての顔面偏差値

これら2つのDataFrameを1つにします。

2つを結合するためには共通するキー項目を作る必要があります。

今回は、「画像ファイル名」をキー項目とします。

それぞれのテーブルからは下記のようにキー項目を作成します。
storeimagesは「image_url」から文字列をsplitします。
detectapiは「input_file」から文字列をsplitします。

14. 左外部結合

こうして「key」というカラムができたら2つのテーブルを結合します。

storeimagesを親としてdetectapiを結合します。

今回はどっちが親でも関係ないです。
storeimageのレコードは要するに画像の一覧です。
このテーブルのレコードは結合落ちしてほしくないので親にしました。

そして結合したあと、
顔面偏差値の降順にソートしました。(これは別に必要ないです。趣味です。

最後に必要なカラムだけに絞った結果が下記です。

name beauty_female age
人物名 顔面偏差値 推定年齢

15. BIツールで可視化&結果発表

最後は結合して作ったDataFrameを可視化します。

ランキング表形式での可視化が分かりやすいなと思いました。

表形式での可視化はPythonだとちょっと苦手かなという印象が個人的にあります。

そこでMotionBoardというBIツールを使って可視化してみました。

1_3.PNG

1位大黒柚姫 さん
418.L.jpg

2位小泉遥香 さん
2013.L.jpg

3位華山志歩 さん
614.L.jpg

(以上写真はhttps://www.stardust.co.jp/stardustplanet/)

冒頭の通りですが、
ちなみに試しに自分の写真を判定してもらったところ
スコアは56点でした。。

かなしい。

アイドルさんは当たり前ですが顔面偏差値高いです!

以上で今回の企画は終了です。

16. サンプルコード

今回の内容をコードに落とすと以下のようになります。

makeview.py
import numpy as np
import pandas as pd


# storeimages.csv
storeimages_csv = 'YOUR_PATH_storeimages.csv'

# detectapi.csv
detectapi_csv = 'YOUR_PATH_detectapi.csv'

# 取得したデータフレームを格納するアウトプットディレクトリ
outputfiles_dir = 'YOUR_OUTPUT_DIRECTLY'


# テーブルとして読み込む
df_images = pd.read_csv(
    storeimages_csv)
# テーブルとして読み込む
df_detectapi = pd.read_csv(
    detectapi_csv)

# 2つのテーブルを結合するキー項目を作成。
# イメージファイル名をキー項目とする
df_images['key'] = df_images['image_url'].str.rsplit('/', 1).str[1]

df_detectapi['key'] = df_detectapi['file_path'].str.rsplit('\\', 1).str[1]

# キー項目で結合。
df_view = df_images.merge(df_detectapi, how='left', on='key')

# beautyを降順ソート
df_view = df_view.sort_values(
    'beauty_female', ascending=False, na_position='last')

df_view = df_view.loc[:, ['name', 'beauty_female', 'age']]

# CSV出力
df_view.to_csv(
    outputfiles_dir+'view.csv')
#view.csvをBIツールで可視化する
2
4
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
4