4.14. CSIの基本¶
csi モジュールは、Pythonコードがカメラセンサーを駆動する手段です。フレームをキャプチャするすべてのスクリプトは、同じ3部構成の形に従います。上部にインポート、中央に1回限りの設定、そして下部にカメラから1フレームずつ取り出す while True ループです。
4.14.1. 典型的なループ¶
import csi, image, time
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# process img here
print(clock.fps())
4.14.2. 各呼び出しの動作¶
import csi, image, time3つのモジュールを取り込みます。
csiはセンサーを制御し、imageはsnapshot()が返すImageクラスを定義し、timeは1秒あたりのフレーム数を測定するために使うtime.clock()ヘルパーを提供します。csi.CSI()1つの物理カメラセンサーをラップする
CSIインスタンスを構築します。コンストラクタはカメラペリフェラルを確保し、センサーごとの設定を記録します。単一のセンサーを持つカメラには1つのCSIインスタンスがあり、2つのセンサー(カラーとサーマル、カラーとイベント)を持つカメラには2つあり、それぞれコンストラクタへのcid引数で選択されます。csi0.reset()センサーに電源を入れて設定します。デフォルトではセンサーのリセットピンをパルスし、その後センサーのI2Cレジスタを既知の初期状態に書き込みます。後続の設定呼び出し(
pixformat、framesize、オート制御の各設定)は、同じI2C制御バスを通じてさらにレジスタ書き込みを送ります。csi0.pixformat(csi.RGB565)出力ピクセルフォーマットを選択するセンサーレジスタに書き込みます。選択肢は ピクセルフォーマット ページで紹介したフォーマット、すなわち
RGB565、GRAYSCALE、BAYER、YUV422、そしてサポートするセンサーではJPEGです。csi0.framesize(csi.QVGA)出力解像度を選択するレジスタに書き込みます。
QVGAは320 × 240です。名前付きサイズは、サポートするセンサーではWQXGA2(2592 × 1944、約5 MP)まであります。カスタムの(width, height)タプルも、センサーの出力能力に合致していれば使えます。clock = time.clock()クロックヘルパーを作成します。ループ内の
clock.tick()の各呼び出しは反復の開始時刻を記録し、time.clock.fps()は最近のループレートを1秒あたりのフレーム数で報告します。img = csi0.snapshot()センサーから1フレームをキャプチャし、
Imageとして返します。そのフレームがメモリに収まる仕組みは、より詳しく見る価値があります。
4.14.3. snapshotがメモリを埋める仕組み¶
センサーは、センサーバス で説明されているピクセルデータバス上で、毎秒数百メガバイトの速度でピクセルを供給します。これはCPUがソフトウェアでピクセルごとにコピーするには速すぎます。
代わりに、MCUは転送を ダイレクトメモリアクセス(DMA)にオフロードします。これはCPUとは別のハードウェアエンジンで、CPUを一切介さずにMCU内のある場所から別の場所へバイトをコピーします。カメラ入力ペリフェラルは、入ってくる各ピクセルバイトを小さなオンチップFIFOに取り込み、MCU側で実行されるISP段階が通過中にデータを処理し、DMAエンジンが完成したピクセルをRAM内のフレームバッファの対応するピクセルオフセットに書き込みます。DMAチャネルがプログラムされた後は、この連鎖のどの部分もCPUを必要としません。
snapshot() が呼び出されると:
CSIドライバは、フレームバッファのアドレス、転送長(1フレーム分のピクセル)、およびDMA完了割り込み用のコールバックをDMAエンジンにプログラムします。
ドライバはカメラ入力ペリフェラルを有効にし、センサーが次のフレームの開始を通知するのを待ちます。
センサーがフレームをストリーム出力すると、ペリフェラルは各ピクセルバイトをISPを通じてDMAエンジンに渡し、DMAエンジンが結果をRAM内の次のフレームバッファオフセットに書き込みます。転送中、CPUは他のコードを自由に実行できます。
フレームの最後のピクセルが到着すると、DMAは完了割り込みを発生させ、ドライバはフレームバッファを
Imageでラップし、snapshot()がそれをユーザーコードに返します。
返される Image はピクセルデータのコピーを所有しません。それはRAM内のカメラのフレームバッファの1つを指しています。カメラがいくつのフレームバッファを保持するか、そしてそれらが snapshot() の各呼び出しでDMAとユーザーコードの間でどのように受け渡されるかは、アプリケーションが framebuffers() を通じて選択したバッファリングモードに依存します。