算术均值滤波与中值滤波去噪
算术均值滤波与中值滤波去噪
我们知道在图像生成和传输的过程中,很容易产生噪声干扰。噪声其实分为很多类型,分为泊松噪声、椒盐噪声等。这我们就不一一赘述了,我们主要介绍一下如何通过算术均值滤波和中值滤波对一般的椒盐噪声进行平滑去噪。
首先我们需要明白算术均值滤波去噪以及中值滤波去噪的基本原理,而后我们才能通过代码实现,以期达成最终目的。
一、 算术均值滤波去噪
首先我们应当知道,图像的各个像素之间具有极大的相关性,而噪声的产生就标志着噪声这一点的像素与它周围的像素“格格不入”。因此我们可以先假设一个九宫格模型,把整个图像利用九宫格遍历一遍。并对每一个RGB分量进行相同的九宫格平均操作,即把每一个像素都作为九宫格的核心,然后分别将九宫格内的像素相加最终平均一下,重新赋值给当前遍历到的像素值。具体流程如下图:
这么一看是不是觉得这个算术均值滤波很简单呀?下面是代码实现:
//对图像进行算数均值滤波
//算法思想:对一组像素点取平均值赋值给中心点
public static BufferedImage average(BufferedImage leftImage) {
int width = leftImage.getWidth();
int height = leftImage.getHeight();
int srcRGBs[] = leftImage.getRGB(0, 0, width, height, null, 0, width);
//BufferedImage destImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int rgb[]=new int[3];
int rs[][]=new int[width][ height]; //
int gs[][]=new int[width][ height];
int bs[][]=new int[width][ height];
for(int j=0; j<height; j++) {
for (int i = 0; i < width; i++) {
ImageUtil.decodeColor(srcRGBs[j*width+i],rgb); //rgb[0]=R,rgb[1]=G,rgb[2]=B
rs[i][j]=rgb[0]; //Rֵ
gs[i][j]=rgb[1]; //Gֵ
bs[i][j]=rgb[2]; //bֵ
}
}
BufferedImage destImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int r=0,g=0,b=0;
for (int j = 0; j < height; j++) {
for(int i=0; i<width; i++) {
try {
ImageUtil.decodeColor(srcRGBs[j*width+i],rgb); //rgb[0]=R,rgb[1]=G,rgb[2]=B
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(i);
}
if (j>=1&&i>=1&&j<height-1&&i<width-1){
rgb[0]=(int)((rs[i-1][j-1]+rs[i][j-1]+rs[i+1][j-1]+
rs[i-1][j]+rs[i][j]+rs[i+1][j]+
rs[i-1][j+1]+rs[i][j+1]+rs[i+1][j+1])/9);
rgb[1]=(int)((gs[i-1][j-1]+gs[i][j-1]+gs[i+1][j-1]+
gs[i-1][j]+gs[i][j]+gs[i+1][j]+
gs[i-1][j+1]+gs[i][j+1]+gs[i+1][j+1])/9);
rgb[2]=(int)((bs[i-1][j-1]+bs[i][j-1]+bs[i+1][j-1]+
bs[i-1][j]+bs[i][j]+bs[i+1][j]+
bs[i-1][j+1]+bs[i][j+1]+bs[i+1][j+1])/9);
}else {
rgb[0]=rs[i][j];
rgb[1]=gs[i][j];
rgb[2]=bs[i][j];
}
destImage.setRGB(i,j, ImageUtil.encodeColor(rgb));
}
}
return destImage;
}
下面是效果展示:
值得注意的是,算术均值滤波对于边缘一圈像素点的处理有些玩味儿,他有自身的局限性,目前我尚不知道如何解决,有解决了的,还请下面评论告知!但是中值滤波有办法解决,并且呈现效果更好,下面我们看中值滤波如何去噪!
二、 中值滤波去噪
其实类似于算术均值滤波,我们也是要去一个九宫格模型,然后对每个像素值进行九宫格处理,但是不同的是我们这次把将整个九宫格平均一下给当前像素值了,我们将九宫格内的所有像素进行排序,取排在中间的像素值赋给当前待处理的像素值。
这是有一定的内在原理的,一个就是像素的相关性,还有一个就是椒盐噪声的噪声点要么是0要么是255,因此若当前我们要处理的正好是噪声点,那么赋给该噪声点的不可能会是它原本的像素值,而更可能是周围的正常的像素值。
下面是代码实现过程:
//中值滤波
//算法思想:将一组像素值排序,将中间大小的像素值赋值给目标点
public static BufferedImage getMid(BufferedImage leftImage) {
int width = leftImage.getWidth();
int height = leftImage.getHeight();
int srcRGBs[] = leftImage.getRGB(0, 0, width, height, null, 0, width);
int rgb[]=new int[3];
int rs[][]=new int[width][ height]; //
int gs[][]=new int[width][ height];
int bs[][]=new int[width][ height];
for(int j=0; j<height; j++) {
for (int i = 0; i < width; i++) {
ImageUtil.decodeColor(srcRGBs[j*width+i],rgb); //rgb[0]=R,rgb[1]=G,rgb[2]=B
rs[i][j]=rgb[0]; //Rֵ
gs[i][j]=rgb[1]; //Gֵ
bs[i][j]=rgb[2]; //bֵ
}
}
BufferedImage destImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int rgbs0[]=new int[9];
int rgbs1[]=new int[9];
int rgbs2[]=new int[9];
for (int j = 0; j < height; j++) {
for(int i=0; i<width; i++) {
try {
ImageUtil.decodeColor(srcRGBs[j*width+i],rgb); //rgb[0]=R,rgb[1]=G,rgb[2]=B
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(i);
}
int x=i,y=j;
x=x<1?1:x;
y=y<1?1:y;
x=x>=width-1?width-2:x;
y=y>=height-1?height-2:y;
int sum0=0;
for(int k=-1;k<2;k++){
for(int l=-1;l<2;l++){
rgbs0[sum0]=rs[x+k][y+l];
sum0++;
}
}
int sum1=0;
for(int k=-1;k<2;k++){
for(int l=-1;l<2;l++){
rgbs1[sum1]=gs[x+k][y+l];
sum1++;
}
}
int sum2=0;
for(int k=-1;k<2;k++){
for(int l=-1;l<2;l++){
rgbs2[sum2]=bs[x+k][y+l];
sum2++;
}
}
sort(rgbs0);
sort(rgbs1);
sort(rgbs2);
rgb[0]=rgbs0[4];
rgb[1]=rgbs1[4];
rgb[2]=rgbs2[4];
destImage.setRGB(i,j, ImageUtil.encodeColor(rgb));
}
}
return destImage;
}
这里有个处理边缘问题的小技巧,我假原图像周围有一圈的白色像素点,这样既不会影响最终的值,也能处理好真正边缘的像素。
下面是效果展示:
至此,我们利用两个滤波去除噪声的方法和简单原理就介绍完了,总体来说还是比较简单的,但也希望能帮助大家一点点。