通过傅里叶变换方法求图像卷积-OpenCV实现
来源:互联网 发布:网络销售合同 编辑:程序博客网 时间:2024/06/07 13:12
在图像处理中经常会遇到各种滤波(平滑、锐化)的情况,基本方法都是将图像与一个核进行卷积实现。而卷积定理指出,两个函数的卷积的傅里叶变换等于各自的傅里叶变换的乘积,即:
[1]
那么,两个函数的卷积可以通过如下方式得到,对两个函数傅里叶变换的乘积做傅里叶反变换,即:
[1]
在进行卷积运算时,一般是将核沿着图像从左到右从上到下计算每一个像素处与核卷积后的值,这样的计算量较大,采用傅里叶变换的方法可以提高运算效率。
#include "opencv2/core/core.hpp"#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include <iostream>using namespace cv;using namespace std;//http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#dft[2]void convolveDFT(Mat A, Mat B, Mat& C){ // reallocate the output array if needed C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); Size dftSize; // calculate the size of DFT transform dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); // allocate temporary buffers and initialize them with 0's Mat tempA(dftSize, A.type(), Scalar::all(0)); Mat tempB(dftSize, B.type(), Scalar::all(0)); // copy A and B to the top-left corners of tempA and tempB, respectively Mat roiA(tempA, Rect(0,0,A.cols,A.rows)); A.copyTo(roiA); Mat roiB(tempB, Rect(0,0,B.cols,B.rows)); B.copyTo(roiB); // now transform the padded A & B in-place; // use "nonzeroRows" hint for faster processing dft(tempA, tempA, 0, A.rows); dft(tempB, tempB, 0, B.rows); // multiply the spectrums; // the function handles packed spectrum representations well mulSpectrums(tempA, tempB, tempA, DFT_COMPLEX_OUTPUT);//mulSpectrums(tempA, tempB, tempA, DFT_REAL_OUTPUT); // transform the product back from the frequency domain. // Even though all the result rows will be non-zero, // you need only the first C.rows of them, and thus you // pass nonzeroRows == C.rows dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); // now copy the result back to C. tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C); // all the temporary buffers will be deallocated automatically}int main(int argc, char* argv[]){const char* filename = argc >=2 ? argv[1] : "Lenna.png"; Mat I = imread(filename, CV_LOAD_IMAGE_GRAYSCALE); if( I.empty()) return -1;Mat kernel = (Mat_<float>(3,3) << 1, 1, 1, 1, 1, 1, 1, 1, 1);cout << kernel;Mat floatI = Mat_<float>(I);// change image type into floatMat filteredI;convolveDFT(floatI, kernel, filteredI);normalize(filteredI, filteredI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a // viewable image form (float between values 0 and 1).imshow("image", I);imshow("filtered", filteredI);waitKey(0);}
convolveDFT函数是从官方文档中抄录并做了修改,因为原来的程序有问题。一是输出Mat C应声明为引用;二是其中的mulSpectrums函数的第四个参数flag值没有指定,应指定为DFT_COMPLEX_OUTPUT或是DFT_REAL_OUTPUT.
main函数中首先按灰度图读入图像,然后创造一个平滑核kernel,将输入图像转换成float类型(注意这步是必须的,因为dft只能处理浮点数),在调用convolveDFT求出卷积结果后,将卷积结果归一化方便显示观看。
需要注意的是,一般求法中,利用核游走整个图像进行卷积运算,实际上进行的是相关运算,真正意义上的卷积,应该首先把核翻转180度,再在整个图像上进行游走。OpenCV中的filter2D实际上做的也只是相关,而非卷积。"The function does actually compute correlation, not the convolution: ... That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip the kernel using flip() and set the new anchor to (kernel.cols - anchor.x - 1, kernel.rows - anchor.y - 1)"[3]
参考文献:
[1] http://zh.wikipedia.org/wiki/%E5%8D%B7%E7%A7%AF%E5%AE%9A%E7%90%86
[2] http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#dft
[3] http://docs.opencv.org/modules/imgproc/doc/filtering.html#filter2d
- 通过傅里叶变换方法求图像卷积-OpenCV实现
- 傅里叶变换方法求图像卷积-OpenCV实现 遇到的问题!!!求指教!!!!!!
- opencv实现图像的傅里叶变换
- Opencv 实现图像的离散傅里叶变换(DFT)、卷积运算(相关滤波)
- Opencv 实现图像的离散傅里叶变换(DFT)、卷积运算(相关滤波)
- Opencv 实现图像的离散傅里叶变换(DFT)、卷积运算(相关滤波)
- OpenCV下利用傅里叶变换和逆变换实现图像卷积算法,并附自己对于卷积核/模板核算子的理解!
- 用opencv求图像的快速傅里叶变换和反变换
- opencv 图像傅里叶变换
- opencv filter2D函数实现图像卷积
- 轻松理解-opencv-数字图像图像处理--一维离散卷积和一维离散傅里叶变换
- opencv学习(6)图像离散傅里叶变换的实现过程
- opencv学习实现简单的图像离散傅里叶变换
- OpenCV实现傅里叶变换,通过直线检测矫正文本
- OPENCV图像卷积运算
- opencv图像处理-卷积
- OpenCV实现傅里叶变换
- OpenCV实现傅里叶变换
- [LeetCode]String to Integer (atoi)
- SHELL : echo字体控制
- is not in the sudoers file 解决(转)
- window7 wifi配置
- @property与内存管理以及可传参数
- 通过傅里叶变换方法求图像卷积-OpenCV实现
- 程序员面试100题之五:二叉树两个结点的最低共同父结点
- PHP控制Header信息以强制转换文件类型表
- MyBatis的动态SQL详解
- mybatis学习笔记
- SHELL : 数组变量及数组参数
- 如何查看linux开启了哪些服务
- 【.NET线程--开篇】--线程从零开始
- VIM提文件权限问题:...e45 readonly option…