まりま

個人的備忘録 MyReferenceManual

ライセンス問題

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

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

前回は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

 

AndroidStudio2.0でOpenCV3.1(sample編)

 ちょっとアイデアが浮かび、Androidで画像処理を利用したアプリを作りたいな~と思ったので古くなったAndroidStudio1.5+OpenCV3.0の環境を更新し、AndroidStudio2.0+OpenCV+3.1へ移行することに。AndroidStudio+OpenCVの環境構築というのはn番煎じでしょうが、自分用メモも兼ねて公開します。

 なお、ここでの説明ではOSはWindows8.1を使い、AndroidStudio2.0とNDKは既にインストールされているものとします。NDKはr12を使用します。

概要

まずこのページではOpenCV for Androidのダウンロードから簡単なサンプルの動作までを行います。NDKが必要なサンプルのビルドや自作ソフトにOpenCVを組み込む、というのは後日行います。

1.OpenCV for Androidのダウンロード

 OpenCVの公式ページからOpenCV for Androidをダウンロードします。公式ページ右側のLATESTDOWNLOADSからOpenCV for Androidをクリックすることで最新バージョンのダウンロードが出来ます。又、画面上の目次からDOWNLOADSをクリックすることで開くDownloadページでは最新バージョンを含めたこれまでのバージョン全てのダウンロードリンクが纏められているのでそちらでダウンロードすることもできます。ダウンロード完了後、適当なディレクトリに配置、解凍してください。ここではD:\OpenCV内で解凍したとして説明をします。

2.AndroidStudioにサンプルをインポート

 AndroidStudioを起動し、File→New→Import Projectをクリック、解凍したフォルダ内にあるsamples/15-puzzleを選択します。

f:id:ewvss:20160421004742j:plain

 

Nextをクリックします。

f:id:ewvss:20160421004835p:plain

Finishをクリックします。

これでサンプルのインポートが完了しました。

3.設定の変更

インポートは完了しましたが、この状態ではまだビルドを実行することが出来ません。build.gradleで設定されている、compileSdkVersionとminSdkVersionを適切な値に設定しなければなりません。変更しなければならないbuild.gradleは2つあります。まずはOpenCVLibraryのbuild.gradleです。

apply plugin: 'com.android.library'

android {
compileSdkVersion 14
buildToolsVersion "23.0.3"

defaultConfig {
minSdkVersion 8
targetSdkVersion 21
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}

 恐らくこのようになっていると思います。変更するべき場所はcompileSdkVersionとminSdkVersionです。以下のように変更してください。

    compileSdkVersion 14 → 21に
        minSdkVersion 8 → 21に

変更後はこのようになります。

apply plugin: 'com.android.library'

android {
compileSdkVersion 21
buildToolsVersion "23.0.3"

defaultConfig {
minSdkVersion 21
targetSdkVersion 21
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}

 次にOpenCVSample15Puzzleのbuild.gradleを変更します。

apply plugin: 'com.android.application'

android {
compileSdkVersion 14
buildToolsVersion "23.0.3"

defaultConfig {
applicationId "org.opencv.samples.puzzle15"
minSdkVersion 8
targetSdkVersion 21
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}

dependencies {
compile project(':openCVLibrary310')
}

多少構造は先程のものと違いますが、変更する箇所は同じです。変更後は以下のようになります。

apply plugin: 'com.android.application'

android {
compileSdkVersion 21
buildToolsVersion "23.0.3"

defaultConfig {
applicationId "org.opencv.samples.puzzle15"
minSdkVersion 21
targetSdkVersion 21
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}

dependencies {
compile project(':openCVLibrary310')
}

ここまで変更できたらGradleを同期してください。これでGradleの設定は完了です。

4.プログラムの修正

次にプログラムのエラー箇所を修正します。Puzzle15Activityを開いてください。恐らく下図のようにエラーが発生していると思います。

f:id:ewvss:20160420223213j:plain

このエラーはLog.iメソッドに渡すTAGが23文字を超えて長過ぎる為に発生しています。22行目で定義されているTAG変数を適当に23文字以内になるよう修正してください。これでビルドが出来るようになりました。

5.ビルド&実行

ビルドして実行をする前にまだしていない方はAndroidにOpenCVManagerをインストールしてください。

play.google.com

AndroidをPCとUSB接続し、実行してみてください。成功すればAndroid上でカメラの画像が15個に分割されバラバラに並べられたパズルアプリが起動します。カメラの画像が写っていない空欄の横にある欄をタッチすると空欄と場所が入れ替わる、15パズルのようです。

 

これでAndroidStudio2.0でOpenCV3.1のサンプルプログラムのビルドと実行は終了です。お疲れ様でした。次回はNDKを使ったサンプルプログラムのビルドと実行をします。

次回:

mlcppcnncpppp.hatenablog.com

mbedが公式にC++11に対応したら

f:id:ewvss:20160420233818p:plain

 これは普通のタイマー割り込みLチカコード。たかだかLEDを点滅させるという一行だけの処理にわざわざ関数flip()を定義していてとても無駄に見えます。

f:id:ewvss:20160420233819p:plain

 これはラムダ式を利用したタイマー割り込みLチカコード。さきほどのプログラムと完全に同じ動作をしますが、ラムダ式を利用することによりコードがよりすっきりしています。見た目がよくなっただけではなく、関数の名前を考える必要が無いという命名の苦手なプログラマには嬉しい効果もあります。苦手でなくとも、割り込みで動作させる関数が複数あり、それらの関数の動作が非常に似ている場合などは関数名を考えるのは少し大変ですし、量が増えてくると関数定義が多すぎて読みにくい&命名の手間が関数の数だけかかる、というつらいプログラムが出来上がってしまいます。早くmbedも公式でC++11以降に対応して欲しい…と願う僕でした。

 

ちなみに、現状ではオフラインIDEを使う、Cloud9や自前のLinuxにmbedコンパイラを導入し、Makefileを書き換える、と言った方法でC++11やC++14の機能を使うことが出来ます。最先端を行きたい(今時の本当の最先端はC++17なんでしょうが...)という方は挑戦してみてはどうでしょうか。

 

mbedとArduino

 お手軽二大マイコン弄り環境としてmbedとArduinoがあります。どちらもマイコンを扱う上で必要なレジスタとかそういう小難しい知識を知らなくても、開発者の思うようにポート入出力を行い、計算をし、制御することが出来ます。最近だとロボコンに活用しているチームも幾つかあるのではないかと思います。簡単に出来るということは決して初心者だけにメリットがあるわけではなく、マイコンの扱いに慣れたような人でも開発スピードを早める事ができ、大会までに限られた時間を有効に使えるようになるはずです。僕の所属するチームでも最近そういった理由で、僕が主体となって開発スピードを上げるためにPICからmbedへと開発環境を移行しました。

マイコンを容易に扱うことのできるこの2つのシステム、何が違い、どちらが優れて、使うべきはどちらなのか。結論から言ってしまうと、僕はmbedが優れていると判断し、だから僕のチームでもmbedを採用することにしました。以下にその理由となる根拠を示します。

1.コスパが良い

 物を作るためには当然ですがお金がかかります。なので、コスパの良い製品を選び、お金を有効に使う事は良い物を作る上で必要なことです。以下の表はmbedとArduinoマイコンの価格と性能をまとめたものです。mbedからはNucleoF401REとLPC1114FN28、ArduinoからはArduino M0とArduino Pro miniを用います。これらを選んだ理由はそれぞれで探した中でコスパが良いと個人的に感じたものだからです。

製品名価格[円]bit周波数[MHz]RAM[KB]Flash[KB]
NucleoF401RE 1,900 32 84 96 512
LPC1114FN28 216 32 50 4 32
Arduino M0 3,240 32 48 32 256
Arduino Pro mini 355 8 16 2 32

 価格はページ作成当時の物です。現在の価格やさらに詳細な性能は表下の各製品のamazonへのリンクで確認してください。この表にあるスペックが全てではありません。ピン性能やボードに備わった電源性能なども考慮した上で考える必要がありますが、とりあえずCPUの処理速度に関係するスペックについて纏めた表です。こうして並べると、mbedのコスパの良さが際立つと思います。特にたった216円のLPC1114FN28のメモリ周りを除けば3000円以上のコストがかかるArduino M0に匹敵する性能を持っていることは凄まじいと感じます。但し、前者はマイコン単体、後者はマイコンボードであり、電源やUSB接続等のインターフェースは後者のほうが充実していることにも注意が必要です。なお、NucleoF401REもマイコンボードであり、電源として幅広い電圧(3.3V~12V)に対応し、ピンは5Vトレラント、ピンの数もこの表の中のもので最多と扱いやすさとコスパを両立しているのでこの中ではもっともおすすめの製品です。特に、この中でFPUを積んでいるのはNucleoF401REのみなので、浮動小数点型が絡むような高度な演算、制御を行う場合は実質これしか選択肢がありません。

2.プログラミングの方法が明快である

 mbedはC++98(もしかしたら03かな?)を使いプログラミングを行えます。そのため、PC向けソフトの作成で得た知識や経験などをそのまま活かす事ができます。しかし、ArduinoC++を"元にした"Arduino言語を使います。これはC++とは似て非なるものなので、慣れるまでは結構使いにくかったりします。全くプログラミングなんてしたことがない!という人向けには確かに使いやすく作ってあるのかなぁと思うところもあります。実際C++未経験者にC++でプログラムを書けというのは結構厳しいところもありますし。しかし、独自の言語というところからくる言語仕様がなんだかよくわからないというのは既にある程度プログラミングをこなしている自分にとってはちょっと受け入れられませんでした。

3.IDEが便利

 mbedはIDEが非常に便利です。クラウドIDEなので開発環境をわざわざ新しいPCにインストールする必要もない上、作ったプログラムやライブラリをそのまま公開、チームで共有することが可能です。但し、時々メンテナンスが行われ、使えなくなる時があるなど、クラウドならではのデメリットも存在します。ArduinoIDEもインストール自体は簡単ですが、やはりコードの共有をしようとすると一旦githubに上げるとか別のサービスを介さなければならないのは多少不便です。

4.コミュニティが活発

 mbedはコミュニティが活発で、大量のライブラリがユーザーの手で開発・公開されており、そのライブラリはmbedのコミュニティサイトの中で容易に探し出して自作のプログラムの中に組み込む事が可能です。Arduinoでもライブラリはある程度多く出回っていますが、mbedのようにどこか一箇所にライブラリが集まっていてそこから検索することですぐさまライブラリを自作のプログラムにインポートできるような仕組みは無く、多少手順が増えるので面倒だと感じました。

5.種類が豊富

 mbedはArduinoよりも種類がたくさんあります。その為、用途に合わせて超高速なCPUを積んだもの、価格を抑えたもの、シリアル通信等通信機能をたくさん載せたもの、DSPの使えるもの、DACが出来るもの、など様々な種類の中から最適な物を選択することが出来ます。対してArduinoは基本的にはそんなに種類は多くなく、mbed程の選択の自由はありません。

 

ざっとこんな感じですね。mbedは最初からある程度マイコンやプログラミングに対して知識があるような人には使いやすく、Arduinoはこれが初めてのマイコンでプログラミングとかあんまりしたことないって人には触れやすいものだと思います。なのでロボコンに参加するような元々ある程度の技術力があるようなところの場合、mbedを使うとしっくりくるだろうし、デザイナーのような普段余りプログラミングに縁が無いような方はmbedは少し敷居が高いのでArduinoから触れてみると良いかなぁと思います。

バックアップは取ろう

f:id:ewvss:20160416175904j:plain

 

自作ソフトの話。Qtの練習の為に作ったこのソフトはTextの部分に

 

f:id:ewvss:20160416180903j:plain

 

このように適当に文字を入れてやると

 

f:id:ewvss:20160416180923j:plain

 

こんな感じにいい感じに見やすくボードの画像に文字を出力してくれる。設計の情報伝達とかの為にそれなりに役に立ってくれたがソースコードの方はとても人に見せられないような汚いものだった。このソフトを作った当時(1年くらい前だったかなぁ...)、自分は一体どんなコードを書いていたのか、ちょっと気になったのでソースコードを探してみるもどうやら消失してしまったらしく…バックアップはしっかり取っておこうと思った出来事でした。当時はgitの使い方もあまり分かっておらず、もっと早く身に付けておくべきだったなぁと。まぁ今もはっきり言って使えてるとは言えない状況ですけどね

Not compatible with Windows

Andoird SDK Managerを開くとAPI13以下のSDK PlatformがNot compatible with Windowsに。

f:id:ewvss:20160414004015p:plain

StackOverFlowにも同じような質問が。単純にAPI古すぎるから新しいのを使えとの事らしい。どうしても古いAPISDKが必要な場合に入手する方法もあった。

Download Android SDK standalone for offline installation | Quakeboy'z Dev Arena

stackoverflow.com

 

しかし、いつの間にかGingerbread以下のシェアが2.7%にまで落ちてるとは…時の移り変わりというのは早い。でもよくよく考えたら5年以上も前のOSだし妥当なんだろうなぁ…