Android高性能高斯模糊方案

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

简述:

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

使用RenderScript方案:

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

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

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /**  
  2.  * 类描述:利用RenderScript进行图片的高斯模糊(该方案兼容最低版本API17)  
  3.  * Created by lizhenya on 16/5/28.  
  4.  */  
  5. public class RenderScriptBlur {  
  6.     private static final float BITMAP_SCALE = 0.4f;  
  7.     private static final int BLUR_RADIUS = 7;  
  8.   
  9.     public static Bitmap blur(Context context, Bitmap bitmap) {  
  10.         return blur(context, bitmap, BITMAP_SCALE, BLUR_RADIUS);  
  11.     }  
  12.   
  13.     public static Bitmap blur(Context context, Bitmap bitmap, float bitmap_scale) {  
  14.         return blur(context, bitmap, bitmap_scale, BLUR_RADIUS);  
  15.     }  
  16.   
  17.     public static Bitmap blur(Context context, Bitmap bitmap, int blur_radius) {  
  18.         return blur(context, bitmap, BITMAP_SCALE, blur_radius);  
  19.     }  
  20.   
  21.     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)  
  22.     public static Bitmap blur(Context context, Bitmap bitmap, float bitmap_scale, int blur_radius) {  
  23.         //先对图片进行压缩然后再blur  
  24.         Bitmap inputBitmap = Bitmap.createScaledBitmap(bitmap, Math.round(bitmap.getWidth() * bitmap_scale),  
  25.                 Math.round(bitmap.getHeight() * bitmap_scale), false);  
  26.         //创建空的Bitmap用于输出  
  27.         Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);  
  28.         //①、初始化Renderscript  
  29.         RenderScript rs = RenderScript.create(context);  
  30.         //②、Create an Intrinsic Blur Script using the Renderscript  
  31.         ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));  
  32.         //③、native层分配内存空间  
  33.         Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);  
  34.         Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);  
  35.         //④、设置blur的半径然后进行blur  
  36.         theIntrinsic.setRadius(blur_radius);  
  37.         theIntrinsic.setInput(tmpIn);  
  38.         theIntrinsic.forEach(tmpOut);  
  39.         //⑤、拷贝blur后的数据到java缓冲区中  
  40.         tmpOut.copyTo(outputBitmap);  
  41.         //⑥、销毁Renderscript  
  42.         rs.destroy();  
  43.         bitmap.recycle();  
  44.   
  45.         return outputBitmap;  
  46.     }  
  47.   
  48.   
  49. }  
实际效果如何呢?下面我把多次测试打印出来的日志贴出来:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 07-28 17:16:32.394 20734-20734/? E/TAg: 耗时时间:30ms  
  2. 07-28 17:16:33.450 20734-20734/? E/TAg: 耗时时间:13ms  
  3. 07-28 17:16:34.207 20734-20734/? E/TAg: 耗时时间:7ms  
  4. 07-28 17:16:35.045 20734-20734/? E/TAg: 耗时时间:9ms  
  5. 07-28 17:16:35.909 20734-20734/? E/TAg: 耗时时间:6ms  
  6. 07-28 17:16:36.806 20734-20734/? E/TAg: 耗时时间:9ms  
  7. 07-28 17:16:39.312 20734-20734/? E/TAg: 耗时时间:7ms  
  8. 07-28 17:16:44.045 20734-20734/? E/TAg: 耗时时间:8ms  
  9. 07-28 17:16:44.877 20734-20734/? E/TAg: 耗时时间:8ms  
  10. 07-28 17:16:45.555 20734-20734/? E/TAg: 耗时时间:13ms  
  11. 07-28 17:16:46.202 20734-20734/? E/TAg: 耗时时间:8ms  
  12. 07-28 17:16:46.901 20734-20734/? E/TAg: 耗时时间:9ms  
  13. 07-28 17:16:47.952 20734-20734/? E/TAg: 耗时时间:7ms  
  上面的日志可以一眼看得出平均时间是小于16ms的,时间性能杠杠的。但是这个方案只能适用于API17以上的版本,对于低版本怎么办呢?上网搜了一圈,看到一个第三方的框架FastBlur。

使用FastBlur兼容低版本:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /**  
  2.  * Created by paveld on 3/6/14.  
  3.  */  
  4. public class StackBlur {  
  5.   
  6.     public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {  
  7.   
  8.         // Stack Blur v1.0 from  
  9.         // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html  
  10.         //  
  11.         // Java Author: Mario Klingemann  
  12.         // http://incubator.quasimondo.com  
  13.         // created Feburary 29, 2004  
  14.         // Android port : Yahel Bouaziz  
  15.         // http://www.kayenko.com  
  16.         // ported april 5th, 2012  
  17.   
  18.         // This is a compromise between Gaussian Blur and Box blur  
  19.         // It creates much better looking blurs than Box Blur, but is  
  20.         // 7x faster than my Gaussian Blur implementation.  
  21.         //  
  22.         // I called it Stack Blur because this describes best how this  
  23.         // filter works internally: it creates a kind of moving stack  
  24.         // of colors whilst scanning through the image. Thereby it  
  25.         // just has to add one new block of color to the right side  
  26.         // of the stack and remove the leftmost color. The remaining  
  27.         // colors on the topmost layer of the stack are either added on  
  28.         // or reduced by one, depending on if they are on the right or  
  29.         // on the left side of the stack.  
  30.         //  
  31.         // If you are using this algorithm in your code please add  
  32.         // the following line:  
  33.         //  
  34.         // Stack Blur Algorithm by Mario Klingemann  
  35.   
  36.         Bitmap bitmap;  
  37.         if (canReuseInBitmap) {  
  38.             bitmap = sentBitmap;  
  39.         } else {  
  40.             bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);  
  41.         }  
  42.   
  43.         if (radius < 1) {  
  44.             return (null);  
  45.         }  
  46.   
  47.         int w = bitmap.getWidth();  
  48.         int h = bitmap.getHeight();  
  49.   
  50.         int[] pix = new int[w * h];  
  51.         bitmap.getPixels(pix, 0, w, 0, 0, w, h);  
  52.   
  53.         int wm = w - 1;  
  54.         int hm = h - 1;  
  55.         int wh = w * h;  
  56.         int div = radius + radius + 1;  
  57.   
  58.         int r[] = new int[wh];  
  59.         int g[] = new int[wh];  
  60.         int b[] = new int[wh];  
  61.         int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;  
  62.         int vmin[] = new int[Math.max(w, h)];  
  63.   
  64.         int divsum = (div + 1) >> 1;  
  65.         divsum *= divsum;  
  66.         int dv[] = new int[256 * divsum];  
  67.         for (i = 0; i < 256 * divsum; i++) {  
  68.             dv[i] = (i / divsum);  
  69.         }  
  70.   
  71.         yw = yi = 0;  
  72.   
  73.         int[][] stack = new int[div][3];  
  74.         int stackpointer;  
  75.         int stackstart;  
  76.         int[] sir;  
  77.         int rbs;  
  78.         int r1 = radius + 1;  
  79.         int routsum, goutsum, boutsum;  
  80.         int rinsum, ginsum, binsum;  
  81.   
  82.         for (y = 0; y < h; y++) {  
  83.             rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;  
  84.             for (i = -radius; i <= radius; i++) {  
  85.                 p = pix[yi + Math.min(wm, Math.max(i, 0))];  
  86.                 sir = stack[i + radius];  
  87.                 sir[0] = (p & 0xff0000) >> 16;  
  88.                 sir[1] = (p & 0x00ff00) >> 8;  
  89.                 sir[2] = (p & 0x0000ff);  
  90.                 rbs = r1 - Math.abs(i);  
  91.                 rsum += sir[0] * rbs;  
  92.                 gsum += sir[1] * rbs;  
  93.                 bsum += sir[2] * rbs;  
  94.                 if (i > 0) {  
  95.                     rinsum += sir[0];  
  96.                     ginsum += sir[1];  
  97.                     binsum += sir[2];  
  98.                 } else {  
  99.                     routsum += sir[0];  
  100.                     goutsum += sir[1];  
  101.                     boutsum += sir[2];  
  102.                 }  
  103.             }  
  104.             stackpointer = radius;  
  105.   
  106.             for (x = 0; x < w; x++) {  
  107.   
  108.                 r[yi] = dv[rsum];  
  109.                 g[yi] = dv[gsum];  
  110.                 b[yi] = dv[bsum];  
  111.   
  112.                 rsum -routsum;  
  113.                 gsum -goutsum;  
  114.                 bsum -boutsum;  
  115.   
  116.                 stackstart = stackpointer - radius + div;  
  117.                 sir = stack[stackstart % div];  
  118.   
  119.                 routsum -sir[0];  
  120.                 goutsum -sir[1];  
  121.                 boutsum -sir[2];  
  122.   
  123.                 if (y == 0) {  
  124.                     vmin[x] = Math.min(x + radius + 1, wm);  
  125.                 }  
  126.                 p = pix[yw + vmin[x]];  
  127.   
  128.                 sir[0] = (p & 0xff0000) >> 16;  
  129.                 sir[1] = (p & 0x00ff00) >> 8;  
  130.                 sir[2] = (p & 0x0000ff);  
  131.   
  132.                 rinsum += sir[0];  
  133.                 ginsum += sir[1];  
  134.                 binsum += sir[2];  
  135.   
  136.                 rsum += rinsum;  
  137.                 gsum += ginsum;  
  138.                 bsum += binsum;  
  139.   
  140.                 stackpointer = (stackpointer + 1) % div;  
  141.                 sir = stack[(stackpointer) % div];  
  142.   
  143.                 routsum += sir[0];  
  144.                 goutsum += sir[1];  
  145.                 boutsum += sir[2];  
  146.   
  147.                 rinsum -sir[0];  
  148.                 ginsum -sir[1];  
  149.                 binsum -sir[2];  
  150.   
  151.                 yi++;  
  152.             }  
  153.             yw += w;  
  154.         }  
  155.         for (x = 0; x < w; x++) {  
  156.             rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;  
  157.             yp = -radius * w;  
  158.             for (i = -radius; i <= radius; i++) {  
  159.                 yi = Math.max(0, yp) + x;  
  160.   
  161.                 sir = stack[i + radius];  
  162.   
  163.                 sir[0] = r[yi];  
  164.                 sir[1] = g[yi];  
  165.                 sir[2] = b[yi];  
  166.   
  167.                 rbs = r1 - Math.abs(i);  
  168.   
  169.                 rsum += r[yi] * rbs;  
  170.                 gsum += g[yi] * rbs;  
  171.                 bsum += b[yi] * rbs;  
  172.   
  173.                 if (i > 0) {  
  174.                     rinsum += sir[0];  
  175.                     ginsum += sir[1];  
  176.                     binsum += sir[2];  
  177.                 } else {  
  178.                     routsum += sir[0];  
  179.                     goutsum += sir[1];  
  180.                     boutsum += sir[2];  
  181.                 }  
  182.   
  183.                 if (i < hm) {  
  184.                     yp += w;  
  185.                 }  
  186.             }  
  187.             yi = x;  
  188.             stackpointer = radius;  
  189.             for (y = 0; y < h; y++) {  
  190.                 // Preserve alpha channel: ( 0xff000000 & pix[yi] )  
  191.                 pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];  
  192.   
  193.                 rsum -routsum;  
  194.                 gsum -goutsum;  
  195.                 bsum -boutsum;  
  196.   
  197.                 stackstart = stackpointer - radius + div;  
  198.                 sir = stack[stackstart % div];  
  199.   
  200.                 routsum -sir[0];  
  201.                 goutsum -sir[1];  
  202.                 boutsum -sir[2];  
  203.   
  204.                 if (x == 0) {  
  205.                     vmin[y] = Math.min(y + r1, hm) * w;  
  206.                 }  
  207.                 p = x + vmin[y];  
  208.   
  209.                 sir[0] = r[p];  
  210.                 sir[1] = g[p];  
  211.                 sir[2] = b[p];  
  212.   
  213.                 rinsum += sir[0];  
  214.                 ginsum += sir[1];  
  215.                 binsum += sir[2];  
  216.   
  217.                 rsum += rinsum;  
  218.                 gsum += ginsum;  
  219.                 bsum += binsum;  
  220.   
  221.                 stackpointer = (stackpointer + 1) % div;  
  222.                 sir = stack[stackpointer];  
  223.   
  224.                 routsum += sir[0];  
  225.                 goutsum += sir[1];  
  226.                 boutsum += sir[2];  
  227.   
  228.                 rinsum -sir[0];  
  229.                 ginsum -sir[1];  
  230.                 binsum -sir[2];  
  231.   
  232.                 yi += w;  
  233.             }  
  234.         }  
  235.   
  236.         bitmap.setPixels(pix, 0, w, 0, 0, w, h);  
  237.   
  238.         return (bitmap);  
  239.     }  
  240. }  
这个方案的时间性能惨不忍睹呀,远远大于16ms,

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 07-28 18:33:14.751 11928-11928/? E/TAg: 耗时时间:483ms  
  2. 07-28 18:33:17.602 11928-11928/? E/TAg: 耗时时间:431ms  
  3. 07-28 18:33:19.176 11928-11928/? E/TAg: 耗时时间:369ms  
  4. 07-28 18:33:20.452 11928-11928/? E/TAg: 耗时时间:405ms  
  5. 07-28 18:33:21.599 11928-11928/? E/TAg: 耗时时间:412ms  
  6. 07-28 18:33:22.791 11928-11928/? E/TAg: 耗时时间:368ms  
  7. 07-28 18:33:23.970 11928-11928/? E/TAg: 耗时时间:314ms  
  8. 07-28 18:33:25.059 11928-11928/? E/TAg: 耗时时间:335ms  
  9. 07-28 18:33:25.886 11928-11928/? E/TAg: 耗时时间:384ms  
  10. 07-28 18:33:26.806 11928-11928/? E/TAg: 耗时时间:404ms  
  11. 07-28 18:33:27.423 11928-11928/? E/TAg: 耗时时间:473ms  
  12. 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、付费专栏及课程。

余额充值