简体   繁体   中英

Access R,G and B pixel values using a pointer to image data

I have read an image in Mat format.

Mat image = imread("image.png", 1);

I declare a pointer to its data using

unsigned char *ptr_source = image.data

Now, I want to access the value of R,G and B values at each pixel in a for loop . I already know the method to do it with img.at<Veb3b>(i,j) or similar things but now, I have to do it using a pointer of unsigned char type.

uchar R_value = ptr_source[ i*?? + ??? ];
uchar G_value = ptr_source[ i*?? + ??? ];
uchar B_value = ptr_source[ i*?? + ??? ];

IMPORTANT: Some people here have mentioned to use the following:

unsigned char *input = (unsigned char*)(img.data);
for(int j = 0;j < img.rows;j++){
    for(int i = 0;i < img.cols;i++){
        unsigned char b = input[img.step * j + i ] ;
        unsigned char g = input[img.step * j + i + 1];
        unsigned char r = input[img.step * j + i + 2];
    }
}

which makes sense to me as per the openCV docs but unfortunately it is not working in my case. The other method posted at SO says to use the following:

uchar b = frame.data[frame.channels()*(frame.cols*y + x) + 0];    
uchar g = frame.data[frame.channels()*(frame.cols*y + x) + 1];
uchar r = frame.data[frame.channels()*(frame.cols*y + x) + 2];

Basic Question: Though, it seems to be working but I do not understand it logically. Why do we need to multiply (frame.cols*y + x) with frame.channels() ??

The cv::Mat::channels() method returns the number of channels in an image.
In a 8UC3 three-channel color image, channels() returns 3, and the pixels are stored in consecutive byte-triplets: BGRBGRBGRBGRBGR... .

To access pixel (x,y) given a unsigned char* ptr_source pointer, you need to calculate the pixel offset. The image width is frame.cols . Each pixel is channels() == 3 bytes, so the pixel's unsiged char* offset will be ptr_source + frame.channels()*(frame.cols*y + x) . This unsigned char* would usually be the blue channel with the following 2 char s the green and red.

For example, given a 3x4 image, the pixels in memory would look like this (spaces for clarity only):

r\c  0   1   2   
 0  BGR BGR BGR
 1  BGR BGR BGR
 2  BGR>BGR<BGR
 3  BGR BGR BGR

So if you count bytes you'll see that the blue channel byte of pixel (1,2) is exactly at byte offset 3*(2*3+1) = 21

It is actually advisable to use img.step instead of the raw computation since some images have padding at the end of each pixel row so that it is not always true that img.step[0] == img.channels()*img.cols .
In this case you should use ptr_source[img.step[0]*y + img.channels()*x] .

Additionally, your question assumes that the pixel depth is 8U which may not be correct for all images. If it is not, you will need to multiply everything by the depth (bytes per pixel) as well.
And this is essentially what cv::Mat:at<> does...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM