A certain engineer "COMPLEX"

.NETで画像処理を試してみる OpenCVSharp編 第3回

前回は顔認識における前処理の説明を行いました。

Introduction


前回、さりげなく、というかさらっとカメラを使っていたので、カメラの使い方を説明します。

OpenCVSharp はカメラも簡単に使えます。
複数のカメラを接続して切り替えることも可能です。

Explanation


ソースコード

説明するよりソースコードを見た方が早いです。
サンプルソースは末尾にあります。


public class MainViewModel : ViewModelBase
{

#region フィールド

private IDisposable _CaptureHandler;

private CvCapture _CvCapture;

#endregion

#region コンストラクタ

public MainViewModel()
{
this.CameraIndex = 0;
}

#endregion

#region プロパティ

private BitmapSource _CameraImage;

public BitmapSource CameraImage
{
get
{
return this._CameraImage;
}
set
{
this._CameraImage = value;
this.RaisePropertyChanged();
}
}

private int _CameraIndex;

public int CameraIndex
{
get
{
return this._CameraIndex;
}
set
{
this._CameraIndex = value;
this.RaisePropertyChanged();

this.ExecuteStart();
}
}

#endregion

#region メソッド

#region ヘルパーメソッド

private CvCapture CreateCvCapture()
{
CvCapture cvCapture = null;

try
{
cvCapture = new CvCapture(this.CameraIndex);
}
catch (Exception)
{
// ignore
}

return cvCapture;
}

private void ExecuteStart()
{
this.ExecuteStop();

this._CvCapture = this.CreateCvCapture();
if (this._CvCapture == null)
{
return;
}

var ms = 60;
this._CaptureHandler = Observable.Interval(TimeSpan.FromMilliseconds(ms), DispatcherScheduler.Current)
.Select(_ =>
{
if (this._CvCapture == null)
{
return null;
}

return Cv.QueryFrame(this._CvCapture);
})
.Where(frame => frame != null)
.Subscribe(frame =>
{
var writeableBitmap = frame.ToWriteableBitmap();
frame.Dispose();
this.CameraImage = writeableBitmap;
});
}

private void ExecuteStop()
{
if (this._CvCapture != null)
{
this._CvCapture.Dispose();
this._CvCapture = null;
}

if (this._CaptureHandler != null)
{
this._CaptureHandler.Dispose();
this._CaptureHandler = null;
}
}

#endregion

#endregion

}

CameraImage プロパティ

XAMLのViewとバインディングされており、ここが変化するとカメラ映像が行進されます。

CameraIndex プロパティ

XAMLのViewとバインディングされており、ここが変化するとカメラが切り替わります。
基本は0以上の整数値です。
カメラに対応していない数値が設定されると、 CvCapture のコンストラクタで例外を投げて、その後の処理でカメラの処理が自動で停止します。

ExecuteStart メソッド

CameraIndex プロパティの変更で呼ばれます。
まずは既存のカメラを停止させます。
次に、Reactive ExtensionsSystem.Reactive.Linq.Observable.Interval メソッド を使い指定した間隔でカメラ映像の取得を試みます。
OpenCVSharp.Cv.QueryFrame メソッドに作成した CvCapture のインスタンスを渡すことで、OpenCVSharp.IplImage オブジェクトを返します。
あとは、次々の発生する IplImage を Where でフィルタして、CameraImage プロパティ設定します。

Reactive Extensions 利用のアイデアはkattoshi様のRx と OpenCVSharp を使用して 簡単にカメラキャプチャアプリを作成する を参考にさせていただきました。
ありがとうございます。

重要なのは2つ。

まず、Interval メソッドの最後の引数は現在のスレッドの System.Windows.Threading.Dispatcher を渡します。
これにより、Viewに対する更新が自動的にバックグランドで実行されます。

次に、Subscribe メソッドの戻りをクラスメンバーに保持しておくことです。
この戻りは System.IDisposable インターフェイスです。
これを破棄することで、Interval メソッドによるイベントの発生が停止します。

ExecuteStop メソッド

CvCapture オブジェクトとSubscribe メソッドの戻りを破棄し、カメラを停止させます。

動作イメージ

サンプルには、MVVM Light ToolkitMahApps.Metro を使っています。
味気ないデフォルトウィンドウ以外を使うだけで、なんかかっこよく見えます。
これ大事。

Conclusion


OpenCVSharpを使えば、カメラも簡単に使えます。やったね。本当に。

Source Code


https://github.com/takuya-takeuchi/Demo/tree/master/OpenCV3

コメントを残す

メールアドレスが公開されることはありません。

%d人のブロガーが「いいね」をつけました。