图像增强是图像处理中一个重要的内容,在图像生成,传输或变换的过程中,由于多种因素的影响,造成图像质量下降,图像模糊,特征淹没,给分析和识别带来困难。因此,按特定的需要将图像中感兴趣的特征友选择地突出,衰减不需要的特征,提高图像的可懂度是图像增强的主要内容。图像增强不考虑图像降质的原因,而且改善后的图像也不一定逼近原图像,这是它与图像复原本质的区别。图像增强的主要目的有两个:一是改善图像的视觉效果,提高图像的清晰度;二是将图像转换成一种更适合人类或机器进行分析处理的形式,一边从图像中获取更多有用的信息。
图像增强方法大致分为两类:一类是空间域处理法,另一类是频域处理法。空间域是直接对图像的像素进行处理,基本上是以灰度映射变换为基础的,所用的映射变换取决于图像的特点和增强的目的,主要包括灰度修正,图像平滑和锐化等。频域处理法是在图像的某种变换域内,对变换后的系数进行运算,然后再求其饭变换到原来的空间域得到增强的图像,主要包括:低通滤波,高通滤波,带阻滤波,同态滤波等。
1、噪声
噪声可以理解为影响传感器对所接受图像源信息进行理解或分析的各种因素。噪声一般是不可预测的随机信号,它只能用概率统计的方法去认识。噪声对图像的输入,采集和处理的各个环节以及输出结果全过程都有影响。因此,去噪已经成为图像处理中极为重要的手段,也是图像处理领域研究的一个重点。
1.1、噪声的分类
常见的噪声有以下几种:
(1)白噪声
(2)椒盐噪声:是一种在图像中产生黑色、白色点的脉冲噪声。该噪声在图像中显现较为明显,对图像分割。边缘检测、特征提取等后续处理具有严重的破坏作用。
(3)冲击噪声
(4)量化噪声
2、图像质量评价
在进行图像增强过程中,对一副含有噪声的图像在进行去噪之后图像质量是否有所提高,需要一个评价标准来衡量,因此,简单地引入图像的客观评价标准对去噪前后的图像质量进行衡量。信噪比是比较常用的一个标准。
图像的信噪比计算公式如下:
其中,M和N分别是图像长度和宽度上的像素个数,f(x,y)和g(x,y)分别是原始图像和去噪后的图像在点(x,y)处的灰度值。
信噪比的数值越大,说明图像质量越好。
下面是一段实现该算法的代码:
CString CImgEnhance::SNR(unsigned char* m_pSrcImgData) { int byteCount; // DIB位图的字节数 int i; // LPBITMAPINFOHEADER lpbmi; // lpbmi=(LPBITMAPINFOHEADER)lpSrcDIB; // m_pSrcImgData=(LPBYTE)lpbmi lpbmi->biSize sizeof(RGBQUAD)*lpbmi->biClrUsed; //计算图像信噪比 double temp1=0.0; double temp2=0.0; //处理8位灰度图像 if (m_nBitCount==8) { //计算整幅DIB位图的字节数 byteCount =m_imgHeight*m_imgWidth*m_nBitCount/8; for( i=0; i<byteCount; i ) { temp1=temp1 (double)m_pImgData[i]*m_pImgData[i]; temp2=temp2 (double)(m_pImgData[i]-m_pSrcImgData[i])*(m_pImgData[i]-m_pSrcImgData[i]); } } else { AfxMessageBox("只能处理8位灰度图像!"); return "ERROR"; } double SNR=temp1/temp2; SNR=10*log10(SNR); CString StrSNR; StrSNR.Format("%f",SNR); return StrSNR; }
灰度修正
灰度修正是图像在空间域中增强的简单而有效的方法,通常根据图像不同的降质现象二采用不同的修正方法。常用的方法主要有三种:一是灰度级矫正:二是灰度变换;三是直方图修正。
2.1、灰度校正
图像在成像过程中,往往由于光照、摄像、传感器灵敏度以及光学系统等的不均匀现象而引起图像某些部分较暗或较亮。对这类图像使用灰度级修正,能够获得满意的视觉效果。
设原始图像为f(x,y),不均匀降质图像为g(x,y),代表降质性质图像的函数为e(x,y),则降质过程可用下式来描述:
g(x,y) = e(x,y)f(x,y)--------------------------(1)
从上式可以看出,只要能够获得降质函数e(x,y),不难由降质图像g(x,y)来重建原始图像f(x,y)。但降质函数e(x,y)往往是不知道的,需设法根据图像降质系统的特征来计算或测量。最简单的方是:用一个已知灰度级全部为常数C的图像来标定测量这个将之系统的降质函数。也就是假设输入这个图像的降质系统的图像为fc(x,y)=C,那么可获得其输出图像为gc(x,y)。根据(1)式可得:
gc(x,y)=e(x,y)fc(x,y)
由此可得:
e(x,y)= gc(x,y)/ fc(x,y)= gc(x,y)/ C-------(2)
再将(2)带入(1)中,即可由降质图像g(x,y)求出原始图像f(x,y)
f(x,y)=g(x,y)/ e(x,y)=g(x,y)* C / gc(x,y)
图像的平滑用来减弱或消除图像中的高频分量,但不影响低频分量。因为高频分量主要对应图像中的区域边缘等灰度值具有较大较快变化的部分,平滑滤波将这些分量滤去可减少局部灰度起伏,使图像变得比较平滑。实际应用中,平滑滤波还可用于消除噪声,或者在提取较大目标前取出过小的细节或将目标内的小间断连接起来。它的主要目的是消除图像采集过程中的图像噪声,在空间域中主要利用邻域平均法、中值滤波法和选择式掩膜平滑法来减少噪声。
1、邻域平均法
邻域平均法是将原图中一个像素的灰度值和它周围邻域n个像素的灰度值相加,然后将求的的平均值作为新图中该像素的灰度值。邻域平均法采用了模板计算的思想,模板操作实现了一种邻域运算,在数学中的描述就是卷积运算。
邻域平均法的模板为:
中间带*号的表示以该像素为中心元素,即该像素是要进行处理的像素。在实际应用中,也可以根据不同的需要选择使用不同的模板尺寸。常用的模板尺寸如:3X3, 5X5,7X7,9X9等。
算法实现:
1 /********************************************************************** 2 * 参数: 3 * int TempH 模板的高度 4 * int TempW 模板的宽度 5 * int TempCX 模板的中心元素X坐标 ( < iTempW - 1) 6 * int TempCY 模板的中心元素Y坐标 ( < iTempH - 1) 7 * float *fpTempArray 指向模板数组的指针 8 * float f 模板系数 9 * 10 **********************************************************************/ 11 void CImgEnhance::AvgTemplate(int TempH, int TempW, int TempCX, int TempCY, float *fpTempArray, float f) 12 { 13 unsigned char* pSrc; 14 unsigned char* pDst; 15 int i,j,k,l; 16 float value; 17 if(m_pImgDataOut != NULL) 18 { 19 delete []m_pImgDataOut; 20 m_pImgDataOut = NULL; 21 } 22 int lineByte = (m_imgWidth * m_nBitCount / 8 + 3) / 4 * 4; 23 24 if(m_nBitCount != 8) 25 { 26 AfxMessageBox("只能处理8位灰度图像!"); 27 return ; 28 } 29 //创建要复制的图像区域 30 m_nBitCountOut = m_nBitCount; 31 int lineByteOut = (m_imgWidth*m_nBitCountOut / 8 + 3) / 4 * 4; 32 if (!m_pImgDataOut) 33 { 34 m_pImgDataOut = new unsigned char[lineByteOut*m_imgHeight]; 35 } 36 37 int pixelByte = m_nBitCountOut / 8; 38 for(i = 0; i < m_imgHeight; i++) 39 { 40 for(j = 0; j < m_imgWidth * pixelByte; j++) 41 *(m_pImgDataOut+i*lineByteOut+j)= *(m_pImgData+i*lineByteOut+j); 42 } 43 //行处理(去掉边缘几行) 44 for (i = TempCY; i < m_imgHeight - TempH + TempCY + 1; i++) //m_imgHeight - (TempH -TempCY) + 1故弄玄虚!靠 45 { 46 //列处理(去掉边缘几列) 47 for (j = TempCX; j < m_imgWidth - TempW + TempCX + 1; j++) 48 { 49 //指向新DIB第i行第j列的像素的指针 50 pDst = m_pImgDataOut + lineByte * i + j; 51 value=0; 52 //计算 53 for (k = 0; k < TempH; k++) 54 { 55 for (l = 0; l < TempW; l++) 56 { 57 pSrc = m_pImgData + lineByte * (i + TempCY - k) + j - TempCX + l; 58 //计算加权平均,保存像素值 59 value += (*pSrc) * fpTempArray[k * TempW + l]; 60 } 61 } 62 //乘以系数 63 value *= f; 64 //取结果的绝对值 65 value=(float)fabs(value); 66 if (value > 255) 67 { 68 *pDst = 255; 69 } 70 else 71 { 72 *pDst = (unsigned char)(value + 0.5); 73 } 74 } 75 } 76 }
邻域平均算法思想简单易行,但是在减小噪声的同时让图像变得模糊。
邻域平均法和加权平均法在消除噪声的同时,都不可避免地带来平均化的缺憾,致使尖锐变化的边缘或线条变得模糊。考虑图像中目标物体和背景一般都具有不同的统计特性,即不同的均值和方差,为保留一定的边缘信息,可采用选择式掩膜平滑滤波,这样可以得到较好的图像细节。这种方法以尽量不模糊边缘轮廓为目的。
1.基本原理
选择式掩膜平滑方法取5×5的模板窗口,以中心像素为基准点,制作4个五边形、4个六边形、一个边长为3的正方形共9个形状的屏幕窗口,分别计算每个窗口内的平均值及方差。由于含有尖锐边缘的区域,方差必定比平缓区域大,因此采用方差最小的屏蔽窗口进行平均化。这种方法在完成滤波操作的同时,又不破坏区域边界的细节。这种采用9种形状的屏蔽窗口,分别计算各窗口内的灰度值方差,并采用方差最小的屏蔽窗口进行平均化的方法,也称为自适应平滑方法。下图为9种屏蔽窗口的模板
均值的计算公式为:
计算方差的公式为:
式中,k=1,2,3,4·····,N N为各模板对应的像素个数。
算法实现:
1 void CImgEnhance::ChooseMask() 2 { 3 if(m_nBitCount!=8) 4 { 5 AfxMessageBox("只能处理8位灰度图像!"); 6 return ; 7 } 8 int n,pixel[9],nmin; 9 float mean[9],var[9],bmin; 10 11 if(m_pImgDataOut!=NULL) 12 { 13 delete []m_pImgDataOut; 14 m_pImgDataOut=NULL; 15 } 16 //创建要复制的图像区域 17 m_nBitCountOut=m_nBitCount; 18 int lineByteOut=(m_imgWidth*m_nBitCountOut/8+3)/4*4; 19 if (!m_pImgDataOut) 20 { 21 m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeight]; 22 } 23 24 memset(m_pImgDataOut,255,lineByteOut * m_imgHeight); 25 for(int j=2;j<=m_imgHeight-3;j++) 26 for(int i=2;i<=m_imgWidth-3;i++) 27 { 28 //求9种近邻区域的均值及其方差 29 //第1近邻区域 30 pixel[0]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 31 pixel[1]=m_pImgData[(j-1)*lineByteOut+i]; 32 pixel[2]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 33 pixel[3]=m_pImgData[j*lineByteOut+(i-1)]; 34 pixel[4]=m_pImgData[j*lineByteOut+i]; 35 pixel[5]=m_pImgData[j*lineByteOut+(i+1)]; 36 pixel[6]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 37 pixel[7]=m_pImgData[(j+1)*lineByteOut+i]; 38 pixel[8]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 39 mean[0]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6]+pixel[7]+pixel[8])/9; 40 var[0]=0; 41 for(n=0;n<=8;n++) 42 var[0]+=pixel[n]*pixel[n]-mean[0]*mean[0]; 43 //第2近邻区域 44 pixel[0]=m_pImgData[(j-2)*lineByteOut+(i-1)]; 45 pixel[1]=m_pImgData[(j-2)*lineByteOut+i]; 46 pixel[2]=m_pImgData[(j-2)*lineByteOut+(i+1)]; 47 pixel[3]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 48 pixel[4]=m_pImgData[(j-1)*lineByteOut+i]; 49 pixel[5]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 50 pixel[6]=m_pImgData[j*lineByteOut+i]; 51 mean[1]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 52 var[1]=0; 53 for(n=0;n<=6;n++) 54 var[1]+=pixel[n]*pixel[n]-mean[1]*mean[1]; 55 //第3近邻区域 56 pixel[0]=m_pImgData[(j-1)*lineByteOut+(i-2)]; 57 pixel[1]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 58 pixel[2]=m_pImgData[j*lineByteOut+(i-2)]; 59 pixel[3]=m_pImgData[j*lineByteOut+(i-1)]; 60 pixel[4]=m_pImgData[j*lineByteOut+i]; 61 pixel[5]=m_pImgData[(j+1)*lineByteOut+(i-2)]; 62 pixel[6]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 63 mean[2]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 64 var[2]=0; 65 for(n=0;n<=6;n++) 66 var[2]+=pixel[n]*pixel[n]-mean[2]*mean[2]; 67 //第4近邻区域 68 pixel[0]=m_pImgData[j*lineByteOut+i]; 69 pixel[1]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 70 pixel[2]=m_pImgData[(j+1)*lineByteOut+i]; 71 pixel[3]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 72 pixel[4]=m_pImgData[(j+2)*lineByteOut+(i-1)]; 73 pixel[5]=m_pImgData[(j+2)*lineByteOut+i]; 74 pixel[6]=m_pImgData[(j+2)*lineByteOut+(i+1)]; 75 mean[3]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 76 var[3]=0; 77 for(n=0;n<=6;n++) 78 var[3]+=pixel[n]*pixel[n]-mean[3]*mean[3]; 79 //第5近邻区域 80 pixel[0]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 81 pixel[1]=m_pImgData[(j-1)*lineByteOut+(i+2)]; 82 pixel[2]=m_pImgData[j*lineByteOut+i]; 83 pixel[3]=m_pImgData[j*lineByteOut+(i+1)]; 84 pixel[4]=m_pImgData[j*lineByteOut+(i+2)]; 85 pixel[5]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 86 pixel[6]=m_pImgData[(j+1)*lineByteOut+(i+2)]; 87 mean[4]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 88 var[4]=0; 89 for(n=0;n<=6;n++) 90 var[4]+=pixel[n]*pixel[n]-mean[4]*mean[4]; 91 //第6近邻区域 92 pixel[0]=m_pImgData[(j-2)*lineByteOut+(i+1)]; 93 pixel[1]=m_pImgData[(j-2)*lineByteOut+(i+2)]; 94 pixel[2]=m_pImgData[(j-1)*lineByteOut+i]; 95 pixel[3]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 96 pixel[4]=m_pImgData[(j-1)*lineByteOut+(i+2)]; 97 pixel[5]=m_pImgData[j*lineByteOut+i]; 98 pixel[6]=m_pImgData[j*lineByteOut+(i+1)]; 99 mean[5]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 100 var[5]=0; 101 for(n=0;n<=6;n++) 102 var[5]+=pixel[n]*pixel[n]-mean[5]*mean[5]; 103 //第7近邻区域 104 pixel[0]=m_pImgData[(j-2)*lineByteOut+(i-2)]; 105 pixel[1]=m_pImgData[(j-2)*lineByteOut+(i-1)]; 106 pixel[2]=m_pImgData[(j-1)*lineByteOut+(i-2)]; 107 pixel[3]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 108 pixel[4]=m_pImgData[(j-1)*lineByteOut+i]; 109 pixel[5]=m_pImgData[j*lineByteOut+(i-1)]; 110 pixel[6]=m_pImgData[j*lineByteOut+i]; 111 mean[6]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 112 var[6]=0; 113 for(n=0;n<=6;n++) 114 var[6]+=pixel[n]*pixel[n]-mean[6]*mean[6]; 115 //第8近邻区域 116 pixel[0]=m_pImgData[j*lineByteOut+(i-1)]; 117 pixel[1]=m_pImgData[j*lineByteOut+i]; 118 pixel[2]=m_pImgData[(j+1)*lineByteOut+(i-2)]; 119 pixel[3]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 120 pixel[4]=m_pImgData[(j+1)*lineByteOut+i]; 121 pixel[5]=m_pImgData[(j+2)*lineByteOut+(i-2)]; 122 pixel[6]=m_pImgData[(j+2)*lineByteOut+(i-1)]; 123 mean[7]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 124 var[7]=0; 125 for(n=0;n<=6;n++) 126 var[7]+=pixel[n]*pixel[n]-mean[7]*mean[7]; 127 //第9近邻区域 128 pixel[0]=m_pImgData[j*lineByteOut+i]; 129 pixel[1]=m_pImgData[j*lineByteOut+(i+1)]; 130 pixel[2]=m_pImgData[(j+1)*lineByteOut+i]; 131 pixel[3]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 132 pixel[4]=m_pImgData[(j+1)*lineByteOut+(i+2)]; 133 pixel[5]=m_pImgData[(j+2)*lineByteOut+(i+1)]; 134 pixel[6]=m_pImgData[(j+2)*lineByteOut+(i+2)]; 135 mean[8]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 136 var[8]=0; 137 for(n=0;n<=6;n++) 138 var[8]+=pixel[n]*pixel[n]-mean[8]*mean[8]; 139 //求方差最小的近邻区域nmin 140 bmin=var[0]; 141 nmin=0; 142 for(n=0;n<=8;n++) 143 { 144 if(bmin>var[n]) 145 { 146 bmin=var[n]; 147 nmin=n; 148 } 149 //把nmin的值四舍五入后作为显示图像的值 150 m_pImgDataOut[j*lineByteOut+i]=(int)(mean[nmin]+0.5); 151 } 152 } 153 }
邻域平均法和加权平均法在消除噪声的同时,都不可避免地带来平均化的缺憾,致使尖锐变化的边缘或线条变得模糊。考虑图像中目标物体和背景一般都具有不同的统计特性,即不同的均值和方差,为保留一定的边缘信息,可采用选择式掩膜平滑滤波,这样可以得到较好的图像细节。这种方法以尽量不模糊边缘轮廓为目的。
1.基本原理
选择式掩膜平滑方法取5×5的模板窗口,以中心像素为基准点,制作4个五边形、4个六边形、一个边长为3的正方形共9个形状的屏幕窗口,分别计算每个窗口内的平均值及方差。由于含有尖锐边缘的区域,方差必定比平缓区域大,因此采用方差最小的屏蔽窗口进行平均化。这种方法在完成滤波操作的同时,又不破坏区域边界的细节。这种采用9种形状的屏蔽窗口,分别计算各窗口内的灰度值方差,并采用方差最小的屏蔽窗口进行平均化的方法,也称为自适应平滑方法。下图为9种屏蔽窗口的模板
均值的计算公式为:
计算方差的公式为:
式中,k=1,2,3,4·····,N N为各模板对应的像素个数。
算法实现:
1 void CImgEnhance::ChooseMask() 2 { 3 if(m_nBitCount!=8) 4 { 5 AfxMessageBox("只能处理8位灰度图像!"); 6 return ; 7 } 8 int n,pixel[9],nmin; 9 float mean[9],var[9],bmin; 10 11 if(m_pImgDataOut!=NULL) 12 { 13 delete []m_pImgDataOut; 14 m_pImgDataOut=NULL; 15 } 16 //创建要复制的图像区域 17 m_nBitCountOut=m_nBitCount; 18 int lineByteOut=(m_imgWidth*m_nBitCountOut/8+3)/4*4; 19 if (!m_pImgDataOut) 20 { 21 m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeight]; 22 } 23 24 memset(m_pImgDataOut,255,lineByteOut * m_imgHeight); 25 for(int j=2;j<=m_imgHeight-3;j++) 26 for(int i=2;i<=m_imgWidth-3;i++) 27 { 28 //求9种近邻区域的均值及其方差 29 //第1近邻区域 30 pixel[0]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 31 pixel[1]=m_pImgData[(j-1)*lineByteOut+i]; 32 pixel[2]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 33 pixel[3]=m_pImgData[j*lineByteOut+(i-1)]; 34 pixel[4]=m_pImgData[j*lineByteOut+i]; 35 pixel[5]=m_pImgData[j*lineByteOut+(i+1)]; 36 pixel[6]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 37 pixel[7]=m_pImgData[(j+1)*lineByteOut+i]; 38 pixel[8]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 39 mean[0]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6]+pixel[7]+pixel[8])/9; 40 var[0]=0; 41 for(n=0;n<=8;n++) 42 var[0]+=pixel[n]*pixel[n]-mean[0]*mean[0]; 43 //第2近邻区域 44 pixel[0]=m_pImgData[(j-2)*lineByteOut+(i-1)]; 45 pixel[1]=m_pImgData[(j-2)*lineByteOut+i]; 46 pixel[2]=m_pImgData[(j-2)*lineByteOut+(i+1)]; 47 pixel[3]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 48 pixel[4]=m_pImgData[(j-1)*lineByteOut+i]; 49 pixel[5]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 50 pixel[6]=m_pImgData[j*lineByteOut+i]; 51 mean[1]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 52 var[1]=0; 53 for(n=0;n<=6;n++) 54 var[1]+=pixel[n]*pixel[n]-mean[1]*mean[1]; 55 //第3近邻区域 56 pixel[0]=m_pImgData[(j-1)*lineByteOut+(i-2)]; 57 pixel[1]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 58 pixel[2]=m_pImgData[j*lineByteOut+(i-2)]; 59 pixel[3]=m_pImgData[j*lineByteOut+(i-1)]; 60 pixel[4]=m_pImgData[j*lineByteOut+i]; 61 pixel[5]=m_pImgData[(j+1)*lineByteOut+(i-2)]; 62 pixel[6]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 63 mean[2]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 64 var[2]=0; 65 for(n=0;n<=6;n++) 66 var[2]+=pixel[n]*pixel[n]-mean[2]*mean[2]; 67 //第4近邻区域 68 pixel[0]=m_pImgData[j*lineByteOut+i]; 69 pixel[1]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 70 pixel[2]=m_pImgData[(j+1)*lineByteOut+i]; 71 pixel[3]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 72 pixel[4]=m_pImgData[(j+2)*lineByteOut+(i-1)]; 73 pixel[5]=m_pImgData[(j+2)*lineByteOut+i]; 74 pixel[6]=m_pImgData[(j+2)*lineByteOut+(i+1)]; 75 mean[3]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 76 var[3]=0; 77 for(n=0;n<=6;n++) 78 var[3]+=pixel[n]*pixel[n]-mean[3]*mean[3]; 79 //第5近邻区域 80 pixel[0]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 81 pixel[1]=m_pImgData[(j-1)*lineByteOut+(i+2)]; 82 pixel[2]=m_pImgData[j*lineByteOut+i]; 83 pixel[3]=m_pImgData[j*lineByteOut+(i+1)]; 84 pixel[4]=m_pImgData[j*lineByteOut+(i+2)]; 85 pixel[5]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 86 pixel[6]=m_pImgData[(j+1)*lineByteOut+(i+2)]; 87 mean[4]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 88 var[4]=0; 89 for(n=0;n<=6;n++) 90 var[4]+=pixel[n]*pixel[n]-mean[4]*mean[4]; 91 //第6近邻区域 92 pixel[0]=m_pImgData[(j-2)*lineByteOut+(i+1)]; 93 pixel[1]=m_pImgData[(j-2)*lineByteOut+(i+2)]; 94 pixel[2]=m_pImgData[(j-1)*lineByteOut+i]; 95 pixel[3]=m_pImgData[(j-1)*lineByteOut+(i+1)]; 96 pixel[4]=m_pImgData[(j-1)*lineByteOut+(i+2)]; 97 pixel[5]=m_pImgData[j*lineByteOut+i]; 98 pixel[6]=m_pImgData[j*lineByteOut+(i+1)]; 99 mean[5]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 100 var[5]=0; 101 for(n=0;n<=6;n++) 102 var[5]+=pixel[n]*pixel[n]-mean[5]*mean[5]; 103 //第7近邻区域 104 pixel[0]=m_pImgData[(j-2)*lineByteOut+(i-2)]; 105 pixel[1]=m_pImgData[(j-2)*lineByteOut+(i-1)]; 106 pixel[2]=m_pImgData[(j-1)*lineByteOut+(i-2)]; 107 pixel[3]=m_pImgData[(j-1)*lineByteOut+(i-1)]; 108 pixel[4]=m_pImgData[(j-1)*lineByteOut+i]; 109 pixel[5]=m_pImgData[j*lineByteOut+(i-1)]; 110 pixel[6]=m_pImgData[j*lineByteOut+i]; 111 mean[6]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 112 var[6]=0; 113 for(n=0;n<=6;n++) 114 var[6]+=pixel[n]*pixel[n]-mean[6]*mean[6]; 115 //第8近邻区域 116 pixel[0]=m_pImgData[j*lineByteOut+(i-1)]; 117 pixel[1]=m_pImgData[j*lineByteOut+i]; 118 pixel[2]=m_pImgData[(j+1)*lineByteOut+(i-2)]; 119 pixel[3]=m_pImgData[(j+1)*lineByteOut+(i-1)]; 120 pixel[4]=m_pImgData[(j+1)*lineByteOut+i]; 121 pixel[5]=m_pImgData[(j+2)*lineByteOut+(i-2)]; 122 pixel[6]=m_pImgData[(j+2)*lineByteOut+(i-1)]; 123 mean[7]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 124 var[7]=0; 125 for(n=0;n<=6;n++) 126 var[7]+=pixel[n]*pixel[n]-mean[7]*mean[7]; 127 //第9近邻区域 128 pixel[0]=m_pImgData[j*lineByteOut+i]; 129 pixel[1]=m_pImgData[j*lineByteOut+(i+1)]; 130 pixel[2]=m_pImgData[(j+1)*lineByteOut+i]; 131 pixel[3]=m_pImgData[(j+1)*lineByteOut+(i+1)]; 132 pixel[4]=m_pImgData[(j+1)*lineByteOut+(i+2)]; 133 pixel[5]=m_pImgData[(j+2)*lineByteOut+(i+1)]; 134 pixel[6]=m_pImgData[(j+2)*lineByteOut+(i+2)]; 135 mean[8]=(float)(pixel[0]+pixel[1]+pixel[2]+pixel[3]+pixel[4]+pixel[5]+pixel[6])/7; 136 var[8]=0; 137 for(n=0;n<=6;n++) 138 var[8]+=pixel[n]*pixel[n]-mean[8]*mean[8]; 139 //求方差最小的近邻区域nmin 140 bmin=var[0]; 141 nmin=0; 142 for(n=0;n<=8;n++) 143 { 144 if(bmin>var[n]) 145 { 146 bmin=var[n]; 147 nmin=n; 148 } 149 //把nmin的值四舍五入后作为显示图像的值 150 m_pImgDataOut[j*lineByteOut+i]=(int)(mean[nmin]+0.5); 151 } 152 } 153 }
中值滤波是一种典型的非线性滤波技术。它在一定条件下可以克服线性滤波器如最小均方滤波,均值滤波等带来的图像细节模糊,而且对滤波脉冲干扰及图像扫描噪声非常有效。
传统的中值滤波一般采用含有奇数个点的滑动窗口,用窗口中各点灰度值的中值来替代指定点的灰度值。对于奇数个元素,中值为大小排序后中间的数值;对于偶数个元素,中值为排序后中间两个元素灰度值的平均值。
中值滤波是一种典型的低通滤波器,主要用来抑制脉冲噪声,它能彻底滤除尖波干扰噪声,同时又具有能较好地保护目标图像边缘的特点。
标准一维中值滤波器的定义为:
yk = med{ xK-N, xk-N+1, ... ,xk, ... ,xK+N }
式中,med表示取中值操作。中值滤波的滤波方法是对滑动滤波窗口(2N+1)内的像素做大小排序,滤波结果的输出像素值规定为该序列的中值。
二维中值滤波的窗口形状和尺寸设计对滤波的效果影响较大,不同的图像内容和不同的应用要求,往往采用不同的形状和尺寸。常用的二维中值滤波窗口有线状,方形,圆形,十字形及圆环形等,窗口尺寸一般选为3。当然也可以采用其他尺寸,主要视具体情况而定。
1.中值的计算关键在于对滑动窗口内的像素进行排序,排序算法的选择是影响中值滤波算法的重要因素。传统的排序算法是基于冒泡排序法,若窗口中的像素为m,则每个窗口排序需要m(m-2)/2次像素的比较操作,时间复杂度为O(m2)。此外常规的滤波算法每移动一次窗口就要进行一次排序。当一幅图像的大小为NXN时,则整个计算需要O(m2N2)时间,当窗口较大时,计算量很大,较费时。
2.为了提高中值滤波的实现速度,针对3X3中值滤波,介绍一种快速的并行中值滤波方法。下图为3X3窗口内像素排列
首先对窗口内的每一列分别计算最大值,中值和最小值,这样就得到了3组数据
最大值组:Max0 = max[P0,P3,P6],Max1 = max[P1,P4,P7],Max2 = max[P2,P5,P8]
中值组: Med0 = med[P0,P3,P6],Med1 = med[P1,P4,P7], Med2 = med[P2,P5,P8]
最小值组:Min0 = Min[P0,P3,P6],Min1 = Min[P1,P4,P7],Min2 = max[P2,P5,P8]
由此可以看到,最大值组中的最大值与最小值组中的最小值一定是9个元素中的最大值和最小值,不可能为中值,剩下7个;中值组中的最大值至少大于5个像素,中值组中的最小值至少小于5个像素,不可能为中值,剩下5个;最大值组中的中值至少大于5个元素,最小值组中的中值至少小于5个元素,不可能为中值,最后剩下3个要比较的元素,即
最大值组中的最小值Maxmin,中值组中的中值Medmed,最小值组中的最大值MinMax;找出这三个值中的中值为9个元素的中值。
算法实现:
/********************************************************************** * * 函数名称: * MedFilter(int FilterH, int FilterW, int FilterCX, int FilterCY) * * 参数: * int FilterH 模板的高度 * int FilterW 模板的宽度 * int FilterCX 模板的中心元素X坐标 ( < FilterW - 1) * int FilterCY 模板的中心元素Y坐标 ( < FilterH - 1) * * 返回值: * void * * 说明: * 中值滤波的算法 * **********************************************************************/ void CImgEnhance::MedianFilter(int FilterH, int FilterW, int FilterCX, int FilterCY) { unsigned char* pSrc; unsigned char* pDst; int i,j,k,l; unsigned char* value; //指向滤波器数组的指针 if(m_pImgDataOut != NULL) { delete []m_pImgDataOut; m_pImgDataOut = NULL; } //计算图像每行的字节数 int lineByte = (m_imgWidth * m_nBitCount / 8 + 3) / 4 * 4; if(m_nBitCount != 8) { AfxMessageBox("只能处理8位灰度图像!"); return ; } //分配内存,以保存新图像 m_nBitCountOut = m_nBitCount; int lineByteOut = (m_imgWidth * m_nBitCountOut / 8 + 3) / 4 * 4; if (!m_pImgDataOut) { //为处理后的图像分配内存空间 m_pImgDataOut = new unsigned char[lineByteOut * m_imgHeight]; } int pixelByte = m_nBitCountOut / 8; for(i = 0; i < m_imgHeight; i++){ for(j = 0; j < m_imgWidth * pixelByte; j++) *(m_pImgDataOut + i * lineByteOut +j) = *(m_pImgData + i * lineByteOut + j); } //暂时分配内存,以保存滤波器数组 value = new unsigned char[FilterH * FilterW]; for (i = FilterCY; i < m_imgHeight - FilterH ; i++)//+ FilterCY + 1 { for (j = FilterCX; j < m_imgWidth - FilterW ; j++)//+ FilterCX + 1 { pDst = m_pImgDataOut + lineByte * (m_imgHeight - 1 - i) + j; for (k = 0; k < FilterH; k++) { for (l = 0; l < FilterW; l++) { pSrc = m_pImgData + lineByte * (m_imgHeight - l - i + FilterCY - k) + j - FilterCX + l; value[k * FilterW + l] = *pSrc; } } *pDst = FindMedianValue(value,FilterW * FilterH); } } }
图像锐化主要影响图像中的低频分量,不影响图像中的高频分量。
图像锐化的主要目的有两个:
1.增强图像边缘,使模糊的图像变得更加清晰,颜色变得鲜明突出,图像的质量有所改善,产生更适合人眼观察和识别的图像;
2.希望通过锐化处理后,目标物体的边缘鲜明,以便于提取目标的边缘、对图像进行分割、目标区域识别、区域形状提取等,进一步的图像理解与分析奠定基础。
图像锐化一般有两种方法:
1.微分法
2.高通滤波法
这里主要介绍一下两种常用的微分锐化方法:梯度锐化和拉普拉斯锐化。
注意:由于锐化使噪声受到比信号还要强的增强,所以要求锐化处理的图像有较高的信噪比;否则,锐化后的图像的信噪比更低。
1.梯度锐化
基本理论
邻域平均法或加权平均法可以平滑图像,反过来利用对应的微分算法可以锐化图像。微分算法是求信号的变化率,有加强高频分量胡作用,从而使图像轮廓清晰。
由于图像模糊胡实质是图像受到平均或积分运算造成的,所以为了把图像中任何方向伸展的边缘肯模糊的轮廓变得清晰,可以对图像进行逆运算如微分运算,从而使图像清晰化。
在图像处理中,一阶微分是通过梯度算法来实现的,对于一幅图像用函数f(x,y)表示,定义在f(x,y)在点(x,y)处的梯度是一个矢量,定义为:
梯度的方向在函数f(x,y)最大变化率的方向上,梯度的幅度G[f(x,y)]可以由以下公式算出:
由上式可知:梯度的数值就是f(x,y)在其最大变化率方向上的单位距离所增加的量。
对于数字图像而言,微分可用差分来近似。因此上式可以写成:
为了便于编程和提高运算速度,在计算精度允许的情况下,可采用绝对差算法近似为:
这种算法又称为水平垂直差分法,另一种梯度算法是交叉的进行查分计算,称为罗伯特梯度法,表示为:
同样可采用绝对差算法近似:
运用上述两种梯度近似算法,在图像的最后一行后最后一列无法计算像素的梯度时,一般用前一行或前一列的梯度值近似代替。
为了不破坏图像背景的前提下更好地增强边缘,也可以对上述直接用梯度值代替灰度值的方法进行改进,可以引入一个阈值来判断是否对某一像素点进行锐化。具体公式如下:
对于图像而言,物体与物体之间,背景与背景之间的梯度变化很小,灰度变化较大的地方一般集中在图像的边缘上,也就是物体和背景交接的地方。当我们设定一个阈值时,G[f(i,j)]大于阈值就认为该像素点处于图像的边缘,对结果加上常数C,以使边缘变亮;而对于G[f(i,j)]不大于阈值就认为该像素点为同类像素,即同为物体或同为背景,常数C的选取可以根据具体的图像特点。这样既增亮了图像的边界,同时又保留了图像背景原来的状态,比传统的梯度锐化具有更好的增强效果和适用性。
另外拉普拉斯算子也可用于图像锐化,这里不再赘述。
算法实现:
1 /************************************************************************* 2 * 函数名称: 3 * GradSharp() 4 * 参数: 5 * BYTE bThre - 阈值 6 * 返回值: 7 * BOOL - 成功返回TRUE,否则返回FALSE。 8 * 说明: 9 * 该函数用来对图像进行梯度锐化,设定梯度锐化的阈值为30 10 /************************************************************************/ 11 void CImgEnhance::GradSharp(unsigned char Thre) 12 { 13 unsigned char* pSrc; // 指向源图像的指针 14 unsigned char* pDst; 15 unsigned char* pSrc1; 16 unsigned char* pSrc2; 17 LONG i,j; // 循环变量 18 int bTemp; 19 if(m_pImgDataOut != NULL) 20 { 21 delete []m_pImgDataOut; 22 m_pImgDataOut = NULL; 23 } 24 25 if(m_nBitCount != 8) 26 { 27 AfxMessageBox("只能处理8位灰度图像!"); 28 return ; 29 } 30 int lineByte = (m_imgWidth * m_nBitCount / 8 + 3) / 4 * 4; 31 32 //创建要复制的图像区域 33 m_nBitCountOut = m_nBitCount; 34 int lineByteOut = lineByte; 35 if (!m_pImgDataOut) 36 { 37 m_pImgDataOut = new unsigned char[lineByteOut * m_imgHeight]; 38 } 39 40 int pixelByte = m_nBitCountOut / 8; // 此处实际就是1,因为只处理8位图像 41 for(i = 0; i < m_imgHeight; i++) 42 { 43 for(j = 0; j < m_imgWidth * pixelByte; j++) 44 *(m_pImgDataOut + i * lineByteOut + j) = *(m_pImgData + i * lineByteOut + j); 45 } 46 47 for(i = 0; i < m_imgHeight; i++) // 每行 48 { 49 for(j = 0; j < m_imgWidth; j++) // 每列 50 { 51 //指向新DIB第i行第j列的像素的指针 52 pDst = m_pImgDataOut + lineByte * i + j; 53 54 // 进行梯度运算 55 // 指向DIB第i行,第j个象素的指针 56 pSrc = (unsigned char*)m_pImgData + lineByte * i + j; 57 // 指向DIB第i+1行,第j个象素的指针 58 pSrc1 = (unsigned char*)m_pImgData + lineByte * (i+1) + j; 59 // 指向DIB第i行,第j+1个象素的指针 60 pSrc2 = (unsigned char*)m_pImgData + lineByte * i + j + 1; 61 bTemp = abs((*pSrc)-(*pSrc1)) + abs((*pSrc)-(*pSrc2)); 62 63 // 判断是否小于阈值 64 if ((bTemp+120) < 255) 65 { 66 // 判断是否大于阈值,对于小于情况,灰度值不变。 67 if (bTemp >= Thre) 68 { 69 *pSrc = bTemp + 120; 70 } 71 } 72 else 73 { 74 *pSrc = 255; 75 } 76 //生成新的DIB像素值 77 *pDst = *pSrc; 78 } 79 } 80 81 }
原文:http://blog.csdn.net/feixiang_john/article/details/27342605