高斯濾波
一、目的與原理
(1)目的:用於消除高斯噪聲;
(2)原理:高斯噪聲的特點是噪聲分布服從正態分布,要消除這樣分布的噪聲那么處理的方法也需要有正態分布的思想,即對於圖像而言,着重於處理圖像中心,其次再稍微處理邊緣,因為正態分布的特點是中間部分多,外側比較少。所以卷積核的設計思路是中間點的權值最大,越靠近中間點的權值越大。
公式①:
是一個常數,由於我們最終需要對高斯模板歸一化,而常數不影響數值比例,所以可以忽略掉。我們實際要計算的部分是:
高斯濾波的步驟:
假定中心點的坐標是(0,0),那么距離它最近的8個點的坐標如下:
y軸水平向上,x軸水平向右。
根據二維高斯函數:,設定 的值,假設其=1.5可得權重矩陣:
歸一化:
假設有九個點,灰度值如下圖:
每個點乘以權重后的結果:
可得:
這九個點的累加就是中心點的高斯模糊值。
二、算法步驟
(1)建立坐標系關系
(2)根據高斯函數計算出坐標矩陣的值
(3)對矩陣的值歸一化
(4)卷積求和獲得輸出圖像的灰度值
(5)將結果賦值到輸出圖像
(6)顯示圖像
三、偽代碼
輸入:卷積核大小wsize,高斯函數的sigma
輸出:高斯模板Mask
void generateGaussMask(cv::Mat& Mask, cv::Size wsize, double sigma)
{
for(循環處理點,生成各個坐標點){
根據高斯函數算出坐標點對應的值
對上一步的值歸一化
生成高斯模板Mask
}
}
輸入:原圖src,高斯模板Mask
輸出:結果圖dst
void GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat Mask)
{
for(循環處理原圖src像素點){
if(圖片為單通道){
根據高斯模板Mask卷積求核獲得輸出圖像的灰度值
將灰度值賦值到輸出圖像中
}
if(圖片為多通道){
根據通道數,用高斯模板Mask卷積求核獲得輸出圖像的各個通道的值
將各個通道值賦值到輸出圖像中
}
}
}
四、源碼:
// 按二維高斯函數實現高斯濾波
void GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat kernel) {
int hh = (kernel.rows - 1) / 2;
int hw = (kernel.cols - 1) / 2;
dst = cv::Mat::zeros(src.size(), src.type());
//邊界填充
cv::Mat Newsrc;
cv::copyMakeBorder(src, Newsrc,hh, hh, hw, hw, cv::BORDER_REPLICATE);//邊界復制
//高斯濾波
for (int i = hh; i < src.rows + hh; ++i) {
for (int j = hw; j < src.cols + hw; ++j) {
double sum[3] = { 0 };
for (int r = -hh; r <= hh; ++r) {
for (int c = -hw; c <= hw; ++c) {
if (src.channels() == 1) {
sum[0] = sum[0] + Newsrc.at<uchar>(i + r, j + c) * kernel.at<double>(r + hh, c + hw);
}
else if (src.channels() == 3) {
cv::Vec3b rgb = Newsrc.at<cv::Vec3b>(i + r, j + c);
sum[0] = sum[0] + rgb[0] * kernel.at<double>(r + hh, c + hw);//B
sum[1] = sum[1] + rgb[1] * kernel.at<double>(r + hh, c + hw);//G
sum[2] = sum[2] + rgb[2] * kernel.at<double>(r + hh, c + hw);//R
}
}
}
for (int k = 0; k < src.channels(); ++k) {
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (src.channels() == 1)
{
dst.at<uchar>(i - hh, j - hw) = static_cast<uchar>(sum[0]);
}
else if (src.channels() == 3)
{
cv::Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
dst.at<cv::Vec3b>(i - hh, j - hw) = rgb;
}
}
}
}
// x,y方向聯合實現獲取高斯模板
void generateGaussMask(cv::Mat& Mask, cv::Size wsize, double sigma) {
Mask.create(wsize, CV_64F);
int h = wsize.height;
int w = wsize.width;
int center_h = (h - 1) / 2;
int center_w = (w - 1) / 2;
double sum = 0.0;
double x, y;
for (int i = 0; i < h; ++i) {
y = pow(i - center_h, 2);
for (int j = 0; j < w; ++j) {
x = pow(j - center_w, 2);
//因為最后都要歸一化的,常數部分可以不計算,也減少了運算量
double g = exp(-(x + y) / (2 * sigma*sigma));
Mask.at<double>(i, j) = g;
sum += g;
}
}
Mask = Mask / sum;
}
六、結果圖
高斯模板:
原圖、Opencv高斯函數處理結果、自定義高斯函數處理結果、原圖+噪聲、做差求算法區別: