高斯濾波器的原理及實(shí)現(xiàn)過(guò)程
發(fā)布時(shí)間:2019-09-02 責(zé)任編輯:xueqi
【導(dǎo)讀】高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑圖像。其作用原理和均值濾波器類似,都是取濾波器窗口內(nèi)的像素的均值作為輸出。本文主要介紹了高斯濾波器的原理及其實(shí)現(xiàn)過(guò)程。
其窗口模板的系數(shù)和均值濾波器不同,均值濾波器的模板系數(shù)都是相同的為1;而高斯濾波器的模板系數(shù),則隨著距離模板中心的增大而系數(shù)減小。所以,高斯濾波器相比于均值濾波器對(duì)圖像個(gè)模糊程度較小。
什么是高斯濾波器
既然名稱為高斯濾波器,那么其和高斯分布(正態(tài)分布)是有一定的關(guān)系的。一個(gè)二維的高斯函數(shù)如下:
其中(x,y)(x,y)為點(diǎn)坐標(biāo),在圖像處理中可認(rèn)為是整數(shù);σσ是標(biāo)準(zhǔn)差。要想得到一個(gè)高斯濾波器的模板,可以對(duì)高斯函數(shù)進(jìn)行離散化,得到的高斯函數(shù)值作為模板的系數(shù)。例如:要產(chǎn)生一個(gè)3×33×3的高斯濾波器模板,以模板的中心位置為坐標(biāo)原點(diǎn)進(jìn)行取樣。模板在各個(gè)位置的坐標(biāo),如下所示(x軸水平向右,y軸豎直向下)
這樣,將各個(gè)位置的坐標(biāo)帶入到高斯函數(shù)中,得到的值就是模板的系數(shù)。
對(duì)于窗口模板的大小為(2k+1)×(2k+1),模板中各個(gè)元素值的計(jì)算公式如下:
這樣計(jì)算出來(lái)的模板有兩種形式:小數(shù)和整數(shù)。
小數(shù)形式的模板,就是直接計(jì)算得到的值,沒(méi)有經(jīng)過(guò)任何的處理;
整數(shù)形式的,則需要進(jìn)行歸一化處理,將模板左上角的值歸一化為1,下面會(huì)具體介紹。使用整數(shù)的模板時(shí),需要在模板的前面加一個(gè)系數(shù),系數(shù)為
也就是模板系數(shù)和的倒數(shù)。
高斯模板的生成
知道模板生成的原理,實(shí)現(xiàn)起來(lái)也就不困難了
void generateGaussianTemplate(double window[][11], int ksize, double sigma)
{
static const double pi = 3.1415926;
int center = ksize / 2; // 模板的中心位置,也就是坐標(biāo)的原點(diǎn)
double x2, y2;
for (int i = 0; i < ksize; i++)
{
x2 = pow(i - center, 2);
for (int j = 0; j < ksize; j++)
{
y2 = pow(j - center, 2);
double g = exp(-(x2 + y2) / (2 * sigma * sigma));
g /= 2 * pi * sigma;
window[i][j] = g;
}
}
double k = 1 / window[0][0]; // 將左上角的系數(shù)歸一化為1
for (int i = 0; i < ksize; i++)
{
for (int j = 0; j < ksize; j++)
{
window[i][j] *= k;
}
}
}
需要一個(gè)二維數(shù)組,存放生成的系數(shù)(這里假設(shè)模板的最大尺寸不會(huì)超過(guò)11);第二個(gè)參數(shù)是模板的大小(不要超過(guò)11);第三個(gè)參數(shù)就比較重要了,是高斯分布的標(biāo)準(zhǔn)差。
生成的過(guò)程,首先根據(jù)模板的大小,找到模板的中心位置ksize/2。然后就是遍歷,根據(jù)高斯分布的函數(shù),計(jì)算模板中每個(gè)系數(shù)的值。
需要注意的是,最后歸一化的過(guò)程,使用模板左上角的系數(shù)的倒數(shù)作為歸一化的系數(shù)(左上角的系數(shù)值被歸一化為1),模板中的每個(gè)系數(shù)都乘以該值(左上角系數(shù)的倒數(shù)),然后將得到的值取整,就得到了整數(shù)型的高斯濾波器模板。
下面截圖生成的是,大小為3×3,σ=0.83×3,σ=0.8的模板
對(duì)上述解結(jié)果取整后得到如下模板:
這個(gè)模板就比較熟悉了,其就是根據(jù)σ=0.8的高斯函數(shù)生成的模板。
至于小數(shù)形式的生成也比較簡(jiǎn)單,去掉歸一化的過(guò)程,并且在求解過(guò)程后,模板的每個(gè)系數(shù)要除以所有系數(shù)的和。具體代碼如下:
void generateGaussianTemplate(double window[][11], int ksize, double sigma)
{
static const double pi = 3.1415926;
int center = ksize / 2; // 模板的中心位置,也就是坐標(biāo)的原點(diǎn)
double x2, y2;
double sum = 0;
for (int i = 0; i < ksize; i++)
{
x2 = pow(i - center, 2);
for (int j = 0; j < ksize; j++)
{
y2 = pow(j - center, 2);
double g = exp(-(x2 + y2) / (2 * sigma * sigma));
g /= 2 * pi * sigma;
sum += g;
window[i][j] = g;
}
}
//double k = 1 / window[0][0]; // 將左上角的系數(shù)歸一化為1
for (int i = 0; i < ksize; i++)
{
for (int j = 0; j < ksize; j++)
{
window[i][j] /= sum;
}
}
}
3×3,σ=0.8的小數(shù)型模板。
σσ值的意義及選取
通過(guò)上述的實(shí)現(xiàn)過(guò)程,不難發(fā)現(xiàn),高斯濾波器模板的生成最重要的參數(shù)就是高斯分布的標(biāo)準(zhǔn)差σσ。標(biāo)準(zhǔn)差代表著數(shù)據(jù)的離散程度,如果σσ較小,那么生成的模板的中心系數(shù)較大,而周圍的系數(shù)較小,這樣對(duì)圖像的平滑效果就不是很明顯;反之,σσ較大,則生成的模板的各個(gè)系數(shù)相差就不是很大,比較類似均值模板,對(duì)圖像的平滑效果比較明顯。
來(lái)看下一維高斯分布的概率分布密度圖:
橫軸表示可能得取值x,豎軸表示概率分布密度F(x),那么不難理解這樣一個(gè)曲線與x軸圍成的圖形面積為1。σσ(標(biāo)準(zhǔn)差)決定了這個(gè)圖形的寬度,可以得出這樣的結(jié)論:σσ越大,則圖形越寬,尖峰越小,圖形較為平緩;σσ越小,則圖形越窄,越集中,中間部分也就越尖,圖形變化比較劇烈。這其實(shí)很好理解,如果sigma也就是標(biāo)準(zhǔn)差越大,則表示該密度分布一定比較分散,由于面積為1,于是尖峰部分減小,寬度越寬(分布越分散);同理,當(dāng)σσ越小時(shí),說(shuō)明密度分布較為集中,于是尖峰越尖,寬度越窄!
于是可以得到如下結(jié)論:
σσ越大,分布越分散,各部分比重差別不大,于是生成的模板各元素值差別不大,類似于平均模板;
σσ越小,分布越集中,中間部分所占比重遠(yuǎn)遠(yuǎn)高于其他部分,反映到高斯模板上就是中心元素值遠(yuǎn)遠(yuǎn)大于其他元素值,于是自然而然就相當(dāng)于中間值得點(diǎn)運(yùn)算。
基于OpenCV的實(shí)現(xiàn)
在生成高斯模板好,其簡(jiǎn)單的實(shí)現(xiàn)和其他的空間濾波器沒(méi)有區(qū)別,具體代碼如下:
void GaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
{
CV_Assert(src.channels() || src.channels() == 3); // 只處理單通道或者三通道圖像
const static double pi = 3.1415926;
// 根據(jù)窗口大小和sigma生成高斯濾波器模板
// 申請(qǐng)一個(gè)二維數(shù)組,存放生成的高斯模板矩陣
double **templateMatrix = new double*[ksize];
for (int i = 0; i < ksize; i++)
templateMatrix[i] = new double[ksize];
int origin = ksize / 2; // 以模板的中心為原點(diǎn)
double x2, y2;
double sum = 0;
for (int i = 0; i < ksize; i++)
{
x2 = pow(i - origin, 2);
for (int j = 0; j < ksize; j++)
{
y2 = pow(j - origin, 2);
// 高斯函數(shù)前的常數(shù)可以不用計(jì)算,會(huì)在歸一化的過(guò)程中給消去
double g = exp(-(x2 + y2) / (2 * sigma * sigma));
sum += g;
templateMatrix[i][j] = g;
}
}
for (int i = 0; i < ksize; i++)
{
for (int j = 0; j < ksize; j++)
{
templateMatrix[i][j] /= sum;
cout << templateMatrix[i][j] << " ";
}
cout << endl;
}
// 將模板應(yīng)用到圖像中
int border = ksize / 2;
copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
int channels = dst.channels();
int rows = dst.rows - border;
int cols = dst.cols - border;
for (int i = border; i < rows; i++)
{
for (int j = border; j < cols; j++)
{
double sum[3] = { 0 };
for (int a = -border; a <= border; a++)
{
for (int b = -border; b <= border; b++)
{
if (channels == 1)
{
sum[0] += templateMatrix[border + a][border + b] * dst.at<uchar>(i + a, j + b);
}
else if (channels == 3)
{
Vec3b rgb = dst.at<Vec3b>(i + a, j + b);
auto k = templateMatrix[border + a][border + b];
sum[0] += k * rgb[0];
sum[1] += k * rgb[1];
sum[2] += k * rgb[2];
}
}
}
for (int k = 0; k < channels; k++)
{
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (channels == 1)
dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
else if (channels == 3)
{
Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
dst.at<Vec3b>(i, j) = rgb;
}
}
}
// 釋放模板數(shù)組
for (int i = 0; i < ksize; i++)
delete[] templateMatrix[i];
delete[] templateMatrix;
}
只處理單通道或者三通道圖像,模板生成后,其濾波(卷積過(guò)程)就比較簡(jiǎn)單了。不過(guò),這樣的高斯濾波過(guò)程,其循環(huán)運(yùn)算次數(shù)為m×n×ksize2,其中m,n為圖像的尺寸;ksize為高斯濾波器的尺寸。這樣其時(shí)間復(fù)雜度為O(ksize2),隨濾波器的模板的尺寸呈平方增長(zhǎng),當(dāng)高斯濾波器的尺寸較大時(shí),其運(yùn)算效率是極低的。為了,提高濾波的運(yùn)算速度,可以將二維的高斯濾波過(guò)程分解開(kāi)來(lái)。
分離實(shí)現(xiàn)高斯濾波
由于高斯函數(shù)的可分離性,尺寸較大的高斯濾波器可以分成兩步進(jìn)行:首先將圖像在水平(豎直)方向與一維高斯函數(shù)進(jìn)行卷積;然后將卷積后的結(jié)果在豎直(水平)方向使用相同的一維高斯函數(shù)得到的模板進(jìn)行卷積運(yùn)算。具體實(shí)現(xiàn)代碼如下:
// 分離的計(jì)算
void separateGaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
{
CV_Assert(src.channels()==1 || src.channels() == 3); // 只處理單通道或者三通道圖像
// 生成一維的高斯濾波模板
double *matrix = new double[ksize];
double sum = 0;
int origin = ksize / 2;
for (int i = 0; i < ksize; i++)
{
// 高斯函數(shù)前的常數(shù)可以不用計(jì)算,會(huì)在歸一化的過(guò)程中給消去
double g = exp(-(i - origin) * (i - origin) / (2 * sigma * sigma));
sum += g;
matrix[i] = g;
}
// 歸一化
for (int i = 0; i < ksize; i++)
matrix[i] /= sum;
// 將模板應(yīng)用到圖像中
int border = ksize / 2;
copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
int channels = dst.channels();
int rows = dst.rows - border;
int cols = dst.cols - border;
// 水平方向
for (int i = border; i < rows; i++)
{
for (int j = border; j < cols; j++)
{
double sum[3] = { 0 };
for (int k = -border; k <= border; k++)
{
if (channels == 1)
{
sum[0] += matrix[border + k] * dst.at<uchar>(i, j + k); // 行不變,列變化;先做水平方向的卷積
}
else if (channels == 3)
{
Vec3b rgb = dst.at<Vec3b>(i, j + k);
sum[0] += matrix[border + k] * rgb[0];
sum[1] += matrix[border + k] * rgb[1];
sum[2] += matrix[border + k] * rgb[2];
}
}
for (int k = 0; k < channels; k++)
{
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (channels == 1)
dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
else if (channels == 3)
{
Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
dst.at<Vec3b>(i, j) = rgb;
}
}
}
// 豎直方向
for (int i = border; i < rows; i++)
{
for (int j = border; j < cols; j++)
{
double sum[3] = { 0 };
for (int k = -border; k <= border; k++)
{
if (channels == 1)
{
sum[0] += matrix[border + k] * dst.at<uchar>(i + k, j); // 列不變,行變化;豎直方向的卷積
}
else if (channels == 3)
{
Vec3b rgb = dst.at<Vec3b>(i + k, j);
sum[0] += matrix[border + k] * rgb[0];
sum[1] += matrix[border + k] * rgb[1];
sum[2] += matrix[border + k] * rgb[2];
}
}
for (int k = 0; k < channels; k++)
{
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (channels == 1)
dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
else if (channels == 3)
{
Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
dst.at<Vec3b>(i, j) = rgb;
}
}
}
delete[] matrix;
}
代碼沒(méi)有重構(gòu)較長(zhǎng),不過(guò)其實(shí)現(xiàn)原理是比較簡(jiǎn)單的。首先得到一維高斯函數(shù)的模板,在卷積(濾波)的過(guò)程中,保持行不變,列變化,在水平方向上做卷積運(yùn)算;接著在上述得到的結(jié)果上,保持列不邊,行變化,在豎直方向上做卷積運(yùn)算。這樣分解開(kāi)來(lái),算法的時(shí)間復(fù)雜度為O(ksize)O(ksize),運(yùn)算量和濾波器的模板尺寸呈線性增長(zhǎng)。
在OpenCV也有對(duì)高斯濾波器的封裝GaussianBlur,其聲明如下:
CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
二維高斯函數(shù)的標(biāo)準(zhǔn)差在x和y方向上應(yīng)該分別有一個(gè)標(biāo)準(zhǔn)差,在上面的代碼中一直設(shè)其在x和y方向的標(biāo)準(zhǔn)是相等的,在OpenCV中的高斯濾波器中,可以在x和y方向上設(shè)置不同的標(biāo)準(zhǔn)差。
下圖是自己實(shí)現(xiàn)的高斯濾波器和OpenCV中的GaussianBlur的結(jié)果對(duì)比
上圖是5×5,σ=0.8的高斯濾波器,可以看出兩個(gè)實(shí)現(xiàn)得到的結(jié)果沒(méi)有很大的區(qū)別。
總結(jié)
高斯濾波器是一種線性平滑濾波器,其濾波器的模板是對(duì)二維高斯函數(shù)離散得到。由于高斯模板的中心值最大,四周逐漸減小,其濾波后的結(jié)果相對(duì)于均值濾波器來(lái)說(shuō)更好。
高斯濾波器最重要的參數(shù)就是高斯分布的標(biāo)準(zhǔn)差σσ,標(biāo)準(zhǔn)差和高斯濾波器的平滑能力有很大的能力,σσ越大,高斯濾波器的頻帶就較寬,對(duì)圖像的平滑程度就越好。通過(guò)調(diào)節(jié)σσ參數(shù),可以平衡對(duì)圖像的噪聲的抑制和對(duì)圖像的模糊。
特別推薦
- 復(fù)雜的RF PCB焊接該如何確保恰到好處?
- 電源效率測(cè)試
- 科技的洪荒之力:可穿戴設(shè)備中的MEMS傳感器 助運(yùn)動(dòng)員爭(zhēng)金奪銀
- 輕松滿足檢測(cè)距離,勞易測(cè)新型電感式傳感器IS 200系列
- Aigtek推出ATA-400系列高壓功率放大器
- TDK推出使用壽命更長(zhǎng)和熱點(diǎn)溫度更高的全新氮?dú)馓畛淙嘟涣鳛V波電容器
- 博瑞集信推出低噪聲、高增益平坦度、低功耗 | 低噪聲放大器系列
技術(shù)文章更多>>
- 如何選擇和應(yīng)用機(jī)電繼電器實(shí)現(xiàn)多功能且可靠的信號(hào)切換
- 基于APM32F411的移動(dòng)電源控制板應(yīng)用方案
- 數(shù)字儀表與模擬儀表:它們有何區(qū)別?
- 聚焦制造業(yè)企業(yè)貨量旺季“急難愁盼”,跨越速運(yùn)打出紓困“連招”
- 選擇LDO時(shí)的主要考慮因素和挑戰(zhàn)
技術(shù)白皮書(shū)下載更多>>
- 車規(guī)與基于V2X的車輛協(xié)同主動(dòng)避撞技術(shù)展望
- 數(shù)字隔離助力新能源汽車安全隔離的新挑戰(zhàn)
- 汽車模塊拋負(fù)載的解決方案
- 車用連接器的安全創(chuàng)新應(yīng)用
- Melexis Actuators Business Unit
- Position / Current Sensors - Triaxis Hall
熱門(mén)搜索
光收發(fā)器
光通訊器件
光纖連接器
軌道交通
國(guó)防航空
過(guò)流保護(hù)器
過(guò)熱保護(hù)
過(guò)壓保護(hù)
焊接設(shè)備
焊錫焊膏
恒溫振蕩器
恒壓變壓器
恒壓穩(wěn)壓器
紅外收發(fā)器
紅外線加熱
厚膜電阻
互連技術(shù)
滑動(dòng)分壓器
滑動(dòng)開(kāi)關(guān)
輝曄
混合保護(hù)器
混合動(dòng)力汽車
混頻器
霍爾傳感器
機(jī)電元件
基創(chuàng)卓越
激光二極管
激光器
計(jì)步器
繼電器