android 图像处理sdk,用于AndroidSDK的快速位图模糊

这是一个问答页面,似乎仍有很多点击量。我知道我一直在为这个职位争取选票。但如果你在读这篇文章,你需要意识到在这里张贴的答案(我的和接受的答案)都过时了。如果你想实现高效的模糊今天, 您应该使用Renderscript而不是NDK或Java。Renderscript运行在Android2.2+上(使用Android支持库),所以没有理由不使用它。

旧的答案随之而来,但要小心,因为它已经过时了。

对于未来的谷歌用户,这是我从Yahel的Quasimondo算法端口移植的算法,但使用的是NDK。当然,这是基于雅赫尔的回答。但这是运行本机C代码,所以它更快。快多了。大概快40倍。

我发现使用NDK是所有图像处理应该在Android上进行的方式.一开始实现起来有点烦人(请阅读关于使用JNI和NDK的一个很好的教程这里),但要好得多,而且在很多事情上几乎是实时的。

作为参考,使用Yahel的Java函数,用了10秒的时间模糊了我的480x532像素图像,模糊半径为10,但使用本机C版本需要250 ms。我很确定它还能被进一步优化.。我只是对java代码做了一个简单的转换,可能有一些操作可以缩短,不想花费太多的时间来重构整个过程。#include #include #include #include #include #include #define LOG_TAG "libbitmaputils"#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 red;

uint8_t green;

uint8_t blue;

uint8_t alpha;} rgba;JNIEXPORT void JNICALL Java_com_insert_your_package_ClassName_functionToBlur(JNIEnv* env, jobject obj, jobject bitmapIn, jobject bitmapOut, jint radius) {

LOGI("Blurring bitmap...");

// Properties

AndroidBitmapInfo   infoIn;

void*               pixelsIn;

AndroidBitmapInfo   infoOut;

void*               pixelsOut;

int ret;

// Get image info

if ((ret = AndroidBitmap_getInfo(env, bitmapIn, &infoIn)) 

LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);

return;

}

// Check image

if (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 || infoOut.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {

LOGE("Bitmap format is not RGBA_8888!");

LOGE("==> %d %d", infoIn.format, infoOut.format);

return;

}

// Lock all images

if ((ret = AndroidBitmap_lockPixels(env, bitmapIn, &pixelsIn)) 

LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);

}

int h = infoIn.height;

int w = infoIn.width;

LOGI("Image size is: %i %i", w, h);

rgba* input = (rgba*) pixelsIn;

rgba* output = (rgba*) pixelsOut;

int wm = w - 1;

int hm = h - 1;

int wh = w * h;

int whMax = max(w, h);

int div = radius + radius + 1;

int r[wh];

int g[wh];

int b[wh];

int rsum, gsum, bsum, x, y, i, yp, yi, yw;

rgba p;

int vmin[whMax];

int divsum = (div + 1) >> 1;

divsum *= divsum;

int dv[256 * divsum];

for (i = 0; i 

dv[i] = (i / divsum);

}

yw = yi = 0;

int stack[div][3];

int stackpointer;

int stackstart;

int rbs;

int ir;

int ip;

int r1 = radius + 1;

int routsum, goutsum, boutsum;

int rinsum, ginsum, binsum;

for (y = 0; y 

rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;

for (i = -radius; i <= radius; i++) {

p = input[yi + min(wm, max(i, 0))];

ir = i + radius; // same as sir

stack[ir][0] = p.red;

stack[ir][1] = p.green;

stack[ir][2] = p.blue;

rbs = r1 - abs(i);

rsum += stack[ir][0] * rbs;

gsum += stack[ir][1] * rbs;

bsum += stack[ir][2] * rbs;

if (i > 0) {

rinsum += stack[ir][0];

ginsum += stack[ir][1];

binsum += stack[ir][2];

} else {

routsum += stack[ir][0];

goutsum += stack[ir][1];

boutsum += stack[ir][2];

}

}

stackpointer = radius;

for (x = 0; x 

r[yi] = dv[rsum];

g[yi] = dv[gsum];

b[yi] = dv[bsum];

rsum -= routsum;

gsum -= goutsum;

bsum -= boutsum;

stackstart = stackpointer - radius + div;

ir = stackstart % div; // same as sir

routsum -= stack[ir][0];

goutsum -= stack[ir][1];

boutsum -= stack[ir][2];

if (y == 0) {

vmin[x] = min(x + radius + 1, wm);

}

p = input[yw + vmin[x]];

stack[ir][0] = p.red;

stack[ir][1] = p.green;

stack[ir][2] = p.blue;

rinsum += stack[ir][0];

ginsum += stack[ir][1];

binsum += stack[ir][2];

rsum += rinsum;

gsum += ginsum;

bsum += binsum;

stackpointer = (stackpointer + 1) % div;

ir = (stackpointer) % div; // same as sir

routsum += stack[ir][0];

goutsum += stack[ir][1];

boutsum += stack[ir][2];

rinsum -= stack[ir][0];

ginsum -= stack[ir][1];

binsum -= stack[ir][2];

yi++;

}

yw += w;

}

for (x = 0; x 

rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;

yp = -radius * w;

for (i = -radius; i <= radius; i++) {

yi = max(0, yp) + x;

ir = i + radius; // same as sir

stack[ir][0] = r[yi];

stack[ir][1] = g[yi];

stack[ir][2] = b[yi];

rbs = r1 - abs(i);

rsum += r[yi] * rbs;

gsum += g[yi] * rbs;

bsum += b[yi] * rbs;

if (i > 0) {

rinsum += stack[ir][0];

ginsum += stack[ir][1];

binsum += stack[ir][2];

} else {

routsum += stack[ir][0];

goutsum += stack[ir][1];

boutsum += stack[ir][2];

}

if (i 

yp += w;

}

}

yi = x;

stackpointer = radius;

for (y = 0; y 

output[yi].red = dv[rsum];

output[yi].green = dv[gsum];

output[yi].blue = dv[bsum];

rsum -= routsum;

gsum -= goutsum;

bsum -= boutsum;

stackstart = stackpointer - radius + div;

ir = stackstart % div; // same as sir

routsum -= stack[ir][0];

goutsum -= stack[ir][1];

boutsum -= stack[ir][2];

if (x == 0) vmin[y] = min(y + r1, hm) * w;

ip = x + vmin[y];

stack[ir][0] = r[ip];

stack[ir][1] = g[ip];

stack[ir][2] = b[ip];

rinsum += stack[ir][0];

ginsum += stack[ir][1];

binsum += stack[ir][2];

rsum += rinsum;

gsum += ginsum;

bsum += binsum;

stackpointer = (stackpointer + 1) % div;

ir = stackpointer; // same as sir

routsum += stack[ir][0];

goutsum += stack[ir][1];

boutsum += stack[ir][2];

rinsum -= stack[ir][0];

ginsum -= stack[ir][1];

binsum -= stack[ir][2];

yi += w;

}

}

// Unlocks everything

AndroidBitmap_unlockPixels(env, bitmapIn);

AndroidBitmap_unlockPixels(env, bitmapOut);

LOGI ("Bitmap blurred.");}int min(int a, int b) {

return a > b ? b : a;}int max(int a, int b) {

return a > b ? a : b;}

然后像下面这样使用它(考虑一个名为com.sert.your.Package.ClassName的类和一个名为FunctionToBlur的本机函数,如上面的代码所述):// Create a copyBitmap bitmapOut = bitmapIn.copy(Bitmap.Config.ARGB_8888, true);// Blur the copyfunctionToBlur(bitmapIn, bitmapOut, __radius);

它期望一个RGB_8888位图!

若要使用RGB_565位图,请在传递参数(Yuck)之前创建转换后的副本,或更改函数以使用新的rgb565类型代替rgba:typedef struct {

uint16_t byte0;} rgb565;

问题是,如果你这样做,你就不能阅读.red, .green和.blue对于像素,你需要正确地读取字节,嗯。当我以前需要的时候,我做了这个:r = (pixels[x].byte0 & 0xF800) >> 8;g = (pixels[x].byte0 & 0x07E0) >> 3;b = (pixels[x].byte0 & 0x001F) <

但可能有一些不那么愚蠢的方法。恐怕我不是什么低级的C级编码器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值