圖像濾波之高斯濾波介紹


1 高斯濾波簡介

  了解高斯濾波之前,我們首先熟悉一下高斯噪聲。高斯噪聲是指它的概率密度函數服從高斯分布(即正態分布)的一類噪聲。如果一個噪聲,它的幅度分布服從高斯分布,而它的功率譜密度又是均勻分布的,則稱它為高斯白噪聲。高斯白噪聲的二階矩不相關,一階矩為常數,是指先后信號在時間上的相關性,高斯白噪聲包括熱噪聲散粒噪聲

  高斯濾波器是一類根據高斯函數的形狀來選擇權值的線性平滑濾波器。高斯平滑濾波器對於抑制服從正態分布的噪聲非常有效。一維零均值高斯函數為:

                             g(x)=exp( -x^2/(2 sigma^2) 

  其中,高斯分布參數Sigma決定了高斯函數的寬度。對於圖像處理來說,常用二維零均值離散高斯函數作平滑濾波器,高斯函數的圖形: 

                  

2 高斯濾波函數

  對於圖像來說,高斯濾波器是利用高斯核的一個2維的卷積算子,用於圖像模糊化(去除細節和噪聲)。

  1) 高斯分布

  一維高斯分布:

         

  二維高斯分布:

    

  2) 高斯核

  理論上,高斯分布在所有定義域上都有非負值,這就需要一個無限大的卷積核。實際上,僅需要取均值周圍3倍標准差內的值,以外部份直接去掉即可。 如下圖為一個標准差為1.0的整數值高斯核。

                        

3 高斯濾波性質

  高斯函數具有五個重要的性質,這些性質使得它在早期圖像處理中特別有用.這些性質表明,高斯平滑濾波器無論在空間域還是在頻率域都是十分有效的低通濾波器,且在實際圖像處理中得到了工程人員的有效使用.高斯函數具有五個十分重要的性質,它們是: 

  (1)二維高斯函數具有旋轉對稱性,即濾波器在各個方向上的平滑程度是相同的.一般來說,一幅圖像的邊緣方向是事先不知道的,因此,在濾波前是無法確定一個方向上比另一方向上需要更多的平滑.旋轉對稱性意味着高斯平滑濾波器在后續邊緣檢測中不會偏向任一方向. 

  (2)高斯函數是單值函數.這表明,高斯濾波器用像素鄰域的加權均值來代替該點的像素值,而每一鄰域像素點權值是隨該點與中心點的距離單調增減的.這一性質是很重要的,因為邊緣是一種圖像局部特征,如果平滑運算對離算子中心很遠的像素點仍然有很大作用,則平滑運算會使圖像失真. 

  (3)高斯函數的傅立葉變換頻譜是單瓣的.正如下面所示,這一性質是高斯函數付立葉變換等於高斯函數本身這一事實的直接推論.圖像常被不希望的高頻信號所污染(噪聲和細紋理).而所希望的圖像特征(如邊緣),既含有低頻分量,又含有高頻分量.高斯函數付立葉變換的單瓣意味着平滑圖像不會被不需要的高頻信號所污染,同時保留了大部分所需信號. 

  (4)高斯濾波器寬度(決定着平滑程度)是由參數σ表征的,而且σ和平滑程度的關系是非常簡單的.σ越大,高斯濾波器的頻帶就越寬,平滑程度就越好.通過調節平滑程度參數σ,可在圖像特征過分模糊(過平滑)與平滑圖像中由於噪聲和細紋理所引起的過多的不希望突變量(欠平滑)之間取得折衷. 

  (5)由於高斯函數的可分離性,較大尺寸的高斯濾波器可以得以有效地實現.二維高斯函數卷積可以分兩步來進行,首先將圖像與一維高斯函數進行卷積,然后將卷積結果與方向垂直的相同一維高斯函數卷積.因此,二維高斯濾波的計算量隨濾波模板寬度成線性增長而不是成平方增長.

4 高斯濾波應用

  高斯濾波后圖像被平滑的程度取決於標准差。它的輸出是領域像素的加權平均,同時離中心越近的像素權重越高。因此,相對於均值濾波(mean filter)它的平滑效果更柔和,而且邊緣保留的也更好。

  高斯濾波被用作為平滑濾波器的本質原因是因為它是一個低通濾波器,見下圖。而且,大部份基於卷積平滑濾波器都是低通濾波器。

                        

                      圖.高斯濾波器(標准差=3像素)的頻率響應。The spatial frequency axis is marked 

                          in cycles per pixel, and hence no value above 0.5 has a real meaning

5 高斯濾波步驟

 1)移動相關核的中心元素,使它位於輸入圖像待處理像素的正上方 

 2)將輸入圖像的像素值作為權重,乘以相關核 

 3)將上面各步得到的結果相加做為輸出 

 

6 高斯濾波源碼(C語言版)

  1 // gaosilvbo.cpp : 定義控制台應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <stdlib.h>
  6 #include <math.h>
  7 
  8 typedef unsigned long DWORD;
  9 typedef long LONG;
 10 typedef unsigned short WORD;
 11 typedef unsigned char BYTE;
 12 
 13 typedef struct tagRGBQUAD {
 14     BYTE    rgbBlue;
 15     BYTE    rgbGreen;
 16     BYTE    rgbRed;
 17     BYTE    rgbReserved;
 18 } RGBQUAD;
 19 
 20 #pragma pack (2)     /*指定按字節對齊*/  
 21 typedef struct tagBITMAPFILEHEADER {
 22     WORD    bfType;
 23     DWORD   bfSize;
 24     WORD    bfReserved1;
 25     WORD    bfReserved2;
 26     DWORD   bfOffBits;
 27 } BITMAPFILEHEADER;
 28 
 29 //恢復對齊狀態
 30 typedef struct tagBITMAPINFOHEADER{
 31     DWORD      biSize;
 32     LONG       biWidth;
 33     LONG       biHeight;
 34     WORD       biPlanes;
 35     WORD       biBitCount;
 36     DWORD      biCompression;
 37     DWORD      biSizeImage;
 38     LONG       biXPelsPerMeter;
 39     LONG       biYPelsPerMeter;
 40     DWORD      biClrUsed;
 41     DWORD      biClrImportant;
 42 } BITMAPINFOHEADER;
 43 
 44 unsigned char *pTempBmpBuf;    //讀入圖像數據的指針
 45 
 46 unsigned char *pBmpBuf;    //讀入圖像數據的指針
 47 
 48 
 49 int bmpWidth;              //圖像的寬
 50 int bmpHeight;             //圖像的高
 51 RGBQUAD *pColorTable;       //顏色表指針
 52 int biBitCount;            //圖像類型,每像素位數
 53 
 54 bool readBmp(char *bmpName)
 55 {
 56     //二進制讀方式打開指定的圖像文件
 57 
 58     FILE *fp=fopen(bmpName,"rb");
 59     if(fp==0) return 0;
 60 
 61 
 62     //跳過位圖文件頭結構BITMAPFILEHEADER
 63     fseek(fp, sizeof(BITMAPFILEHEADER),0);
 64 
 65     //定義位圖信息頭結構變量,讀取位圖信息頭進內存,存放在變量head中
 66     BITMAPINFOHEADER head;  
 67     fread(&head, sizeof(BITMAPINFOHEADER), 1,fp); 
 68 
 69     //獲取圖像寬、高、每像素所占位數等信息
 70     bmpWidth = head.biWidth;
 71     bmpHeight = head.biHeight;
 72     biBitCount = head.biBitCount;
 73 
 74 
 75     //定義變量,計算圖像每行像素所占的字節數(必須是的倍數)
 76     int lineByte=(bmpWidth * biBitCount/8+3)/4*4;
 77 
 78     //灰度圖像有顏色表,且顏色表表項為
 79     if(biBitCount==8){
 80         //申請顏色表所需要的空間,讀顏色表進內存
 81         pColorTable=new RGBQUAD[256];
 82         fread(pColorTable,sizeof(RGBQUAD),256,fp);
 83     }
 84 
 85 
 86     //申請位圖數據所需要的空間,讀位圖數據進內存
 87     pTempBmpBuf=new unsigned char[lineByte * bmpHeight];
 88 
 89     pBmpBuf=new unsigned char[lineByte * bmpHeight];
 90     fread(pTempBmpBuf,1,lineByte * bmpHeight,fp);
 91     fseek(fp, 1078,0);
 92     fread(pBmpBuf,1,lineByte * bmpHeight,fp);
 93 
 94     //關閉文件
 95     fclose(fp);
 96     return 1;
 97 }
 98 
 99 bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height,int biBitCount, RGBQUAD *pColorTable)
100 {
101     
102     if(!imgBuf)
103         return 0;
104 
105     //顏色表大小,以字節為單位,灰度圖像顏色表為字節,彩色圖像顏色表大小為
106     int colorTablesize=0;
107     if(biBitCount==8)
108         colorTablesize=1024;
109 
110     //待存儲圖像數據每行字節數為的倍數
111     int lineByte=(width * biBitCount/8+3)/4*4;
112 
113     //以二進制寫的方式打開文件
114     FILE *fp=fopen(bmpName,"wb");
115     if(fp==0) return 0;
116 
117     //申請位圖文件頭結構變量,填寫文件頭信息
118     BITMAPFILEHEADER fileHead;
119     fileHead.bfType = 0x4D42;//bmp類型
120 
121     //bfSize是圖像文件個組成部分之和
122     fileHead.bfSize= sizeof(BITMAPFILEHEADER)
123         + sizeof(BITMAPINFOHEADER)
124         + colorTablesize + lineByte*height;
125 
126     fileHead.bfReserved1 = 0;
127     fileHead.bfReserved2 = 0;
128 
129     //bfOffBits是圖像文件前個部分所需空間之和
130     fileHead.bfOffBits=54+colorTablesize;
131 
132     //寫文件頭進文件
133     fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);
134 
135     //申請位圖信息頭結構變量,填寫信息頭信息
136     BITMAPINFOHEADER head; 
137     head.biBitCount=biBitCount;
138     head.biClrImportant=0;
139     head.biClrUsed=0;
140     head.biCompression=0;
141     head.biHeight=height;
142     head.biPlanes=1;
143     head.biSize=40;
144     head.biSizeImage=lineByte*height;
145     head.biWidth=width;
146     head.biXPelsPerMeter=0;
147     head.biYPelsPerMeter=0;
148 
149     //寫位圖信息頭進內存
150     fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);
151 
152     //如果灰度圖像,有顏色表,寫入文件
153     if(biBitCount==8)
154         fwrite(pColorTable, sizeof(RGBQUAD),256, fp);
155 
156     //寫位圖數據進文件
157     fwrite(imgBuf, height*lineByte, 1, fp);
158 
159     //關閉文件
160     fclose(fp);
161     return 1;
162 }
163 
164 int _tmain(int argc, _TCHAR* argv[])
165 {
166         //讀入指定BMP文件進內存
167     char readPath[]="guass_test.bmp";
168     readBmp(readPath);
169     //輸出圖像的信息
170     printf("width=%d,height=%d,biBitCount=%d\n",
171         bmpWidth,bmpHeight,biBitCount);
172 
173     //每行字節數
174     int lineByte=(bmpWidth*biBitCount/8+3)/4*4;
175     //定義最終寫入的數據體
176     //pBmpBuf=new unsigned char[lineByte * bmpHeight];
177     //循環變量,圖像的坐標
178     int y,x;
179 
180     //循環變量,針對彩色圖像,遍歷每像素的三個分量
181     int k;
182     //單精度變量暫存計算后的灰度值(針對灰度圖像)
183     float       TempNum;
184     //指向TempBmpbuf的指針
185     unsigned char *TemPtr;
186     //指向BmpBuf的指針
187     unsigned char *Ptr;
188     //定義*3的模板(拉普拉斯)
189     float CoefArray[9]={1.0f,2.0f,1.0f,2.0f,4.0f,2.0f,1.0f,2.0f,1.0f};
190     //定義模板前乘的系數(拉普拉斯)
191     float coef=(float)(1.0/16.0);;  
192 
193     //lapulas濾波
194     if(biBitCount==8){//對於灰度圖像
195         for(y=1;y<bmpHeight-1;y++){
196             for(x=0;x<bmpWidth-1;x++){    
197 
198                 TemPtr=pTempBmpBuf+y*lineByte+x;
199                 Ptr=pBmpBuf+y*lineByte+x;
200 
201                 TempNum=(float)((unsigned char)*(TemPtr+lineByte-1))*CoefArray[0];
202                 TempNum+=(float)((unsigned char)*(TemPtr+lineByte))*CoefArray[1];
203                 TempNum+=(float)((unsigned char)*(TemPtr+lineByte+1))*CoefArray[2];
204                 TempNum+=(float)((unsigned char)*(TemPtr-1))*CoefArray[3];
205                 TempNum+=(float)((unsigned char)*TemPtr)*CoefArray[4];
206                 TempNum+=(float)((unsigned char)*(TemPtr+1))*CoefArray[5];
207                 TempNum+=(float)((unsigned char)*(TemPtr-lineByte-1))*CoefArray[6];
208                 TempNum+=(float)((unsigned char)*(TemPtr-lineByte))*CoefArray[7];
209                 TempNum+=(float)((unsigned char)*(TemPtr-lineByte+1))*CoefArray[8];
210 
211                 TempNum*=coef;
212 
213                 if(TempNum>255.0) *Ptr =(BYTE)255;
214                 else if(TempNum<0.0) 
215                     *Ptr =(unsigned char)fabs(TempNum);
216                 //用到了fabs函數,需要添加math.h頭文件
217                 else *Ptr=(char)TempNum;
218             }
219         }
220     }
221 
222     else if(biBitCount==24){//彩色圖像
223         for(y=0;y<bmpHeight/2;y++){
224             for(x=0;x<bmpWidth/2;x++){ 
225                 for(k=0;k<3;k++)//每像素RGB三個分量分別置才變成黑色
226                     *(pBmpBuf+y*lineByte+x*3+k)=0;
227             }
228         }
229     }
230     //將圖像數據存盤
231     char writePath[]="gauss_result.BMP";
232     saveBmp(writePath, pBmpBuf, bmpWidth, 
233         bmpHeight, biBitCount, pColorTable);
234     //清除緩沖區,pBmpBuf和pColorTable是全局變量,在文件讀入時申請的空間
235     delete []pBmpBuf;
236     delete []pTempBmpBuf;
237     if(biBitCount==8)
238         delete []pColorTable;
239     return 0;
240 }

高斯濾波處理之后:                                                                   高斯濾波處理之前:

   

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM