超小型のシングルボードコンピューター「Raspberry Pi」は安価で拡張性も高いのが魅力ですが、実際に外部モジュールなどと連携して使用するためにはプログラムで機器の動作を制御する必要があります。 今回はRaspberry Piにカメラモジュールと画像認識ライブラリー「OpenCV」を用いて、カメラモジュールが捉えた画像から人の顔を判別して動作するプログラムをいくつかご紹介します。
画像認識の流れ
今回はRaspberry Piに接続したカメラモジュールで捉えた画像を「OpenCV」と呼ばれる画像認識ライブラリーを用いて人の顔かどうかを判別します。
「OpenCV(Open Source Computer Vision Library、オープンシーブイ)」はオープンソースの画像認識ライブラリ(プログラムの集まり)で、カメラが捉えた画像の解析、パターン認識による物体検出や機械学習のための画像処理など、様々な機能を備えており、Raspberry Piで多く用いられるプログラミング言語Pythonにも対応しています。
今回はRaspberry Pi上のプログラムにより人の顔を認識したことをきっかけ(トリガー)に顔を枠で囲んだり顔写真を撮影したりします。
今回の具体的な画像認識の流れですが、カメラモジュールを接続したRaspberry Piで撮影した画像を、OpenCVがあらかじめ準備しておいた機械学習の結果データ(カスケード分類器)を参照し、捉えた画像が人の顔(今回は人の顔かどうか、と目を判別しています)かどうかを判別します。
今回の記事では、判別した結果に基づき、下記3種の動作を行うプログラムを作成します。
- 人の顔と目を枠で囲んで撮影する
- 人の顔を判別したらシャッターを切る
- 動画の中で顔に追従して枠を表示する
画像認識の準備
OpenCVのセットアップ
まずRaspberry Pi上でOpenCVを使用するためのセットアップを行います。
画面上部のメニューから下図アイコンをクリックし「LXTerminal」を開きます。
起動したLXTerminal画面(以下「ターミナル」)で下記コマンドを入力し、Python対応版のOpenCVをインストールします。
sudo apt-get install python-opencv
機械学習データ(カスケード分類器)の準備
カメラが捉えた画像がなんの画像かを判別するために、判別したいものの特徴をあらかじめまとめておいたデータが必要となります。
今回は人の顔を認識するために「人の顔か」「人の顔ではないのか」を判定するために、人の顔が含まれる画像の特徴をまとめたデータを準備しています。このまとめたデータのことを「カスケード分類器」と呼びます。
通常はこの「カスケード分類器」を作成するために、大量の画像を用意し、「これは人の画像」「これは人の画像ではない」と、プログラムに学習させる必要がありますが、OpenCVには人の顔を判別するカスケード分類器があらかじめ用意されていますので、今回はそちらを使用したいと思います。
OpenCVはファイルなどの変更履歴を管理する「Git」という仕組みを使ってファイルを公開しているサービス「Github」ダウンロードします。ブラウザで下記のURLにアクセスしてください。
“GitHub – opencv/opencv: Open Source Computer Vision Library”
https://github.com/opencv/opencv/
アクセスしたら、「Clone or download」をクリックしてください
クリックすると、「Download ZIP」というボタンが表示されますのでクリックしてダウンロードを開始します。
ダウンロードが終了したら、「LXTeminal」に戻ります。
ターミナル上で下記コマンドを実行し、「Downloads」ディレクトリへ移動します。
cd Downloads
移動したら、先ほどダウンロードしたファイルを解凍します。
今回はコマンドでファイルを解凍したいと思います。
ターミナル上で
unzip opencv-master.zip
コマンドを実行してください
「Downloads」フォルダ内に解凍された「opencv-master」フォルダができています。
続いて「opencv-master」フォルダをダブルクリックします。
「opencv-master」フォルダ内の「data」フォルダをダブルクリックします。
dataフォルダの中にある「haarcascades」フォルダがあることを確認してください。
この「haarcascades」フォルダに「カスケード分類器(判別する対象物の画像的特徴を学習した結果データ)」が格納されています。
カスケード分類器ファイルはそれぞれ下記のような対象物に関するデータとなっています。
- haarcascade_eye.xml 目
- haarcascade_eye_tree_eyeglasses.xml 眼鏡
- haarcascade_frontalcatface.xml 猫の顔(正面)
- haarcascade_frontalcatface_extended.xml 猫の顔(正面)
- haarcascade_frontalface_alt.xml 顔(正面)
- haarcascade_frontalface_alt2.xml 顔(正面)
- haarcascade_frontalface_alt_tree.xml 顔(正面)
- haarcascade_frontalface_default.xml 顔(正面)
- haarcascade_fullbody.xml 全身
- haarcascade_lefteye_2splits.xml 左目
- haarcascade_licence_plate_rus_16stages.xml ロシアのナンバープレート(全体)
- haarcascade_lowerbody.xml 下半身
- haarcascade_profileface.xml 顔(証明写真)
- haarcascade_righteye_2splits.xml 右目
- haarcascade_russian_plate_number.xml ロシアのナンバープレート(数字)
- haarcascade_smile.xml 笑顔
- haarcascade_upperbody.xml 上半身
今回はこの中で「haarcascade_eye.xml」目と「haarcascade_frontalface_alt.xml」顔を使用します。
使用するカスケード分類器ファイルを変更すると、「猫の顔」や「笑顔」を検出することも可能になります
「haarcascades」フォルダを「home/pi」ディレクトリーにドラッグ&ドロップして移動します。
移動ができたら、再び「LXTerminal」の方に戻ります。
先ほどの操作を終えた状態では現在「Downloads」ディレクトリにいるはずですので、下記コマンドを入力して一階層上のディレクトリ(home/pi)に戻ります。
cd ../
顔と目に枠を描画するプログラム
カスケード分類器の準備ができたら、実際にソースコードを書いてOpenCVを使ってみましょう
まずは顔と目に枠を描画するプログラムを作成します。
今から作成するプログラムを実行すると、カメラが起動して映像が出力され、一定時間経過すると、カメラが撮影を開始して画像を保存します。
撮影された画像の中で顔が認識されると、顔の枠が赤い枠で囲まれ、目を認識すると緑の枠で目が囲まれた状態で画像ファイルが上書き保存されます。
プログラムを作成するために、ターミナル上で下記コマンドを入力し、新たに「camface.py」をvimで作成する画面を開きます。
sudo vim camface.py
vimエディタが開いたら、「i」キーを押して「編集モードに」に移行し、下記のソースコードをコピー&ペーストしてください。
# -*- coding: utf-8 -*- import time import picamera import cv2 as cv fn = 'my_pic.jpg' # カメラ初期化 with picamera.PiCamera() as camera: # 解像度の設定 camera.resolution = (512, 384) # 撮影の準備 camera.start_preview() # 準備している間、少し待機する time.sleep(2) # 撮影して指定したファイル名で保存する camera.capture(fn) # 撮影した写真を読み込む img = cv.imread(fn) # 顔検出の処理効率化のために、写真の情報量を落とす(モノクロにする) grayimg = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 顔検出のための学習元データを読み込む face_cascade = cv.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml') # 目検出のための学習元データを読み込む eye_cascade = cv.CascadeClassifier('haarcascades/haarcascade_eye.xml') # 顔検出を行う facerect = face_cascade.detectMultiScale(grayimg, scaleFactor=1.2, minNeighbors=2, minSize=(1, 1)) # 目検出を行う eyerect = eye_cascade.detectMultiScale(grayimg) print(facerect) print(eyerect) # 顔を検出した場合 if len(facerect) > 0: # 検出した場所すべてに赤色で枠を描画する for rect in facerect: cv.rectangle(img, tuple(rect[0:2]), tuple(rect[0:2]+rect[2:4]), (0, 0, 255), thickness=3) # 目を検出した場合 if len(eyerect) > 0: # 検出した場所すべてに緑色で枠を描画する for rect in eyerect: cv.rectangle(img, tuple(rect[0:2]), tuple(rect[0:2]+rect[2:4]), (0, 255, 0), thickness=3) # 結果の画像を表示する cv.imshow('camera', img) # 結果を書き出す cv.imwrite(fn, img) # 何かキーが押されるまで待機する cv.waitKey(0) # 表示したウィンドウを閉じる cv.destroyAllWindows()
コピー&ペーストができたら、「編集モード」から「Esc」キーを押して「コマンドモード」に切り替え、「Shift」キーを押しながら「z」キーボードを2回押してvimエディタを閉じます。
vimエディタを閉じたら、プログラムを実行してみます。
下記コマンドを入力してプログラムを実行してください。
sudo python camface.py
実際にプログラムが動作している様子は下記の動画をご覧ください。
顔を認識したら写真を撮影するプログラム
次は顔を認識したら自動で写真を撮影するプログラムを作ってみます。
プログラムを実行すると、カメラの映像が出力され、映像の中に「顔」を認識すると、自動でシャッターを切り画像を保存します。
今回はファイルの名前を「camface2.py」で作成します。
先ほどと同様にターミナル上で下記コマンドを入力し、「camface2.py」を作成した状態でvimエディタを開きます。
sudo vim camface2.py
vimエディタが開いたら、「i」キーを押して「編集モード」に移行し、下記のソースコードをコピー&ペーストしてください。
# -*- coding: utf-8 -*- import picamera import picamera.array import cv2 as cv # カメラ初期化 with picamera.PiCamera() as camera: # カメラの画像をリアルタイムで取得するための処理 with picamera.array.PiRGBArray(camera) as stream: # 解像度の設定 camera.resolution = (512, 384) while True: # カメラから映像を取得する(OpenCVへ渡すために、各ピクセルの色の並びをBGRの順番にする) camera.capture(stream, 'bgr', use_video_port=True) # 顔検出の処理効率化のために、写真の情報量を落とす(モノクロにする) grayimg = cv.cvtColor(stream.array, cv.COLOR_BGR2GRAY) # 顔検出のための学習元データを読み込む face_cascade = cv.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml') # 顔検出を行う facerect = face_cascade.detectMultiScale(grayimg, scaleFactor=1.2, minNeighbors=2, minSize=(100, 100)) # 顔が検出された場合 if len(facerect) > 0: # そのときの画像を保存する cv.imwrite('my_pic2.jpg', stream.array) break # カメラから取得した映像を表示する cv.imshow('camera', stream.array) # カメラから読み込んだ映像を破棄する stream.seek(0) stream.truncate() # 何かキーが押されたかどうかを検出する(検出のため、1ミリ秒待つ) if cv.waitKey(1) > 0: break # 表示したウィンドウを閉じる cv.destroyAllWindows()
コピー&ペーストができたら先ほどと同様に、「編集モード」から「Esc」キーを押して「コマンドモード」に切り替え、「Shift」キーを押しながら「z」キーボードを2回押してvimエディタを閉じます。
vimエディタを閉じたら、下記コマンドを入力し、「camface2.py」を実行します。
sudo python camface2.py
下記動画を見ていただくと、隠していた顔がカメラに捉えられた瞬間にシャッターが切られる様子が分かると思います。
動画の中で顔を捕捉、追従するプログラム
先ほどのプログラムを応用すると、動画内で顔を捕捉しながら追従するプログラムも作成することができます。
このプログラムは顔を認識すると赤い枠で顔を囲み、人が動くと人の顔を追いかけながら赤い枠が追従していくというプログラムです。
# -*- coding: utf-8 -*- import picamera import picamera.array import cv2 as cv # カメラ初期化 with picamera.PiCamera() as camera: # カメラの画像をリアルタイムで取得するための処理 with picamera.array.PiRGBArray(camera) as stream: # 解像度の設定 camera.resolution = (512, 384) while True: # カメラから映像を取得する(OpenCVへ渡すために、各ピクセルの色の並びをBGRの順番にする) camera.capture(stream, 'bgr', use_video_port=True) # 顔検出の処理効率化のために、写真の情報量を落とす(モノクロにする) grayimg = cv.cvtColor(stream.array, cv.COLOR_BGR2GRAY) # 顔検出のための学習元データを読み込む face_cascade = cv.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml') # 顔検出を行う facerect = face_cascade.detectMultiScale(grayimg, scaleFactor=1.2, minNeighbors=2, minSize=(100, 100)) # 顔が検出された場合 if len(facerect) > 0: # 検出した場所すべてに赤色で枠を描画する for rect in facerect: cv.rectangle(stream.array, tuple(rect[0:2]), tuple(rect[0:2]+rect[2:4]), (0, 0, 255), thickness=3) # 結果の画像を表示する cv.imshow('camera', stream.array) # カメラから読み込んだ映像を破棄する stream.seek(0) stream.truncate() # 何かキーが押されたかどうかを検出する(検出のため、1ミリ秒待つ) if cv.waitKey(1) > 0: break # 表示したウィンドウを閉じる cv.destroyAllWindows()
下記動画を見ていただくと、顔に追従して赤い枠が動く様子がよく分かります。
まとめ
今回はRaspberry Piでの画像認識にOpenCVを用いて挑戦してみました。少ない手間で画像認識を試したい場合OpenCVの「カスケード分類器」を使用するのはとても便利ですが、「カスケード分類器」のファイルは自分で作成することも可能です。
別の機会に自分でカスケードファイルを作成して画像認識を行う手順についても紹介したいと思います。
石郷祐介
大学卒業後、公設研究機関勤務を経て、「情報科学芸術大学院大学[IAMAS]」に入学。
専門学校講師を経て、企業の研究開発をコンセプトから開発まで支援する「合同会社4D Pocket」代表、エンジニアを養成するフリースクール「一般社団法人HOPTER TECH SCHOOL」代表理事、「名古屋文理大学」及び「名古屋造形大学」非常勤講師。