はじめに
こんにちは、リコーの@roohii_3です。
これまでTHETAの中でOpenCVを動かすことに関して記事を書いてきました。
- THETAの中でOpenCVを動かす (←NDKを使った例)
- THETAの中でOpenCVを動かす【プレビューフレーム取得編】 (←前回の記事)
本記事は「THETAの中でOpenCVを動かす【プレビューフレーム取得編】」の応用編です。
プレビューフレームから「動体検知」し、何か動くものを認識したら写真を撮る、といったようにTHETAを監視カメラ的なものに改造してみました。
コードは以下で公開しています。
https://github.com/theta-skunkworks/theta-plugin-opencv-detection-sample
※ 実装はいろいろと手を抜いてます。流用する場合はご注意を…。
開発環境
- OpenCV Android pack ver. 3.4.5
- Android Studio ver. 3.3+
- gradle ver. 5.1.1
- RICOH THETA V Firmware ver. 3.00.1
実装
事前準備・OpenCVの導入手順などは前回記事の「事前準備」を見てください。
実装は、前回のコードをベースに動体認識、静止画撮影の処理を追加しています。
動体認識
動体認識アルゴリズムは以下のような流れです。
それぞれの処理はOpenCVのチュートリアルに載っているようなものです。
対象言語はPythonですが、OpenCV-Pythonチュートリアル(日本語訳版)も参考になります。
実際にどう実装しているかは、GitHubから MainActivity.java
の onCameraFrame()
メソッドを見てみてください。
静止画撮影
静止画撮影処理の部分は、OpenCVの tutorial-3-cameracontrol
と THETA Plug-in: CameraAPI Capture Plugin を参考にしました。
どちらとも takePicture()
と Camera.PictureCallback
という静止画撮影に必要なメソッドの実装がされていますが、本記事のコードでは ThetaController.java
で実装しています。
Camera APIパラメータ
前回記事でも触れたように、THETAには独自のCamera APIパラメータがあります。
たとえば撮影時には、以下のパラメータを設定しています。
Camera.Parameters params = mCamera.getParameters();
// 画像サイズ
params.setPictureSize(5376, 2688);
// 静止画撮影モード
params.set("RIC_SHOOTING_MODE", "RicStillCaptureStd");
// 自動露出モード
params.set("RIC_EXPOSURE_MODE", "RicAutoExposureP");
// スティッチングの種類を"DynamicStitching"に設定
params.set("RIC_PROC_STITCHING", "RicDynamicStitchingAuto");
スティッチング
上のコード例の一番最後にあるように、ここでは「スティッチングの種類」のパラメータに"RicDynamicStitchingAuto
"を設定しています。
これは被写体に応じて精密なスティッチングを行うものですが、少し処理時間がかかります。
「スティッチングは簡易的で良いので、処理時間を速くしたい」という方は"RicStaticStitching
"を使うと良いと思います。
他にもスティッチングの種類を示すパラメータがあるので、作るものに応じて使い分けてみてください。
パラメータ値と特徴を以下にまとめておきます。
(参考: THETA Plug-inドキュメント > Camera API)
パラメータ値 | 特徴 |
---|---|
“RicNonStitching” | スティッチングしない(魚眼画像が横に2枚並んだ状態になる)。 |
“RicStaticStitching” | 簡易的にスティッチングを行う。 |
“RicDynamicStitchingAuto” | 被写体に応じて精密にスティッチングを行う。 ちょっと処理時間がかかる。 |
“RicDynamicStitchingSave” | 精密にスティッチングするときの「スティッチングの仕方(つなぐ位置など)」の情報を保持する。 連続撮影するときに便利。 1枚目はこのパラメータ値を使い、2枚目以降は“ RicDynamicStitchingLoad ”を使うようにすると、1枚目と同じ具合にスティッチングできる。 |
“RicDynamicStitchingLoad” | “RicDynamicStitchingSave ”と合わせて使う。 |
画像サイズ
ここでは THETA V
用のプラグインを想定していますが、THETA Z1
では画像サイズを 6720x3360
に設定する必要があります。
// Z1で動かすときは、6720x3360 を設定する
params.setPictureSize(6720, 3360);
また、スティッチングの種類を示すパラメータに“RicNonStitching
”を設定したときも、画像サイズが変わります。
THETA V
は5792x2896
、THETA Z1
は7296x3648
を設定します。
注意点
記事の最初に書いたように、本記事のコードはいろいろと手を抜いてます。
たとえば…
- 静止画にExif情報が付与されない
- THETAが動いたり、露出が変わるだけでも敏感に動体認識が反応してしまう
- 認識処理~撮影~画像保存が単一スレッド上で行われている(本来であれば、保存など処理が重い部分は別スレッドに分けるべし)
- 容量がいっぱいになっても撮り続けようとする(本来であれば、ストレージ容量に応じて撮影制限する必要あり)
- (たぶん他にもある)
もし本コードを何かに流用する場合は、その辺りも注意して実装お願いします…。
実行
一番最初にプラグインを動かすときは、Vysor等を使ってパーミッションの設定をします。
※ プラグインストアからインストールしたプラグインは、パーミッション設定は不要です。
パーミッションの設定
Vysor等を使ってSettingsアプリを開き、"Motion Detector > Permissions"より、"Camera"、"Storage"の許可をONにします。
実行してみた様子
Vysorを使ってプラグインを実行したときは、リアルタイムで動体認識の様子を見られるようにしました。
緑色の四角で囲まれた部分が動体認識した箇所です。
THETAの前で手を振ってみましたが、ちゃんと手が認識されました。
処理速度など
OpenCVの出力文によると、27~30fpsくらい出ていました。
今回はプレビューのフレームサイズを最小の640x320
にしました。フレームサイズによってはフレームレートが下がってしまいます。作るものに応じてフレームサイズを調整すると良いと思います。
フレームサイズを変更するには、"RIC_SHOOTING_MODE
"のパラメータ値を変更します。
パラメータ値はTHETA Plug-in ドキュメント > Camera APIのShooting Mode
を参考にしてください。
Camera.Parameters params = mCamera.getParameters();
// プレビューのフレームサイズを 1920x960 に設定
params.set("RIC_SHOOTING_MODE", "RicMoviePreview1920");
保存ファイル
PCにTHETAを繋いで中身を確認すると、"DCIM"の下に"MotionDetector"フォルダができています。
その中に [1]動体認識したときの撮影画像 と、[2]認識したものを矩形で示した画像 が保存されます。
※ 例によって手抜き実装なので、[1]、[2]の画像が保存されるタイミングがズレてます…。
おわりに
THETAの中で、果たしてリアルタイム画像処理なんてできるのかな?、と思っていましたが案外動いちゃいました。
THETA+Computer Visionに興味ありなユーザーさんがもしいたら、本記事が参考になれば幸いです。
参考
- Docs / THETA Plug-in > Camera API
- THETA Plug-in: CameraAPI Capture Plugin
- OpenCV Tutorials:
- OpenCV-Python-Tutorials(日本語訳版)
- OpenCV Java documentation
RICOH THETAプラグインパートナープログラムについて
THETAプラグインに興味を持たれた方がいれば、以下の記事もぜひご覧ください。
RICOH THETAプラグイン開発者コミュニティでは、他にも記事を書いています。
RICOH THETAプラグインについてはこちら。興味を持たれた方はtwitterのフォローとTHETAプラグイン開発コミュニティ(slack)への参加もぜひどうぞ。