以前改造したフォロでは搭載したRaspberry PIに接続したカメラ映像をMjpg-Streamer経由でスマホから確認できるようにしていました。
Mjpg-Streamerを使う事でかなり高速で映像のストリーミングを実現することができます。
また、Raspberry PIでのOpenCVを使った
Pythonおよび
C++での画像処理の方法についても紹介してきました。
さて、ストリーミングと画像処理が両方できると組み合わせて使いたくなります。
ストリーミング→OpenCVで処理はアドレスを入力するだけでので割愛します。
今回紹介するのは
OpenCV4系での処理を
ストリーミング配信する方法です。
幾つか方法がある様ですが、Mjpg-Streamer自体で安定したストリーミングができており、さらにOpenCV用のプラグインが用意されているとの事なのでありがたく使わせていただきます。
基本的なセッティングについては以下サイトを参考にさせて頂きました。
ビルドの設定変更
Qiita@zuttonetetai様
ラズパイでmjpg-streamerのopencvプラグインを使う+OpenCVのビルドインストール(備忘録)プラグインの使い方
detamamoruのブログ様
Raspberry Pi B+でinsta360 airの動画をOpenCVで処理する標準設定だとMjpg-StreamerはOpenCV3系のみ対応の様ですが、
OpenCV4系でもOpenCV自体がビルドできていれば
Python、
C++共に対応することができました。(OpenCV4.5.0で動作確認)
以降はOpenCVをビルド済みということを前提にして話を進めます。
OpenCVのビルドが済んでいない方は
Pythonおよび
C++を参考にビルドして頂ければと思います。
※2024/03/01 誤記など修正
Mjpg-Streamerをインストール
とりあえずMjpg-Streamerをインストールします。
たぶんOpenCVの環境が整っていれば追加で必要なライブラリは無いと思います。
ターミナルから
git clone https://github.com/jacksonliam/mjpg-streamer.gitでソースファイルをとってきて
フォルダ移動して
cd ~/mjpg-streamer/mjpg-streamer-experimentalメイク
sudo makeとりあえずこれでMjpg-Streamer自体はインストールできました。
OpenCVプラグインをMake
このままではOpenCV4系を組み込んでもらえないので、設定を変更します。
OpenCV関連機能は以下のフォルダ内にあります。
~/mjpg-streamer/mjpg-streamer-experimental/plugins/input_opencvMakeが必要となるのは
・input_opencv.cpp → input_opencv.so OpenCVのデータ受け渡し
・filter_cpp.cpp → cvfilter_cpp.so C++系で実行する場合の処理内容
・filter_py.cpp+conversion.cpp → cvfilter_py.so Python系で実行する場合の処理内容
OpenCVは大元がC++なのでPythonを対応させるにもC++の知識が少々必要となります。
zuttonetetai様の記事を参考にOpenCVの対応バージョン制限を解除します。
とりあえず編集するファイルは2つ
・input_opencv直下:CMakeList.txt
・filters/cvfilter_py内:CMakeList.txt
※filters/cvfilter_cpp内CMakeList.txtはバージョン制限がかかってない
メモ帳で対象のファイルを開いて
MJPG_STREAMER_PLUGIN_OPTION(input_opencv "OpenCV input #plugin" ONLYIF OpenCV_FOUND #${OpenCV_VERSION_MAJOR} EQUAL 3)を
#MJPG_STREAMER_PLUGIN_OPTION(input_opencv "OpenCV input #plugin"# ONLYIF OpenCV_FOUND #${OpenCV_VERSION_MAJOR} EQUAL 3)MJPG_STREAMER_PLUGIN_OPTION(input_opencv "OpenCV input #plugin")と変更します。(行先頭#はコメントアウトの役割)
OpenCVのバージョンが3限定になっているのでコメントアウトして、強制的にビルドする設定を追記しています。
OpenCV4系だと
このままMakeしてもエラーになるのですが、Makeしてみます。
※2024/03/01 追記
現在のMjpeg-Streamerだと
#plugin の表記が異なる様ですが対応方法は同じです。
フォルダ移動して
cd ~/mjpg-streamer/mjpg-streamer-experimentalメイク
sudo make error: 'CV_IMWRITE_JPEG_QUALITY' was no decleard in this scopeとか出てきます。
要するにinput_opencv.cppでCV_IMWRITE_JPEG_QUALITYが使われているけど見つからないという事です。4系?から表記方法が変わったので変更します。
input_opencvフォルダの
input_opencv.cppを開いて
408行目付近にある
CV_IMWRITE_JPEG_QUALITYを
cv::IMWRITE_JPEG_QUALITYへ変更して保存します。
これでMakeするとinput_opencv.cppがビルドされて
mjpg-streamer-experimentalフォルダに
input_opencv.soが生成されたと思います。
ついでに
cvfilter_cpp.soも生成されているはずです。
で、次のエラーが出ます。
allocateが何たらと出てきます。 これもOpenCVの仕様変更で書き方が変わってます。
今度はfilters/cvfilter_py内の
conversion.cppを開きます
エラーになっているのは
・121行目の
flags・146行目の
accessFlagsです。
どちらもstdAllocator->allocateを実行しようとしてエラーになっています。
そこで、stdAllocatorの宣言を調べると
stdAllocator = Mat::getStdAllocator();
となっています。という事でallocate opencvでググってみると
https://docs.opencv.org/4.x/df/d4c/classcv_1_1MatAllocator.html
flagsはint型ではなくAccessFlag型を使うとなっています。
そこで
・121行目のflagsの宣言→115行目のint flags
・146行目のaccessFlagsの宣言→144行目のint accessFlags
の
intをそれぞれ
AccessFlagに変更します
これでMakeが通ります。
今度は
cvfilter_py.soが生成されたと思います。
たぶんPython用はこれで準備が出来ました。
filters/cvfilter_py内のexample_filter.pyの内容が実行できるようになります。
とりあえずそのまま実行してみる
フォルダを移動しておいて
cd ~/mjpg-streamer/mjpg-streamer-experimentalpython用の実行
./mjpg_streamer -i "./input_opencv.so --filter ./cvfilter_py.so --fargs ./plugins/input_opencv/filters/cvfilter_py/example_filter.py -r 320x240 -d /dev/video0" -o "./output_http.so -w ./www -p 8080"c++用の実行
./mjpg_streamer -i "input_opencv.so --filter cvfilter_cpp.so -r 320x240 -d /dev/video0" -o "./output_http.so -w ./www -p 8080"2024/03/01 c++用の実行で
8080" が抜けていたので修正
どちらかを実行しておいて、ラズパイのwebブラウザで
http://localhost:8080でページが開いたら
Streamから映像を確認できます。
他のPCやスマホ等から確認する場合は
ラズパイのIPアドレスを調べておいて、WiFiなど経由で
http://IPアドレス:8080へアクセスすれば同じ画面を確認できます。
Mjpg-Streamerを停止するにはターミナルでCtrl+C
C++用の準備
C++用のビルドにはもう少し設定変更が必要です。
filters/cvfilter_cpp内のfilter_cpp.cppを編集するのですが、編集して実行するとエラーになります。
試しにfilter_cpp.cppのfilter_prosecc関数に
cv::circle(dst,cv::
Point(100,100),5,cv::Scalar(0,255,0),-1,0);
とか書いてMakeして実行してみます。
※2024/08/22 誤記修正
Makeは通るのですが、実行すると
undefined symbol: _ZN2cv6circleERKNS17とか出てきます。
これはOpenCVライブラリが読めてない状態です。
これをググってみると
https://github.com/jacksonliam/mjpg-streamer/issues/128input_opencv直下のCMakeList.txtライブラリの場所を追加するとOKとの事なので
target_link_libraries(input_opencv ${OpenCV_LIBS})の少し上に
link_libraries(${OpenCV_LIBS})を追加してMakeします。
これで円が描画されます。
もうちょっと修正が必要です。
定番の顔認識をやってみます。
filter_cpp.cppへプログラムを移していきます。
初期化処理
void filter_init(const char* args, void** filter_ctx)
メイン処理(自動的に定期実行される)
void filter_process(void* filter_ctx, Mat &src, Mat &dst)
Mat &srcこれにカメラ画像が入る
Mat &dstストリーミングする画像をこれに入れる
終了処理
void filter_free(void* filter_ctx)
へそれぞれプログラムを移していきます。
なお、カメラの初期化処理は
input_opencv.cppに記述してあるので、
カメラのバッファを1に設定する等はこちらに記述します。
pythonで記述する場合もカメラ入力は
input_opencv.cppを使用しています。
相変わらずMakeは通ります。
実行すると今度は
undefined symbol: _ZN2cv17CascadeClassFilterD1Evとか出てきます。 例によってライブラリ関連です。
これについてはinput_opencv直下のCMakeList.txtの冒頭部分にコンポーネントを追加しろとか書いてあるので、対応する
objdetectを追加してMakeして実行すれば顔認識が実行できるようになります。