高斯模糊

高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值。

一种实现

点击打开链接<-这里是一片关于高斯模糊算法的介绍,我们需要首先根据高斯分布函数计算权重值,为了提高效率我们采用一维高斯分布函数,然后处理图像的时候在横向和纵向进行两次计算得到结果。下面是一种实现

  1. public static void gaussBlur(int[] data, int width, int height, int radius,
  2. float sigma) {
  3. float pa = (float) (1 / (Math.sqrt(2 * Math.PI) * sigma));
  4. float pb = -1.0f / (2 * sigma * sigma);
  5. // generate the Gauss Matrix
  6. float[] gaussMatrix = new float[radius * 2 + 1];
  7. float gaussSum = 0f;
  8. for (int i = 0, x = -radius; x <= radius; ++x, ++i) {
  9. float g = (float) (pa * Math.exp(pb * x * x));
  10. gaussMatrix[i] = g;
  11. gaussSum += g;
  12. }
  13. for (int i = 0, length = gaussMatrix.length; i < length; ++i) {
  14. gaussMatrix[i] /= gaussSum;
  15. }
  16. // x direction
  17. for (int y = 0; y < height; ++y) {
  18. for (int x = 0; x < width; ++x) {
  19. float r = 0, g = 0, b = 0;
  20. gaussSum = 0;
  21. for (int j = -radius; j <= radius; ++j) {
  22. int k = x + j;
  23. if (k >= 0 && k < width) {
  24. int index = y * width + k;
  25. int color = data[index];
  26. int cr = (color & 0x00ff0000) >> 16;
  27. int cg = (color & 0x0000ff00) >> 8;
  28. int cb = (color & 0x000000ff);
  29. r += cr * gaussMatrix[j + radius];
  30. g += cg * gaussMatrix[j + radius];
  31. b += cb * gaussMatrix[j + radius];
  32. gaussSum += gaussMatrix[j + radius];
  33. }
  34. }
  35. int index = y * width + x;
  36. int cr = (int) (r / gaussSum);
  37. int cg = (int) (g / gaussSum);
  38. int cb = (int) (b / gaussSum);
  39. data[index] = cr << 16 | cg << 8 | cb | 0xff000000;
  40. }
  41. }
  42. // y direction
  43. for (int x = 0; x < width; ++x) {
  44. for (int y = 0; y < height; ++y) {
  45. float r = 0, g = 0, b = 0;
  46. gaussSum = 0;
  47. for (int j = -radius; j <= radius; ++j) {
  48. int k = y + j;
  49. if (k >= 0 && k < height) {
  50. int index = k * width + x;
  51. int color = data[index];
  52. int cr = (color & 0x00ff0000) >> 16;
  53. int cg = (color & 0x0000ff00) >> 8;
  54. int cb = (color & 0x000000ff);
  55. r += cr * gaussMatrix[j + radius];
  56. g += cg * gaussMatrix[j + radius];
  57. b += cb * gaussMatrix[j + radius];
  58. gaussSum += gaussMatrix[j + radius];
  59. }
  60. }
  61. int index = y * width + x;
  62. int cr = (int) (r / gaussSum);
  63. int cg = (int) (g / gaussSum);
  64. int cb = (int) (b / gaussSum);
  65. data[index] = cr << 16 | cg << 8 | cb | 0xff000000;
  66. }
  67. }
  68. }

实际测试会发现这种计算方式是很耗时间的,而且模糊半径越大,从原理也可以看到计算量是平方增长的,所以计算时间也越长。

RenderScript

RenderScript是Android在API 11之后加入的,用于高效的图片处理,包括模糊、混合、矩阵卷积计算等,代码示例如下

  1. public Bitmap blurBitmap(Bitmap bitmap){
  2. //Let's create an empty bitmap with the same size of the bitmap we want to blur
  3. Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
  4. //Instantiate a new Renderscript
  5. RenderScript rs = RenderScript.create(getApplicationContext());
  6. //Create an Intrinsic Blur Script using the Renderscript
  7. ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
  8. //Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
  9. Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
  10. Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
  11. //Set the radius of the blur
  12. blurScript.setRadius(25.f);
  13. //Perform the Renderscript
  14. blurScript.setInput(allIn);
  15. blurScript.forEach(allOut);
  16. //Copy the final bitmap created by the out Allocation to the outBitmap
  17. allOut.copyTo(outBitmap);
  18. //recycle the original bitmap
  19. bitmap.recycle();
  20. //After finishing everything, we destroy the Renderscript.
  21. rs.destroy();
  22. return outBitmap;
  23. }

(示例来源 https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8

FastBlur

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

这里的方法也可以实现高斯模糊的效果,但使用了特殊的算法,比第一种可以快很多,但比起RenderScript还是慢一些

 
(示例来源 Android高级模糊技术
 

实现YAHOO天气的动态模糊效果

  YAHOO天气中的背景会随着手指上滑模糊程度加深,实际使用中发现怎么都达不到那样流畅的效果,因为手势刷新的速度很快,每一帧都去重新模糊计算一遍,还是会有延迟,造成页面卡顿。后来在一次偶然的开发中发现其实不需要每一帧都重新去模糊一遍,而是将图片最大程度模糊一次,之后和原图叠加,通过改变叠加的模糊图片的alpha值来达到不同程度的模糊效果。下面是一个例子,可以看到随着模糊图片alpha值的变化,叠加后产生不同程度的模糊效果。

随滑动变换alpha值的代码如下

  1. mBlurImage.setOnTouchListener(new OnTouchListener() {
  2. private float mLastY;
  3. @Override
  4. public boolean onTouch(View v, MotionEvent event) {
  5. switch (event.getAction()) {
  6. case MotionEvent.ACTION_DOWN:
  7. mLastY = event.getY();
  8. break;
  9. case MotionEvent.ACTION_MOVE:
  10. float y = event.getY();
  11. float alphaDelt = (y - mLastY) / 1000;
  12. float alpha = mBlurImage.getAlpha() + alphaDelt;
  13. if (alpha > 1.0) {
  14. alpha = 1.0f;
  15. } else if (alpha < 0.0) {
  16. alpha = 0.0f;
  17. }
  18. mTextView.setText(String.valueOf(alpha));
  19. mBlurImage.setAlpha(alpha);
  20. break;
  21. case MotionEvent.ACTION_UP:
  22. break;
  23. }
  24. return true;
  25. }
  26. });

示例代码下载 http://download.csdn.net/detail/xu_fu/7628139

最新文章

  1. 学习笔记-----Android的View绘制过程
  2. SpringMVC中的controller默认是单例的原因
  3. gradle使用eclipse debug 代码
  4. Spark SQL概念学习系列之Spark生态之Spark SQL(七)
  5. OpenJudge 2747 数字方格
  6. 最新Connectify注冊码(序列号) Connectify3.7序列号 破解版
  7. MFC 单文档中动态添加菜单项和响应菜单事件
  8. 使用require.js和backbone实现简单单页应用实践
  9. VBS获取Ini配置文件一个节点下的所有字段的值
  10. Hopfield神经网络实现污染字体的识别
  11. Android内存泄露的原因
  12. Huffman Tree 简单构造
  13. 在虚拟机中搭建qduoj(一)——准备工作
  14. 面向对象学习(python)
  15. C#版 - 小红书后台开发面试题: 二维数组中的查找
  16. Revit二次开发之获得项目族预览图
  17. nginx配置ssl证书
  18. HTTPS 基本流程3
  19. 启动tomcat时报错:http-nio-8080-exec-10
  20. Windows Server 2016-Active Directory域服务端口汇总

热门文章

  1. [转] VR-FORCES 介绍
  2. 微信分享签名Java代码实现
  3. E: 无法获得锁 /var/cache/apt/archives/lock - open (11 资源临时不可用)
  4. 字典序全排列(java实现)
  5. Sonar在ant工程中读取单元测试和覆盖率报告
  6. maven编译报错 -source 1.5 中不支持 lambda 表达式(转)
  7. 根据马甲、应用商店、统计每天的注册量,要求可以根据选择马甲和app,马甲和appstrore和user_login不同表问题
  8. 使用POI导出Excel(二)-利用模板
  9. iPhone设备及屏幕适配
  10. Idea 使用 Maven 搭建 Web 项目