学习opencv 第六章 习题十三
用傅里叶变换加速卷积,直接上代码,Mat版是Copy他人的。
CvMat版
1 #include "stdafx.h" 2 #include "cv.h" 3 #include "highgui.h" 4 #include <iostream> 5 6 using namespace cv; 7 using namespace std; 8 9 void speedy_convolution(const CvMat* A,const CvMat* B,CvMat* C); 10 11 int main() 12 { 13 IplImage* img=cvLoadImage("C:/Users/shark/Desktop/fruits.jpg",0); 14 CvMat* src=cvCreateMat(img->height,img->width,CV_32FC1); 15 /*int data; 16 for(int i=0;i<img->height;i++) 17 { 18 for(int j=0;j<img->width;j++) 19 { 20 data=img->imageData[i*img->widthStep+j]; 21 cvmSet(src,i,j,data); 22 } 23 }*/ 24 //必须归一化矩阵的值为0-1之间(缩放比例在1/255.0附近效果最好,太小最后会全黑,接近1或大于1几乎是全白; 25 //(还未深入了解函数cvConvertScale的机理),缩放比例不能为1,打出目标图像的像素有正有负 26 cvConvertScale(img,src,1/255.0,0); 27 28 29 CvMat* kernel=cvCreateMat(3,3,CV_32FC1); 30 cvSetReal2D(kernel,0,0,1.0/16); cvSetReal2D(kernel,0,1,2.0/16); cvSetReal2D(kernel,0,2,1.0/16); //注意设置值时必须加个.0否则1/16的值0 31 cvSetReal2D(kernel,1,0,2.0/16); cvSetReal2D(kernel,1,1,4.0/16); cvSetReal2D(kernel,1,2,2.0/16); 32 cvSetReal2D(kernel,2,0,1.0/16); cvSetReal2D(kernel,2,1,2.0/16); cvSetReal2D(kernel,2,2,1.0/16); 33 CvMat* C=cvCreateMat((src->rows+kernel->rows-1),(src->cols+kernel->cols-1),src->type); 34 speedy_convolution(src,kernel,C); 35 36 IplImage* img_src=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1); 37 cvGetImage(src,img_src); 38 IplImage* img_dst=cvCreateImage(cvGetSize(C),IPL_DEPTH_32F,1); 39 cvGetImage(C,img_dst); 40 41 cvNamedWindow("img_src"); 42 cvShowImage("img_src",img_src); 43 cvNamedWindow("img"); 44 cvShowImage("img",img); 45 cvNamedWindow("dst"); 46 cvShowImage("dst",img_dst); 47 cvWaitKey(); 48 return 0; 49 } 50 51 void speedy_convolution( 52 const CvMat* A, 53 const CvMat* B, 54 CvMat* C 55 ){ 56 int dft_M=cvGetOptimalDFTSize(A->rows+B->rows-1); 57 int dft_N=cvGetOptimalDFTSize(A->cols+B->cols-1); 58 59 CvMat *dft_A=cvCreateMat(dft_M,dft_N,A->type); 60 CvMat *dft_B=cvCreateMat(dft_M,dft_N,B->type); 61 CvMat tmp; 62 cvGetSubRect(dft_A,&tmp,cvRect(0,0,A->cols,A->rows)); 63 cvCopy(A,&tmp); 64 cvGetSubRect(dft_A,&tmp,cvRect(A->cols,0,dft_A->cols-A->cols,A->rows)); 65 cvZero(&tmp); 66 cvDFT(dft_A,dft_A,CV_DXT_FORWARD,A->rows); 67 68 cvGetSubRect(dft_B,&tmp,cvRect(0,0,B->cols,B->rows)); 69 cvCopy(B,&tmp); 70 cvGetSubRect(dft_B,&tmp,cvRect(B->cols,0,dft_B->cols-B->cols,B->rows)); 71 cvZero(&tmp); 72 cvDFT(dft_B,dft_B,CV_DXT_FORWARD,B->rows); 73 74 cvMulSpectrums(dft_A,dft_B,dft_A,0); 75 76 cvDFT(dft_A,dft_A,CV_DXT_INV_SCALE,C->rows); 77 cvGetSubRect(dft_A,&tmp,cvRect(0,0,C->cols,C->rows)); 78 cvCopy(&tmp,C); 79 cvReleaseMat(&dft_A); 80 cvReleaseMat(&dft_B); 81 }
Mat版
1 #include "opencv2/core/core.hpp" 2 #include "opencv2/imgproc/imgproc.hpp" 3 #include "opencv2/highgui/highgui.hpp" 4 #include <iostream> 5 6 using namespace cv; 7 using namespace std; 8 9 //http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#dft[2] 10 void convolveDFT(Mat A, Mat B, Mat& C) 11 { 12 // reallocate the output array if needed 13 C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); 14 Size dftSize; 15 // calculate the size of DFT transform 16 dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); 17 dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); 18 19 // allocate temporary buffers and initialize them with 0's 20 Mat tempA(dftSize, A.type(), Scalar::all(0)); 21 Mat tempB(dftSize, B.type(), Scalar::all(0)); 22 23 // copy A and B to the top-left corners of tempA and tempB, respectively 24 Mat roiA(tempA, Rect(0,0,A.cols,A.rows)); 25 A.copyTo(roiA); 26 Mat roiB(tempB, Rect(0,0,B.cols,B.rows)); 27 B.copyTo(roiB); 28 29 // now transform the padded A & B in-place; 30 // use "nonzeroRows" hint for faster processing 31 dft(tempA, tempA, 0, A.rows); 32 dft(tempB, tempB, 0, B.rows); 33 34 // multiply the spectrums; 35 // the function handles packed spectrum representations well 36 mulSpectrums(tempA, tempB, tempA, DFT_COMPLEX_OUTPUT); 37 //mulSpectrums(tempA, tempB, tempA, DFT_REAL_OUTPUT); 38 39 // transform the product back from the frequency domain. 40 // Even though all the result rows will be non-zero, 41 // you need only the first C.rows of them, and thus you 42 // pass nonzeroRows == C.rows 43 dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); 44 45 // now copy the result back to C. 46 tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C); 47 48 // all the temporary buffers will be deallocated automatically 49 } 50 51 52 int main(int argc, char* argv[]) 53 { 54 const char* filename = argc >=2 ? argv[1] : "Lenna.png"; 55 56 Mat I = imread(filename, CV_LOAD_IMAGE_GRAYSCALE); 57 if( I.empty()) 58 return -1; 59 60 Mat kernel = (Mat_<float>(3,3) << 1, 1, 1, 1, 1, 1, 1, 1, 1); 61 cout << kernel; 62 63 Mat floatI = Mat_<float>(I);// change image type into float 64 Mat filteredI; 65 convolveDFT(floatI, kernel, filteredI); 66 67 normalize(filteredI, filteredI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a 68 // viewable image form (float between values 0 and 1). 69 imshow("image", I); 70 imshow("filtered", filteredI); 71 waitKey(0); 72 73 } 74 75 //一是输出Mat C应声明为引用;二是其中的mulSpectrums函数的第四个参数flag值没有指定,应指定为DFT_COMPLEX_OUTPUT或是DFT_REAL_OUTPUT. 76 77 //main函数中首先按灰度图读入图像,然后创造一个平滑核kernel,将输入图像转换成float类型(注意这步是必须的,因为dft只能处理浮点数),在调用convolveDFT求出卷积结果后,将卷积结果归一化方便显示观看。 78 79 //需要注意的是,一般求法中,利用核游走整个图像进行卷积运算,实际上进行的是相关运算,真正意义上的卷积,应该首先把核翻转180度,再在整个图像上进行游走。OpenCV中的filter2D实际上做的也只是相关,而非卷积。