UnityでOpenCVを動かしてみよう(主にMac対応)
これは Oculus Rift Advent Calendar 18日目の関する記事です。
Oculus Riftで OpenCV 動かせたら夢広がりますよね?笑い男とか、電脳メガネとか、スカウターとか。
で、Oculus RiftでOpenCV動かすには、UnityでOpenCVで動かすのが一番簡単に使えます。僕が一番OpenCVをうまく動かせれるんだ!です。
UnityからOpenCVを使うには、C#ラッパーのOpenCVSharpを使います。これだとC#スクリプトから直接OpenCVが使えて、スーパー便利なんですよねー。
https://code.google.com/p/opencvsharp/
ただ本来、OpenCVSharpはWindows用のようで、通常のビルドでは必要の無いもの(GDI系WindowsAPIを使ってる)も含まれて、これがネックとなってMacではビルドできません。
というわけで、GDI系WindowsAPIを外して、Mac用に改めてビルドしたいところですが、なかなかハードルが高いです。そこで、Mac用のビルドを配布しているサイトがあるので、そちらに乗っかりましょう。
http://ux.getuploader.com/aimino
Mac用: CSharpTest_MacOS.zip
Win用: CSharpTest_Win.zip
Macの方は以下のようにdylibを配置しましょう。root権限が必要です。
sudo mkdir -p /usr/local/lib
sudo cp *.dylib /usr/local/lib
そして、一旦PC再起動した方が良いでしょう。で、Unityでプロジェクトを開きましょう。サンプルがEditor上で動きますか?動きませんねw
なんか入っているサンプルシーンがうまく行かないようです。ですので、以下のサンプルコードを使ってみてください。カメラからの画像を線画にするものです。
using UnityEngine;
using System.Collections;
using OpenCvSharp;
using System.Runtime.InteropServices;
public class CVSample : MonoBehaviour {
WebCamTexture webcamTexture;
Texture2D texture = null;
public string deviceName;
private int devId = -1;
// Use this for initialization
void Start () {
WebCamDevice[] devices = WebCamTexture.devices;
print ( "num:" + devices.Length );
for(int i=0 ; i<devices.Length ; i++ ) {
print ( devices[i].name );
if ( devices[i].name.CompareTo( deviceName ) == 0 ) {
devId = i;
}
}
if (devId >= 0) {
webcamTexture = new WebCamTexture(devices[devId].name ,640, 480, 60);
webcamTexture.Play();
}
}
void Update() {
if ( devId >= 0 ) {
Color32[] pixels = webcamTexture.GetPixels32();
GCHandle pixelsHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
DoCanny(pixelsHandle.AddrOfPinnedObject());
if (texture) Destroy(texture);
texture = new Texture2D(webcamTexture.width, webcamTexture.height);
texture.SetPixels32(pixels);
texture.Apply();
pixelsHandle.Free();
renderer.material.mainTexture = texture;
}
else {
print ("Can't find camera!");
}
}
void DoCanny(System.IntPtr data)
{
int width = webcamTexture.width;
int height = webcamTexture.height;
IplImage p = Cv.CreateImageHeader(Cv.Size (width, height), BitDepth.U8, 4);
Cv.SetData ( p, data, p.WidthStep);
IplImage g = Cv.CreateImage(Cv.Size (width, height), BitDepth.U8, 1);
Cv.CvtColor (p, g, ColorConversion.RgbaToGray);
Cv.Canny(g, g, 50.0f, 200.0f);
Cv.CvtColor (g, p, ColorConversion.GrayToRgba);
}
}
このスクリプトを適当なオブジェクト(例えばCube)に追加して、新規マテリアルを作って「Unlit/Texture」にしてそれをこのオブジェクトに割り当てましょう。
「Device Name」はカメラのデバイス名です。一旦プロジェクトを動かしてみると、カメラがDebugログに表示されてくると思います。一旦プロジェクトを止めて、該当のカメラデバイス名を「Device Name」にコピペしてください。そしてプレイすると、うまく行きましたか?
で、ですね。
私のMacでMac用ビルドした際に、プレイしてもうまく動いてくれないことがありました。Player.logを見てみるとlibcxcore.dylibが見つからないというエラーでした。その対策としては以下のサイトで言及してあります。
http://answers.unity3d.com/questions/23615/how-to-make-unity-find-dylib-files.html
かなーーーーり苦労されている様子がわかりますw
ここからはかなり端末依存するので、できる保証もありません。あらかじめご了承ください。おそらくMacOSのバージョン次第ではうまく行かないケースもあるでしょう。
まずは先ほど、コピーした /usr/local/lib/*.dylib を /usr/lib に mv してみましょう。行けました?行けませんか…
うまく行かない場合は最後の手段で、一旦ビルドして、そのアプリの中身の
YourApp.app/Contents/Plugins/
に直接先ほどの *.dylib を置いてみてください。行けましたか?
当然、ビルドするごとにコピーする必要が出てきてしまうので、オススメしません。ただ、よくわからないのですが、一旦ビルドできたらここに置かなくても良くなりました。正直良くわかりません。
まあとりあえず、うまく行ったらおめでとうございます。
うまくいかなかったらコメントに内容を詳しく書いていってください。