高斯模糊(英語: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();
}
}
運行結果
原圖片
高斯模糊化後的圖片
附:程序源碼下載