2018/08/30

【10.基礎3】GoogLeNetでリアルタイム画像認識&音出力

どうも、ディープなクラゲです。
ゼロから学ぶディープラーニング推論」シリーズの10回目記事です。
このシリーズでは、Neural Compute StickとRaspberryPiの使い方をゼロから徹底的に学び、成果としてディープラーニングの推論アプリケーションが作れるようになることを目指しています。

第10回目はGoogLeNet画像認識のコードを改造して、カメラ映像からリアルタイムに画像認識させ、特定の画像を検出したら音を出力させます

【 目次 】


ソースコード入手

実行するためのソースコードをダウンロードします
Pythonのソースコード demo.pyに加えて、今回は音の出力用に3つの音声ファイルを用意しています。
つまり合計4ファイルをダウンロードします。

ダウンロード方法は2つありますので、やりやすい方でお願いします。

【方法1】1ファイルずつダウンロード

まずGoogLeNetフォルダに移動します

cd /home/pi/workspace/ncsdk/examples/caffe/GoogLeNet

wgetコマンドを使って、下の4つのコマンドを実行します
wgetコマンドは指定したURLにあるファイルをダウンロードするコマンドです

wget https://raw.githubusercontent.com/electricbaka/movidius-ncs/master/GoogLeNet/demo.py
wget https://raw.githubusercontent.com/electricbaka/movidius-ncs/master/GoogLeNet/sound1.wav
wget https://raw.githubusercontent.com/electricbaka/movidius-ncs/master/GoogLeNet/sound2.wav
wget https://raw.githubusercontent.com/electricbaka/movidius-ncs/master/GoogLeNet/sound3.wav

lsコマンドなどで確認して、以下4つのファイルがあればOKです

【方法2】一括ダウンロードした後にファイル移動

ターミナルで、適当な場所に移動します

cd /home/pi/ダウンロード

git cloneコマンドを使ってダウンロードします
git cloneコマンドはGitHubから、まとめてソースコードをダウンロードできます(難しく言うと、ローカルにリポジトリをクローン)

git clone https://github.com/electricbaka/movidius-ncs.git

movidius-ncsというフォルダが出来ていると思います。
ファイルマネージャーを2つ開きます

以下の4つのファイルを、"/home/pi/workspace/ncsdk/examples/caffe/GoogLeNet" へコピーすればOKです

アプリ実行

USBカメラ接続に加え、今回は音を出力させるため、スピーカーを用意します。ミニジャックをラズパイに接続してください。
なお、HDMIディスプレイに内蔵スピーカーが付いている場合は、それでも構いません。

ターミナルにて、GoogLeNetフォルダに移動します

cd /home/pi/workspace/ncsdk/examples/caffe/GoogLeNet

demo.pyを実行します

python demo.py

USBカメラを動かし「エレキギター」「アコースティックギター」「PCキーボード」のどれかを写してみて下さい。音が鳴れば成功です。
家にギターが無いよという人は、インターネットで適当に画像検索してPC画面等にエレキギターやアコースティックギターを表示して、そこにUSBカメラを向けてみて下さい。

もし音が鳴らないという人は、ラズパイ画面の右上のスピーカーアイコンを右クリックして以下のメニュー表示を行い、"Analog"か"HDMI"を選択してください。USBスピーカーから音を出す場合は"Analog"、HDMIディスプレイから音を出す場合は"HDMI"です

それでもまだ音が鳴らない人は、ラズパイ画面の右上のスピーカーアイコンを左クリックして音量を確かめてください。
なお、USBスピーカー自体に音量調整がある場合もありますので、そちらも確かめましょう

ソースコード解説

それではソースコードの解説です。run.pyから手を加えた箇所を説明します。
全コードはこちらからも閲覧可能です。
https://github.com/electricbaka/movidius-ncs/blob/master/GoogLeNet/demo.py

video caputure追加

"detect_counter"と"detect_old"という変数を用意し0を代入しています。別の箇所で使用します
それ以外は「OpenCV」カメラ映像の読み込みと表示 で習ったコードそのままです。リアルタイムにカメラ映像を取得・表示、何らかのキーが押されたら終了します。

# *************************************************************** 
# video capture 
# *************************************************************** 
detect_counter = 0
detect_old = 0
 
cap = cv2.VideoCapture(0)
 
while True:
    ret, frame = cap.read()
    cv2.imshow('image', frame)
    key = cv2.waitKey(1)
    if key != -1:
        break

インデント挿入

video chaptureで追加したwhileのブロック内に収めて無限ループさせるために、以下の4ブロックは全て先頭にインデント(4つのスペース)を挿入しています

Load the image にて img 変更

run.pyでは入力画像がエレキギター"nps_electric_guitar.png"のファイルでしたが、そこをコメントアウトして、カメラ映像から取得した画像 frame を代入しています。

    #img = cv2.imread(EXAMPLES_BASE_DIR+'data/images/nps_electric_guitar.png') 
    img = frame

detect & sound追加

新たなブロックを挿入しています。
ここでは、推論結果を元に、以下の特定の画像を認識した場合のみ音を出力しています。

546, 402, 508などの番号は、第8回時に紹介した "synset_words.txt" を見れば分かります。
別のモノで検出したい場合は、番号を書き換えればい良いだけです
例:computer mouseであれば 673

    # *************************************************************** 
    # detect and sound 
    # *************************************************************** 
    #detect 
    detect_new = order[0]
    if detect_new == detect_old:
        detect_counter = detect_counter + 1
    else:
        detect_counter = 0
 
    detect_old = detect_new
 
    #sound 
    if detect_counter == 2:
        if detect_new == 546:
            os.system('aplay ./sound1.wav &')
        elif detect_new == 402:
            os.system('aplay ./sound2.wav &')
        elif detect_new == 508:
            os.system('aplay ./sound3.wav &')

音の出力は「Python基礎」で習った os.systemを使ったLinuxコマンドを利用しています。
実際にターミナルで以下のコマンドを打ってみて下さい。音が鳴ると思います。

aplay ./sound1.wav

なお、demo.pyで普通にaplayを行うと音声出力中にプログラムが止まってしまいます。その対策としてaplayの最後に "&" を付け、音声出力中にプログラムが止まらないようにしています。

最後にdetect_new、detect_old、detect_counterという変数を使っている理由を説明します。
推論結果は order[0] に入っています。その数値を見て if で単純に分岐させるだけだと、検知中何度も音が鳴りっぱなしになってしまいます。
そこで、counterを設け、2回連続検知したときだけ音を鳴らすようにしています。1回のみや3回以上連続検知では音は鳴りません。その代わり、最後に検知したモノと異なる検知した場合は counterは 0 にリセットするという仕組みです。

後片付け追加

「OpenCV」カメラ映像の読み込みと表示 で習ったコードそのままです。
ブロックの終わりに挿入しています

# *************************************************************** 
# Clean up video capture and windows 
# *************************************************************** 
cap.release()
cv2.destroyAllWindows()

次回は性別や年齢を推論するGenderNet/AgeNetの実行を行います!
以上、「GoogLeNetでリアルタイム画像認識&音出力」でした。