前回のエントリではNode-REDを使用したカメラの使用を行っていましたが、その中で気になっていたものが残っていたのですが、 ちょっと試してみるとハマったのでそれに関してメモっておこうと思います。
気になった拡張ノードは以下のものです。
これを使用するとカメラ画像をストリーミング的に使用できそう?
A node that consumes a mjpeg stream and outputs the latest saved frame as buffer
ドキュメントを見ると、mpeg_stream
を使用してカメラ撮影した最新のバッファを取得するという機能を持つもののようです。
ページをパッと見た感じではインストールせよとははっきりとはわからないのですが、mjpg_stream
というアプリケーションが必要のようです。
もう少しはっきりと書いてほしいかも。
事前準備
ドキュメントにもgithubのURLがあるのでこちらを見ながらインストールをします。apt
コマンドではインストールはできないのでちょっと手間がかかります。
githubのドキュメントに従って行けば概ねインストールには引っかからない感じです。
$ cd ~ $ sudo apt update $ sudo apt install -y cmake libv4l-dev libjpeg-dev imagemagick $ git clone https://github.com/jacksonliam/mjpg-streamer.git $ cd mjpg-streamer/mjpg-streamer-experimental $ make $ sudo make install
ネットで検索すると上記の手順の最後にあるsudo make install
を行わず、ローカルディレクトリで実行しているところが多かったのですが、私はインストールまで行っています。
インストールが終わったら試しに実行してみます。
mjpg_streamer
は入力方法と出力方法のそれぞれをオプションの指定することによって実行する仕組なのでそれぞれ指定します。
$ mjpg_streamer -o "output_http.so -w /usr/local/share/mjpg-stream/www" -i "input_raspicam.so"
以下の実行例では
- 入力:RaspberryPiのカメラモジュール(パラメータの類はデフォルト設定)
- 出力:httpプロトコル
(注記)/usr/local/share/mjpg-stream/www
はテスト用の静的コンテンツの入ったパスになります。インストールするとローカルからこのパスにコピーされます。
となっています。実行するとエラーが発生しなければ以下のような設定一覧が表示された画面が出力され、起動します。
ここまできたら、キャプチャがうまく行っているか確認してみます。ブラウザでhttp://raspberrypi.local:8080/にアクセスするとWebでの実行画面が表示されます。 (注)mDNSでのアクセスが出来ていない場合にはhttp://【RaspberryPiのIPアドレス】:8080/でアクセスをしてください。
これでmjpg_stream
のインストールは完了です。
インストールの確認が終わったら、コンソール上で起動したmjpg_stream
はCtrl+Cで終了させておきます。
拡張ノード(node-red-contrib-mjpgcamera
)をインストール
先程作業で、事前準備が終わったので拡張ノードをインストールします。 これまでの拡張ノード同様に【三】をクリックし、メニューから【パレットの管理】を選択します。
【ユーザー設定】で【ノード追加】タブをクリックし、検索ボックスにmjpg
を入力すると該当の拡張ノードが表示されます。
名前を確認して【ノードを追加】ボタンをクリックします。確認ダイアログでも【追加】ボタンをクリックしてください。●
インストールが完了するとelectronicplayground
のカテゴリーに拡張ノードが格納されます。
名称はmjpg consumer
となっています。
実際に使用してみる
今回は、ノードをワークスペースにドロップせず、以下のテキスト(JSON形式ですが)をクリップボードからペーストしてみます。テキストで保存できるので gitなんかとも親和性ありそうですね。今後調べてみたいです。
[{"id":"5b126518.b3359c","type":"tab","label":"mjpg_streming","disabled":false,"info":""},{"id":"2e754e61.560a52","type":"debug","z":"5b126518.b3359c","name":"","active":true,"console":"false","complete":"false","x":550,"y":60,"wires":[]},{"id":"343fc213.65c74e","type":"file","z":"5b126518.b3359c","name":"Camera Capture","filename":"capture.jpg","appendNewline":false,"createDir":false,"overwriteFile":"true","x":560,"y":140,"wires":[[]]},{"id":"81850657.0c4598","type":"mjpg-consumer","z":"5b126518.b3359c","name":"MjpgConsumer","stream":"http://raspberrypi.local:8080/?action=stream","interval":"5","x":360,"y":100,"wires":[["2e754e61.560a52","343fc213.65c74e"]]},{"id":"1307914e.5c5d0f","type":"inject","z":"5b126518.b3359c","name":"Stop Consumer","topic":"","payload":"stop","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":160,"y":140,"wires":[["81850657.0c4598"]]},{"id":"d30efe8.65f4f","type":"inject","z":"5b126518.b3359c","name":"Start Consumer","topic":"","payload":"start","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"","x":160,"y":60,"wires":[["81850657.0c4598"]]}]
ペーストの作業は、画面右上の【三】をクリックし、メニューから【読み込み】→【クリップボード】を選択してクリックを行います。●
【フローをクリップボードから読み込み】というダイアログが開くので、先ほどのJSON形式のテキストをコピー&ペースト、【読み込み先】を新規のタブに変更、【読み込み】ボタンをクリックします。
すると新しいフローが生成されて以下のようなフローが表示されます。
拡大するとこんな感じです。(あんまり拡大になってませんが、文字は読みやすくなったと思います)
各ノードはこんな感じの設定になっています。
Start Consumer
のinjectノードは【ペイロード】にstart
を設定しています。
Stop Consumer
のinjectノードは【ペイロード】にstop
を設定しています。
MjpgConsumer
のmjpg-consumerノードは【Stream】にhttp://raspberrypi.local:8080/?action=stream
、【Streaming Interval】は5
(秒)を設定してます。mjpg_streamは起動して、http://raspberrypi.local:8080/?action=stream
にアクセスするとカメラで撮影した画像が表示され、start
を送ると撮影開始し、stop
を送ると撮影を停止する機能を持っています。
debugノードは特に変更はありません。
Camera Capturefile
のfileードは【ファイル名】をcaputure.jpg
に設定しています。
とりあえず、そのまま【デプロイ】ボタンを押して実行してみます。(スタートを指定しなくても5秒間隔で動作します) そして、デバッグのタブを覗いてみると…
undefined?うまく動作してないようです。なぜだ
うまくいかない?
ググってもなかなか情報が得られないのでいろいろ試したら、割とあっさり理由がわかりました。
Node-REDからこの拡張ノードを使用した場合でもmjpg_stream
を起動してはくれないようです…原因は簡単でしたが、そこまで至るのに時間かかり過ぎた。
ということで、この拡張ノードを使用する際は起動時にサービスとしてmjpg_streamを起動しておくか、事前に起動する必要があります。 自分は面倒なので、起動スクリプトと終了スクリプトを書いて、事前に起動することにしました。(RaspberryPi2では結構負荷が高いので) 各スクリプトには実行権限をつけておきましょう。
起動時の実行に関してはrc.local
に入れる方法やSupervisor
を使用もあると思いますが、からあげさんのエントリーが参考になると思います。
【起動スクリプト】
#!/bin/sh # mjpg-streamer start script export LD_LIBRARY_PATH=/usr/local/lib/mjpg_streamer STREAMER="/usr/local/bin/mjpg_streamer" # Pi camera configurations XRES="640" YRES="480" FPS="10" # Web configurations WWWDOC="/usr/local/share/mjpg-streamer/www" PORT="8080" # Start streaming $STREAMER \ -i "input_raspicam.so -x $XRES -y $YRES -fps $FPS" \ -o "output_http.so -w $WWWDOC -p $PORT"
【停止スクリプト】
#!/bin/bash if pgrep mjpg_streamer then kill $(pgrep mjpg_streamer) > /dev/null 2>&1 echo "mjpg_streamer stopped" else echo "mjpg_streamer not running" fi
起動するタイミングは事前でも、Node-RED作業後でもよいので、起動スクリプトを実行しておけば動作します。
Node-REDからフローを実行するとカレントパスにcapture.jpg
が保存されます。dubugノードからの表示はデータ配列の形なので以下の画面のような表示になります。
今回はpiユーザのhomeディレクトリで実行していたので以下のようになります。
もし、ターミナルからの都度のmjpg_stream
が面倒であれば、Node-REDのexecノードを使用しても良いかもしれません。
injectノードとexecノードを使用してこんな風に起動させることで起動忘れを防ぐ事もできると思います。
おわりに
これでmjpg_stream
を使用して、動画っぽいデータを取得できました。
だた、以前使用したcamerapiなどの拡張ノードでも同じことできるような気がしますが、違いはWebサービスとして公開が同時にできつつ、画像を処理することができる点かなと思います。使いどころは難しいかもしれませんが。
とりあえずうまく動いたということで。ググってもNode-REDとmjpg_stream
ノードの組み合わせの日本語の情報が少なかったので書いてみたというエントリーでした。
【今回のフロー】
[ { "id": "1a4b6256.e141ce", "type": "tab", "label": "mjpg_streming", "disabled": false, "info": "" }, { "id": "ff084c2e.c225a", "type": "debug", "z": "1a4b6256.e141ce", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 550, "y": 60, "wires": [] }, { "id": "765a06f7.6ca7e8", "type": "file", "z": "1a4b6256.e141ce", "name": "Camera Capture", "filename": "capture.jpg", "appendNewline": false, "createDir": false, "overwriteFile": "true", "x": 560, "y": 140, "wires": [ [] ] }, { "id": "46e883a0.2e335c", "type": "mjpg-consumer", "z": "1a4b6256.e141ce", "name": "MjpgConsumer", "stream": "http://raspberrypi.local:8080/?action=stream", "interval": "5", "x": 360, "y": 100, "wires": [ [ "ff084c2e.c225a", "765a06f7.6ca7e8" ] ] }, { "id": "309b4801.230ef8", "type": "inject", "z": "1a4b6256.e141ce", "name": "Stop Consumer", "topic": "", "payload": "stop", "payloadType": "str", "repeat": "", "crontab": "", "once": false, "onceDelay": "", "x": 160, "y": 140, "wires": [ [ "46e883a0.2e335c" ] ] }, { "id": "9577ebc6.72bee8", "type": "inject", "z": "1a4b6256.e141ce", "name": "Start Consumer", "topic": "", "payload": "start", "payloadType": "str", "repeat": "", "crontab": "", "once": true, "onceDelay": "", "x": 160, "y": 60, "wires": [ [ "46e883a0.2e335c" ] ] }, { "id": "aa22e1d5.e6c6", "type": "exec", "z": "1a4b6256.e141ce", "command": "./mjpg-streamer/start_mjpg_streamer.sh", "addpay": true, "append": "", "useSpawn": "false", "timer": "", "oldrc": false, "name": "", "x": 440, "y": 200, "wires": [ [], [], [] ] }, { "id": "d141f688.7d0d28", "type": "inject", "z": "1a4b6256.e141ce", "name": "Start", "topic": "", "payload": "", "payloadType": "date", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "x": 130, "y": 200, "wires": [ [ "aa22e1d5.e6c6" ] ] } ]
【参考】