opencv学习:二维浮点数离散傅里叶变换及其扩展边界优化

来源:互联网 发布:交换机端口灯不亮 编辑:程序博客网 时间:2024/06/14 16:13

opencv中提供了傅里叶变换函数cvDFT,执行二维浮点数离散傅里叶变换的代码如下:

void fft2(const IplImage* src, IplImage* dst){    //实部、虚部      IplImage *image_Re = 0, *image_Im = 0, *Fourier = 0;      image_Re = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  //实部      image_Im = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 1);  //虚部      Fourier = cvCreateImage(cvGetSize(src), IPL_DEPTH_32F, 2);   //二通道图像        //将实部从8u转换为32f    cvConvertScale(src, image_Re);          // 虚部置零      cvZero(image_Im);          //将实部与虚部合并到Fourier中    cvMerge(image_Re, image_Im, 0, 0, Fourier);        // 进行正向离散傅里叶变换     cvDFT(Fourier, dst, CV_DXT_FORWARD);      cvReleaseImage(&image_Re);      cvReleaseImage(&image_Im);      cvReleaseImage(&Fourier);  }

将图像中心移到原点:

void cvShiftDFT(CvArr* src, CvArr* dst){//定义变量 CvMat * tmp;    CvMat q1stub, q2stub;    CvMat q3stub, q4stub;    CvMat d1stub, d2stub;    CvMat d3stub, d4stub;    CvMat * q1, * q2, * q3, * q4;    CvMat * d1, * d2, * d3, * d4;//获取源图像和目标图像的尺寸    CvSize size = cvGetSize(src);    CvSize dst_size = cvGetSize(dst);    int cx, cy;//若源图像和目标图像的尺寸不一致,抛出异常错误    if(dst_size.width != size.width ||        dst_size.height != size.height){        cvError( CV_StsUnmatchedSizes, "cvShiftDFT", "Source and Destination arrays must have equal sizes", __FILE__, __LINE__ );       }//若源和目标为同一指针,则创建临时矩阵变量    if(src==dst){        tmp = cvCreateMat(size.height/2, size.width/2, cvGetElemType(src));    }        cx = size.width/2;    cy = size.height/2; // 图像中心//分别获取第一、二、三、四象限的子图像    q1 = cvGetSubRect( src, &q1stub, cvRect(0,0,cx, cy) );    q2 = cvGetSubRect( src, &q2stub, cvRect(cx,0,cx,cy) );    q3 = cvGetSubRect( src, &q3stub, cvRect(cx,cy,cx,cy) );    q4 = cvGetSubRect( src, &q4stub, cvRect(0,cy,cx,cy) );    d1 = cvGetSubRect( src, &d1stub, cvRect(0,0,cx,cy) );    d2 = cvGetSubRect( src, &d2stub, cvRect(cx,0,cx,cy) );    d3 = cvGetSubRect( src, &d3stub, cvRect(cx,cy,cx,cy) );    d4 = cvGetSubRect( src, &d4stub, cvRect(0,cy,cx,cy) );/*** 若源与目标不一致* 则直接将源图像的第一、二、三、四象限对应复制到目标图像的第三、四、一、二象限* 否则,直接交换一三象限、二四象限**/    if(src!=dst){        if( !CV_ARE_TYPES_EQ( q1, d1 )){            cvError( CV_StsUnmatchedFormats, "cvShiftDFT", "Source and Destination arrays must have the same format", __FILE__, __LINE__ );         }        cvCopy(q3, d1, 0);        cvCopy(q4, d2, 0);        cvCopy(q1, d3, 0);        cvCopy(q2, d4, 0);    }    else{        cvCopy(q3, tmp, 0);        cvCopy(q1, q3, 0);        cvCopy(tmp, q1, 0);        cvCopy(q4, tmp, 0);        cvCopy(q2, q4, 0);        cvCopy(tmp, q2, 0);    }}

以上代码参考了richel_zhang的博客和opencv教程基础篇。

cvDFT函数执行时的效率与图像尺寸有关,当图像的宽高都为2的指数幂时,将可利用快速傅里叶变换,运算时间为O(NlogN), 否则为O(N^2),故为了提高运算效率,需要提前将待处理图像的尺寸扩展为2的指数幂大小。

opencv中提供了函数cvGetOptimalDFTSize可以获取最优傅里叶变换尺寸,再结合扩展边界函数copyMakeBorder将源图像尺寸扩展。

代码如下:

void getOptimalDFTSize(const IplImage* src, CvSize& size){size.width = cvGetOptimalDFTSize(src->width);size.height = cvGetOptimalDFTSize(src->height);}IplImage* border(const IplImage* src, CvSize size){IplImage* borderImg = cvCreateImage(size, src->depth, src->nChannels);copyMakeBorder(cv::cvarrToMat(src), cv::cvarrToMat(borderImg),0,size.height-src->height, 0, size.width-src->width,cv::BORDER_CONSTANT);return borderImg;}void border_fft2(const IplImage* src, IplImage* dst){//计算最优DFT尺寸CvSize size;getOptimalDFTSize(src, size);border_fft2(src, dst, size);//调用函数扩展边界并做傅里叶变换}void border_fft2(const IplImage* src, IplImage* dst, CvSize size){IplImage* bordersrc = border(src, size);//扩展边界fft2(bordersrc, dst);//二维傅里叶变换cvReleaseImage(&bordersrc);//释放内存}

版权所有,转载请注明出处。





0 0