ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

顔認識でハッピー分析

こんにちは、2週連続の田中です。(でも、先週とは別の田中です。。)

前々から気になってたことを少しだけではありますが解析したので今日はそれについて共有します。

気になっていたこと

それは、、

「保護者のみなさまが購入した写真はハッピーな表情が多いのか?」

きっと、そうだろう とは思いつつも調べてなかったので今回調べてみました。

分析ステップ

  1. 保護者の方が購入した写真を抽出する
  2. 顔認識を行い、顔を検出するとともに表情の認識も行う
  3. どんな表情が検出されているか集計、可視化する

ステップ3に関して、本来は写真とその認識結果を対で示しながらというのが分かりやすくベストなのですがプライバシーの問題のため園の実際の写真を出せないのが残念です。

数字とテキストでまとめただけの結果になりますがご容赦ください。。

顔認識

顔認識は Amazon Rekognition を使いました。 Rekognition は 元々、アメリカのベンチャー企業 Orbeus社 が開発したサービスで実は弊社の子どもの顔認識機能のリリース当初、この技術を使っていました。

突然、サービス停止のアナウンスがあり、慌てて代替の顔認識サービスを探して置き換えの開発を余儀なくされた思い出深いサービスです。その時は、

ええ、マジかよ?! ╰(゚x゚​)╯

と戸惑うばかりでしたがそういう事情(Amazonによる買収)だったんですね。。

当時、顔認識をAPIで提供するサービスはいくつかありましたがRekognitionの性能が頭一つは抜けていたので今回改めて使ってみました。

Rekognitionでは顔の認識とともに表情も検出でき、検出できる表情の種類は

  • HAPPY
  • SAD
  • ANGRY
  • CONFUSED
  • DISGUSTED
  • SURPRISED
  • CALM
  • UNKNOWN

の8種類です。

http://docs.aws.amazon.com/rekognition/latest/dg/API_Emotion.html

表情にはそれぞれ0から100までのスコアがつきます。 検出されなかった表情についてはスコアはつきません。

AWSのアカウントを持っている方は Rekognitionのコンソール画面からデモでお試しできます。

Rekognitionの注意点として現時点では使えるリージョンが限定されていて東京リージョンでは使えません。そのため、今回はOregon(us-west-2)を使いました。対象写真を格納しておくS3バケットも同じリージョンになります。

参考までに使用したコードはこちらです。

require 'optparse'
require "aws-sdk"
require 'dotenv'

options = {}
OptionParser.new do |opt|
  opt.on('-b VALUE', '--bucket VALUE', 'bucket name') { |v| options[:bucket] = v }
  opt.on('-p VALUE', '--prefix VALUE', 'key prefix') { |v| options[:prefix] = v }
  opt.on('-o VALUE', '--output VALUE', 'output directory') { |v| options[:output] = v }
  opt.parse!(ARGV)
end

Dotenv.load

Aws.config = {
  access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
  secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
  region: 'us-west-2'
}

bucket = options[:bucket] || 'your_default_bucket'
prefix = options[:prefix] || ''
output_directory = options[:output] || '.'

s3 = Aws::S3::Client.new(region: 'us-west-2')
keys = s3.list_objects(bucket: bucket, prefix: prefix).contents.map do |object|
  object.key
end
puts "#{keys.count} objects"

rekog = Aws::Rekognition::Client.new(region: "us-west-2")
keys.each do |key|
  puts key

  result = rekog.detect_faces({
    image: {
      s3_object: {
        bucket: bucket,
        name: key
      },
    },
    attributes: ["ALL"]
  })

  output_filename = output_directory + "/" + File.basename(key, '.jpg') + ".json"
  File.write(output_filename, result.to_h.to_json)
end

分析

とりあえず、3枚以上購入があった写真を1000枚抽出して顔認識を行い結果を見てみました。1000枚なのは私の体力的な都合によるものです。

結果

まず、検出した顔が1つの写真に絞り集計してみます。(購入者のお子様だと考えられ、結果の解釈がしやすいため)

表情 カウント スコア平均値
HAPPY 95 73.5
SURPRISED 19 52.5
CALM 3 40.4
CONFUSED 9 35.6
DISGUSTED 3 45.8
ANGRY 9 54.0
SAD 23 36.9

実際の写真も確認して、まとめると

  • 当然ながら HAPPY が多くそのスコアも高い
  • 真面目な表情(何かに真剣に取り組んでいたりetc)は SURPRISED, CALM, CONFUSED あたりでそこそこカウントされた
  • ANGRY, SAD が想定よりカウントが多い。。

ANGRY, SAD となった写真を確認してみると実際には怒ったり悲しい表情をしているというより 下向き顔が多く、機械学習をかけるとこの分類になりやすいようです。下向き顔 = うつむき顔 = 悲しい ということで分類としては妥当な気がしました。

園児がデスクワークしている姿を保育士が立った位置から撮影するとどうしても園児の顔向きとしてはうつむき加減になってしまいます。このような子どもが作業に没頭している写真も残しておきたい大事な1枚ということになります。

続いて、集計する顔の数を増やしてみましたが傾向は大きく変わりませんでした。

今後…

購入のなかった写真には HAPPYな顔は少ないのか? と言ったら恐らくそうとは言えず(自分の子ども以外は良い写真であっても基本的には買わないため)今回の分析には課題や突っ込みどころがたくさんあります。(頑張って数値解析したら有意な差が出るかも?)

ただ、自分の子どもが写っている写真がたくさんある中、購入する写真はそのごく一部であり購入された写真には親の感情により響く、言わばハッピーをより感じさせる何か画像特徴としてのエッセンスがあると考えています。

引き続き検討を行い、保護者が感じるハッピーのエッセンスをシステムとして抽出し、それにマッチする写真を優先的に届けられたらなと思います。ƪ(•◡•ƪ)"