はじめに
FA(ファクトリーオートメーション)や検査装置で使われる産業用カメラを制御する際、GenICam(Generic Interface for Cameras) という規格に触れることになります。
本記事では、GenICamの概要と、カメラ設定(Feature)には順番があるという重要なポイントを、具体例と図を交えて解説します。
GenICamとは
GenICam は、EMVA(European Machine Vision Association) が策定した、産業用カメラを統一的に制御するための規格群です。
カメラメーカーごとに異なっていた制御方法を共通化し、メーカーに依存しない共通のインターフェースでカメラを操作できることを目指しています。
GenICamの主な構成要素
| 構成要素 | 役割 |
|---|---|
| GenAPI | カメラの設定項目(Feature)をXMLで記述し、共通APIで読み書きする仕組み |
| SFNC (Standard Features Naming Convention) | Feature名の命名規則。ExposureTime、Widthなど、メーカー共通の名前を定義 |
| GenTL (Generic Transport Layer) | カメラとの通信方式(GigE Vision、USB3 Visionなど)を抽象化するレイヤー |
Featureとは
GenICamでは、カメラの設定項目のことを Feature(フィーチャー) と呼びます。
Feature は文字列の名前で指定し、値を読み書きします。
// 擬似コード:Featureの読み書き
camera.SetFloat("ExposureTime", 5000.0) // 露光時間を5000μsに設定
fps = camera.GetFloat("AcquisitionFrameRate") // フレームレートを取得
ポイント:Featureを設定すると、カメラにはその設定が即座に反映されます。
そして、ある設定が反映されることで、別のFeatureの設定可能範囲が変化することがあります。これが「設定の順番が重要」な理由です。
設定例1:露光時間とフレームレート
カメラをフリーラン(連続撮影)モードで動作させ、露光時間とフレームレートを設定する例を見てみましょう。
フリーランの基本設定
// 擬似コード:フリーラン設定
camera.SetEnum("TriggerMode", "Off") // トリガーモードをOFF(=フリーラン)
camera.SetEnum("AcquisitionMode", "Continuous") // 連続取り込みモード
露光時間とフレームレートの関係
露光時間とフレームレートには、以下の制約関係があります。
露光時間 < 1 / フレームレート
つまり、露光時間が長いと、1フレームあたりの時間が長くなるため、フレームレートの上限が下がります。逆に、露光時間が短ければ、フレームレートの上限が上がります。
ケースA:フレームレートを速くしたい場合
先に露光時間を短くしてから、フレームレートを上げます。
// 現在の状態:露光時間=10000μs、フレームレート=30fps
// NG:先にフレームレートを上げようとする
camera.SetFloat("AcquisitionFrameRate", 200.0) // エラー! 露光時間が長すぎて200fpsにできない
// OK:先に露光時間を短くしてから、フレームレートを上げる
camera.SetFloat("ExposureTime", 1000.0) // ① 露光時間を1000μsに短縮
camera.SetFloat("AcquisitionFrameRate", 200.0) // ② フレームレートを200fpsに変更 → 成功!
なぜNGになるかというと、露光時間が10000μs(=10ms)のままだと、1フレームに最低10msかかるため、フレームレートの上限は100fps程度に制限されます。200fpsは上限を超えているため、エラーになります。
①で露光時間を1000μs(=1ms)に短くすると、1フレームあたりの最低所要時間が短くなり、フレームレートの設定可能上限が大幅に上がります。その後に②で200fpsを設定すれば、範囲内なので成功します。
ケースB:露光時間を長くしたい場合
先にフレームレートを遅くしてから、露光時間を長くします。
// 現在の状態:露光時間=1000μs、フレームレート=100fps
// NG:先に露光時間を長くしようとする
camera.SetFloat("ExposureTime", 20000.0) // エラー! 100fpsでは露光時間20000μsを確保できない
// OK:先にフレームレートを遅くしてから、露光時間を長くする
camera.SetFloat("AcquisitionFrameRate", 30.0) // ① フレームレートを30fpsに変更
camera.SetFloat("ExposureTime", 20000.0) // ② 露光時間を20000μsに変更 → 成功!
なぜNGになるかというと、フレームレートが100fps(=1フレームあたり10ms)のままだと、1フレーム内で使える時間が短いため、露光時間の上限は10000μs(=10ms)程度に制限されます。20000μs(=20ms)は上限を超えているため、エラーになります。
①でフレームレートを30fps(=1フレームあたり約33ms)に遅くすると、1フレーム内で使える時間が増え、露光時間の設定可能上限が大幅に上がります。その後に②で20000μsを設定すれば、範囲内なので成功します。
なぜ順番が重要なのか
Featureを設定した瞬間にカメラに反映されるため、設定の途中状態でも、各Featureの設定可能範囲は常に整合性が保たれています。
- 露光時間を短くする → フレームレートの設定可能上限が上がる
- フレームレートを遅くする → 露光時間の設定可能上限が上がる
この仕組みにより、設定の順番を間違えると、まだ範囲が広がっていない状態で値を設定しようとして、エラーになります。
設定例2:ROI(撮影領域)の設定
ROI(Region of Interest)は、センサの一部分だけを読み出して撮影する機能です。読み出す範囲を小さくすることで、フレームレートを向上させることができます。
ROIに関するFeature
| Feature名 | 説明 |
|---|---|
Width |
読み出し幅(ピクセル) |
Height |
読み出し高さ(ピクセル) |
OffsetX |
読み出し開始位置のX座標 |
OffsetY |
読み出し開始位置のY座標 |
制約条件として、OffsetY + Height ≦ センサの全高さ を満たす必要があります。
ケースA:センサの上下中心付近を撮影する設定
全体(1920×1200)から、上下中心付近の領域(1920×400、OffsetY=400)を撮影する設定にします。
先にHeightを小さくしてから、OffsetYを設定します。
// 現在の状態:Width=1920, Height=1200, OffsetX=0, OffsetY=0(センサ全体)
// NG:先にOffsetYを設定しようとする
camera.SetInt("OffsetY", 400) // エラー! OffsetY(400) + Height(1200) = 1600 > 1200
// OK:先にHeightを小さくしてから、OffsetYを設定する
camera.SetInt("Height", 400) // ① Heightを400に縮小(OffsetY=0のまま上から400px)
camera.SetInt("OffsetY", 400) // ② OffsetYを400に設定 → 成功!(400 + 400 = 800 ≦ 1200)
ケースB:センサ全体に戻す設定
上下中心付近の設定(Height=400、OffsetY=400)から、センサ全体に戻します。
先にOffsetYを0に設定してから、Heightを全体に設定します。
// 現在の状態:Width=1920, Height=400, OffsetX=0, OffsetY=400
// NG:先にHeightを全体にしようとする
camera.SetInt("Height", 1200) // エラー! OffsetY(400) + Height(1200) = 1600 > 1200
// OK:先にOffsetYを0にしてから、Heightを全体にする
camera.SetInt("OffsetY", 0) // ① OffsetYを0にリセット
camera.SetInt("Height", 1200) // ② Heightを1200に設定 → 成功!(0 + 1200 = 1200 ≦ 1200)
ROI設定の順番まとめ
| やりたいこと | 設定順序 |
|---|---|
| ROIを狭める | ① Heightを小さくする → ② OffsetYを設定する |
| ROIを全体に戻す | ① OffsetYを0にする → ② Heightを大きくする |
露光時間とフレームレートの例と同じく、Featureの設定が即座に反映されるため、途中状態でも制約条件が常にチェックされます。
まとめ
GenICamの設定で覚えておくべきこと
- Featureを設定するとカメラに即座に反映される
- ある設定が反映されると、別のFeatureの設定可能範囲が変化する
- そのため、設定の順番を間違えるとエラーになる
依存関係のあるFeatureを設定する際は、先に「制約を緩める」方向の設定を行い、その後に「目的の値を設定する」 という順番を意識しましょう。
個人的な所感
個人的には、プログラマという立場としては、設定値(Feature)を文字列で指定して設定する方法は、設定の自由度が高いものの、文字列を一字一句覚えないといけない(プログラムに書かないといけない)ので、あまり好きではありません。せめてenum(列挙型)のような型安全な仕組みにして欲しかったところです。
実際には、カメラ制御のソフトで、GenICamのパラメータ一覧を取得できる場合が多いので、その一覧からFeatureの設定名(文字列)をコピペしてプログラムに貼り付けると安全です。(「コピペ」というキーワードもプログラマ的にはあまり好きではありませんが(笑))
// 文字列指定(GenICamの実際の方法)
camera.SetFloat("ExposureTime", 5000.0) // タイポしたらランタイムエラー...
// enumだったら嬉しかった(理想)
camera.Set(Feature.ExposureTime, 5000.0) // コンパイル時にチェックできる
さらに、Featureの設定名(文字列)を SFNC(Standard Features Naming Convention) という規格で統一したまでは良かったものの、カメラメーカーによっても設定の解釈が異なり、似たような設定内容で別のFeature名を使っている場合もあります。結局、細かい部分は統一感がなかったりもします。
そのため、実際にカメラの設定を行うときは、各カメラメーカーのマニュアルを必ず参照するようにしてください。SFNCの名前だけを頼りにすると、思わぬ動作の違いに悩まされることがあります。



