Posts Tagged: unity

OpenCV(Android)で顔認識した結果のテクスチャをUnityで表示する

はじめに

UnityでOpenCVを使用する場合、
AssetStoreで販売されているOpenCV for Unityを使用するか、
自前でC++などでUnityネイティブプラグインを開発するかの2つ方法があります。
OpenCV for Unityは自分は使ったことはありませんが、言及しているブログも多く、
マルチプラットフォームそれぞれ用にネイティブプラグインを作るのが面倒くさかったりする場合は
お金で解決してしまった方が手っ取り早いかもしれません。

さて、今回の内容は、
いやAssetStoreに頼らず自分でネイティブプラグイン作ってみたい!
とか、お金がない!
などといった事情をお持ちの方向けとなってます。

構成

Unity側でAndroidの機能を使うにはいくつか方法があります。
Android用プラグインのビルドと使用
ここにまとまっています。

このプロジェクトでは
AAR プラグインと Android ライブラリ(1)

UnityPlayerActivity Java コードの拡張(2)
の2つのドキュメントで述べられている機能を使います。

Unity(C#)からAndroid(Java)のコードを呼ぶには(1)だけやればよいのですが、
今回はAndroid(Java)側が起動したカメラ画像を使用したかったため(2)が必要でした。
Unityでカメラ画像使いたいならWebCamTextureが簡単じゃん、と思うのですが今回は後述の理由のため使用していません。

構成としてはこの様になっています。

Android
|- OpenCVでカメラ画像を取得/顔検出
|- OpenGLでテクスチャを生成
Unity
|- テクスチャを受け取り表示

また、今回使用したバージョンは次の通りです。

Unity 2017.4.0f1 Perfonal(64bit)
Android Studio 3.0.1
Android OpenCV library 3.4.1

チュートリアル

簡単ですが作成方法を記載します。
プロジェクトはGithubに上げています。
詳細はこちらでご確認ください。

Unityプロジェクトの作成

まずはUnityプロジェクトを作成します。
シーンにはカメラ画像を表示するためのQuadを追加したのみです。
このQuadにはネイティブプラグイン側の機能を呼び出すためのスクリプト:FaceDetectionをつけています。

Unity側は大体これだけです!

Androidプロジェクトの作成

Android Studioで新規プロジェクトを作成します。
パッケージ名は
com.example.opencvfacedetection
とします。

プロジェクトの設定/OpenCVモジュールのインポート

UnityにインポートするAARファイルを作成するために新しくModuleを作成します。
プロジェクトを右クリック>New>Module>Android Library
名前はlibとします。
パッケージ名は
com.example.opencvfacedetection.lib
となるように修正します。

次に、AndroidでOpenCVを使う準備をします。
OpenCV4Android SDKをダウンロードページから取得します。
現時点での最新の3.4.1を取得しました。
参考:Android OpenCV library

zipを解凍して顔検出用の学習済みデータ、
OpenCV-android-sdk\samples\face-detection\res\raw\lbpcascade_frontalface.xml
をlibモジュール中の
res\raw\以下にコピーします。(rawフォルダはなければ作成します。)

次にFile>New>Import Moduleで
OpenCV-android-sdk\sdk\java
を選択します。
すると
OpenCVLibrary341
というモジュールが追加されます。
OpenCVLibrary341モジュールのbuild.gradleで
compileSdkVersion 14
というのがエラーになっていたのでメインのプロジェクトと同じ24を指定します。

モジュールのインポートが完了したら
File>Project Structure>(左ペイン)Modules>(メインプロジェクト名)>Dependenciesタブ>+ボタン
をクリックして、OpenCVLibrary341モジュールを選択します。

これでやっとAndroidでOpenCVを使う準備が整いました!
これ以降はJavaからOpenCVのクラスを呼ぶことができます。

顔認識Activityの開発

新しくUnityPlayerActivityを継承したActivityを作成します。
つまり冒頭で述べたUnityPlayerActivity Java コードの拡張の方法です。

CustomMainActityというクラスを作成しました。
これがデフォルトのUnityPlayerActivityの代わりに、Unity起動時に呼ばれるようにします。
そのためにはUnityのAssets/Plugins/Android以下にAndroidManifest.xmlを配置します。
(詳細はGithub)

大まかに処理を説明すると、
CustomMainActity起動

OpenCVのクラスでカメラが起動

画像取得時のリスナーで顔認識

認識結果を描画した画像でテクスチャ用Bitmapオブジェクトを作成

OpenGLでテクスチャ作成
となります。

ソースはGithubに上げていますのでCloneしてご確認ください。

ビルド

Gradleメニューのassembleをクリックするとビルドが開始され、
うまくいけば、OpenCVFaceDetection\build\outputs\aar以下にAARファイルが出力されます。
(エラーになった場合Build>Clean Projectをしてからやり直してみてください)
また、OpenCVのARRもビルドします。
成功すると
OpenCVFaceDetection\openCVLibrary341\build\outputs\aar\openCVLibrary341-release.aar
が出力されます。

Unityにインポートしてビルド

出力された2つのAARファイル(lib-release.aar、openCVLibrary341-release.aar)
をUnityのAssets>Plugins>Android以下にコピーします。

また、OpenCV SDKの中に
OpenCV-android-sdk\sdk\native\libs\アーキテクチャ名
の下にOpenCVの機能をJavaから呼ぶために必要な.soファイルが入っています。
アーキテクチャはいろいろあるみたいですがひとまずここでは
armeabi-v7aとx86だけ対応することにします。
OpenCV-android-sdk\sdk\native\libs\armeabi-v7a\libopencv_java3.so

OpenCV-android-sdk\sdk\native\libs\x86\libopencv_java3.so
をAssets/Pulugins/Androidの下の同じアーキテクチャ名のフォルダにコピーします。

実行

動作するとこんな感じになります。
1280×720で実行しています。
端末はMoto g5という結構お安めの機種です。
それでもかなりサクサク動作しています。

ハマりどころ

Android+OpenGLを扱ったことがなかったのでテクスチャ生成に手間取りました。
ひとまずちゃんとテクスチャが生成されているかサンプルプログラムを動かしてみたり。

UnityからAndroidのアクティビティを呼ぶときのスレッドの違いが腹落ちできていません…。
createTexture()を読んだ時のポインタの値は同じなのにテクスチャが更新されなかったりといろいろハマり、
結果今の様になっています。

Unityでビルドするとエラーが出ました。

CommandInvokationFailure: Gradle build failed. 
C:/Program Files/Android/Android Studio/jre\bin\java.exe -classpath 
"H:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-4.0.1.jar"
 org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx2048m" "assembleDebug"

stderr[

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'gradleOut'.
> Failed to find Build Tools revision 28.0.0

BuildSettingでBuild SystemをInternalにする。
or
こちらで解決。

おまけ: UnityでOpenCVを使う他の方法

今回の方法を使う前は、以下の構成をとっていました。

Unity
|- WebCamTextureを使ってカメラ画像を取得
|- カメラ画像のポインタをC++に渡す
C++
|- OpenCVで顔認識
Unity
|- 顔認識結果(画像の座標)をC++側から取得、表示

こちらの方が構成としては簡単です。
しかし、恐らくWebCamTextureから取得できる画像データのフォーマットをうまくcv::Matに変換できなかったせいだと思うのですが、
全然顔認識されませんでした。
Android OpenCV libraryに付属のサンプルではかなり高速&正確に顔認識されていたので、
Unityからその部分を拝借する構成にしました。

Unity、C#で日本語入力

今年の夏くらいから、友人とにわかにUnityでゲーム開発を始めました。

お互い本業もあるので超スローペースでぼちぼちやっています。
そんなUnity初心者が一番最初にぶつかる壁は、

「Unity標準のIDE(MonoDevelop)では日本語入力できない」

ことではないでしょうか。

ちなみに僕らは言語はC#を採用しました。
WindowsならVisualStudioを使えばいいところですが、僕も友人もMacユーザなのでVSは使えません。

調べてみると
・SublimeText
・Xamarin
あたりが有力候補のようです。

で、最初はMonoDevelopの存在はスルーして他のIDEを探していたのですが、
あ、最新のMDにすれば入力できる様になってたりしないかな…と淡い期待を抱いて、
MonoDevelopのサイトから最新バージョン(4.0.13)をインストールしてみました。

するとなぜか「XamarinStudio」ってのをインストールする事になるんですよね。
ちょっとこのへんよくわからないのですが(;´Д`A MonoDevelopはXamarinStudioってのに変わるってこと???
そんな戸惑いは一旦置いておいて、とりあえず、マニュアル通り、
XamarinStudioとMono+GTK#をインストールしました。

XamarinStudioはUIもきれいでなんだか使いやすそうな感じ。

さっそく、Unityの設定から外部エディタにXamarinStudioを指定して使ってみたところ、
日本語入力も出来る!
補完もいい感じ!
で、今のところXamarinStudioで開発しよう、ってことになってます。

ちなみにGameObjectインスタンスとかの補完は一旦XamarinStudioでUnityのプロジェクト(ソリューション?)を開いてやればちゃんと補完される様になります。

まだ、少しさわっただけなので使っていくうちに問題が出てくるかもしれないけど、
その時はまた追記します。
今はやっと日本語コメントを楽に書けるーっていうので満足しています^^

fuZe VJKitの使い方

先日お世話になったfuZe powered by Unity
そこで使用したVJKitがとても面白く、Unity初心者がUnityの基本機能を学ぶにはうってつけだったので、
自分の備忘録も兼ねて、使い方をメモしておきます。

説明が正確でないところもあるかと思いますm(._.)m
不明点はコメントいただくか、Unityの入門書などを参考にしてみてください。

Unityをダウンロード/インストールする

まずUnityをダウンロード。
バージョンは4系でなくてはいけません。
ここからダウンロードできます。

※ユーザ登録とか細かい設定とかあった気がしますが、すみませんそのあたりはメモし忘れました。
でもそんなに難しい事はしなかったはず。。。

fuZe VJKitをダウンロードする

次はfuZe VJKitをこちらからダウンロード。
「ZIP」ボタンを押すとダウンロードされると思います。

中にはUnityのプロジェクトパッケージとREADMEが入っているはずです。
READMEには楽曲に関するライセンスが書かれているので、
作った作品をYouTubeなどにアップする際は、こちらをよく読んでください。

Unityで新規プロジェクトを作成する

無事Unityが起動できたら、メニューの
File>New Projectを選択して適当な名前で新しいプロジェクトを作成します。

いろいろなウィンドウが並んでいて初めてだと意味不明な感じでしょうか…。
簡単に各ウィンドウの説明を書いておきます。

Scene
このシーンを設定する3D空間です。シーンとは名前の通りプロジェクト(例えばゲーム)を構成する1場面の事ですが今はまだ深く考えなくていいでしょう。
Game
シーンが実行される画面です。画面上部中央の再生マークを押すとこのウィンドウ内でシーンが動き始めます。
Hierarchy
シーンに含まれているオブジェクトの一覧です。
Project
そのプロジェクトに含まれるオブジェクトやスクリプトなどの一覧です。
Inspector
選択したオブジェクトのプロパティが表示されます。

ちなみにここ↓の「2by3」というセレクト項目をいじるとウィンドウのレイアウトを変更できます。
スクリーンショット 2013-03-20 19.58.31
また各ウィンドウはドラッグ&ドロップで好きな位置に持っていく事が出来ます。
僕は2by3というレイアウトを選択後、ProjectウィンドウをHierarchyウィンドウの下に持ってくるレイアウトが好きです。
こんな感じ↓
スクリーンショット 2013-03-20 19.58.29

VJKitをUnityプロジェクトにインポート

次はVJKitをこのプロジェクトで使えるようにします。
Unityが起動した状態で、ダウンロードしたVJKitのフォルダに含まれる、
fuZe_VJ_StarterKit_v(バージョン番号).unitypackage
という名前のファイルをダブルクリックします。
するとこんな↓ウィンドウが出てくると思うので、右下のImportボタンをクリックします。
スクリーンショット 2013-03-20 20.12.18
無事にインポートできればProjectウィンドウにVJKitというフォルダが作成されます。
以上で準備は完了です!

サンプルシーンを実行してみる

VJKitフォルダの中に、
SampleScenesという名前のフォルダがあるのでダブルクリック。
中にはあらかじめUnityの中の凄い人が用意してくださったいくつかのサンプルシーンがあります。
どれでも良いのでダブルクリックしてみましょう。
「シーンを保存しますか?」的なダイアログが出てくるかもしれませんが、
「Don’t Save」でOKです。

するとSceneウィンドウとGameウィンドウに何か表示されたと思います。
ここで画面上の再生ボタンを押してみます。

音楽が鳴って何かオブジェクトが動き出したら、
おめでとう! これであなたも今日からUnityユーザの一員です!笑

スクリーンショット 2013-03-20 20.42.54

Hierarchyウィンドウに表示されているオブジェクトを選択して、
Inspectorウィンドウの数字などをいろいろいじって遊んでみましょう。

VJKitの構成やキーとなるオブジェクト

「いろいろいじって遊んでみましょう」
と言われたところで全然意味分からないと思うので、
VJKitの構成や特に重要な役目をするオブジェクトについて軽くメモしておきます。

まずVJKitのフォルダ構成です。

SampleScene
先ほども説明しましたが、あらかじめ用意されたサンプルシーンです。
まずはこちらから始めましょう。
Preset Items
あらかじめ色々な設定が済ませてあるオブジェクト達が入っています。
これらはSceneウィンドウにドラッグ&ドロップするとすぐに使用できるので、
始めはここにあるオブジェクトを使ってみて、
どんな設定がされているのかをみてみると良いと思います。

次に重要な役目をするオブジェクトです。

AudioPlayer
音楽を再生するオブジェクトです
VJManager_8Spectrum
AudioPlayerの鳴らす音を聞いてビート解析をするオブジェクトです。音を8種類に分けます。
VJManager_HighMidLow
これもビート解析をするオブジェクトですが、こちらは音を高音、中音、低音の3種類に分けます。

チュートリアル: キューブを音に合わせて動かす

まず適当にキューブをおいてみます。
メニューの
GameObject > CreateOther > Cube
を選択。
するとSceneウィンドウにキューブが登場します。
このキューブを選択した状態でInspectorウィンドウをみると、
一番下に
「Add Component」というボタンがありますのでクリック。
VJKit > Modifiers > GameObjectPropertyを選択。
新しく「VJGame Object Modifiers(Script)」という項目が追加されます。
これが、MJManagerと連動してこのオブジェクト(キューブ)の属性を変える役目を果たします。
全部は説明しきれませんが、次の様な設定項目があります。

Manager
VJManagerの種類を選択します。
DatSource
VJManagerで解析する音の種類を選択します。
ここで選択された音によってオブジェクトのプロパティが変化します。
Boost
変化量を”ブースト”させます。変化があまり見られなかったらここの値を増やしてみましょう。
Value Min/Value Max
変化の最小値/最大値です。
Property To Modify
変化させるプロパティを選びます。
例えば「Position_X」を選ぶと、音に反応してそのオブジェクトのx軸方向の位置が変化します。

以上、凄く簡単でしたがfuZe VJKitの使い方でした〜。