SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

OpenCvSharpでWebカメラ画像のキャプチャ

今度は、Webカメラから画像をキャプチャしてWPFのウィンドウに表示してみました。
前回の動画再生とほとんど同じです。

カメラデバイスの準備

前回も使ったCvCaptureクラスですが、コンストラクタに数値でIDを渡すと、そのIDで指定されたデバイスに対するCvCaptureクラスのインスタンスが作成されます。

var capture = new CvCapture(0)

このようにして作成したCvCaptureインスタンスのQueryFrameを呼ぶと、カメラから次のフレームが取得されるまで処理が止まるので、Task.Delayなどでの待機処理は入れていません。

f:id:minami_SC:20141005214642j:plain:w300

MainWindow.xaml
<Window x:Class="OpenCVSharpTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350" Loaded="Window_Loaded">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Image x:Name="imgResult"
               Margin="10" />
    </Grid>
</Window>
MainWindow.xaml.cs
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Window_Loaded(object sender, RoutedEventArgs e)
        {
            await CaptureAsync();
        }

        private WriteableBitmap wb;
        private async Task CaptureAsync()
        {
            using (var capture = new CvCapture(0))
            {
                // キャプチャした画像のコピー先となるWriteableBitmapを作成
                wb = new WriteableBitmap(capture.FrameWidth, capture.FrameHeight, 96, 96, PixelFormats.Bgr24, null);
                while (true)
                {
                    // フレーム画像を非同期に取得
                    var image = await QueryFrameAsync(capture);
                    if (image == null) break;

                    WriteableBitmapConverter.ToWriteableBitmap(image, wb);
                    imgResult.Source = wb;
                }
            }
        }

        private async Task<IplImage> QueryFrameAsync(CvCapture capture)
        {
            // awaitできる形で、非同期にフレームの取得を行います。
            return await Task.Run(() =>
                {
                    return capture.QueryFrame();
                });
        }
    }