# 高斯模糊 - 高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值。 一种实现 [点击打开链接](http://my.oschina.net/tonywolf/blog/64896)<-这里是一片关于高斯模糊算法的介绍,我们需要首先根据高斯分布函数计算权重值,为了提高效率我们采用一维高斯分布函数,然后处理图像的时候在横向和纵向进行两次计算得到结果。下面是一种实现 <div class="dp-highlighter bg_java"> <div class="bar"> <div class="tools"> **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="29" height="15" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> </div> - <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> gaussBlur(<span class="keyword">int</span>[] data, <span class="keyword">int</span> width, <span class="keyword">int</span> height, <span class="keyword">int</span> radius, - <span class="keyword">float</span> sigma) { - - <span class="keyword">float</span> pa = (<span class="keyword">float</span>) (<span class="number">1</span> / (Math.sqrt(<span class="number">2</span> * Math.PI) * sigma)); - <span class="keyword">float</span> pb = –<span class="number">1</span>.0f / (<span class="number">2</span> * sigma * sigma); - - <span class="comment">// generate the Gauss Matrix</span> - <span class="keyword">float</span>[] gaussMatrix = <span class="keyword">new</span> <span class="keyword">float</span>[radius * <span class="number">2</span> + <span class="number">1</span>]; - <span class="keyword">float</span> gaussSum = 0f; - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>, x = -radius; x <= radius; ++x, ++i) { - <span class="keyword">float</span> g = (<span class="keyword">float</span>) (pa * Math.exp(pb * x * x)); - gaussMatrix[i] = g; - gaussSum += g; - } - - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>, length = gaussMatrix.length; i < length; ++i) { - gaussMatrix[i] /= gaussSum; - } - - <span class="comment">// x direction</span> - <span class="keyword">for</span> (<span class="keyword">int</span> y = <span class="number"></span>; y < height; ++y) { - <span class="keyword">for</span> (<span class="keyword">int</span> x = <span class="number"></span>; x < width; ++x) { - <span class="keyword">float</span> r = <span class="number"></span>, g = <span class="number"></span>, b = <span class="number"></span>; - gaussSum = <span class="number"></span>; - <span class="keyword">for</span> (<span class="keyword">int</span> j = -radius; j <= radius; ++j) { - <span class="keyword">int</span> k = x + j; - <span class="keyword">if</span> (k >= <span class="number"></span> && k < width) { - <span class="keyword">int</span> index = y * width + k; - <span class="keyword">int</span> color = data[index]; - <span class="keyword">int</span> cr = (color & <span class="number">0x00ff0000</span>) >> <span class="number">16</span>; - <span class="keyword">int</span> cg = (color & <span class="number">0x0000ff00</span>) >> <span class="number">8</span>; - <span class="keyword">int</span> cb = (color & <span class="number">0x000000ff</span>); - - r += cr * gaussMatrix[j + radius]; - g += cg * gaussMatrix[j + radius]; - b += cb * gaussMatrix[j + radius]; - - gaussSum += gaussMatrix[j + radius]; - } - } - - <span class="keyword">int</span> index = y * width + x; - <span class="keyword">int</span> cr = (<span class="keyword">int</span>) (r / gaussSum); - <span class="keyword">int</span> cg = (<span class="keyword">int</span>) (g / gaussSum); - <span class="keyword">int</span> cb = (<span class="keyword">int</span>) (b / gaussSum); - - data[index] = cr << <span class="number">16</span> | cg << <span class="number">8</span> | cb | <span class="number">0xff000000</span>; - } - } - - <span class="comment">// y direction</span> - <span class="keyword">for</span> (<span class="keyword">int</span> x = <span class="number"></span>; x < width; ++x) { - <span class="keyword">for</span> (<span class="keyword">int</span> y = <span class="number"></span>; y < height; ++y) { - <span class="keyword">float</span> r = <span class="number"></span>, g = <span class="number"></span>, b = <span class="number"></span>; - gaussSum = <span class="number"></span>; - <span class="keyword">for</span> (<span class="keyword">int</span> j = -radius; j <= radius; ++j) { - <span class="keyword">int</span> k = y + j; - <span class="keyword">if</span> (k >= <span class="number"></span> && k < height) { - <span class="keyword">int</span> index = k * width + x; - <span class="keyword">int</span> color = data[index]; - <span class="keyword">int</span> cr = (color & <span class="number">0x00ff0000</span>) >> <span class="number">16</span>; - <span class="keyword">int</span> cg = (color & <span class="number">0x0000ff00</span>) >> <span class="number">8</span>; - <span class="keyword">int</span> cb = (color & <span class="number">0x000000ff</span>); - - r += cr * gaussMatrix[j + radius]; - g += cg * gaussMatrix[j + radius]; - b += cb * gaussMatrix[j + radius]; - - gaussSum += gaussMatrix[j + radius]; - } - } - - <span class="keyword">int</span> index = y * width + x; - <span class="keyword">int</span> cr = (<span class="keyword">int</span>) (r / gaussSum); - <span class="keyword">int</span> cg = (<span class="keyword">int</span>) (g / gaussSum); - <span class="keyword">int</span> cb = (<span class="keyword">int</span>) (b / gaussSum); - data[index] = cr << <span class="number">16</span> | cg << <span class="number">8</span> | cb | <span class="number">0xff000000</span>; - } - } - } </div> 实际测试会发现这种计算方式是很耗时间的,而且模糊半径越大,从原理也可以看到计算量是平方增长的,所以计算时间也越长。 ## <a name="t2"></a>RenderScript RenderScript是Android在API 11之后加入的,用于高效的图片处理,包括模糊、混合、矩阵卷积计算等,代码示例如下 <div class="dp-highlighter bg_java"> <div class="bar"> <div class="tools"> **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) <div> <embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="29" height="15" align="middle" name="ZeroClipboardMovie_2"> </embed> </div> </div> </div> - <span class="keyword">public</span> Bitmap blurBitmap(Bitmap bitmap){ - - <span class="comment">//Let’s create an empty bitmap with the same size of the bitmap we want to blur</span> - Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); - - <span class="comment">//Instantiate a new Renderscript</span> - RenderScript rs = RenderScript.create(getApplicationContext()); - - <span class="comment">//Create an Intrinsic Blur Script using the Renderscript</span> - ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); - - <span class="comment">//Create the Allocations (in/out) with the Renderscript and the in/out bitmaps</span> - Allocation allIn = Allocation.createFromBitmap(rs, bitmap); - Allocation allOut = Allocation.createFromBitmap(rs, outBitmap); - - <span class="comment">//Set the radius of the blur</span> - blurScript.setRadius(<span class="number">25</span>.f); - - <span class="comment">//Perform the Renderscript</span> - blurScript.setInput(allIn); - blurScript.forEach(allOut); - - <span class="comment">//Copy the final bitmap created by the out Allocation to the outBitmap</span> - allOut.copyTo(outBitmap); - - <span class="comment">//recycle the original bitmap</span> - bitmap.recycle(); - - <span class="comment">//After finishing everything, we destroy the Renderscript.</span> - rs.destroy(); - - <span class="keyword">return</span> outBitmap; - - - } </div> (示例来源 [https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8](https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8)) ## <a name="t3"></a>FastBlur <div> <div class="dp-highlighter bg_java"> <div class="bar"> <div class="tools"> **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) <div> <embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="29" height="15" align="middle" name="ZeroClipboardMovie_3"> </embed> </div> </div> </div> - <span class="keyword">public</span> <span class="keyword">class</span> FastBlur { - - <span class="keyword">public</span> <span class="keyword">static</span> Bitmap doBlur(Bitmap sentBitmap, <span class="keyword">int</span> radius, <span class="keyword">boolean</span> canReuseInBitmap) { - - <span class="comment">// Stack Blur v1.0 from</span> - <span class="comment">// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html</span> - <span class="comment">//</span> - <span class="comment">// Java Author: Mario Klingemann <mario at quasimondo.com></span> - <span class="comment">// http://incubator.quasimondo.com</span> - <span class="comment">// created Feburary 29, 2004</span> - <span class="comment">// Android port : Yahel Bouaziz <yahel at kayenko.com></span> - <span class="comment">// http://www.kayenko.com</span> - <span class="comment">// ported april 5th, 2012</span> - - <span class="comment">// This is a compromise between Gaussian Blur and Box blur</span> - <span class="comment">// It creates much better looking blurs than Box Blur, but is</span> - <span class="comment">// 7x faster than my Gaussian Blur implementation.</span> - <span class="comment">//</span> - <span class="comment">// I called it Stack Blur because this describes best how this</span> - <span class="comment">// filter works internally: it creates a kind of moving stack</span> - <span class="comment">// of colors whilst scanning through the image. Thereby it</span> - <span class="comment">// just has to add one new block of color to the right side</span> - <span class="comment">// of the stack and remove the leftmost color. The remaining</span> - <span class="comment">// colors on the topmost layer of the stack are either added on</span> - <span class="comment">// or reduced by one, depending on if they are on the right or</span> - <span class="comment">// on the left side of the stack.</span> - <span class="comment">//</span> - <span class="comment">// If you are using this algorithm in your code please add</span> - <span class="comment">// the following line:</span> - <span class="comment">//</span> - <span class="comment">// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com></span> - - Bitmap bitmap; - <span class="keyword">if</span> (canReuseInBitmap) { - bitmap = sentBitmap; - } <span class="keyword">else</span> { - bitmap = sentBitmap.copy(sentBitmap.getConfig(), <span class="keyword">true</span>); - } - - <span class="keyword">if</span> (radius < <span class="number">1</span>) { - <span class="keyword">return</span> (<span class="keyword">null</span>); - } - - <span class="keyword">int</span> w = bitmap.getWidth(); - <span class="keyword">int</span> h = bitmap.getHeight(); - - <span class="keyword">int</span>[] pix = <span class="keyword">new</span> <span class="keyword">int</span>[w * h]; - bitmap.getPixels(pix, <span class="number"></span>, w, <span class="number"></span>, <span class="number"></span>, w, h); - - <span class="keyword">int</span> wm = w – <span class="number">1</span>; - <span class="keyword">int</span> hm = h – <span class="number">1</span>; - <span class="keyword">int</span> wh = w * h; - <span class="keyword">int</span> div = radius + radius + <span class="number">1</span>; - - <span class="keyword">int</span> r[] = <span class="keyword">new</span> <span class="keyword">int</span>[wh]; - <span class="keyword">int</span> g[] = <span class="keyword">new</span> <span class="keyword">int</span>[wh]; - <span class="keyword">int</span> b[] = <span class="keyword">new</span> <span class="keyword">int</span>[wh]; - <span class="keyword">int</span> rsum, gsum, bsum, x, y, i, p, yp, yi, yw; - <span class="keyword">int</span> vmin[] = <span class="keyword">new</span> <span class="keyword">int</span>[Math.max(w, h)]; - - <span class="keyword">int</span> divsum = (div + <span class="number">1</span>) >> <span class="number">1</span>; - divsum *= divsum; - <span class="keyword">int</span> dv[] = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">256</span> * divsum]; - <span class="keyword">for</span> (i = <span class="number"></span>; i < <span class="number">256</span> * divsum; i++) { - dv[i] = (i / divsum); - } - - yw = yi = <span class="number"></span>; - - <span class="keyword">int</span>[][] stack = <span class="keyword">new</span> <span class="keyword">int</span>[div][<span class="number">3</span>]; - <span class="keyword">int</span> stackpointer; - <span class="keyword">int</span> stackstart; - <span class="keyword">int</span>[] sir; - <span class="keyword">int</span> rbs; - <span class="keyword">int</span> r1 = radius + <span class="number">1</span>; - <span class="keyword">int</span> routsum, goutsum, boutsum; - <span class="keyword">int</span> rinsum, ginsum, binsum; - - <span class="keyword">for</span> (y = <span class="number"></span>; y < h; y++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = <span class="number"></span>; - <span class="keyword">for</span> (i = -radius; i <= radius; i++) { - p = pix[yi + Math.min(wm, Math.max(i, <span class="number"></span>))]; - sir = stack[i + radius]; - sir[<span class="number"></span>] = (p & <span class="number">0xff0000</span>) >> <span class="number">16</span>; - sir[<span class="number">1</span>] = (p & <span class="number">0x00ff00</span>) >> <span class="number">8</span>; - sir[<span class="number">2</span>] = (p & <span class="number">0x0000ff</span>); - rbs = r1 – Math.abs(i); - rsum += sir[<span class="number"></span>] * rbs; - gsum += sir[<span class="number">1</span>] * rbs; - bsum += sir[<span class="number">2</span>] * rbs; - <span class="keyword">if</span> (i > <span class="number"></span>) { - rinsum += sir[<span class="number"></span>]; - ginsum += sir[<span class="number">1</span>]; - binsum += sir[<span class="number">2</span>]; - } <span class="keyword">else</span> { - routsum += sir[<span class="number"></span>]; - goutsum += sir[<span class="number">1</span>]; - boutsum += sir[<span class="number">2</span>]; - } - } - stackpointer = radius; - - <span class="keyword">for</span> (x = <span class="number"></span>; 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[<span class="number"></span>]; - goutsum -= sir[<span class="number">1</span>]; - boutsum -= sir[<span class="number">2</span>]; - - <span class="keyword">if</span> (y == <span class="number"></span>) { - vmin[x] = Math.min(x + radius + <span class="number">1</span>, wm); - } - p = pix[yw + vmin[x]]; - - sir[<span class="number"></span>] = (p & <span class="number">0xff0000</span>) >> <span class="number">16</span>; - sir[<span class="number">1</span>] = (p & <span class="number">0x00ff00</span>) >> <span class="number">8</span>; - sir[<span class="number">2</span>] = (p & <span class="number">0x0000ff</span>); - - rinsum += sir[<span class="number"></span>]; - ginsum += sir[<span class="number">1</span>]; - binsum += sir[<span class="number">2</span>]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + <span class="number">1</span>) % div; - sir = stack[(stackpointer) % div]; - - routsum += sir[<span class="number"></span>]; - goutsum += sir[<span class="number">1</span>]; - boutsum += sir[<span class="number">2</span>]; - - rinsum -= sir[<span class="number"></span>]; - ginsum -= sir[<span class="number">1</span>]; - binsum -= sir[<span class="number">2</span>]; - - yi++; - } - yw += w; - } - <span class="keyword">for</span> (x = <span class="number"></span>; x < w; x++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = <span class="number"></span>; - yp = -radius * w; - <span class="keyword">for</span> (i = -radius; i <= radius; i++) { - yi = Math.max(<span class="number"></span>, yp) + x; - - sir = stack[i + radius]; - - sir[<span class="number"></span>] = r[yi]; - sir[<span class="number">1</span>] = g[yi]; - sir[<span class="number">2</span>] = b[yi]; - - rbs = r1 – Math.abs(i); - - rsum += r[yi] * rbs; - gsum += g[yi] * rbs; - bsum += b[yi] * rbs; - - <span class="keyword">if</span> (i > <span class="number"></span>) { - rinsum += sir[<span class="number"></span>]; - ginsum += sir[<span class="number">1</span>]; - binsum += sir[<span class="number">2</span>]; - } <span class="keyword">else</span> { - routsum += sir[<span class="number"></span>]; - goutsum += sir[<span class="number">1</span>]; - boutsum += sir[<span class="number">2</span>]; - } - - <span class="keyword">if</span> (i < hm) { - yp += w; - } - } - yi = x; - stackpointer = radius; - <span class="keyword">for</span> (y = <span class="number"></span>; y < h; y++) { - <span class="comment">// Preserve alpha channel: ( 0xff000000 & pix[yi] )</span> - pix[yi] = (<span class="number">0xff000000</span> & pix[yi]) | (dv[rsum] << <span class="number">16</span>) | (dv[gsum] << <span class="number">8</span>) | dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer – radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[<span class="number"></span>]; - goutsum -= sir[<span class="number">1</span>]; - boutsum -= sir[<span class="number">2</span>]; - - <span class="keyword">if</span> (x == <span class="number"></span>) { - vmin[y] = Math.min(y + r1, hm) * w; - } - p = x + vmin[y]; </div> </div> - sir[<span class="number"></span>] = r[p]; - sir[<span class="number">1</span>] = g[p]; - sir[<span class="number">2</span>] = b[p]; - - rinsum += sir[<span class="number"></span>]; - ginsum += sir[<span class="number">1</span>]; - binsum += sir[<span class="number">2</span>]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + <span class="number">1</span>) % div; - sir = stack[stackpointer]; - - routsum += sir[<span class="number"></span>]; - goutsum += sir[<span class="number">1</span>]; - boutsum += sir[<span class="number">2</span>]; - - rinsum -= sir[<span class="number"></span>]; - ginsum -= sir[<span class="number">1</span>]; - binsum -= sir[<span class="number">2</span>]; - - yi += w; - } - } - - bitmap.setPixels(pix, <span class="number"></span>, w, <span class="number"></span>, <span class="number"></span>, w, h); - - <span class="keyword">return</span> (bitmap); - } 这里的方法也可以实现高斯模糊的效果,但使用了特殊的算法,比第一种可以快很多,但比起RenderScript还是慢一些 (示例来源 [Android高级模糊技术](http://blog.jobbole.com/63894/)) 实现YAHOO天气的动态模糊效果 YAHOO天气中的背景会随着手指上滑模糊程度加深,实际使用中发现怎么都达不到那样流畅的效果,因为手势刷新的速度很快,每一帧都去重新模糊计算一遍,还是会有延迟,造成页面卡顿。后来在一次偶然的开发中发现其实不需要每一帧都重新去模糊一遍,而是将图片最大程度模糊一次,之后和原图叠加,通过改变叠加的模糊图片的alpha值来达到不同程度的模糊效果。下面是一个例子,可以看到随着模糊图片alpha值的变化,叠加后产生不同程度的模糊效果。
...