概要
ESP32-WROVER-E/OV2640/arduino-esp32のesp-cameraライブラリを使ったときに、青色部分が多い画像を撮影しようとすると失敗するので、原因を調べ対処した。
背景と目的
arduino-esp32で、先日作製を始めた家庭菜園の成長記録用カメラの製作において、青色部分が多い画像を撮影しようとすると、なぜか撮影がうまくいかないという現象が発生した。原因を調べ、撮影できるように対処方法を考える。
詳細
1. 問題発生状況の整理
- ハードウェア: 家庭菜園の成長記録用カメラ
- CPU: ESP32-WROVER-E
- カメラモジュール: OV2640
- ソフトウェア: arduino-esp32 v1.0.6とそれに含まれるesp-cameraライブラリを使用し撮影周りの処理を実装
- 主な設定
上記の条件に置いて、以下の画像のような、プランターを中心として背景に青色が主体の日除けシート(ホームセンターなどで売っているもの)が映る構図(図1.1)で撮影したところ、
撮影画像のデータサイズが極端に小さく(10kB程度、正常なら200~300kB程度はある)なってしまい、大部分がJPEGへのエンコードが失敗しているような画像(図1.2)となる
という現象が発生した。
図1.1 撮影構図のイメージ(以下は、別途スマートフォンで撮影したものであり、実際のカメラ設置位置ではさらに浅い角度で撮っているため、青色部分はもう少し増える。)
図1.2 撮影失敗した画像(※この画像よりももっと灰色部分が多い)
2. 解決策
検討をたくさん行ったので、先に結論を書くと、はっきりした解決方法が見つからなかったが、とりあえず対症療法的になんとなく効果のある方法がいくつか見つかった。
- 以下の設定を変えると多少失敗の確率が下がる。
- オートホワイトバランスを無効化すると、少しだけ失敗の確率は下がる。
- jpeg_qualityを下げると、少しだけ失敗の確率は下がる。
- DCWはONがよい。
- 失敗しても継続的に40回くらい繰り返すとなぜか撮れるようになる。
以下、解決策に至るまでの検討内容をメモ。
3. 撮影対象範囲の青色部分の多さが関係していることを確認
様々な確認を行った結果、
青色部分が多いことが撮影失敗に関係している
ことが疑わくなってきたので、1で示した構図よりももっと単純な構図として、
カメラレンズの前5cm程度に、青色の紙を置いて、写真全体が青1色となる構図
で撮影してみたところ、
ほぼ100%撮影に失敗する
ことがわかった。
4. CameraWebServerサンプルでも同じことが起こることを確認
しかし、単なる自分の実装ミスではないか?と疑わしかったので、リアルタイムに撮影画像を観察してみた。撮影設定は、現象確認時と同じだが、jpeg_qualityは5に設定できなかったので10とした。 結果、確かにCameraWebServerサンプルでも青一色の場合に同様の現象が起きた。具体的には、画像サイズが正常な場合に比べ極端に小さくなり、Web画面上に画像が表示されない。ということで、自分の実装ミスではなく、今回の条件における固有の現象と言えそうだ。
23:01:22.191 -> MJPG: 7200B 12ms (83.3fps), AVG: 434ms (2.3fps), 0+0+0+0=0 0
5. jpeg_qualityの変更→多少効果あり
jpeg_qualityを下げる(数値を大きくする)と、失敗の確率が下がる
という傾向が見えた。しかし、できるだけ高品質で写真を撮りたいのと、一応画質の満足いく設定としてjpeg_quality=10でも、失敗確率がそれなりにあり、回避できないため、この方法だけでは解決が難しそう。
6. オートホワイトバランス無効化→多少効果あり
特定の色が多いときにおかしいということは、オートホワイトバランスがうまく動かないせいなのか?という疑問もあり、オートホワイトバランスを無効化して撮影したところ、失敗確率が下がった。特に、3の画像全体が青色の場合のほうが顕著に差が出た。
オートホワイトバランス無効化は、やや効果がある
具体的には、esp_camera_sensor_getでステータスを取得し、set_whitebalとset_awb_gainで第2引数を0に設定している。
sensor_t * s = esp_camera_sensor_get(); s->set_whitebal(s, 0); s->set_awb_gain(s, 0);
色のバランスが極端であれば、オートホワイトバランスがうまく動かないのは考えられるが、だからといって撮影そのものができなったり、jpegのエンコードがうまくいかなくなったりするのか?という疑問は残る。しかし、このあたり、いろいろ調べてもよくわからなかった。arduino-esp32の場合、esp-cameraライブラリ部分はヘッダファイル以外バイナリで提供されているので詳しい実装が覗けないということもある。(esp-idfと同じであれば、そちらを覗けばいいのかも?)
7. DCWの設定について
CameraWebServerのWeb画面には、DCW(Downsize EN)という設定がある。プランター撮影時に、ONだとうまく撮れるが、これを解除すると失敗する。なので、これも関係しているように見えたのだが、これはONがデフォルトらしく、作成したソフトでもONになっていた。したがって、これが決定打ということでもない。
8. そのほかの設定
結局、esp-cameraライブラリのsensor.hで定義されている設定値をいろいろいじってみたのだが、改善できるものは見つからなかった。
9. arduino-esp32をアップデートしてみたらどうなるか?→そもそもコンパイルできず(githubの2021/07/03時点のmaster)
arduino-esp32として正式リリースされArduino IDEから参照可能なバージョンは、2021/07/03時点ではv1.0.6であるが、githubのリポジトリにはそれより新しいバージョンがあるので試してみたが、そもそもesp-camera以外の部分のコンパイルでつまずき動かせなかった。正式リリースされていないので、まあこんなものか。とはいえ、esp-cameraライブラリを見ると、ヘッダファイルの配置先ディレクトリの構造が変わっていたりして、何かしら手が入っているのかも?と思えなくもないので、改善される希望はあるのかも?正式リリースされるまで、しばらく待ちたい。
10.継続的にesp_camera_fb_getを繰り返す
やけくそで、esp_camera_initをしてから、esp_camera_fb_getを何度も繰り返すと、失敗しながらも撮影画像のデータサイズが少しずつ大きくなり、あるところで突然撮影ができるようになった。試しに、何度か同じことを試したが、やはりちゃんと撮れる。なので、いまいち納得いかないが、失敗しても無理やり撮影を繰り返すのも有効だといえる。
まとめと今後の課題
いろいろ検討を行い、はっきりした解決方法が見つからなかったが、多少の改善がみられる方法が見つかった。