まりま

移転しました→5hyn3.github.io

C++で関数テーブルを作る

 条件に合わせて行う処理を切り替える時、ただ単に分岐するよりも関数テーブルを作ってそれを利用したほうが可読性が増します。しかし、ポインタを弄ったりして関数テーブルを作るのは意外と骨が折れます。ここではC++11の機能を使ってお手軽に実装できる関数テーブルを紹介します。

 これだけのコードで関数テーブルが実装できます。クラス内でメンバ関数を登録する場合は

functionTable["foo"]=std::bind(&Classname::Funcname,this,std::placeholders::_1;

とstd::bindの中身を書き換えてやると良いです。

Courseraの機械学習コース受講終了

f:id:ewvss:20160515230011p:plain

3月中頃から始めてようやく終わりました…長かった…でも、楽しかったですし、最後のビデオを見終わった時は感無量でしたね。これからどうしようかなぁ…とりあえずTensorFlowとCaffeやChainerあたりを触ってみましょうかね。元々去年辺りから機械学習の技術に触れてそれらライブラリを触ってみるも知識の無さに打ちのめされたので受講したわけですし、兎にも角にも自分にお疲れ様です。

 

なお、お金がそもそもそんなに無かった上、入金する手段も無かったので修了証はありません。そこだけちょっと後悔してますが、まぁ欲しかったらまた受ければいいので。

Activity不在のServiceから別のServiceを起動するとServiceが落ちる話

移転のお知らせ
ブログはこちらに移転しました。現在はこちらで更新をしています。

https://5hyn3.github.io/

 

Activity起動中、もしくはバックグラウンドでまだActivityが生きている時には正しく動作する、しかしActivityを殺してから操作するとエラーでサービスが落ちる、しかもその内容はデバッグログに上がってこない上至る所でLog出力をさせてもServiceが落ちてしまう場所が変わってしまう。

 こんな現象があり、デバッグのしようもなく途方に暮れていましたが、Logcatの出力から自作アプリのみのフィルタを外し、全出力を閲覧した時、ようやく原因が分かりました。サービスから起動した別のサービス上でandroid.os.DeadObjectExceptionが投げられていました。どうやら、Activityから起動したServiceが、Activityが死んでいる状態でさらに別のServiceを起動する場合には、起動対象のServiceを別プロセスに分離しなければならないようです。ということでandroidmanifest.xmlandroid:process属性を追記してやってデバッグ完了です。

参考

d.hatena.ne.jp

AndroidStudio2.0でパッケージ名の変更

 AndroidStudio2.0以降でパッケージ名を変更する場合もこれまでと大差無い方法で変更できますが、このバージョンではアプリを検索されやすくするというApp Indexingの為のコードを自動生成する機能が付いています。

App Indexing  |  Google Developers

本来なら自動生成したらそのままさわらないで良いはずです、実際そのほうがアプリをいろいろな人にみてもらえるそうですし。しかし、コードを自動生成後にパッケージ名を変更するとビルドは通りますがなぜか動いてくれません。自分の手で作ったソースの変えなければいけない所すべての部分においてパッケージ名を適切に変更しても自動生成されたコード内でエラーが発生してしまいます。こうなってしまえばもうお手上げで、自動生成された部分を消すしかありませんでした。パッケージ名はよく考えて付けましょう。

ライセンス問題

 私はライセンスについてちょっとうるさいです。というのも、フリーのオープンソースライブラリを使わさせていただいている立場なのだから、そのライブラリのライセンスを守ることは最低限のそのコミュニティに対する礼儀として必要な事だと考えているからです。しかし、周りを見ると部活で作った公開範囲の小さなプログラムには著作権表示なんてしなくていいだろ、と言った姿勢の方が結構多く…自分が無闇に目くじらを立てすぎな感じもしますが、ライセンスは守った方がいいに越したことはありません。技術のレベルがどうこうとかそういう問題以上に倫理レベルの話で問題を起こしてどうするんだろうと感じるのでこれからもライセンスについてはとやかく言っていこうと思います。

AndroidStudio2.0でOpenCV3.1(sample with NDK編)

移転のお知らせ

ブログはこちらに移転しました。現在はこちらで更新しています。

https://5hyn3.github.io/

 

前回はOpenCV for Androidをダウンロードし、NDKの要らないサンプルをビルドしました。

mlcppcnncpppp.hatenablog.com

今回はNDKの必要なサンプルをビルドしてみます。

1.サンプルをインポートする

 前回と同じ手順でサンプルプログラム「face-detection」をインポートします。

f:id:ewvss:20160422230358p:plain

2.設定の変更

f:id:ewvss:20160422230526p:plain

インポートするとこのようにエラーが発生します。エラーの青文字部分をクリックするとIDEが適切な設定をしてエラーを解決してくれます。次に、このサンプルも前回と同じようにcompileSdkVersionとminSdkVersionを変更しなければなりません。前回の記事を参考に変更してください。

3.NDKの設定

 NDKの設定をします。まず、local.propertiesを編集します。ndk.dirで始まる行がなければ以下の例のようにndkのディレクトリの位置をndk.dir=につづいて入力してください。

ndk.dir=C:\Users\userSdk\ndk

私の環境ではこのndk.dirの行はインポート時にIDE側が勝手に追加してくれていました。次にbuild.gradleを編集します。

f:id:ewvss:20160422235834p:plain

このようになっているのを

apply plugin: 'com.android.application'

android {
compileSdkVersion 21
buildToolsVersion "23.0.3"

defaultConfig {
applicationId "org.opencv.samples.facedetect"
minSdkVersion 21
targetSdkVersion 21

ndk {
moduleName "detection_based_tracker"
}
}

sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir 'src/main/libs' // This is not necessary unless you have precompiled libraries in your project.
}

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
def ndkDir = "C:/Users/user/Sdk/ndk"
commandLine "$ndkDir/ndk-build.cmd",
'-C', file('src/main/jni').absolutePath, // Change src/main/jni the relative path to your jni source
'-j', Runtime.runtime.availableProcessors(),
'all',
'NDK_DEBUG=1'
}

task cleanNative(type: Exec, description: 'Clean JNI object files') {
def ndkDir = "C:/Users/user/Sdk/ndk"
commandLine "$ndkDir/ndk-build.cmd",
'-C', file('src/main/jni').absolutePath, // Change src/main/jni the relative path to your jni source
'clean'
}

clean.dependsOn 'cleanNative'

tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative
}
}

dependencies {
compile project(':openCVLibrary310')
}

このように変更します。変更点はdefaultConfig{}より下の部分で、その部分をコピペし、ndkDirを自分の環境でのndkのディレクトリの位置に差し替えます。次にAndroid.mkを編集します。

f:id:ewvss:20160422233857p:plain

15行、inclueで始まる行にはOpenCV.mkのディレクトリが相対パスで入力されています。これを絶対パスに書き換えます。

f:id:ewvss:20160423000802p:plain

私の環境ではこのようになりました。

4.ビルド&実行

 これでビルドができる状態になりました。ビルドして実行してみてください。画面にカメラの映像が写れば成功です。それを顔に向けると顔を認識して認識した顔を矩形で囲む…はずなんですが、それが一応正しい動作なんですがどうやらOpenCV3.1 for Androidではバグで学習済み分類器のロードに失敗するようで顔認識は出来ません。どうしてもこのサンプルのような顔認識や、他にもカスケード分類器を利用した物体認識をさせたいという方はOpenCV2.4.11を使用するべきだそうです。個人的にはロードが出来ないのならコード内に分類器の文字列を埋め込んじゃえば解決できそうだなぁとは思いますが。後味は悪いですが、とりあえず今回はこれで終了です、お疲れ様でした。次回は自作のプログラムにOpenCVを組み込む手順を紹介します。

参考

AndroidStudioでOpenCVのサンプルを動かす | Workpiles

JNI and Gradle in Android Studio - Stack Overflow

java - Unable to load classifier in OpenCV for Android - Stack Overflow