7

I am confused about the use of number of channels. Which one is correct of the following?

// roi is the image matrix

for(int i = 0; i < roi.rows; i++)
{
    for(int j = 0; j < roi.cols; j+=roi.channels())
    {
        int b = roi.at<cv::Vec3b>(i,j)[0];
        int g = roi.at<cv::Vec3b>(i,j)[1];
        int r = roi.at<cv::Vec3b>(i,j)[2];
        cout << r << " " << g << " " << b << endl ;
    }
}

Or,

for(int i = 0; i < roi.rows; i++)
{
    for(int j = 0; j < roi.cols; j++)
    {
        int b = roi.at<cv::Vec3b>(i,j)[0];
        int g = roi.at<cv::Vec3b>(i,j)[1];
        int r = roi.at<cv::Vec3b>(i,j)[2];
        cout << r << " " << g << " " << b << endl ;
    }
}
Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91
Barshan Das
  • 3,677
  • 4
  • 32
  • 46
  • 8
    Second is correct. Check docs for details – Sam Nov 26 '12 at 15:19
  • see more [Ans 1](http://stackoverflow.com/questions/8932893/accessing-certain-pixel-rgb-value-in-opencv?rq=1) and [Ans 2](http://stackoverflow.com/questions/4742251/pixel-access-in-opencv-2-2) – Nikson Kanti Paul Apr 16 '13 at 10:35

3 Answers3

2

the second one is correct, the rows and cols inside the Mat represents the number of pixels, while the channel has nothing to do with the rows and cols number. and CV use BGR by default, so assuming the Mat is not converted to RGB then the code is correct

reference, personal experience, OpenCV docs

ypx
  • 1,459
  • 11
  • 19
azwald
  • 31
  • 3
1

A quicker way to get color components from an image is to have the image represented as an IplImage structure and then make use of the pixel size and number of channels to iterate through it using pointer arithmetic.

For example, if you know that your image is a 3-channel image with 1 byte per pixel and its format is BGR (the default in OpenCV), the following code will get access to its components:

(In the following code, img is of type IplImage.)

for (int y = 0; y < img->height; y++) {
    for(int x = 0; x < img->width; x++) {
        uchar *blue = ((uchar*)(img->imageData + img->widthStep*y))[x*3];
        uchar *green = ((uchar*)(img->imageData + img->widthStep*y))[x*3+1];
        uchar *red = ((uchar*)(img->imageData + img->widthStep*y))[x*3+2];
    }
}

For a more flexible approach, you can use the CV_IMAGE_ELEM macro defined in types_c.h:

/* get reference to pixel at (col,row),
   for multi-channel images (col) should be multiplied by number of channels */
#define CV_IMAGE_ELEM( image, elemtype, row, col )       \
    (((elemtype*)((image)->imageData + (image)->widthStep*(row)))[(col)])
Daniel Martín
  • 7,815
  • 1
  • 29
  • 34
  • What makes you think this isn't **exactly** what gets compiled from his 2nd example? – Christian Rau Apr 16 '13 at 13:22
  • 1
    Stop using the old IplImage implementation. The 'second' example is valid. The 2nd example, however, is not super fast, but very readable. What you can do for speed up is first split the channels and then read out using pointers. Or, if you're smarter, use pointers immediatelly by taking in account the step size and bitsize. – TimZaman Jan 09 '14 at 14:08
0

I guess the 2nd one is correct, nevertheless it is very time consuming to get the data like that.

A quicker method would be to use the IplImage* data structure and increment the address pointed with the size of the data contained in roi...

Julien Greard
  • 969
  • 1
  • 12
  • 32
  • 1
    *"it is very time consuming to get the data like that. A quicker method would be to use the `IplImage*` data structure and increment the address pointed with the size of the data contained in roi"* - Are you sure about that? Shouldn't make any significant difference (if any difference at all). Those methods will all get inlined, anway. – Christian Rau Apr 16 '13 at 11:18
  • I think that when you try to access to element i,j, openCV will calculate the position of the element in the memory and return it (based on the width, nb of channels and size of each matrix element). This computation (done width * height times) is more time consuming than adding 8 bits to the address you're working with. – Julien Greard Apr 16 '13 at 13:06
  • Not sure this really matters, let aside from the compiler being smart enough for that. But ok, might very well be, but then again, using a pointer to `cv::Vec3b` data and increasing that by 1 shouldn't be any different either, no need for any `IplImage`s. You cannot cross the row boundary with this anyway, since rows don't need to be contiguous in OpenCV (and this holds for `cv::Mat`s the same like for `IplImage`s). So the nested loop is still there, but Ok you could optimize out the multiplication by `widthStep` like you said (if the compiler doesn't do it). – Christian Rau Apr 16 '13 at 13:20