picamera2を用いたカメラ画像の取得とLcdディスプレイへの表示
カメラで取得した映像を、LCDディスプレイに表示させる方法を考えます。
picamera21を用いたカメラ画像の取得方法と、取得した画像をLcdディスプレイに表示するための処理について考えます。
画像のリサイズに関する比較を行い、処理速度の違いについても考えます。
環境
以下は、今回使用している、システム情報とpicamera2の情報です。
&
Arducamのカメラ2を使用してます。最大の解像度は "4656 × 3496" です。
Picamera2でカメラ画像を取得する
Picamera2では画像の取得方法が複数あります。
はじめに簡単な例として、Picamera2.capture_file
を使用し、カメラから画像を取得する例を示します。
=
=
ファイル名からフォーマットを取得し、画像を保存しています。
Picamera2では保存する際に、PILを用いるため、JPEG, PNG, GIFがサポートされるようです。
(ちなみにPicamera2.capture_file
はio.BytesIO()
を使って、取得した画像をメモリ上のバイナリデータとして扱うこともできます。→ おまけ)
処理時間の比較
上記例ではカメラ画像をファイルとして保存していますが、普通にデータとして扱いたい場合もあります。
取得した後に、どのように使用するかによって、使い分けることになります。
以下に各関数を用いた際の処理時間をまとめました。
time.time()
を使って計測し、1000回実行時の平均値を採用しています。
関数名 | 処理時間 [s] | 返り値 |
---|---|---|
capture_buffers | 0.255 | [<class 'numpy.ndarray'> ], <class 'dict'> (1dimとメタデータ) |
capture_array | 0.607 | <class 'numpy.ndarray'> (2dim) |
capture_image | 0.701 | <class 'PIL.Image.Image'> |
capture_file(".jpg") | 1.260 | <class 'dict'> (メタデータ) |
capture_file(".png") | 5.391 | <class 'dict'> (メタデータ) |
処理時間は圧倒的にPicamera2.capture_buffers
が速いことがわかります。
Picamera2.capture_array
ではHelpers.make_array
により変換処理がされています。
Picamera2.capture_image
ではその変換されたarrayをPILイメージに変換しています。
ということで、Helpers.make_array
が、処理のボトルネックになっていそうです。
Picamera2.capture_image
を使うケースが多いかと思います。
しかし、写真を保存し、あとで利用する等であれば、Picamera2.capture_buffers
を使って取得した値をpickleで保存するのがメタです。
buffers
から復元する例を最後に記載します。→ おまけ
画像表示処理の検討
LCDディスプレイに表示するために、PILのイメージを準備することを想定した場合、必要な処理は以下になります。
- PILイメージを生成する。
- 画像をLCDディスプレイのサイズにリサイズする。
この2つの処理を出来る限り素早く行うことが必要になります。
そもそもフルの解像度で撮ったものを小さなLCDに出力する必要は全くありませんが、"4656 × 3496"のフルサイズで撮ったものをリサイズして"160 × 128"にします。
パターン1: Image.fromarray
とても単純な方法です。
Picamera2.capture_image
から得た画像をリサイズします。
=
=
= 0
=
=
+=
パターン2: cv2
OpenCVを使用してリサイズを行ってから、イメージを生成します。
=
=
= 0
=
=
=
=
=
=
+=
※ OpenCVのライセンスはライセンスの制約があるため注意が必要です。
処理時間
上記2パターンの出力結果は以下になります。
パターン | 処理時間 [s] |
---|---|
パターン1 | 0.927 |
パターン2 | 0.600 |
一般的にPILのイメージのリサイズよりもcv2のリサイズの方が速いと言われています。 今回の結果も割とそれを反映していると考えられます。
イメージサイズが大きい状態での比較なので、顕著に差が出ていそうです。
次にできる限り、処理時間が短くなるように解像度とセンサーサイズを変更します。
the resolution of the sensor output
デフォルトではmain=
sizeを選択すると、画角が決まってしまいます。
そこでraw=
をのsizeを使用して画角を最大で固定し、出力サイズをディスプレイサイズに変更します。
=
計測した結果を示します。最初に比べればだいぶ速くなりました。
パターン | 処理時間 [s] |
---|---|
パターン3 | 0.286 |
ディスプレイ表示に必要な時間を0秒だとしたら、4fps程度になりました。 (ディスプレイは最大60fps程度です。。)
他に良いアイディアが思いつくまではこれで行こうと思います。
おまけ
io.BytesIO()
io.BytesIO()
を使用する場合はフォーマットがないためformat=
を指定してあげる必要があります。
=
Picamera2.capture_buffers
buffersからイメージを作成するに際し、picamera2.request.Helpers
を使用します。
まずpickleなどでbuffers
を保存します。
Helpers
を使ってみます。
=
=
=
, =
=
saveする際に、Helpers
に引数としてPicamera2
を渡しています。
saveする時にカメラ情報をいくつか使用するため、しかたないです。
掻い潜れますが、とりあえずはカメラがないケースでの現像はないのでおいておきます。
(追記)
make_array
やmake_image
するだけなら実際はPicamera2()
を使用しません。
そのため、ソースコードを参考に変換することは容易です。
ただ、私はrawで撮影し、カメラとPicamera2無しで現像することにしました。
→ Picamera2を使用したRAW撮影と現像処理の方法
picam2.helpers.make_image
を使って生成する方がスマートかと思います。exampleがGitHubにありました。
picamera2/examples/capture_helpers.py - raspberrypi/picamera2 - GitHub
参考文献
picamera2は、Pythonのライブラリで、Raspberry Pi上でカメラシステムを使用する際に利用されます。基本的にはリボンケーブルで接続されるカメラを想定しているようです。Picamera2はドキュメントがPDFにより提供されています。 raspberrypi/picamera2 - GitHub PDF: The Picamera2 Library