83

I have searched internet and stackoverflow thoroughly, but I haven't found answer to my question:

How can I get/set (both) RGB value of certain (given by x,y coordinates) pixel in OpenCV? What's important-I'm writing in C++, the image is stored in cv::Mat variable. I know there is an IplImage() operator, but IplImage is not very comfortable in use-as far as I know it comes from C API.

Yes, I'm aware that there was already this Pixel access in OpenCV 2.2 thread, but it was only about black and white bitmaps.

EDIT:

Thank you very much for all your answers. I see there are many ways to get/set RGB value of pixel. I got one more idea from my close friend-thanks Benny! It's very simple and effective. I think it's a matter of taste which one you choose.

Mat image;

(...)

Point3_<uchar>* p = image.ptr<Point3_<uchar> >(y,x);

And then you can read/write RGB values with:

p->x //B
p->y //G
p->z //R
Community
  • 1
  • 1
Wookie88
  • 33,079
  • 4
  • 27
  • 32

6 Answers6

104

Try the following:

cv::Mat image = ...do some stuff...;

image.at<cv::Vec3b>(y,x); gives you the RGB (it might be ordered as BGR) vector of type cv::Vec3b

image.at<cv::Vec3b>(y,x)[0] = newval[0];
image.at<cv::Vec3b>(y,x)[1] = newval[1];
image.at<cv::Vec3b>(y,x)[2] = newval[2];
Boaz
  • 4,549
  • 2
  • 27
  • 40
  • Can you suggest me the same using Ipl Image.? – Frankenstein Jun 27 '13 at 10:14
  • 1
    Sure! check out cvGet2D http://docs.opencv.org/modules/core/doc/old_basic_structures.html?#CvScalar%20cvGet2D%28const%20CvArr%2a%20arr,%20int%20idx0,%20int%20idx1%29 – Boaz Jun 28 '13 at 20:00
  • Can you help me in writing the same using IplImage..? – Frankenstein Jul 03 '13 at 12:18
  • @Frankenstein See my comment about cvGet2D – Boaz Jul 03 '13 at 12:24
  • @Boaz.Jan What actually mean Vec3b ? it didn't give me the exact defination in documentation , i know its for 3 dimension vector , but when we need to use it , here we use it for two dimensions isn't `(y,x)`? – AHF Mar 24 '14 at 10:52
  • 2
    @Ahmad typedef Vec Vec3b; - which means a vector of 3 uchars (0-255), each component of the RGB (The R, the G and the B) are represented using a numerical value between 0 and 255. The "at" method of image, is a method of cv::Mat, a class representing a 2 dimensional matrix. Saying cv::Mat with cell type of CV_8UC3 means that each cell in the matrix will fit inside 3 channels of 8 bits each, by saying image.at – Boaz Mar 25 '14 at 16:21
  • @Ahmad Thus making "image.at(y,x)[0]" be "Get the cell X,Y in the matrix mat as a vector of 3 uchars and then choose the first vector element" - returning the "B" color channel of the BGR cell (As said in the original answer, openCV represent RBG as BGR - it re-orders the channel order). the "(y,x)" applys to the Mat & the "[0]" applys to the Vec3b. See http://en.cppreference.com/w/cpp/language/function_template – Boaz Mar 25 '14 at 16:24
  • you can also use: `image.at(y,x) = cv::Vec3b(0, 0, 255);` – 2LayerNN300HU Jan 13 '17 at 17:59
19

The low-level way would be to access the matrix data directly. In an RGB image (which I believe OpenCV typically stores as BGR), and assuming your cv::Mat variable is called frame, you could get the blue value at location (x, y) (from the top left) this way:

frame.data[frame.channels()*(frame.cols*y + x)];

Likewise, to get B, G, and R:

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];

Note that this code assumes the stride is equal to the width of the image.

Autonomous
  • 8,935
  • 1
  • 38
  • 77
aardvarkk
  • 14,955
  • 7
  • 67
  • 96
2

A piece of code is easier for people who have such problem. I share my code and you can use it directly. Please note that OpenCV store pixels as BGR.

cv::Mat vImage_; 

if(src_)
{
    cv::Vec3f vec_;

    for(int i = 0; i < vHeight_; i++)
        for(int j = 0; j < vWidth_; j++)
        {
            vec_ = cv::Vec3f((*src_)[0]/255.0, (*src_)[1]/255.0, (*src_)[2]/255.0);//Please note that OpenCV store pixels as BGR.

            vImage_.at<cv::Vec3f>(vHeight_-1-i, j) = vec_;

            ++src_;
        }
}

if(! vImage_.data ) // Check for invalid input
    printf("failed to read image by OpenCV.");
else
{
    cv::namedWindow( windowName_, CV_WINDOW_AUTOSIZE);
    cv::imshow( windowName_, vImage_); // Show the image.
}
Java Devil
  • 10,629
  • 7
  • 33
  • 48
ShannonLiu
  • 101
  • 1
  • 1
0
uchar * value = img2.data; //Pointer to the first pixel data ,it's return array in all values 
int r = 2;
for (size_t i = 0; i < img2.cols* (img2.rows * img2.channels()); i++)
{

        if (r > 2) r = 0;

        if (r == 0) value[i] = 0;
        if (r == 1)value[i] =  0;
        if (r == 2)value[i] = 255;

        r++;
}
karlphillip
  • 92,053
  • 36
  • 243
  • 426
Saef Myth
  • 143
  • 1
  • 2
  • 11
0

The current version allows the cv::Mat::at function to handle 3 dimensions. So for a Mat object m, m.at<uchar>(0,0,0) should work.

Jacob
  • 34,255
  • 14
  • 110
  • 165
  • 5
    Actually this version of `at` will not work on multichannel Mat. Despite the fact that 2-dimentional multichannel Mat has the same memory layout as 3-dimentional single-channel Mat, method will throw exception because of differences in Mat header. – Andrey Kamaev Jan 19 '12 at 21:46
-6
const double pi = boost::math::constants::pi<double>();

cv::Mat distance2ellipse(cv::Mat image, cv::RotatedRect ellipse){
    float distance = 2.0f;
    float angle = ellipse.angle;
    cv::Point ellipse_center = ellipse.center;
    float major_axis = ellipse.size.width/2;
    float minor_axis = ellipse.size.height/2;
    cv::Point pixel;
    float a,b,c,d;

    for(int x = 0; x < image.cols; x++)
    {
        for(int y = 0; y < image.rows; y++) 
        {
        auto u =  cos(angle*pi/180)*(x-ellipse_center.x) + sin(angle*pi/180)*(y-ellipse_center.y);
        auto v = -sin(angle*pi/180)*(x-ellipse_center.x) + cos(angle*pi/180)*(y-ellipse_center.y);

        distance = (u/major_axis)*(u/major_axis) + (v/minor_axis)*(v/minor_axis);  

        if(distance<=1)
        {
            image.at<cv::Vec3b>(y,x)[1] = 255;
        }
      }
  }
  return image;  
}
user537723
  • 93
  • 1
  • 9