Windows ネイティブ アプリケーションにおいて、USB 接続のカメラなどから画像をキャプチャして、ピクセルデータを取得するためのメモ。
背景
以前に作った CUDGlass を久々に起動してみたところ、USB カメラを画像ソースにするキャプチャ機能が動作しなくなっていました
…さすがにもう 10 年前のシロモノなので、画像処理関係が大幅に変わってしまっている様子ですが、検索してみたところやたら COM バリバリのサンプル コードばかりで、理解するのが大変でした。
ひとまず、USB 接続のカメラからキャプチャした画像をビットマップ形式でファイル保存するところまで進めたので、そこに至るまでのステップを覚書きとして公開します。
ソースコード
上から順にコードを付け足していったので、差分を見て頂ければ、何がどう変わったのか追いかけやすいと思います。
- 01. EnumDevice
-
接続されたビデオ入力デバイスを列挙するところまでで、スタートが「COM ってなんじゃらホイ?」からだったので練習も兼ねて。
System Device Enumerator を取得して、VideoInputDeviceCategory カテゴリの列挙子を取得して、そこからモニカを列挙する、という手順になります。更に、取得したモニカからデバイス名を取得するには、BindToStorage でオブジェクトが格納されているストレージへのインターフェイス ポインタを取得して、名前が VARIANT 型のために printf
一発で済まないだとか。まぁ、慣れるまでは(今でも)よく判りません。CoCreateInstance
などで生成したインスタンスは、使わなくなったら忘れずに Release
しましょう。
- 02. Capture
-
一つ目に列挙されたデバイスから画像をキャプチャして、ウィンドゥに表示するところまで。試しに複数台の USB カメラを接続して試してみましたが動いているよ
うです。またここで新しい概念(?)が登場しており、動画や音声は「フィルタ グラフ」で管理するということ。「フィルタ」とは、入力・出力ピンを持つブロックのようなもので、画像を取り込むカメラ「フィルタ」の出力ピンを、画面に出力するキャプチャ「フィルタ」の入力ピンに繋いでやる、という感じです。動画が MPEG ストリームなどであれば、途中に動画をデコードする変換「フィルタ」を挟んでやることになります。でもって、これら複数の「フィルタ」の繋がりを管理しているのが「フィルタ グラフ」ということでしょうか?
カメラ デバイスのモニカをフィルタに BindToObject
して、フィルタ グラフ(CLSID_FilterGraph) を作って、フィルタ グラフにフィルタを AddFilter
して…、とまぁ大変です。その後、キャプチャ グラフだとか、IAMStreamConfig
だとか出てきてしっかり理解できておらず、参考にしたサンプル コードそのままだったりします。
- 03. SaveBitmap
-
キャプチャした画像のビットマップを得るには、Sample Grabber Filterを利用するとのこと。Sample Grabber Filter とは、入力ピンからのデータ(サンプル)をそのまま出力ピンに渡す変換フィルタで、これをカメラとキャプチャ表示ウィンドゥの間に差し込んでやると、そこを流れるデータを横取りできるようになるわけです。
CoCreateInstance
で Sampling 用のフィルタを生成して、フィルタの画像フォーマットを設定してから、フィルタ グラフに追加します。これらのフィルタをどのように、どんな順番で接続するのか明示はしていませんが、そのあたりは CaptureGraphBuilder2
が良しなにやってくれるとのこと。
pSampleGrabber->GetCurrentBuffer で画像データを取得できるので、その後、BITMAPFILEHEADER
構造体などを適切に設定してから、確認のためにビットマップ画像ファイルとして書き出しています。
いろいろ