連続高速キャプチャ(GbE-2 / Python)
This content is not available in your language yet.
HelloWorld で作成した共通モジュール puclib.py と スレッド間キュー (queue.Queue) を使用して、GbE-2 から連続送信されるフレームデータをコマ落ち(フレームドロップ)させることなく高速に取り込み・復号するスクリプトの作成手順です。
-
スクリプトの作成
puclib.pyと同じフォルダーにgbe2_continuous_capture.pyを作成し、以下のコードを記述します。gbe2_continuous_capture.py import ctypesfrom ctypes import c_uint32, c_ushort, c_ubyte, c_void_p, POINTER, WINFUNCTYPE, byrefimport threadingimport queueimport timeimport numpy as np# 共通モジュール puclib.py から読み込みfrom puclib import (load_sdk, PUC_SUCCEEDED, PUC_DETECT_TARGET_HAWK,PUC_Q_COUNT, PUC_DETECT_FILTER, PUC_DETECT_INFO, PUC_XFER_DATA_INFO)def main():print("INFINICAM GbE-2 連続高速キャプチャ開始...")# 1. SDKのロードと初期化puclib = load_sdk()if puclib.PUC_Initialize() != PUC_SUCCEEDED:print("エラー: SDKの初期化に失敗しました。")return# 2. 連続転送制御用 API の追加型定義CALLBACK_FUNC = WINFUNCTYPE(None, POINTER(PUC_XFER_DATA_INFO), c_void_p)puclib.PUC_SetRingBufferCount.argtypes = [c_void_p, c_uint32]puclib.PUC_SetRingBufferCount.restype = c_uint32puclib.PUC_BeginXferData.argtypes = [c_void_p, CALLBACK_FUNC, c_void_p]puclib.PUC_BeginXferData.restype = c_uint32puclib.PUC_EndXferData.argtypes = [c_void_p]puclib.PUC_EndXferData.restype = c_uint32# 3. デバイスの検索とオープンdetect_filter = PUC_DETECT_FILTER(nDeviceTypeFlags=PUC_DETECT_TARGET_HAWK)detect_info = PUC_DETECT_INFO()if puclib.PUC_DetectDevice2(byref(detect_filter), byref(detect_info)) != PUC_SUCCEEDED or detect_info.nDeviceCount == 0:print("エラー: GbE-2 カメラが見つかりませんでした。")returnh_device = c_void_p()if puclib.PUC_OpenDevice2(0, byref(h_device)) != PUC_SUCCEEDED:print("エラー: デバイスのオープンに失敗しました。")return# 4. カメラパラメータの取得width, height = c_uint32(), c_uint32()puclib.PUC_GetResolution(h_device, byref(width), byref(height))w, h = width.value, height.valueq_vals = (c_ushort * PUC_Q_COUNT)()puclib.PUC_GetQuantization2(h_device, q_vals)print(f"解像度: {w} x {h} ピクセル")# 5. データキューと処理用の準備line_bytes = (w + 3) & ~3frame_queue = queue.Queue(maxsize=100) # 受信バッファキューcaptured_count = 0target_frames = 100 # キャプチャ目標フレーム数stop_event = threading.Event()# 6. 画像受信コールバック関数 (SDK内部スレッドから呼び出されます)@CALLBACK_FUNCdef image_callback(p_xfer_data, p_user_param):nonlocal captured_countif not p_xfer_data or p_xfer_data.contents.isDamaged:return# コールバック内では生の圧縮データを高速コピーしてキューに退避raw_data = bytes(ctypes.cast(p_xfer_data.contents.pData, POINTER(c_ubyte * p_xfer_data.contents.nDataSize)).contents)seq_no = p_xfer_data.contents.nSequenceNotry:frame_queue.put_nowait((seq_no, raw_data))captured_count += 1except queue.Full:print(f"警告: キューが満杯のためフレーム {seq_no} をドロップしました。")# 7. バックグラウンド復号・処理スレッドprocessed_count = 0def processing_worker():nonlocal processed_count# 復号用バッファdecoded_buf = (c_ubyte * (line_bytes * h))()while not stop_event.is_set() or not frame_queue.empty():try:seq_no, raw_bytes = frame_queue.get(timeout=0.1)except queue.Empty:continue# 圧縮データを ctypes バッファへ変換して復号comp_buf = (c_ubyte * len(raw_bytes)).from_buffer_copy(raw_bytes)ret = puclib.PUC_DecodeData(decoded_buf, 0, 0, w, h, line_bytes, comp_buf, q_vals)if ret == PUC_SUCCEEDED:processed_count += 1# 必要に応じてここで NumPy 化や解析・ファイル保存を実施if processed_count % 20 == 0:print(f"処理進捗: {processed_count}/{target_frames} フレーム完了 (SequenceNo: {seq_no})")frame_queue.task_done()# 8. ワーカースレッドの開始worker_thread = threading.Thread(target=processing_worker, daemon=True)worker_thread.start()# 9. 連続転送の開始puclib.PUC_SetRingBufferCount(h_device, 64)ret = puclib.PUC_BeginXferData(h_device, image_callback, None)if ret != PUC_SUCCEEDED:print(f"エラー: 連続転送の開始に失敗しました。ErrorCode: {ret}")puclib.PUC_CloseDevice(h_device)returnstart_time = time.time()print(f"連続キャプチャ中 ({target_frames} フレームの到達を待ちます)...")# 10. 目標フレーム数に達するまで待機while captured_count < target_frames:time.sleep(0.01)elapsed_time = time.time() - start_time# 11. 転送停止と後処理puclib.PUC_EndXferData(h_device)stop_event.set()worker_thread.join()fps = target_frames / elapsed_time if elapsed_time > 0 else 0print(f"\n--- キャプチャ完了 ---")print(f"取得フレーム数: {captured_count} フレーム")print(f"復号処理数 : {processed_count} フレーム")print(f"所要時間 : {elapsed_time:.2f} 秒")print(f"平均スループット: {fps:.1f} fps")# 12. クローズpuclib.PUC_CloseDevice(h_device)if __name__ == "__main__":main() -
スクリプトの実行
Terminal window python gbe2_continuous_capture.py実行するとカメラから目標フレーム数(100フレーム)がキュー経由で高速取り込み・復号され、処理完了後にキャプチャ時間と実効 fps が表示されます。
高速キャプチャ実装のポイント
Section titled “高速キャプチャ実装のポイント”1. コールバック内の処理最小化(データ退避のみ)
Section titled “1. コールバック内の処理最小化(データ退避のみ)”コールバック関数 image_callback 内で重い画像復号(PUC_DecodeData)やディスク保存を行うと、SDK 内部の受信処理が遅延しフレームドロップの原因となります。コールバック内では圧縮データ(バイト配列)の退避とキューへの追加のみを最短時間で完了させます。
2. プロデューサー・コンシューマー構成(queue.Queue)
Section titled “2. プロデューサー・コンシューマー構成(queue.Queue)”- データ受信(プロデューサー): コールバック関数が受信した生データをキューへ投入。
- データ復号(コンシューマー): 別スレッド(
processing_worker)がキューからデータを取り出して非同期に復号・解析。
このマルチスレッド構造を採用することで、CPU のコアを効率的に利用し、コマ落ちのない安定した高速連続撮影が可能になります。
