(原)使用intel的ipp库计算卷积及相关
转载请注明出处:
http://www.cnblogs.com/darkknightzh/p/5462631.html
参考网址:
https://software.intel.com/zh-cn/node/504170
https://software.intel.com/en-us/node/599808
https://software.intel.com/en-us/node/504340
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/highgui/highgui.hpp> 3 #include <opencv2/imgproc/imgproc.hpp> 4 using namespace cv; 5 #include <ipp.h> 6 7 enum ConvolutionType // 卷积时参数的类型 8 { 9 CONVOLUTION_FULL, // 卷积时的参数,和 matlab 的 full 一致 10 CONVOLUTION_SAME, // 卷积时的参数,和 matlab 的 same 一致 11 CONVOLUTION_VALID // 卷积时的参数,和 matlab 的 valid 一致 12 }; 13 14 void Conv2IPP(Mat& convRes, const Mat& imgIn, const Mat& kernelIn, ConvolutionType type, int ddepth) 15 { 16 Mat img = imgIn.clone(), kernel = kernelIn.clone(); 17 const IppiSize imgSize = { img.cols, img.rows }; 18 const IppiSize kerSize = { kernel.cols, kernel.rows }; 19 20 if (CV_32FC1 != img.type()) 21 { 22 img.convertTo(img, CV_32FC1); // ipp的库支持8u,16s,32f这几种精度的数据的卷积 23 } 24 if (CV_32FC1 != kernel.type()) 25 { 26 kernel.convertTo(kernel, CV_32FC1); 27 } 28 29 int nConvResW = img.cols + kernel.cols - 1; 30 int nConvResH = img.rows + kernel.rows - 1; 31 // 如果直接声明Mat的变量,并在ippiConv_32f_C1R中传递.data缓冲区的话,程序会崩溃,因而只能先加一个临时变量 32 float *pConvRes = new float[nConvResW * nConvResH]; 33 34 // ippiROIFull改为ippiROIValid或者ippiROISame对应matlab响应的参数。不能直接改,否则结果不对。具体怎么改,暂时不清楚。 35 IppEnum funCfgFull = (IppEnum)(ippAlgAuto | ippiROIFull | ippiNormNone); 36 int bufSizeFull; 37 IppStatus status = ippiConvGetBufferSize(imgSize, kerSize, ipp32f, 1, funCfgFull, &bufSizeFull); 38 Ipp8u* pBuffer = ippsMalloc_8u(bufSizeFull); 39 40 ippiConv_32f_C1R((Ipp32f*)img.data, img.step, imgSize, (Ipp32f*)kernel.data, kernel.step, kerSize, 41 pConvRes, nConvResW * 4, funCfgFull, pBuffer); // 此处应该使用nConvResW * 4 42 43 Mat matConvResTemp(nConvResH, nConvResW, CV_32FC1); 44 memcpy(matConvResTemp.data, pConvRes, sizeof(float)* nConvResH * nConvResW); 45 46 Rect r; 47 switch (type) 48 { 49 case CONVOLUTION_FULL: // full 50 r = Rect(0, 0, matConvResTemp.cols, matConvResTemp.rows); 51 break; 52 case CONVOLUTION_SAME: // same 53 r = Rect((kernel.cols + 0.5) / 2, (kernel.rows + 0.5) / 2, img.cols, img.rows); 54 break; 55 case CONVOLUTION_VALID: // valid 56 r = Rect((kernel.cols + 0.5) / 2, (kernel.rows + 0.5) / 2, img.cols - kernel.cols + 1, img.rows - kernel.rows + 1); 57 break; 58 default: // same 59 r = Rect((kernel.cols + 0.5) / 2, (kernel.rows + 0.5) / 2, img.cols, img.rows); 60 break; 61 } 62 63 matConvResTemp(r).convertTo(convRes, ddepth, 1, 0); // ddepth为CV_32FC1等类型 64 65 ippsFree(pBuffer); 66 delete[] pConvRes; 67 pConvRes = nullptr; 68 }
说明:不确定的有2处:
1. 此程序计算卷积还是相关?感觉像是相关而非卷积(之前写过的程序计算相关,此处和之前的结果总体上相似。理论上卷积是核需要上下左右镜像的,这个地方不确定)
ps:应该是卷积。
2. CONVOLUTION_FULL没有问题,CONVOLUTION_SAME不确定矩形框是否正确,CONVOLUTION_VALID也不确定是否正确。实际上对于后两者,可以将标志funCfgFull从ippiROIFull改为ippiROISame或者ippiROIValid,不过卷积的缓冲区pConvRes需要相应的改变大小。还有,如果直接改标志的话,卷积的结果不正确。不清楚什么原因。
ps:当使用ippiROISame时,计算到的bufSizeFull的值为0,因而卷积的结果不正确。不明白为什么。
150506更新:
在第三个参考网址中,发现了另一个函数ippiCrossCorrNorm_32f_C1R,用于计算相关。可以选用ippiROISame参数。
1 Mat Conv2IPPSame(const Mat& imgIn, const Mat& kernelIn) 2 { 3 Mat img = imgIn.clone(), kernel = kernelIn.clone(); 4 const IppiSize imgSize = { img.cols, img.rows }; 5 const IppiSize kerSize = { kernel.cols, kernel.rows }; 6 7 if (CV_32FC1 != img.type()) 8 { 9 img.convertTo(img, CV_32FC1); 10 } 11 if (CV_32FC1 != kernel.type()) 12 { 13 kernel.convertTo(kernel, CV_32FC1); 14 } 15 16 int nConvResW = img.cols; 17 int nConvResH = img.rows; 18 float *pConvRes = new float[nConvResW * nConvResH]; 19 20 int bufSize; 21 IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiROISame | ippiNormNone); 22 IppStatus status = ippiCrossCorrNormGetBufferSize(imgSize, kerSize, funCfg, &bufSize); 23 Ipp8u* pBuffer = ippsMalloc_8u(bufSize); 24 25 ippiCrossCorrNorm_32f_C1R((Ipp32f*)img.data, img.step, imgSize, (Ipp32f*)kernel.data, kernel.step, kerSize, 26 pConvRes, nConvResW * 4, funCfg, pBuffer); 27 28 Mat matConvRes(nConvResH, nConvResW, CV_32FC1); 29 memcpy(matConvRes.data, pConvRes, sizeof(float)* nConvResH * nConvResW); 30 31 ippsFree(pBuffer); 32 delete[] pConvRes; 33 pConvRes = nullptr; 34 35 return matConvRes; 36 }
从参考网址3中可以看到,ippiNormNone是计算相关的意思。
需要注意的是,第二个程序是计算相关的程序,而非卷积。和matlab的程序对比测试,发现第一个程序结果和卷积的结果相似,第二个程序的结果和相关的结果相似。
posted on 2016-05-05 17:24 darkknightzh 阅读(5211) 评论(2) 编辑 收藏 举报