忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

ラズパイOpenCV4系の処理結果をMjpg-Streamerで配信

以前改造したフォロでは搭載した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自体がビルドできていればPythonC++共に対応することができました。(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_opencv

Makeが必要となるのは
・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-experimental

python用の実行
./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して実行してみます。

Makeは通るのですが、実行すると
undefined symbol: _ZN2cv6circleERKNS17とか出てきます

これはOpenCVライブラリが読めてない状態です。
これをググってみると
https://github.com/jacksonliam/mjpg-streamer/issues/128
input_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して実行すれば顔認識が実行できるようになります。

PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント