見出し画像

【iOS】ガイドライン付き写真判定機能の紹介

自己紹介

こんにちは、プロダクト開発部のyuyaです。
普段の業務では、画像解析や機械学習などをメインにおこなっています。
最近は、弊社に機械学習やデータサイエンティストのメンバーが増え、とても嬉しいです。
弊社のデータサイエンスチームでは、おもにマッチングアプリに関連した機能を手掛けています。
今回は、プロフィール写真を自撮りする際のサポート機能としてiOSに実装したガイドライン付き写真判定機能を紹介します。


背景

マッチングアプリ内でプロフィール写真は非常に重要なファクターであり、顔写真の写りによってマッチ率は大きく変わってきます。
しかし、現状は不鮮明で写りが良くない写真を使用しているユーザーが多く見受けられます。
そこで今回は写真写りを改善する手段の1つとして、ガイドライン付き写真撮影機能を実装しました。
具体的には自撮り撮影をする際に、顔や身体を収めるガイドラインが出現し、そのガイドラインに正しく収まっているかどうかを判定する機能です。
この機能によって顔の距離が近すぎたり、顔が画面の端で見切れたりするなどのケースを防ぎ、写真写りの改善が見込めます。

機能の紹介

本機能のデモ映像になります。

顔がガイドラインに収まるときに「OK」と画面下に表示しています。撮影者の様々な状況を考慮し、正確に一致したときだけではなく、ある程度ガイドラインに顔が入っていればOK判定となるように判定に余裕を持たせています。
また、顔がカメラに近い場合は、ガイドラインに顔の一部が含まれていてもOK判定がされないようにしました。
判定は顔のみ行なっております。こちらも撮影者の様々な状況を考慮し、姿勢やポーズのガイドラインはあくまで撮影時の参考程度の役割になっております。

実装の解説

1. リアルタイム顔検出

カメラに映る映像から顔を検出するために、ML Kitを使いました。
ML Kitは、Googleが提供するモバイルアプリ向けの機械学習モデルを提供するサービスです。オンデバイスで学習済みモデルを利用できるため、ネットワークの通信が不要となり高速で安定した運用が可能となります。今回のような、常に映像から顔を検出するようなリアルタイム性が要求されるケースに最適です。
ML Kitの顔検出では、画像から顔や各パーツの輪郭座標が取得できます。

2. 判定方法の概要

顔がどれくらいガイドラインに収まっているかの判定方法について解説します。
まず考えられるアプローチとしては、ガイドラインの顔面積とML Kitで検出された顔面積、またその両者が重なっている領域の面積を求めてそれらの比を計算する方法があります。

しかし、カメラのフレームごとに変化する顔の面積から重なっている領域を都度計算する処理は、計算量が大きくなってしまいます。
今回は、各フレーム内で処理をするため、短時間で判定を終える必要があります。そのため、なるべくプログラムの計算量を小さくするべきと考えました。
そこで少ない計算量で正しく判定する手法として、顔領域の中心点に着目した判定方法を考案しました。
本手法では、ガイドラインの顔の中心点から一定半径をとった円の領域に、顔の中心点が入ったかどうかを判定します。

顔の中心点がオレンジの領域外の場合は、顔とガイドラインの重なる領域が小さくなるため判定は×、領域内に入った場合は、重なる領域が大きくなるため判定は○とします。

しかし、このままだと領域内にさえ入っていれば、ガイドラインに対し顔が著しく大きい場合でも判定が○となってしまいます。
そのケースに対応するために、顔とガイドラインの面積比が一定以上になる場合は判定を×とするようにしています。

本手法により、冒頭のデモ映像のような正しいガイドライン判定が実現できました。
また実装コストと計算量をかなり抑えることにも成功しました。
次の章より具体的な実装方法を解説します。

3. 機種間の判定処理の統一方法

スマートフォンは機種によって画面サイズが異なります。カメラの映像を映すViewの縦幅と横幅の比率が機種ごとに変わると、画面内のガイドラインの位置やサイズがそれに合わせて変わってしまうため、判定機能の実装が複雑になってしまう問題があります。

そこで機種ごとのガイドライン判定処理を統一するために、カメラの映像を映すViewの縦横比を固定するようにしました。
どの機種でもViewを縦横1.3:1のサイズで作成し、またガイドライン用画像もそれと同じ比率で作成します。そうすることで機種が変わってもViewに投影されるガイドラインの位置とサイズを統一することができます。

4. ガイドラインの顔の計測

事前準備として、ガイドラインの顔領域の中心点と面積を画像全体から見た相対値で求めておきます。
ガイドライン画像(1000×1300[pixel])における顔の中心点が(600,540)だった場合、中心点の相対値は(0.6, 0.42)となります。この値は画像全体に対する中心点の相対的な位置であり、画像左上を原点としx座標が60%、y座標が42%の位置に中心点があることを示しています。

顔の面積は画面の面積を1とし、その相対値として求めます。
顔の面積は、顔領域に近似させた楕円の面積と考え計算します。楕円に近似することで、ガイドライン画像が変更された際にも容易に算出できます。
今回の例では顔の面積の相対値が0.089となりました。この値は、画像全体に対し、顔の面積が約9%であることを示しています。

絶対値から相対値に変換することで、機種ごとに画面のサイズが異なる場合も共通した値として使用できます。

これらの値は事前に計測し、以下のように定数として定義しておきます。

class GuidelineData {
static let faceMidPoint = CGPoint(x: 0.6, y: 0.42)
static let faceAreaRelativeValue = 0.089
...
}

5. 撮影者の顔の計測方法

ML Kitで検出された顔に対しても同様に、中心点と面積の相対値を計算します。

赤い点線で囲われた領域の面積を求めるには、実装コストと計算量が大きくなってしまいます。また、この点線はおでこの上部や髪まで含まれないため、計算量が大きい割に正確さに欠けます。
よって顔の中心と面積を以下のように定めます。

  • 顔の中心点:緑色の四角形の中心点

  • 顔の面積:四角形の面積を0.7倍した値

顔の面積の計算については、四角形の面積から実際の顔の面積に近づけるために定数倍しています。0.7倍とした理由は、四角形と実際の顔の面積比を10ケース計測し、それらの平均値が約0.7になったためです。
ガイドラインと同様に、算出した値を相対値に変換しておきます。

6. 判定方法の定義

6-1. 顔中心点の許容範囲領域による判定ついて

先ほど計測したガイドラインの面積と同じ面積になる正円を求め、その直径を半分にした円を顔中心点の許容範囲とします。
この範囲の領域となる円の直径を変えることで、判定の厳しさを自由に変えることができます。

範囲領域の形状を正円にした理由は、顔の中心点がこの領域に入っているかどうかの計算を簡単にするためです。
以下の図のように「顔の中心点からガイドラインの中心点の距離」と「領域の円の半径」を比較することで判定します。
顔中心点がオレンジの領域に入っていれば判定を○(許容する)、顔中心点がオレンジ領域に入っていなければ判定を×(許容しない)とします。

判定処理のソースコードは以下のようになります。正円を用いることで、とても単純な計算で判定が可能になります。

// 判定処理のソースコード例
class GuidelineData {
    static let faceMidPoint = CGPoint(x: 0.6, y: 0.42)
    ...
    // 顔中心点許容円の半径
    static var toleranceRadius: Double {
        ...
    }
    ...
    
    // ある座標が顔中心点許容円に入っているかどうか
    static func isPointInToleranceCircle(point: CGPoint) -> Bool {
        // 円の中心点からの距離
        let distance = sqrt(pow(point.x-faceMidPoint.x, 2) + pow(point.y-faceMidPoint.y, 2))
        return distance < toleranceRadius
    }
}

6-2. 面積による判定について

今回は、顔の面積がガイドラインの面積の2倍以上、または1/2倍以下のとき
に判定×としました。
面積の判定も閾値を変更することで、判定の厳しさを変更可能です。

7. デモ

顔の中心点、顔中心点許容領域、面積比を可視化してみました。

青い点が顔の中心点、顔中心点許容領域がオレンジであり、面積比を画面下部に出力しています。
想定通りの判定がされていることがわかります。

8. 機能間の疎結合化

本機能は、顔検出とガイドライン判定の2つの機能の組み合わせで構成されています。
今回は、顔検出にML Kitを用いましたが、今後ほかのアルゴリズムに変更する可能性も考えられます。
そこで、改修のしやすい設計にするために2つの機能が疎結合になるようにしました。
実装はSwiftを用いており、処理のフローは以下の図のようになっております。はじめに、カメラを写すViewControllerから顔検出クラスへカメラのフレームデータを送ります。そして顔検出クラスで顔を検出しその情報をViewControllerに返します。ViewControllerは、受け取った顔の情報からガイドライン判定をし画面へ描画を行います。

以下の図のように、protocolを用いることでViewControllerと顔検出クラスを疎結合にしています。顔検出機能を別のアルゴリズムに変更する際は、protocolを実装したクラスを作るだけで良いため、安全な機能改修が可能になります。

まとめ

今回は、ガイドライン付き写真判定機能を紹介しました。
本手法は少ない計算量で動作するため、システムへの負荷も少なく、また機能調整や改修がしやすい構成となっています。
今回「顔とガイドラインの重なり度合い」の問題を正円を用いた計算で単純化したように、ビジネス課題を達成するための研究開発では、問題を抽象化して扱うことも重要だと考えています。

この機能はまだ未導入ですが、最適なデザインやUXになるように機能を調整して、導入できたら良いなと思います。
今後も、サービスの質が上がるような機能の開発をしていきたいです。
研究開発は新たな知見を得ることができ、とても刺激的です。
今後は機械学習やデータサイエンス領域にも力を入れていくので、興味のある方はぜひ弊社の求人をご覧になってください。

Newbeesでは一緒に働く仲間を募集しています

Newbeesはフルリモート&フレックス勤務を導入し、場所にとらわれない自由な仕事のやり方が可能です。詳細は以下をご覧ください。

みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!