c#去除图像噪音

自从发表了用于验证码图片识别的类(C#代码)后,不断有网友下载这个类后,问如何用于一些特定的验证码。总结一下网友们的提问,很多都是不会从复杂背景中提到干净的字符图片来,这主要就是一个去噪问题,即除去图片上的背景、干扰点、干扰线等信息。这当中要用到很多图像学数学算法,首先声明,本人不是学图像学的,以下方法理论说得不对,敬请多批评指正。
    1、如何设前景/背景的分界值
    UnCodebase类中有一个GetPicValidByValue( int dgGrayValue) 函数,可以得到前景的有效区域,常有人问我前景/背景的分界值dgGrayValue是如何确定的(常用的是灰度128)。这个值的获取是有数学算法,叫最大类间方差法,即图像的前后景的平方差为最大时的值就是我们关心的分界值,对付如  这样较复杂的背景非常管用,下面是具体的C#代码。

 

复制代码
Code
        
///   <summary>
        
///  得到灰度图像前景背景的临界值 最大类间方差法,yuanbao,2007.08
        
///   </summary>
        
///   <returns> 前景背景的临界值 </returns>
         public   int  GetDgGrayValue()
        {
            
int [] pixelNum  =   new   int [ 256 ];            // 图象直方图,共256个点
             int  n, n1, n2;
            
int  total;                               // total为总和,累计值
             double  m1, m2, sum, csum, fmax, sb;      // sb为类间方差,fmax存储最大方差值
             int  k, t, q;
            
int  threshValue  =   1 ;                       //  阈值
             int  step  =   1 ;
            
// 生成直方图
             for  ( int  i  = 0 ; i  <  bmpobj.Width ; i ++ )
            {
                
for  ( int  j  =   0 ; j  <  bmpobj.Height; j ++ )
                {
                    
// 返回各个点的颜色,以RGB表示
                    pixelNum[bmpobj.GetPixel(i,j).R] ++ ;             // 相应的直方图加1
                }
            }
            
// 直方图平滑化
             for  (k  =   0 ; k  <=   255 ; k ++ )
            {
                total 
=   0 ;
                
for  (t  =   - 2 ; t  <=   2 ; t ++ )               // 与附近2个灰度做平滑化,t值应取较小的值
                {
                    q 
=  k  +  t;
                    
if  (q  <   0 )                      // 越界处理
                        q  =   0 ;
                    
if  (q  >   255 )
                        q 
=   255 ;
                    total 
=  total  +  pixelNum[q];     // total为总和,累计值
                }
                pixelNum[k] 
=  ( int )(( float )total  /   5.0   +   0.5 );     // 平滑化,左边2个+中间1个+右边2个灰度,共5个,所以总和除以5,后面加0.5是用修正值
            }
            
// 求阈值
            sum  =  csum  =   0.0 ;
            n 
=   0 ;
            
// 计算总的图象的点数和质量矩,为后面的计算做准备
             for  (k  =   0 ; k  <=   255 ; k ++ )
            {
                sum 
+=  ( double )k  *  ( double )pixelNum[k];      // x*f(x)质量矩,也就是每个灰度的值乘以其点数(归一化后为概率),sum为其总和
                n  +=  pixelNum[k];                        // n为图象总的点数,归一化后就是累积概率
            }

            fmax 
=   - 1.0 ;                           // 类间方差sb不可能为负,所以fmax初始值为-1不影响计算的进行
            n1  =   0 ;
            
for  (k  =   0 ; k  <   256 ; k ++ )                   // 对每个灰度(从0到255)计算一次分割后的类间方差sb
            {
                n1 
+=  pixelNum[k];                 // n1为在当前阈值遍前景图象的点数
                 if  (n1  ==   0 ) {  continue ; }             // 没有分出前景后景
                n2  =  n  -  n1;                         // n2为背景图象的点数
                 if  (n2  ==   0 ) {  break ; }                // n2为0表示全部都是后景图象,与n1=0情况类似,之后的遍历不可能使前景点数增加,所以此时可以退出循环
                csum  +=  ( double )k  *  pixelNum[k];     // 前景的“灰度的值*其点数”的总和
                m1  =  csum  /  n1;                      // m1为前景的平均灰度
                m2  =  (sum  -  csum)  /  n2;                // m2为背景的平均灰度
                sb  =  ( double )n1  *  ( double )n2  *  (m1  -  m2)  *  (m1  -  m2);    // sb为类间方差
                 if  (sb  >  fmax)                   // 如果算出的类间方差大于前一次算出的类间方差
                {
                    fmax 
=  sb;                     // fmax始终为最大类间方差(otsu)
                    threshValue  =  k;               // 取最大类间方差时对应的灰度的k就是最佳阈值
                }
            }
            
return  threshValue;
        }
复制代码

 

    2、如何去除干扰点/干扰线
    2.1 干扰点/干扰线的特征分析
    现在网上的大多数的验证码都是加了干扰的,一般分为干扰点和干扰线,如下图。标用1、2、3的分别为点、线、字符。

 

   去干扰,一般是逐点分析,这三种情况下,每一点及周边8个点的情况都不一样(分别为1点,3点,8点),这是一种干扰信息的粒度比字符的粒度小的典型情况。现在就可以动手编写去杂代码了。

   

    2.2 根据周边有效点数去噪函数

复制代码
Code
        
///   <summary>
        
///   去掉杂点(适合杂点/杂线粗为1)
        
///   </summary>
        
///   <param name="dgGrayValue"> 背前景灰色界限 </param>
        
///   <returns></returns>
         public   void  ClearNoise( int  dgGrayValue,  int  MaxNearPoints)
        {
            Color piexl;
            
int  nearDots  =   0 ;
            
int  XSpan, YSpan, tmpX, tmpY;
            
// 逐点判断
             for  ( int  i  =   0 ; i  <  bmpobj.Width; i ++ )
                
for  ( int  j  =   0 ; j  <  bmpobj.Height; j ++ )
                {
                    piexl 
=  bmpobj.GetPixel(i, j);
                    
if  (piexl.R  <  dgGrayValue)
                    {
                        nearDots 
=   0 ;
                        
// 判断周围8个点是否全为空
                         if  (i  ==   0   ||  i  ==  bmpobj.Width  -   1   ||  j  ==   0   ||  j  ==  bmpobj.Height  -   1 )   // 边框全去掉
                        {
                            bmpobj.SetPixel(i, j, Color.FromArgb(
255 255 255 ));
                        }
                        
else
                        {
                            
if  (bmpobj.GetPixel(i  -   1 , j  -   1 ).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i, j  -   1 ).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i  +   1 , j  -   1 ).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i  -   1 , j).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i  +   1 , j).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i  -   1 , j  +   1 ).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i, j  +   1 ).R  <  dgGrayValue) nearDots ++ ;
                            
if  (bmpobj.GetPixel(i  +   1 , j  +   1 ).R  <  dgGrayValue) nearDots ++ ;
                        }

                        
if  (nearDots  <  MaxNearPoints)
                            bmpobj.SetPixel(i, j, Color.FromArgb(
255 255 255 ));    // 去掉单点 && 粗细小3邻边点
                    }
                    
else    // 背景
                        bmpobj.SetPixel(i, j, Color.FromArgb( 255 255 255 ));
                }
        }


    
2.3  滤波算法去噪函数
     图像预处理中有多种滤波算法,其原理与方法分别为
     
1 ) 中值滤波
    它通过从图像中的某个采样窗口取出奇数个数据进行排序得到的结果。顾名思义,所谓中值就是窗口中奇数个数据按大小顺序排列后处于中心位置的那个数。中值滤波以窗口的中值作为处理结果。
    实现起来很简单
    
1 :先对窗口排序
    
2 :用排序后的中值取代要处理的数据即可
    注意事项:
    
1 :注意图像边缘数据的处理
    
2 :对于不同的目的选用不同的窗体,一般有3× 3 5 ×5等等
Code
        
///   <summary>
        
///  3×3中值滤波除杂,yuanbao,2007.10
        
///   </summary>
        
///   <param name="dgGrayValue"></param>
         public   void  ClearNoise( int  dgGrayValue)
        {
            
int  x, y;
            
byte [] p  =   new   byte [ 9 ];  // 最小处理窗口3*3
             byte  s;
            
// byte[] lpTemp=new BYTE[nByteWidth*nHeight];
             int  i, j;

            
// --!!!!!!!!!!!!!!下面开始窗口为3×3中值滤波!!!!!!!!!!!!!!!!
             for  (y  =   1 ; y  <  bmpobj.Height  -   1 ; y ++ // --第一行和最后一行无法取窗口
            {
                
for  (x  =   1 ; x  <  bmpobj.Width  -   1 ; x ++ )
                {
                    
// 取9个点的值
                    p[ 0 =  bmpobj.GetPixel(x  -   1 , y  -   1 ).R;
                    p[
1 =  bmpobj.GetPixel(x, y  -   1 ).R;
                    p[
2 =  bmpobj.GetPixel(x  +   1 , y  -   1 ).R;
                    p[
3 =  bmpobj.GetPixel(x  -   1 , y).R;
                    p[
4 =  bmpobj.GetPixel(x, y).R;
                    p[
5 =  bmpobj.GetPixel(x  +   1 , y).R;
                    p[
6 =  bmpobj.GetPixel(x  -   1 , y  +   1 ).R;
                    p[
7 =  bmpobj.GetPixel(x, y  +   1 ).R;
                    p[
8 =  bmpobj.GetPixel(x  +   1 , y  +   1 ).R;
                    
// 计算中值
                     for  (j  =   0 ; j  <   5 ; j ++ )
                    {
                        
for  (i  =  j  +   1 ; i  <   9 ; i ++ )
                        {
                            
if  (p[j]  >  p[i])
                            {
                                s 
=  p[j];
                                p[j] 
=  p[i];
                                p[i] 
=  s;
                            }
                        }
                    }
              
//       if (bmpobj.GetPixel(x, y).R < dgGrayValue)
                        bmpobj.SetPixel(x, y, Color.FromArgb(p[ 4 ], p[ 4 ], p[ 4 ]));     // 给有效值付中值
                }
            }
        }  
复制代码

 

 经过实际运行证实,中值滤波能有效去除图像中的噪声点,特别是在一片连续变化缓和的区域中(比如人的衣服,皮肤),几乎100%去除灰度突变点(可以认为是噪声点),也因为如此,中值滤波不适合用在一些细节多,如细节点,细节线多的图像中,因为细节点有可能被当成噪声点去除。
   

    中值滤波的窗口还可以有多种形状,上面程序选择的是矩形(容易计算),其实窗口还可以是菱形,圆形,十字形等等,不同的窗口形状有不同的滤波效果,对有缓慢且有较长轮廓线的物体适合用矩形或者原型窗口,对于有尖顶角物体的图像适合采用十字形窗口。
    中值滤波可以进行线性组合,不同窗口形状的滤波器可以线性组合
    改进中值滤波方法:
    对一些内容复杂的图像,可以使用复合型中值滤波。如, 中值滤波线性组合、高阶中值滤波组合、加权中值滤波以及迭代中值滤波等。
    中值滤波的线性组合是将几种窗口尺寸大小和形状不同的中值滤波器复合使用,只要各窗口都与中心对称,滤波输出可保持几个方向上的边缘跳变,而且跳变幅度可调节。
    高阶中值滤波组合可以使输入图像中任意方向的细线条保持不变。
    为了在一定的条件下尽可能去除噪声,又有效保持图像细节,可以对中值滤波器参数进行修正, 如加权中值滤波, 也就是对输入窗口进行加权。
    也可以是对中值滤波器的使用方法进行变化, 保证滤波的效果, 还可以和其他滤波器联合使用。
  
    2).均值滤波(模糊算法)
    均值滤波是典型的线性滤波算法,它是指在图像上对待处理的像素给一个模板,该模板包括了其周围的临近像素。将模板中的全体像素的均值来代替原来的像素值的方法。

    3)维纳(Wiener)滤波
    维纳(Wiener)滤波是对退化图像进行恢复处理的另一种常用算法,是一种有约束的恢复处理方法,其采用的维纳滤波器是一种最小均方误差滤波器,其数学形式比较复杂:
    F(u,v)=[(1/H(u,v))*(|H(u,v)|2)/(|H(u,v)|2+s*[Sn(u,v)/Sf(u,v)])]*G(u,v)
& nbsp;   当s为1时,上式就是普通的维纳滤波;如果s为变量,则为参数维纳滤波,如果没有噪声干扰,即Sn (u,v)=0时,上式实际就是前面的逆滤波。从其数学形式可以看出:维纳滤波比逆滤波在对噪声的处理方面要强一些。以上只是理论上的数学形式,在进行实际处理时,往往不知道噪声函数Sn(u,v)和Sf(u,v)的分布情况,因此在实际应用时多用下式进行近似处理:
    F(u,v)=[(1/H(u,v))* (|H(u,v)|2)/(|H(u,v)|2+K)]*G(u,v)
    其中K是一个预先设定的常数。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: OpenCV(开放源代码计算机视觉库)是一个用于计算机视觉和机器学习领域的开源库。在OpenCV中,傅里叶变换(Fourier Transform)被广泛应用于图像处理和分析中。 傅里叶变换是一种将时域信号转换为频域信号的数学变换。在图像处理中,傅里叶变换可以将一个图像从空间域转换到频域。通过傅里叶变换,我们可以获取图像中的频率信息,包括高频、低频和中频成分。 在OpenCV中,可以使用函数cv2.dft()来进行傅里叶变换。该函数接受一个输入图像和一个标志参数来控制变换的类型。通过傅里叶变换,可以将图像从空域转换到频域,并且可以使用逆变换将频域图像转换回空域。 傅里叶变换在图像处理中有许多应用。其中一个重要的应用是图像滤波。通过对图像进行傅里叶变换,我们可以将图像从频域进行滤波,然后使用逆变换将其转换回空域。这种方法可以用于去除图像中的噪声或增强图像的某些频率成分。 傅里叶变换还可以应用于图像压缩。通过将图像从空域转换到频域,并且只保留一部分频率成分,我们可以有效地压缩图像的数据量。在解压缩时,可以使用逆变换将频域图像转换回空域。 总而言之,傅里叶变换是一种在图像处理中非常重要的数学工具。它可以帮助我们理解图像的频率性质并进行相应的处理。OpenCV提供了方便的功能来进行傅里叶变换,并且可以应用于图像滤波和压缩等各种应用。 ### 回答2: OpenCV中的傅里叶变换是一种将图像从空间域转换到频率域的方法。傅里叶变换可以用于图像处理中的多个任务,包括滤波、图像增强和图像分析。 在OpenCV中,可以使用`cv2.dft()`函数来进行傅里叶变换。该函数的输入可以是灰度图像或浮点型彩色图像。输出为一个复数数组,表示变换后图像的幅度和相位信息。 傅里叶变换的基本步骤如下: 1. 将输入图像转换为灰度图像(如果不是灰度图像)。 2. 根据需要,对图像进行填充或裁剪,以确保图像的尺寸是2的幂。这是因为傅里叶变换要求输入图像的尺寸是2的幂。 3. 对图像应用`cv2.dft()`函数进行傅里叶变换。 4. 可选地,对变换后的图像进行频率域操作,如滤波或增强。 5. 对变换后的图像应用`cv2.idft()`函数进行傅里叶逆变换,将图像从频率域转换回空间域。 6. 可选地,对逆变换后的图像进行后处理,如归一化或类型转换。 利用傅里叶变换,可以实现图像的频率域滤波,例如通过去除高频噪声或低频噪声来实现图像增强。还可以实现图像的频谱分析,例如确定图像的主要频率成分或频谱特征。 总之,OpenCV中的傅里叶变换是一种功能强大的图像处理工具,它可以用于多种任务,包括滤波、增强和分析。通过了解傅里叶变换的基本步骤和原理,我们可以更好地利用这个工具来处理图像数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值