標籤:影像處理 ndk 介面更新
最近的學習真的比較困難,因為學習了SDK開發項目後,做了一些簡單的項目後,覺得在UI線程中載入較多圖片時,總會出現卡頓的感覺,特別是手指滑動下拉時,這種卡頓更易察覺到,而java的結構化開發能力確實是很強大的,使用java開發確實是一件非常享受的事情,但是java在一些高密度的計算中是沒有什麼優勢的,在享受記憶體自動回收時也會遇到一些不如意的事。任何語言或事物,總會有優缺點,這是java如此簡單易用的一個副作用。所以為了不使java的副作用危害到開發人員使用java,java產生了一種非常有吸引力的的技術JNI技術,這種技術可以讓Java調用C/C++和其他的語言所寫的程式。而這種技術也在android中得以支援--NDK, NDK提供了一系列的工具,協助開發人員快速開發C(或C++)的動態庫,並能自動將so和java應用一起打包成apk,使用起來非常方便。
說了一堆的廢話,接下來記錄下自己最近所學習到的東西,可以說NDK重要的學習資料之一就是android的官方網站提供的資料,包括下載了NDK後,也能看到一些簡單的使用了NDK的項目源碼,這些源碼能讓我們知道android官方建議我們如何使用NDK,甚至可以用純C/C++語言開發應用,但這並不是我感興趣的,具體原因就不說了。
按照官方的使用方式還是比較簡單的,這裡寫了一個用C語言提取照片灰階圖的函數,並在java中調用
先寫java代碼
public class PhotoProcessingActivity extends Activity{private Bitmap bmOriginal,bmGray;private ImageView iv;private Button btGray,btOpen;static{System.loadLibrary("PhotoProcessing");}@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.photo_processing_activity);setup();}public void setup(){iv = (ImageView) findViewById(R.id.showPhoto);bmOriginal = ImageShare.mBitmap;iv.setImageBitmap(bmOriginal);btGray = (Button) findViewById(R.id.btGray);btGray.setOnClickListener(onclick);btOpen = (Button) findViewById(R.id.btOpen);btOpen.setOnClickListener(onclick);}OnClickListener onclick = new OnClickListener(){@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch(v.getId()){case R.id.btGray:bmGray = Bitmap.createBitmap(bmOriginal.getWidth(), bmOriginal.getHeight(), Config.ALPHA_8);grayPhoto(bmOriginal, bmGray);iv.setImageBitmap(bmGray);break;case R.id.btOpen:Intent intent = new Intent(PhotoProcessingActivity.this,SurfaceProcessingActivity.class);startActivity(intent);break;}}};public native void grayPhoto(Bitmap bmOriginal,Bitmap bmGray);}使用javah工具得到標頭檔PhotoProcessingActivity.h並且添加處理圖片所需的一些標頭檔,這些標頭檔都是NDK中的include中內建的,使用時可以把把該檔案夾連結進去
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_photoprocessing_activity_PhotoProcessingActivity */#include <android/bitmap.h>#include <android/log.h>#include <math.h>#include <string.h>#ifndef _Included_com_example_photoprocessing_activity_PhotoProcessingActivity#define _Included_com_example_photoprocessing_activity_PhotoProcessingActivity#ifdef __cplusplusextern "C" {#endif#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_PRIVATE#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_PRIVATE 0L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_READABLE#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_READABLE 1L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_WRITEABLE#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_WRITEABLE 2L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_APPEND#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_APPEND 32768L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_MULTI_PROCESS#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_MULTI_PROCESS 4L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING#define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_AUTO_CREATE#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_AUTO_CREATE 1L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_DEBUG_UNBIND#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_DEBUG_UNBIND 2L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_NOT_FOREGROUND#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_NOT_FOREGROUND 4L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ABOVE_CLIENT#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ABOVE_CLIENT 8L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ALLOW_OOM_MANAGEMENT#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ALLOW_OOM_MANAGEMENT 16L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_WAIVE_PRIORITY#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_WAIVE_PRIORITY 32L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_IMPORTANT#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_IMPORTANT 64L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ADJUST_WITH_ACTIVITY#define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ADJUST_WITH_ACTIVITY 128L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_INCLUDE_CODE#define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_INCLUDE_CODE 1L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_IGNORE_SECURITY#define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_IGNORE_SECURITY 2L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_RESTRICTED#define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_RESTRICTED 4L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_CANCELED#define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_CANCELED 0L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_OK#define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_OK -1L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_FIRST_USER#define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_FIRST_USER 1L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DISABLE#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DISABLE 0L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DIALER#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DIALER 1L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SHORTCUT#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SHORTCUT 2L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_LOCAL#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L#undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_GLOBAL#define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L/* * Class: com_example_photoprocessing_activity_PhotoProcessingActivity * Method: grayPhoto * Signature: (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap;)V *//** * xuan */#define LOG_TAG "PhotoProcessing"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)typedef struct {uint8_t alpha;uint8_t red;uint8_t green;uint8_t blue;} argb;JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_PhotoProcessingActivity_grayPhoto (JNIEnv *, jobject, jobject, jobject);#ifdef __cplusplus}#endif#endif接著編寫C代碼
#include "PhotoProcessingActivity.h"JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_PhotoProcessingActivity_grayPhoto(JNIEnv *env, jobject photoProcessingActivity, jobject bmOriginal,jobject bmGray) {AndroidBitmapInfo origanalColor;void* pixelscolor;AndroidBitmapInfo infogray;void* pixelsgray;int ret;int y;int x;LOGI("In convertToGray");if ((ret = AndroidBitmap_getInfo(env, bmOriginal, &origanalColor)) < 0) {LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);return;}if ((ret = AndroidBitmap_getInfo(env, bmGray, &infogray)) < 0) {LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);return;}LOGI("original image :: width is %d; height is %d; stride is %d; format is %d;flags is%d,stride is %u", origanalColor.width, origanalColor.height, origanalColor.stride, origanalColor.format, origanalColor.flags, origanalColor.stride);if (origanalColor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {LOGE("Bitmap format is not RGBA_8888 !");//return;}if (origanalColor.format == ANDROID_BITMAP_FORMAT_RGB_565) {LOGI("Original Image is ANDROID_BITMAP_FORMAT_RGB_565");if ((ret = AndroidBitmap_lockPixels(env, bmOriginal, &pixelscolor))< 0) {LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);}if ((ret = AndroidBitmap_lockPixels(env, bmGray, &pixelsgray)) < 0) {LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);}// modify pixels with image processing algorithmfor (y = 0; y < origanalColor.height; y++) {__uint16_t * line = (__uint16_t *) pixelscolor;uint8_t * grayline = (uint8_t *) pixelsgray;for (x = 0; x < origanalColor.width; x++) {grayline[x] = (uint8_t)(((line[x] >> 11 <<3) + (line[x] >> 5 & 63 * 16) + (line[x]&31 * 8)) / 3);//LOGI("%d %d %d %d",line[x].alpha,line[x].red,line[x].green,line[x].blue);/*if(x ==0){LOGI("line:%o grayline %o ",line[x],grayline[x]);}*/}pixelscolor = (char *) pixelscolor + origanalColor.stride;pixelsgray = (char *) pixelsgray + infogray.stride;}LOGI("unlocking pixels");AndroidBitmap_unlockPixels(env, bmOriginal);AndroidBitmap_unlockPixels(env, bmGray);LOGI("Return !! ");return ;}LOGI("gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d %d,stride is %u", infogray.width, infogray.height, infogray.stride, infogray.format, infogray.flags, infogray.stride);if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) {LOGE("Bitmap format is not A_8 !");return;}if ((ret = AndroidBitmap_lockPixels(env, bmOriginal, &pixelscolor)) < 0) {LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);}if ((ret = AndroidBitmap_lockPixels(env, bmGray, &pixelsgray)) < 0) {LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);}// modify pixels with image processing algorithmfor (y = 0; y < origanalColor.height; y++) {argb * line = (argb *) pixelscolor;uint8_t * grayline = (uint8_t *) pixelsgray;for (x = 0; x < origanalColor.width; x++) {grayline[x] = (line[x].red + line[x].green + line[x].blue) / 3;}pixelscolor = (char *) pixelscolor + origanalColor.stride;pixelsgray = (char *) pixelsgray + infogray.stride;}LOGI("unlocking pixels");AndroidBitmap_unlockPixels(env, bmOriginal);AndroidBitmap_unlockPixels(env, bmGray);}編寫Android.mk檔案,該檔案主要是指明要使用的.so檔案,並且產生我們自己的.so檔案
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := PhotoProcessingLOCAL_SRC_FILES := PhotoProcessing.cppLOCAL_LDLIBS := -llog -ljnigraphicsinclude $(BUILD_SHARED_LIBRARY)
關鍵的一些代碼就是這些了,其中處理的灰階演算法可能不是非常最佳化,這其中處理RGB565部分是我自己根據影像處理中灰階的定義所寫的,其中也要感謝孫志海大哥對我的協助 !!
可以說使用這種方法還是比較簡易的,但是,似乎仍沒解決我一開頭說道的問題,即這種方式僅僅是提升了程式的效率,但依然需要在UI線程中更新介面,這裡也可以使用SurfaceVIew來進行非同步更新介面,但是這裡,我想知道,在不修改android系統源碼情況下,NDK的極限,即它能否直接控制View的surface,使其不通過java代碼就直接把介面重新整理呢?這個可能會涉及到Linux的檔案許可權問題,以及需要翻閱android系統源碼。
望對這個方面感興趣的朋友,能夠和我一起交流,或者能夠給我一些建議。我的QQ是835060947,也可以發郵件給我。
Android 使用NDK處理BItmap及如何通過C/C++直接控制View的suface顯示,學習筆記及方向