(原)使用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也不確定是否正確。實際上對於后兩者,可以將標志funCfgFullippiROIFull改為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的程序對比測試,發現第一個程序結果和卷積的結果相似,第二個程序的結果和相關的結果相似。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM