仮想Webカメラでウェブ画面をOpenCVで認識させるまでのメモ

##一番良いのはVisualStudio2010でコンパイルすることなのか？
詳しく分からないが、VisualStudio2015でコンパイルするとReleaseがコンパイルできない状態に陥ったりした。
この原因としてはWindowsランタイムが更新されているかららしい。
VisualStudio2010でBaseClassesやPushSouceFilterをコンパイルするとあっさりとコンパイルできる。
なのでここでは**VisualStudio2010**を用いて**PushSouceFilterのライブラリファイル**を作成することにする。

ランタイムとやらが新しいバージョンと古いバージョンでコンパイルしてライブラリファイルを作った場合に、その後にVisualStudio2015などでそのライブラリファイルを利用する時にどう影響するのか？
.libファイルにしてしまえばランタイムの新しい古いは関係ないのか？
知識がなくて不明なのでここは調べる必要あり。

#まずはVisualStudio2010を手に入れる
[VISUAL STUDIO 2010 EXPRESSと旧版のダウンロード先まとめ　http://wolfish.org/blog/p2010042901/](http://wolfish.org/blog/p2010042901/)というサイトからVisual Studio 2010 Expressをまずダウンロードする。
これを使ってコンパイルまでするのが一番確実。ダウンロードできたらVisualC++2010 Expressを選択。
Microsoft SilverlightとかMicroSoft SQL Server 2008 Express Service Pack1(x64)とかはインストールオプションでチェックを外す。
インストールするファイルは以下のとおり。
![VisualStudio2010download.png](https://qiita-image-store.s3.amazonaws.com/0/139645/85a39399-8e9f-cd1d-95c4-6b6564781eeb.png)
![VisualStudio2010download2.png](https://qiita-image-store.s3.amazonaws.com/0/139645/2c970f83-5f08-0654-770d-16bae46383eb.png)

#次にSDKversion7.1を手に入れる
VisualStudio2015Communityとかが入ってるとダウンロードができないことがある。面倒だがアンインストールするなりして、これはどうにかするしかない。VisualStudio2015だとReleaseでエラーが出た。

ダウンロード先は[Microsoft Windows SDK for Windows 7 and .NET Framework 4
　https://www.microsoft.com/en-us/download/details.aspx?id=8279](https://www.microsoft.com/en-us/download/details.aspx?id=8279)

Redistributable PackagesのMicrosoftVisualC++はまずは、インストールしないでおく。
・**Samples**と・**Windows Headers and Libraries**に☑を入れる。
※画像と違うので注意。Redistributable PackagesのMicrosoft Visual C++ 2010をインストールしてしまうと、Windows SDK 7.1 用 Microsoft Visual C++ 2010 Service Pack 1 コンパイラ更新プログラムがインストールできなくなる可能性があるので注意。
![SDKinstall.png](https://qiita-image-store.s3.amazonaws.com/0/139645/0a0b73f5-953a-c28c-d7a1-fd20d2d3c505.png)

ここで、C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshowにbaseclassesというフォルダがあり（これがDirectShowのベースとなるDLLを作る元）、C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\filtersにpushsourceというフォルダ（これががデスクトップキャプチャをするPushSourceDesktop.cppの存在場所）あることを確認する。

#Windows SDK 7.1 用 Microsoft Visual C++ 2010 Service Pack 1 コンパイラ更新プログラムをインストール
これをインストールしないと、コンパイルするときにx64でコンパイルができない。
[Windows SDK 7.1 用 Microsoft Visual C++ 2010 Service Pack 1 コンパイラ更新プログラム https://www.microsoft.com/ja-jp/download/details.aspx?id=4422](https://www.microsoft.com/ja-jp/download/details.aspx?id=4422)をダウンロードしてインストール。

#まずはbaseclasses.slnのコンパイル
##x64でコンパイルするために追加のライブラリディレクトリにアドレスを追加
C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclassesの中のbaseclasses.slnをVisualStudio2010で開く。
変換が必要ですとの注意がでるが、OKでバックアップを取って進む。

コンパイルするとWarningが出るかもしれないがそれは無視する。２重宣言みたいなやつ。

64bitでコンパイルするためには、下記のようにSDKv7.1のLib\x64を追加のライブラリへ記入する。
Debugの時は**strmbasd.lib**が、Releaseの時は**strmbase.lib**が生成されるので、下記のように出力ファイルにあらかじめ記入してもＯＫ。

![追加のライブラリディレクトリプロパティ.png](https://qiita-image-store.s3.amazonaws.com/0/139645/3faf1846-b100-a17c-dd0a-f566274c438c.png)
ここまででBaseClassesのコンパイル終了。

#pushsource.slnのコンパイル
x64の場合だけ注意が必要で、プロジェクトのプロパティのリンカーの全般の追加のライブラリディレクトリに同じようにC:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\x64を追加する必要がある。
これをしないとx64ではコンパイルできない。

#ここまででDLLの作成は終了　動くかどうか確かめる
ここで動くかどうか確かめてみる。必要なのはGraphEditというexeファイル。
Microsoftは再配布を行っていないとのことだが、ダウンロードは[ここ（GraphEdit 非公式ガイド）](regsvr32.exe PushSource.dll)からできる。

まず、登録するファイルがc:\aaaa.dllの場合、

- ActiveX.DLLの登録   C:\>regsvr32 c:\aaaa.dll
- ActiveX.DLLの削除   C:\>regsvr32 /u c:\aaaa.dll

それかcdでdllファイルがあるフォルダまで飛んでから、regsvr32 PushSource.dllを実行する。
そうすると、GraphEditのDirectShowにPushSourceDesktopFilterが追加される。
GraphEditの操作方法は省略。いじりまくると分かる。とりあえずこれでフィルターは完成。

#OpenCVのソースについて
##cap_dshow.cpp
今のところこのファイルしか分からないが、RendererFilterを作っているだろうと思われる部分が見受けられた。

```cap_dshow.cpp
//以下使用例
/*
    //videoInputオブジェクトを作成する
    videoInput VI;

    //利用可能なデバイスのリストをプリントし、見つかったデバイス番号を返す
    int numDevices = VI.listDevices();

    int device1 = 0;  //this could be any deviceID that shows up in listDevices
    int device2 = 1;  //this could be any deviceID that shows up in listDevices

    //もし異なるフレームレートでキャプチャしたければ（デフォルトは30）
    //このfpsを得られなければ、下のコードをここに書く。
    //VI.setIdealFramerate(dev, 60);

    //setup the first device - there are a number of options:

    VI.setupDevice(device1);                           //setup the first device with the default settings
    //VI.setupDevice(device1, VI_COMPOSITE);           //or setup device with specific connection type
    //VI.setupDevice(device1, 320, 240);               //or setup device with specified video size
    //VI.setupDevice(device1, 320, 240, VI_COMPOSITE); //or setup device with video size and connection type

    //VI.setFormat(device1, VI_NTSC_M);                //if your card doesn't remember what format it should be
                                                       //call this with the appropriate format listed above
                                                       //NOTE: must be called after setupDevice!

    //optionally setup a second (or third, fourth ...) device - same options as above
    VI.setupDevice(device2);

    //As requested width and height can not always be accomodated
    //make sure to check the size once the device is setup

    int width   = VI.getWidth(device1);
    int height  = VI.getHeight(device1);
    int size    = VI.getSize(device1);

    unsigned char * yourBuffer1 = new unsigned char[size];
    unsigned char * yourBuffer2 = new unsigned char[size];

    //to get the data from the device first check if the data is new
    if(VI.isFrameNew(device1)){
        VI.getPixels(device1, yourBuffer1, false, false);   //fills pixels as a BGR (for openCV) unsigned char array - no flipping
        VI.getPixels(device1, yourBuffer2, true, true);     //fills pixels as a RGB (for openGL) unsigned char array - flipping!
    }

    //same applies to device2 etc

    //to get a settings dialog for the device
    VI.showSettingsWindow(device1);


    //Shut down devices properly
    VI.stopDevice(device1);
    VI.stopDevice(device2);

```
このソースコードを見る限り、まずはvideoInput::listDevices関数を調べてみる必要がある。
ここでnumDevicesとしてデバイス番号が見つかれば映像がキャプチャされることになるのだろう。

##videoInput::listDevices関数


#余談　SCFHというニコ生配信用フリーウェア
ニコ生のゲーム配信ソフトにSCFHというフリーウェアがある。これを使ってみた。
ダウンロードして実行してみると、OpenCVで認識ができた。これを使って仮想Webカメラとしてモニターをキャプチャすることはできるのだが、なんか気持ち悪いのでちゃんとコーディングすることを目指す。

##突如終了
Wind32APIを用いた方が良いとの話をもらったので、ここでDirectShowを用いた実装はひとまず中止する。
Win32APIで実装できたらまた記事に載せる。