(原)使用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的程序对比测试,发现第一个程序结果和卷积的结果相似,第二个程序的结果和相关的结果相似。

 

posted on 2016-05-05 17:24  darkknightzh  阅读(5211)  评论(2编辑  收藏  举报

导航