在讲述如何通过JAVA编程实现中值滤波之前,先谈一下与空间滤波相关的数字图像处理的概念。
1.关于图像和数字图像处理
可以将图像视为是一个二维函数F(x,y),其中(x,y)代表一张数字图像上面对应像素点的坐标,而在任意坐标处的函数值F(x,y)就是该像素点的灰度或者亮度。因此,数字图像处理的过程就是通过计算机编程实现操作数字图像像素矩阵的过程。初学者大多接触的数字图像处理工具是Matlab,它里面提供了大量的内置函数来实现对图像的各种处理,包括灰度变换与空间滤波处理,频率与滤波处理,图像复原与重建,彩色图像处理,图像压缩,图像分割这几块内容。(具体可以参见冈萨雷斯和伍兹所著的《数字图像处理》)
2.空间滤波
空间滤波是用一个掩模(滤波器)依次处理每一个像素,输出图像的结果不只是由原来对应位置的像素值确定,而是由掩模范围内的元素值共同作用。空间滤波分为线性滤波与非线性滤波。
下面以中值滤波为例进行说明:
中值滤波属于空间滤波中的非线性滤波,基于图像像素的邻域进行操作时,使用一个mn的滤波器(编程时本质为一个mn的二维数组)的中心点划过一幅图像的的机理。可用于处理椒盐噪声。
椒盐噪声(salt & pepper noise)是数字图像的一个常见噪声,所谓椒盐,椒就是黑,盐就是白,椒盐噪声就是在图像上随机出现黑色白色的像素,椒盐噪声是一种因为信号脉冲强度引起的噪声。
下图为包含椒盐噪声的待处理图像:
下图为处理后的不含椒盐噪声的图像
中值滤波处理过程
1.对下图5*5的图像像素矩阵,以第二行第二列的2为中心,选取菱形邻域;
2.对选取的值:4 1 2 3 2进行排序,得到:1 2 2 3 4,故中值为2;
3.以中值2替换原像素中心点的值;
4.重复此步骤,直至将所有位置的像素点处理完毕。得到如下结果:
3.中值滤波算法:*
(1) 从内存区中读取待处理的包含椒盐噪声的图像;
(2) 对图像进行边界扩充处理(此次项目中采用“零值填充扩充边界”的方法;
(3) 将待处理的图像从RGB彩色图像转换为灰度图像;
(4) 创建33的中值滤波器(实质上为一个33的二维数组),利用冒泡排序算法求取中值滤波器中存放像素值的中位数,将其返回作为当前区域中心像元元素值;
(5) 设置for循环,是滤波器对图像中的各个像元依次进行处理,最终将处理好的图像输出。
下面请看代码:
package com.Image;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.Buffer;
import java.util.ArrayList;
import javax.imageio.*;
/*中值滤波*/
public class Median_FIlter {
String Image_path="D:\\impulsenoise.png";//图像路径
BufferedImage image;//存放读取图像的容器
BufferedImage image_expand;//拓展后的图像
int Alpha_Image,Red_Image,Green_Image, Blue_Image;//分别用于记录图像对应位置的透明度和三段灰度值
int[][] filter_image=new int[3][3];//中值滤波器,用于存放中心像元的邻域像素点值
int filter_image_length=this.filter_image.length;//中值滤波器长度
int[] disordered_pixel=new int[this.filter_image_length*this.filter_image_length];//存放未排序的邻域像元值
int median_value;//中值滤波器求取的中值
public Median_FIlter()//主类构造方法
{
try{
this.image=ImageIO.read(new File(this.Image_path));//读取图像
this.expand_image(this.image_expand);//拓展图像,并进行像素值填充
this.RGB_to_GRAY(this.image); //将RGB图像转换成灰度图像
ImageIO.write(this.image_expand,"jpg",new File("D:\\creation1.jpg"));//将拓展后的图像保存在内存中
this.MedianFilter_Image(this.image_expand); //对图像进行中值滤波处理,去除椒盐噪声影响
//将处理后的图像写入内存中
ImageIO.write(this.image_expand,"PNG",new File("D:\\filterred.jpg"));
}catch (Exception e){e.printStackTrace();}
}
public void expand_image(BufferedImage image_expand)//扩展图像:将边界以零值填充的形式进行扩充
{
//图像扩展
this.image_expand=new BufferedImage(this.image.getWidth(),this.image.getHeight(),BufferedImage.TYPE_INT_BGR);
//创建新的灰度图像,使用RGB(4)而不直接创建GRAY(10)的图像是为了避免对图像进行处理后像素丢失,以至于图像变暗
for (int row=0;row<this.image_expand.getHeight();row++)//将原图像像素值赋予新的RGB图像
{
for (int column=1;column<this.image_expand.getWidth();column++)
{
if(row==0||row==4||column==0||column==4)
{
this.image_expand.setRGB(row,column,0);//以零扩充图像边界
}else
{
this.image_expand.setRGB(row,column,this.image.getRGB(row,column));
}
}
}
}
public void RGB_to_GRAY(BufferedImage image)//将RGB图像转换为GRAY灰度图像
{
for (int row=0;row<image.getHeight();row++)
{
for (int column=0;column<image.getWidth();column++)
{
int trans=this.image_expand.getRGB(row,column);//获取图像的像素值
this.Alpha_Image=(trans>>24)&0xff;
this.Red_Image=(trans>>16)&0xff;
this.Green_Image=(trans>>8)&0xff;
this.Blue_Image=trans&0xff;
int average=(this.Red_Image+this.Green_Image+this.Blue_Image)/3;
trans=(this.Alpha_Image<<24)|(average<<16)|(average<<8)|(average);//色彩转换
this.image_expand.setRGB(row,column,trans);//重新设置当前像素点的像素值
}
}
System.out.println("RGB图像转换灰度图像成功");
}
public void MedianFilter_Image(BufferedImage image_expand)//中值滤波函数,对图像进行滤波处理,去除椒盐噪声影响
{
for (int row=1;row<this.image_expand.getHeight()-1;row++)
{
for (int column=1;column<this.image_expand.getWidth()-1;column++)
{
//使用中值滤波器获取当前像元邻域像元元素值
this.filter_image[0][0]=this.image_expand.getRGB(row-1,column-1);
this.filter_image[0][1]=this.image_expand.getRGB(row-1,column);
this.filter_image[0][2]=this.image_expand.getRGB(row-1,column+1);
this.filter_image[1][0]=this.image_expand.getRGB(row,column-1);
this.filter_image[1][1]=this.image_expand.getRGB(row,column);
this.filter_image[1][2]=this.image_expand.getRGB(row,column+1);
this.filter_image[2][0]=this.image_expand.getRGB(row+1,column-1);
this.filter_image[2][1]=this.image_expand.getRGB(row+1,column);
this.filter_image[2][2]=this.image_expand.getRGB(row+1,column+1);
//对滤波器内的元素值进行排序,并求取中值
this.image_expand.setRGB(row,column,this.Bubble(this.filter_image));//重新设定当前像元的元素值为求取的中值
}
}
}
public int Bubble(int[][] filter_image)//冒泡排序:将中值滤波器中存放的邻域像素值进行排序并返回中值
{
int count=0;//计数器
for (int row=0;row<this.filter_image_length;row++)//将滤波器中的像元值存放到一维数组中
{
for (int column=0;column<this.filter_image_length;column++)
{
if (count>=0&&count<=this.filter_image_length*this.filter_image_length)
{
this.disordered_pixel[count]=this.filter_image[row][column];
//System.out.println(this.disordered_pixel[count]);
count++;
}
}
}
//冒泡排序
for(int i=0;i<this.disordered_pixel.length-1;i++)
{ //only need n-1 swaps to move the smallest to the front
for(int j=0;j<this.disordered_pixel.length-1;j++){
if(this.disordered_pixel[j]>this.disordered_pixel[j+1])
{
int temp=this.disordered_pixel[j];
this.disordered_pixel[j]=this.disordered_pixel[j+1];
this.disordered_pixel[j+1]=temp;
}
}
}
this.median_value=this.disordered_pixel[this.filter_image_length*this.filter_image_length/2];//取邻域像元值中值
return this.median_value;
}
public static void main(String[] args)
{
new Median_FIlter();
}
}
代码说明:
此项目的主类名称为:Median_Filter,包含8个变量和4个主要方法,下面依次进行介绍。
(1) 类的变量
i. String Image_path=“C:\Users\13241\Desktop\impulsenoise.png”;//图像路径
2. BufferedImage image;//存放读取图像的容器
3. BufferedImage image_expand;//拓展后的图像
4. int Alpha_Image,Red_Image,Green_Image, Blue_Image;//分别用于记录图像对应位置的透明度和三段灰度值
5. int[][] filter_image=new int[3][3];//中值滤波器,用于存放中心像元的邻域像素点值
6. int filter_image_length=this.filter_image.length;//中值滤波器长度
7. int[] disordered_pixel=new int[this.filter_image_length*this.filter_image_length];//存放未排序的邻域像元值
8. int median_value;//中值滤波器求取的中值
(2) 类的方法
- public void expand_image(BufferedImage image_expand)//扩展图像:将边界以零值填充的形式进行扩充
- public void RGB_to_GRAY(BufferedImage image)//将RGB图像转换为GRAY灰度图像
- public void MedianFilter_Image(BufferedImage image_expand)//中值滤波函数,对图像进行滤波处理,去除椒盐噪声影响
- public int Bubble(int[][] filter_image)//冒泡排序:将中值滤波器中存放的邻域像素值进行排序并返回中值
- 涉及算法简介
(1) RGB图像转GRAY图像算法
主要通过遍历RGB图像每个像素点位的像素值,通过JAVA提供的getRGB()方法获取当前像元的灰度值;通过setRGB()方法对原图像的灰度值进行直接处理,完成转换
for (int row=0;row<image.getHeight();row++)
{
for (int column=0;column<image.getWidth();column++)
{
int trans=this.image_expand.getRGB(row,column);//获取图像的像素值
this.Alpha_Image=(trans>>24)&0xff;
this.Red_Image=(trans>>16)&0xff;
this.Green_Image=(trans>>8)&0xff;
this.Blue_Image=trans&0xff;
int average=(this.Red_Image+this.Green_Image+this.Blue_Image)/3;
trans=(this.Alpha_Image<<24)|(average<<16)|(average<<8)|(average);//色彩转换
this.image_expand.setRGB(row,column,trans);//重新设置当前像素点的像素值
}
}
(2) 冒泡排序算法(不多介绍,编程基础排序算法)
for(int i=0;i<this.disordered_pixel.length-1;i++)
{ //only need n-1 swaps to move the smallest to the front
for(int j=0;j<this.disordered_pixel.length-1;j++){
if(this.disordered_pixel[j]>this.disordered_pixel[j+1])
{
int temp=this.disordered_pixel[j];
this.disordered_pixel[j]=this.disordered_pixel[j+1];
this.disordered_pixel[j+1]=temp;
}
}
}
由于刚接触数字图像处理,不足之处还请各位多提修改意见,谢谢。