http://blog.csdn.net/jdsjlzx/article/details/51699463
转自一叶飘舟
之前做过高斯模糊的的效果,不过依赖一个三方库,今天看到了一篇文章,一个类文件就能解决,感觉窃喜,分享给大家。
三方库Android-stackblur:https://github.com/kikoso/android-stackblur
使用:
Glide.with(getActivity()).load(mUser.avatarUrl).asBitmap().into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { if(resource != null) { StackBlurManager stackBlurManager = new StackBlurManager(resource); Bitmap bitmap = stackBlurManager.process(20); mUserContainer.setBackground(new BitmapDrawable(getResources(),bitmap)); } } }); 12345678910 12345678910使用简单方便。
正文开始。
我要做的效果就是自定义image大小,自定义高斯模糊的区域,这样才算我要的效果。
先上图分别是优化前和优化后的,大家可想这个优化的作用多么巨大,我直接把这个效果的显示耗时在界面绘制出来了,下面图片中的单位打错了额,是ms。
3ms VS 209ms
4ms VS 197ms
说下实现吧,那个算法我就没有怎么研究了,直接是个算法类,直接把要模糊的Bitmap传进去返回的就是模糊后的。代码如下:
public class FastBlur { 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 <mario at="" quasimondo.com=""> // http://incubator.quasimondo.com // created Feburary 29, 2004 // Android port : Yahel Bouaziz <yahel at="" kayenko.com=""> // 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 <mario@quasimondo.com> 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); } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238接下来就是在代码中去用了。
先上优化前的方法:因为下面红字部分那句的代码把我坑惨了,原来用了matrix,在新建的时候还是要用matrix前的大小,我也是晕的不要不要的了。。。
还有注意要根据演示区域的大小,缩放bitmap的大小后再剪裁,再模糊。 这里顺便熟悉了canvas,drawBitmap,放大缩小的一些方法
public void test(View v) { Bitmap srcbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meitu); long t1 = System.currentTimeMillis(); imageView.setBackground(new BitmapDrawable(getResources(), srcbitmap));// 设置大背景 Bitmap backBitmap = Bitmap.createBitmap(textView.getMeasuredWidth(),// 设置需高斯模糊的背景 textView.getMeasuredHeight(), Config.RGB_565); float f1 = (float) imageView.getMeasuredWidth() / (float) srcbitmap.getWidth(); float f2 = (float) imageView.getMeasuredHeight() / (float) srcbitmap.getHeight(); Matrix matrix = new Matrix(); matrix.postScale(f1, f2); Bitmap desBitmap = Bitmap.createBitmap(srcbitmap, 0, 0, srcbitmap.getWidth(), srcbitmap.getHeight(), matrix, true); //因为作为背景的bmp已经缩放,那么需要剪裁的bmp也要缩放----------这里3/4参数是坑 Bitmap lastBitmap = Bitmap.createBitmap(desBitmap, textView.getLeft(), textView.getTop(), textView.getMeasuredWidth(), textView.getMeasuredHeight()); // 根据模糊的区域剪裁 Canvas canvas = new Canvas(backBitmap); canvas.drawBitmap(lastBitmap, 0, 0, new Paint()); backBitmap = FastBlur.doBlur(backBitmap, (int) 20, true); textView.setBackground(new BitmapDrawable(getResources(), backBitmap)); long t2 = System.currentTimeMillis(); textView.setText((t2 - t1) + "S");// 319S } 1234567891011121314151617181920212223242526272829303132 1234567891011121314151617181920212223242526272829303132下面是优化后的方法: 其实现原理是反正效果也是模糊的,先把图片弄小模糊,再把模糊放大,这样就减少了算法的复杂度
public void test2(View v) { int rad = 8; Bitmap srcbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meitu); long t1 = System.currentTimeMillis(); imageView.setBackground(new BitmapDrawable(getResources(), srcbitmap));// 设置大背景 Bitmap backBitmap = Bitmap.createBitmap(textView.getMeasuredWidth()/rad,// 设置需高斯模糊的背景 textView.getMeasuredHeight()/rad, Config.RGB_565); float f1 = (float) imageView.getMeasuredWidth() / (float) srcbitmap.getWidth(); float f2 = (float) imageView.getMeasuredHeight() / (float) srcbitmap.getHeight(); Matrix matrix = new Matrix(); matrix.postScale(f1/8, f2/8); Bitmap desBitmap = Bitmap.createBitmap(srcbitmap, 0, 0, srcbitmap.getWidth(), srcbitmap.getHeight(), matrix, true); // 因为作为背景的bmp已经缩放,那么需要剪裁的bmp也要缩放----------这里3/4参数是坑 Bitmap lastBitmap = Bitmap.createBitmap(desBitmap, textView.getLeft()/8, textView.getTop()/8, textView.getMeasuredWidth()/8, textView.getMeasuredHeight()/8); // 根据模糊的区域剪裁 Canvas canvas = new Canvas(backBitmap); canvas.drawBitmap(lastBitmap, 0, 0, new Paint()); backBitmap = FastBlur.doBlur(backBitmap, (int) 2, true); canvas.scale(1/rad, 1/rad); textView.setBackground(new BitmapDrawable(getResources(), backBitmap)); long t2 = System.currentTimeMillis(); textView.setText((t2 - t1) + "S");// 2S } 1234567891011121314151617181920212223242526272829303132333435 1234567891011121314151617181920212223242526272829303132333435摘自:http://blog.csdn.net/scboyhj__/article/details/50273059