opencv中傅里叶变换的使用

xiaoxiao2025-08-06  21

一、频率域滤波:

频率域滤波的原理:

频率直接关系到空间变化率,低频对应于图像中变化缓慢的灰度成分,较高的频率对应于图像中越来越快的灰度变化:      

1.频谱的直流低频分量对应于图像的平滑区域      

2.频率的高频分量对应于图像的边沿或变化剧烈区域      

3.外界叠加噪声对应于频谱中频率较高的成分     

 4.恒定的干扰条纹对应于频谱中的某些特征点

频率域的滤波技术的基础:修改傅里叶变换以达到特殊的目的,然后计算IDFT返回到图像域,我们修改傅里叶变换主要是修改变换之后的幅度和相角。

 

opencv中步骤不是唯一的,我所知道的步骤如下:

1.首先找到最适合做dft的宽和高,根据找到的宽和高扩充图像

2.将图像进行中心化

3.对图像进行傅里叶变换

4.根据H(u,v),得到与扩充后的图像大小相同的模板

5. 使用矩阵的对应相乘得到G(u,v)

6.进行傅里叶反变换得到处理之后的结果。

二、下面是在网上找到的两个比较有代表性的代码

1.这个代码是对图像进行低通和高通进行处理

#include <iostream> #include<opencv2/opencv.hpp> using namespace cv; int main(){ cv::Mat src=cv::imread("../1.jpg",0); if(src.empty()){ std::cout<<"could not load image"<<std::endl; return -1; } cv::imshow("src",src); int w=cv::getOptimalDFTSize(src.cols); int h=cv::getOptimalDFTSize(src.rows); cv::Mat padded; cv::copyMakeBorder(src,padded,0,h-src.rows,0,w-src.cols,cv::BORDER_DEFAULT,cv::Scalar::all(0)); padded.convertTo(padded,CV_32FC1); cv::imshow("padded",padded); for(int i=0;i<padded.rows;i++){ float *ptr=padded.ptr<float>(i); for(int j=0;j<padded.cols;j++){ ptr[j]*=pow(-1,i+j); } } cv::imshow("hahha",padded); Mat plane[]={padded,Mat::zeros(padded.size(),CV_32F)}; Mat CompleImg; merge(plane,2,CompleImg); dft(CompleImg,CompleImg); cv::Mat gaussianBlur(padded.size(),CV_32FC2); cv::Mat gaussianSharp(padded.size(),CV_32FC2); float D0=2*10*10; for(int i=0;i<padded.rows;i++){ float *p=gaussianBlur.ptr<float>(i); float *q=gaussianSharp.ptr<float>(i); for(int j=0;j<padded.cols;j++){ float d=pow(i-padded.rows/2,2)+pow(j-padded.cols/2,2); //p[j]=expf(-d/D0); //高斯低通变换 // p[2*j]=expf(-d/D0); // p[2*j+1]=expf(-d/D0); // //q[j]=1-expf(-d/D0); //高斯高通 // q[2*j]=1-expf(-d/D0); // q[2*j+1]=1-expf(-d/D0); // if(d<D0) // { // //理想低通 // p[2*j]=1; // p[2*j+1]=1; // //q[j]=1-expf(-d/D0); // //理想高通 // q[2*j]=0; // q[2*j+1]=0; // }else // { // p[2*j]=0; // p[2*j+1]=0; // //q[j]=1-expf(-d/D0); // q[2*j]=1; // q[2*j+1]=1; // } p[2*j]=1/(1+pow((d/D0),5)); p[2*j+1]=1/(1+pow((d/D0),5)); //q[j]=1-expf(-d/D0); //高斯高通 q[2*j]=1-1/(1+pow((d/D0),5)); q[2*j+1]=1-1/(1+pow((d/D0),5)); } } multiply(CompleImg,gaussianBlur,gaussianBlur);//矩阵元素对应相乘法,注意,和矩阵相乘区分 multiply(CompleImg,gaussianSharp,gaussianSharp); split(CompleImg,plane); magnitude(plane[0],plane[1],plane[0]); plane[0]+=Scalar::all(1); log(plane[0],plane[0]); normalize(plane[0],plane[0],1,0,CV_MINMAX); imshow("dft",plane[0]); //平滑的高斯模板 split(gaussianBlur,plane); magnitude(plane[0],plane[1],plane[0]); plane[0]+=Scalar::all(1); log(plane[0],plane[0]); normalize(plane[0],plane[0],1,0,CV_MINMAX); imshow("gaussianBlur",plane[0]); //锐化的高斯模板 split(gaussianSharp,plane); magnitude(plane[0],plane[1],plane[0]); plane[0]+=Scalar::all(1); log(plane[0],plane[0]); normalize(plane[0],plane[0],1,0,CV_MINMAX); imshow("gaussianSharpen",plane[0]); idft(gaussianBlur,gaussianBlur); idft(gaussianSharp,gaussianSharp); split(gaussianBlur,plane); magnitude(plane[0],plane[1],plane[0]); normalize(plane[0],plane[0],1,0,CV_MINMAX); imshow("idft-gaussianBlur",plane[0]); split(gaussianSharp,plane); magnitude(plane[0],plane[1],plane[0]); normalize(plane[0],plane[0],1,0,CV_MINMAX); imshow("idft-gaussianSharpen",plane[0]); cv::waitKey(0); return 0; }

代码中三种不同的滤波器,公式如下:

原图

图像中心化之后傅里叶变换之后的频谱图

高斯低通的模板处理之后的结果

高通处理之后的结果  高通与低通正好相反

高斯低通滤波器处理之后反变换的结果  图像平滑

高斯高通滤波器处理之后反变换的结果  图像锐化

 

2.使用高斯滤波去除噪声

 因为噪声对应的一般是高频的,所以使用低通滤波器可以达到一定的滤波效果

#include<opencv2/opencv.hpp> #include<iostream> #include<cmath> using namespace std; using namespace cv; cv::Mat gaussianlbrf(cv::Mat src,float sigm); cv::Mat freqfilt(cv::Mat src,cv::Mat blur); int main() { cv::Mat img=cv::imread("../1.png",0); cv::imshow("img",img); int w=cv::getOptimalDFTSize(img.cols); int h=cv::getOptimalDFTSize(img.rows); cv::Mat padded; cv::copyMakeBorder(img,padded,0,h-img.rows,0,w-img.cols,cv::BORDER_CONSTANT,cv::Scalar::all(0)); padded.convertTo(padded,CV_32FC1); cv::Mat gaussianKernel=gaussianlbrf(padded,35); cv::Mat out=freqfilt(padded,gaussianKernel); cv::imshow("result",out); cv::waitKey(0); return 0; } //高斯低通滤波器 cv::Mat gaussianlbrf(cv::Mat src,float sigma){ cv::Mat gaussianBlur(src.size(),CV_32FC1); float d0=2*sigma*sigma;//高斯函数参数,越小 频率高斯滤波器越窄 滤出高斯成分越多 图像就越平滑 for(int i=0;i<src.rows;i++){ for(int j=0;j<src.cols;j++){ float d=pow((i-src.rows/2),2)+pow((j-src.cols/2),2); gaussianBlur.at<float>(i,j)=expf(-d/d0); } } cv::imshow("高斯低通滤波器",gaussianBlur); return gaussianBlur; } //频率域滤波 cv::Mat freqfilt(cv::Mat src,cv::Mat blur){ //创建通道 存储dft后的实部和虚部 必须为CV_32FC单通道 cv::Mat planes[]={src,cv::Mat::zeros(src.size(),CV_32FC1)}; cv::Mat complexImg; cv::merge(planes,2,complexImg);//合并通道 把两个矩阵 合并为一个2通道的Mat cv::dft(complexImg,complexImg);//傅里叶变换 //分离通道 cv::split(complexImg,planes); //中心化(实部) int cx=planes[0].cols/2; int cy=planes[0].rows/2; cv::Mat t0(planes[0],cv::Rect(0,0,cx,cy)); cv::Mat t1(planes[0],cv::Rect(cx,0,cx,cy)); cv::Mat t2(planes[0],cv::Rect(0,cy,cx,cy)); cv::Mat t3(planes[0],cv::Rect(cx,cy,cx,cy)); cv::Mat temp; t0.copyTo(temp); t3.copyTo(t0); temp.copyTo(t3); t1.copyTo(temp); t2.copyTo(t1); temp.copyTo(t2); //中心化(虚部) cv::Mat i0(planes[1],cv::Rect(0,0,cx,cy)); cv::Mat i1(planes[1],cv::Rect(cx,0,cx,cy)); cv::Mat i2(planes[1],cv::Rect(0,cy,cx,cy)); cv::Mat i3(planes[1],cv::Rect(cx,cy,cx,cy)); cv::Mat tempi; i0.copyTo(tempi); i3.copyTo(i0); tempi.copyTo(i3); i1.copyTo(tempi); i2.copyTo(i1); tempi.copyTo(i2); cv::Mat blur_r,blur_i,BLUR; cv::multiply(planes[0],blur,blur_r);//实部滤波 cv::multiply(planes[1],blur,blur_i);//虚部滤波 cv::Mat plane1[]={blur_r,blur_i}; cv::merge(plane1,2,BLUR);//实部虚部合并 //得到原图频率图 cv::magnitude(planes[0],planes[1],planes[0]);//获取幅度图像 planes[0]+=cv::Scalar::all(1); cv::log(planes[0],planes[0]); cv::normalize(planes[0],planes[0],1,0,CV_MINMAX);//归一化 imshow("原图像频谱图",planes[0]); //归一化之后返回 cv::Mat r0(BLUR,cv::Rect(0,0,cx,cy)); cv::Mat r1(BLUR,cv::Rect(cx,0,cx,cy)); cv::Mat r2(BLUR,cv::Rect(0,cy,cx,cy)); cv::Mat r3(BLUR,cv::Rect(cx,cy,cx,cy)); cv::Mat tempr; r0.copyTo(tempr); r3.copyTo(r0); tempr.copyTo(r3); r1.copyTo(tempr); r2.copyTo(r1); tempr.copyTo(r2); cv::idft(BLUR,BLUR); cv::split(BLUR,planes); cv::magnitude(planes[0],planes[1],planes[0]); cv::normalize(planes[0],planes[0],1,0,CV_MINMAX); return planes[0]; }

原图

原图像频谱

高斯低通频谱

反变换之后的结果

我们可以看到中心化有两种方式:1、f(x,y)*(-1)^(i+j)  2、通过将图像四分及位置的改变达到中心化的效果

傅里叶变换也有两种方式 :1、实部和虚部分开操作 2.实部和虚部一起操作

得出的结果都是一样的

转载请注明原文地址: https://www.6miu.com/read-5034354.html

最新回复(0)