266.ラズパイ無双[12_opencvストリーミング3]
初回:2022/7/20
Raspberry Pi (ラズベリーパイ、通称"ラズパイ")で何か作ってみようという新シリーズです。カメラ画像をストリーミング出来るサーバーの最終回...というか、スタートの為のベースシステムについて、説明したいと思います。
P子「ここから始まるのね」※1
このサーバーをベースに、モジュールとなるプログラムを差し替えて使用していくという感じです。
1.環境設定
ラズパイやカメラ、openCVの設定が出来ていないと、動かすことができないかもしれませんが、逆にこれを機会にラズパイワールドに参加されてもよいかもしれません。
P子「無理やり巻き込むのね」
楽しいですよ。
さて、とりあえず環境を構築しましょう。まずは、ソースをzip圧縮しましたので、ダウンロードします。
≪OSDN の作業部屋≫
https://ja.osdn.net/users/chatrun/pf/eu63/files/
OSDN の作業部屋という所に、@IT を作成しました。この中の No266.zip がソースになります。
展開すると、中には、www , www_test , www_zoom という3つのフォルダが見えます。ラズパイのIDを、xxxとして話を進めます。
P子「OSインストール時の pi を止めて、xxx にしたという想定ね」
/home/xxx/www というフォルダを作成します。wwwの下に、概要.txtがありますので、その説明に従って、bottle.py と、waitress を設定します。それで一通り完成です。
2.フォルダ構成説明
www 以下の構成は、このようになります。
├── static 静的ファイル(flaskとの共通化)
│ ├── CAMERA.png
│ ├── custom.css イメージ表示関連などのカスタマイズ系のCSS
│ └── default.css 一般的なスタイルシートの設定
├── views テンプレート
│ ├── header.html include評価用
│ └── index.html 開始点
├── waitress マルチスレッドサーバー(ファイル展開した場合)
│ └── ・・・・
├── bottle.py アプリケーションサーバー
├── camera.py app.py に組み込まれるマルチストリーミング処理本体
├── ogServer.desktop ディスクトップにショートカットを作成する場合のサンプル
├── ogServer.py サーバー本体
├── ogServer.service サービス設定ファイル
└── ogServer.sh サービス/アプリケーション起動用シェルスクリプト
起動例
$ cd www
$ python ./ogServer.py
ブラウザから、http://xxxx:8088/ で、トップページが見えれば、OKです。
3.camera.py 説明
前回の解説記事のように、参考URLのソースを元に改造しています。改造内容は出来るだけオリジナルとの比較ができるようにコメントを残しています。
# ≪参考≫
# https://qiita.com/RIckyBan/items/a7dea207d266ef835c48
# FlaskとOpenCVでカメラ画像をストリーミングして複数ブラウザでアクセスする
# 今回のソースの参照元であり、マルチスレッドでの最終形の解説がされています。
# 本体ソースでは継承とかstaticmethod、classmethod を使用していましたが、
# インスタンスメソッド化とフィルター処理を組み込めるように改造しています。
pi-cam-streaming/base_camera.py を、camera.py に変更しています。
CameraEven クラスは、ほとんど同じなので、判ると思います。
BaseCamera クラスを、Camera クラスとして、インスタンスメソッド化とフィルター処理を組み込めるように改造しています。フィルターは、配列として登録しておき、イメージを返す前にフィルターで画像を変換しています。もちろん、フィルター未設定時は、オリジナルのイメージが返されます。
そして、mainメソッドは、動作確認用のテストプログラムで、Webサーバーなしで動作確認できるようにしていますが、実際問題として、bottle APIサーバーがきちんと動けば、そのサーバーで確認した方が良いと思います。
4.ogServer.py 説明
ogServer.py が、本体のWeb API サーバーになります。先の記事の app.py 相当になりますが、色々と改造していますので、こちらは参考にならないでしょう。
大きな改造点は、
1.bottle + waitress 対応
2.argparse モジュールで、引数の処理
3.importlib の import_module で、モジュールを動的読み込み
4./static/
引数で、'-m','--module' でモジュールを取り込みます。
モジュールプログラムには、def new_obj(): という関数を定義しておき、import_module で、動的に読み込んだ後、このメソッドを実行しています。
そして、{'filter':filter,'module':filter,'subapp':subapp } という辞書にオブジェクトを渡しています。
filter は、Camera オブジェクトにadd_filterして組み込みます。
module は、そのプログラムのxxxx_module.py のxxxx部分を切り取って、これをキーとして、モジュールの辞書を作成して、bottle の bottle.template にパラメータとして渡します。そうすることで、先のキーワードで、html内でWeb APIオブジェクトとして利用可能になります。
最後に、subapp は、bottle の merge 関数で、マージします。これは、モジュール内にルーティングを定義できることを意味します。
P子「判りにくいわね」
もう少し判りやすくできると思うんですけど、今は、これが精一杯です。一応、サンプルとして、www_test とwww_zoom というフォルダも先の zip に含めていますので、これらを、www の中にコピーして動作確認してみてください。これらのサンプルの使用方法は、次々回に説明したいと思います。
5.シェルファイル
ここまでで、一通りの機能紹介は終了です。
ogServer.sh は、実行用のシェルファイルです。ogServer.py を起動しているだけですので、判ると思います。一応、先のサンプルのwww_test とwww_zoomフォルダにもogServer.sh ファイルを入れています。起動時の引数などを含めたサンプルとお考え下さい。
そして、ogServer.desktop は、デスクトップ上にアイコンとして表示して、ダブルクリックで実行できるようにするためのサンプルです。デスクトップアイコンについては、『257.ラズパイ無双[5_リモート(RDP)]#4.スクリーンキーボードの設定』で述べていますので、参考にしてください。
6.サービス化
同様に、サービス化についても、ogServer.service ファイルを参考に置いています。こちらも、『256.ラズパイ無双[4.SDカード延命]』や『258.ラズパイ無双[5_リモート(noVNC)]』で述べていますので、参考にしてください。
256.ラズパイ無双[4.SDカード延命]
https://el.jibun.atmarkit.co.jp/pythonlove/2022/05/2564sd.html
258.ラズパイ無双[5_リモート(noVNC)]
https://el.jibun.atmarkit.co.jp/pythonlove/2022/05/2585_novnc.html
ある程度、モジュールが決まれば、サービス化しておけば楽になります。
7.番外編(サンプル)
www_test とwww_zoom というフォルダの説明が、次々回まで待てないという方に、さわりだけ説明しておきます。
P子「余計にストレスかかるんじゃない?」
実際、ソースを見れば、大体わかると思いますので、それほど説明もいらないと思います。
www_test は、フィルターとモジュールのサンプルです。
$ python3 ./ogServer.py -m test_filter test_module
という感じで起動します。
test_filter.py は、リサイズと画像に時刻を入れるサンプルフィルターです。そして、subapp に/testというbottleのルーティングを設定することで、引数のキーワード scale の値を取り込んでいます。
モジュールについては、test_filter.py の test がキーになりますが、test_module.py からもモジュールとして組み込んでいます。名前衝突を回避するため、特殊なキーワード module.MOD_NAME = 'modname' に変更しています。
views の test.html で、<% obj = modname %> として取り込んで使用できます。
一方、www_zoom の方は少し複雑で、Web画面の動画をマウスで選択(左上と右下)した範囲を、拡大します。static の zoom.js でマウスイベントを ajax で送信した JSON を受けているという感じです。
興味があれば、解析してみてください。
8.まとめ
とにもかくにも、Web API サーバーとして動くところまで来ました。
フィルターやモジュールは、ほんの少しの変更で、Flask 対応が可能です。bottleはちょっと...という方も多いと思いますので、次回はこれらのサーバーを、Flask してみます。
モジュール名に別名を付けたりして、ほぼ、互換対応も可能かもしれませんが、bottle派もFlask派も、それぞれ、ずっと、自分たちの派閥のままでしょうから、無理に合わすことはしないことにします。
次回以降は、bottle での記事になりますが、書き換えは最小限になるはずなので、Flask派の方にも参考になると思います。
ほな、さいなら
======= <<注釈>>=======
※1 P子「ここから始まるのね」
P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。