作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

场景需求

做图像处理,滤波是家常便饭,今天给大家分享高斯滤波器实现。

众所周知,在频谱中,低频主要对应图像在平滑区域的总体灰度级分布,高频对应图像细节部分,如边缘和噪声。高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。公式和具体原理就不再罗列了,百度一下全都有,接下来是硬货——C++&OpenCV代码实现。

相关功能函数的C++实现代码

// 高斯低通滤波核函数
cv::Mat gaussian_low_pass_kernel(cv::Mat scr, float sigma)
{cv::Mat gaussianBlur(scr.size(), CV_32FC1); //,CV_32FC1float d0 = sigma;//高斯函数参数,越小,频率高斯滤波器越窄,滤除高频成分越多,图像就越平滑for (int i = 0; i < scr.rows; i++) {for (int j = 0; j < scr.cols; j++) {float d = pow(float(i - scr.rows / 2), 2) + pow(float(j - scr.cols / 2), 2);//分子,计算pow必须为float型gaussianBlur.at<float>(i, j) = expf(-d / (2 * d0*d0));//expf为以e为底求幂(必须为float型)}}return gaussianBlur;
}
// 高斯低通滤波
cv::Mat gaussian_low_pass_filter(cv::Mat &src, float d0)
{cv::Mat padded = image_make_border(src);cv::Mat gaussian_kernel = gaussian_low_pass_kernel(padded, d0);cv::Mat result = frequency_filter(padded, gaussian_kernel);return result;
}
// 高斯高通滤波核函数
cv::Mat gaussian_high_pass_kernel(cv::Mat scr, float sigma)
{cv::Mat gaussianBlur(scr.size(), CV_32FC1); //,CV_32FC1float d0 = sigma;for (int i = 0; i < scr.rows; i++) {for (int j = 0; j < scr.cols; j++) {float d = pow(float(i - scr.rows / 2), 2) + pow(float(j - scr.cols / 2), 2);//分子,计算pow必须为float型gaussianBlur.at<float>(i, j) = 1 - expf(-d / (2 * d0*d0));;}}return gaussianBlur;
}
// 高斯高通滤波
cv::Mat gaussian_high_pass_filter(cv::Mat &src, float d0)
{cv::Mat padded = image_make_border(src);cv::Mat gaussian_kernel = gaussian_high_pass_kernel(padded, d0);//理想低通滤波器cv::Mat result = frequency_filter(padded, gaussian_kernel);return result;
}
// 频率域滤波
cv::Mat frequency_filter(cv::Mat &scr, cv::Mat &blur)
{cv::Mat mask = scr == scr;scr.setTo(0.0f, ~mask);//创建通道,存储dft后的实部与虚部(CV_32F,必须为单通道数)cv::Mat plane[] = { scr.clone(), cv::Mat::zeros(scr.size() , CV_32FC1) };cv::Mat complexIm;cv::merge(plane, 2, complexIm); // 合并通道 (把两个矩阵合并为一个2通道的Mat类容器)cv::dft(complexIm, complexIm); // 进行傅立叶变换,结果保存在自身// 分离通道(数组分离)cv::split(complexIm, plane);// 以下的操作是频域迁移fftshift(plane[0], plane[1]);// *****************滤波器函数与DFT结果的乘积****************cv::Mat blur_r, blur_i, BLUR;cv::multiply(plane[0], blur, blur_r);  // 滤波(实部与滤波器模板对应元素相乘)cv::multiply(plane[1], blur, blur_i);  // 滤波(虚部与滤波器模板对应元素相乘)cv::Mat plane1[] = { blur_r, blur_i };// 再次搬移回来进行逆变换fftshift(plane1[0], plane1[1]);cv::merge(plane1, 2, BLUR); // 实部与虚部合并cv::idft(BLUR, BLUR);       // idft结果也为复数BLUR = BLUR / BLUR.rows / BLUR.cols;cv::split(BLUR, plane);//分离通道,主要获取通道return plane[0];
}
// 图像边界处理
cv::Mat image_make_border(cv::Mat &src)
{int w = cv::getOptimalDFTSize(src.cols); // 获取DFT变换的最佳宽度int h = cv::getOptimalDFTSize(src.rows); // 获取DFT变换的最佳高度cv::Mat padded;// 常量法扩充图像边界,常量 = 0cv::copyMakeBorder(src, padded, 0, h - src.rows, 0, w - src.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0));padded.convertTo(padded, CV_32FC1);return padded;
}
// fft变换后进行频谱搬移
void fftshift(cv::Mat &plane0, cv::Mat &plane1)
{// 以下的操作是移动图像  (零频移到中心)int cx = plane0.cols / 2;int cy = plane0.rows / 2;cv::Mat part1_r(plane0, cv::Rect(0, 0, cx, cy));  // 元素坐标表示为(cx, cy)cv::Mat part2_r(plane0, cv::Rect(cx, 0, cx, cy));cv::Mat part3_r(plane0, cv::Rect(0, cy, cx, cy));cv::Mat part4_r(plane0, cv::Rect(cx, cy, cx, cy));cv::Mat temp;part1_r.copyTo(temp);  //左上与右下交换位置(实部)part4_r.copyTo(part1_r);temp.copyTo(part4_r);part2_r.copyTo(temp);  //右上与左下交换位置(实部)part3_r.copyTo(part2_r);temp.copyTo(part3_r);cv::Mat part1_i(plane1, cv::Rect(0, 0, cx, cy));  //元素坐标(cx,cy)cv::Mat part2_i(plane1, cv::Rect(cx, 0, cx, cy));cv::Mat part3_i(plane1, cv::Rect(0, cy, cx, cy));cv::Mat part4_i(plane1, cv::Rect(cx, cy, cx, cy));part1_i.copyTo(temp);  //左上与右下交换位置(虚部)part4_i.copyTo(part1_i);temp.copyTo(part4_i);part2_i.copyTo(temp);  //右上与左下交换位置(虚部)part3_i.copyTo(part2_i);temp.copyTo(part3_i);
}

测试代码

#include<iostream>
#include<opencv2/opencv.hpp>
#include<ctime>
using namespace std;
using namespace cv;cv::Mat gaussian_low_pass_kernel(cv::Mat scr, float sigma);
cv::Mat gaussian_low_pass_filter(cv::Mat &src, float d0);
cv::Mat gaussian_high_pass_kernel(cv::Mat scr, float sigma);
cv::Mat gaussian_high_pass_filter(cv::Mat &src, float d0);
cv::Mat frequency_filter(cv::Mat &scr, cv::Mat &blur);
cv::Mat image_make_border(cv::Mat &src);
void fftshift(cv::Mat &plane0, cv::Mat &plane1);int main(void)
{Mat test = imread("tangsan.jpg", 0);float D0 = 50.0f;float D1 = 5.0f;Mat lowpass = gaussian_low_pass_filter(test, D0);Mat highpass = gaussian_high_pass_filter(test, D1);imshow("original", test);imshow("low pass", lowpass / 255);     // lowpass的数据有正有负,又因为数据的模值大于1,imshow显示出来就是大于1的就是白,小于0的都是黑imshow("high pass", highpass / 255);   // highpass的数据都比较大,0-255,imshow对于float型Mat显示需要除以255waitKey(0);system("pause");return 0;
}// 高斯低通滤波核函数
cv::Mat gaussian_low_pass_kernel(cv::Mat scr, float sigma)
{cv::Mat gaussianBlur(scr.size(), CV_32FC1); //,CV_32FC1float d0 = sigma;//高斯函数参数,越小,频率高斯滤波器越窄,滤除高频成分越多,图像就越平滑for (int i = 0; i < scr.rows; i++) {for (int j = 0; j < scr.cols; j++) {float d = pow(float(i - scr.rows / 2), 2) + pow(float(j - scr.cols / 2), 2);//分子,计算pow必须为float型gaussianBlur.at<float>(i, j) = expf(-d / (2 * d0*d0));//expf为以e为底求幂(必须为float型)}}return gaussianBlur;
}
// 高斯低通滤波
cv::Mat gaussian_low_pass_filter(cv::Mat &src, float d0)
{cv::Mat padded = image_make_border(src);cv::Mat gaussian_kernel = gaussian_low_pass_kernel(padded, d0);cv::Mat result = frequency_filter(padded, gaussian_kernel);return result;
}
// 高斯高通滤波核函数
cv::Mat gaussian_high_pass_kernel(cv::Mat scr, float sigma)
{cv::Mat gaussianBlur(scr.size(), CV_32FC1); //,CV_32FC1float d0 = sigma;for (int i = 0; i < scr.rows; i++) {for (int j = 0; j < scr.cols; j++) {float d = pow(float(i - scr.rows / 2), 2) + pow(float(j - scr.cols / 2), 2);//分子,计算pow必须为float型gaussianBlur.at<float>(i, j) = 1 - expf(-d / (2 * d0*d0));;}}return gaussianBlur;
}
// 高斯高通滤波
cv::Mat gaussian_high_pass_filter(cv::Mat &src, float d0)
{cv::Mat padded = image_make_border(src);cv::Mat gaussian_kernel = gaussian_high_pass_kernel(padded, d0);//理想低通滤波器cv::Mat result = frequency_filter(padded, gaussian_kernel);return result;
}
// 频率域滤波
cv::Mat frequency_filter(cv::Mat &scr, cv::Mat &blur)
{cv::Mat mask = scr == scr;scr.setTo(0.0f, ~mask);//创建通道,存储dft后的实部与虚部(CV_32F,必须为单通道数)cv::Mat plane[] = { scr.clone(), cv::Mat::zeros(scr.size() , CV_32FC1) };cv::Mat complexIm;cv::merge(plane, 2, complexIm); // 合并通道 (把两个矩阵合并为一个2通道的Mat类容器)cv::dft(complexIm, complexIm); // 进行傅立叶变换,结果保存在自身// 分离通道(数组分离)cv::split(complexIm, plane);// 以下的操作是频域迁移fftshift(plane[0], plane[1]);// *****************滤波器函数与DFT结果的乘积****************cv::Mat blur_r, blur_i, BLUR;cv::multiply(plane[0], blur, blur_r);  // 滤波(实部与滤波器模板对应元素相乘)cv::multiply(plane[1], blur, blur_i);  // 滤波(虚部与滤波器模板对应元素相乘)cv::Mat plane1[] = { blur_r, blur_i };// 再次搬移回来进行逆变换fftshift(plane1[0], plane1[1]);cv::merge(plane1, 2, BLUR); // 实部与虚部合并cv::idft(BLUR, BLUR);       // idft结果也为复数BLUR = BLUR / BLUR.rows / BLUR.cols;cv::split(BLUR, plane);//分离通道,主要获取通道return plane[0];
}
// 图像边界处理
cv::Mat image_make_border(cv::Mat &src)
{int w = cv::getOptimalDFTSize(src.cols); // 获取DFT变换的最佳宽度int h = cv::getOptimalDFTSize(src.rows); // 获取DFT变换的最佳高度cv::Mat padded;// 常量法扩充图像边界,常量 = 0cv::copyMakeBorder(src, padded, 0, h - src.rows, 0, w - src.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0));padded.convertTo(padded, CV_32FC1);return padded;
}
// fft变换后进行频谱搬移
void fftshift(cv::Mat &plane0, cv::Mat &plane1)
{// 以下的操作是移动图像  (零频移到中心)int cx = plane0.cols / 2;int cy = plane0.rows / 2;cv::Mat part1_r(plane0, cv::Rect(0, 0, cx, cy));  // 元素坐标表示为(cx, cy)cv::Mat part2_r(plane0, cv::Rect(cx, 0, cx, cy));cv::Mat part3_r(plane0, cv::Rect(0, cy, cx, cy));cv::Mat part4_r(plane0, cv::Rect(cx, cy, cx, cy));cv::Mat temp;part1_r.copyTo(temp);  //左上与右下交换位置(实部)part4_r.copyTo(part1_r);temp.copyTo(part4_r);part2_r.copyTo(temp);  //右上与左下交换位置(实部)part3_r.copyTo(part2_r);temp.copyTo(part3_r);cv::Mat part1_i(plane1, cv::Rect(0, 0, cx, cy));  //元素坐标(cx,cy)cv::Mat part2_i(plane1, cv::Rect(cx, 0, cx, cy));cv::Mat part3_i(plane1, cv::Rect(0, cy, cx, cy));cv::Mat part4_i(plane1, cv::Rect(cx, cy, cx, cy));part1_i.copyTo(temp);  //左上与右下交换位置(虚部)part4_i.copyTo(part1_i);temp.copyTo(part4_i);part2_i.copyTo(temp);  //右上与左下交换位置(虚部)part3_i.copyTo(part2_i);temp.copyTo(part3_i);
}

测试效果

图1 低通高通效果图

不同的滤波参数导致的滤波器尺寸大小不一,得到的结果也就不一样~

另外,如果我的代码有什么问题,欢迎大家提出异议批评指正,一同进步~

如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

OpenCV-高斯低通高通滤波器(C++)相关推荐

  1. python高通滤波器设计_python实现直方图均衡化,理想高通滤波与高斯低通滤波

    写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验二,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验二. 由于时间紧张,代码没有进行任何优化, ...

  2. OpenCV实现频率域滤波——以高斯低通滤波去噪为例

    最近由于作业原因,试着用OpenCV实现频率域滤波,但是OpenCV中并没有像MATLAB中fftshift这样的中心化操作,所以我写了一个频率域滤波的函数,以后用频率域滤波的时候在主函数中调用即可. ...

  3. Opencv学习笔记 各向异性滤波/均值滤波/高斯滤波/中值滤波/加权中值滤波/高斯低通滤波

    各向异性滤波         各向异性扩散滤波主要是用来平滑图像的,克服了高斯模糊的缺陷,各向异性扩散在平滑图像时是保留图像边缘的,和双边滤波很像. public static void ImageA ...

  4. 图像降噪算法——高斯低通滤波

    图像降噪算法--高斯低通滤波 图像降噪算法--高斯低通滤波 1. 基本原理 2. C++代码实现 3. 结论 图像降噪算法--高斯低通滤波 1. 基本原理 通过离散傅里叶变换对图像进行滤波流程作非常简 ...

  5. 读入一幅图像,对图像分别进行高斯低通、巴特沃兹低通、高斯高通和巴特沃兹高通频域滤波,比较其锐化和平滑效果。

    ↵ 1.高斯低通 二维高斯低通滤波器定义如下: D0为截止频率与原点的距离,D(u,v)是点(u,v)与原点的距离. 图像表示: 读入图片并得到频谱图,后续搭建高斯低通滤波器如下. [m,n]=siz ...

  6. MATLAB图像处理--高斯低通滤波、高斯高通滤波(代码及示例)

    本文目录 常用的滤波器 高斯低通滤波器 matlab代码 高斯高通滤波器 Butterworth 低通滤波器 常用的滤波器 常用的滤波器有以下几种: 频域滤波器 频域平滑滤波器 理想低通滤波器 巴特沃 ...

  7. python高通滤波_python实现直方图均衡化,理想高通滤波与高斯低通滤波

    写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验二,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验二. 由于时间紧张,代码没有进行任何优化, ...

  8. 数字图像处理——高斯低通、高通滤波算法

    通过代码来分析如何对图像进行高斯滤波 先放镇楼图: 1. 读取图像,转灰度图像 I = imread('lena.bmp'); %读取原图像 I = rgb2gray(I); %原图像转灰度图像 i_ ...

  9. 数字图像处理 空间域高斯低通滤波 MATLAB实验

    一.原理_空间域高斯低通滤波 高斯低通滤波是一种使用的去噪滤波,可用于去除高斯噪声,且几乎没有振铃现象. 二.步骤 (1)读入原图像lena.bmp并显示: (2)对原图像分别添加高斯噪声,并显示加噪 ...

最新文章

  1. python3调用腾讯AI开放平台
  2. 福田车载无线充电器方案开发设计_过年自驾回家,带上优胜仕车载无线充电器,一放即充导航无忧...
  3. WebBrowser1.Navigate重复载入同一页面时载入的是旧页面
  4. apple tv 开发_如何防止Apple TV进入睡眠状态
  5. sql server2008中怎样用sql语句创建数据库和数据表
  6. Android之提示Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider
  7. 【数据结构与算法】广度优先遍历(BFS) 深度优先遍历(DFS)
  8. 搜索——滑雪(poj1088)
  9. 最全面的智能锁领域常见的无线传输协议类型
  10. 11 种方法教你用 Python 高效下载资源
  11. 数学方面的能力该怎么培养
  12. Atitit recv https req post code 接受https请求// npm install axios// 安装依赖:npm install body-parse
  13. 基于matlab测量物体直径,基于MATLAB的不规则面积图像测量
  14. 一种简单的图像白平衡计算方法
  15. Cosy V3.1.3 简洁大气WordPress博客主题自适应个人自媒体网站模板(含积木部分插件)
  16. Linux 怎么防止 ssh 被暴力破解
  17. 应用计算机测定电阻伏安特性,实验: 应用计算机测线性电阻伏安特性
  18. 关系运算符与逻辑运算符
  19. 45-js操作DOM和bom操作
  20. How to design an FPGA from scratch-1_FPGA_8_24

热门文章

  1. 大数据应用现状:从发现价值到创造价值
  2. web测试知识点整理
  3. Canvas实现简单刮刮乐效果
  4. Android studio设置代码自动提示
  5. Java MongoDB 资料集合
  6. Java 面向对象(基础) 知识点总结I
  7. Juniper 防火墙session拥堵案例解决
  8. python 声明不赋值_为什么Python赋值不返回值?
  9. 【毕业设计】基于PHP的网上书店的设计(论文)
  10. 【毕业论文写作技巧】毕业设计(论文)写作框架