喋る同人誌が作りたい!② OpenCV編
前回,Android OSのAPI(android.camera2)を直接利用することでカメラを使っていましたが,後の画像処理を見据えてOpenCVを使ったカメラ利用の実装にしていきたいと思います.
前回
…とその前に,前回スルーしていたエラーを消しておきます.
※ Gradleのバージョンアップ(3.x→4.4)で治りました.
Error:Execution failed for task ':app:preDebugAndroidTestBuild'. > Conflict with dependency 'com.android.support:support-annotations' in project ':app'. Resolved versions for app (26.1.0) and test app (27.1.1) differ. See https://d.android.com/r/tools/test-apk-dependency-conflicts.html for details.
ざっくり訳すと,「アプリのバージョン(26.1.0)とテストのバージョン(27.1.1)が違うので直せ」って感じ.アプリのバージョンはプロジェクト作成時に選ぶKitKatとかMarshmallowとかのあれですが,テストのバージョンなんていじってないぞ…(^ω^;)新しいプロジェクトを作っただけで出てくるのでいかがなものかとも思いますが.(環境の問題?)テストのエラーなのでapkは作れます.が,気持ち悪い&後々テストコード書くときに困るので直します.
最も一般的そうなソリューションがコレ.build.gradleにandroidTestCompile 'com.android.support:support-annotations:26.1.0'と書く. increment.hatenablog.com
でも何故かGradleが認識するテストのバージョンが変わりません.更に調べていると,依存しているモジュール内に27がある的な情報が…build.gradleに次のように書きます.
androidTestCompile 'com.android.support:support-annotations:27.1.1' compile 'com.android.support.test:runner:1.+'
これ通りにやれば解決したのですが,testが27,appが26って言われてるのに,androidTestCompile 'com.android.support:support-annotations:27.1.1'を書いて通る意味が分からない…あとrunner:1.+で明示を避けるのも釈然としません.そして更に他のソリューションが,
www.youtube.com 要約するとbuild.gradleの
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
を次のように修正する
androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
明示的にテストのバージョンを落としているのでさっきのよりはまだマシな気がします.(結局中身についてはイマイチ理解できていませんが…)
それでは本命のOpenCVをインポートしていきます.
AndroidのOpenCVは基本的にCで書かれたネイティブなライブラリをJavaでラップしたものです.(もちろん自分でラッパーを実装する方法もあるけど超面倒くさい)ですので,1)AndroidStudioにJavaのライブラリをインポート.2)ネイティブのライブラリをインストール.という二つの手順が必要です.具体的な操作は次のようにやればOKですが,この記事少し間違っているみたいで,2の手順はネイティブライブラリをapkに埋め込む場合の方法です.この埋め込みタイプは公式でも非推奨ですが,個人的には多少の非合理性よりもユーザーの操作数を減らすことの方が重要だと考えているので,このままいきます.(なので,OpenCV Managerをユーザーがインストールする必要はありません)しかし,またもや私の環境ではエラーが出ました.
Error:Execution failed for task ':app:transformNativeLibsWithStripDebugSymbolForDebug'. A problem occurred starting process 'command 'C:\Users\huser\AppData\Local\Android\Sdk\ndk-bundle\toolchains\mips64el-linux-android-4.9\prebuilt\windows-x86_64\bin\mips64el-linux-android-strip''
commandが何を意味しているのかよくわかりませんが,とにかくmipsのライブラリが原因のようです.app/src/main/jniLibs/内のmipsとmips64を消します.するとエラーは消えました.(どうせスマホのCPUなんてほとんどARM,ほんのりx86でしょ)
確認のためにapkの中身を見てみましょう.apkは実質zipなので拡張子をzipに変更すれば解凍できます.
おったー!
取り敢えずこれがSUCCESEになることを確認したら,めでたくOpenCVのセットアップ完了です.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(!OpenCVLoader.initDebug()){ Log.i("OpenCV", "Failed"); }else{ Log.i("OpenCV", "successfully built !"); } }
OpenCVのAPIからカメラを使います.
前回,AndroidOSのAPI(android.camera2)を叩いた時はかなりコードが長く複雑になりましたが,その点OpenCVはレガシーなAPIのラッパーであることもあって(android.camera)かなりシンプルです.でも,公式でも非推奨になったAPIを使ってるので不安ですよね…いっそこれを参考にcamera2のラッパーに改造して使った方がいいのかもしれませんが,めんどくさい.
public class MainActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener{ private CameraBridgeViewBase mCameraView; private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { if (status == LoaderCallbackInterface.SUCCESS) mCameraView.enableView(); else super.onManagerConnected(status); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mCameraView =findViewById(R.id.camera_view); mCameraView.setCvCameraViewListener(this); } static { // ネイティブライブラリ読み込み System.loadLibrary("opencv_java3"); } @Override protected void onResume() { super.onResume(); mLoaderCallback.onManagerConnected (LoaderCallbackInterface.SUCCESS); // OpenCV Managerつかうならこっち // OpenCVLoader.initDebug()で切り分けるのがお行儀良い // //OpenCVLoader.initAsync( // OpenCVLoader.OPENCV_VERSION_3_0_0, // this, mLoaderCallback); } @Override public void onCameraViewStarted(int width, int height) { Log.d("CvCamera","Start"); } @Override public void onCameraViewStopped() { } @Override public Mat onCameraFrame(Mat inputFrame) { return inputFrame; // 30fps固定らしい } }
参考
実行結果
けだまきちゃんとゆかりさんの可愛さに心に染み渡ります.また最近,A5の同人誌(B5は専用ケースx2に収納)やVOICEROIDを収めるために技術書が追いやられて床にスタックされていますw
向きやスケールが滅茶苦茶ですが,取り敢えずCVのカメラで表示することができました.これをうまく合わせるにはやっぱりMat→BitmapにしてImageViewにはっ付けるしかないのでしょうか?それなら前回のcamera2を使ったものの方がいいような気さえします.具体的な画像処理はonCameraFrameの引数であるMat(画素行列)をCVの関数でエイヤッ↑↑として返り値に渡せばOKです.OpenCV自体はそれなりに使った経験があるので一山超えた気分ですね.
全然関係ないですが,先日VOCALOIDのV4 flowerさん(花ちゃんさん)をお迎えいたしまして,VOCALOIDマスターデビューしました!(ドンドンパフパフ
尚,私は中学時代リコーダーも碌に吹けなかった以来ほぼ楽器に触れていないどころかカラオケすら何年も行っていないのでお察しです…(´;ω;`)でもこれで堂々と花ちゃんさんを愛で愛でできるようになりました!HIPHOPが好きなのでいつの日にか花ちゃんさんとBro.Hiみたいなラップができるように頑張っていきたいと思います.