高斯滤波
在进行图像分割之前通常会使用滤波器进行平滑操作,其目的是消除高斯噪声的影响。学习高斯噪声/高斯滤波的相关概念并实现高斯滤波器
高斯分布
一维高斯分布
二维高斯分布
每次计算均以当前像素点为中心,所以均值
标准差
1 | # -*- coding: utf-8 -*- |


高斯噪声
高斯噪声是指它的概率密度函数服从高斯分布(即正态分布)的一类噪声
数字图像中的高斯噪声的主要来源出现在采集期间,由于不良照明/高温引起的传感器噪声
高斯滤波
高斯滤波(gaussian filter)是一种线性平滑滤波,就是对整幅图像进行加权平均的过程,对每个像素点的值,结合邻域内其他像素值进行加权平均
具体操作如下:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域像素的加权平均灰度值去替代模板中心像素点的值
高斯滤波的优点在于消除高斯噪声,其副作用是消除图像细节,所以又称为高斯模糊(gaussian blur)
模板
有两个常用的高斯模板,分别是

滤波过程中的模板是通过高斯公式计算得到的,以
1 | [[2 1 2] |
假定
1 | [[0.11759572 0.23493154 0.11759572] |
进行归一化
1 | [[0.06256912 0.12499996 0.06256912] |
除以最小值
1 | [[1 2 1] |
1 | if __name__ == '__main__': |
彩色图像
高斯滤波默认对单个通道图像进行,所以对于彩色图像,需要先分离为3个单通道图像,分别进行滤波处理后再合并为3通道图像
opencv实现
opencv提供了高斯滤波以及高斯模板的实现
源码位于:path/to/modules/imgproc/src/smooth.cpp
getGaussianKernel
函数getGaussianKernel()计算并返回高斯滤波系数的
- 参数
应该是正奇数( 1/3/5/...),如果输入为0(即Size(0,0)),则根据sigma值进行计算 - 参数
是高斯标准差,如果输入不为正,根据 ksize计算,当 ksize=3, sigma=0.8,当ksize=5, sigma=1.1 - 参数
遍历 - 参数
是缩放因子,其目的是使矩阵归一化:
getGaussianKernel源码位于/path/to/modules/imgproc/src/smooth.cpp
当ksize=Size(0,0)时,计算如下:
1 | // automatic detection of kernel size from sigma |
- 当
sigma=1.0时,ksize.width = cvRound(7)|1 = 0111|1 = 0111 = 7 - 当
sigma=0.8时,ksize.width = cvRound(5.8)|1 = 6|1 = 0110|1 = 0111 = 7 - 当
sigma=0.5时,ksize.width = cvRound(4)|1 = 0100|1 = 0101 = 5
GaussianBlur
函数GaussianBlur()将源图像与高斯核进行卷积操作
使用
python语言
1 | import cv2 |
C++语言
1 | #include <iostream> |
自定义实现(c++)
创建类GaussianFilter,实现获取高斯滤波功能
- 使用
gaussFilter2d实现高斯分布计算(去掉weight计算,其在归一化过程中不需要) - 使用
Conv2d实现卷积核与图像计算 - 使用
getGaussianKernel计算高斯模板 - 使用
GaussianBlur进行高斯滤波
1 | // |
1 | // |
优化
二维高斯分布公式可由两个一维高斯分布公式组成:
利用二维高斯模板对图像进行滤波:
$$
f(x,y) = \frac {1}{\sum^{r}{u=-r}\sum^{r}{v=-r}G(u,v)}
\cdot \sum^{r}{u=-r}\sum^{r}{v=-r}G(u,v)\cdot I(x+u,y+v)
$$
其中
利用一维高斯分布公式进行优化如下:
$$
f(x,y) = \frac {1}{\sum^{r}{u=-r}\sum^{r}{v=-r}G(u,v)}
\cdot \sum^{r}{u=-r}\sum^{r}{v=-r}G(u,v)\cdot I(x+u,y+v)\
=\frac {1}{\sum^{r}{u=-r}\sum^{r}{v=-r}G(u)\cdot G(v)}
\cdot \sum^{r}{u=-r}\sum^{r}{v=-r}G(u)\cdot G(v)\cdot I(x+u,y+v)\
=\frac {1}{\sum^{r}{u=-r}G(u)\cdot \sum^{r}{v=-r} G(v)}
\cdot \sum^{r}{u=-r}G(u)\cdot \sum^{r}{v=-r} G(v)\cdot I(x+u,y+v)\
=\frac {1}{\sum^{r}{v=-r} G(v)}\cdot \sum^{r}{u=-r}G(u) [
\frac {1}{\sum^{r}{u=-r}G(u)}\cdot \sum^{r}{v=-r} G(v)\cdot I(x+u,y+v)]
$$
可以先在垂直方向对图像进行一维高斯变换,再在水平方向对图像进行一维高斯变换
按照原先的二维模板计算方式,对单个图像像素进行计算需要
如果转换成一维模板计算,先进行垂直方向计算,需要
单单对单个图像像素进行计算不太好理解,好像使用一维模板计算的只是沿该像素点水平和垂直的领域像素,没有涉及到对角领域像素;如果扩大到整副图像就好理解了
修改后的GaussianFilter实现如下:
getGaussianKernel生成一维高斯算子,参考OpenCV实现使用固定模板GaussianBlur先对水平方向进行高斯滤波,再对垂直方向进行高斯滤波
完整类定义如下:
1 | // |
1 | // |
测试代码如下:
1 | #include <sys/time.h> |
CMakeLists.txt内容如下:
1 | cmake_minimum_required(VERSION 3.13) |
测试结果如下(单位:ms):
| | OpenCV | 自定义 | 优化 |
|:—: |:——: |:——: |:—-: |
| 3x3 | 4 | 67 | 64 |
| 5x5 | 6 | 182 | 94 |
进一步优化方向是多线程、编译优化、模板查表等