更新日から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 を使って何でもできるようになりました。後は好き放題画像をいじくってください。
以上!