下面是频域滤波示例程序:
在本程序中,共有五个自定义函数,分别是:
1. myMagnitude(),在该函数中封装了Opencv中的magnitude函数,实现对于复数图像的幅值计算。
2. dftshift(),该函数实现对图像四个象限的对角互换,相当于MatLab中 fftshift(),将频谱的原点(0,0)移到图像中心。示例1中采用了该函数实现了频谱图中心化。
3. srcCentralized()用于傅里叶变换前的预处理,以便得到傅里叶频谱的原点(0,0)位于图像的中心。
该函数与dftshift()目的一致,实现方法不同,一个是变换前预处理,一个是变换后处理。
示例2中采用了该函数实现了频谱图中心化。
4. displayDftSpectrum(),该函数用于显示复数图像。
5. makeFilter(),用于制作频域滤波器,该函数利用了ptr()
   指针遍历图像的方法,实现了圆等滤波函数。
下面是两个示例,分别采用了dftshift()、srcCentralized()实现频谱图的中心化。示例2与冈萨雷斯的《数字图像处理(第3版)》的4.6.7小结中的流程一致。
在主程序内容,参见注释。
示例1:在该程序中采用了第2个函数dftshift(),实现了频谱图中心化。

#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std; void myMagnitude(Mat & complexImg,Mat & mI)
{
Mat planes[];
split(complexImg,planes);
magnitude(planes[],planes[],mI);
}
void dftshift(Mat& ds)
{
int cx=ds.cols/;//图像的中心点x 坐标
int cy=ds.rows/;//图像的中心点y 坐标
Mat q0=ds(Rect(,,cx,cy));//左上
Mat q1=ds(Rect(cx,,cx,cy));//右上
Mat q2=ds(Rect(,cy,cx,cy));//左下
Mat q3=ds(Rect(cx,cy,cx,cy));//右下
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
void displayDftSpectrum(Mat&dftDst,String winName,bool inverseSpectrum)
{
Mat magI;
myMagnitude(dftDst,magI);
if(!inverseSpectrum)//如果是正向傅里叶变换谱
{
magI+=Scalar::all();
log(magI,magI);
}
normalize(magI,magI,,,NORM_MINMAX);
imshow(winName,magI);
}
void makeFilter(Mat&filter,int R,bool isLowPassFilter)
{
int cx=filter.cols/,cy=filter.rows/;
int R2=R*R; for(int i=;i<filter.rows;i++)
{
Vec2d* pf=filter.ptr<Vec2d>(i);
for(int j=;j<filter.cols;j++)
{
int r2=(j-cx)*(j-cx)+(i-cy)*(i-cy);
if(r2<R2)
{
pf[j][]=;
pf[j][]=pf[j][];
}
}
}
if(!isLowPassFilter)
{
filter =Scalar::all()-filter;
}
Mat displayFilter;
extractChannel(filter,displayFilter,);
imshow("filter image",displayFilter);
} int main()
{
///读入灰度图像
Mat src=imread("D:\\Qt\\MyImage\\baboon.jpg",);
int ny=src.rows,nx=src.cols;
cv::copyMakeBorder(src,src,,ny,,nx,BORDER_CONSTANT);
imshow("original image",src);
/***************傅里叶变换*************/
src.convertTo(src,CV_64FC1);//转成浮点数据类型
Mat dftDst(src.size(),CV_64FC2);//预设dft的输出结果矩阵
dft(src,dftDst,DFT_COMPLEX_OUTPUT,);//离散傅立叶变换
dftshift(dftDst);//将傅里叶变换的结果,四象限对角互换
displayDftSpectrum(dftDst,"dftSpectrum display",false);//显示傅里叶频谱图 /***************频域滤波*************/
Mat filter(src.size(),CV_64FC2,Scalar::all());
makeFilter(filter,,false);
Mat fftTemp=dftDst.mul(filter);//复数频谱图与滤波器相乘,实现频域滤波
Mat srcFiltered;
dft(fftTemp,srcFiltered,DFT_INVERSE);//逆傅里叶变换
//显示经过滤波后的图像
displayDftSpectrum(srcFiltered,"filtered image",true);//显示逆傅里叶频谱图
waitKey();
return ;
}

示例2:在该示例中采用了第3个函数srcCentralized(),实现频谱图中心化。程序流程即

在本教材的6.2.3频域滤波步骤小结中,或者在冈萨雷斯的《数字图像处理》4.6.7节中,频域滤波流程总结如下:

    1. 给定一幅大小为M×N的输入图像f(x,y),从式(6.1-25)和式(6.1-26)得到填充参数P和Q。典型地,我们选择P=2M和Q=2N;
    2. 对f(x,y)添加必要数量的0,形成大小为P×Q填充后的图像
    3. 用(-1)(x+y)乘以fp(x,y),进行频谱中心化的预处理;
    4. 计算中心化预处理过的fp(x,y)的傅里叶变换,得到Fp(u,v);
    5. 生成一个实的、对称的滤波函数H(u,v),其大小为P×Q,频谱零点位于(P/2,Q/2)处。用阵列相乘形成乘积G(u,v)=F(u,v)H(u,v);
    6. 经过频域滤波后的图像:
            gp(x,y)={real[fft-1[G(u,v)]]}(-1)(x+y)
      其中,为忽略由于计算不准确导致的寄生复分量,选择了实部,下标P指出我们处理的是填充后的阵列;
    7. 通过从 gp(x,y)的左上象限提取M×N区域,得到最终处理结果g(x,y)。
/*求取复数矩阵的幅值*/
void myMagnitude(Mat & complexImg,Mat & mI)
{
Mat planes[];
split(complexImg,planes);
magnitude(planes[],planes[],mI);
}
/*傅里叶变换后的频谱图后处理,将傅里叶普的原点(0,0)平移到图像的中心*/
void dftshift(Mat& ds)
{
int cx=ds.cols/;//图像的中心点x 坐标
int cy=ds.rows/;//图像的中心点y 坐标
Mat q0=ds(Rect(,,cx,cy));//左上
Mat q1=ds(Rect(cx,,cx,cy));//右上
Mat q2=ds(Rect(,cy,cx,cy));//左下
Mat q3=ds(Rect(cx,cy,cx,cy));//右下
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
/*傅里叶变换前的预处理,以便频谱图的原点(0,0)移动到图像的中心*/
void srcCentralized(Mat& src)
{
for(int i=;i<src.rows;i++)
{
for(int j=;j<src.cols;j++)
{
float* mv=CV_MAT_ELEM2(src,float,i,j);
if((i+j)%!=)
mv[]=-mv[];//如果i+j为奇数,该像素值取负值
}
}
}
/*在窗口中显示复数图像,如果是正向傅里叶矩阵,需要取log才能显示更多频谱信息
*如果是逆傅里叶变换,通过normalize归一化后,显示频谱图*/
void displayDftSpectrum(Mat&dftDst,String winName,bool inverseSpectrum)
{
Mat magI;
myMagnitude(dftDst,magI);
if(!inverseSpectrum)//如果是正向傅里叶变换谱
{
magI+=Scalar::all();
log(magI,magI);
}
normalize(magI,magI,,,NORM_MINMAX);
imshow(winName,magI);
}
void makeFilter(Mat&filter,int R,bool isLowPassFilter)
{
int cx=filter.cols/,cy=filter.rows/;
int R2=R*R; for(int i=;i<filter.rows;i++)
{
Vec2d* pf=filter.ptr<Vec2d>(i);
for(int j=;j<filter.cols;j++)
{
int r2=(j-cx)*(j-cx)+(i-cy)*(i-cy);
if(r2<R2)
{
pf[j][]=;
pf[j][]=pf[j][];
}
}
}
if(!isLowPassFilter)
{
filter =Scalar::all()-filter;
}
Mat displayFilter;
extractChannel(filter,displayFilter,);
imshow("filter image",displayFilter);
} int main()
{
///读入灰度图像
Mat src=imread("D:\\Qt\\MyImage\\interferometer2.jpg",);
int ny=src.rows,nx=src.cols;
imshow("original image",src);
src.convertTo(src,CV_32FC1);
srcCentralized(src);
cv::copyMakeBorder(src,src,,ny,,nx,BORDER_CONSTANT); /***************傅里叶变换*************/
src.convertTo(src,CV_64FC1);//转成浮点数据类型
Mat dftDst(src.size(),CV_64FC2);//预设dft的输出结果矩阵
dft(src,dftDst,DFT_COMPLEX_OUTPUT,);//离散傅立叶变换
// dftshift(dftDst);//将傅里叶变换的结果,四象限对角互换
displayDftSpectrum(dftDst,"dftSpectrum display",false);//显示傅里叶频谱图 /***************频域滤波*************/
Mat filter(src.size(),CV_64FC2,Scalar::all());
makeFilter(filter,,true);
Mat fftTemp=dftDst.mul(filter);//复数频谱图与滤波器相乘,实现频域滤波
srcCentralized(fftTemp); Mat srcFiltered;
dft(fftTemp,srcFiltered,DFT_INVERSE);//逆傅里叶变换
// 显示经过滤波后的图像
displayDftSpectrum(srcFiltered,"filtered image",true);//显示逆傅里叶频谱图
waitKey();
return ;
}
												

opencv的频域滤波的更多相关文章

  1. Python下opencv使用笔记(十)(图像频域滤波与傅里叶变换)

    前面以前介绍过空间域滤波,空间域滤波就是用各种模板直接与图像进行卷积运算,实现对图像的处理,这个方案直接对图像空间操作,操作简单.所以也是空间域滤波. 频域滤波说究竟终于可能是和空间域滤波实现相同的功 ...

  2. Python下opencv使用笔记(图像频域滤波与傅里叶变换)

    Python下opencv使用笔记(图像频域滤波与傅里叶变换) 转载一只程序喵 最后发布于2018-04-06 19:07:26 阅读数 1654  收藏 展开 本文转载自  https://blog ...

  3. Matlab中图像处理实例:灰度变换,空域滤波,频域滤波,傅里叶变换的实现

    http://blog.sciencenet.cn/blog-95484-803140.html % %图像灰度变换 % f = imread('E:\2013第一学期课程\媒体计算\实验一\Img\ ...

  4. 目标跟踪之粒子滤波---Opencv实现粒子滤波算法

    目标跟踪学习笔记_2(particle filter初探1) 目标跟踪学习笔记_3(particle filter初探2) 前面2篇博客已经提到当粒子数增加时会内存报错,后面又仔细查了下程序,是代码方 ...

  5. 灰度图像--频域滤波 傅里叶变换之离散傅里叶变换(DFT)

    学习DIP第23天 转载请标明本文出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对此表示很不 ...

  6. 灰度图像--频域滤波 傅里叶变换之离散时间傅里叶变换(DTFT)

    学习DIP第22天 转载请标明本文出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对此表示很不 ...

  7. 灰度图像--频域滤波 傅里叶变换之连续信号傅里叶变换(FT)

    学习DIP第20天 转载请标明本文出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对此表示很不 ...

  8. CUDA加opencv复现导向滤波算法

    CUDA是GPU通用计算的一种,其中现在大热的深度学习底层GPU计算差不多都选择的CUDA,在这我们先简单了解下其中的一些概念,为了好理解,我们先用DX11里的Compute shader来和CUDA ...

  9. opencv中的滤波

    以前的时候,为了过滤图像中的一些噪点,学过一些简单的滤波,比如中值滤波,均值滤波,也是自己实现的. 在opencv中有现成的函数可以调用,实现滤波的操作. 函数的原型如下: CVAPI(void) c ...

随机推荐

  1. Summer training round2 #4 (Training #20)

    A!:UESTC1752 B!:找区间内L到R之间内的数的个数  权值分块加莫队 C!:给你一个哈斯图 去掉其中的几条边 要求输出字典序最大的拓扑排序:线段树模拟拓扑排序 D!:要求你找到最短路树并输 ...

  2. maven生成jar包编码问题

    要做一个jar文件供外部调用,此jar的源代码中注释为中文,用maven打包后在其它工程中导入后总不能正常显示中文,记录解决方法如下: 在pom.xml中设置默认编码类型为UTF-8: <pro ...

  3. Pandas的常见使用方法操作

    Series Series是一种类似于一维数组的 对象,由一组数据(各种NumPy数据类型)以及一组与之对应的索引(数据标签)组成. 类似一维数组的对象由数据和索引组成索引(index)在左,数据(v ...

  4. SQL中Charindex和Oracle中对应的函数Instr

    转:http://blog.csdn.net/zhuyu19911016520/article/details/8568640 sql :charindex('字符串',字段)>0 charin ...

  5. gulp[13124]: c:\ws\src\node_contextify.cc:626: Assertion `args[1]->IsString()' failed

    在执行gulp sass时报下面错误,又或者执行ionic serve时报这个错,选择低一点版本的node,建议8v; gulp[13124]: c:\ws\src\node_contextify.c ...

  6. Java多线程和并发(十),JMM(Java内存模型)

    目录 1.什么是JMM 2.JMM的主内存和工作内存 3.JMM如何解决可见性问题-指令重排序 4.Volatile 十.JMM(Java内存模型)(暂时没有理解) 1.什么是JMM 2.JMM的主内 ...

  7. codevs 2597 团伙x

                         题目描述 Description 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的 ...

  8. windows下kafka配置入门 示例

    实验平台与软件: 操作系统:windows7 32  位 java 开发包: jdk1.8.0_144 集群: zookeeper-3.3.6 消息队列: kafka_2.11-0.11.0.1 安装 ...

  9. classpath说明

    概念解释: classpath : 即项目中WEB-INF下面的classes目录; 应用: [01] src路径下的文件在编译后会放到WEB-INF/classes路径下.默认的classpath是 ...

  10. [LOJ3120][CTS2019|CTSC2019]珍珠:生成函数+NTT

    分析 容易发现\(D \leq n - 2m\)时,任意数列都满足要求,直接判掉,下文所讨论的均为\(D > n - 2m\)的情况. 考虑把两个数列合并,显然可以认为是两个带标号对象的合并,可 ...