Mugichoko's blog

Mugichoko’s blog

プログラミングを中心としたメモ書き.

OpenCVをUnityで使う (Native Plug-ins)

UnityでOpenCVを使いたい.UnityのNative Plug-insを使って,C++OpenCVのDLL経由でOpenCVをUnityから呼び出す方法を取った.

UnityでOpenCVを使う方法

実装方法の候補

ざっと調べたところ,以下の3つの方法がよく知られているようだった.

  • Asset StoreでOpenCV for Unity等の有料のものを購入する
    • 利点:すぐに使える(試していないので確約はできない)
    • 欠点:有料,メンテナンスされなくなったら終了
  • OpenCVSharpを使う
    • 利点:無料,すぐに使える(同上)
    • 欠点:Unityでは上手くいかないかも,と書いてある
  • Native Plug-insを利用する
    • 利点:無料,OpenCV以外への応用も可能(と思われる)
    • 欠点:導入方法がよく分からない

手順

ということで,Native Plug-insを使う方法を調べてみることにした.実装手順としては,以下を考えている.

  1. C++のDLLを作ってUnityで使ってみる
  2. OpenCVのDLLをUnityで使ってみる

まずは,確実に動くであろう自作のC++のDLLをUnity上で使い,インストール済みのOpenCVのDLLをUnityで使ってみようという作戦だ.

実装環境

C++のDLLを作ってUnityで使う

C++のDLLを作る

手順は以下の通り.

  1. Visual StudioでDLL用プロジェクトを作成
    • File > New > ProjectNew Project Windowを表示
    • そしてVisual C++ > Windows Desktop > Dynamic-Link Library (DLL)を選択
    • プロジェクト名がDLLの名前になるので,分かりやすいようCppPluginsとした
  2. CppPlugins.hCppPlugins.cppを作成
    • コード自体は下記参照
    • ファイル名は何でもいいです
  3. Releaseモードでx86とx64の2つのプラットフォームでビルド
    • Releasex64/ReleaseフォルダにCppPlugins.dllが作成されているはず

必要なコード

//
// CppPlugins.h
//
#pragma once

#ifdef CPPPLUGINS_EXPORTS
#define CPP_API __declspec(dllexport)
#else
#define CPP_API __declspec(dllimport)
#endif

extern "C"
{
    CPP_API int Add(int x, int y);
}
//
// CppPlugins.cpp
//
#include "stdafx.h"

#include "CppPlugins.h"

CPP_API int Add(int x, int y)
{
    return x + y;
}

作成したC++のDLLをUnityで使う

  1. Unity 3Dのプロジェクトを新規作成
  2. Assets/Plugins/x86フォルダとAssets/Plugins/x64フォルダを作成
  3. 作成したC++のDLLを対応するプラットフォームのフォルダにコピー
    • Releasex64/ReleaseCppPlugins.dllをそれぞれ Assets/Plugins/x86フォルダとAssets/Plugins/x64フォルダへ
  4. C#プラグインを書く
    • コード自体は下記のCppPlugins.csを参照
  5. GameObject(何でもよい)から読み込み
    • コード自体は下記のPluginTest.csを参照
  6. 実行

必要なコード

//
// CppPlugins.cs
//
using System.Runtime.InteropServices;

public class CppPlugins
{
    [DllImport("CppPlugins")]
    public static extern int Add(int x, int y);
}
//
// PluginTest.cs
//
using UnityEngine;

public class PluginTest : MonoBehaviour
{
    void Start()
    {
        Debug.Log("Add(1, 2): " + CppPlugins.Add(1, 2));
    }
}

Unityでの設定

f:id:Mugichoko:20191011172525j:plain
CppPlugins.dllを入れたUnityのWindow.HierarchyタブとProjectタブ内のフォルダ構成に注目

実行結果

Add(1, 2): 3
UnityEngine.Debug:Log(Object)
PluginTest:Start() (at Assets/PluginTest.cs:8)

OpenCVC++のDLLをUnityで使う

自作DLLと同様の手順で進める.OpenCVのDLLはビルド済で,x86とx64アーキテクチャのDLLがあるものとする.OpenCVのビルドは色々と参考になるページがあるので別途参考のこと.

C++のDLLを更新

C++のDLLを作るで作成したVisual Studioのプロジェクトに以下の2つのコードを追加してビルドし,DLLを更新する.OpenCVへのリンクを忘れずに!

//
// CvPlugins.h
//
#pragma once

#ifdef CPPPLUGINS_EXPORTS
#define CV_API __declspec(dllexport)
#else
#define CV_API __declspec(dllimport)
#endif

extern "C"
{
    CV_API int cvAdd(int x, int y);
}
//
// CvPlugins.cpp
//
#include "stdafx.h"

#include <opencv2/opencv.hpp>
#include "CvPlugins.h"

CV_API int cvAdd(int x, int y)
{
    cv::Mat xMat(1, 1, CV_32S);
    cv::Mat yMat(1, 1, CV_32S);
    xMat.at<int>(0, 0) = x;
    yMat.at<int>(0, 0) = y;
    
    // 無理やりcv::Matを使って足し算してみる
    cv::Mat zMat = xMat + yMat;
    return zMat.at<int>(0, 0);
}

自作のDLLとOpenCVのDLLをUnityに導入

  1. Unity内でDLLを更新
  2. C#プラグインを書く
    • 先のCppPlugins.csに追記
    • 下記参照
  3. GameObject(何でもよい)から読み込み
    • 先のPluginTest.csに追記
    • 下記参照
  4. 実行

更新したコード

//
// CppPlugins.cs
//
using System.Runtime.InteropServices;

public class CppPlugins
{
    [DllImport("CppPlugins")]
    public static extern int Add(int x, int y);
    [DllImport("CppPlugins")] // added
    public static extern int cvAdd(int x, int y);
}
//
// PluginTest.cs
//
using UnityEngine;

public class PluginTest : MonoBehaviour
{
    void Start()
    {
        Debug.Log("Add(1, 2): " + CppPlugins.Add(1, 2));
        Debug.Log("cvAdd(3, 5): " + CppPlugins.cvAdd(3, 5)); // added
    }
}

Unityでの設定

f:id:Mugichoko:20191011165136j:plain
opencv_world411.dllを追加したUnityのWindow.HierarchyタブとProjectタブ内のフォルダ構成に注目

実行結果

Add(1, 2): 3
UnityEngine.Debug:Log(Object)
PluginTest:Start() (at Assets/PluginTest.cs:8)

cvAdd(3, 5): 8
UnityEngine.Debug:Log(Object)
PluginTest:Start() (at Assets/PluginTest.cs:9)