2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WPFアプリでBaslerカメラの静止画を表示する【pylon SDK / C# / .NET 8】

Posted at

WPFアプリでBaslerカメラの静止画を表示する【pylon SDK / C# / .NET 8】

「コードは動くけど、GUIでプレビューできるところまで一気に行きたい」。
本記事はその最初の一歩として、WPF で “Connect / Disconnect / Snap” を備えた最小ビューアを作ります。
ボタンを押すだけで1枚撮影し、画面の Image に表示されるところまでを丁寧に解説します。

実行例


ゴール

  • Connect / Disconnect / Snap の3ボタンで操作できる
  • Snap で取得した1枚を Image に表示
  • 終了時に確実に切断・解放(リソースリーク防止)

構成

これまでの記事で作成した BaslerCameraSample(クラスライブラリ)Basler pylon SDKでソフトウェアトリガー撮影を行う(C# / .NET対応))をそのまま使い、
新しく WPF アプリ BaslerGUISample を追加して参照に設定します。


View(XAML)

3つのボタンとプレビュー用 Image を並べます。

<Window x:Class="BaslerGUISample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BaslerGUISample"
        mc:Ignorable="d"
        Title="BaslerGUISample" Height="450" Width="450" Closing="Window_Closing">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Grid Grid.Row="0" Grid.Column="0">
      <Button Content="Connect" Width="80" Margin="4,0" Command="{Binding ConnectCommand}"/>
    </Grid>
    <Grid Grid.Row="0" Grid.Column="1">
      <Button Content="Disconnect" Width="80" Margin="4,0" Command="{Binding DisconnectCommand}"/>
    </Grid>
    <Grid Grid.Row="0" Grid.Column="2">
      <Button Content="Snap" Width="80" Margin="4,0" Command="{Binding SnapCommand}"/>
    </Grid>

    <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3">
      <Image x:Name="PreviewImage" Source="{Binding CurrentFrame}" Stretch="UniformToFill"/>
    </Grid>
  </Grid>
</Window>

XAMLデザイナ上での見た目は次の通り。

XAML配置

コードビハインド側では DataContext = new MainViewModel(); を設定し、
Window_Closing で必ず切断するようにします(後述)。


ViewModel

  • BindableBase / DelegateCommand は任意の実装でOK(本稿では中身は省略)
  • これまで作ってきた BaslerCameraSample を使って接続・撮影・切断
  • CurrentFrameBitmapSource)を Image.Source にバインド
  • 接続時にUIが固まるようなら、Connectの非同期化も検討
using BaslerSamples;
// 筆者は`BindableBase`、`DelegateCommand`を`Common`で実装しています。
// お使いの環境に合わせて実装してください。
// using Common; 
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Imaging;

namespace BaslerGUISample.ViewModels
{
    public partial class MainViewModel : BindableBase
    {
        private readonly BaslerCameraSample _cameraService = new();

        public MainViewModel()
        {
            ConnectCommand    = new DelegateCommand(Connect,    () => !IsConnected);
            DisconnectCommand = new DelegateCommand(Disconnect, () =>  IsConnected);
            SnapCommand       = new DelegateCommand(Snap,       () =>  IsConnected);

            Connect(); // 起動時に自動接続する場合はここで
        }

        private bool _isConnected;
        public bool IsConnected
        {
            get => _isConnected;
            set
            {
                SetProperty(ref _isConnected, value);
            }
        }

        private BitmapSource? _currentFrame;
        public BitmapSource? CurrentFrame
        {
            get => _currentFrame;
            set => SetProperty(ref _currentFrame, value);
        }

        public DelegateCommand ConnectCommand    { get; }
        public DelegateCommand DisconnectCommand { get; }
        public DelegateCommand SnapCommand       { get; }

        public void Connect()
        {
            IsConnected = _cameraService.Connect();
        }

        /// <summary>
        /// カメラ接続を切断します。
        /// </summary>
        public void Disconnect()
        {
            _cameraService.Disconnect();
            IsConnected = _cameraService.IsConnected;
        }

        public void Snap()
        {
            try
            {
                CurrentFrame = _cameraService.SnapToBitmapSource();
            }
            catch (InvalidOperationException ex)
            {
                // カメラ未接続時にメッセージボックスを表示。
                MessageBox.Show($"Failed to snap. Error: {ex.Message}");
            }
        }
    }
}

(参考)MainWindow のコードビハインド

public partial class MainWindow : Window
{
    private readonly MainViewModel _viewModel;

    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new MainViewModel();
        DataContext = _viewModel;
    }

    /// <summary>
    /// ウィンドウが閉じられる前にカメラ接続を切断します。 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        _viewModel.Disconnect();
    }

BaslerCameraSample に切断機能を追加

これまで接続中心だったので、確実に解放する Disconnect() を用意し、アプリ終了時に呼び出します。

public void Disconnect()
{
    if (Camera != null)
    {
        if (IsGrabbing) StopGrabbing();
        if (Camera.IsOpen) Camera.Close();

        Camera.Dispose();
        Camera = null;
        Console.WriteLine("Camera disconnected.");
    }
}

実装のポイント / よくあるハマりどころ

  • UIスレッド更新
    連続撮影(イベント駆動)に進むと、UIが固まらないようにするため、ImageGrabbed は別スレッドで発火します。
    その場合は Application.Current.Dispatcher.Invoke などで UIスレッドに戻して CurrentFrame を更新 してください(次回以降で実装予定)

  • Stretch の違い
    UniformToFill は余白なく表示・一部トリミングあり、Uniform は全体表示・余白あり。用途に合わせて選択

  • 例外の扱い
    接続や撮影に失敗した場合は、MessageBox などでユーザーに分かる形で通知すると親切


まとめ

  • WPF の 最小ビューア(Connect / Disconnect / Snap / 画像表示)を実装した
  • MVVM で View と制御ロジックを分離Image.SourceBitmapSource をバインド
  • 終了時の Disconnect() でリソースを確実に解放
  • 連続撮影やイベント駆動表示へ進む下地が整った(次回以降で発展)

次回予告

次の記事では、イベント駆動で連続取得しながらUIを非同期更新する方法を解説します。
キュー+非同期保存や OpenCV 表示とも連携し、実務投入できるビューアへ発展させます。


👨‍💻 筆者について

@MilleVision
産業用カメラ・画像処理システムの開発に関する情報を発信中。
pylon SDK × C# の活用シリーズを連載しています。


🛠 サンプルコード完全版のご案内

Qiita記事のサンプルをまとめた C#プロジェクト(単体テスト付き) を BOOTH で配布しています。
本記事で省略した BindableBaseDelegateCommand の実装も同梱。

  • 撮影・露光・ゲイン・フレームレート・ROI・イベント駆動撮影など主要機能を網羅
  • 単体テスト同梱で動作確認や学習がスムーズ
  • 記事更新に合わせてアップデート予定

👉 商品ページはこちら

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?