読者です 読者をやめる 読者になる 読者になる

自習室

こもります

UnityでOpenCVを Native Plugin にして利用する (Windows)

はじめに

UnityでOpenCVを使いたい動機と下調べについては前回の記事に書きました

UnityでOpenCVSharpをつかってOpenCVする。マルチスレッドにもしてみる。 (Windows) - 自習室

今回は、OpenCVを native plugin 化して使う方法についてまとめます、というか、 @hecomi 先生のをなぞった時に出た問題点をまとめておきます

環境

参考にした記事

基本(ただしMac)

この記事で、@hecomi 先生が OpenCVを native plugin 化して使う方法についてまとめてくださっています。基本はこれですが、内容がMacでbundleな感じです。

Unity で OpenCV で作成したテクスチャをネイティブプラグイン経由で利用してみた - 凹みTips

公式の基本(ただし英語)

Windowsでのやり方は、公式のLive Trainingで簡潔に説明されていました。前半はC#でManagedなpluginの説明で、23分あたりから、C++で作る Nativeなプラグインの説明になっています。ランダム関数を回して適当に数値を返すだけのプラグインを例にしているので、英語ですがわかりやすいと思います。

Live Training: Introduction to Plugins - YouTube

dllを作ること自体は Visual Studio Expressでもできますが、作った native Pluginを使うことは、Unity Proでないとできません。このあたりはUnityの厳しいところですね。

応用 Windows8.1 で、DllNotFoundException への対処付き

また、 @hecomi 先生が別の記事で、OpenCVのスタティックライブラリをラップしたdllにする方法についてもまとめくださっています。この記事で通常のlibを使ってdllにするとDllNotFoundException が出る、と報告されていますが、私のところでは解消できましたので後ほど紹介します。

Unity と OpenCV を組み合わせて現実・仮想双方を加工した AR な世界を Oculus Rift 越しに覗いてみた - 凹みTips

やること

ここでは試しに、先述の Windows8.1 の環境下で、@hecomi さんの一つ目の記事でやられていた、 OpenCVでカメラキャプチャーしてウィンドウを開いて表示しつつ、Unity内でテクスチャとして利用する、をやってみようと思います。

手順

プロジェクトの作成

このあたりは、Unity - Writing Plugins を参考に。

  • Visual Studio
  • VC++ / Win32 Application を
  • Application type: DLL
  • Additional Options: EmptyProject でつくる

f:id:AMANE:20141212212952j:plain

OpenCV周りのプロジェクト設定をする

PROJECT > Properties からいろいろ下記のような設定します

追加のインクルードディレクトリ

OpenCV関連のヘッダを読めるようにします。適宜OpenCVをインストールした場所に読み替えてください

f:id:AMANE:20141208233647j:plain

OpenCVのスタティックリンクライブラリを利用する

OpenCVをせっかくdllとしてラップするので、別途 OpenCVのdll群を使わなくてもよいようにしたいです。ユーザにOpenCVをインストールさせたり、完成したアプリのフォルダ内にdllをたくさん含んだ状態で配布するのはちょっといけてない感じです。

そこで、OpenCVからリリースされている <OPENCV_ROOT>\build\x86\staticlib.lib ファイルたちを利用するように指定します。これを使って以下ので順でdllを作成すると、すべての .lib ファイルが一つのdllに固められて、そのdllだけをユーザに渡せばいい状態になります。

f:id:AMANE:20141212213158j:plain

ランタイムライブラリをマルチスレッド(/MT)に変更

ここは @hecomi さんの受け売りです。

f:id:AMANE:20141212212939j:plain

DLL化のためのおきまりのコードを書く

#include <iostream>

#define DLLExport __declspec (dllexport)

extern "C"
{
    DLLExport int GetRandom()
    {
        return rand();
    }
}

先ほど動画を貼ったLive Trainingでは、上記のようなコードで ランダムな数値をはき出すだけの機能を dll 化しています。同様の手法で@hecomiさんのこちらの記事では、OpenCVを使ってカメラをたたいたり、別ウィンドウで表示したり、Unityのテクスチャとして使えるようにしています。コードは @hecomiさんの記事を参考にされてください

DLL化のために必要なスタティックライブラリをリンクする

私の環境ですと、 @hecomiさんの記事 の通り だとライブラリが不足しているようで、unresolved external symbol エラーが大量発生します。エラーは下記のようなものたちで、多くはOpenCVのDLL本体に含まれているもののようです。これらもリンクするようにして、最終的には以下のような感じになります。

f:id:AMANE:20141212213644j:plain

このあたりは、こちらの記事様で勉強させていただきました

ビルド→Unityで使う

BUILD -> BUILD <Project Name>

で、ビルドされ、ReleaseなりDebugなりのフォルダに .dll ファイルが生成されます。

これを、Unityで Assets/Plugins/hoge.dll の位置に置きます

dllで定義された関数をUnityで利用する際は、以下のようにDllをインポートし関数を宣言するコードを用意し、オブジェクトにアタッチして使います。これは先述のUnity公式Live Trainingでの例です。

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

public class TestNative : MonoBehaviour
{
    [DllImport("RandomNumberDLL")]
    private static extern int GetRandom();

    // Use this for initialization
    void Start ()
    {
        print("Native Random Number: " + GetRandom());
    }

}

同様に @hecomi さんの記事を参考に、dllに定義したOpenCVを使った関数を呼び出してください

その2:スタティックライブラリを使わない場合

先述の Unity公式 live Trainingと同じやり方になります。

通常のライブラリファイルをリンクする

ProjectのPropertiesで staticlib フォルダを参照するように指定している追加のライブラリディレクトリを、 lib フォルダを参照するように書き換えます。

f:id:AMANE:20141212220007j:plain

ランタイムライブラリを /MD にする

f:id:AMANE:20141212220134j:plain

システム環境変数OpenCVのDLLのありかを通す

Path に以下の二つを記入します (F:\develop\opencv\ の部分は、ご自身の環境に合わせてください)

F:\develop\opencv\build\x64\vc12\bin; 
F:\develop\opencv\build\x86\vc12\bin;

はじめ x64 のものだけを追加していたのですが、 dll を 32bit でビルドしてたため、DllNotFoundException が発生しました。 x86 のbinもPathに通したら、エラーがなくなりました。

ビルドなど以下略

ここから先は、staticlibを使う場合と同じです

最後に

これで、 @hecomi さんの記事のように、カメラ画像がテクスチャに貼れて、同時に別ウィンドウが開きカメラ画像が見られたらOKです。

@hecomi さんありがとうございました。