高斯模糊

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

一种实现

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

  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

Android图片高斯模糊的一些方法的更多相关文章

  1. android 图片叠加效果——两种方法

    效果图: 第一种: 第二种: 第一种是通过canvas画出来的效果: public void first(View v) { // 防止出现Immutable bitmap passed to Can ...

  2. android 图片叠加效果——两种方法的简介与内容 ,带解决Immutable bitmap passed to Canvas constructor错误

    第一种是通过canvas画出来的效果: public void first(View v) { // 防止出现Immutable bitmap passed to Canvas constructor ...

  3. Android 图片圆角的简单方法

    package com.jereh.helloworld.activity.ui; import android.content.Context; import android.graphics.Ca ...

  4. android图片处理方法

    Java代码 //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ...

  5. 转-android图片降低图片大小保持图片清晰的方法

    http://i.cnblogs.com/EditPosts.aspx?opt=1 android里面对于图片的处理一直是个比较烦人的问题,烦人之处在于一个不小心,就有可能造成OOM. 最近碰到一个关 ...

  6. android图片压缩方法

    android 图片压缩方法: 第一:质量压缩法: private Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = ...

  7. android图片处理方法(不断收集中)

    //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArr ...

  8. Android 图片处理方法

    //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArr ...

  9. android图片处理方法(转)

    //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArr ...

随机推荐

  1. Jmeter界面总是有warning提示

    要用Jmeter测试服务器性能,发现GUI界面总是有warning提示: WARNING: Could not open/create prefs root node Software\JavaSof ...

  2. c++指向指针的指针与 c++指针作为函数参数传递问题

    一直搞不明白,c++中指针到底是个啥东西,今天遇到到c++,指向指针的指针的问题,突然有点开窍了. 举个例子: int main(int argc, char** argv){ int a[5]={1 ...

  3. Linux命令详解-info

    info是一种文档格式,也是阅读此格式文档的阅读器:我们常用它来查看Linux命令的info文档.它以主题的形式把几个命令组织在一起,以便于我们阅读:在主题内以node(节点)的形式把本主题的几个命令 ...

  4. C#皮肤之IrisSkin4.dll

    1. 将IrisSkin4.dll动态文件导入当前项目引用中.具体操作为:解决方案资源管理器->当前项目->引用->右键->添加引用,找到IrisSkin4.dll文件,然后加 ...

  5. 调试工具-fiddler:本地资源替换线上调试

    Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(指cookie,html,js,css等文件,这 ...

  6. Zabbix SNMP OID discovery,自动发现

    Unlike file system and network interface discovery, the item does not necessarily have to have “snmp ...

  7. Class 'SoapClient' not found 解决方法

    Class 'SoapClient' not found ? 在百度上搜了解决办法,可是收效不佳,只知道好像要添加soap扩展模块,但怎么添加却没有说.于是,我上了google.果然,查看一些英文资料 ...

  8. Docker ENTRYPOINT

    entrypoint: 在启动镜像的时候会执行这个命令下的脚本,在docker run 和docker start情况下都会触发. 好比这个脚本是对某一个文件追加数据,每次start的时候都会追加,文 ...

  9. 《Agile Web Development With Rails》读后感--rails基于web设计的best Practices

    最近看完<Agile Web Development with Rails>一书,受益匪浅.书中先是用一个简单的web应用带你进入Rails的世界,然后在你大致熟悉之后,再带你了解Rail ...

  10. block 回调个人理解

    在网上见过这么个面试题 使用block和GCD时要注意些什么?他们是一回事吗?block在ARC和MRC的用法有什么不同?使用时要注意些什么? 首先block 和 GCD 在我看来他们是完全不同的概念 ...