UnityとiPhoneとOpenCVでなにかやる

iPhoneアプリ作ってみたい
Unityってどうなんだろ
ARっていったらOpneCVだよね

っていう短絡的な考えのもと
Unity@iPhoneOpenCVを使えないかここ数日取り組んでいます。

結果的に言うと
Unity@iPhoneOpenCVを使うならばNativePluginでやるしかないっぽいです。

UnityでOpenCVを使うのであればOpenCVSharpっていうOpneCVのC#用ラッパーを使うのが一般的みたいなんですけど、
dylibを認識してくれないorビルドが通らなくなるってことで

とりあえずNativePluginでやってくことにしました。

以下のページを参照しました。
UnityでOpenCVを使う(iOS編)



とりあえずUnityで新規プロジェクト作成からのメモ書きを以下にしておきます。

Unityで新規プロジェクト作成
Planeを追加

Game Object -> Create Other -> Plane

Directional Lightを追加

Game Object -> Create Other -> Directional Light

Planeにスクリプトを追加
    1. 画面左の一覧からPlaneを選択
    2. 画面右のInspectorでAdd Component
    3. New Scriptを選択 imageProcessingとか名前をつけておきます。

なおこの時Planeの位置を(上部Transform内Position)を0 0 0ぐらいにしておきます。
カメラは右下のプレビューでPlane全体が映る程度にしたほうがいいです。
あと今回はiPhone5で行いました。Xを90度回転とかさせたほうがいいかもです。
とりあえずiPhoneの画面に映るものというのはCameraの設定で弄れるとおぼえておいてください
スクリプトで処理をした結果をPlaneのテクスチャに反映させ、それをカメラで映し出しています。

スクリプトの編集

AssetsフォルダにimageProcessing.csが表示されていると思います
それをダブルクリックするとMonoDevelopperが表示されるので
下記に編集してください

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class imageProcessing : MonoBehaviour {
	
	[DllImport ("__Internal")]
	private static extern void UpdateTexture(System.IntPtr colors, int width, int height);
	WebCamTexture webcamTexture;
	Texture2D texture = null;
	
	// Use this for initialization
	void Start () {
		WebCamDevice[] devices = WebCamTexture.devices;
		if (devices.Length > 0) {
			webcamTexture = new WebCamTexture(devices[0].name ,320, 240, 10);
			webcamTexture.Play();
		} 

	}
	
	// Update is called once per frame
	void OnGUI() {
		Color32[] pixels = webcamTexture.GetPixels32();
		GCHandle pixelsHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
		UpdateTexture(pixelsHandle.AddrOfPinnedObject(), webcamTexture.width, webcamTexture.height);
		if (texture) Destroy(texture);
		texture = new Texture2D(webcamTexture.width, webcamTexture.height);
		texture.SetPixels32(pixels);
		texture.Apply();

		pixelsHandle.Free();
		renderer.material.mainTexture = texture;
	}
}

iPhone5 でいうとdevices[0]が背面のカメラ devices[1]が全面のカメラになります
print(devices[i].name)とかして確認して下さい
解像度は320x240で10FPSをターゲットとして要求します。

NativePluginの作成

Assetsの中にPlugins/iOSフォルダを作成します(ここにおいておくとXcode起動時に自動で入れてくれるらしいです。)
その中にPlaneに設定したスクリプト名と同名のファイルを作成します。
今回はimageProcessing.csなのでimageProcessing.cppになります。
中身は以下のようにしてください

#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif

extern "C" {
  void UpdateTexture(char* data, int width, int height);
} 

void UpdateTexture(char* data, int width, int height)
{
    IplImage* p = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, 4);
    cvSetData(p, data, p->widthStep);
    IplImage* g = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    cvCvtColor(p, g, CV_RGBA2GRAY);
    cvCanny(g, g, 50.0, 200.0);
    cvCvtColor(g, p, CV_GRAY2RGBA);
    cvReleaseImageHeader(&p);
    cvReleaseImage(&g);
}

ここまで設定ができればあとはビルドです。

iOSへのビルド設定をする
    1. File->Build Settingsを選択
    2. 上部のAdd Currentで今のSceneを追加します
    3. 画面下のPlatformでiOSを選択します。
    4. この時Development Buildにチェックを入れてください
iOSへBuildする

Build and RunをクリックするとXcodeが立ち上がります。
このままでは動かないので更に設定が必要です
ビルドにコケても驚かないでください。

Frameworkを追加する

Unity-iPhone.xcodeprojをクリックBuild Phasesで Link Binary with Libraries
opencv2.framework(作成方法は参考URLへ)
libc++.dylibを追加

これでビルドができます。
あと dSYMの作成に時間かかりまくるので
Build Settings Debug Information FormatでDWARFだけにしておくと早いです。

まとめ

Class 名
Planeに追加したスクリプトのファイル名
Plugins/iOS内においた.cppファイルのファイル名
はいずれも同じにしてください
大文字小文字もあります。