轉載請注明出處:
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的程序對比測試,發現第一個程序結果和卷積的結果相似,第二個程序的結果和相關的結果相似。
