2018年3月24日土曜日

Raspberry Pi ZeroとPicameraと0.96インチLCDで物体認識装置を作ってみた


背景

ideinさんのデモの真似です。

以前の記事でLCDの使い方と、OpenCVのDNNモジュールでMobileNetを利用した物体判別をする方法を学びました。
学んだことを組み合わせて、物体認識装置を作りました。

備忘録を兼ねて、内容を共有します。

使ったもの

下記2つの記事の内容を実行できるRaspberry Piを使います。
Raspberry Piに0.96インチのLCDを付けて、カメラの画像を表示してみた
OpenCVのDNNモジュールをPythonで呼び出し、MobileNetを利用した物体認識をしてみた



プログラムの説明

こちらのプログラムを実行します。
mobilenet_picamera_display.py
import io, picamera, pygame, sys, os
import argparse
import cv2
import numpy as np
from cv2 import dnn
from pygame.locals import *
os.environ["SDL_FBDEV"] = "/dev/fb1"

parser = argparse.ArgumentParser()
parser.add_argument("--video", help="number of video device", default=0)
parser.add_argument("--prototxt", default="mobilenet_v2_deploy.prototxt")
parser.add_argument("--caffemodel", default="mobilenet_v2.caffemodel")
parser.add_argument("--classNames", default="synset.txt")
args = parser.parse_args()

width = 480
height= 640
camera = picamera.PiCamera()
camera.resolution = (width, height)
camera.rotation = 90
offset = 22

net = dnn.readNetFromCaffe(args.prototxt, args.caffemodel)
f = open(args.classNames, 'r')
rawClassNames = f.readlines()
classNames = []
for nameStr in rawClassNames:
    spaceIndex = nameStr.find(' ')
    nameStr = nameStr[spaceIndex:-2]
    classNames.append(nameStr)

inWidth = 224
inHeight = 224
inScaleFactor = 0.017
meanVal = (103.94, 116.78, 123.68)
resultText = None

pygame.init()
screen = pygame.display.set_mode((160, 124), 0, 32)
screen.fill(0)

basicfont = pygame.font.SysFont(None, 15)

# run the game loop
while True:
    screen.fill(0)

    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    frame = np.empty((width * height * 3), dtype=np.uint8)
    camera.capture(frame, format='rgb')
    frame = frame.reshape((height, width, 3))
    blob = dnn.blobFromImage(frame, inScaleFactor, (inWidth, inHeight), meanVal)
    net.setInput(blob)
    detections = net.forward()

    maxClassId = 0
    maxClassPoint = 0;
    for i in range(detections.shape[1]):
        classPoint = detections[0, i, 0, 0]
        if (classPoint > maxClassPoint):
            maxClassId = i
            maxClassPoint = classPoint

    img = pygame.image.frombuffer(frame.tobytes(), (width, height), 'RGB')
    img = pygame.transform.scale(img, (int(img.get_width() * 80 / img.get_height()), 80))
    screen.blit(img, (0, offset))

    if (resultText != None):
        screen.fill((0, 0, 0), resultText.get_rect())

    print("class id: ", maxClassId)
    print("class point: ", maxClassPoint)
    print("name: ", classNames[maxClassId])
    resultText = basicfont.render(classNames[maxClassId], True, (255, 255, 255))
    textrect = resultText.get_rect()
    textrect.left = img.get_width()
    textrect.centery = screen.get_rect().centery
    screen.blit(resultText, textrect)

    pygame.display.update()

「使ったもの」で紹介した記事で触れていない部分をところどころ解説します。

表示領域が制限されるので、クラス名の先頭に付けられているidのような文字列を削除しました。
f = open(args.classNames, 'r')
rawClassNames = f.readlines()
classNames = []
for nameStr in rawClassNames:
    spaceIndex = nameStr.find(' ')
    nameStr = nameStr[spaceIndex:-2]
    classNames.append(nameStr)

numpyの空の領域を用意し、そこへPicameraからのrgb形式の画像データを書き込んでいます。
frame = np.empty((width * height * 3), dtype=np.uint8)
camera.capture(frame, format='rgb')
frame = frame.reshape((height, width, 3))

動作確認

LCDを起動します。
modprobe fbtft_device name=adafruit18 gpios=reset:22,dc:27,cs:3 rotate=90

先ほど紹介したプログラムはgithubで公開しているので、下記のようなコマンドで実行できます。
mkdir ~/gitprojects
cd ~/gitprojects
git clone https://github.com/asukiaaa/raspi_mobilenet_display.git
cd raspi_mobilenet_display
sudo python3 mobilenet_picamera_display.py


0.2fps(5秒に1回更新)位で処理を行う、物体認識装置ができました。

自動起動設定

下記のような記述を/etc/rc.localに追加すると、Raspberry Pi起動後に物体認識プログラムが動き始めます。
フルパスを指定してプログラムを実行する場合、関連ファイルのパスがずれてしまうため、それぞれのファイルもフルパスで指定しています。
/etc/rc.local
modprobe fbtft_device name=adafruit18 gpios=reset:22,dc:27,cs:3 rotate=90
python3 /home/pi/gitprojects/raspi_mobilenet_display/mobilenet_picamera_display.py \
  --prototxt=/home/pi/gitprojects/raspi_mobilenet_display/mobilenet_v2_deploy.prototxt \
  --caffemodel=/home/pi/gitprojects/raspi_mobilenet_display/mobilenet_v2.caffemodel \
  --classNames=/home/pi/gitprojects/raspi_mobilenet_display/synset.txt &

まとめ

0.2fps位で動く物体認識装置を作れました。
ideinさんのデモのようなスムーズな処理にはかないませんが、似たものを作れたので個人的に満足です。

何かの参考になれば嬉しいです。

参考

Raspberry Piに0.96インチのLCDを付けて、カメラの画像を表示してみた
OpenCVのDNNモジュールをPythonで呼び出し、MobileNetを利用した物体認識をしてみた
Capturing to an OpenCV object | Picamera

0 件のコメント :