1. 物体検出とは何か
本ページでは、Rapsberry Pi で「物体検出」を行う方法を紹介します。「物体検出」とは何かを知るには、下図の画像を見るのがわかりやすくて良いでしょう。机の上にキーボード、カッター、カップ、マウスが置かれており、その写真に物体検出を適用した結果、物体の位置、大きさ、種類が表示されています。 図ではわかりにくいですが、検出された物体にそれぞれキーボード、ナイフ、カップ、マウスという名称が英語で記されています。
なお、「カッター」が「ナイフ」と検出されている理由は後に解説しますが、一言で言えば「学習データにカッターが含まれていないから」です。
物体検出には様々な方法がありますが、本ページで用いる物体検出は、本書で紹介した CNN (畳み込みニューラルネットワーク) の技術が使われたものです。
しかし、下図に示したように通常のCNNと物体検出では大きく異なる点があります。
通常のCNNでは、上図(A)のように画像中に一つの対象が記されており、その画像が属するクラス(「2」や「カップ」と言った分類先)が出力されます。
一方、物体検出では上図(B)のように、一枚の画像中に複数の物体が存在することがあり得ます。そして、それぞれの物体のクラスだけではなく位置や大きさも出力されねばなりません。
2. YOLOとは何か
この物体検出に CNN (畳み込みニューラルネットワーク) の考え方を応用した手法がいくつか提案されており、本ページで紹介するのはそのうちの一つである YOLO です。YOLO(You Only Look Once、一度だけ見る)は 2016 年に J. Redmon らにより提案された手法です。 オリジナルの論文はこちらから入手できます。
You only look once とは、英語表現 You only live once(一度だけの人生)をもじったものと考えられます。「一度だけ見る」とは、YOLO では一枚の画像に対する認識に CNN の計算を一度だけ実行すれば良いことを示しています。
物体検出に CNN を用いる他の手法では、一枚の画像に対する認識時に何度も CNN の計算を行わねばならなかったことと対比しているのだと思われます。
通常の CNN の出力層ではソフトマックス関数により入力が属するクラスを出力します。詳細は省略しますが、YOLO では出力層に機械学習の回帰の考え方を適用し、物体の位置や大きさに関わる量も出力できるようにします。それにより、物体検出を可能にしているのです。
なお、執筆時点で YOLO にはバージョン 1 からバージョン 3 が存在します。本ページでは YOLO バージョン 3 を実行する方法を紹介します。
バージョンごとに性能が向上されている他に、学習時に用いられたデータが異なるという特徴があります。それにより、認識される物体の種類が異なるのです。
YOLO バージョン 1 ではクラス数 20 の Pascal VOC 2007 といううデータセットが用いられています。20 種類の物体を検出できるということです。その性能を向上させた YOLO バージョン 2 ではImageNet と COCO という 2 つのデータセットを組み合わせてクラス数 9000 の認識が可能な YOLO9000 というネットワークを実装しています。
そして、本ページで用いる用いた YOLO バージョン 3 では COCO というデータセットを用いてクラス数 80 の認識が可能です。80 種類のクラスをこちらでみることができます。
上で見た図で、カッターを「ナイフ」と認識しているのは「カッター」のデータがデータセットに含まれていなかったであると既に述べましたが、それは上のリンクにあるクラス一覧で確認することができます。
なお、これらの「学習済ネットワーク」から出発して新たなデータを学習させる「転移学習」という方法もありますが、本ページでは取り扱いません。
また、通常 YOLO で用いる CNN は、何十個もの畳み込み層と 2 個の全結合層を持ちます。これをそのまま Raspberry Pi の計算能力で実行するのはやや荷が重いといえます。そのため、本ページでは畳み込み層の数を十個程度に減らした YOLO の簡易版である Tiny YOLO の実行方法も紹介します。
Raspberry Pi 3までをお使いの方はこの Tiny YOLO を利用すると良いでしょう。 高速な Raspberry Pi 4 をお使いの方は通常の YOLO もあわせてチャレンジしてみましょう。
また、本ページの続編的なページとして、物体検出の高速化に関連する「Raspberry Pi + Coral USB Accelerator + TensorFlow Lite で物体検出と姿勢推定を試してみよう」もありますので合わせてご覧ください。Coral USB Acceleratorをお持ちでない場合も演習を実行できます。
3. Python3 用の TensorFlow と OpenCV のインストール
さて、YOLO および Tiny YOLO を実行するためには、Python3 用の TensorFlow および OpenCV のインストールが必要です。本書の補足ページの下記ページに従い、Python3 用の TensorFlow および OpenCV をインストールして下さい。 なお、本ページの内容を Anaconda で実行したい方は「本書の演習を Anaconda の Spyder で実行する方法」を参考にしてください。さて、ここからは以下の流れで解説が進みます。 TensorFlow 1 系に比べて TensorFlow 2 系の解説は簡易的となっておりますのでご了承ください。
- 1. [TensorFlow 2 系] プログラムのダウンロードから実行まで
- 2. [TensorFlow 1 系] プログラムのダウンロードと準備
- 3. [TensorFlow 1 系] プログラムの実行 (静止画の場合)
- 4. [TensorFlow 1 系] プログラムの実行 (カメラの映像の場合)
1. [TensorFlow 2 系] プログラムのダウンロードから実行まで
TensorFlow 2 系で行うための方法を記します。簡易的な解説となっていますのでご了承ください。まず、プログラムをダウンロードするには下記のコマンドを実行して下さい。cedrickchee氏のプログラムに筆者が手を加えたファイルがダウンロードされます。TensorFlow 1 系とは別のプログラムを用いていることにもご注意ください。
git clone https://github.com/neuralassembly/tensorflow2-yolo-v3プログラムのダウンロードが終わったら、下記コマンドを実行し、tensorflow2-yolo-v3 ディレクトリ(フォルダ)内に移動します。
cd tensorflow2-yolo-v3そして、下記の4つのコマンドを実行し、YOLOv3用の重みをダウンロ―ドし、さらにそれを TensorFlow 用に変換します。前半 2 つが通常の YOLO 用のコマンド、後半 2 つが tiny YOLO 用のコマンドです。
wget https://pjreddie.com/media/files/yolov3.weights -O data/yolov3.weights python3 convert.py wget https://pjreddie.com/media/files/yolov3-tiny.weights -O data/yolov3-tiny.weights python3 convert.py --weights ./data/yolov3-tiny.weights --output ./checkpoints/yolov3-tiny.tf --tinyRaspberry Pi 4 登場以前の Raspberry Pi 3 などで、コマンド「python3 convert.py」実行時にエラーが出る場合、 「2. [TensorFlow 1 系] プログラムのダウンロードと準備」で解説されているスワップ領域の増加を試してみると良いかもしれません。
次に、静止画に対して物体検出を行うコマンドが下記の 2 つです。1 つ目のコマンドは、通常の YOLO を画像「./data/meme.jpg」に対して適用します。 「./data/meme.jpg」は、「現在のディレクトリ(./)にある data ディレクトリ(data/)にある画像 meme.jpg」という意味です。 同様に、2 つ目のコマンドは、tiny YOLO を画像「./data/street.jpg」に対して適用します。
どちらの場合も、検出結果が描かれた output.jpg というファイルが保存されます。
python3 detect.py --image ./data/meme.jpg python3 detect.py --weights ./checkpoints/yolov3-tiny.tf --tiny --image ./data/street.jpg最後に、ウェブカメラから取得した映像への物体検出は以下で行います。1 つ目が通常のYOLO、2 つ目が tiny YOLO 用のコマンドです。どちらも、終了するにはウインドウ上でキーボードの「q」をタイプしてください。
なお、Bullseye 64-bit で、Legacy Camera 有効 + カメラモジュールで使っている場合、カメラモジュールでの認識が可能です。 Bookworm 64-bit の場合カメラモジュールでの認識はできません。USBで接続するウェブカメラが必要です。その場合、detect.py の 57行目の「cap = cv2.VideoCapture(0)」のカッコ内の数字を 0 から 1 に変更する必要があるかもしれません。
python3 detect.py --webcam python3 detect.py --weights ./checkpoints/yolov3-tiny.tf --tiny --webcam
2. [TensorFlow 1 系] プログラムのダウンロードと準備
ここからは、TensorFlow 1 系用の YOLO バージョン 3 (YOLOv3) のダウンロードと準備を行いましょう。公式の YOLO は、darknet というライブラリでネットワークを実現しています。 それを別のディープラーニング用ライブラリで実行するためのプログラムを様々な方が公開しています。
ここでは、kcosta42 氏が公開しているプロクラムを用います。 kcosta42 氏のプログラムに、カメラ映像に対する物体検出機能を筆者が追加したプログラムをダウンロードします。 ターミナルを開き、下記のコマンドでプログラムをダウンロードしましょう。
git clone https://github.com/neuralassembly/Tensorflow-YOLOv3次に、学習済のパラメーター(結合係数)ファイルをダウンロードして TensorFlow 用のファイルに変換します。下記の3つのコマンドを順に一つずつ実行します。
cd Tensorflow-YOLOv3 curl https://pjreddie.com/media/files/yolov3-tiny.weights > ./weights/yolov3-tiny.weights python3 convert_weights.py --tiny一つ目のコマンドはディレクトリの移動を、二つ目のコマンドははTiny YOLO用のパラメーターファイル (35MB程度) のダウンロードを表します。
三つ目のコマンドはファイル変換を行います。Pi 3 B+で 1 分 30 秒程度、Pi 4 B で40秒程度の時間がかかります。このときコンソールに大量の WARNING が出ますが、変換は適切に行われますので気にする必要はありません。
Raspberry Pi 4 をお使いの方で Tiny ではない通常の YOLO の実行もしたい方は、引き続き下記の2コマンドを実行してください。
curl https://pjreddie.com/media/files/yolov3.weights > ./weights/yolov3.weights python3 convert_weights.pyそれぞれ YOLO 用のパラメーターファイルのダウンロードと変換を行っています。Pi 4 B で 2 分程度の時間がかかります。
なお、パラメータファイルは250MB程度ありますので、SDカードの容量に注意してください。
なお、ファイルの変換には多くのメモリが必要とされるため、 Pi 3 B+までのRaspberry Piでは途中で強制終了してしまいます。
なお、2019.12末に試したところ、2つめのコマンドで Raspberry Pi 4 でもメモリに関するエラーが出て終了してしまいました(std::bad_alloc)。
これは、この時期にインストールされた tensorflow-1.14.0 に問題があるからのようです。
sudo pip3 install tensorflow==1.13.1上記のコマンドにより tensorflow 1.13.1 にバージョンを落とすと上の変換コマンド「python3 convert_weights.py」はRaspberry Pi 4 メモリ 8GB 版と 4GB 版とでは問題なく実行でき、「Model Saved at "./weights/model.ckpt" 」と表示されて正常終了します。その場合、「3. プログラムの実行 (静止画の場合)」に進んでください。
なお、Raspberry Pi 4 メモリ 2GB 版ではメモリが足りず tensorflow-1.13.1 にバージョンを落としても「python3 convert_weights.py」コマンドに失敗することがあります。 その場合、SDカードの領域をメモリの一部として使う「スワップ」という領域のサイズを増やす必要があります。スワップ領域のデフォルトのサイズは 100MB であるので、これを 600MB に増やしてみましょう。 下記コマンドにより、スワップ領域のサイズを決めるファイル /etc/dphys-swapfile を管理者権限のテキストエディタで開きます。
sudo mousepad /etc/dphys-swapfile下記の行がありますので、
CONF_SWAPSIZE=100この数値 100 を下記のように 600 に変更します。
CONF_SWAPSIZE=600変更したらテキストエディタでファイルを上書き保存してから、Raspberry Pi を再起動します。すると、スワップ領域の量が 600MB に増えており、変換コマンド「python3 convert_weights.py」が「Model Saved at "./weights/model.ckpt" 」と表示されて正常終了するようになります。
正常終了を確認したら、再び /etc/dphys-swapfile を管理者権限で開き、CONF_SWAPSIZE の値を 100 に戻して構いません。
以上が終わったら物体検出を実行してみましょう。
3. [TensorFlow 1 系] プログラムの実行 (静止画の場合)
まず、静止画に対する物体検出を試してみましょう。プログラムをダウンロードすることでユーザー pi のホームディレクトリに Tensorflow-YOLOv3 というディレクトリ(フォルダ)が出来ていますが、その中の data ディレクトリ→ imagesディレクトリとたどった中にある person.jpg というファイルに対して物体検出をおこないます。あらかじめ、Raspberry Pi上のファイルマネージャで画像をダブルクリックしてどのような画像か確認しておきましょう。
そして、 Tensorflow-YOLOv3 というディレクトリに移動してからプログラムを実行します。 結合係数の変換からターミナルを閉じていなければそのまま実行してよいのですが、新たにターミナルを起動した場合はあらかじめ
cd Tensorflow-YOLOv3というコマンドを実行し、ディレクトリを移動してからプログラムを実行します。
Tiny YOLO (YOLOv3-tiny) によりperson.jpgに対して物体検出を行うには下記のコマンドを実行します。
python3 detect.py --tiny image 0.5 0.5 ./data/images/person.jpgPi 3 B+で 45秒程度(パラメータファイルからのモデルの構築に36秒、入力から検出結果を得るのに9秒)、Pi 4 B で 24 秒程度(パラメータファイルからのモデルの構築に20秒、入力から検出結果を得るのに4秒)の時間待つと、結果が保存されます。
結果は、Tensorflow-YOLOv3 ディレクトリ内の detections ディレクトリにある image_output.png というファイルに保存されています(ファイル名は毎回固定です)。 下記のようなファイルが保存されているはずです。
犬に対する枠が2重に表示されていたり、馬が sheep と判定されているなど若干問題はありますが、Tinyではない通常の YOLO を用いるとこの問題はどちらも解決されます(その方法は後述します)。
なお、犬に対する枠が2重に表示されている問題は Tiny の範囲で解決できます。実行コマンド中の「0.5 0.5」のうち、一つ目の数字は「同じクラスの物体を示す枠が複数あって重なっているとき、重なりが大きい枠を除去する」という処理に使われます。 この数字を 0 から 1 の範囲で小さくすると(例えば 0.3)、犬の枠は一つになります。すなわち「python3 detect.py --tiny image 0.3 0.5 ./data/images/person.jpg」ですので興味のある方は試してみてください。
ここで、実行コマンドの中の「./data/images/person.jpg」について解説しておきましょう。これは物体検出を行う対象となる画像の位置を指定しています。このとき、下記の記号を覚えておくと便利です。
. | ユーザーが現在いるディレクトリ |
/ | ディレクトリの区切り |
この表によると、「./data/images/person.jpg」は「ユーザーが現在いるディレクトリ内にあるdataディレクトリ→imagesディレクトリにあるperson.jpgという画像」という意味になります。 それ以外には下記の記号を覚えておくと良いでしょう。
.. | ユーザーが現在いるディレクトリの一つ上のディレクトリ |
この記号を用いると、例えば「../image.jpg」と書くことで「ユーザーが現在いるディレクトリの一つ上のディレクトリにあるimage.jpgという画像」という意味になります。
ここで学んだ知識を確認するため、別の画像に対しても Tiny YOLO で物体検出を行ってみましょう。本ページの冒頭に示した机の上にキーボード、カッター、カップ、マウスを置いた画像を試してみましょう。下記のコマンドで画像をダウンロードします。
wget https://raw.githubusercontent.com/neuralassembly/raspi/master/desk-image.jpgファイルマネージャで Tensorflow-YOLOv3 ディレクトリにダウンロードされた desk-image.jpg の存在を確認し、どんな画像か確認しておきましょう。 そして、下記のコマンドにより物体検出を実行します。
python3 detect.py --tiny image 0.5 0.5 ./desk-image.jpg先ほど学んだように「./desk-image.jpg」は「現在のディレクトリにある desk-image.jpg という画像ファイル」という意味になるのでしたね。
実行結果は先程と同じく detections ディレクトリの image_output.png として保存されます。以下のような図になっているはずです。
本ページ冒頭の図と異なり、カッターが検出されていません。これは、物体かどうかを判定する基準が厳しいからです。実行コマンド中の「0.5 0.5」のうち二つ目の数字を0.2にすると、基準が緩くなり、カッターがナイフと判定されるようになります (基準は0から1の範囲の数値で定めます)。すなわち「python3 detect.py --tiny image 0.5 0.2 ./desk-image.jpg」です。このコマンドで本ページ冒頭の図と同じものが detections ディレクトリの image_output.png として保存されます。
さて、ここまで Tiny YOLO での物体検出を解説してきました。通常の YOLO で物体検出を行いたい場合は、コマンドから「--tiny」を除いて下記を実行します。Pi 3 B+までではパラメータファイルの変換に失敗するので、実行可能なのは Raspberry Pi 4 以降のみでしたね(メモリ 4GB 版と 2GB版とで動作を確認)。
python3 detect.py image 0.5 0.5 ./data/images/person.jpgPi 4 B で 1 分弱(パラメータファイルからのモデルの構築に45秒、入力から検出結果を得るのに8秒)待つと、これまで通り detections ディレクトリの image_output.png として保存されます。
認識率はこちらの通常の YOLO を用いることで格段に上がりますが、そのぶん認識結果を得るまでの時間がかかるようになっています。
4. [TensorFlow 1 系] プログラムの実行 (カメラの映像の場合)
最後に、Raspberry Pi に接続したカメラから得られた映像に対して物体検出を行う方法を紹介します。カメラは、Raspberry Pi 公式のカメラモジュールおよび USB 接続のウェブカメラのどちらでも構いません。USB 接続のウェブカメラとしてこちらで動作確認したのは ロジクール社の C270 および C920 です。
本ページでは「××社の○○と言うカメラで動くか」という質問や「××社の○○と言うカメラで動くようにして欲しい」という要望には応えることができませんのでご了承ください。
実行方法は、静止画の場合と同様に Tensorflow-YOLOv3 ディレクトリに「cd Tensorflow-YOLOv3」コマンドで移動してから下記を実行します。
Tiny YOLOの場合はこちらです。
python3 detect.py --tiny webcam 0.5 0.5利用状況は下図のようになります。Pi 3 B+ では、約1秒に一回くらい映像が更新されましたが、5秒くらいの映像遅れがあるので実用は厳しいところです。
Pi 4 B では、1秒に複数回映像が更新され、2秒くらいの映像遅れがあります。
通常の YOLO の場合はコマンドから「--tiny」を除いた下記のコマンドを実行します。こちらは Raspberry Pi 4 でのみ実行できます(メモリ 4GB 版と 2GB 版とで動作を確認)。 こちらは Tiny YOLO よりも認識率は良いのですが、映像の遅れが25秒程度あるので使いどころは難しいところです。
python3 detect.py webcam 0.5 0.5
8. まとめ
Raspberry Pi で YOLO v3-Tiny / YOLO v3 による物体検出を試してみました。カメラ映像に対する例を試してみたところ、実用するためには Raspberry Pi 4 + YOLO v3-Tiny くらいの動作速度は最低限欲しいところです。また、YOLO v3-Tiny は認識精度が低いので、実用するにはなんらかの工夫が必要と思われます。
この物体検出の高速化に関して、「Raspberry Pi + Coral USB Accelerator + TensorFlow Lite で物体検出と姿勢推定を試してみよう」ページを作成しましたので、引き続きご覧ください。Coral USB Acceleratorをお持ちでない場合も演習を実行できます。