Reputation: 3941
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:
_a
have 1 channel the first element of _b
should be assigned in the respective position_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 positionUpvotes: 0
Views: 2999
Reputation: 1025
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]);
Upvotes: 0
Reputation: 824
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;
}
}
Upvotes: 0
Reputation: 11329
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;
Upvotes: 1