Baslerカメラ画像をOpenCVで表示・保存する【pylon SDK × OpenCvSharp / C#】
Baslerカメラの画像を取得して処理したいとき、
OpenCVの Mat
形式に変換できると画像処理の幅が一気に広がります。
この記事では、pylon SDKで得た GrabResult
から
OpenCVの Mat
に変換し、リアルタイム表示 (Cv2.ImShow
) と保存 (Cv2.ImWrite
) を行う方法を紹介します。
✅ 使用環境
項目 | 内容 |
---|---|
カメラ | Basler acA2500-14gm |
SDK | pylon Camera Software Suite |
画像形式 | Mono8(8bitグレースケール) |
OpenCVラッパー | OpenCvSharp4.Windows(NuGet) |
🎯 目的:GrabResult → Mat に変換して表示・保存
イメージ図:
[GrabResult] → [byte[]] → [Mat] → [ImShow / ImWrite]
🔧 GrabResult から Mat を作るコード
PixelDataConverter
クラスのConvert()
メソッドを用いて、IGrabResult
をbyte[]
に変換します。
その後、byte[]
を引数にMat
をインスタンス化します。
実装する際は以下のようなIGrabResult
の拡張メソッドを作っておくと使いやすいです。
using Basler.Pylon;
using OpenCvSharp;
namespace BaslerSamples
{
public static class IGrabResultExtensions
{
public static Mat ToMat(this IGrabResult result)
{
if (!result.GrabSucceeded)
throw new InvalidOperationException("Grab failed");
var converter = new PixelDataConverter
{
OutputPixelFormat = PixelType.Mono8
};
int width = result.Width;
int height = result.Height;
byte[] buffer = new byte[width * height];
converter.Convert(buffer, result);
// OpenCVのMatに変換(Gray8 → CV_8UC1)
var handle = System.Runtime.InteropServices.GCHandle.Alloc(buffer, System.Runtime.InteropServices.GCHandleType.Pinned);
try
{
IntPtr ptr = handle.AddrOfPinnedObject();
// ※ Mat.FromPixelData() は OpenCvSharp の拡張メソッドで、バイト配列から Mat を生成できます。
return Mat.FromPixelData(height, width, MatType.CV_8UC1, ptr);
}
finally
{
handle.Free();
}
}
}
}
🖼️ ImShowでリアルタイム表示
今回も前回記事(Baslerカメラの画像取得をイベント駆動+非同期保存で安定化する)で紹介したBaslerCameraSample
クラスに、機能を追加していきます。
前回はバッファに貯めた画像を非同期で保存しましたが、今回は表示させてみます。
using OpenCvSharp;
public async Task ShowBufferedImages(CancellationTokenSource cts)
{
// キューが空になるまで、またはキャンセル要求があるまでループします。
// 撮影中はキューに追加される可能性があるため、ループを続けます。
while (!cts.IsCancellationRequested && (IsGrabbing || _bufferedImageQueue.Count > 0))
{
if (_bufferedImageQueue.TryDequeue(out var item))
{
using (Mat mat = item.Item2.ToMat())
{
Cv2.ImShow("Camera", mat);
Cv2.WaitKey(1); // 0だとブロックするので1ミリ秒待機
}
}
else
{
await Task.Delay(1); // 空ループ対策
}
}
// キューをクリア(次のStartGrabbingで実行する実装でもよい)
_bufferedImageQueue.Clear();
}
実行例
テストコードは以下のようになります。前回とほとんど同じですね。
[TestMethod()]
public async Task ShowBufferedImagesTest()
{
if (!_baslerCameraSample.IsConnected)
_baslerCameraSample.Connect();
Task? showTask = null;
try
{
_baslerCameraSample.StartGrabbing();
Assert.IsTrue(_baslerCameraSample.IsGrabbing, "Camera should be grabbing after StartGrabbing is called.");
// 撮影開始後に画像を表示するタスクを開始する。
// 保存をキャンセルしたい場合は、cts.Cancel()を呼び出します。
var cts = new CancellationTokenSource();
showTask = _baslerCameraSample.ShowBufferedImages(cts);
await Task.Delay(10000); // 10秒間連続撮影し、画像を表示する
}
catch (InvalidOperationException ex)
{
Assert.Fail($"StartGrabbing failed: {ex.Message}");
}
finally
{
// StopGrabbingを呼び出して、グラブを停止する。
_baslerCameraSample.StopGrabbing();
Assert.IsFalse(_baslerCameraSample.IsGrabbing, "Camera should not be grabbing after StopGrabbing is called.");
if (showTask is not null)
await showTask; // 保存タスクが完了するのを待つ
}
}
実行すると以下の画像のようにCamera
というウィンドウにカメラのライブ画像が表示されます。
💾 ImWriteでファイル保存 ― Matを画像として保存するには?
Mat
の画像を保存するにはImWrite()
メソッドを使用します。
以下はSnap()
で1枚画像を取得してMat
に変換し、画像処理を加えて保存するサンプルコードです。
[TestMethod]
public void SnapAndSaveMatTest()
{
if (!_baslerCameraSample.IsConnected)
_baslerCameraSample.Connect();
var result = _baslerCameraSample.Snap(1000);
using (var mat = result.ToMat())
{
Assert.IsNotNull(mat);
// 画像を保存
mat.ImWrite("SnapAndSaveMatTest_Mat.bmp");
// 試しに2値化処理する。
Cv2.Threshold(mat, mat, 128, 255, ThresholdTypes.Binary);
mat.ImWrite("SnapAndSaveMatTest_Mat_Thresholded.bmp");
Assert.IsTrue(System.IO.File.Exists("SnapAndSaveMatTest_Mat.bmp"));
}
// 比較のため、BitmapSourceでも保存してみる。
var bitmap = _baslerCameraSample.ConvertGrabResultToBitmap(result);
BaslerCameraSample.SaveBitmap(bitmap, "SnapAndSaveMatTest_Bitmap.bmp");
Assert.IsNotNull(result);
}
サンプルを実行すると以下の3枚画像が保存されます。
-
BitmapSource
に変換した後で保存した画像 -
ImWrite()
で保存した画像 -
Cv2.Threshold()
で生成した2値化画像
比較してみると、BitmapSource
とMat
で同じ画像が保存できていることがわかります。
BitmapSource | Mat | Mat(2値化) |
---|---|---|
![]() |
![]() |
![]() |
📌 注意点とハマりポイント
カメラの種類に応じて、MatTypeを変える必要があります。また、ImShow()
で動作確認する場合はWaitKey()
を入れ忘れないようにしてください。
注意点 | 内容 |
---|---|
PixelFormatがRGB/BGRの場合 | MatTypeを CV_8UC3 にする必要あり |
カラー画像で表示がずれる | RGB/BGR順の変換が必要な場合あり |
WaitKey() を忘れると表示されない |
必ず呼ぶ必要あり |
NuGetでOpenCvSharpを導入 |
OpenCvSharp4 , OpenCvSharp4.runtime.windows を併用 |
✅ まとめ
-
GrabResult
からbyte[]
を取得し、OpenCVのMat
に変換できる -
Cv2.ImShow
でリアルタイム表示、Cv2.ImWrite
で保存可能 - 今後、OpenCVによるフィルタ処理や輪郭抽出などにも展開しやすい
筆者:@MilleVision