• Open CV学习 01 离散傅里叶变换DFT


    适用于图像处理的二维离散傅里叶变换

      

    通常项目使用过程中由于DFT运算耗时,基本都会采用快速傅里叶变换。

     通过欧拉公式我们可以展开。

    	cv::Mat mat(21, 7, CV_8UC1);
    	cv::randu(mat, cv::Scalar::all(0), cv::Scalar::all(255));//为矩阵随机填充[0,255)的随机值
    	std::cout << "original:
    " << mat << std::endl << std::endl;
    
    	cv::Mat paddedMat;
    	int optimalRows = cv::getOptimalDFTSize(mat.rows);
    	int optimalCols = cv::getOptimalDFTSize(mat.cols);
    	
    	//最优尺寸补零
    	cv::copyMakeBorder(mat, paddedMat, 0, optimalRows - mat.rows, 0, optimalCols - mat.cols,cv::BORDER_CONSTANT, cv::Scalar::all(0));
        
    	cv::Mat paddedMatDouble;
    	paddedMat.convertTo(paddedMatDouble, CV_64FC1);
    	
    	Mat myresMat = mydft(paddedMatDouble);
    	cv::Mat mydft_res_real_imaginary[] = { cv::Mat::zeros(myresMat.size(),CV_64FC1), Mat::zeros(myresMat.size(), CV_64FC1) };
    	cv::split(myresMat, mydft_res_real_imaginary);//拆分数据
    
    	Mat dftMat;
    	cv::dft(paddedMatDouble, dftMat, DFT_COMPLEX_OUTPUT);
    	cv::Mat dft_res_real_imaginary[] = { cv::Mat::zeros(dftMat.size(),CV_64FC1), Mat::zeros(dftMat.size(), CV_64FC1)};
    	cv::split(dftMat, dft_res_real_imaginary);//拆分数据
    
    	std::cout << "------------------------" << std::endl;
    	for (int i = 0; i < dftMat.rows; i++)
    	{
    		double * myreal = mydft_res_real_imaginary[0].ptr<double>(i);
    		double * myimg = mydft_res_real_imaginary[1].ptr<double>(i);
    		double * real = dft_res_real_imaginary[0].ptr<double>(i);
    		double * img = dft_res_real_imaginary[1].ptr<double>(i);
    		for (int j = 0; j < dftMat.cols; j++)
    		{
    			std::cout << "-" << (std::abs(myreal[j] - real[j] - myimg[j] + img[j]) < 0.0001) << "- ";
    		}
    		std::cout << std::endl;
    	}
    
    Mat mydft(const Mat& mat)
    {
    	CV_Assert(mat.type() == CV_64FC1);
    	int N = mat.cols;
    	int M = mat.rows;
    	Mat realMat(M, N, CV_64FC1);
    	Mat imaginaryMat(M, N, CV_64FC1);
    
    	for (int u = 0; u < M; u++)
    	{
    		double * ptrReal = realMat.ptr<double>(u);
    		double * ptrImaginary = imaginaryMat.ptr<double>(u);
    		for (int v = 0; v < N; v++)
    		{
    			double realSum = 0;
    			double imaginary = 0;
    			for (int x = 0; x < M; x++)
    			{
    				const double * ptrRow = mat.ptr<double>(x);
    				for (int y = 0; y < N; y++)
    				{
    					realSum += ptrRow[y] * std::cos(-2. * CV_PI *(u * x * 1.0 / M + v * y * 1.0 / N));
    					imaginary += ptrRow[y] * std::sin(-2. * CV_PI *(u * x * 1.0 / M + v * y * 1.0 / N));
    				}
    
    			}
    			ptrReal[v] = realSum;
    			ptrImaginary[v] = imaginary;
    		}
    	}
    
    	Mat res;
    	Mat planes[] = { realMat, imaginaryMat };
    	merge(planes, 2, res);
    	return res;
    }
    

      

     OpenCV提供的dft接口 void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);

     dft函数的flags参数说明:

    DFT_INVERSE  傅里叶逆变换

    DFT_SCALE  与DFT_INVERSE结合使用,输出结果除以元素数来进行缩放

    DFT_ROWS 对输入矩阵每一行进行傅里叶变换或逆变换,同时对多个向量进行变换,可以减少三围和多维变换操作的开销

    DFT_COMPLEX_OUTPUT 傅里叶变换的结果是关于原点共轭对称的,两个原点对称点的值实部相等虚部相反,所以在一个象限中存储实部,对称象限存储虚部,这样,要两个通道存储的复数就只需要一个通道,节省内存。默认,如果输入为单通道,输出也为单通道(复共轭对称压缩存储复数); 如果输入为双通道,输出也为双通道复数结果;如果指定此参数,总是使用双通道输出结果。

    DFT_REAL_OUTPUT 对共轭对称矩阵(如正向傅里叶变换生成的矩阵)进行反傅里叶变换时,结果是一个实数矩阵,但函数不会判断是否共轭对称,可以通过这个参数来告诉输入矩阵是共轭对称的,从而输出实数矩阵。如果输入只有一个通道(复共轭对称压缩存储复数),函数会认为这是一个经过压缩的共轭对称矩阵,从而输出实数矩阵。

    DTF_COMPLEX_INPUT 输入必须要有两个通道分别表示实部和虚部,如果输入有两个通道,默认也认为是实部和虚部通道。

  • 相关阅读:
    c# 并行运算二
    c# 并行运算
    Task+http请求
    Task多线程
    SSO系统认证
    web系统权限设计
    AutoMapper的使用
    中间件
    express-middleware
    中间件概念
  • 原文地址:https://www.cnblogs.com/merlinzjl/p/14275209.html
Copyright © 2020-2023  润新知