高斯模糊

高斯模糊

高斯模糊(英語:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等圖像處理軟體中廣泛使用的處理效果,通常用它來減少圖像噪聲以及降低細節層次。在PS中,把要模糊的像素色值統計,用數學上加權平均的計算方法(高斯函式)得到色值,對範圍、半徑等進行模糊,大致就是高斯模糊。

基本介紹

高斯模糊(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.00000067

0.00002292

0.00019117

0.00038771

0.00019117

0.00002292

0.00000067

0.00002292

0.00078633

0.00655965

0.01330373

0.00655965

0.00078633

0.00002292

0.00019117

0.00655965

0.05472157

0.11098164

0.05472157

0.00655965

0.00019117

0.00038771

0.01330373

0.11098164

0.22508352

0.11098164

0.01330373

0.00038771

0.00019117

0.00655965

0.05472157

0.11098164

0.05472157

0.00655965

0.00019117

0.00002292

0.00078633

0.00655965

0.01330373

0.00655965

0.00078633

0.00002292

0.00000067

0.00002292

0.00019117

0.00038771

0.00019117

0.00002292

0.00000067

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

Java程式實現

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

import java.awt.Color;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;

import javax.imageio.ImageIO;

public class Test {

/**

* 簡單高斯模糊算法

*

* @param args

* @throws IOException [參數說明]

*

* @return void [返回類型說明]

* @exception throws [ 違例 類型] [違例說明]

* @see [類、類#方法、類#成員]

*/

public static void main (String[] args)

throws IOException {

BufferedImage img = ImageIO.read(new File("d:\\My Documents\\psb.jpg"));

System.out.println(img);

int height = img.getHeight();

int width = img.getWidth();

int[][] matrix = 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(matrix, values);

img.setRGB(i, j, avgMatrix(matrix));

}

}

ImageIO.write(img, "jpeg", new File("d:/test.jpg"));//保存在d盤為test.jpeg檔案

}

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

}

}

相關搜尋

熱門詞條

聯絡我們