lab/技術情報 最終更新日:2010-11-21 (日) 15:06:00

android NDK revision 4b

  • android NDK r4bについてのメモ。
  • android端末で画像処理をする。DalvikVM経由ではいかんせん遅いらしい。JNIを使ってVMを経由せずにコードを実行することで、高速化をはかる。
  • NDKでは、androidからJNIを使うためのコンパイラを提供する。cで記述したコードをNDKでコンパイルしてライブラリ化(.so)。ライブラリをandroidアプリからコールする。

目次

環境

  • PC
    • ubuntu 10.4 (のハズ)
    • eclipse (helios)
  • android
    • Softbank Desire (root取得し、ANDROID2.2(froyo)をインストール済み)

インストール

  • JDK 1.6 ... 問題無し
  • eclipse (helios)
    • eclipseのインストールは本家サイトからtar.gzをDLしてくること。ジャンク☆ニュース 臥龍にあるように、apt-getでインストールしたeclipseだとandroid sdkがうまく入らない。
  • android sdk ... 問題なし
  • android ndk ... 問題なし

てすと

NDKに付属のテスト”hello-jni”をビルドしてみる。

  • DalvikVM上で動作する側のHelloJni?.javaは、eclipseにてAutoBuild?されるようになっている。問題無し。
  • 呼び出される側のhello-jni.cのビルドはeclipseではAutoBuild?されない模様。 コマンドラインから
    % ndk-build
    すると、Android.mkに記述されたコマンドが走り、.soファイルが1つ上位階層のlibsディレクトリに生成される。
  • 実機でHelloJni?.javaのコンパイルしたものを走らせてみる。うまくいったぽい。 helloJni.png

openCVは動くのか?!

  • Androidの移植が進んでいることは以前から知っていた。実際に手元の実機で試してみる。
  • 「なんとなく実験 with SIProp開発記」の2009年10月23日のポスト、OpenCV Ver.1.1 For Android NDK の メンテチームが結成されました。にしたがってみる。
  • プロジェクトサイトに上がっているライブラリはNDKのrev.3向けである(last commitは2010/3/9で開発が止まっている)。rev.4でビルドした手順は以下のとおり。
    1. <android-ndk-root>/samples/testOpenCV/jni/ なるディレクトリを作る。その下にライブラリをDLしてできた中身を展開。つまり、<android-ndk-root>/samples/testOpenCV/jniの下に、cv cvauc ml cxcoreなどのディレクトリができることとなる。
    2. <android-ndk-root>/samples/hello-jni/AndroidManifest?.xml を <android-ndk-root>/samples/testOpenCV/ にコピー
    3. <android-ndk-root>/samples/testOpenCV/ にて
      ndk-build
      すると、<android-ndk-root>/samples/testOpenCV/tests/VideoEmulation?/libs/armeabi/libopencv.so なるライブラリがビルドされる。

画像キャプチャ系サンプルのコンパイル

  • <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" />
  • いけたぽい
    cameraConfigurationCopy.jpg

画像処理系サンプルのコンパイル

  • ようやく本題(のスタートラインに立つか立たないか、くらい。。。)
  • http://www.stanford.edu/~zxwang/android_opencv.html にてextractSURFFrature()なる関数を呼んでいるサンプルがある。このサンプル本体のコードは、こちらから入手すればよし。
  • openCVのライブラリ(libopencv.so)はさっきコンパイルしたものを流用。
  • いけたぽいよ
    extractSURFFeature.jpg

bad know-how

JNIメソッド名にアンダースコアを入れるとエラー

  • 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ファイル)に反映されない。

  • ライブラリを再ビルドしたことを何らかの形でコンパイラ?eclipse?に伝える必要あり。とりあえず今はコマンドラインから.apkファイルを削除して、再ビルドしている。
    rm <project_root>/bin/FooBar.apk
  • そんなんでええのんか

comments

#comment_kcaptcha


添付ファイル: fileextractSURFFeature.jpg 341件 [詳細] filecameraConfigurationCopy.jpg 356件 [詳細] filehelloJni.png 334件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-11-21 (日) 15:06:00 (4898d)