マルチカメラシステム#
マルチカメラ設定は、検査、3D再構築、同期データ取り込みなどの産業用アプリケーションで一般的です。単一のカメラでは必要なすべての情報をキャプチャできない場合に使用されます。
一般的なユースケース:
- 対象物の異なる視点のキャプチャ
- 視野の拡大
- スループットの向上
- 複数オブジェクトの並列検査
基本的な課題#
複数のカメラを使用する場合、いくつかの課題が生じます:
- 同期(タイミング)
- 帯域幅の制限(特にGigEカメラを使用する場合)
- CPU負荷(複数のストリームの処理)
- デバイスの識別とマッピング
デバイスの識別#
各カメラには、通常はシリアル番号などの一意の識別子が必要です。
マッピングの例:
次のようなインデックスの使用は避けてください。 devices[0] カメラが列挙される順序が変わる可能性があるためです。詳細については、以下を参照してください。 カメラの列挙.
複数のカメラインスタンスの作成#
from pypylon import pylon
factory = pylon.TlFactory.GetInstance()
device_info_list = factory.EnumerateDevices()
cameras = []
for device_info in device_info_list:
camera = pylon.InstantCamera(factory.CreateDevice(device_info))
camera.Open()
cameras.append(camera)
これにより、デバイスごとに1つのカメラインスタンスが作成され、開かれます。
取得方法#
複数のカメラを使用する場合は、取得方法(順次(sequential)または並列(parallel))を決定する必要があります。
順次取得#
これは、画像処理が1台ずつ順番に行われることを意味します。
この方法の主な特徴:
- 実装が簡単
- 時間同期されない
- 全体的に処理が遅い
並列取り込み#
これは、複数のカメラからの画像が一緒に処理されることを意味します。
この方法の主な特徴:
- カメラが同時に取得を行う
- 同期に必要
- CPUと帯域幅の要件が高い
同期方法#
カメラを同期させるには、ソフトウェア同期とハードウェア同期のいずれかを選択できます。メリットとデメリットは、ソフトウェアトリガーとハードウェアトリガーの場合と似ています。
ソフトウェア同期#
この方法の主な特徴:
- ソフトウェアによるカメラのトリガー
- 精度が限られている
- オペレーティングシステムのスケジューリングの影響を受ける
例:
ハードウェア同期(推奨)#
この方法の主な特徴:
- 正確なタイミング
- 決定論的な動作
- ステレオシステムまたは計測システムに必要です
帯域幅に関する考慮事項(GigE)#
複数のGigEカメラが同じネットワーク帯域幅を共有します。
発生する可能性のある問題:
- パケットロス
- フレームドロップ
- 遅延の増加
潜在的な問題を軽減するために、次のいずれかの戦略を使用できます。
- 専用のネットワークインターフェイスカード(NIC)を使用する
- ジャンボフレームを有効にする(MTU 9000)
- ROIまたはフレームレートを削減する
- パケット遅延を設定する
処理アーキテクチャ#
シングルスレッド#
- シンプル
- スケーラビリティが限られている
マルチスレッド(推奨)#
- スケーラブル
- 優れたCPU使用率
- 実装がより複雑
パターンの例#
基本的なマルチカメラのループ(順次ポーリング)#
from pypylon import pylon
def process(image):
print(image.shape)
factory = pylon.TlFactory.GetInstance()
device_info_list = factory.EnumerateDevices()
cameras = [pylon.InstantCamera(factory.CreateDevice(device_info)) for device_info in device_info_list]
for camera in cameras:
camera.Open()
camera.StartGrabbing()
while any(camera.IsGrabbing() for camera in cameras):
for camera in cameras:
if camera.IsGrabbing():
with camera.RetrieveResult(1000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
# Do processing on image here, e.g. call a function.
process(image)
高度なアプローチ:InstantCameraArray(推奨)#
pypylonには、マルチカメラ設定用の専用の抽象化が用意されています。 InstantCameraArray.
このクラスは複数のカメラを管理し、どのカメラが画像を提供したかに関する情報を含む、 単一の統合された RetrieveResult() 呼び出しを提供します。
from pypylon import pylon
def process(image):
print(image.shape)
COUNT_OF_IMAGES_TO_GRAB = 100
RETRIEVE_TIMEOUT_MS = 5000
factory = pylon.TlFactory.GetInstance()
device_info_list = factory.EnumerateDevices()
with pylon.InstantCameraArray(len(device_info_list)) as cameras:
for i, camera in enumerate(cameras):
camera.Attach(factory.CreateDevice(device_info_list[i]))
print("Using device:", camera.DeviceInfo.ModelName)
cameras.StartGrabbing()
for i in range(COUNT_OF_IMAGES_TO_GRAB):
if not cameras.IsGrabbing():
break
with cameras.RetrieveResult(
RETRIEVE_TIMEOUT_MS,
pylon.TimeoutHandling_ThrowException
) as grab_result:
if grab_result.GrabSucceeded():
cam_idx = grab_result.CameraContext
print(f"Camera {cam_idx}: {cameras[cam_idx].DeviceInfo.ModelName}")
image = grab_result.Array
# Do processing on image here, e.g. call a function.
process(image)
else:
print("Error:", grab_result.ErrorDescription)
なぜ InstantCameraArray が重要なのか
手動によるループ処理と比較して、このアプローチには以下の利点があります。
- すべてのカメラに対する単一の取得ループ
- 自動カメラコンテキスト追跡(
camera.CameraContext) - よりシンプルになった同期処理
- より効率的なスレッド使用
概念的には:
実用的な設計ガイドライン#
- カメラは必ずシリアル番号で識別してください。
- ハードウェア同期を優先してください。
- 可能な限り帯域幅を削減します(例:ROIを指定する、またはフレームレートを下げる)。
- スケーラビリティのために、別々の処理スレッドを使用してください。
- システム負荷(CPU、ネットワーク)を監視します。
よくある落とし穴#
- デバイスインデックスに依存する。
- ネットワーク帯域幅を超える。
- 同期要件を無視する。
- 取得ループ内の処理をブロックする。
メンタルモデル#
主なポイント#
- マルチカメラシステムには綿密な設計が必要です。
- 同期は多くのアプリケーションにおいて極めて重要です。
- 帯域幅とCPUは早期に検討する必要があります。
- スケーラブルなアーキテクチャでは並列処理が使用されます。