はじめに
こんにちは!「顔認証AIブログ第3回」 を開いていただきありがとうございます! 今回のブログは、手始めにPythonを使った簡単な実装を行なっていきます。この記事を見ている人の中には、「プログラミングやったことない!」 って人もいると思うので、機械学習を使う前に少し基本的なプログラムを組んでみましょう!
この記事で書くこと
今回の記事では「顔データを収集するための実装」を行います!なぜ顔データを収集する必要があるのかと言うと、機械学習をするためには大量のデータが必要だからです。(ここら辺に関しては次回解説します。)前述の通り、画像処理に関して基本的な要素が詰まっている実装なので、プログラミングに慣れやすいと思います。
画像データを収集する
プログラムによって画像データを収集する、と聞いて少し難しそうと思った人もいると思いますが、全然そんなことはありません!前章で説明したOpenCVというライブラリを使えばさっくり作成することができます👌
主な手順は、
- webカメラを起動する
- 映像の中から顔を認識する
- 顔の領域を切り取って顔画像データとして保存
↑たったこれだけ!
下準備
実装の下準備をします。機械学習(深層学習)を行う場合、学習データとテストデータが必要です。詳しいことは次回説明しますが、ざっくり説明すると学習データが学習するためのデータ、テストデータが学習の精度を確かめるためのデータといった感じです!
なのでまず、学習データを格納するためのフォルダとテストデータを格納するためのフォルダを作ります。
Eclipse画面の左にある「プロジェクト・エクスプローラー」の中の、今回作成したプロジェクトの上で右クリック → 新規 → フォルダーを選択。
↑こんな感じで、まずは学習データとテストデータを格納するためのfacesフォルダを作成しましょう!(「親フォルダーを入力または選択:」の中身は今は気にしなくて良いです。)
作成できたら同じ手順で、facesフォルダの中にtrainフォルダ(学習用データ格納フォルダ)とtestフォルダ(テスト用データ格納フォルダ)を作りましょう!
↑うまくいくとこんな感じ
実装
それでは実装していきます!
python import cv2 import os import time from datetime import datetime as dt NAME = "hogehoge" print(NAME + "さんの顔データを取得します。") # カスケードパス cascade_path = '/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml' # カスケードを実行するためのパーツ faceCascade = cv2.CascadeClassifier(cascade_path) # 取得する顔の総数 cnt_max = 10 # 顔データのカウント cnt_face = 0 # 顔データを格納する配列 faces = [] # カメラ取り込み開始 cap = cv2.VideoCapture(0) while True: # フレームの取得 time.sleep(1) end_flag, c_frame = cap.read() # 画像取得 img = c_frame # グレースケールに変換して格納 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 画像上の顔領域を見つける face_list = faceCascade.detectMultiScale(img_gray, minSize=(100, 100)) # 画像上に複数の顔領域がある場合ループの最初へ if len(face_list) > 1: continue; # 顔領域を切り取って収集 for (pos_x, pos_y, w, h) in face_list: # 顔の切出 img_face = img[pos_y:pos_y+h, pos_x:pos_x+w] # 画像サイズ変更 img_face = cv2.resize(img_face, (100, 100)) # facesに顔画像を格納 faces.append(img_face) # 顔データのカウントを進める cnt_face+=1 print(cnt_face) # 指定した数分のデータを収集したら終了 if cnt_max == cnt_face: break; # カメラの領域を開放 cap.release() print("顔データの収集が終わりました。") print("顔データを名前ごとに振り分けます。") # 学習データの数 num = 0 # 画像データの名前の最初に付ける日付 tdatetime = dt.now() tstr = tdatetime.strftime("%Y%m%d%H%M") # 学習用データを入れるディレクトリを作成 path = os.getcwd() + '/faces/train/' + NAME os.makedirs(path) print("学習用データ格納用のディレクトリを作成", path) # trainディレクトリに学習用データを格納 for face in faces[:-1]: # "ファイル名"-"データ数カウント".jpg と言う名前のファイル名 filename = tstr + '-' + str(num) + '.jpg' print("\t", filename) # path/filename で顔画像データを書き込む cv2.imwrite(path + '/' + filename, face) # カウントを進める num += 1 # テスト用データを入れるディレクトリを作成 path = os.getcwd() + '/faces/test/' + NAME print("テストデータ", path) os.makedirs(path) # testディレクトリに学習用データを格納 face = faces[-1] # "ファイル名"-"データ数カウント".jpg と言う名前のファイル名 filename = tstr + '-' + str(num) + '.jpg' print("\t", filename) # path/filename で顔画像データを書き込む cv2.imwrite(path + '/' + filename, face)
↑ざっとこんな感じ
実装の解説
それでは実装の解説をしていきます!
初期設定部分
python import cv2 import os import time from datetime import datetime as dt NAME = "hogehoge" print(NAME + "さんの顔データを取得します。")
↑ここでは各種インポート、作成する顔データの人物名を入力します。(今は仮名として"hogehoge"さんになっています。)インポート部分では環境構築でインストールしたライブラリを呼び出します。
python # カスケードパス cascade_path = '/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml' # カスケードを実行するためのパーツ faceCascade = cv2.CascadeClassifier(cascade_path)
↑ここではカスケードの読み込みを行います。前章で説明したカスケード機はこのように記述することで呼び出すことができます。"cascade_path"の値に入っているパスはPCによって変わるので、自身の環境で適切なパスを記述してください!
python # 取得する顔の総数 cnt_max = 10 # 顔データのカウント cnt_face = 0 # 顔データを格納する配列 faces = [] # カメラ取り込み開始 cap = cv2.VideoCapture(0)
↑ここでは取得するデータの総数とwebカメラの起動を行います。今は仮で10としていますが変更することも可能です。カメラの呼び出しに関しては、なんとこの1行のみで完了です。
顔データ取得部分
python while True: # フレームの取得 time.sleep(1) end_flag, c_frame = cap.read() # 画像取得 img = c_frame # グレースケールに変換して格納 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 画像上の顔領域を見つける face_list = faceCascade.detectMultiScale(img_gray, minSize=(100, 100)) # 画像上に複数の顔領域がある場合ループの最初へ if len(face_list) > 1: continue;
↑ここからはループに入り顔画像を取得します。まずは"cap.read()"によってwebカメラに写っている映像から1フレームを切り取って、画像として"c_frame"に入れます。 カスケード機を使って顔領域を検出するためには白黒の画像でないといけないので、取得した画像を"cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)"によってグレースケールと言う形に変換します。その後、"faceCascade.detectMultiScale"によって"face_list"の中に画像上の顔領域の座標を格納します。顔領域が2つ以上検出された場合はやり直します。
python # 顔領域を切り取って収集 for (pos_x, pos_y, w, h) in face_list: # 顔の切出 img_face = img[pos_y:pos_y+h, pos_x:pos_x+w] # 画像サイズ変更 img_face = cv2.resize(img_face, (100, 100)) # facesに顔画像を格納 faces.append(img_face) # 顔データのカウントを進める cnt_face+=1 print(cnt_face) # 指定した数分のデータを収集したら終了 if cnt_max == cnt_face: break;
↑ループの後半部分。ここでは取得した顔領域の座標を元に顔画像を切り取ります。そして"cv2.resize()"によって顔画像を100x100の正方形に整形します。その後、顔画像を用の"faces"と言う配列の中に格納します。格納した個数をカウントしていき、指定数になったらループ終了です。
フォルダに画像を振り分ける部分
python # 学習データの数 num = 0 # 画像データの名前の最初に付ける日付 tdatetime = dt.now() tstr = tdatetime.strftime("%Y%m%d%H%M")
↑最後のフォルダに顔画像を振り分ける部分です。ここではファイル名にくっつける日付の文字列化を行います。ファイル名はそれぞれ異なる名前に設定する必要があります。 日付を用いることでお手軽にファイル名を異なるものに設定することができます。
python # 学習用データを入れるディレクトリを作成 path = os.getcwd() + '/faces/train/' + NAME os.makedirs(path) print("学習用データ格納用のディレクトリを作成", path) # trainディレクトリに学習用データを格納 for face in faces[:-1]: # "ファイル名"-"データ数カウント".jpg と言う名前のファイル名 filename = tstr + '-' + str(num) + '.jpg' print("\t", filename) # path/filename で顔画像データを書き込む cv2.imwrite(path + '/' + filename, face) # カウントを進める num += 1
↑ここではまずtrainフォルダのなかに、入力された名前のフォルダを作成します。"os.getcwd()"はカレントディレクトリ(今いるディレクトリ)を示すので、このようにパスを記述し、"os.makedirs()"を使用することで作成できます。 その後、先ほど顔データを入れたfacesの中身を一つずつ回していき、ファイル名に"(日付)_(ナンバー).jpg"を割り当てて保存していきます。
python # テスト用データを入れるディレクトリを作成 path = os.getcwd() + '/faces/test/' + NAME print("テストデータ", path) os.makedirs(path) # testディレクトリに学習用データを格納 face = faces[-1] # "ファイル名"-"データ数カウント".jpg と言う名前のファイル名 filename = tstr + '-' + str(num) + '.jpg' print("\t", filename) # path/filename で顔画像データを書き込む cv2.imwrite(path + '/' + filename, face)
↑テストデータ用フォルダについても同様です。
結果確認
正常に動作すると、このように画像データとテストデータが指定個数格納されます!
↑中身はこんな感じ。
しっかり格納できて入れば無事成功です!
最後に
第3回の記事はいかがだったでしょうか!
これで画像データは取得し放題なので、次回からは機械学習の部分についてやっていきます。お楽しみに!
ではでは👋