身分証明書の発行のために
仙台商業高等学校では、写真屋さんに全生徒の証明写真を撮影して頂き、そのデータを基に、学校で身分証明書を発行しています。しかし、写真屋さんから頂くデータはトリミングされていないため、全校生徒の写真のトリミングという作業が発生します。この作業は一人一人手作業やっていては日が暮れます。そこで、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枚の写真のトリミングが数分で終わります。
来年度、機種更新になるそうなので、環境の構築からですがそれも勉強ですね。
過去に私が書いた記事はこちら