Basler pylon × WPF:ビニングGUIを最小実装する(1×1 / 2×2 切替、解像度追従)
導入
前回はビニングの仕組みと効果(S/N・FPS) をコード中心に確認しました。
組み込み装置は画面にカメラのライブビューが映っているだけで、安心感が増すものです。常にフル解像度で使うのではなく、画面表示用に普段はビニングで解像度を落とし処理の負荷を下げ、何かの計測時にフル解像度へ戻すことも、ときにはあるかと思います。
このように、通常はアプリ内部で自動制御する場合でも、現場で即座に切り替えたい動機はあります。例えば、"何か"あったとき にオペレータから解像度を手動で上げたいという要望がきます。逆に、動作確認時に効率化のため、解像度を下げたいときもあるかと思います。
そのような場合に、オペレータがワンクリックで 1×1 / 2×2 のようにビニングを切り替えられるGUIがあれば、評価や開発のスピードも向上します。
ゴール
- ボタン1クリックで Binning 1×1 / 2×2 を切替
- 非対応機では自動的にスイッチ無効化
- 現在の 解像度とBinning値 を常時表示
使用環境 / 前提
- Basler pylon Camera Software Suite(
Basler.Pylon参照済み) - .NET 8 / WPF(Windowsデスクトップ)
- カメラ:acA2500-14gm(Mono8想定)
コード
これまでの内容に追加で実装していきます。
Baslerカメラ × pylon SDK 制御シリーズまとめ
設計の方針は「停止→設定→ROIフル戻し→再開」といったビニングの設定をカメラクラス側で吸収し、GUIは状態に応じたボタン活性制御とサイズ追従のFit呼び出しに専念できるよう分離します。これにより、UIの変更だけでなく、機種差に強い実装となります。
XAML(ツールバー最小)
既存のImage+HUDのレイアウトはそのまま。
Gridを1行追加し、上段に切り替えボタンを設けます。
実装が増えてきたので適宜省略します。直近のXAMLの記事はこちらです。(WPF × Basler pylon SDKで背景差分(動体検出)を実装する)
<Grid Grid.Row="3" Grid.Column="0">
<Button x:Name="SetBinning11Button" Content="Binning 1x1" Width="80" Margin="0,5"
Command="{Binding SetBinningCommand}"
CommandParameter="1,1"/>
</Grid>
<Grid Grid.Row="3" Grid.Column="1">
<Button x:Name="SetBinning22Button" Content="Binning 2x2" Width="80" Margin="0,5"
Command="{Binding SetBinningCommand}"
CommandParameter="2,2"/>
</Grid>
<Grid Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Resolution:" VerticalAlignment="Center"/>
<TextBlock Text="{Binding ResolutionLabel}" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
<Grid Grid.Row="3" Grid.Column="4">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Binning:" VerticalAlignment="Center"/>
<TextBlock Text="{Binding BinningLabel}" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
ついでに現在のステータスを表示させるラベルも画像のGridの下に追加しておきます。
<Grid Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="5" Background="#e9ecef">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding StatusMessage}" Margin="6,0,0,0" VerticalAlignment="Center" Opacity="0.8"/>
</StackPanel>
</Grid>
デザイナのレイアウトは以下のようになります。
ViewModel(最小:コマンドと表示)
MVVMでコマンドを実装していきます。
public sealed class MainViewModel : BindableBase
{
BaslerCameraSample _cameraService = new BaslerCameraSample();
private string _statusMessage = "";
private string _resolutionLabel = "—";
private string _binningLabel = "—";
/// <summary>
/// ビューモデルの初期化を行います。
/// コマンドの生成や初期表示用の各種状態を設定します。
/// </summary>
public MainViewModel()
{
// 他のコマンドは省略。
SetBinningCommand = new DelegateCommand<string>((param) =>
{
try
{
// "2,2" のような形式で引数を受け取る
var parts = (param ?? "1,1").Split(',');
if (parts.Length != 2 || !int.TryParse(parts[0], out var h) || !int.TryParse(parts[1], out var v))
{
StatusMessage = "Invalid binning parameter. Use \"H,V\" (e.g., \"2,2\").";
return;
}
SetBinning(h, v);
}
catch (Exception ex)
{
StatusMessage = $"Error setting binning: {ex.Message}";
}
}, (_) => CanChangeBinning);
}
/// <summary>
/// 操作結果やエラー内容など、状態通知のためのメッセージを表します。
/// </summary>
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
/// <summary>
/// 現在の解像度(幅×高さ)を表示用の文字列として提供します。
/// 未接続時は空表示になります。
/// </summary>
public string ResolutionLabel
{
get => _resolutionLabel;
private set => SetProperty(ref _resolutionLabel, value);
}
/// <summary>
/// 現在のビニング設定(H×V)を表示用の文字列として提供します。
/// 取得できない場合は空表示になります。
/// </summary>
public string BinningLabel
{
get => _binningLabel;
private set => SetProperty(ref _binningLabel, value);
}
/// <summary>
/// ビニング設定が変更可能かどうかを示します。
/// </summary>
/// <returns></returns>
public bool CanChangeBinning
=> _cameraService.IsConnected && !_cameraService.IsGrabbing && _cameraService.IsBinningSupported();
/// <summary>
/// ビニング設定を変更するコマンドを示します。
/// </summary>
/// <value></value>
public DelegateCommand<string> SetBinningCommand { get; }
/// <summary>
/// ビニングを設定します。
/// </summary>
/// <param name="h"></param>
/// <param name="v"></param>
private void SetBinning(int h, int v)
{
if (_cameraService.SetBinning(h, v))
{
StatusMessage = $"Binning set: {h}×{v}";
}
else
{
StatusMessage = $"Failed to set binning: {h}×{v}";
}
UpdateResolutionLabel();
UpdateBinningLabel();
}
/// <summary>
/// カメラの現在の解像度を取得して ResolutionLabel を更新します(未接続時は空)。
/// </summary>
private void UpdateResolutionLabel()
{
if (_cameraService?.IsConnected == true)
ResolutionLabel = $"{_cameraService.GetWidth()} × {_cameraService.GetHeight()}";
else
ResolutionLabel = "—";
}
/// <summary>
/// カメラの現在のビニング値を取得して BinningLabel を更新します(取得不可時は空)。
/// </summary>
private void UpdateBinningLabel()
{
var b = _cameraService?.GetBinning();
BinningLabel = (b is { H: > 0, V: > 0 }) ? $"{b.Value.H} × {b.Value.V}" : "—";
}
}
省略が増えてきて、コードの抜き出しに失敗していないか心配です。
設計メモ
-
切替は 1×1 / 2×2 のみ:実務ではこの2択で多くの用途をカバーできます。ただし、
ComboBoxで実装した方が拡張性は高いです -
非対応機のUI無効化:
CanChangeBinning(接続済・停止中・対応機)で制御しました -
安全側の一時停止:
SetBinning内部で停止→設定→ROIフル戻し→再開を前回記事で実装しました。これはVM側では意識しない“ファサード”となります
実行例
-
Connect→Start→ライブ表示 -
Stop→Binning 2×2→Start- 解像度ラベルが 2592×1944 → 1296×972 に変わる
-
Stop→Binning 1×1に戻す→サイズ/表示が復帰 - 非対応機でボタンが無効化される(
IsBinningSupported=false)
| 1x1 | 2x2 |
|---|---|
![]() |
![]() |
まとめ
- 1×1/2×2の簡易切り替えGUIを実装
- 非対応はボタン無効化
👨💻 筆者について
@MilleVision
産業用カメラ・画像処理システムの開発に関する情報を発信中。
pylon SDK × C# の活用シリーズを連載しています。
🛠 サンプルコード完全版のご案内
Qiita記事のサンプルをまとめた C#プロジェクト(単体テスト付き) を BOOTH で配布しています。
本記事で省略した BindableBase や DelegateCommand の実装も同梱。
- 撮影・露光・ゲイン・フレームレート・ROI・イベント駆動撮影など主要機能を網羅
- WPFへの実装もフォロー
- 単体テスト同梱で動作確認や学習がスムーズ
- 記事更新に合わせてアップデート予定
- 記事投稿後の加筆修正あり


