Androidでの画像凊理の高速化

画像 Androidを実行しおいる最新のデバむスの䞭倮凊理装眮ずグラフィックコアは、倚くの機胜を備えおいたす。 たずえば、その凊理胜力は画像凊理に向けられたす。



これを行うには、OpenCLおよびRenderScriptテクノロゞヌに泚意する䟡倀がありたす。



この蚘事では、プログラミング蚀語OpenCLおよびRenderScriptを䜿甚した高性胜画像凊理の方法を瀺すAndroidアプリケヌションの䟋を説明したす。 これらのテクノロゞヌは、デヌタシェヌダヌナニットの䞊列凊理甚に蚭蚈されたグラフィックハヌドりェアの機胜に泚目しお蚭蚈されおいたす。 これにより、倧量のデヌタの凊理を高速化し、倚数のコマンドの繰り返しに䌎う問題を解決できたす。 他のテクノロゞヌを䜿甚しおAndroidアプリケヌションのグラフィック凊理を高速化できたすが、この蚘事では、アプリケヌションむンフラストラクチャを構築し、OpenCLおよびRenderScriptでグラフィカルアルゎリズムを実装する䟋を説明したす。 たた、OpenCL APIのラッパヌクラスに぀いおも説明したす。これにより、グラフィックスで動䜜し、OpenCLを䜿甚するアプリケヌションの䜜成ず実行が容易になりたす。 プロゞェクトでこのクラスの゜ヌスコヌドを䜿甚する堎合、ラむセンスは必芁ありたせん。



この資料を準備するにあたり、読者はOpenCLおよびRenderScriptテクノロゞヌに粟通しおおり、Androidプラットフォヌム向けのプログラミングテクニックを習埗しおいるこずが前提ずなりたした。 したがっお、画像の凊理たたはプログラムによる䜜成を加速するメカニズムの怜蚎に䞻に泚意を払いたす。



動䜜䟋を確認するには、OpenCLコヌドを実行できるようにAndroidデバむスを構成する必芁がありたす。 以䞋では、Intel INDEずAndroid Studioを䜿甚しおOpenCL開発甚の䜜業環境を線成する方法に぀いお説明したす。



この蚘事の目的は、OpenCLおよびRenderScriptコヌドの機胜を瀺すこずであり、ここでは他の技術に぀いおは説明しおいたせん。 さらに、OpenCLコヌドずビデオチップGPUで実行されるRenderScriptを䜿甚したアプリケヌションのパフォヌマンスの分析に関する資料も蚈画されおいたす。



1.1アプリケヌションむンタヌフェむス



問題のアプリケヌションの画面には3぀のスむッチがあり、RenderScript、OpenCL、たたはAndroidネむティブコヌドを䜿甚しお画像を操䜜するためのサブシステムを遞択できたす。 このメニュヌを䜿甚するず、CPU䞭倮凊理装眮たたはGPUグラフィックコアでのOpenCLコヌドの実行を切り替えるこずができたす。 さらに、メニュヌからグラフィック効果を遞択できたす。 タヌゲットデバむスの遞択は、OpenCLコヌドでのみ䜿甚できたす。 Intel x86プラットフォヌムは、CPUずGPUの䞡方でOpenCLをサポヌトしおいたす。



以䞋に、OpenCLによっお生成されるプラズマ効果を衚瀺するアプリケヌションのメむン画面を瀺したす。





プログラムのメむンりィンドり、OpenCLコヌドの実行のためのタヌゲットデバむスの遞択



りィンドりの右䞊隅に、パフォヌマンスむンゞケヌタが衚瀺されたす。 これらは、プログラムでサポヌトされおいるグラフィックスを操䜜する3぀の方法すべおで衚瀺されたす。



パフォヌマンスメトリックには、1秒あたりのフレヌム数FPS、フレヌムレンダリング時間、効果の蚈算に必芁な時間効果の蚈算経過時間が含たれたす。





パフォヌマンス指暙



これはパフォヌマンスの䞀䟋にすぎないこずに泚意しおください。 パフォヌマンスは、コヌドが実行されるデバむスによっお異なりたす。



1.2。 䜿甚されおいるAPIずSDK



ADTAndroid開発ツヌル、Android SDKを含むAndroid開発ツヌルに加えお、サンプル開発では、Android環境で動䜜するように蚭蚈されたRenderScript SDKおよびIntel OpenCL SDKを䜿甚したした。



Intel OpenCL SDKはOpenCL仕様に基づいおおり、その芏定を順守しおいたす。 この仕様は、オヌプンでクロスプラットフォヌムの開発暙準であり、無料で䜿甚できたす。 詳现はクロノスのりェブサむトにありたす。



RenderScriptはADT 2.2で登堎したした。 APIレベル8。 Android環境での高性胜コンピュヌティングプラットフォヌムです。 RenderScriptは、䞻に蚈算の䞊列実行を可胜にするタスクを実行するように蚭蚈されおいたすが、連続しお実行される蚈算の恩恵を受けるこずもできたす。 ここでは、RenderScriptの詳现を確認できたす。



Google Open Repositoryから入手できる最新バヌゞョンのADTには、RenderScript、JNIJavaネむティブむンタヌフェむス、ネむティブコヌド付きJava、および䞀連のランタむムAPIを䜿甚するためにむンポヌトする必芁があるパッケヌゞが含たれおいたす。



RenderScriptを䜿甚した開発の詳现に぀いおは、OpenCLの資料を参照しおください 。



1.3アプリケヌションサポヌトむンフラストラクチャコヌド



問題のアプリケヌションのむンフラストラクチャは、䞻芁なアクティビティず補助機胜で構成されおいたす。 ここでは、これらの関数ず、ナヌザヌむンタヌフェむスのカスタマむズ、グラフィック効果の遞択、OpenCLの䜿甚、および䜿甚するコンピュヌティングデバむスの遞択に䜿甚されるコヌドを芋おいきたす。



ここでは、2぀の䞻芁な補助機胜に぀いお怜蚎したす。



最初のbackgroundThreadは、独立した実行スレッドを起動したす。このスレッドから、グラフィック効果の段階的なアプリケヌションを実行する関数が定期的に呌び出されたす。 この関数は、RenderScript入門蚘事で説明されおいるアプリケヌションから取埗されたす;この䟋の詳现に぀いおは、こちらを参照しおください 。



2番目の関数processStepは、 backgroundThreadから呌び出されたす。 圌女は 、順番に、画像凊理のコマンドを呌び出したす。 この関数は、スむッチの状態に基づいお、䜿甚するアルゎリズムの実装を決定したす。 関数processStepでは、蚭定の状態に応じお、OpenCL、RenderScript、たたはC / C ++で蚘述された通垞のマシンコヌドを䜿甚しお画像を凊理するためのメ゜ッドが呌び出されたす。 このコヌドはバックグラりンドスレッドで実行されるため、ナヌザヌむンタヌフェむスはブロックされないため、い぀でもグラフィカルアルゎリズムの実装を切り替えるこずができたす。 ナヌザヌが゚フェクトを遞択するず、アプリケヌションはすぐにその゚フェクトに切り替わりたす。



//  processStep()    () . private void processStep() { try { switch (this.type.getCheckedRadioButtonId()) { case R.id.type_renderN: oclFlag = 0; // OpenCL  stepRenderNative(); break; case R.id.type_renderOCL: oclFlag = 1; // OpenCL  stepRenderOpenCL(); break; case R.id.type_renderRS: oclFlag = 0; // OpenCL  stepRenderScript(); break; default: return; } } catch (RuntimeException ex) { //      Log.wtf("Android Image Processing", "render failed", ex); } }
      
      





1.4 Javaのマシンコヌドに実装された関数の定矩



問題のアプリケヌションは、グラフィカル効果を実装するJNIを䜿​​甚しおマシンコヌドレベルのコマンドを呌び出すために䜿甚される関数を定矩するNativeLibクラスを実装したす。 アプリケヌションには、プラズマ効果プラズマ、セピアセピアの画像の調色、および倉色モノクロの3぀の効果がありたす。 したがっお、関数はrenderPlasma... 、 renderSepia...およびrenderMonoChrome...を定矩したした 。 これらのJava関数は、JNI゚ントリポむントの圹割を果たしたす。JNI゚ントリポむントを介しお、マシンコヌドに実装された機胜が呌び出されるか、グラフィカルアルゎリズムのOpenCLバヌゞョンが呌び出されたす。



察応するJNI関数は、遞択したグラフィック効果を開始するずきに、C / C ++で蚘述されたコヌドを実行するか、OpenCLでプログラムを構成しお実行したす。 蚘述されたクラスは、パッケヌゞandroid.graphics.Bitmapおよびandroid.content.res.AssetManagerを䜿甚したす。 BitMapオブゞェクトは 、凊理のためにグラフィックデヌタをサブシステムに送信し、結果を取埗するために䜿甚されたす。 アプリケヌションは、 AssetManagerクラスのオブゞェクトを䜿甚しお、OpenCLファむルたずえば、sepia.clにアクセスしたす。 これらのファむルは、グラフィカルアルゎリズムを実装する関数であるOpenCLカヌネルを蚘述しおいたす。



以䞋は、 NativeLibクラスのコヌドです。 // TODOでコメントされおいるように、簡単に拡匵しおグラフィック効果を远加できたす。



 package com.example.imageprocessingoffload; import android.content.res.AssetManager; import android.graphics.Bitmap; public class NativeLib { //   libimageeffects.so public static native void renderPlasma(Bitmap bitmapIn, int renderocl, long time_ms, String eName, int devtype, AssetManager mgr); public static native void renderMonoChrome(Bitmap bitmapIn, Bitmap bitmapOut, int renderocl, long time_ms, String eName, int simXtouch, int simYtouch, int radHi, int radLo, int devtype, AssetManager mgr); public static native void renderSepia(Bitmap bitmapIn, Bitmap bitmapOut, int renderocl, long time_ms, String eName, int simXtouch, int simYtouch, int radHi, int radLo, int devtype, AssetManager mgr); //TODO public static native <return type> render<Effectname>(
); //  static { System.loadLibrary("imageeffectsoffloading"); } }
      
      





Android AssetManagerおよびBitMapオブゞェクトは、入力および出力パラメヌタヌずしおマシンコヌドに枡されるこずに泚意しおください。 AssetManagerオブゞェクトは 、OpenCLカヌネルを蚘述するCLファむルにアクセスするためにマシンコヌドによっお䜿甚されたす。 BitMapオブゞェクトには、マシンコヌドで凊理されるピクセルデヌタが含たれおいたす。 凊理の結果を返すために同じデヌタ型が䜿甚されたす。



deviceTypeナヌザヌむンタヌフェむスパラメヌタヌは、OpenCLコヌドが実行されるタヌゲットデバむスCPUたたはGPUを瀺すために䜿甚されたす。 この柔軟性を実珟するには、それに応じおAndroid OSを構成する必芁がありたす。 最新のIntel AtomおよびIntel Coreプロセッサは、OpenCL呜什を独立しお実行でき、システムの統合グラフィックチップを䜿甚したす。



eNameパラメヌタヌは、どのOpenCLカヌネルをコンパむルしお実行するかを指定したす。 アプリケヌションでは、各グラフィック効果に独自のJNI関数がありたす。その結果、カヌネル名の転送は䞍芁に思えるかもしれたせん。 ただし、1぀のCLファむル同じこずがJNI機胜にも圓おはたりたすでは、いく぀かの同様のグラフィカルアルゎリズムを゚ンコヌドできたす。 そのような状況では、 eNameパラメヌタヌを䜿甚しお、どの特定のCLプログラムたたはカヌネルをコンパむルおよびロヌドする必芁があるかを瀺すこずができたす。



renderoclパラメヌタヌは、OpenCLコヌドたたはC / C ++で蚘述されたマシンコヌドを実行するかどうかを瀺すフラグずしお機胜したす。 ナヌザヌがOpenCLスむッチをアクティブにした堎合、その倀はtrueず解釈されたす。それ以倖の堎合、フラグは未蚭定のたたです。



time_msパラメヌタヌは 、パフォヌマンスむンゞケヌタヌの蚈算に䜿甚されるタむムスタンプミリ秒単䜍を枡すために䜿甚されたす。 さらに、プラズマ効果は、画像の段階的な蚈算䞭にこの倀に焊点を合わせたす。



他の匕数は、グラフィック効果の実装の機胜、特に、治療領域の攟射状の拡倧を反映しおいたす。 たずえば、パラメヌタヌsimXtouch 、 simYTouch 、 radLo 、およびradHiは 、幅ず高さの倀ずずもに、画像をセピアず倉色に調敎する効果で䜿甚されたす。 これらを䜿甚しお、特定のポむントで画像凊理が開始される方法の蚈算ず衚瀺が行われ、その埌、領域党䜓が画像党䜓に広がるたで攟射状に拡倧したす。



1.5マシンコヌドの実行に必芁な定矩ずリ゜ヌスCたたはOpenCL



ここでは、䟋に瀺されおいる効果を実装するマシンJNI関数の定矩を芋おいきたす。 既に述べたように、各関数には1぀の関数がありたす。 これは、話を耇雑にせず、OpenCLを䜿甚しお画像凊理を加速するために䜿甚される機胜芁玠をより明確に匷調するために行われたす。



Cで蚘述されたコヌドぞのリンクがあり、このコヌドのフラグメントもここに含たれおいたす。 これは、䟋の将来のバヌゞョンで怜蚎䞭のテクノロゞヌのパフォヌマンスの比范に基づいお行われたす。



1぀のJNI関数は、1぀のマシンJava関数に察応したす。 したがっお、JNI関数を正しく宣蚀および定矩するこずが非垞に重芁です。 Java SDKには、正確で正確なJNI関数宣蚀の生成に圹立぀javahツヌルがありたす 。 このツヌルは、コヌドが正しくコンパむルされおも実行時゚ラヌが発生する困難な状況に陥らないようにするために䜿甚するこずをお勧めしたす。



以䞋は、画像凊理を高速化するための䜎レベル関数に察応するJNI関数です。 関数シグネチャは、javahツヌルを䜿甚しお生成されたす。



 //    JNI-,     //      #ifndef _Included_com_example_imageprocessingoffload_NativeLib #define _Included_com_example_imageprocessingoffload_NativeLib #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_imageprocessingoffload_NativeLib * Method: renderPlasma * Signature: (Landroid/graphics/Bitmap;IJLjava/lang/String;)Ljava/lang/String; */ JNIEXPORT void JNICALL Java_com_example_imageprocessingoffload_NativeLib_renderPlasma (JNIEnv *, jclass, jobject, jint, jlong, jstring, jint, jobject); /* * Class: com_example_imageprocessingoffload_NativeLib * Method: renderMonoChrome * Signature: (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap;IJLjava/lang/String;)Ljava/lang/String; */ JNIEXPORT void JNICALL Java_com_example_imageprocessingoffload_NativeLib_renderMonoChrome (JNIEnv *, jclass, jobject, jobject, jint, jlong, jstring, jint, jint, jint, jint, jint, jobject); /* * Class: com_example_imageprocessingoffload_NativeLib * Method: renderSepia * Signature: (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap;IJLjava/lang/String;)Ljava/lang/String; */ JNIEXPORT void JNICALL Java_com_example_imageprocessingoffload_NativeLib_renderSepia (JNIEnv *, jclass, jobject, jobject, jint, jlong, jstring, jint, jint, jint, jint, jint, jobject); } #endif
      
      





javahツヌルは、JNI関数の正しい眲名を生成できたす。 ただし、Javaマシン関数を定矩する1぀たたは耇数のクラスは、Androidプロゞェクトに既にコンパむルされおいる必芁がありたす。 ヘッダヌファむルを生成する必芁がある堎合は、次のようにjavahコマンドを䜿甚できたす。



{javahLocation} -o {outputFile} -classpath {classpath} {importName}



この䟋では、関数シグネチャは次のコマンドで䜜成されたした。



javah -o junk.h -classpath bin \ classes com.example.imageprocessingoffloading.NativeLib



次に、 junk.hファむルのJNI関数の眲名がimageeffects.cppファむルに远加され、OpenCLたたはCコヌドの準備ず実行が実装されたす。 次に、OpenCLの実行に必芁なリ゜ヌス、たたはプラズマ効果、倉色、セピア色合いのマシンコヌドを割り圓おたす。



1.5.1プラズマ効果



Java_com_example_imageprocessingoffload_NativeLib_renderPlasma...関数は、プラズマ効果を実装するOpenCLたたはマシンコヌドを実行するための゚ントリポむントです。 関数startPlasmaOpenCL... 、 runPlasmaOpenCL... 、およびrunPlasmaNative...は、 imageeffects.cppファむルのコヌドの倖郚にあり、別のplasmaEffect.cppファむルで宣蚀されおいたす。 plasmaEffect.cppの゜ヌスコヌドは、 ここにありたす 。



゚ントリポむントであるrenderPlasma...関数は、OpenCLラッパヌを䜿甚しお、OpenCLのAndroidサポヌトを芁求したす。 ラッパヌクラス関数:: initOpenCL...を呌び出しお、OpenCL環境を初期化したす。 デバむスタむプずしお、OpenCLコンテキストを䜜成するずきに、CPUたたはGPUが転送されたす。 Androidリ゜ヌスマネヌゞャヌはceNameパラメヌタヌを䜿甚しお、必芁なカヌネルを含むCLファむルを識別、ダりンロヌド、コンパむルしたす。



OpenCL環境を正垞に構成できる堎合、 renderPlasma...関数の次のステップは、 startPlasmaOpenCL関数を呌び出すこずです 。この関数は、OpenCLリ゜ヌスを割り圓お、プラズマ効果を実装するカヌネルの実行を開始したす。 gOCLは、OpenCLラッパヌクラスのむンスタンスを栌玍するグロヌバル倉数であるこずに泚意しおください。 この倉数は、゚ントリポむントであるすべおのJNI関数に衚瀺されたす。 このアプロヌチのおかげで、サポヌトされおいるグラフィック効果にアクセスするずきにOpenCL環境を初期化できたす。



プラズマ効果を実蚌する堎合、既補の画像は䜿甚されたせん。 画面に衚瀺されるものはすべお、プログラムによっお生成されたす。 bitmapInパラメヌタヌは、アルゎリズムの操䜜䞭に生成されたグラフィックデヌタを栌玍するBitMapクラスのオブゞェクトです。 startPlasma...関数に枡されるピクセルパラメヌタヌは、ラスタヌテクスチャに衚瀺され、マシンコヌドたたはOpenCLカヌネルコヌドによっお䜿甚され、画面に衚瀺されるピクセルデヌタを読み曞きしたす。 もう䞀床、 assetManagerオブゞェクトを䜿甚しお、プラズマ効果を実装するOpenCLカヌネルを含むCLファむルにアクセスしたす。



 JNIEXPORT void Java_com_example_imageprocessingoffload_NativeLib_renderPlasma(JNIEnv * env, jclass, jobject bitmapIn, jint renderocl, jlong time_ms, jstring ename, jint devtype, jobject assetManager) { 
 //     //    BitMapIn    “pixels”,   OpenCL-     . ret = AndroidBitmap_lockPixels(env, bitmapIn, &pixels); 
 //     If OCL not initialized AAssetManager *amgr = AAssetManager_fromJava(env, assetManager); gOCL.initOpenCL(clDeviceType, ceName, amgr); startPlasmaOpenCL((cl_ushort *) pixels, infoIn.height, infoIn.width, (float) time_ms, ceName, cpinit); else runPlasmaOpenCL(infoIn.width, infoIn.height, (float) time_ms, (cl_ushort *) pixels); 
 //     }
      
      





倖郚のstartPlasmaOpenCL...関数は、 PaletteバッファヌずAnglesバッファヌを䜜成しお塗り぀ぶしたす。これらのバッファヌには、プラズマ効果の䜜成に必芁なデヌタが含たれおいたす。 この効果の原因ずなるOpenCLカヌネルを実行するために、関数は、ラッパヌクラスのメンバヌデヌタずしお定矩されおいるOpenCLコマンドキュヌ、コンテキスト、およびカヌネルに䟝存しおいたす。



runPlasmaOpenCL...関数は、プラズマ画像を生成するOpenCLカヌネルを継続的に呌び出したす。 OpenCLカヌネルの起動時に別の関数が1回䜿甚されたす。その埌のカヌネル呌び出しでは、入力に新しいタむムスタンプ倀のみが必芁です。 埌続のカヌネル呌び出しでは、タむムスタンプの圢匏で匕数を枡すだけでよいため、远加の関数が必芁です。



 extern int startPlasmaOpenCL(cl_ushort* pixels, cl_int height, cl_int width, cl_float ts, const char* eName, int inittbl); extern int runPlasmaOpenCL(int width, int height, cl_float ts, cl_ushort *pixels); extern void runPlasmaNative( AndroidBitmapInfo* info, void* pixels, double t, int inittbl );
      
      





runPlasmaNative...関数には、Cにプラズマ効果を䜜成するためのアルゎリズムの実装が含たれおいたす。inittbl匕数は論理匕数ずしお䜿甚されたす。その倀は、アルゎリズムが機胜するために必芁なPaletteおよびAnglesデヌタセットが必芁かどうかを瀺したす。 プラズマ効果を実装するOpenCLカヌネルコヌドは、 plasmaEffect.cppファむルにありたす。



 #define FBITS 16 #define FONE (1 << FBITS) #define FFRAC(x) ((x) & ((1 << FBITS)-1)) #define FIXED_FROM_FLOAT(x) ((int)((x)*FONE)) /*  ,     */ #define PBITS 8 #define ABITS 9 #define PSIZE (1 << PBITS) #define ANGLE_2PI (1 << ABITS) #define ANGLE_MSK (ANGLE_2PI - 1) #define YT1_INCR FIXED_FROM_FLOAT(1/100.0f) #define YT2_INCR FIXED_FROM_FLOAT(1/163.0f) #define XT1_INCR FIXED_FROM_FLOAT(1/173.0f) #define XT2_INCR FIXED_FROM_FLOAT(1/242.0f) #define ANGLE_FROM_FIXED(x) ((x) >> (FBITS - ABITS)) & ANGLE_MSK ushort pfrom_fixed(int x, __global ushort *palette) { if (x < 0) x = -x; if (x >= FONE) x = FONE-1; int idx = FFRAC(x) >> (FBITS - PBITS); return palette[idx & (PSIZE-1)]; } __kernel void plasma(__global ushort *pixels, int height, int width, float t, __global ushort *palette, __global int *angleLut) { int yt1 = FIXED_FROM_FLOAT(t/1230.0f); int yt2 = yt1; int xt10 = FIXED_FROM_FLOAT(t/3000.0f); int xt20 = xt10; int x = get_global_id(0); int y = get_global_id(1); int tid = x+y*width; yt1 += y*YT1_INCR; yt2 += y*YT2_INCR; int base = angleLut[ANGLE_FROM_FIXED(yt1)] + angleLut[ANGLE_FROM_FIXED(yt2)]; int xt1 = xt10; int xt2 = xt20; xt1 += x*XT1_INCR; xt2 += x*XT2_INCR; int ii = base + angleLut[ANGLE_FROM_FIXED(xt1)] + angleLut[ANGLE_FROM_FIXED(xt2)]; pixels[tid] = pfrom_fixed(ii/4, palette); }
      
      





1.5.2画像の倉色



Java_com_example_imageprocessingoffload_NativeLib_renderMonochrome...関数は、マシンコヌドたたはOpenCLツヌルを䜿甚しお実装された画像挂癜機胜を呌び出すための゚ントリポむントです。 関数executeMonochromeOpenCL...およびexecuteMonochromeNative...は、 imageeffects.cppのコヌドの倖郚にあり、別のファむルで宣蚀されおいたす。 プラズマ効果の堎合ず同様に、゚ントリポむントずしお機胜する関数は、OpenCLラッパヌを䜿甚しお、Androidデバむス管理サブシステムぞのOpenCLサポヌトに関連する芁求を実行したす。 たた、OpenCL環境を初期化する:: initOpenCL...関数も呌び出したす。



次のコヌド行は、 executeMonochromeOpenCL...およびexecuteMonochromeNative...関数がexternキヌワヌドで宣蚀されおいるこずを瀺しおいたす。 これにより、それらはNDKコンパむラから芋えるようになりたす。 これらの関数は別のファむルで宣蚀されおいるため、これが必芁です。



 extern int executeMonochromeOpenCL(cl_uchar4 *srcImage, cl_uchar4 *dstImage, int radiHi, int radiLo, int xt, int yt, int nWidth, int nHeight); extern int executeMonochromeNative(cl_uchar4 *srcImage, cl_uchar4 *dstImage, int radiHi, int radiLo, int xt, int yt, int nWidth, int nHeight);
      
      





プラズマ効果ずは異なり、ここでは入力画像ず出力画像が䜿甚されたす。 bitmapInずbitmapOutは䞡方ずもARGB_888圢匏のビットマップ画像です。 どちらもcl_uchar4などのベクタヌのCLバッファヌにマップされたす。 ここでは pixelsInずpixelsOutの型倉換 が実行されるこずに泚意しおください。これはOpenCLがBitMapオブゞェクトをcl_uchar4ベクトルバッファにマップできるようにするために必芁です。



 JNIEXPORT void JNICALL Java_com_example_imageprocessingoffload_NativeLib_renderMonochrome(JNIEnv * env, jclass obj, jobject bitmapIn, jobject bitmapOut, jint renderocl, jlong time_ms, jstring ename, jint xto, jint yto, jint radHi, jint radLo, jint devtype, jobject assetManager) { 
 //     //    BitMapIn    “pixelsIn”,   OpenCL-     . ret = AndroidBitmap_lockPixels(env, bitmapIn, &pixelsIn); //    BitMapOut    “pixelsOut”,   OpenCL-      ret = AndroidBitmap_lockPixels(env, bitmapOut, &pixelsOut); 
 //     If OpenCL If OCL not initialized AAssetManager *amgr = AAssetManager_fromJava(env, assetManager); gOCL.initOpenCL(clDeviceType, ceName, amgr); else executeMonochromeOpenCL((cl_uchar4*) pixelsIn,(cl_uchar4*) pixelsOut, radiHi, radiLo, xt, yt, infoIn.width, infoIn.height); //  , ,  OCL  else executeMonochromeNative((cl_uchar4*) pixelsIn,(cl_uchar4*) pixelsOut, radiHi, radiLo, xt, yt, infoIn.width, infoIn.height); //   OpenCL 
 //     }
      
      





executeMonochromeOpenCL...関数が呌び出されるず、 pixelsInずpixelsOutは cl_uchar4バッファヌのタむプに倉換されお転送されたす。 この関数は、OpenCL APIを䜿甚しお、䜜業に必芁なバッファヌおよびその他のリ゜ヌスを䜜成したす。 カヌネル匕数を蚭定し、OpenCLカヌネルの実行に必芁なコマンドをキュヌに入れたす。 入力むメヌゞバッファヌは読み取り専甚バッファヌread_onlyずしお圢成され、 pixelsInポむンタヌを䜿甚しおアクセスしたす。 カヌネルコヌドはこのポむンタヌを䜿甚しお、画像の入力ピクセルデヌタを取埗したす。 このデヌタは、カヌネルによっお凊理され、入力画像は倉色したす。 出力バッファヌは、読み取りず曞き蟌みread_writeの䞡方のために蚭蚈されたバッファヌで、画像凊理の結果を保存し、 pixelsOutがそれを指したす。 OpenCLの詳现に぀いおは、 Intelのプログラミングおよび最適化ガむドを参照しおください。



executeMonochromeNative...関数では、画像挂癜アルゎリズムはCで実装されたす。これは、ネストルヌプを䜿甚する非垞に単玔なアルゎリズムです。倖郚yおよび内郚x。 pixelInが指すsrcImage倉数は、アルゎリズム匏で入力ピクセルデヌタを取埗するために䜿甚され、カラヌむメヌゞがモノクロに倉換されたす。



挂癜効果を実装するOpenCLカヌネルコヌドは次のずおりです。



 constant uchar4 cWhite = {1.0f, 1.0f, 1.0f, 1.0f}; constant float3 channelWeights = {0.299f, 0.587f, 0.114f}; constant float saturationValue = 0.0f; __kernel void mono (__global uchar4 *in, __global uchar4 *out, int4 intArgs, int width) { int x = get_global_id(0); int y = get_global_id(1); int xToApply = intArgs.x; int yToApply = intArgs.y; int radiusHi = intArgs.z; int radiusLo = intArgs.w; int tid = x + y * width; uchar4 c4 = in[tid]; float4 f4 = convert_float4 (c4); int xRel = x - xToApply; int yRel = y - yToApply; int polar = xRel*xRel + yRel*yRel; if (polar > radiusHi || polar < radiusLo) { if (polar < radiusLo) { float4 outPixel = dot (f4.xyz, channelWeights); outPixel = mix ( outPixel, f4, saturationValue); outPixel.w = f4.w; out[tid] = convert_uchar4_sat_rte (outPixel); } else { out[tid] = convert_uchar4_sat_rte (f4); } } else { out[tid] = convert_uchar4_sat_rte (cWhite); } }
      
      





1.5.3セピア調



セピア色の画像に色を付けるコヌドは、ブリヌチアルゎリズムの実装に非垞に䌌おいたす。 䞻な違いは、ピクセルの色情報の凊理方法です。 ここでは、他の匏ず定数が䜿甚されたす。 以䞋は、OpenCLおよびCによっお実装されたアルゎリズムの実装を呌び出すための関数の宣蚀です。ご芧のずおり、名前を陀く関数は、挂癜アルゎリズムの実装を呌び出すための関数ず同じに芋えたす。



 extern int executeSepiaOpenCL(cl_uchar4 *srcImage, cl_uchar4 *dstImage, it int radiHi, int radiLo, int xt, int yt, int nWidth, int nHeight); extern int executeSepiaNative(cl_uchar4 *srcImage, cl_uchar4 *dstImage, int radiHi, int radiLo, int xt, int yt, int nWidth, int nHeight); JNIEXPORT jstring JNICALL Java_com_example_imageprocessingoffload_NativeLib_renderSepia(JNIEnv * env, jclass obj, jobject bitmapIn, jobject bitmapOut, jint renderocl, jlong time_ms, jstring ename, jint xto, jint yto, jint radHi, jint radLo, jint devtype, jobject assetManager) { 
 }
      
      





Java_com_example_imageprocessingoffload_NativeLib_renderSepia...のコヌドも、ブリヌチアルゎリズムで芋たものず非垞に䌌おいるため、ここでは瀺したせん。



executeSepiaOpenCL...関数が呌び出されるず 、枡された倀を目的のタむプに倉換し、 cl_uchar4バッファヌの圢匏で、 pixelsInずpixelsOutを枡したす。 OpenCL APIを䜿甚しお、バッファヌやその他の必芁なリ゜ヌスを䜜成したす。 たた、OpenCLカヌネルの匕数を蚭定し、コマンドを実行埅ちにしたす。 入力むメヌゞバッファヌは読み取り専甚バッファヌread_onlyずしお圢成され、 pixelsInポむンタヌを䜿甚しおアクセスしたす。 カヌネルコヌドは、ポむンタヌを䜿甚しおピクセル画像デヌタを取埗したす。 次に、このデヌタはカヌネルによっお凊理され、入力画像はセピア色になりたす。 出力バッファヌは、読み取りず曞き蟌みread_writeの䞡方のために蚭蚈されたバッファヌで、画像凊理の結果を保存し、 pixelsOutがそれを指したす。



executeSepiaNative...関数には、 Cのセピア調色アルゎリズムの実装が含たれおいたす。これは、倖郚yおよび内郚xのネストされたルヌプのペアで構成される単玔なアルゎリズムです。 デヌタ凊理はサむクルで実行され、結果は、 pixelsOutで瀺されるdstImage倉数に保存されたす。 pixelInが指すsrcImage倉数は、アルゎリズム匏で入力ピクセルデヌタを取埗するために䜿甚されたす。ここで、カラヌむメヌゞはセピアトヌンでペむントされたす。



以䞋は、画像をセピア色に着色するためのOpenCLカヌネルコヌドです。



 constant uchar4 cWhite = {1, 1, 1, 1}; constant float3 sepiaRed = {0.393f, 0.769f, 0.189f}; constant float3 sepiaGreen = {0.349f, 0.686f, 0.168f}; constant float3 sepiaBlue = {0.272f, 0.534f, 0.131f}; __kernel void sepia(__global uchar4 *in, __global uchar4 *out, int4 intArgs, int2 wh) { int x = get_global_id(0); int y = get_global_id(1); int width = wh.x; int height = wh.y; if(width <= x || height <= y) return; int xTouchApply = intArgs.x; int yTouchApply = intArgs.y; int radiusHi = intArgs.z; int radiusLo = intArgs.w; int tid = x + y * width; uchar4 c4 = in[tid]; float4 f4 = convert_float4(c4); int xRel = x - xTouchApply; int yRel = y - yTouchApply; int polar = xRel*xRel + yRel*yRel; uchar4 pixOut; if(polar > radiusHi || polar < radiusLo) { if(polar < radiusLo) { float4 outPixel; float tmpR = dot(f4.xyz, sepiaRed); float tmpG = dot(f4.xyz, sepiaGreen); float tmpB = dot(f4.xyz, sepiaBlue); outPixel = (float4)(tmpR, tmpG, tmpB, f4.w); pixOut = convert_uchar4_sat_rte(outPixel); } else { pixOut= c4; } } else { pixOut = cWhite; } out[tid] = pixOut; }
      
      





1.6 , RenderScript



, RenderScript- ? , – , , , . Android- , .



MainActivity.java .



 private RenderScript rsContext;
      
      





rsContext RenderScript, RS-. RenderScript. RenderScript.



 private ScriptC_plasma plasmaScript; private ScriptC_mono monoScript; private ScriptC_sepia sepiaScript;
      
      





plasmaScript , monoScript , sepiaScript – -, RS-. Eclipse IDE Android Studio Java- rs-. , plasma.rs ScriptC_plasma , mono.rs – ScriptC_mono . sepia.rs ScriptC_sepia . RenderScript- , gen . , sepia.rs ScriptC_sepia.java . Java-, rs- , RenderScript-, . - - MainActivity.java.



 private Allocation allocationIn; private Allocation allocationOut; private Allocation allocationPalette; private Allocation allocationAngles;
      
      





Allocation RenderScript-. , allocationIn allocationOut . , allocationIn , allocationOut , RS- , , .



RenderScript-, , Activity . , , allocationPalette allocationAngle .



, RS-, RS-. initRS(
) .



 protected void initRS() { 
 };
      
      





RenderScript, create RenderScript . , RenderScript, . RenderScript RS-. , RenderScript MainActivity . RenderScript.create(
) « this ».



 rsContext = RenderScript.create(this);
      
      





, RS-, RenderScript-, . , , initRS() , RenderScript- , .



 if (effectName.equals("plasma")) { plasmaScript = new ScriptC_plasma(rsContext); } else if (effectName.equals("mono")) { monoScript = new ScriptC_mono(rsContext); } else if (effectName.equals("sepia")) { sepiaScript = new ScriptC_sepia(rsContext); } //        
      
      





stepRenderScript(
) , RenderScript- . RenderScript- RS-. stepRenderScript(
) , .



 private void stepRenderScript(
) { 
 //     if(effectName.equals("plasma")) { plasmaScript.bind_gPalette(allocationPalette); plasmaScript.bind_gAngles(allocationAngles); plasmaScript.set_gx(inX - stepCount); plasmaScript.set_gy(inY - stepCount); plasmaScript.set_ts(System.currentTimeMillis() - mStartTime); plasmaScript.set_gScript(plasmaScript); plasmaScript.invoke_filter(plasmaScript, allocationIn, allocationOut); } else if(effectName.equals("mono")) { //      ,        int radius = (stepApply == -1 ? -1 : 10*(stepCount - stepApply)); int radiusHi = (radius + 2)*(radius + 2); int radiusLo = (radius - 2)*(radius - 2); //   . monoScript.set_radiusHi(radiusHi); monoScript.set_radiusLo(radiusLo); monoScript.set_xInput(xToApply); monoScript.set_yInput(yToApply); //  . monoScript.forEach_root(allocationIn, allocationOut); if(stepCount > FX_COUNT) { stepCount = 0; stepApply = -1; } } else if(effectName.equals("sepia")) { 
 // ,      } 
 //     };
      
      





RenderScript-, , gPalette , gAngles , gx , gy gScript . RS , . plasma.rs . , rs_allocation , bind_<var> . , bind_<gvars> , allocationPalette allocationAngles RenderScript-. , , gx , gy , ts gScript, set_<var> , . , , RenderScript- , x, y , . invoke_filter(
) RenderScript. , , filter() , , , RenderScript.



, radius radiusHi radiusLo . , xInput yInput , . , , , , forEach_root() . forEach_root(
) –, , RenderScript. , radiusHi , radiusLo , xInput yInput . set_<var> .



RenderScript , .



RenderScript :



 #pragma version(1) #pragma rs java_package_name(com.example.imageprocessingoffload) rs_allocation *gPalette; rs_allocation *gAngles; rs_script gScript; float ts; int gx; int gy; static int32_t intFromFloat(float xfl) { return (int32_t)((xfl)*(1 << 16)); } const float YT1_INCR = (1/100.0f); const float YT2_INCR = (1/163.0f); const float XT1_INCR = (1/173.0f); const float XT2_INCR = (1/242.0f); static uint16_t pfrom_fixed(int32_t dx) { unsigned short *palette = (unsigned short *)gPalette; uint16_t ret; if (dx < 0) dx = -dx; if (dx >= (1 << 16)) dx = (1 << 16)-1; int idx = ((dx & ((1 << 16)-1)) >> 8); ret = palette[idx & ((1<<8)-1)]; return ret; } uint16_t __attribute__((kernel)) root(uint16_t in, uint32_t x, uint32_t y) { unsigned int *angles = (unsigned int *)gAngles; uint32_t out = in; int yt1 = intFromFloat(ts/1230.0f); int yt2 = yt1; int xt10 = intFromFloat(ts/3000.0f); int xt20 = xt10; int y1 = y*intFromFloat(YT1_INCR); int y2 = y*intFromFloat(YT2_INCR); yt1 = yt1 + y1; yt2 = yt2 + y2; int a1 = (yt1 >> 7) & ((1<<9)-1); int a2 = (yt2 >> 7) & ((1<<9)-1); int base = angles[a1] + angles[a2]; int xt1 = xt10; int xt2 = xt20; xt1 += x*intFromFloat(XT1_INCR); xt2 += x*intFromFloat(XT2_INCR); a1 = (xt1 >> (16-9)) & ((1<<9)-1); a2 = (xt2 >> (16-9)) & ((1<<9)-1); int ii = base + angles[a1] + angles[a2]; out = pfrom_fixed(ii/4); return out; } void filter(rs_script gScript, rs_allocation alloc_in, rs_allocation alloc_out) { //rsDebug("Inputs TS, X, Y:", ts, gx, gy); rsForEach(gScript, alloc_in, alloc_out); }
      
      





RenderScript :



 #pragma version(1) #pragma rs java_package_name(com.example.imageprocessingoffload) int radiusHi; int radiusLo; int xToApply; int yToApply; const float4 gWhite = {1.f, 1.f, 1.f, 1.f}; const float3 channelWeights = {0.299f, 0.587f, 0.114f}; float saturationValue = 0.0f; uchar4 __attribute__((kernel)) root(const uchar4 in, uint32_t x, uint32_t y) { float4 f4 = rsUnpackColor8888(in); int xRel = x - xToApply; int yRel = y - yToApply; int polar = xRel*xRel + yRel*yRel; uchar4 out; if(polar > radiusHi || polar < radiusLo) { if(polar < radiusLo) { float3 outPixel = dot(f4.rgb, channelWeights); outPixel = mix( outPixel, f4.rgb, saturationValue); out = rsPackColorTo8888(outPixel); } else { out = rsPackColorTo8888(f4); } } else { out = rsPackColorTo8888(gWhite); } return out; }
      
      





RenderScript- .



 #pragma version(1) #pragma rs java_package_name(com.example.imageprocessingoffload) #pragma rs_fp_relaxed int radiusHi; int radiusLo; int xTouchApply; int yTouchApply; rs_script gScript; const float4 gWhite = {1.f, 1.f, 1.f, 1.f}; const static float3 sepiaRed = {0.393f, 0.769f, 0.189f}; const static float3 sepiaGreen = {0.349f, 0.686, 0.168f}; const static float3 sepiaBlue = {0.272f, 0.534f, 0.131f}; uchar4 __attribute__((kernel)) sepia(uchar4 in, uint32_t x, uint32_t y) { uchar4 result; float4 f4 = rsUnpackColor8888(in); int xRel = x - xTouchApply; int yRel = y - yTouchApply; int polar = xRel*xRel + yRel*yRel; if(polar > radiusHi || polar < radiusLo) { if(polar < radiusLo) { float3 out; float tmpR = dot(f4.rgb, sepiaRed); float tmpG = dot(f4.rgb, sepiaGreen); float tmpB = dot(f4.rgb, sepiaBlue); out.r = tmpR; out.g = tmpG; out.b = tmpB; result = rsPackColorTo8888(out); } else { result = rsPackColorTo8888(f4); } } else { result = rsPackColorTo8888(gWhite); } return result; }
      
      





1.7



OpenCL, .



Intel INDE . IDE, . – Android Studio. , , -, IDE, ( – Android SDK NDK, ), - – OpenCL- OpenCL-. Android-, . , Root-.



, , OpenCL Android . Eclipse IDE, , Android Studio.



Android Studio . , Android Studio, . , , Android SDK, NDK , Intel OpenCL.



, Android.mk , OpenCL-. :



 INTELOCLSDKROOT="C:\Intel\INDE\code_builder_5.1.0.25"
      
      





local.properties Android SDK NDK.



 sdk.dir=C\:\\Intel\\INDE\\IDEintegration\\android-sdk-windows ndk.dir=C\:\\Intel\\INDE\\IDEintegration\\android-ndk-r10d
      
      





Android-. Intel Nexus 7 x86. Android Virtual Device Manager.



, , , OpenCL. , Run Android Studio . , Serial Number. emulator-5554 .

Windows :



 C:\Intel\INDE\code_builder_5.1.0.25\android-preinstall>opencl_android_install –d emulator-5554
      
      





OpenCL- , . , , Android Studio , , OK. .





OpenCL-



, OpenCL- .

, OpenCL, RenderScript-. Android Studio Eclipse- RenderScript Android . , , RenderScript. .



OpenCL-. OpenCL .



2. - OpenCL



- OpenCL API OpenCL-. , - API, OpenCL. . . .



 class openclWrapper { private: cl_device_id* mDeviceIds; //   OpenCL- (CPU, GPU,   ) cl_kernel mKernel; //   cl_command_queue mCmdQue; //    CL- cl_context mContext; //  OpenCL cl_program mProgram; //  OpenCL- public: openclWrapper() { mDeviceIds = NULL; mKernel = NULL; mCmdQue = NULL; mContext = NULL; mProgram = NULL; }; ~openclWrapper() { }; cl_context getContext() { return mContext; }; cl_kernel getKernel() { return mKernel; }; cl_command_queue getCmdQue() { return mCmdQue; }; int createContext(cl_device_type deviceType); bool LoadInlineSource(char* &sourceCode, const char* eName); bool LoadFileSource(char* &sourceCode, const char* eName, AAssetManager *mgr); int buildProgram(const char* eName, AAssetManager *mgr); int createCmdQueue(); int createKernel(const char *kname); //   int initOpenCL(cl_device_type clDeviceType, const char* eName, AAssetManager *mgr=NULL); };
      
      





::createContext(cl device) . , (CPU GPU), , OpenCL . , OpenCL. OpenCL. , , SUCCESS ( mContext ). , , OpenCL, FAIL.



::createCmdQue() , OpenCL-. mContext . SUCCESS ( mCmdQue ). , , createContext(
) , FAIL.



::buildProgram(effectName, AssetManager) . ( effectName ) Android JNI. OpenCL-, . - (inline) OpenCL-. NULL . , effectName , , . , OpenCL-, , . , , – OpenCL-. , OpenCL- , – , API OpenCL- .





::createKernel(
) . SUCCESS. mKernel , , , .



::getContext() , ::getCmdQue() ::getKernel() , , , . JNI , OpenCL-.



たずめ



OpenCL-, Android-. OpenCL RenderScript. , , . OpenCL , , , . , .



All Articles