Java實現高斯模糊算法處理圖像

高斯模糊(英語:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等圖像處理軟件中廣泛使用的處理效果,通常用它來減少圖像噪聲以及降低細節層次。

簡介

高斯模糊(Gaussian Blur)是美國Adobe圖像軟件公司開發的一個圖像處理軟件:Adobe Photoshop(系列)中的一個濾鏡,具體的位置在:濾鏡—模糊——高斯模糊!高斯模糊的原理中,它是根據高斯曲線調節像素色值,它是有選擇地模糊圖像。說得直白一點,就是高斯模糊能夠把某一點周圍的像素色值按高斯曲線統計起來,採用數學上加權平均的計算方法得到這條曲線的色值,最後能夠留下人物的輪廓,即曲線.是指當 Adobe Photoshop 將加權平均應用於像素時生成的鐘形曲線。
在PS中間,你應該知道所有的顏色不過都是數字,各種模糊不過都是算法。把要模糊的像素色值統計,用數學上加權平均的計算方法(高斯函數)得到色值,對範圍、半徑等進行模糊,大致就是高斯模糊。

原理

周邊像素的平均值

所謂”模糊”,可以理解成每一個像素都取周邊像素的平均值。





上圖中,2是中間點,周邊點都是1。
“中間點”取”周圍點”的平均值,就會變成1。在數值上,這是一種”平滑化”。在圖形上,就相當於產生”模糊”效果,”中間點”失去細節。
顯然,計算平均值時,取值範圍越大,”模糊效果”越強烈。

下圖分別是原圖、模糊半徑3像素、模糊半徑10像素的效果。模糊半徑越大,圖像就越模糊。從數值角度看,就是數值越平滑。



接下來的問題就是,既然每個點都要取周邊像素的平均值,那麼應該如何分配權重呢?
如果使用簡單平均,顯然不是很合理,因爲圖像都是連續的,越靠近的點關係越密切,越遠離的點關係越疏遠。因此,加權平均更合理,距離越近的點權重越大,距離越遠的點權重越小。

正態分佈的權重



正態分佈顯然是一種可取的權重分配模式。
在圖形上,正態分佈是一種鐘形曲線,越接近中心,取值越大,越遠離中心,取值越小。
計算平均值的時候,我們只需要將”中心點”作爲原點,其他點按照其在正態曲線上的位置,分配權重,就可以得到一個加權平均值。

高斯函數

上面的正態分佈是一維的,圖像都是二維的,所以我們需要二維的正態分佈。



正態分佈的密度函數叫做”高斯函數”(Gaussian function)。它的一維形式是:


一維形式

其中,μ是x的均值,σ是x的方差。因爲計算平均值的時候,中心點就是原點,所以μ等於0。據一維高斯函數,可以推導得到二維形式


進一步推導


二維高斯函數

有了這個函數 ,就可以計算每個點的權重了

權重矩陣

假定中心點的座標是(0,0),那麼距離它最近的8個點的座標如下:


權重矩陣


權重矩陣


權重矩陣

更遠的點以此類推。

爲了計算權重矩陣,需要設定σ的值。假定σ=1.5,則模糊半徑爲1的權重矩陣如下:
這9個點的權重總和等於0.4787147,如果只計算這9個點的加權平均,還必須讓它們的權重之和等於1,因此上面9個值還要分別除以0.4787147,得到最終的權重矩陣。

計算高斯模糊

有了權重矩陣,就可以計算高斯模糊的值了。假設現有9個像素點,灰度值(0-255)如下:


計算高斯模糊


計算高斯模糊


計算高斯模糊

每個點乘以自己的權重值:
得到將這9個值加起來,就是中心點的高斯模糊的值。
對所有點重複這個過程,就得到了高斯模糊後的圖像。如果原圖是彩色圖片,可以對RGB三個通道分別做高斯模糊。

高斯模糊矩陣示例表

這是一個計算 σ = 0.84089642 的高斯分佈生成的示例矩陣。注意中心元素 [4,4]] 處有最大值,隨着距離中心越遠數值對稱地減小。



注意中心處的 0.22508352 比 3σ 外的 0.00019117 大 1177 倍。

源碼實現

package cn.zju.edu.liuxing;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
/**
* 簡單高斯模糊算法
*
* @param args
* @throws IOException [參數說明]
*
* @return void [返回類型說明]
* @exception throws [違例類型] [違例說明]
* @see [類、類#方法、類#成員]
*/
public class GaussianBlur {
    public static void main(String[] args) throws IOException {
        BufferedImage img = ImageIO.read(new File("./a.jpg")); //將這個圖片拷貝到你項目根目錄下
        System.out.println(img);
        int height = img.getHeight();
        int width = img.getWidth();
        int[][] martrix = new int[3][3];
        int[] values = new int[9];
        for (int i = 0; i < width; i++)
            for (int j = 0; j < height; j++) {
                readPixel(img, i, j, values);
                fillMatrix(martrix, values);
                img.setRGB(i, j, avgMatrix(martrix));
            }
        ImageIO.write(img, "jpeg", new File("./test.jpg"));
    }

    private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
        int xStart = x - 1;
        int yStart = y - 1;
        int current = 0;
        for (int i = xStart; i < 3 + xStart; i++)
            for (int j = yStart; j < 3 + yStart; j++) {
                int tx = i;
                if (tx < 0) {
                    tx = -tx;

                } else if (tx >= img.getWidth()) {
                    tx = x;
                }
                int ty = j;
                if (ty < 0) {
                    ty = -ty;
                } else if (ty >= img.getHeight()) {
                    ty = y;
                }
                pixels[current++] = img.getRGB(tx, ty);

            }
    }

    private static void fillMatrix(int[][] matrix, int[] values) {
        int filled = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                x[j] = values[filled++];
            }
        }
    }

    private static int avgMatrix(int[][] matrix) {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                if (j == 1) {
                    continue;
                }
                Color c = new Color(x[j]);
                r += c.getRed();
                g += c.getGreen();
                b += c.getBlue();
            }
        }
        return new Color(r / 8, g / 8, b / 8).getRGB();

    }
}

運行結果

原圖片


原圖片

高斯模糊化後的圖片


高斯模糊化後的圖片

程序源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章