简体   繁体   中英

What is the correct (best) way to set the value of cv::Scalar to a pixel in a cv::Mat in opencv?

I have a cv::Mat object,

cv::Mat _a ...

... and a cv::Scalar object,

cv::Scalar _b ...

What is the correct (best) way to set the value of _b to a pixel (in the position (x, y)) in _a ?

Note that the object _a can have 1, 2, 3, 4 channels, but the code should work in all cases, that is:

  • when _a have 1 channel the first element of _b should be assigned in the respective position
  • when _a have 2 channel the first element of _b should be assigned to the first channel and the second element of _b should be assigned to the second channel, both in the respective position
  • (....)

cv::Mat has an overloaded operator= which takes a cv::Scalar . This has the exact behavior you desire. Unfortunately, there isn't a direct way to assign Scalar to pixel values. However, you can create a Region of Interest containing the single pixel at the coordinates (x, y) and assign the Scalar to that:

cv::Mat a; // contains data
cv::Scalar b(1,2,3,4);

cv::Range xr(x, x + 1);
cv::Range yr(y, y + 1);
a(xr, yr) = b;

This is not very nice or concise but you can switch the possible types of the Mat and iterate over the channels of the Mat to create/assign the Scalar . Something like this:

void getPixel(Mat m, int x, int y, Scalar &pixel) {
    switch (m.depth()) {
    case 0:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<uchar>(x, y);
        break;
    case 1:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<char>(x, y);
        break;
    case 2:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<ushort>(x, y);
        break;
    case 3:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<short>(x, y);
        break;
    case 4:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<long>(x, y);
        break;
    case 5:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<float>(x, y);
        break;
    case 6:
        for (size_t i =  0; i < m.channels(); ++i) pixel[i] = m.at<double>(x, y);
        break;
    }
}

I would not use the .at function from opencv. Its slow when you iterate through a big picture. Get some structs ready for example for RGB images:

 #pragma pack(push, 2)
  struct RGB {        //members are in "bgr" order!
     uchar blue;
     uchar green;
     uchar red;  };

And then create a pointer to the scanline of the image like this:

RGB& rgb = image.ptr<RGB>(y)[x]; //y = row, x = col

You can then assign the values like this:

cv::Scalar(image.ptr<RGB>(y)[x].value[0], image.ptr<RGB>(y)[x].value[1], image.ptr<RGB>(y)[x].value[2]);

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