Android 中比较“高效”的图像模糊处理算法

介绍了一种在Android平台上实现图像模糊处理的方法,该方法通过计算每个像素与其相邻像素的平均值来达到模糊效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://www.littledai.com/tag/blurmaskfilter

本文假设读者拥有基础的图像处理概念。

这是今天刚刚完成的一个方法,之前不停地在网上找有关 Android 的图像模糊处理代码。
期间找到了倒影、缩放等参考代码,却无一帖子对模糊处理有过提及。
最多也就是提到使用 BlurMaskFilter 来进行模糊处理。
为了这个害人的帖子,我整整浪费了一下午时间,最后发现它只能用于对 Paint 的边缘进行处理。
而我们要处理的是整幅图像,所以这完完全全是一个骗人的说法。

由于先前在 VB.NET 上处理过图像,也写过相关代码,当时 VB.NET 代码分两种形式:
1、死算:即将每个像素点的颜色值与周围 8 点计算平均值,每计算一次 SetPixel() 一次,这样做非常慢;
2、读取整幅图像的内存数据,也就是已三原色为单位了,数据量(颜色数组)比上一种方法大一倍。
这样的做法可以将所有颜色计算好以后再重新写入内存,肯定比 SetPixel() 更高效。
不过由于也并非通过底层函数对内存操作,因此虽然有提速,效果和 C++ 相比却是小巫见大巫了。

下面说正事,其实 JAVA 和 .NET 很类似的(据说 .NET 的架构师就是 SUN 过去的呢)。
当然也无法直接对内存操作,当然也无法像 .NET 这样间接对内存操作,很抓狂啊!
要知道,我是死也不会用第一种方法死算的!
那么怎么办?我仍然希望从第二种方法入手,虽然慢了一些,但还是能忍受的。
好在 Android 提供了 setPixels() 方法,看清楚,Pixel 后面有 s 的!
这个方法其实是 setPixel() 的“批量”版本,也就是说允许我们一下子填充多个连续的像素。
既然这样,我们离模拟第二点还差一半,那就是取得包含三原色的数组了,看代码吧。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/* 设置图片模糊 */
public static Bitmap SetBlur(Bitmap bmpSource, int Blur)  //源位图,模糊强度
{
     int pixels[] = new int [bmpSource.getWidth() * bmpSource.getHeight()];  //颜色数组,一个像素对应一个元素
     int pixelsRawSource[] = new int [bmpSource.getWidth() * bmpSource.getHeight() * 3 ];  //三原色数组,作为元数据,在每一层模糊强度的时候不可更改
     int pixelsRawNew[] = new int [bmpSource.getWidth() * bmpSource.getHeight() * 3 ];  //三原色数组,接受计算过的三原色值
     bmpSource.getPixels(pixels, 0 , bmpSource.getWidth(), 0 , 0 , bmpSource.getWidth(), bmpSource.getHeight());  //获取像素点
 
     //模糊强度,每循环一次强度增加一次
     for ( int k = 1 ; k <= Blur; k++)
     {
         //从图片中获取每个像素三原色的值
         for ( int i = 0 ; i < pixels.length; i++)
         {
             pixelsRawSource[i * 3 + 0 ] = Color.red(pixels[i]);
             pixelsRawSource[i * 3 + 1 ] = Color.green(pixels[i]);
             pixelsRawSource[i * 3 + 2 ] = Color.blue(pixels[i]);
         }
 
         //取每个点上下左右点的平均值作自己的值
         int CurrentPixel = bmpSource.getWidth() * 3 + 3 ; // 当前处理的像素点,从点(2,2)开始
         for ( int i = 0 ; i < bmpSource.getHeight() - 3 ; i++) // 高度循环
         {
             for ( int j = 0 ; j < bmpSource.getWidth() * 3 ; j++) // 宽度循环
             {
                 CurrentPixel += 1 ;
                 // 取上下左右,取平均值
                 int sumColor = 0 ; // 颜色和
                 sumColor = pixelsRawSource[CurrentPixel - bmpSource.getWidth() * 3 ]; // 上一点
                 sumColor = sumColor + pixelsRawSource[CurrentPixel - 3 ]; // 左一点
                 sumColor = sumColor + pixelsRawSource[CurrentPixel + 3 ]; // 右一点
                 sumColor = sumColor + pixelsRawSource[CurrentPixel + bmpSource.getWidth() * 3 ]; // 下一点
                 pixelsRawNew[CurrentPixel] = Math.round(sumColor / 4 ); // 设置像素点
             }
         }
 
         //将新三原色组合成像素颜色
         for ( int i = 0 ; i < pixels.length; i++)
         {
             pixels[i] = Color.rgb(pixelsRawNew[i * 3 + 0 ], pixelsRawNew[i * 3 + 1 ], pixelsRawNew[i * 3 + 2 ]);
         }
     }
 
     //应用到图像
     Bitmap bmpReturn = Bitmap.createBitmap(bmpSource.getWidth(), bmpSource.getHeight(), Config.ARGB_8888);
     bmpReturn.setPixels(pixels, 0 , bmpSource.getWidth(), 0 , 0 , bmpSource.getWidth(), bmpSource.getHeight());  //必须新建位图然后填充,不能直接填充源图像,否则内存报错
 
     return bmpReturn;
}

代码其实很简单,总体而言就是分为三步:
1、取得该位图所有的字节对应的数据;
2、计算每个像素的模糊平均值;
3、利用颜色数组重新绘图。

这就是跟 VB.NET 不同的地方了,我们在 VB.NET 中是改写内存,而这里是申请新的内存区域。
此外,还多了一个大循环,将上述三步进行多次循环,每次循环前将上一次计算好的平均颜色数组作为新的源数据,这样就能获取更模糊的效果了。

要注意的是,此方法对设备性能要求较高,在 1 GHz 处理器上(三星 Galaxy S i9000)模糊强度为 8 时处理 800 × 400 的图像耗时约 20 秒。
HTC Magic 512 MHz 处理器中约 40 秒,可以说基本保持在一个固定比例中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值