ウェブカメラで高解像度の静止画を取得する

USB接続のウェブカメラで撮影した動画から、静止画をキャプチャして取り出す必要が有ったので調査してみた。使用する環境は下記の通り。

LOGICOOL ウェブカム HD画質 200万画素 C510

LOGICOOL ウェブカム HD画質 200万画素 C510

まず、こんな有益な情報が見つかったので早速テストしてみた。

USBカメラをWindows環境で利用するためには,主に二種類の方法があります.一つはVideo for Windowsを利用する方法,もう一つはDirect Showを利用する方法です.今回は,後者のDirectShowを利用して,C#でUSBカメラを制御する方法を紹介します.

USBカメラをC#で使おう

動作として希望のものに近くて良いのだけど、少し問題が有る。

  • 画像保存処理に失敗してしまう。
    • UI以外のスレッドからUIの状態を切り替えようとしているのが原因。.NET Framwork1.1の頃は、厳密なチェックが行われていなかったのでこれでも良かったのだけど、今はチェックが厳しいので例外になってしまう。この辺りは、下記のようなコードを追加して非UIスレッド以外から呼び出されたら、UIスレッドから再度呼び直せば良い。
if (InvokeRequired)
{
    Invoke((MethodInvoker)delegate()
    {
            this.ChangeGuiMode(mode);
    });
    return;
}
  • 画像解像度が低い。
    • ウェブカメラのデフォルト値(?)である640x480ピクセルで撮影しているようだけど、カメラのハードウェア上のスペックは720pなのでもっと高い。出来れば、この解像度で撮影出来ないものだろうか?

次に試したのがこちら。DirectShowの.NET向けラッパーらしい。

The purpose of this library is to allow access to Microsoft's DirectShow functionality from within .NET applications. This library supports both Visual Basic .NET and C#, and theoretically, should work with any .NET language.

DirectShowNet library

サンプルも豊富に用意されており、下記のソフトが希望の動作に近いようだ。

DxSnap – Use DirectShow to take snapshots from the Still pin of a capture device. Note the MS encourages you to use WIA for this, but if you want to do in with DirectShow and C#, here's how.

DirectShowNet library

コードの内容を確認し、カメラの解像度を設定するところで1280x720のHDサイズを指定したら、正常に動作した。

const int VIDEOWIDTH = 1280; // Depends on video device caps
const int VIDEOHEIGHT = 720; // Depends on video device caps

cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, pictureBox2);

機能的には当初の目標を達成出来るので良いのだけど、惜しいことに、このソフトを64bitのWindows7で起動させると例外が発生してしまう。

System.Runtime.InteropServices.COMException はハンドルされませんでした。
  Message="接続に必要な中間フィルターの組み合わせが見つかりませんでした。 "
  Source="DirectShowLib-2005"
  ErrorCode=-2147220969
  StackTrace:
       場所 DirectShowLib.DsError.ThrowExceptionForHR(Int32 hr)
       場所 SnapShot.Capture.SetupGraph(DsDevice dev, Int32 iWidth, Int32 iHeight, Int16 iBPP, Control hControl) 場所 C:\Users\Foo\Desktop\DxSnap\DxSnap\Capture.cs:行 311
       ...

DirectShow関連の問題らしいのでややこしい。困っていたら、下記のサンプルを見つけた。

C# sample code demonstrating control of a high resolution webcam (Quickcam Pro 9000) with DirectShow

http://sites.google.com/site/thomasnaiser/software

同じDirectShowLib-2005.dllを使っているけれど、こちらは32bit環境だけではなく、64bit環境でも正常に動作した。上記のフィルタの問題を上手くクリアしているようだ。720pのサイズで静止画も取得出来るし、素晴らしい。

コードではインデックス0のカメラを使うようになっているので、利用可能なデバイスをリストアップするには下記のように列挙すればよい。

private void frmTest_Load_1(object sender, EventArgs e)
{
    foreach (DsDevice ds in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))
    {
        this.cbxCameraDevice.Items.Add(ds.Name);
    }
    if (this.cbxCameraDevice.Items.Count > 0)
    {
        this.cbxCameraDevice.SelectedIndex = 0;
    }
}       

なお、Windows 7MacOS X上のVMware fusionで稼働させていると、MacBook Proに付いているFaceTime HDカメラでも動作する*1。仮想環境で動いているOSから、このようなデバイスも正常に動作するのは凄い仕組みだと思う。

*1:但し、BrightnessとGainの設定で例外が出るので、コードの変更が必要。