Oculus Rift 2 Advent Calendar 2014 - Qiitaの6日目です。
↑のカレンダーが途切れそうだったので、急いでネタを作りました。
今回はゲームエンジン使いません。題名の通り、
C# + OvrvisionSDK(C#) + OpenCVSharp + WPFでゴリゴリコード書く感じです。
VisualStudioCommunity2013を使います。
いつも以上に説明雑いです。仕様です。
OvrvisionSDK(C#)をセットアップしてみた結果www
まずはセットアップです。公式サイトのスタートアップガイドに
手順が書いてあるので、それを参考にセットアップしましょう!
startup_manual - Ovrvision Developer Document
C#版のセットアップ手順書いてねええええええええええええええ!!!
いいもん、自力でセットアップするもん(おこ
(2014/12/06現在)
セットアップしてみた
まずWindows用のSDKをダウンロードします。
downloads - Ovrvision Developer Document
ダウンロードしたファイルの中にある「example_csharp_vs2008」フォルダを
開きます。
そして、中にある以下のファイルを自分のC#プロジェクトに追加して下さい
- COvrvision.cs
- COvrvisionProperty.cs
あとは、ovrvision.dllを追加します。dllの追加方法はググって下さい
面倒くさい方は、System32やSysWow64にぶち込めばいいと思います
("ovrvisionsdk_windows\bin\x86_csharp\ovrvision.dll")
OpenCVSharpをセットアップした結果www
Ovrvisionから受け取った画像データをそのまま出すだけでは芸がないので
OpenCVSharpで画像を出してみます。OpenCVSharpでフィルタ処理などを
使うことができるので、色々楽しいことができそうです
セットアップ方法
OpenCvSharpをつかう その17(NuGetで導入) - schima.hatenablog.com
以上。手抜きです、はい。
(本家のOpenCV、Nugetで取れるようになっていたんですね…素晴らしい…)
OvrvisionSDK(C#)リファレンスを見た結果www
作業に取り掛かる前にリファレンスを見ます。大切です。見ます!
reference_cs - Ovrvision Developer Document
↓リファレンスの一部
…え?
ovrvisionSDKのC#リファレンス…思いっきりC++なんですけど、これはいったい http://t.co/rPW5uPNvuL
— おかず (@pafuhana1213) December 5, 2014
@pafuhana1213 pic.twitter.com/4AzuUv22Gc
— izm (@izm) December 5, 2014
あ、はい
リファレンスが整備されるまでは、「COvrvision.cs」の中身を見ましょう
コードがリファレンスです
WPF上にovrvisionから受け取った画像を出してみた結果www
細かい解説してもアレなので、コード全部貼ります。
WPFプロジェクト作成時に用意されているMainWindowのコードです。
MainWindows.xaml
<Window x:Class="OVRVision_WPF.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="1280" Height="480 "> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Viewbox Grid.Column="0" Stretch="Fill" > <Image Name="ImageLeft" HorizontalAlignment="Left" Height="480" Margin="0,0,0,0" VerticalAlignment="Top" Width="640" Loaded="Window_Loaded"/> </Viewbox> <Viewbox Grid.Column="1" Stretch="Fill"> <Image Name="ImageRight" HorizontalAlignment="Right" Height="480" Margin="0,0,0,0" VerticalAlignment="Top" Width="640"/> </Viewbox> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Windows; using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Imaging; using System.ComponentModel; using OpenCvSharp; using ovrvision_app; using OpenCvSharp.Blob; using OpenCvSharp.Extensions; using System.Threading; namespace OVRVision_WPF { /// <summary> /// MainWindow.xaml の相互作用ロジック /// http://thinkami.hatenablog.com/entry/2014/08/01/074831 /// http://sourcechord.hatenablog.com/entry/2014/10/05/022144 /// </summary> public partial class MainWindow : Window { BackgroundWorker worker; COvrvision Ovrvision = new COvrvision(); IplImage imgLeft = new IplImage(); IplImage imgRight = new IplImage(); WriteableBitmap wbLeft; WriteableBitmap wbRight; public MainWindow() { InitializeComponent(); bool result = Ovrvision.Open(); Console.WriteLine("OVR Open:" + result.ToString()); worker = new BackgroundWorker(); // ProgressChangedイベントを発生させるようにする worker.WorkerReportsProgress = true; worker.DoWork += (sender, e) => { while (true) { Ovrvision.UpdateCamera(); worker.ReportProgress(0); Thread.Sleep(16); } }; // ReportProgressメソッドで呼ばれるProgressChangedのイベントハンドラを追加 worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); } private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { // 左目 Ovrvision.UpdateLeft(); using( imgLeft = (IplImage)BitmapConverter.ToIplImage(Ovrvision.imageDataLeft)) { if (wbLeft == null) { wbLeft = new WriteableBitmap(imgLeft.Width, imgLeft.Height, 256, 256, PixelFormats.Bgr24, null); } WriteableBitmapConverter.ToWriteableBitmap(imgLeft, wbLeft); ImageLeft.Source = wbLeft; } // 右目 Ovrvision.UpdateRight(); using( imgRight = (IplImage)BitmapConverter.ToIplImage(Ovrvision.imageDataRight)) { if (wbRight == null) { wbRight = new WriteableBitmap(imgRight.Width, imgRight.Height, 256, 256, PixelFormats.Bgr24, null); } WriteableBitmapConverter.ToWriteableBitmap(imgRight, wbRight); ImageRight.Source = wbRight; } } private void Window_Loaded(object sender, RoutedEventArgs e) { // DoWorkイベントハンドラの実行を開始 worker.RunWorkerAsync(); } } }
…コード汚いけど直す気なし
実行すると、こんな感じで左目と右目用画像が並んだウィンドウ表示されます
これをOculus(Extend)ウィンドウに持って行って、最大化して下さい。
やった!表示された!ばんじゃーい!
おやすみなさい…(現在午前4時
色々と苦労したったwww
↑を作る上で苦労した・嵌った点を書いていきます
Ovrvision → OpenCVの画像変換
Ovrvision側で持っている画像形式は「System.Drawing.Bitmap」、
OpenCV側は「OpenCVSharp.IplImage」です。で、変換は以下のサイトを参考にしました。
おちラボ:教育システム研究開発BLOG: 【C#】OpenCVSharpでのBitmapとIplImageへの相互変換
imgLeft = (IplImage)BitmapConverter.ToIplImage(Ovrvision.imageDataLeft)
OpenCV → WPF Imageの画像変換
WPFで扱う画像形式は「WriteableBitmap」です。
変換処理は以下のサイトを参考にしました。別スレッド処理もこちらのサイトを参考にしています
C# + OpenCvSharp + WPF で、USBカメラ画像の表示や保存をしてみた - メモ的な思考的な
ImageLeft.Source = WriteableBitmapConverter.ToWriteableBitmap(imgLeft);
ハイパーメモリ枯渇タイム
画像変換も終わり、無事表示できたと思ったらメモリ枯渇で落ちました
PCのメモリ容量が不足してるので、メモリ増設しましょう。以上
( ‘д‘⊂彡☆))Д´) パーン
↓の記事に原因・解決方法が解説されていました
OpenCvSharpで動画再生 - SourceChord
毎フレームごとに、ToWriteableBitmap()メソッドで、
新規WriteableBitmapインスタンスを生成しているためですね。
無駄なメモリ消費をしないように、一度作成したWriteableBitmapを
使いまわすように修正します。
ということで、修正しました。内容は上のコードを見て下さい。
作ったもの公開したったwww
ということで、ここまでの実装内容をアップしました
簡単なフィルタを色々用意してます。
https://dl.dropboxusercontent.com/u/30427841/exe/OVRVision_WPF.ZIP
サンプル
びふぉー
あふたー
動かなかったら報告下さい。たぶん直します。
最後に
今作るなら、C++の方が…
OvrvisionのサンプルもC++の方が気合入ってますし…
凹みさんの記事オススメです…
Unity と OpenCV を組み合わせて現実・仮想双方を加工した AR な世界を Oculus Rift 越しに覗いてみた - 凹みTips
カレンダー繋いだはいいけど、12/7(日)はどうしよう…誰か…
Oculus Rift 2 Advent Calendar 2014 - Qiita