У меня есть объект cv::Mat
,
cv::Mat _a ...
... и cv::Scalar
object,
cv::Scalar _b ...
Каков правильный (лучший) способ установить значение _b
на пиксель (в позиции (x, y)) в _a
?
Обратите внимание, что объект _a
может иметь 1, 2, 3, 4 канала, но код должен работать во всех случаях, то есть:
_a
имеет 1 канал, первый элемент _b
должен быть назначен в соответствующем положении_a
имеет 2 канала, первый элемент _b
должен быть назначен первому каналу, а второй элемент _b должен быть назначен второму каналу, как в соответствующем положении cv::Mat
имеет перегруженный operator=
который принимает cv::Scalar
. Это точный характер поведения, который вы желаете. К сожалению, нет прямого способа присвоить значения Scalar
пикселям. Тем не менее, вы можете создать интересующую область, содержащую один пиксель, в координатах (x, y)
и присваивать Scalar
этому:
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;
Я бы не использовал функцию.at из opencv. Его медленно, когда вы повторяете большую картину. Получите некоторые структуры, готовые, например, для изображений RGB:
#pragma pack(push, 2)
struct RGB { //members are in "bgr" order!
uchar blue;
uchar green;
uchar red; };
Затем создайте указатель на строку сканирования изображения следующим образом:
RGB& rgb = image.ptr<RGB>(y)[x]; //y = row, x = col
Затем вы можете присвоить значения следующим образом:
cv::Scalar(image.ptr<RGB>(y)[x].value[0], image.ptr<RGB>(y)[x].value[1], image.ptr<RGB>(y)[x].value[2]);
Это не очень приятно или лаконично, но вы можете переключать возможные типы Mat
и перебирать каналы Mat
для создания/назначения Scalar
. Что-то вроде этого:
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;
}
}
Mat::at<Vec4>
и затем перебирать от 0 доMat::channels-1
Mat::at<Vec4>
Mat::channels-1
по результату, создавая / присваиваяScalar