ROIを活用してバースト撮影を高速化する【Basler pylon SDK / C#】
Baslerカメラを使って画像処理アプリを開発していると、「視野の一部分だけでいいから、もっと速く撮れないか?」とか、単純に「画像サイズを減らしたい」と感じることはありませんか?
フレームレートを最大限に活かすため、ROI(Region of Interest、撮影範囲の絞り込み) を調整すると高速化できる場合があります。
この記事では、フル画角とROI設定の違いによるフレームレート比較や、実際のサンプル画像とともにC#コードでの設定方法を解説します。
✅ 本記事でわかること
- BaslerカメラのROI(撮影範囲)を設定する方法
- ROIを使って画像サイズとフレームレートを改善する
- ROI設定時の注意点やエラーの対処法
📦 環境
| 項目 | 内容 |
|---|---|
| カメラ | Basler acA2500-14gm |
| SDK | pylon Camera Software Suite |
| 言語 | C# / .NET 8.0 (Windows) |
| レンズ | VS-LD25N(25mm Cマウント) |
🔍 ROIとは?
ROI(Region of Interest)は「センサ上で撮影したい領域」だけを選んで読み出す機能です。
Baslerカメラでは、OffsetX, OffsetY, Width, Height の4つのパラメータで定義します。
センサ全体ではなく一部だけを読み出すことで、
- 画像サイズが小さくなる
- 読み出し時間が短くなる → フレームレート向上
- 必要な領域だけ高速処理できる
といったメリットがあります。
🔧 ROIの設定方法(C#)
今回も前回記事(Basler pylon SDKで連続撮影(バーストキャプチャ)をC#で実装する)で紹介したBaslerCameraSampleクラスに、機能を追加していきます。
ROIはカメラ画像の左上を原点として、切り取る四角の位置と大きさを指定します。
public bool SetOffsetX(int offsetX)
=> SetPLCameraParamter(PLCamera.OffsetX, offsetX);
public bool SetOffsetY(int offsetY)
=> SetPLCameraParamter(PLCamera.OffsetY, offsetY);
public bool SetWidth(int width)
=> SetPLCameraParamter(PLCamera.Width, width);
public bool SetHeight(int height)
=> SetPLCameraParamter(PLCamera.Height, height);
毎回個別に指定するのもいいですが、筆者は一度に設定することも多いです。
ROIがセンササイズからはみ出すと例外が発生してしまうため、条件により設定順序を分けておきます。
public bool SetROI(int offsetX, int offsetY, int width, int height)
{
if (width <= 0 || height <= 0)
throw new ArgumentException("ROI width and height must be greater than zero.");
// ROIがカメラのセンサーサイズを超えないように、設定の順番を考慮する。
if (GetWidth() + offsetX < GetSensorWidth())
{
if (!SetOffsetX(offsetX) || !SetWidth(width))
return false;
}
else
{
if (!SetWidth(width) || !SetOffsetX(offsetX))
return false;
}
if (GetHeight() + offsetY < GetSensorHeight())
{
if (!SetOffsetY(offsetY) || !SetHeight(height))
return false;
}
else
{
if (!SetHeight(height) || !SetOffsetY(offsetY))
return false;
}
return true;
}
public int GetWidth()
=> (int)GetPLCameraParamter(PLCamera.Width);
public int GetHeight()
=> (int)GetPLCameraParamter(PLCamera.Height);
public int GetSensorWidth()
=> (int)GetPLCameraParamter(PLCamera.SensorWidth);
public int GetSensorHeight()
=> (int)GetPLCameraParamter(PLCamera.SensorHeight);
あるいはRectを引数に取ります。WPFの場合は以下の通りです。
using Windows;
public bool SetROI(Rect roi)
=> SetROI((int)roi.X, (int)roi.Y, (int)roi.Width, (int)roi.Height);
場合によっては、ROIの大きさをそのままに、int offsetXとint offsetYを引数にとって、切り抜く位置を変えることもあります。
📈 ROIでフレームレートが上がる理由
センサからの読み出しは、通常画素数に比例して時間がかかるため、
読み出す画素数を減らすことで露光時間や保存処理の制約にかかわらずフレームレートを上げることができます。
✅ ROI設定時の注意点
| パラメータ | 注意内容 |
|---|---|
Width, Height
|
2・4・8・16などの「特定の倍数」である必要あり |
OffsetX, OffsetY
|
ROI位置を指定。センサ端を超えないよう注意 |
実装の説明でも軽く触れましたが、ROIの設定は、センサの有効範囲を超えないよう Offset → Size の順に注意して行う必要があります。
また、Baslerカメラでは、Width や Height を設定する際、
カメラ仕様によって 2・4・8・16などの「特定の倍数」である必要があります。
これはセンサーからの読み出し・画像バッファへの配置に関係するもので、GetIncrement()メソッドで確認できます。
public long GetInc(IntegerName parameter)
{
if (Camera == null || !IsConnected)
throw new InvalidOperationException("Camera is not connected.");
if (Camera.Parameters[parameter].IsReadable)
{
long inc = Camera.Parameters[parameter].GetIncrement();
Console.WriteLine($"{parameter} increment: {inc}");
return inc;
}
else
{
throw new InvalidOperationException($"{parameter} is not readable.");
}
}
WidthとHeightについて確認してみます。
acA2500-14gmは1ずつ変えられますが、モデルによってはこれが原因で思った通りの画像サイズにできずハマったりすることもあります。
[TestMethod()]
public void GetIncTest()
{
if (!_baslerCameraSample.IsConnected)
_baslerCameraSample.Connect();
// Basler acA2500-14gmは1ずつ変えられる。
var incWidth = _baslerCameraSample.GetInc(PLCamera.Width);
Assert.AreEqual(1, incWidth, "Width increment should be 1.");
var incHeight = _baslerCameraSample.GetInc(PLCamera.Height);
Assert.AreEqual(1, incHeight, "Height increment should be 1.");
}
✅ フレームレートを設定する
ROIを設定後、フレームレートを制御するには以下のようにします。
実際のフレームレートは ResultingFrameRate で確認可能です。
static BaslerCameraSample _baslerCameraSample = new BaslerCameraSample();
[TestMethod()]
public void SetROITest()
{
if (!_baslerCameraSample.IsConnected)
_baslerCameraSample.Connect();
_baslerCameraSample.EnableFrameRate(true);
_baslerCameraSample.SetFrameRate(30); // 目標値:30fps
_baslerCameraSample.SetROI(1246, 1200, 640, 480); // ROIを設定
var fps1 = _baslerCameraSample.GetResultingFrameRate();
// 5枚バーストキャプチャして撮れる画の変化を比較する。
_baslerCameraSample.BurstCapture(5, "ROITest_640x480");
_baslerCameraSample.SetROI(0, 0, 2592, 1944); // フルサイズに戻す
var fps2 = _baslerCameraSample.GetResultingFrameRate();
_baslerCameraSample.BurstCapture(5, "ROITest_2592x1944");
// ROIを設定した後のフレームレートがフルサイズよりも高いことを確認
Console.WriteLine($"FPS with ROI: {fps1:F2}, FPS without ROI: {fps2:F2}");
Assert.IsTrue(fps1 > fps2);
}
🧪 ROIとfpsの違いを比較する(実測)
下の表は、同じ対象をフル解像度とROIで撮影した連続画像です。
フル解像度では撮影間隔が長くなってしまっていますが、ROI指定をすると目標フレームレートを達成できているのがわかります。
2592 x 1944
| N | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| T[ms] | 72 | 140 | 209 | 277 | 346 |
![]() |
![]() |
![]() |
![]() |
![]() |
640 x 480
| N | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| T[ms] | 23 | 67 | 87 | 120 | 154 |
![]() |
![]() |
![]() |
![]() |
![]() |
比較
| ROI設定 | 解像度 | 実際のフレームレート |
|---|---|---|
| なし(フル) | 2,592 x 1,944 | 14.59fps |
| ROIあり | 640 x 480 | 30.00fps |
実際の値はカメラモデルにより異なります。
🧭 よくあるエラーと対処法
| エラー内容 | 原因 |
|---|---|
InvalidParameterException |
Width や OffsetX が不正(範囲外や偶数違反) |
| ROI設定後にフレームが取れない | 一部機種では ROI 後にカメラ再初期化が必要な場合も |
📝 まとめ
- ROIを使うと、画像サイズを絞って処理を高速化できる
- フレームレートの上限も向上するため、リアルタイム処理に有効
- パラメータの制約(偶数・最大値)に注意して使うと安定動作が得られる
筆者:@MilleVision









