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

  • 相关阅读:
    asp.net mvc(2013424)——基本知识
    asp.net mvc(2013425)——使用模板页
    jquery实现tab切换核心代码
    asp.net mvc(2013422 )——准备入门
    也说C#串行化
    Net Assembly.GetExecutingAssembly() 和 Assembly.GetCallingAssembly()的区别
    log (一)
    C# 重载和从写的区别
    log4net
    C# 反射
  • 原文地址:https://www.cnblogs.com/darkknightzh/p/5462631.html
Copyright © 2020-2023  润新知