OpenCV-高斯低通高通滤波器(C++)
作者:翟天保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);
}
测试效果
不同的滤波参数导致的滤波器尺寸大小不一,得到的结果也就不一样~
另外,如果我的代码有什么问题,欢迎大家提出异议批评指正,一同进步~
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!
OpenCV-高斯低通高通滤波器(C++)相关推荐
- python高通滤波器设计_python实现直方图均衡化,理想高通滤波与高斯低通滤波
写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验二,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验二. 由于时间紧张,代码没有进行任何优化, ...
- OpenCV实现频率域滤波——以高斯低通滤波去噪为例
最近由于作业原因,试着用OpenCV实现频率域滤波,但是OpenCV中并没有像MATLAB中fftshift这样的中心化操作,所以我写了一个频率域滤波的函数,以后用频率域滤波的时候在主函数中调用即可. ...
- Opencv学习笔记 各向异性滤波/均值滤波/高斯滤波/中值滤波/加权中值滤波/高斯低通滤波
各向异性滤波 各向异性扩散滤波主要是用来平滑图像的,克服了高斯模糊的缺陷,各向异性扩散在平滑图像时是保留图像边缘的,和双边滤波很像. public static void ImageA ...
- 图像降噪算法——高斯低通滤波
图像降噪算法--高斯低通滤波 图像降噪算法--高斯低通滤波 1. 基本原理 2. C++代码实现 3. 结论 图像降噪算法--高斯低通滤波 1. 基本原理 通过离散傅里叶变换对图像进行滤波流程作非常简 ...
- 读入一幅图像,对图像分别进行高斯低通、巴特沃兹低通、高斯高通和巴特沃兹高通频域滤波,比较其锐化和平滑效果。
↵ 1.高斯低通 二维高斯低通滤波器定义如下: D0为截止频率与原点的距离,D(u,v)是点(u,v)与原点的距离. 图像表示: 读入图片并得到频谱图,后续搭建高斯低通滤波器如下. [m,n]=siz ...
- MATLAB图像处理--高斯低通滤波、高斯高通滤波(代码及示例)
本文目录 常用的滤波器 高斯低通滤波器 matlab代码 高斯高通滤波器 Butterworth 低通滤波器 常用的滤波器 常用的滤波器有以下几种: 频域滤波器 频域平滑滤波器 理想低通滤波器 巴特沃 ...
- python高通滤波_python实现直方图均衡化,理想高通滤波与高斯低通滤波
写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验二,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验二. 由于时间紧张,代码没有进行任何优化, ...
- 数字图像处理——高斯低通、高通滤波算法
通过代码来分析如何对图像进行高斯滤波 先放镇楼图: 1. 读取图像,转灰度图像 I = imread('lena.bmp'); %读取原图像 I = rgb2gray(I); %原图像转灰度图像 i_ ...
- 数字图像处理 空间域高斯低通滤波 MATLAB实验
一.原理_空间域高斯低通滤波 高斯低通滤波是一种使用的去噪滤波,可用于去除高斯噪声,且几乎没有振铃现象. 二.步骤 (1)读入原图像lena.bmp并显示: (2)对原图像分别添加高斯噪声,并显示加噪 ...
最新文章
- python3调用腾讯AI开放平台
- 福田车载无线充电器方案开发设计_过年自驾回家,带上优胜仕车载无线充电器,一放即充导航无忧...
- WebBrowser1.Navigate重复载入同一页面时载入的是旧页面
- apple tv 开发_如何防止Apple TV进入睡眠状态
- sql server2008中怎样用sql语句创建数据库和数据表
- Android之提示Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider
- 【数据结构与算法】广度优先遍历(BFS) 深度优先遍历(DFS)
- 搜索——滑雪(poj1088)
- 最全面的智能锁领域常见的无线传输协议类型
- 11 种方法教你用 Python 高效下载资源
- 数学方面的能力该怎么培养
- Atitit recv https req post code 接受https请求// npm install axios// 安装依赖:npm install body-parse
- 基于matlab测量物体直径,基于MATLAB的不规则面积图像测量
- 一种简单的图像白平衡计算方法
- Cosy V3.1.3 简洁大气WordPress博客主题自适应个人自媒体网站模板(含积木部分插件)
- Linux 怎么防止 ssh 被暴力破解
- 应用计算机测定电阻伏安特性,实验: 应用计算机测线性电阻伏安特性
- 关系运算符与逻辑运算符
- 45-js操作DOM和bom操作
- How to design an FPGA from scratch-1_FPGA_8_24