Android G高性能的程序设计,Android高性能高斯模糊方案

转载于 http://blog.csdn.net/u012810020/article/details/52059942

简述:

做直播类app的时候点击进入直播间接通的过程中首先显示一张模糊的毛玻璃效果的图片,那么此时就要考虑使用高斯模糊的时候了。Android中提供了RenderScript来操作图片,但是这个的使用版本要求是在API17以上,所以我们还可以考虑使用第三方可FastBlur。

使用RenderScript方案:

Renderscript是android平台上进行高性能计算的框架。Renderscript主要面向并行计算,虽然它对计算密集型工作也是有益的。Renderscript在运行时将在设备上可用的处理器间平衡负载,比如多核CPU,GPU或者DSP,它让你专注于算法而不是平衡负载。RenderScript对图像处理,计算摄影学,计算机视觉方面的应用非常有用。

为了提高模糊的效果以及减少模糊过程中性能的消耗,首先对待模糊的图片进行压缩。废话少说,上代码:

/**

* 类描述:利用RenderScript进行图片的高斯模糊(该方案兼容最低版本API17)

* Created by lizhenya on 16/5/28.

*/

public class RenderScriptBlur {

private static final float BITMAP_SCALE=0.4f;

private static final int BLUR_RADIUS=7;

public static Bitmap blur(Context context, Bitmap bitmap) {

return blur(context, bitmap, BITMAP_SCALE, BLUR_RADIUS);

}

public static Bitmap blur(Context context, Bitmap bitmap, float bitmap_scale) {

return blur(context, bitmap, bitmap_scale, BLUR_RADIUS);

}

public static Bitmap blur(Context context, Bitmap bitmap, int blur_radius) {

return blur(context, bitmap, BITMAP_SCALE, blur_radius);

}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)

public static Bitmap blur(Context context, Bitmap bitmap, float bitmap_scale, int blur_radius) {

//先对图片进行压缩然后再blur

Bitmap inputBitmap=Bitmap.createScaledBitmap(bitmap, Math.round(bitmap.getWidth() * bitmap_scale),

Math.round(bitmap.getHeight() * bitmap_scale), false);

//创建空的Bitmap用于输出

Bitmap outputBitmap=Bitmap.createBitmap(inputBitmap);

//①、初始化Renderscript

RenderScript rs=RenderScript.create(context);

//②、Create an Intrinsic Blur Script using the Renderscript

ScriptIntrinsicBlur theIntrinsic=ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

//③、native层分配内存空间

Allocation tmpIn=Allocation.createFromBitmap(rs, inputBitmap);

Allocation tmpOut=Allocation.createFromBitmap(rs, outputBitmap);

//④、设置blur的半径然后进行blur

theIntrinsic.setRadius(blur_radius);

theIntrinsic.setInput(tmpIn);

theIntrinsic.forEach(tmpOut);

//⑤、拷贝blur后的数据到java缓冲区中

tmpOut.copyTo(outputBitmap);

//⑥、销毁Renderscript

rs.destroy();

bitmap.recycle();

return outputBitmap;

}

}

实际效果如何呢?下面我把多次测试打印出来的日志贴出来:

07-28 17:16:32.394 20734-20734/? E/TAg: 耗时时间:30ms

07-28 17:16:33.450 20734-20734/? E/TAg: 耗时时间:13ms

07-28 17:16:34.207 20734-20734/? E/TAg: 耗时时间:7ms

07-28 17:16:35.045 20734-20734/? E/TAg: 耗时时间:9ms

07-28 17:16:35.909 20734-20734/? E/TAg: 耗时时间:6ms

07-28 17:16:36.806 20734-20734/? E/TAg: 耗时时间:9ms

07-28 17:16:39.312 20734-20734/? E/TAg: 耗时时间:7ms

07-28 17:16:44.045 20734-20734/? E/TAg: 耗时时间:8ms

07-28 17:16:44.877 20734-20734/? E/TAg: 耗时时间:8ms

07-28 17:16:45.555 20734-20734/? E/TAg: 耗时时间:13ms

07-28 17:16:46.202 20734-20734/? E/TAg: 耗时时间:8ms

07-28 17:16:46.901 20734-20734/? E/TAg: 耗时时间:9ms

07-28 17:16:47.952 20734-20734/? E/TAg: 耗时时间:7ms

上面的日志可以一眼看得出平均时间是小于16ms的,时间性能杠杠的。但是这个方案只能适用于API17以上的版本,对于低版本怎么办呢?上网搜了一圈,看到一个第三方的框架FastBlur。

使用FastBlur兼容低版本:

/**

* Created by paveld on 3/6/14.

*/

public class StackBlur {

public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {

// Stack Blur v1.0 from

// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html

//

// Java Author: Mario Klingemann

// http://incubator.quasimondo.com

// created Feburary 29, 2004

// Android port : Yahel Bouaziz

// http://www.kayenko.com

// ported april 5th, 2012

// This is a compromise between Gaussian Blur and Box blur

// It creates much better looking blurs than Box Blur, but is

// 7x faster than my Gaussian Blur implementation.

//

// I called it Stack Blur because this describes best how this

// filter works internally: it creates a kind of moving stack

// of colors whilst scanning through the image. Thereby it

// just has to add one new block of color to the right side

// of the stack and remove the leftmost color. The remaining

// colors on the topmost layer of the stack are either added on

// or reduced by one, depending on if they are on the right or

// on the left side of the stack.

//

// If you are using this algorithm in your code please add

// the following line:

//

// Stack Blur Algorithm by Mario Klingemann

Bitmap bitmap;

if (canReuseInBitmap) {

bitmap=sentBitmap;

} else {

bitmap=sentBitmap.copy(sentBitmap.getConfig(), true);

}

if (radius <1) {

return (null);

}

int w=bitmap.getWidth();

int h=bitmap.getHeight();

int[] pix=newint[w * h];

bitmap.getPixels(pix, 0, w, 0, 0, w, h);

int wm=w- 1;

int hm=h- 1;

int wh=w* h;

int div=radius+ radius + 1;

int r[] = new int[wh];

int g[] = new int[wh];

int b[] = new int[wh];

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

int vmin[] = new int[Math.max(w, h)];

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

divsum *= divsum;

int dv[] = new int[256 * divsum];

for (i=0; i<256* divsum; i++) {

dv[i] = (i / divsum);

}

yw=yi= 0;

int[][] stack=newint[div][3];

int stackpointer;

int stackstart;

int[] sir;

int rbs;

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=pix[yi + Math.min(wm, Math.max(i, 0))];

sir=stack[i + radius];

sir[0] = (p & 0xff0000) >>16;

sir[1] = (p & 0x00ff00) >>8;

sir[2] = (p & 0x0000ff);

rbs=r1- Math.abs(i);

rsum += sir[0] * rbs;

gsum += sir[1] * rbs;

bsum += sir[2] * rbs;

if (i >0) {

rinsum += sir[0];

ginsum += sir[1];

binsum += sir[2];

} else {

routsum += sir[0];

goutsum += sir[1];

boutsum += sir[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;

sir=stack[stackstart % div];

routsum -=sir[0];

goutsum -=sir[1];

boutsum -=sir[2];

if (y== 0) {

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

}

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

sir[0] = (p & 0xff0000) >>16;

sir[1] = (p & 0x00ff00) >>8;

sir[2] = (p & 0x0000ff);

rinsum += sir[0];

ginsum += sir[1];

binsum += sir[2];

rsum += rinsum;

gsum += ginsum;

bsum += binsum;

stackpointer= (stackpointer + 1) % div;

sir=stack[(stackpointer) % div];

routsum += sir[0];

goutsum += sir[1];

boutsum += sir[2];

rinsum -=sir[0];

ginsum -=sir[1];

binsum -=sir[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=Math.max(0, yp) + x;

sir=stack[i + radius];

sir[0] = r[yi];

sir[1] = g[yi];

sir[2] = b[yi];

rbs=r1- Math.abs(i);

rsum += r[yi] * rbs;

gsum += g[yi] * rbs;

bsum += b[yi] * rbs;

if (i >0) {

rinsum += sir[0];

ginsum += sir[1];

binsum += sir[2];

} else {

routsum += sir[0];

goutsum += sir[1];

boutsum += sir[2];

}

if (i 

yp += w;

}

}

yi=x;

stackpointer=radius;

for (y=0; y

// Preserve alpha channel: ( 0xff000000 & pix[yi] )

pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] <<16) | (dv[gsum]<<8) | dv[bsum];

rsum -=routsum;

gsum -=goutsum;

bsum -=boutsum;

stackstart=stackpointer- radius + div;

sir=stack[stackstart % div];

routsum -=sir[0];

goutsum -=sir[1];

boutsum -=sir[2];

if (x== 0) {

vmin[y] = Math.min(y + r1, hm) * w;

}

p=x+ vmin[y];

sir[0] = r[p];

sir[1] = g[p];

sir[2] = b[p];

rinsum += sir[0];

ginsum += sir[1];

binsum += sir[2];

rsum += rinsum;

gsum += ginsum;

bsum += binsum;

stackpointer= (stackpointer + 1) % div;

sir=stack[stackpointer];

routsum += sir[0];

goutsum += sir[1];

boutsum += sir[2];

rinsum -=sir[0];

ginsum -=sir[1];

binsum -=sir[2];

yi += w;

}

}

bitmap.setPixels(pix, 0, w, 0, 0, w, h);

return (bitmap);

}

}

这个方案的时间性能惨不忍睹呀,远远大于16ms,

07-28 18:33:14.751 11928-11928/? E/TAg: 耗时时间:483ms

07-28 18:33:17.602 11928-11928/? E/TAg: 耗时时间:431ms

07-28 18:33:19.176 11928-11928/? E/TAg: 耗时时间:369ms

07-28 18:33:20.452 11928-11928/? E/TAg: 耗时时间:405ms

07-28 18:33:21.599 11928-11928/? E/TAg: 耗时时间:412ms

07-28 18:33:22.791 11928-11928/? E/TAg: 耗时时间:368ms

07-28 18:33:23.970 11928-11928/? E/TAg: 耗时时间:314ms

07-28 18:33:25.059 11928-11928/? E/TAg: 耗时时间:335ms

07-28 18:33:25.886 11928-11928/? E/TAg: 耗时时间:384ms

07-28 18:33:26.806 11928-11928/? E/TAg: 耗时时间:404ms

07-28 18:33:27.423 11928-11928/? E/TAg: 耗时时间:473ms

07-28 18:33:27.959 11928-11928/? E/TAg: 耗时时间:373ms

这个结果也能满足基本的需求,但是对于性能有待进一步的优化。

本次方案设计的Demo链接:Android高斯模糊

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值