VB图像处理,(七)一种邻近均值滤波器的算法介绍(去尘,去噪音)

图像噪音来源众多,视图像来源而定:扫描仪,数码相机,摄像头等等,均会产生图像噪音。
而图像噪音又可以分为点,线,背景波纹等等。
这里简单介绍一下点和线类型的噪音去除算法。

看过我的系列的前几篇文章的朋友,可以发现“模糊”算法也具有去除噪音的效果,
这是因为模糊本身就是一个高频滤波器,但是由于这个模糊算法并非专门为去除噪音而设计,
如果你把它用来去除噪音,那么估计效果是惨不忍睹了。
(噪音点被平均分摊到周围的区域中去了,淡是淡了,范围却变大了)

现在我们要优化一下模糊算法,使之更适用于去除图像噪音,而又不会不分好坏,对正常图像影响太大。

首先,我们来看一下噪音点的形态。一般由于输入设备上的灰尘或划痕(扫描仪,数码相机),造成输入的
数码图像上带上了细微的杂色点或细线。
这些杂点或细线的宽度比较小,一般在1到数个象素之间。
(要是很大的斑点,估计大家就会去清理输入设备重新输入了)
并且,这些杂点的颜色(亮度)和正常图片的差异痕大。

因此我们可以针对每一个象素,取一个范围,比如它周围的最相邻的8个或24(或更多)像素 *注1
在这个范围内的所有象素和当前象素做一个比较,取差异最小的K个象素,用这几个象素的平均值来代替当前象素。

(实际的做法是还要设置一个阀值,当这K个像素平均值和当前像素的差异超过这个阀值的时候,当前像素才会被替换)
这样就有两种情况会发生:
1:当前象素是噪音点:
如果当前象素是噪音点,那么即使是和它的差值最接近的K个象素也都是正常象素,他们的平均值也依然在正常范围内。
因此替代之后,当前的噪音点就被正常点给替代了,也就是说噪音点被去除了。
2:当前点是正常点:
如果当前点是正常点,那么和它差异最小的K个点的平均值代替当前点之后,新点和原来点的差异很小,图像基本不变。
(这里有个假定前提:自然图片,包括照片或摄像输入的图片的主体是色彩平滑的,突变点很少)
因此如果图像本身是一个有很多不平滑的突变点构成的话,那么这些突变点也会被认为是噪音点而被去除。
下面举例子:范围为1,一共9个点,取最接近的点数5点:
(当前点:6)
3  4  5     
6  5 =》最接近的5个点为4,5,5,7,8
3  7  8
均值=(4+5+5+7+8)/5=5.8=>6(四舍五入会比较精确点,当然也可以直接取整=5)
运算后结果为:
3  4  5            3  4  5
6  5  或者  5  5
3  7  8            3  7  8

例2:范围为2,一共25个点,取最接近的点数12点:
(当前点:9)
4  5  5  6  4
3  5  6  3  7
4  3  9  7  8 =》最接近的12点为5,5,5,
5  6  4  6  4                  6,6,6,6,6,7,7,7,8
5  3  4  6  7
均值=(5+5+5+6+6+6+6+6+7+7+7+8)/12=6.2=>6
运算后结果为:
4  5  5  6  4
3  5  6  3  7
4  3  6  7  8
5  6  4  6  4
5  3  4  6  7
可以看出该噪音点已经被去除。

经过上面的例子可以看出这个算法对于正常点和噪音点确实有不同的效果了吧。
有点类似于奥运会打分“去掉一个最高分,再去掉一个最低分...”的效果。

不过因为每一个象素的处理都要进行一次排序,(范围为1的话也有9个点)
因此在处理速度上会比较慢,需要对算法进行狠狠的优化。

'》》》》》》》》》》》》》》》》》》》去尘功能(稍微有点难写的功能,那个敏感度的设置是个问题,也是最耗时的功能)
'》》》》中间还有一个排序算法,想想看每一个像素都要和周围的8个像素来一次排序,就知道不会快了。
'》》排序所用的算法参考:http://community.csdn.net/Expert/topic/5005/5005438.xml?temp=.682873
'》》和http://community.csdn.net/Expert/topic/4985/4985999.xml?temp=.9872553这两个帖子,不注释了
Public Sub Filter(Optional ByVal TemplateSize As Byte = 1, Optional ByVal SortNum As Long = 4, Optional ByVal Sensitivity As Integer = 50)
Dim X As Long
Dim Y As Long
Dim X1 As Long
Dim Y1 As Long
Dim TemplNum As Long
Dim RGB() As Long
Dim DRGB() As Long
Dim I As Long
Dim L As Long
Dim M As Long
Dim N As Long
Dim P As Long
Dim XBegin As Long
Dim YBegin As Long
Dim XEnd As Long
Dim YEnd As Long
Dim XBegin1 As Long
Dim YBegin1 As Long
Dim XEnd1 As Long
Dim YEnd1 As Long

If Not CanPut Then Exit Sub
Done = False
TimeProcess = timeGetTime

TemplNum = (TemplateSize * 2 + 1) ^ 2 - 1
ReDim RGB(TemplNum)
ReDim DRGB(TemplNum)

XBegin = TemplateSize
YBegin = TemplateSize
XEnd = OutPutWid - TemplateSize '- 1
YEnd = OutPutHei - TemplateSize '- 1

For X = XBegin To XEnd
   XBegin1 = X - TemplateSize
   XEnd1 = X + TemplateSize
   For Y = YBegin To YEnd
      YBegin1 = Y - TemplateSize
      YEnd1 = Y + TemplateSize
      For I = 0 To 2
         L = 0
         For X1 = XBegin1 To XEnd1
            For Y1 = YBegin1 To YEnd1
               RGB(L) = ColOut(I, X1, Y1)
               M = ColOut(I, X, Y)
               DRGB(L) = Abs(RGB(L) - M)
               L = L + 1
            Next
         Next
         For M = 0 To SortNum
            For N = SortNum + 1 To TemplNum
               If DRGB(M) > DRGB(N) Then
                  L = DRGB(M)
                  DRGB(M) = DRGB(N)
                  DRGB(N) = L
                 
                  L = RGB(M)
                  RGB(M) = RGB(N)
                  RGB(N) = L
               End If
            Next
         Next
         If DRGB(TemplateSize + 2) >= Sensitivity And DRGB(TemplateSize + 3) >= Sensitivity Then
            P = 0
            For L = TemplateSize + 1 To SortNum + TemplateSize - 1
               P = P + RGB(L)
            Next
            P = P / SortNum
            ColOut(I, X, Y) = P
         End If
      Next
   Next
Next

Done = True
TimeProcess = timeGetTime - TimeProcess
Exit Sub
ErrLine:
Done = True
MsgBox Err.Description

End Sub

该函数的调用,如果选择范围越大,效果越好,但是计算量也是成平方比增加的。

参数说明:

Optional ByVal TemplateSize As Byte = 1 '参与比较的范围,1代表当前象素周围的1个象素,总共是3X3,如果参数是2,则是5X5

Optional ByVal SortNum As Long = 4  '取最接近当前象素的个数,一般来说取范围内的象素总数的一半左右,太大和太小都不是很好。(下面的图像实例中,我用的是3,可以稍微快一点,呵呵)

Optional ByVal Sensitivity As Integer = 50 '设置了一个敏感度,当前象素和最接近的象素的差值大于该值才进行运算。

 

实际效果:

原图:

(请注意左面部分,我加上了很多随机噪音点和线)

处理后:

Imagecast处理参数:

 

*注1:如果取半径为1,那么连同当前像素,一共就有9个像素,扣除本身,就是8个像素;

    如果取半径为2,那么连同当前像素,一共就有25个像素,扣除本身,就是24个像素;

    推论: 半径为R,所包含的像素数量A为: A=(R * 2+1)^2 -1 

                所以这个"去尘"效果的计算量是和上图所示的"范围"成平方比的

 

如果读者对这个过程中的一些数组和变量不清楚,请参考我前面的几篇文章,其中有详细说明:

VB图像处理,(一)像素的获取和输出

 

VB图像处理,(二)二次线性插值的应用

VB图像处理,(三)几个常用滤镜的实现1

VB图像处理,(四)几个常用滤镜的实现2

VB图像处理,(五)图像的色彩纠正 
 

VB图像处理,(六)图像的亮度对比度调整

 

VB图像处理,(七)一种邻近均值滤波器的算法介绍(去尘,去噪音)

你可能感兴趣的:(编程及相关技术)