# 高斯模糊
- 高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值。
一种实现
[点击打开链接](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值的变化,叠加后产生不同程度的模糊效果。
随滑动变换alpha值的代码如下
示例代码下载 http://download.csdn.net/detail/xu_fu/7628139
图: 
效果图:
核心自然是高斯算法,这里没有深究其中的算法实现,只是项目实现而已。
引用代码:
/** 水平方向模糊度 */
private static float hRadius = 10; /** 竖直方向模糊度 / private static float vRadius = 10; /* 模糊迭代度 */ private static int iterations = 7;
<div>
<div id="highlighter_304250" class="syntaxhighlighter nogutter java">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
`/**`
</div>
<div class="line number2 index1 alt1">
` ``* 高斯模糊`
</div>
<div class="line number3 index2 alt2">
` ``*/`
</div>
<div class="line number4 index3 alt1">
` ``public` `static` `Drawable BoxBlurFilter(Bitmap bmp) {`
</div>
<div class="line number5 index4 alt2">
` ``int` `width = bmp.getWidth();`
</div>
<div class="line number6 index5 alt1">
` ``int` `height = bmp.getHeight();`
</div>
<div class="line number7 index6 alt2">
` ``int``[] inPixels = ``new` `int``[width * height];`
</div>
<div class="line number8 index7 alt1">
` ``int``[] outPixels = ``new` `int``[width * height];`
</div>
<div class="line number9 index8 alt2">
` ``Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);`
</div>
<div class="line number10 index9 alt1">
` ``bmp.getPixels(inPixels, ````, width, ````, ````, width, height);`
</div>
<div class="line number11 index10 alt2">
` ``for` `(``int` `i = ````; i < iterations; i++) {`
</div>
<div class="line number12 index11 alt1">
` ``blur(inPixels, outPixels, width, height, hRadius);`
</div>
<div class="line number13 index12 alt2">
` ``blur(outPixels, inPixels, height, width, vRadius);`
</div>
<div class="line number14 index13 alt1">
` ``}`
</div>
<div class="line number15 index14 alt2">
` ``blurFractional(inPixels, outPixels, width, height, hRadius);`
</div>
<div class="line number16 index15 alt1">
` ``blurFractional(outPixels, inPixels, height, width, vRadius);`
</div>
<div class="line number17 index16 alt2">
` ``bitmap.setPixels(inPixels, ````, width, ````, ````, width, height);`
</div>
<div class="line number18 index17 alt1">
` ``Drawable drawable = ``new` `BitmapDrawable(bitmap);`
</div>
<div class="line number19 index18 alt2">
` ``return` `drawable;`
</div>
<div class="line number20 index19 alt1">
` ``}`
</div>
</div>
</td>
</tr>
</table>
</div>
</div>
核心算法:
`public` `static` `void` `blur(``int``[] in, ``int``[] out, ``int` `width, ``int` `height,`
|
💬 评论