天天看點

JAVA空間濾波——中值濾波

在講述如何通過JAVA程式設計實作中值濾波之前,先談一下與空間濾波相關的數字圖像處理的概念。

1.關于圖像和數字圖像處理

可以将圖像視為是一個二維函數F(x,y),其中(x,y)代表一張數字圖像上面對應像素點的坐标,而在任意坐标處的函數值F(x,y)就是該像素點的灰階或者亮度。是以,數字圖像處理的過程就是通過計算機程式設計實作操作數字圖像像素矩陣的過程。初學者大多接觸的數字圖像處理工具是Matlab,它裡面提供了大量的内置函數來實作對圖像的各種處理,包括灰階變換與空間濾波處理,頻率與濾波處理,圖像複原與重建,彩色圖像處理,圖像壓縮,圖像分割這幾塊内容。(具體可以參見岡薩雷斯和伍茲所著的《數字圖像處理》)

2.空間濾波

空間濾波是用一個掩模(濾波器)依次處理每一個像素,輸出圖像的結果不隻是由原來對應位置的像素值确定,而是由掩模範圍内的元素值共同作用。空間濾波分為線性濾波與非線性濾波。

下面以中值濾波為例進行說明:

中值濾波屬于空間濾波中的非線性濾波,基于圖像像素的鄰域進行操作時,使用一個mn的濾波器(程式設計時本質為一個mn的二維數組)的中心點劃過一幅圖像的的機理。可用于處理椒鹽噪聲。

椒鹽噪聲(salt & pepper noise)是數字圖像的一個常見噪聲,所謂椒鹽,椒就是黑,鹽就是白,椒鹽噪聲就是在圖像上随機出現黑色白色的像素,椒鹽噪聲是一種因為信号脈沖強度引起的噪聲。

下圖為包含椒鹽噪聲的待處理圖像:

JAVA空間濾波——中值濾波

下圖為處理後的不含椒鹽噪聲的圖像

JAVA空間濾波——中值濾波

中值濾波處理過程

1.對下圖5*5的圖像像素矩陣,以第二行第二列的2為中心,選取菱形鄰域;

JAVA空間濾波——中值濾波

2.對選取的值:4 1 2 3 2進行排序,得到:1 2 2 3 4,故中值為2;

3.以中值2替換原像素中心點的值;

4.重複此步驟,直至将所有位置的像素點處理完畢。得到如下結果:

JAVA空間濾波——中值濾波

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) 類的方法

  1. public void expand_image(BufferedImage image_expand)//擴充圖像:将邊界以零值填充的形式進行擴充
  2. public void RGB_to_GRAY(BufferedImage image)//将RGB圖像轉換為GRAY灰階圖像
  3. public void MedianFilter_Image(BufferedImage image_expand)//中值濾波函數,對圖像進行濾波處理,去除椒鹽噪聲影響
  4. public int Bubble(int[][] filter_image)//冒泡排序:将中值濾波器中存放的鄰域像素值進行排序并傳回中值
  5. 涉及算法簡介

    (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;

    }

    }

    }

    由于剛接觸數字圖像處理,不足之處還請各位多提修改意見,謝謝。