文章目录

  • 声明
  • 概念
  • 高斯滤波性质
  • 高斯模糊原理
    • 高斯函数
    • 高斯核(高斯模板)
    • 高斯滤波计算
    • 边界处理
    • 优化:高斯函数分离特性
  • 代码实现
  • 参考资料

声明

本文整合了网上内容,引用出处见文末参考链接,如有侵权请联系我删除。


概念

高斯滤波(Gaussian filter) 包含许多种,包括低通、带通和高通等,我们通常图像上说的高斯滤波,指的是 高斯模糊(Gaussian Blur) ,是一种 高斯低通滤波 ,其过滤调图像高频成分(图像细节部分),保留图像低频成分(图像平滑区域),所以对图像进行 ‘高斯模糊’ 后,图像会变得模糊。

高斯模糊对于抑制 高斯噪声 (服从正态分布的噪声) 非常有效。

高斯滤波性质

高斯函数具有五个重要的性质,这些性质使得它在早期图像处理中特别有用.这些性质表明,高斯平滑滤波器无论在空间域还是在频率域都是十分有效的低通滤波器,且在实际图像处理中得到了工程人员的有效使用.高斯函数具有五个十分重要的性质,它们是:

  1. 二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向.

  2. 高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.

  3. 高斯函数的傅立叶变换频谱是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频信号所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号.

  4. 高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.

  5. 由于高斯函数的可分离性,较大尺寸的高斯滤波器可以得以有效地实现.二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长.

高斯模糊原理

要模糊一张图像,可以这么做:对于每个像素点,以它为中心,取其3x3区域内所有像素灰度值的平均作为中心点的灰度值。可是,如果仅使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。

因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。而正态分布显然是一种可取的权重分配模式。由于图像是二维的,所以需要使用二维的高斯函数。

高斯模糊本质上就是利用 高斯函数 生成的 高斯核(高斯模板) 对图像进行卷积操作。

高斯函数

在计算每个像素时,都把当前中心点看作坐标原点,可以使得均值 μ = 0 \mu=0 μ=0 ,简化高斯函数的公式:

高斯核(高斯模板)

理论上,高斯分布在所有定义域上都有非负值,这就需要一个无限大的卷积核。实际上,仅需要取均值周围3倍标准差(即3 δ \delta δ)内的值,以外部份直接去掉即可。
高斯滤波的重要两步就是先找到高斯模板然后再进行卷积,模板(mask在查阅中有的地方也称作掩膜或者是高斯核)。所以这个时候需要知道它怎么来?又怎么用?
举个栗子:
假定中心点的坐标是(0,0),那么取距离它最近的8个点坐标,为了计算,需要设定σ的值。假定σ=1.5,则模糊半径为1的高斯模板就算如下

这个时候我们我们还要确保这九个点加起来为1(即归一化,这个是高斯模板的特性),否则的话,使用总值大于1的模板会让图像偏亮,小于1的模板会让图像偏暗。这9个点的权重总和等于0.4787147,因此上面9个值还要分别除以0.4787147,得到最终的高斯模板:

高斯滤波计算

有了高斯模板,就可以利用高斯模板对图像进行卷积了。对图像进行卷积的原理,其实就是将模板作为权值,与对应像素相乘再求和,得到的结果就是中心点卷积后的结果,本质上就是个加权平均操作。

举个栗子:
假设现有9个像素点,灰度值(0-255)的高斯滤波计算如下:

将这9个值加起来,就是中心点25进行高斯滤波后的值。对所有点重复这个过程,就得到了高斯模糊后的图像。

边界处理

高斯模板在对图像边缘像素进行卷积时,会有一部分权重没有对应像素,因此我们需要在图像的边缘补 0 0 0。这种方法称作Zero Padding。并且权值 g g g(卷积核)要进行归一化操作( ∑ g = 1 \sum\ g = 1 ∑ g=1)。

实际上代码里我没进行归一化,所以滤波后图像边缘像素比较暗。

优化:高斯函数分离特性

直接进行二维高斯模糊效率较低,实际上高斯模糊也可以在二维图像上对两个独立的一维空间分别进行计算,这叫作线性可分:

上式说明,可以先对图像进行y(或x)轴方向的一维高斯模糊,再在得到的结果上进行x(或y)轴方向的一维高斯模糊,其结果与直接对图像进行二维高斯模糊效果相同。

将二维高斯模糊分离为两个一维高斯模糊后,时间复杂度从 O ( w ∗ h ∗ c ∗ r ∗ r ) O(w*h*c*r*r) O(w∗h∗c∗r∗r)降到 O ( 2 ∗ w ∗ h ∗ c ∗ r ) O(2*w*h*c*r) O(2∗w∗h∗c∗r)(详情见代码实现),这里w和h表示图像宽高,c表示图像通道数,一般彩色图是3通道,r表示高斯模板的宽高,一般为奇数,例如上图的高斯核为5x5大小,r=5。下面是优化前后时间对比参考(来源网上):

代码实现

完整可执行工程在这里。

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>using namespace std;
using namespace cv;// 方法一:将二维高斯滤波
cv::Mat gaussian_filter(cv::Mat img, double sigma, int kernel_size){int height = img.rows;int width = img.cols;int channel = img.channels();// prepare outputcv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);// prepare kernelint pad = floor(kernel_size / 2); // 用于坐标系转换int _x = 0, _y = 0;double kernel_sum = 0;// get gaussian kernelfloat kernel[kernel_size][kernel_size];for (int y = 0; y < kernel_size; y++){for (int x = 0; x < kernel_size; x++){_y = y - pad;_x = x - pad; kernel[y][x] = 1 / (2 * M_PI * sigma * sigma) * exp( - (_x * _x + _y * _y) / (2 * sigma * sigma));kernel_sum += kernel[y][x];}}// 归一化到1for (int y = 0; y < kernel_size; y++){for (int x = 0; x < kernel_size; x++){kernel[y][x] /= kernel_sum;}}// filteringfor (int y = 0; y < height; y++){for (int x = 0; x < width; x++){for (int c = 0; c < channel; c++){double v = 0;for (int dy = -pad; dy < pad + 1; dy++){for (int dx = -pad; dx < pad + 1; dx++){int xx = x + dx;int yy = y + dy;// 超过边缘的就不处理了if ( 0 <= xx && xx < width && 0 <= yy && yy < height){v += (double)img.ptr<Vec3b>(yy)[xx][c] * kernel[dy + pad][dx + pad];}}}out.ptr<Vec3b>(y)[x][c] = v;}}}return out;
}// 方法二:优化。将二维高斯滤波分离为两个一维高斯滤波,可以加速
cv::Mat gaussian_filter_1D(cv::Mat img, double sigma, int kernel_size){int height = img.rows;int width = img.cols;int channel = img.channels();// prepare outputcv::Mat out_y = cv::Mat::zeros(height, width, CV_8UC3);// y轴卷积后的结果cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);// prepare kernelint pad = floor(kernel_size / 2); // 用于坐标系转换int _x = 0, _y = 0;// get gaussian kernelfloat kernel_x[kernel_size];float kernel_y[kernel_size];double kernel_sum = 0;for (int x = 0; x < kernel_size; x++){_x = x - pad; kernel_x[x] = 1 / sqrt(2 * M_PI * sigma * sigma) * exp( - (_x * _x) / (2 * sigma * sigma));kernel_sum += kernel_x[x];}// 归一化到1for (int x = 0; x < kernel_size; x++){kernel_x[x] /= kernel_sum;}kernel_sum = 0;for (int y = 0; y < kernel_size; y++){_y = y - pad;kernel_y[y] = 1 / sqrt(2 * M_PI * sigma * sigma) * exp( - (_y * _y) / (2 * sigma * sigma));kernel_sum += kernel_y[y];}// 归一化到1for (int y = 0; y < kernel_size; y++){kernel_y[y] /= kernel_sum;}// filtering_yfor (int y = 0; y < height; y++){for (int x = 0; x < width; x++){for (int c = 0; c < channel; c++){double v = 0;for (int dy = -pad; dy < pad + 1; dy++){int yy = y + dy;// 超过边缘的就不处理了if (0 <= yy && yy < height){v += (double)img.ptr<Vec3b>(y + dy)[x][c] * kernel_y[dy + pad];}}out_y.ptr<Vec3b>(y)[x][c] = v;}}}// filtering_x// 注意,这里取的是上次的结果来卷积,而不是imgfor (int y = 0; y < height; y++){for (int x = 0; x < width; x++){for (int c = 0; c < channel; c++){double v = 0;for (int dx = -pad; dx < pad + 1; dx++){int xx = x + dx;// 超过边缘的就不处理了if (0 <= xx && xx < width ){v += (double)out_y.ptr<Vec3b>(y)[xx][c] * kernel_x[dx + pad];}}out.ptr<Vec3b>(y)[x][c] = v;}}}return out;
}int main(int argc, const char* argv[]){// read imagecv::Mat img = cv::imread("../imori_noise.jpg", cv::IMREAD_COLOR);cv::imshow("raw", img);clock_t start = clock();// gaussian filter// cv::Mat out = gaussian_filter(img, 1.3, 3); // 5400 uscv::Mat out = gaussian_filter_1D(img, 1.3, 3); // 3600 usclock_t end = clock();printf("time: %d us\n", (end-start)); // us //(CLOCKS_PER_SEC/1000)//cv::imwrite("out.jpg", out);cv::namedWindow("answer", cv::WINDOW_NORMAL);cv::imshow("answer", out);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参考资料

  • 简单易懂的高斯滤波
  • 高斯滤波
  • 图像滤波之高斯滤波介绍
  • SIFT算法详解 | 前面的高斯模糊部分
  • 图像处理一百问/问题九 高斯滤波
  • 快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)

【图像处理】之高斯滤波:原理、代码实现和优化加速相关推荐

  1. java 中值滤波_matlab图像处理-中值滤波原理(示例代码)

    中值滤波原理 ??中值滤波本质上是一种统计排序滤波器.对于原图像中某点(i,j),中值滤波以该点为中心的邻域内的所有像素的统计排序中值作为(i,j)点的响应. ??中值不同于均值,是指排序队列中位于中 ...

  2. 图像处理:高斯滤波算法

    目录 前言 概念介绍 基本原理 卷积核的大小 卷积核的形状和权重比 卷积核的归一化 结论 Opencv实现高斯滤波 Python手写实现高斯滤波 参考文章 前言 在此之前,我曾在此篇中推导过图像处理: ...

  3. matlab图像处理-中值滤波原理

    中值滤波原理   中值滤波本质上是一种统计排序滤波器.对于原图像中某点(i,j),中值滤波以该点为中心的邻域内的所有像素的统计排序中值作为(i,j)点的响应.   中值不同于均值,是指排序队列中位于中 ...

  4. 数字图像处理之高斯滤波加速优化

    在上一篇文章中,我们讲了高斯滤波以及分离高斯滤波的原理与C++实现.本文将在此基础上,分别详细讲解使用SSE指令和CUDA来对分离高斯滤波算法的优化加速. 一.SSE指令优化 我们知道,SSE指令优化 ...

  5. 高斯模糊(高斯滤波)原理以及计算过程

    高斯模糊/高斯滤波 通常,图像处理软件会提供模糊滤镜,使图片产生模糊效果. 模糊的算法有很多,其中有一种叫高斯模糊(Gaussian Blur),它将正态分布用于图像处理. 文本介绍了高斯模糊的算法, ...

  6. python高斯滤波和降噪_高斯滤波原理及python实现

    高斯滤波器时一种线性平滑滤波器,主要适用处理高斯噪声,所以在了解高斯滤波之前,我们首先熟悉一下高斯噪声.噪声在图像中表现的通常是引起视觉效果的孤立像素点和像素块,简单说噪声点就是会给图像带来干扰,让图 ...

  7. matlab 均值滤波_数字图像处理基础 — 高斯滤波

    高斯滤波,本文主要讲其如何通过C语言实现.不太擅长写理论性质的文章,这里仅仅阐述自己怎么实现以及简单的优化过程. 通常我们对获取的图像进行进一步处理时,往往需要先进行一次降噪,而通常我们选择的是高斯滤 ...

  8. 带噪图像的高斯滤波MATLAB,图像处理___高斯滤波与高斯噪声

    噪声 1.噪声表现形式 噪声在图像上常表现为一引起较强视觉效果的孤立像素点或像素块.一般,噪声信号与要研究的对象不相关,它以无用的信息形式出现,扰乱图像的可观测信息.通俗的说就是噪声让图像不清楚. 2 ...

  9. 数字图像处理-频率域滤波原理

    from:https://blog.csdn.net/forrest02/article/details/55510711?locationNum=15&fps=1 写在前面的话 作者是一名在 ...

最新文章

  1. MongoDB修改删除数据
  2. layer的一种用法,自己画出弹出框样式
  3. Ubuntu 10.10从零开始建立android 2.2 froyo开发环境
  4. 十九、前端必学Bootstrap美化(下篇)
  5. ETL学习之四:SQL Server Integration Services入门
  6. Android之jni编译出现error: jump to label ‘XXXX’ [-fpermissive]解决办法
  7. cli3解决 ie11语法错误 vue_基于 Vue + Koa2 + MongoDB + Redis 实现一个完整的登录注册...
  8. ffmpeg 解码音频(aac、mp3)输出pcm文件
  9. php 动态加载html内容_ThinkPHP5.1+Swoole实现的开源内容管理框架
  10. 日语学习-多邻国-关卡1-时间2
  11. Spcok简约图片分享网站Typecho主题
  12. ionic滚动条返回顶部
  13. [置顶] 从工作流引擎设计来看人精神活动的一些问题
  14. Tomcat 加载外部dll时如何配置
  15. 脑电时频分析-短时傅里叶变换
  16. 用741运算放大器搭建RC正弦振荡器:文氏电桥振荡电路
  17. 完美解决电脑老是弹出广告窗口!
  18. Android Studio Keymap
  19. 获取百度关键词联想API
  20. php网络编程socket通讯

热门文章

  1. ZOJ3775 ?(_o)!
  2. 物理材质(Physics Materials)
  3. sql注入之堆叠注入
  4. springboot + vue + elementUI项目实战——简洁清新的员工管理系统(一)
  5. 又开始的python-day06-20200723-闭包-装饰器-模块-os-sys-math-random-datetime-time-calendar-hashlib-hmac
  6. java-net-php-python-55jspm启航游泳馆会员管理系统计算机毕业设计程序
  7. ios模拟器各种路径
  8. 至联云讲解《从2G到5G,IPFS的绝佳入场时机》
  9. 958-缺失的第一个整数
  10. 记录 - 收货地址的坑