How would I be able to cycle through an image using opencv as if it were a 2d array to get the rgb values of each pixel? Also, would a mat be preferable over an iplimage for this operation?
-
Possible duplicate: http://stackoverflow.com/questions/998429/opencv-accessing-and-taking-the-square-root-of-pixels – Eugen Constantin Dinca Dec 21 '10 at 23:26
-
I am just going to use this little function I found. float pixval32f( IplImage* img, int r, int c ) { return ( (float*)(img->imageData + img->widthStep*r) )[c]; } – a sandwhich Dec 22 '10 at 01:06
-
http://stackoverflow.com/questions/3859222/c-negative-rgb-values-of-pixels-using-opencv/3860920#3860920 – karlphillip Dec 22 '10 at 12:59
-
http://stackoverflow.com/questions/3851604/c-access-violation-using-opencv-to-get-rgb-value-of-pixel/3851670#3851670 – karlphillip Dec 22 '10 at 13:00
7 Answers
cv::Mat
is preferred over IplImage
because it simplifies your code
cv::Mat img = cv::imread("lenna.png");
for(int i=0; i<img.rows; i++)
for(int j=0; j<img.cols; j++)
// You can now access the pixel value with cv::Vec3b
std::cout << img.at<cv::Vec3b>(i,j)[0] << " " << img.at<cv::Vec3b>(i,j)[1] << " " << img.at<cv::Vec3b>(i,j)[2] << std::endl;
This assumes that you need to use the RGB values together. If you don't, you can uses cv::split to get each channel separately. See etarion's answer for the link with example.
Also, in my cases, you simply need the image in gray-scale. Then, you can load the image in grayscale and access it as an array of uchar.
cv::Mat img = cv::imread("lenna.png",0);
for(int i=0; i<img.rows; i++)
for(int j=0; j<img.cols; j++)
std::cout << img.at<uchar>(i,j) << std::endl;
UPDATE: Using split to get the 3 channels
cv::Mat img = cv::imread("lenna.png");
std::vector<cv::Mat> three_channels = cv::split(img);
// Now I can access each channel separately
for(int i=0; i<img.rows; i++)
for(int j=0; j<img.cols; j++)
std::cout << three_channels[0].at<uchar>(i,j) << " " << three_channels[1].at<uchar>(i,j) << " " << three_channels[2].at<uchar>(i,j) << std::endl;
// Similarly for the other two channels
UPDATE: Thanks to entarion for spotting the error I introduced when copying and pasting from the cv::Vec3b example.

- 10,822
- 13
- 58
- 82
-
1
-
1
-
I got to this question and it solved a problem I had, but now I have the question, why does ::at
work? why doesnt it work with the at alone? like at(0,0)? – lesolorzanov Nov 28 '11 at 03:55 -
-
This is one of the most useful posts for OpenCV beginners ever. Would be perfect if it had some additional info on how to cycle trough that same Mat as if it was a 1D matrix. But I guess that was not the question... – Void Sep 17 '13 at 12:06
-
@DatChu you mention getting non-integer values for the image. When I run the first code example above, I get output like `+ > H`. Do you know any reason for this? – Linell Oct 20 '13 at 20:19
-
I would not know unless you put your code. Perhaps make another question here on StackOverflow? – Dat Chu Oct 21 '13 at 16:41
-
Since OpenCV 3.0, there are official and fastest way to run function all over the pixel in cv::Mat.
void cv::Mat::forEach (const Functor& operation)
If you use this function, operation is runs on multi core automatically.
Disclosure : I'm contributor of this feature.

- 362
- 4
- 8
-
if this would only solve the problem, the user of the library actually would rather have not to deal with the types. Maybe I don't get it, but somehow it is really tedious to "simply" read out pixels or modify them!!! – Arwed Mett Nov 22 '17 at 22:37
-
2Please update the tutorial https://docs.opencv.org/3.4/db/da5/tutorial_how_to_scan_images.html to describe this as well! – gokul_uf Jul 31 '18 at 15:23
If you use C++, use the C++ interface of opencv and then you can access the members via http://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#the-efficient-way or using cv::Mat::at(), for example.

- 16,935
- 4
- 43
- 66
-
Thank you for the link! Looks similar to QImage::scanLine, just what I wanted. – Valentin H Dec 22 '12 at 14:01
-
This is an old question but needs to get updated since opencv is being actively developed. Recently, OpenCV has introduced parallel_for_ which complies with c++11 lambda functions. Here is the example
parallel_for_(Range(0 , img.rows * img.cols), [&](const Range& range){
for(int r = range.start; r<range.end; r++ )
{
int i = r / img.cols;
int j = r % img.cols;
img.ptr<uchar>(i)[j] = doSomethingWithPixel(img.at<uchar>(i,j));
}
});
This is mention-worthy that this method uses the CPU cores in modern computer architectures.

- 1,474
- 16
- 34
Since OpenCV 3.3 (see changelog) it is also possible to use C++11 style for loops:
// Example 1
Mat_<Vec3b> img = imread("lena.jpg");
for( auto& pixel: img ) {
pixel[0] = gamma_lut[pixel[0]];
pixel[1] = gamma_lut[pixel[1]];
pixel[2] = gamma_lut[pixel[2]];
}
// Example 2
Mat_<float> img2 = imread("float_image.exr", cv::IMREAD_UNCHANGED);
for(auto& p : img2) p *= 2;

- 1,554
- 17
- 16
The docs show a well written comparison of different ways to iterate over a Mat image here.
The fastest way is to use C style pointers. Here is the code copied from the docs:
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));
int channels = I.channels();
int nRows = I.rows;
int nCols = I.cols * channels;
if (I.isContinuous())
{
nCols *= nRows;
nRows = 1;
}
int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr<uchar>(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I;
}
Accessing the elements with the at is quite slow.
Note that if your operation can be performed using a lookup table, the built in function LUT is by far the fastest (also described in the docs).

- 300
- 1
- 11
If you want to modify RGB pixels one by one, the example below will help!
void LoopPixels(cv::Mat &img) {
// Accept only char type matrices
CV_Assert(img.depth() == CV_8U);
// Get the channel count (3 = rgb, 4 = rgba, etc.)
const int channels = img.channels();
switch (channels) {
case 1:
{
// Single colour
cv::MatIterator_<uchar> it, end;
for (it = img.begin<uchar>(), end = img.end<uchar>(); it != end; ++it)
*it = 255;
break;
}
case 3:
{
// RGB Color
cv::MatIterator_<cv::Vec3b> it, end;
for (it = img.begin<cv::Vec3b>(), end = img.end<cv::Vec3b>(); it != end; ++it) {
uchar &r = (*it)[2];
uchar &g = (*it)[1];
uchar &b = (*it)[0];
// Modify r, g, b values
// E.g. r = 255; g = 0; b = 0;
}
break;
}
}
}

- 11,506
- 16
- 62
- 109
-
Good point, this is what I was looking for. No need for row/col if you treat pixels independently! – Vlad Nov 28 '18 at 20:22