Androidアプリ開発 -画像処理をC言語で高速化-
画像を扱う際の問題(1):計算処理の遅さ
前回、セピア画像にする方法を書きました。
Androidアプリ開発 -画像を加工してセピア色にしてみる- | PPl@ce
画像を扱う際の問題点の1つに、計算処理の遅さがあります。
前回の計算式レベルでは実時間に処理出来ますが、さらに複雑になってくるとJavaでは厳しいです。
その問題を解消するために、C言語で高速化してみたので、そのお話を以下にまとめておきます。
※もちろん、Javaがなんでもかんでも遅いわけではありません。
他に、メモリー問題もありますが、それはまた別の話。
そして今、私が苦労している話・・(ヘルプミー)。
JNIを使ってC言語利用
まずは、JNI(Java Native Interface)を使うための流れ。
(1)まず、Android NDKをダウンロードします。
(2)Androidのプロジェクトにjniフォルダーを用意
(3)jniフォルダーにAndroid.mkファイルを作成
記述例は以下のような感じ。
※NDK内のサンプルソースを参考にすると良い。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := filter LOCAL_SRC_FILES := filter.c LOCAL_LDLIBS := -lm -llog -ljnigraphics include $(BUILD_SHARED_LIBRARY)
(4)jniフォルダーにC言語ファイルを作成
C言語内の関数は以下のような感じ。
※全体像は、NDK内のサンプルソースを参考にすると良い。
JNIEXPORT void JNICALL Java_com_sample_filter_filter1(JNIEnv * env, jobject obj, jintArray src, jint width, jint height) { int i, totalPixel; jint* arr =(*env)->GetIntArrayElements(env,src,0); totalPixel = width * height; for(i=0; i< totalPixel; i++) { int alpha = (arr[i] & 0xFF000000) >> 24; int red = (arr[i] & 0x00FF0000) >> 16; int green = (arr[i] & 0x0000FF00) >> 8; int blue = (arr[i] & 0x000000FF); //ここに計算処理を色々と書く。 arr[i] = (alpha << 24) | (red << 16) | (green << 8)| blue; } (*env)->ReleaseIntArrayElements(env, src, arr, 0); }
JNI関数の命名規則があるため、「Java_<完全修飾クラス名>_<関数名>」のような形になります。
最初の2つの引数は決まっていてJNI環境へのポインターと呼び出し側クラス・オブジェクト・インスタンスへのポインターになります。
それ以降の値が、計算をするために渡す値になります。
(5)作成したC言語のファイルをコンパイル
作成したC言語に対して以下のコマンドを呼んでコンパイルします。
- ndk-build
※ndk-buildは、ダウンロードしたフォルダ内にあります。
あとは、Java側から作成したC言語を呼び出すだけです。
現時点での、フォルダ構成は以下のとおりです。
おまけ
JNI周りをいじる際に参考になるのは、Android NDKをダウンロードした際にあったサンプルコードです。
これを実際に触って、アプリに入れてみたり、ソースを改良してみたりするとわかりやすいと思います。
Java側から呼び出し
ライブラリ呼び出し
まず、ライブラリを呼び出します。
/* load our native library */ static { System.loadLibrary("filter"); }
クラスを用意
ここで、先程作成したfilter1を宣言します。
class ImgFilter{ private int[] pixcels; private int width, height; private static native void filter1(int[] pixcels,int width, int height); //宣言 public ImgFilter(int[] pixcels, int width, int height) { this.pixcels = pixcels; this.width = width; this.height = height; } /** * filter1 */ public void filter1() { filter1(this.pixcels, this.width, this.height); } }
上記のようにクラスにしなくて、filter1だけ以下のように宣言して、利用しても問題ないです。
public static native void filter1(int[] pixcels,int width, int height);
呼び出し
あとは呼び出したい箇所で、上記のクラスを呼ぶだけです。
以下のような感じです。
int width = image.getWidth(); int height = image.getHeight(); int pixels[] = new int[width * height]; image.getPixels(pixels, 0, width, 0, 0, width, height); ImgFilter ifilter = new ImgFilter(pixels, width, height); ifilter.filter1(); Bitmap bmp = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888); imgView.setImageBitmap(bmp);
まとめ
C言語を使うと、Javaに比べてかなり高速になります。
ただし、どこで扱うかはどの処理が遅いかをちゃんと計測してから使うのが良いかと思います。
今回のような画像処理のようなものに関しては、メリットがでかいです。
色々やり過ぎると今度はメモリー問題が面倒だったりしますが・・。
参考
広告
関連記事
-
iPhoneアプリ開発 −iOS6からの「写真」へのアクセス問題−
写真を扱うアプリを開発している際に問題になったこと。 ※結構前の話を今更まとめてみる。 * 写真へ
-
Jenkins + iPhoneアプリ(3) -ipaファイルをTestFlightにアップロード-
* これまで - -[http://pplace.jp/2013/01/1192/:title=
-
研究室での進捗報告の方法について、ふと思ったこと
* 以下に加筆・修正して移動しました。
-
Jenkins + DeployGate(1) -DeployGateでAndroidアプリ開発-
TestFlight for Androidが発表されて1ヶ月ぐらいたちますが、音沙汰がありません。
-
WordPressプラグイン「SyntaxHighlighter Evolved」が動かない!?
* 起きたこと ある時から、本ブログのコードの部分が「SyntaxHighlighter」で表示され
-
TwitterAPI 1.1対応で困ったこと −フォロー・フォロワー一覧取得−
TwitterのAPI1.1に2013年の3月15日までには対応しないといけません。
-
CakePHP1.3でテストコード(2) -フィクスチャをいじってみる(テストデータの動的登録)-
cakePHP1.3でのSimpleTestを使ったテストケースの第2回目。 今回は、動的にテストデ
-
iPhoneアプリ開発 -同じ画像を2度以上画像処理した際に起こるエラーの対処-
* 起きた現象 (1) UIImageのデータを元にピクセルの値を色々といじって画像処理。 (2)
-
iPhoneアプリ開発 -mixiSDKを使ってmixi連携をしてみる(1)-
* やりたいこと iPhoneアプリでmixiと連携し、mixiボイスなどに文字を投稿する。 ※
-
Facebookがちょっとコワイ vol.2 -本当にあなたはあなたなの?-
以下のブログを読んで、さらにコワイと思ったFacebook。 あなたが登録している「友