图像加噪和图像滤波
1. 椒盐噪声(Salt And Pepper Noise)
椒盐噪声是一种因为信号脉冲强度引起的噪声,信噪比(Signal NoiseRate)是衡量图像噪声的一个数字指标。
给一副数字图像加上椒盐噪声的处理顺序应该如下:
- 指定信噪比 SNR 其取值范围在[0, 1]之间
- 计算总像素数目 SP,得到要加噪的像素数目 NP = SP * (1-SNR)
- 随机获取要加噪的每个像素位置P(i, j)
- 指定像素值为255或者0。
- 重复c, d两个步骤完成所有像素的NP个像素
- 输出加噪以后的图像
int noise_num=(int)height*width*SNR/2; for(int i=0; i<noise_num; i++) { int row = (int)(rand()%height); int col = (int)(rand()%width); for(int j=0;j<nChannels;j++) { des[row * width* nChannels + col* nChannels+j]= 255; } } for(int i=0; i<noise_num; i++) { int row = (int)(rand()%height); int col = (int)(rand()%width); for(int j=0;j<nChannels;j++) { des[row * width* nChannels + col* nChannels+j]=0; } }
2. 高斯噪声(Gaussian Noise)
高斯噪声的密度取决于公式G(x, sigma) 其中X是代表平均值,sigma代表的标准方差,每个输入像素 Pin,
一个正常的高斯采样分布公式G(d), 得到输出像素Pout.
Pout = Pin + XMeans + sigma *G(d)
其中d为一个线性的随机数,G(d)是随机数的高斯分布随机值。
给一副数字图像加上高斯噪声的处理顺序如下:
a. 输入参数sigam 和 X mean
b. 以系统时间为种子产生一个伪随机数
c. 将伪随机数带入G(d)得到高斯随机数
d. 根据输入像素计算出输出像素
e. 重新将像素值防缩在[0 ~ 255]之间
f. 循环所有像素
g. 输出图像
采用了由Marsaglia和Bray在1964年提出的常用成熟的生成高斯分布随机数序列的方法
double gaussrand(int M,int D) { static double V1, V2, S; static int phase = 0; double X; if ( phase == 0 ) { do { double U1 = (double)rand() / RAND_MAX; double U2 = (double)rand() / RAND_MAX; V1 = 2 * U1 - 1; V2 = 2 * U2 - 1; S = V1 * V1 + V2 * V2; } while(S >= 1 || S == 0) X = V1 * sqrt(-2 * log(S) / S); } else X = V2 * sqrt(-2 * log(S) / S); phase = 1 - phase; X=X*D+M; return(X); }
3.均匀噪声
采用了经典的均匀噪声序列生成:
double randomUniform(double dMinValue,double dMaxValue) { double pRandomValue = (double)(rand()/(double)RAND_MAX); pRandomValue = pRandomValue*(dMaxValue-dMinValue)+dMinValue; return pRandomValue; }
二、滤波器的原理与实现
1.修正的阿尔法均值滤波器
假设在领域内去掉g(s,t)最低灰度值的d/2和最高灰度值的d/2。令代表剩下的mn-d个像素。由剩余这些像素的平均值形成的滤波器成为修正的阿尔法均值滤波器:
下面是核心的算法:
//Alpha trimmed mean filter void Alphatrimmedmeanfilter(unsigned char* des, const unsigned char* src, int width, int height, int nChannels) { // TODO: Add your command handler code here //processing int len=9; //定义模板大小为3*3 double* or=new double[len]; //将模板中强度记录成序列待排序 int d=4; //定义d值 //将uint8型转换为double型 //filtering for(int x=2;x<width-2;x++) for(int y=2;y<height-2;y++) for(int n=0;n<nChannels;n++) { or[0]=src[(y-1)*width*nChannels+(x-1)*nChannels + n]; or[1]=src[(y-1)*width*nChannels+x*nChannels + n]; or[2]=src[(y-1)*width*nChannels+(x+1)*nChannels + n]; or[3]=src[y*width*nChannels+(x-1)*nChannels + n]; or[4]=src[y*width*nChannels+x*nChannels + n]; or[5]=src[y*width*nChannels+(x+1)*nChannels + n]; or[6]=src[(y+1)*width*nChannels+(x-1)*nChannels + n]; or[7]=src[(y+1)*width*nChannels+x*nChannels + n]; or[8]=src[(y+1)*width*nChannels+(x+1)*nChannels + n]; orderN(or,9); //从小到大排序 double sum=0; //记录剩余强度之和 for(int k=d/2;k<9-d/2;k++) { sum=sum+or[k]; } sum=sum/(9-d); des[y*width*nChannels+x*nChannels + n]=int(sum); } }
2.自适应中值滤波:
自适应中值滤波器的滤波方式和传统的中值滤波器一样,都使用一个矩形区域的窗口Sxy ,不同的是在滤波过程中,自适应滤波器会根据一定的设定条件改变,即增加滤窗的大小,同时当判断滤窗中心的像素是噪声时,该值用中值代替,否则不改变其当前像素值,这样用滤波器的输出来替代像素(x,y) 处(即目前滤窗中心的坐标的值。我们做如下定义:
Zmin是在Sxy滤窗内灰度的最小值;
Zmax是在Sxy滤窗内灰度的最大值;
Zmed是在Sxy滤窗内灰度的中值;
Zxy是坐标(x,y) 处的灰度值;
Smax指定Sxy所允许的最大值。
自适应中值滤波算法由两个部分组成,称为第一层(Level A) 和第二层(Level B) 。 主要算法如下:
Level A : A1 = Zmed - Zmin A2 = Zmed - Zmax
如果A1> 0 并且A2<0 ,转到level B ,否则增加滤窗Sxy的尺寸。 如果滤窗Sxy≤Smax ,则重复执行Level A ,否则把Zxy作为输出值。
Level B : B1 = Zxy - Zmin B2 = Zxy - Zmax
如果B1>0 并且B2<0 , 把Zxy作为输出值, 否则把Zmed作为输出值。
算法如下:
void Adaptivemedianfilter(unsigned char* des, const unsigned char* src, int width, int height, int nChannels) { // TODO: Add your command handler code here int s=5; //定义最大矩形框大小 int k=0; k=(s-1)/2; //filtering double medtemp=0; double maxtemp=0; double mintemp=0; double pxytemp=0; //定义滤波过程中的临时变量 for(int i=2;i<width-2;i++) for(int j=2;j<height-2;j++) //逐点扫描 for(int n=0;n<nChannels;n++) { int len=3; while(len<=s) { double* or=new double[len*len]; //动态分配一维序列存放 int len2=0; len2=(len-1)/2; for(int x=0;x<len;x++) //将矩形框中的数据读入or进行排序 for(int y=0;y<len;y++) { or[x*len+y]=src[(i-len2+x)*nChannels+(j-len2+y)*nChannels*width+n]; } orderN(or,len*len); medtemp=or[(len*len-1)/2]; maxtemp=or[len*len-1]; mintemp=or[0]; pxytemp=src[i*nChannels+j*nChannels*width+n]; if((maxtemp>medtemp)&(mintemp<medtemp)) { if((maxtemp>pxytemp)&(mintemp<pxytemp)) { des[i*nChannels+j*nChannels*width+n]=int(pxytemp); } else { des[i*nChannels+j*nChannels*width+n]=int(medtemp); } break; } else { len=len+2; } delete []or; } if(len>s) { des[i*nChannels+j*nChannels*width+n]=int(medtemp); } } }
三、结果分析:
1.15%的均匀噪声和10%的椒盐噪声及对其进行修正的阿尔法滤波(d=4,mn=9)后的结果:
通过实验,发现d的取值对结果影响比较大,在d=4是取得比较好的结果,但可以看出依然有一些噪声点。
2.25%的椒盐噪声及对其自适应中值滤波后的结果:
可以看到自适应中值滤波对于椒盐噪声可以说具有非常漂亮的滤波效果,基本上看不出和原图像的区别。但是细心观察可以发现处理后的图像景物的边缘相对原图像比较模糊。
3.20%的均值为0,方差900的高斯噪声及其维纳滤波后的效果: