转载于 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
使用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 = new int[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 = new int[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 < h; 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 < w; 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 < w; 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 < hm) {
- yp += w;
- }
- }
- yi = x;
- stackpointer = radius;
- for (y = 0; y < h; 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);
- }
- }
- 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高斯模糊