MagicLeapでNativeBuildのOpenCVを使う

更新日から1年以上経過しています。情報が古い可能性がございます。

OpenCV for MagicLeap

OpenCVをMagicLeapで使いたかったのでビルドして使ってみました。
この記事ではそのやり方を紹介します。
適宜参考となるリンクを張っておくので、そちらもご参照ください。

ソースをダウンロード

何はともあれソースが無ければ話になりません。GithubからOpenCVのソースを落としてきます。

https://github.com/opencv/opencv

ここで着目すべきは、CMakeLists.txt が用意されていることです。
MagicLeap のリファレンスには CMake を用いたビルドの方法の記載があるのでそちらを参考にします。
以下のページに沿って準備を行います。

https://developer.magicleap.com/learn/guides/sdk-mabu-ref-build-and-link-libraries

実行環境

その前に、これを実行した環境を記載しておきます。

  • Windows10
  • CMake 3.16.4
  • make 4.3
  • MagicLeap SDK 0.23
  • VSCode 1.42.1

今回は Unity 用の Native Plugin としてビルドしたので、動作確認は以下のバージョンの Unity で行っています。

  • Unity 2019.2.20f1

ビルド

MagicLeap 公式の手順に従っていきます。

magicleap.toolchain.cmake の作成

mabu のパスが通っている場所で、リファレンス通りに以下のコマンドを実行します。
MagicLeap SDK の Shell を使うのが楽でしょう。The Lab から起動するのが面倒ですが……
今後も使うものなので、SDK のフォルダに作成しても良いでしょう。

mabu -t lumin --create-cmake-toolchain magicleap.toolchain.cmake

以下のような出力が表示され、magicleap.toolchain.cmake が生成されます。

mabu: using build target 'debug_lumin_clang-3.8_aarch64'
mabu: Generated a cmake toolchain file to magicleap.toolchain.cmake.
This toolchain is entirely independent of mabu, but, depends on the current SDK location;
override the MLSDK cmake variable as needed.
mabu: Example usage:
        del CMakeCache.txt
        cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=magicleap.toolchain.cmake [-DMLSDK=...] ...

ここの記載の通りに動かせば良さそうです。

CMakeLists.txt の修正

CMakeLists.txt を修正していきます。
バージョンで行数は変わりそうなので参考程度にしてもらって、大体 622 行目あたりにある以下の個所を修正します。

# ----------------------------------------------------------------------------
#       CHECK FOR SYSTEM LIBRARIES, OPTIONS, ETC..
# ----------------------------------------------------------------------------

(中略)

- if(ANDROID)
+ if(ANDROID OR LUMIN)

フン。LUMINというのかい?贅沢な名だねぇ。今からおまえの名前はANDROIDだ。いいかい、ANDROIDだよ。分かったら返事をするんだ、ANDROID!!

千と千尋の神隠し から改変

当然ながら OpenCV には LUMIN 用の設定はありません。しかし、 Lumin は Android ベースのカスタム OS なので、困ったときは Android の設定を流用させていただきます。

OpenCVModule.cmake の修正

cmake ディレクトリの中に、OpenCVModule.cmake というファイルがあるので、こちらも修正していきます。
981 行目あたりを以下のように変更します。

# For dynamic link numbering conventions
- if(NOT ANDROID)
+ if(NOT ANDROID AND NOT LUMIN)

お前、本当は Android なんじゃ……という気持ちを抑えながら変更します。
この2つの変更で Lumin 用に OpenCV がビルドできます。

OpenCV のビルド

ビルド用のディレクトリを作成します。今回は Build という名前のディレクトリを OpenCV のディレクトリの中に作成し、そこに生成されるようにしました。

(どっか)\opencv\Build

に移動して CMake を以下のように実行します。
ここでも MagicLeap SDKのシェルを利用しています。

cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="{{magicleap.toolchain.cmakeのディレクトリパス}}\magicleap.toolchain.cmake" ../

以下のメッセージが出て完了します。

-- Configuring done
-- Generating done
-- Build files have been written to: {{どっか}}/opencv/Build

今回は手軽に試したいので world ライブラリを作成します。
個別のライブラリが欲しい方は次の手順をスキップしてください。

CMakeCache.txt の変更

227 行目付近に以下の記載があるので変更しておきます
“world” で検索をかけるのが良いと思います。

//Include opencv_world module into the OpenCV build
- BUILD_opencv_world:BOOL=OFF
+ BUILD_opencv_world:BOOL=ON

これで準備が整いました。

make の実行

それでは make を実行します。
以下のコマンドを実行してお茶でも飲みに出かけましょう。

make
make install

生成された .so を使うには

ビルドが完了すると、Build/install ディレクトリができているはずです。こちらに必要なものがそろっています。
が、OpenCV は2あたりからC言語のサポートを切っています。(C++はもちろん使える)
そのため、Unity から使えるようにするためには OpenCV の関数をラップし、名前マングリングを防いだ形で用意しなければいけません。

https://docs.unity3d.com/ja/2019.2/Manual/NativePlugins.html

mabu プロジェクトの作成

前回の記事を参考に mabu プロジェクトを作成してください。名前は何でも良いのですが、ここでは『OpenCV4Lumin』

https://www.kouken-party.info/2020/01/30/magicleapで使うnative-pluginを作ってunityで使う/

動作確認プラグインの作成

作成した mabu プロジェクトに OpenCV を入れていきます。

『opencv\Build\install\include\opencv4\opencv2』を作成した mabu プロジェクトの inc ディレクトリにコピーします。『inc\opencv2』となっていれば大丈夫です。

次に mabu プロジェクト内に lib ディレクトリを作成し、その中に『opencv\Build\install\lib\libopencv_world.so』をコピーします。『lib\ libopencv_world.so 』となります。

画像をOpenCVで読み込んでテクスチャーに貼る

以下のヘッダーとソースコード、mabuファイルを用意します。

// OpenCV4Lumin.h
#include <stdio.h>

extern "C" {
    UNITYEXPORT void getFileTexture(const char*, unsigned char*);
}
// OpenCV4Lumin.cpp
#include "OpenCV4Lumin.h"
#include "opencv2/opencv.hpp"

void getFileTexture(const char* fileName, unsigned char* data) {
    cv::Mat img = cv::imread(fileName);

    cv::Mat argb_img;
    cv::cvtColor(img, argb_img, cv::COLOR_RGB2BGRA);
    std::vector<cv::Mat> bgra;
    cv::split(argb_img, bgra);
    std::swap(bgra[0], bgra[3]);
    std::swap(bgra[1], bgra[2]);
    std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}
# OpenCV4Lumin.mabu
KIND = shared
SRCS = src/OpenCV4Lumin.cpp
INCS = inc/
USES = ml_sdk
SHLIBS = lib/opencv_world

OPTIONS = \
	standard-c++/11 \
	stl/libc++

サクッと用意したら次はUnity側です。
Unity上からこの mabu を指定してNative Plugin をビルドするか、プロジェクトを作成したツールでビルドするかして、libOpenCV4Lumin.so を手に入れます。このプラグインと、OpenCV 本体である、libopencv_world.so をUnityのPluginsディレクトリに入れておきます。
Lumin用なので、Platform は Lumin だけにしておいてください。

Script の用意

それでは作成した Native Plugin を呼び出すC#のコードを用意します。
今回は動作を確認することが目的なので、マジックナンバーもハードコードしてしまいます。
StreamingAssets に cosmic_cat.jpg という名前の、600×445のサイズの画像を置いています。何の画像かは各自想像にお任せします。

// CVTest
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;

public class CVTest : MonoBehaviour
{
    [DllImport("OpenCV4Lumin", CallingConvention = CallingConvention.Cdecl)]
    private extern static void getFileTexture(byte[] fileName, IntPtr data);

    private Texture2D texture_;
    private Color32[] pixels_;
    private GCHandle pixels_handle_;
    private IntPtr pixels_ptr_;

    void Start()
    {
        texture_ = new Texture2D(600, 445, TextureFormat.ARGB32, false);
        pixels_ = texture_.GetPixels32();
        pixels_handle_ = GCHandle.Alloc(pixels_, GCHandleType.Pinned);
        pixels_ptr_ = pixels_handle_.AddrOfPinnedObject();

        string path = $"{Application.streamingAssetsPath}/cosmic_cat.jpg";
        if (!File.Exists(path))
        {
            Debug.LogError("Image File Not Found!!!!");
            return;
        }
        Debug.Log(path);
        byte[] name = Encoding.ASCII.GetBytes(path);
        getFileTexture(name, pixels_ptr_);
        Debug.Log("Image Loaded");

        texture_.SetPixels32(pixels_);
        texture_.Apply();

        GetComponent<Renderer>().material.mainTexture = texture_;
    }

    void OnApplicationQuit()
    {
        pixels_handle_.Free();
    }
}

スクリプトができたら Scene 上に Plane を配置してこのスクリプトを貼り付けます。
貼り付けたらビルドして MagicLeap で起動します。Editor 上で確認したい方は Windows 用の .dll も別途ビルドして用意してください。

起動

宇宙猫

はい、うまく表示されましたね。
表示されない方は The Lab からエラーを確認して色々直してください。
これで MagicLeap 上で OpenCV を使って何でもできるようになりました。後は好き放題画像をいじくってください。

以上!

コメントする

メールアドレスが公開されることはありません。