顔写真のトリミング

身分証明書の発行のために

仙台商業高等学校では、写真屋さんに全生徒の証明写真を撮影して頂き、そのデータを基に、学校で身分証明書を発行しています。しかし、写真屋さんから頂くデータはトリミングされていないため、全校生徒の写真のトリミングという作業が発生します。この作業は一人一人手作業やっていては日が暮れます。そこで、AIを用いて、写真のトリミングをしています。

インターネットで検索しても、そのやり方を詳しく書いているページがあまり無かったので、ここで備忘録として紹介してみます。

Python環境の構築

まず、学校のPCは簡単にソフトを入れられないようになっています。情報システム部にかけあって、環境を構築しなければいけません。基本的には、pythonのスクリプトが動くように、pythonのインストール。それから、OpenCVを用いてトリミングしますので、OpenCVのインストールが必要になります。

OpenCVで使うカスケード分類器はこちらからダウンロードしてしかるべき場所(下記コード参照)に保存しておきます。

OpenCVのcascadeファイル
https://github.com/opencv/opencv/tree/master/data/haarcascades

ここにある分類器のうち、私が使ったのは以下の2つなのでそれがあれば動きます。

  • haarcascade_frontalface_alt.xml
  • haarcascade_frontalface_default.xml

AIが発達してきたとはいえ、これらの技術はもう10年前なんですね・・・。そしてそれが未だに最前線という話ですが。

トリミング

そして、次のコードを、新規テキストドキュメントとして、トリミングする写真が入ったフォルダに保存し、拡張子を.txtから.pyに変えて、ダブルクリックで実行すると、trimというサブフォルダが作られ、そこにトリミングされた写真が800×600にリサイズされ、保存されていきます。

#リソースのインポート
import cv2
import glob
import os

#trimフォルダの作成
os.makedirs('trim', exist_ok=True)

#カスケード型分類器に使用する分類器のデータ(xmlファイル)を読み込み
HAAR_FILE = "C:\opencv\sources\data\haarcascades\haarcascade_frontalface_alt.xml"
HAAR_SUB = "C:\opencv\sources\data\haarcascades\haarcascade_frontalface_default.xml"
cascade = cv2.CascadeClassifier(HAAR_FILE)
cascade2 = cv2.CascadeClassifier(HAAR_SUB)

#ファイルリストの取得
files = glob.glob("*.jpg")
for file in files:

    #取得したファイル名の表示
    print(file)

    #画像ファイルの読み込み
    img = cv2.imread(file)

    #グレースケールに変換
    img2 = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

    #カスケード型分類器を使用して画像ファイルから顔部分を検出する
    face = cascade.detectMultiScale(img2,scaleFactor=1.09,minNeighbors=5,minSize=(300,300))
    
    #検出できない場合、サブ検出器を試す
    if len(face) == 0:
        face = cascade2.detectMultiScale(img2,scaleFactor=1.08,minNeighbors=5,minSize=(300,300))

    #それでも検出出来ないときは、パラ編してメイン検出器を試す。
    if len(face) == 0:
        face = cascade.detectMultiScale(img2,scaleFactor=1.01,minNeighbors=2,minSize=(300,300))

    #更に検出できない場合、サブ検出器を試す
    if len(face) == 0:
        face = cascade2.detectMultiScale(img2,scaleFactor=1.01,minNeighbors=2,minSize=(300,300))
    
    #検出できないときは、赤斜線を引く
    if len(face) == 0:
        print("検出失敗")
        cv2.line(resize_img,(0,0),(450,600),(0,0, 255),20)
        
    else: 
        #顔部分を切り取り、リサイズする。複数検出する可能性があるので、face[0]を使用。
        x = face[0][0]
        y = face[0][1]
        w = face[0][2]
        h = face[0][3]
        #for x,y,w,h in face:

        #横幅のエリアを1.6倍にし、縦幅のエリアを2.23倍にすることで、4:3の比率でカット
        face_cut = img[y-int(h*0.55):y+int(h*1.583), x-int(w*0.3):x+int(w*1.3)]

        #カットした画像を800*600のサイにする。
        resize_img = cv2.resize(face_cut , dsize=(450, 600))

    #画像の出力
    cv2.imwrite('trim\\' + file , resize_img )

およそ900枚の写真のトリミングが数分で終わります。

来年度、機種更新になるそうなので、環境の構築からですがそれも勉強ですね。

過去に私が書いた記事はこちら

タイトルとURLをコピーしました