C#でSKnet社のHDMIキャプチャ「MonsterX U3.0R」を使ってみた
ゲーム配信マンには馴染み深い(?)MonsterXはUSB3.0で1920x1080(60FPS)のムービーがキャプチャできるボードです。 今回ひょんなことからC#でHDMIキャプチャしたデータを使用したいみたいな要望があったのでこちらの商品を試してみました。
SKNET USB3.0接続 HDMIビデオキャプチャーユニット MonsterX U3.0R SK-MVXU3R
- 出版社/メーカー: エスケイネット
- 発売日: 2013/07/30
- メディア: Personal Computers
- この商品を含むブログを見る
プログラムを書いてみる
ちょっと調べてみるとこれってDirectShowでキャプチャできるみたいなので(それを調べてワザワザ購入した)、OpenCVでVideoCapture使えば余裕そう。というわけでザックリ書いてみました。ButtonとPictureBoxだけをつけたFormを用意した超単純なものです。
VideoCapture m_cap; Timer m_timer; Bitmap m_bitmap; Mat m_imagemat; public Form1() { InitializeComponent(); m_cap = new VideoCapture(); m_timer = new Timer(); m_cap.Open(CaptureDevice.DShow, 1); m_imagemat = new Mat(); } private void button1_Click(object sender, EventArgs e) { if (!m_cap.IsOpened()) return; m_timer.Interval = (int)(1000.0 / 60.0); m_timer.Tick += m_timer_Tick; m_timer.Start(); } void m_timer_Tick(object sender, EventArgs e) { try { m_cap.Read(m_imagemat); if (m_bitmap == null) { m_bitmap = m_imagemat.ToBitmap(); } else { m_imagemat.ToBitmap(m_bitmap); } this.pictureBox1.Image = m_bitmap; } catch (Exception exception) { Console.WriteLine(exception.Message); } }
このプログラム、ちょっとDirectShowのデバイスIDを決めうちで作ってしまってるのが良くないですね。今回はたまたま
m_cap.Open(CaptureDevice.DShow, 1);
で開くことができましたが、ぼくの環境では
m_cap.Open(CaptureDevice.DShow, 0);
ではWebカメラがキャプチャデバイスとして開きました。
あ、あとFPSを
m_timer.Interval = (int)(1000.0 / 60.0);
としてしまってるのも問題かもしれませんね。なぜかm_cap.FPSとしても0が返ってきてしまったので八方塞ですが。
今回ちょっと苦労した点としては、BitmapやMatをm_timer_Tickのたびにnewしていたのでは どうもガベージコレクションがうまく作動しないっぽく、メモリアロケーションがらみの例外を吐いてしまうという問題があったことです。これについては
m_imagemat = new Mat();
m_bitmap = m_imagemat.ToBitmap();
をしまくらないこと(インスタンスが増えすぎてしまう???)で解決することができました。 解像度の低いWebカメラではループのたびにnewしてても問題なかったのでおそらく1フレームあたりの容量とフレームレートが問題になるのかもしれませんね。
最後に
今回はOpenCVを手軽にサクッっと使いたかったのでOpenCVSharpというライブラリを使用させていただきました。 これ、ちょっとOpenCV使いたいなぁって時に便利で、しかもNuGetから使用できるのでC#の手軽さと相まって 超絶便利なライブラリだと思ってます。しかもすぐにUIに反映できるExtensionまで準備されているので感謝感謝です。