LoginSignup
8
15

More than 5 years have passed since last update.

Raspberry Pi CameraモジュールとOpenCVで人間の顔を認識する

Posted at

環境

  • Raspberry Pi 3B (Raspbian 9.4) + Camera Module V2
  • OpenCV 3.4.3

OpenCVのインストール

インストールはチュートリアルのとおりでいけました。
https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html

NOTE: aptリポジトリにもpython-opencvがあるので、古いバージョンでもよければこちらを入れた方が簡単ですね。検出性能は...低いかもしれません。

pi@raspberrypi:~$ apt search python-opencv
ソート中... 完了
全文検索... 完了  
python-opencv/stable 2.4.9.1+dfsg1-2 armhf
  Python bindings for the computer vision library

必要パッケージのインストール

# apt-get install build-essential
# apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
# apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

OpenCVのダウンロード

最新のソースはこちらから

# curl -OL https://github.com/opencv/opencv/archive/3.4.3.zip
# unzip 3.4.3.zip
# cd opencv-3.4.3/

ビルドとインストール

makeにはかなり時間がかかります。私の環境では一度端末がフリーズしてしまいました...

# # IN "opencv-3.4.3/" DIR
# mkdir build
# cd build
# cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
# make
# make install

Pythonのモジュールは /usr/local/lib/PYTHON_VERSION/dist-packages/ にインストールされています。

pi@raspberrypi:~$ ls /usr/local/lib/{python2.7,python3.5}/dist-packages/
/usr/local/lib/python2.7/dist-packages/:
cv2.so

/usr/local/lib/python3.5/dist-packages/:
cv2.cpython-35m-arm-linux-gnueabihf.so

インストールの検証

$ python3 -c "import cv2; print(cv2.__version__)"
3.4.3

カメラの準備

接続とデバイスの有効化

カメラモジュールを接続したら、デバイスを有効化する必要があります。
カメラの接続方法とGUIからデバイスを有効化する方法は公式ページにステップバイステップ手順があります。
https://projects.raspberrypi.org/en/projects/getting-started-with-picamera

コマンドラインから行う場合は、カメラ接続後 raspi-config を起動して "5 Interfacing Options" ---> "P1 Camera" メニューでカメラデバイスを有効化します。設定変更後デバイスを再起動します。

$ sudo raspi-config

カメラのテスト

$ raspistill -v -o test.jpg

カメラで撮った画像から人間の顔を探す

公式の顔検出サンプルコードは下記URLにあります。下記コードは公式のサンプルコードを一部改変したものです。
https://docs.opencv.org/3.4.3/d7/d8b/tutorial_py_face_detection.html

Cameraモジュールで写真を撮る

Cameraモジュールを起動してカレントディレクトリに写真を保存します。
写真を撮る前に3カウントしています。

pic_file = './picamera_work.jpg'
if os.path.exists(pic_file):
    os.remove(pic_file)

camera = PiCamera()
for i in range(3, 0, -1):
    print(i)
    sleep(1)
camera.capture(pic_file)

camera.capture(output)はカメラで撮った写真をoutputで指定されたパスに保存します。ファイルパスの代わりにファイルオブジェクトを渡すこともできます。
保存する画像のフォーマットはファイル名から推測してくれます (例: *.jpg=>JPEGファイル)。format=FORMATで指定することもできます。
https://picamera.readthedocs.io/en/release-1.13/api_camera.html#picamera

OpenCVの学習済分類器をロードする

OpenCVでは学習済の分類器をいくつか提供しています。
分類器は/usr/local/share/OpenCV/haarcascades/にインストールされています。

分類器をロードするにはCascadeClassifierコンストラクタにパラメータとして渡すか、loadメソッドを別途呼び出します。
下記コードサンプルでは目と顔の分類器をそれぞれロードしています。

face_classifier = "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(face_classifier)
eye_classifier = "/usr/local/share/OpenCV/haarcascades/haarcascade_eye.xml"
eye_cascade = cv2.CascadeClassifier(eye_classifier)

顔を検出する

detectMultiScaleで顔を検出します。
http://opencv.jp/opencv-2.1/cpp/object_detection.html#cv-cascadeclassifier-detectmultiscale
detectMultiScaleは与えられた画像を縮小しながら何度も検出を試みます。パラメーターscaleFactorには画像の縮小量を設定します。
最終的に検出される物体は少なくともminNeighborsで指定された分だけ近傍矩形を含む必要があります。minNeighborsに小さな値を指定すると検出できる割合は増えますが、誤検出も増えます。

pic = cv2.imread(pic_file)
pic_gray = cv2.cvtColor(pic, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(
    pic_gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30))

scaleFactorの働きはこちらのQAが理解の助けになりました。
http://answers.opencv.org/question/10654/how-does-the-parameter-scalefactor-in-detectmultiscale-affect-face-detection/

検出したオブジェクトを表示する

検出した顔のエリアを線で囲っています。さらにそのエリア内で目を検出して、見つかった場合はそのエリアも線で囲います。

for (x, y, w, h) in faces:
    cv2.rectangle(pic, (x, y), (x + w, y + h), (255, 0, 0), 2)
    roi_gray = pic_gray[y:y+h, x:x+w]
    roi_color = pic[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex, ey, ew, eh) in eyes:
        cv2.rectangle(roi_color, (ex,ey), (ex+ew,ey+eh), (0,255,0), 2)

cv2.imshow("Raspberry pi camera detects {0} faces".format(len(faces)), pic)
cv2.waitKey(0)
cv2.destroyAllWindows()

コード全体

from picamera import PiCamera
from time import sleep
import cv2
import os
import sys

pic_file = './picamera_work.jpg'

if os.path.exists(pic_file):
    os.remove(pic_file)

camera = PiCamera()
for i in range(3, 0, -1):
    print(i)
    sleep(1)
camera.capture(pic_file)

face_classifier = "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(face_classifier)
eye_classifier = "/usr/local/share/OpenCV/haarcascades/haarcascade_eye.xml"
eye_cascade = cv2.CascadeClassifier(eye_classifier)

pic = cv2.imread(pic_file)
pic_gray = cv2.cvtColor(pic, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(
    pic_gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30))

for (x, y, w, h) in faces:
    cv2.rectangle(pic, (x, y), (x + w, y + h), (255, 0, 0), 2)
    roi_gray = pic_gray[y:y+h, x:x+w]
    roi_color = pic[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex, ey, ew, eh) in eyes:
        cv2.rectangle(roi_color, (ex,ey), (ex+ew,ey+eh), (0,255,0), 2)

cv2.imshow("Raspberry pi camera detects {0} faces".format(len(faces)), pic)
cv2.waitKey(0)
cv2.destroyAllWindows()

おまけ

imwriteを使って切り出した顔を画像として保存することもできます。

count = 0;
for (x, y, w, h) in faces:
        count += 1
        cv2.rectangle(pic, (x, y), (x + w, y + h), (255, 0, 0), 2)
        roi_gray = pic_gray[y:y+h, x:x+w]
        roi_color = pic[y:y+h, x:x+w]
        cv2.imwrite("face_{0}.jpg".format(count), roi_color)
        ...
8
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
15