1

I am processing video frames in real time. I loop through each pixel one at a time, do some math, and then set the pixel to a specific color (if necessary).

In a nutshell, my algorithm looks like this:

     //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);
            }
        }       
    }

but i find that calls cvGet2D(&videoFrame, i, j); and cvSet2D(&videoFrame, i, j, white); are really expensive(slow). Is there an alternative faster way I can access red/green/blue value of each pixel?

Thanks!

0xSina
  • 20,973
  • 34
  • 136
  • 253

4 Answers4

2

Try accessing the data directly with pointer as following.

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;

  }
}
johnlinvc
  • 304
  • 3
  • 6
  • thanks for the input, but this doesn't work. B,G,R are registering as 'nan' or not a number – 0xSina Mar 03 '12 at 08:23
  • Sorry, I was miss leaded by you **double** type.If the IPL is having Unsigned 8-bit integer in each channel, change **double** to **char** should work – johnlinvc Mar 03 '12 at 08:39
2

The answers provided here

Pixel access in OpenCV 2.2

Etarion's (for new interface, with Mat), and Andrew's (for IplImage, like in your case) are cleaner and faster than the example provided by johnlinvc, because they eliminate all the unnecessary casts and access the pixels in row order, minimizing cache misses.

And they work for the general case, even for regions of interest (sub-matrices).

Community
  • 1
  • 1
Sam
  • 19,708
  • 4
  • 59
  • 82
1

In addition to johnlinvc's answer it might be a good idea to swap the iteration of i and j, so you can access the image elements contiguously, since OpenCV stores images in row-major order.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
1

The general cure for inefficiency due to runtime lookup, is to move that lookup to compile time.

Define a pixel iterator template. Before the looping, and perhaps even before the frame generation, obtain a pixel iterator corresponding to the characteristics of the frame images. Then use that iterator for the pixel access.

Mostly you can make do with purely sequential access. Be sure to implement the iterator so that logical sequential access corresponds to sequential access at the raw bytes level. That helps (instead of as the current code being incompatible with) the caching strategies of the hardware.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331