cvGet2D替代方案

时间:2012-03-03 07:45:40

标签: c++ c image-processing opencv

我正在实时处理视频帧。我一次循环一个像素,做一些数学运算,然后将像素设置为特定颜色(如果需要)。

简而言之,我的算法如下所示:

     //videoFrame is IplImage, 8 bit, 4 channel
     for(int i=0;i<videoFrame.width;i++){
        for(int j=0;j<videoFrame.height;j++){

            CvScalar pixel = cvGet2D(&videoFrame, i, j);

            double red = pixel.val[0];
            double green = pixel.val[1];
            double blue = pixel.val[2];

            //do some math


            if (someCondition) {
                cvSet2D(&videoFrame, i, j, white);
            }
        }       
    }

但是我发现调用cvGet2D(&videoFrame, i, j);cvSet2D(&videoFrame, i, j, white);非常昂贵(慢)。是否有更快的方法可以访问每个像素的红/绿/蓝值?

谢谢!

4 个答案:

答案 0 :(得分:2)

尝试使用指针直接访问数据,如下所示。

for(int i=0;i<videoFrame.width;i++){
  for(int j=0;j<videoFrame.height;j++){
    uchar B =((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 0];                      
    uchar G =((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 1];       
    uchar R =((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 2];       


    //do some math

    ((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 0] = B;
    ((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 1] = G;
    ((uchar *)(videoFrame.imageData + j*videoFrame.widthStep))[i*videoFrame.nChannels + 2] = R;

  }
}

答案 1 :(得分:2)

这里提供的答案

Pixel access in OpenCV 2.2

Etarion(用于新界面,使用Mat)和Andrew(用于IplImage,就像你的情况一样)比johnlinvc提供的示例更清晰,更快,因为它们消除了所有不必要的强制转换并按行顺序访问像素,最小化缓存未命中。

它们适用于一般情况,即使对于感兴趣的区域(子矩阵)也是如此。

答案 2 :(得分:1)

除了johnlinvc的答案之外,交换ij的迭代可能是一个好主意,因此您可以连续访问图像元素,因为OpenCV以行主要顺序存储图像。

答案 3 :(得分:1)

由于运行时查找导致效率低下的一般方法是将该查找移动到编译时。

定义像素迭代器模板。在循环之前,甚至在帧生成之前,获得对应于帧图像的特征的像素迭代器。然后使用该迭代器进行像素访问。

大多数情况下,您可以使用纯顺序访问。确保实现迭代器,以便逻辑顺序访问对应于原始字节级别的顺序访问。这有助于(而不是当前代码与硬件的缓存策略不兼容)。