[[lab/技術情報]] 最終更新日:&lastmod;

*android NDK revision 4b [#v0cf1c43]
-android NDK r4bについてのメモ。
-android端末で画像処理をする。DalvikVM経由ではいかんせん遅いらしい。JNIを使ってVMを経由せずにコードを実行することで、高速化をはかる。
-NDKでは、androidからJNIを使うためのコンパイラを提供する。cで記述したコードをNDKでコンパイルしてライブラリ化(.so)。ライブラリをandroidアプリからコールする。
*目次 [#g640c410]
#contents
*環境 [#re1ad813]
-PC
--ubuntu 10.4 (のハズ)
--eclipse (helios)
-android
--Softbank Desire (root取得し、ANDROID2.2(froyo)をインストール済み)
*インストール [#b1a21d3f]
-JDK 1.6 ... 問題無し
-eclipse (helios)
--eclipseのインストールは本家サイトからtar.gzをDLしてくること。[[ジャンク☆ニュース 臥龍>http://d.hatena.ne.jp/garyo/20100314/p2]]にあるように、apt-getでインストールしたeclipseだとandroid sdkがうまく入らない。
-android sdk ... 問題なし
-android ndk ... 問題なし
*てすと [#k8933080]
NDKに付属のテスト”hello-jni”をビルドしてみる。
-DalvikVM上で動作する側のHelloJni.javaは、eclipseにてAutoBuildされるようになっている。問題無し。
-呼び出される側のhello-jni.cのビルドはeclipseではAutoBuildされない模様。
コマンドラインから
 % ndk-build
すると、Android.mkに記述されたコマンドが走り、.soファイルが1つ上位階層のlibsディレクトリに生成される。
-実機でHelloJni.javaのコンパイルしたものを走らせてみる。うまくいったぽい。
&ref(helloJni.png);
*openCVは動くのか?! [#ua83efa9]
-Androidの移植が進んでいることは以前から知っていた。実際に手元の実機で試してみる。
-「なんとなく実験 with SIProp開発記」の2009年10月23日のポスト、[[OpenCV Ver.1.1 For Android NDK の メンテチームが結成されました。>http://www.noritsuna.com/archives/2009/10/opencv_ver11_fo_1.html]]にしたがってみる。
-プロジェクトサイトに上がっているライブラリはNDKのrev.3向けである(last commitは2010/3/9で開発が止まっている)。rev.4でビルドした手順は以下のとおり。
++<android-ndk-root>/samples/testOpenCV/jni/ なるディレクトリを作る。その下にライブラリをDLしてできた中身を展開。つまり、<android-ndk-root>/samples/testOpenCV/jniの下に、cv cvauc ml cxcoreなどのディレクトリができることとなる。
++<android-ndk-root>/samples/hello-jni/AndroidManifest.xml を <android-ndk-root>/samples/testOpenCV/ にコピー
++<android-ndk-root>/samples/testOpenCV/ にて
 ndk-build
すると、<android-ndk-root>/samples/testOpenCV/tests/VideoEmulation/libs/armeabi/libopencv.so なるライブラリがビルドされる。
**画像キャプチャ系サンプルのコンパイル [#h526bd81]
-<android-ndk-root>/samples/testOpenCV/tests/CameraConfigurationをビルドしてみる。このサンプルはandroid1.6あたりのAPIを使っているため、android2.0ではビルドまでできるものの、カメラが動作しない。
-Dev1Camera.javaの244行目あたりに
 //-------------- Camera's method --------------
なるセパレータがあるので、これの上あたりに次の2メソッドを追加
 protected void setPictureFormat(int format) {
     try {
         Camera.Parameters params = mCameraDevice.getParameters();
 	 List<Integer> supported = params.getSupportedPictureFormats();
 	if (supported != null) {
 	    for (int f : supported) {
 	        if (f == format) {
                    mCameraDevice.setPreviewFormat(format);
                    mCameraDevice.setParameters(params);
                    break;
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
 }
 	
 protected void setPreviewSize(int width, int height) {
    Camera.Parameters params = mCameraDevice.getParameters();
    List<Camera.Size> supported = params.getSupportedPreviewSizes();
    if (supported != null) {
        for (Camera.Size size : supported) {
            if (size.width <= width && size.height <=  height) {
                params.setPreviewSize(size.width, size.height);
                mCameraDevice.setParameters(params);
                break;
            }
        }
    }
 }
-これらのメソッドの呼び出し元であるsetViewFinder() 、capture()を修正:
 mCameraDevice.setParameters(parameters);
となっている箇所を
 setParameters(parameters);
に修正。
-surfaceChanged()メソッドに 
 setPictureFormat(format);
な行を追加。
 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // if we're creating the surface, start the preview as well.
    boolean preview = holder.isCreating();
    setPictureFormat(format);
    setViewFinder(w, h, preview);
    mCaptureObject = mImageCapture;
    startPreview();
 }
-撮影と表示の縦横比を合わせるため、AndroidManifest.xmlに次の行を追加。
 <activity android:name="OpenCVSample" android:screenOrientation="landscape" />
-いけたぽい~
&ref(cameraConfigurationCopy.jpg);
**画像処理系サンプルのコンパイル [#h526bd81]
-ようやく本題(のスタートラインに立つか立たないか、くらい。。。)
-http://www.stanford.edu/~zxwang/android_opencv.html にてextractSURFFrature()なる関数を呼んでいるサンプルがある。このサンプル本体のコードは、[[こちら>http://www.stanford.edu/~zxwang/file/android_opencv_example.tar.gz]]から入手すればよし。
-openCVのライブラリ(libopencv.so)はさっきコンパイルしたものを流用。
//-サンプル本体のコードからJNIを使用してOpenCVを呼び出すところでエラー。エラー箇所は、今回JNIのコードを記述しているcvjni.cppとcvjni.h。見てみるとパッケージ名と関数名の関係が崩れている。
//--java側では net.mona.opencvtest のパッケージ名としている
//--JNI側では edu.stanford.opencv のパッケージ名から Java_edu_stanford_opencv_OpenCV_extractSURFFeature を関数名としている
//-JNI側の関数名をパッケージ名に沿うように変更してビルド。無事呼び出しできた。
-いけたぽいよ~
&ref(extractSURFFeature.jpg);
*bad know-how [#t4166684]
**JNIメソッド名にアンダースコアを入れるとエラー [#r94c5a8f]
-java側で
 package com.hoge;
 public class FooBar{
  public native String foo_bar();
 }
のようにメソッドfoo_bar()を呼び出すと、
-呼び出されるC側で
 jstring Java_com_hoge_FooBar_foo_bar()
のような関数定義となる。
-android-SDK,android-NDKともコンパイルは通る。が実行時に
 java.lang.UnsatisfiedLinkError
が投げられて実行時エラー終了する。
-解決策は、メソッド名のアンダースコアを除去し
 //in java source code ...
 package com.hoge;
 public class FooBar{
  public native String foobar();
 }
~
 //in C source code ...
 jstring Java_com_hoge_FooBar_foobar()
のように定義すればOK。JNIではパッケージ名の区切りにアンダースコアを用いている。その区切りと関数名のアンダースコアがバッティングすると、うまくリンクできないということか。そんなアホな。
**ライブラリを再ビルドしてもJavaのビルド(.apkファイル)に反映されない。 [#u704ffb5]
-ライブラリを再ビルドしたことを何らかの形でコンパイラ?eclipse?に伝える必要あり。とりあえず今はコマンドラインから.apkファイルを削除して、再ビルドしている。
 rm <project_root>/bin/FooBar.apk
-そんなんでええのんか
*comments [#hbf172cd]
#comment_kcaptcha

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS