Android Studio + MOVERIO + OpenCV #1
- モチベーション
- 目標
- 開発環境
- MOVERIOでの開発の難点
- Android StudioとAndroid SDKのインストール
- Android StudioでのOpenCVの設定
- MOVERIO用SDKの設定
- サンプルプログラム
- 結果
モチベーション
とあることをきっかけにEpson MOVERIO BT-300でAndroidアプリを開発することになった.Android Studioはほぼ初見だし,Javaにも親しみがないので,新たな発見や理解に苦労した点なども一緒に述べていきたい.
目標
- OpenCVは画像処理に便利なので,とりあえずAndroid Studioで使えるようにする
- OpenCVを使って,MOVERIOのカメラの画像を取得し,それをMOVERIOの画面に表示する
開発環境
- Windows 10 Home
- Android Studio 2.3.3
- Android SDK 5.1 (Lollipop)
- 自身が用いるデバイスに合ったバージョンを選択する
- 以降の内容は,多分,極端に古くなければどのバージョンでも動作すると思う
- OpenCV 3.3.0
- BT300 SDK 1709
- Epson MOVERIO BT-300
MOVERIOでの開発の難点
結構,色々と躓いた.重要なのでこの時点で書いておく.
- Google Play Storeアプリがインストールされていない&インストールできない
- ハックする方法も色々とある様子だが,今回は特段ハックせずに進める
- Google Play Storeアプリが使えない → MOVERIOをGoogle Play Storeに登録できない → OpenCV Managerをインストールできない
- OpenCVをAndroidアプリに引っ付けて,Androidデバイスに送ることにした
- 結論から書くと,OpenCVのコールバックを使って画像を取得すると妙に画角が狭く表示されて使い物にならない
Android StudioとAndroid SDKのインストール
Android StudioとAndroid SDKのインストール方法は公式サイトなどを参照のこと.色んな記事がWeb上に存在するけれど,公式の内容で十分だと思います.
Android StudioでのOpenCVの設定
結局のところ,以下の質問への回答の通りに設定するのが一番だった.英語なので,日本語で,かつもう少し写真や注意点を加えて以下に説明する.
具体的な手順(全10ステップ)
以下の設定を行えば,OpenCV Managerなるものを入れなくても
- OpenCVを公式サイトからダウンロード
- 私はバージョン3.3.0を選択した
- zipファイルを解凍し,任意のパスへ
- 解凍したフォルダまでのパスをPATHとする
- Android Studioを立ち上げてプロジェクトを新規作成
- OpenCVTestというプロジェクト名にしました
- Android StudioのFile>>New>>Import Module(下図)より,PATH/sdk/javaを選択
- 左のProjectメニュー内に "OpenCVLibrary330" というフォルダができる

- 左のProjectメニュー内に "OpenCVLibrary330" というフォルダができる
- <プロジェクト名>/app/build.gradleにある以下の情報を<プロジェクト名>/OpenCVLibrary330/build.gradleにコピペ
- compileSdkVersion
- buildToolsVersion
- minSdkVersion
- targetSdkVersion

- Projectメニュー内のOpenCVTestプロジェクトを右クリックしてOpen Module Srttings (F4)をクリック
- 現れたProject Structureウィンドウでapp>>Dependenciesを開き,右上にある+ボタンを押してModule dependencyをクリックし,OpenCVLibrary330を選択

- PATH/sdk/native/libsフォルダを丸々コピーして<プロジェクト名>/app/src/mainフォルダ内にペースト
- コピーしたlibsフォルダ名をjniLibsに変更
- jniLibsフォルダ以下に多くのフォルダが存在するが,その各フォルダ内にある.soファイルだけが必要なので,その他のファイル(つまり,.aファイル)は削除しておく
- この記事にあるサンプルプログラムを実行
- 実行するには,緑色の右向き三角ボタン
を押す
- 実行するには,緑色の右向き三角ボタン
MOVERIO用SDKの設定
これは,公式のマニュアル通りに設定(特に「2.3. USBドライバの設定」と「2.5. Epson 提供SDKの組み込み」).
マニュアル
BT300 SDKのダウンロード
サンプルプログラム
MainActivity.java
Javaではクラス名とファイル名が紐づけられているのですね.つまり,1つのJavaファイルに1クラスということ.そういえば,昔に大学で習ったような...
このクラスが名前の通りメインです.OpenCVのカメラの画像取得及び表示用コールバック?であるCvCameraViewListener2を使って,お手軽にカメラからの画像を扱えそうです... と思っていたのですが,この記事の最後に書く通り,色々と問題があるので注意.
20行目にあるOpenCVLoader.initDebug()でOpenCVの諸々の初期化が行われる模様.C++では特段必要なかったので新鮮.OpenGLみたいですね.OpenCV Managerを利用する場合は,52行目のOpenCVLoader.initAsync()を呼ぶようだ.
package com.example.XXXXX.opencvtest; // 上記のXXXXXには自身のユーザ名が入る import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.SurfaceView; import android.view.WindowManager; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.CameraBridgeViewBase; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import org.opencv.core.Mat; public class MainActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 { private static final String TAG = "OpenCV::Activity"; private CameraBridgeViewBase mOpenCvCameraView; static { if (OpenCVLoader.initDebug()) { Log.i(TAG, "OpenCV successfully initializated!"); } else { Log.i(TAG, "OpenCV initialization failed!"); } } private BaseLoaderCallback mLoaderCallBack = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { if (mOpenCvCameraView != null) { mOpenCvCameraView.enableView(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { Log.i(TAG, "called onCreate"); super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_main); mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView); mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); mOpenCvCameraView.setCvCameraViewListener(this); } @Override public void onResume() { super.onResume(); if (!OpenCVLoader.initDebug()) { Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization"); OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_3_0, this, mLoaderCallBack); } else { Log.d(TAG, "OpenCV library found inside package. Using it!"); mLoaderCallBack.onManagerConnected(LoaderCallbackInterface.SUCCESS); } } @Override public void onPause() { super.onPause(); if (mOpenCvCameraView != null) { mOpenCvCameraView.disableView(); } } public void onDestroy() { super.onDestroy(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView(); } public void onCameraViewStarted(int width, int height) { } public void onCameraViewStopped() { } public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { return inputFrame.rgba(); } }
activity_main.xml
Android端末に表示する際の画面のレイアウトがここに記述されている.このXMLファイルを開いた時に現れる,Android Studio画面内の下の方にあるDeisgnやTextタブで切り替えるとXMLを理解しやすい.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/activity_main" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:opencv="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="16dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="16dp" tools:context="com.example.XXXXX.opencvtest.MainActivity"> <!--- 上記のXXXXXには自身のユーザ名が入る ---> <org.opencv.android.JavaCameraView android:id="@+id/HelloOpenCvView" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible" opencv:camera_id="any" opencv:show_fps="true"> </org.opencv.android.JavaCameraView> </RelativeLayout>
AndroidManifest.xml
そもそもの決まり事を書くところの様子.カメラを使うとか,使っちゃダメとか.OpenCVの公式ドキュメントのHello OpenCV Sampleにある様に,カメラを使えるように追記する.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.XXXXX.opencvtest"> <!-- 上記のXXXXXには自身のユーザ名が入る --> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <!-- 以下を追記 --> <uses-permission android:name="android.permission.CAMERA"/> <uses-feature android:name="android.hardware.camera" android:required="true"/> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/> <uses-feature android:name="android.hardware.camera.front" android:required="false"/> <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/> </manifest>
結果
こんな感じで表示された.MOVERIOのグラス部分を通してiPhoneで撮影し,必要な部分だけクロップした.明るくなっている視覚の枠内にカメラで取得した画像が写っている.

問題発覚
SDKについてきたサンプルプログラムのSampleCameraPreviewで見たときより,画角が妙に狭いぞ...??? これに気づいてから,色々と原因を探ってみた.例えば,JavaCameraViewからNativeCameraViewに変更を試みてみるも,そもそもMOVERIO内でアプリを起動できないし,他にもCompatible Screenとやらのせいか?と思いレイアウトを色々といじってみたが,どうにも上手くいかない...
解決方法
解決方法として,MOVERIOのサンプルプログラムの様にAndroid SDKを使って画像のByteデータを取得して,表示する方法に切り替えたが,これは次回に記すことにする.
