转载请注明出处:
参考网址:
1 #include2 #include 3 #include 4 using namespace cv; 5 #include 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 * 442 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: // full50 r = Rect(0, 0, matConvResTemp.cols, matConvResTemp.rows);51 break;52 case CONVOLUTION_SAME: // same53 r = Rect((kernel.cols + 0.5) / 2, (kernel.rows + 0.5) / 2, img.cols, img.rows);54 break;55 case CONVOLUTION_VALID: // valid56 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: // same59 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的程序对比测试,发现第一个程序结果和卷积的结果相似,第二个程序的结果和相关的结果相似。