写真内の顔を自動検出

写真内の顔を自動検出

私の職場では、パスポートサイズの写真をまとめてスキャンし、個別の写真に切り分けて、固有のファイル番号を付けて保存しています。現在は、Paint.net を使用して、写真を手動で選択、切り取り、保存しています。

ソニーのサイバーショットカメラには顔検出機能があるのを知りました。Google でも顔検出を検索すると iphoto に関する情報が表示されます。Picasa にも顔検出機能があります。文書内の顔を自動検出する方法はありますか。そうすれば、個々の画像を切り分けるのに必要な時間が短縮され、職場での生産性が向上します。

スキャンした文書のサンプル(実際の文書には 5 行に 4 枚の画像が並んでおり、合計 20 枚あります): (出典:http://www.memoryke​​eperphoto.com/images/passport_photo.jpg、フェアユース)

サンプル画像

たとえば、Picasa 3.8 では、[表示] > [人物] をクリックすると、すべての顔が表示され、名前を付けるように求められます。これらの個々の写真を、名前を付けて別の写真として自動的に保存できますか。

答え1

パスポート写真を自動的に切り取るのは、間違いなくできそうです。照明条件を固定し、常に正面を向き、画像フォーマットを一定に保つ...顔検出にとってこれ以上の好条件は望めないと思います。

使ってみた顔検出サンプル画像の結果を確認するには:

生の顔検出出力

パスポートにはさまざまな形式とサイズがあるため、スキャナーのフラットベッドに不規則に詰め込まれますが、写真は常に垂直に配置するものと想定しています。facedetectすべての顔の中心とサイズがわかります。特に、顔のサイズを使用して、その周囲の領域を比例して切り取ることができます。パスポートの写真は写真の固定領域をカバーする傾向があるため、これは比較的安全な仮定のようです。

画像のサブ領域を切り抜くのはとても簡単ですイメージマジックプロセスを自動化するために、小さな(そして大まかな)シェル スクリプトを作成しました。

#!/bin/sh
pc=60
files="P1Xb8.jpg"

fileno=1
for file in $files; do
  n=1
  facedetect $file | while read x y w h; do
    border=$(($w * $pc / 100))
    x=$(($x - $border))
    y=$(($y - $border))
    w=$(($w + $border * 2))
    h=$(($h + $border * 2))
    echo $x $y $w $h
    convert "$file" -gravity NorthWest -crop "${w}x${h}+$x+$y" "${fileno}_$n.jpg"
    n=$(($n + 1))
  done
  fileno=$(($fileno + 1))
done

私は、検出された顔の幅の 60% (スクリプトの 2 行目) の境界領域を経験的に定義しました。取得した 4 つの画像は次のとおりです。

1_1 1_2 1_3 1_4

これはすでにかなり良いです。上部には常にいくらかの空白が残りますが、呼び出し時に「-fuzz 10% -trim」を追加するだけで削除できましたconvert。その後の最初の画像の結果は次のとおりです。

1_1 トリミング

簡単なスクリプトとしては悪くない出来ですが、改善の余地は十分にあります。たとえば、ほとんどのパスポートは縦向きなので、垂直/水平係数が異なります (通常は 1.3)。また、顔はわずかに上方に移動する傾向があります (おそらく 1.3 程度)。これらを修正すると、切り抜きが改善され、上部の空白部分を完全にトリミングする必要がなくなります。

このスクリプトを実際の出力に対してテストするために、サンプルのフラットベッド スキャンを (非公開でも) 投稿していただければ幸いです。

もちろん、この提案には Linux のインストールが必要です。しかし、私の理解が正しければ、この面倒な作業を自動化するために専用のインストールや仮想マシンをセットアップすることは、まったく不合理ではありません。

プライバシーが問題にならないのであれば(私はそうは思いませんが)、私は実際に、切り取られた顔と引き換えに適切なソリューションの作成を手伝い、顔検出モデルの改善に役立てることに興味があります。

関連情報