Доступ к определенному значению RGB пикселя в openCV

Я искал интернет и stackoverflow полностью, но я не нашел ответа на свой вопрос:

Как я могу получить/установить (оба) значение RGB определенных (заданных координатами x, y) в OpenCV? Что важно - я пишу на С++, изображение хранится в переменной cv:: Mat. Я знаю, что есть оператор IplImage(), но IplImage не очень удобен в использовании - насколько я знаю, он исходит из C API.

Да, я знаю, что уже был этот пиксельный доступ в OpenCV 2.2, но он был только о черно-белых растровых изображениях.

EDIT:

Большое спасибо за все ваши ответы. Я вижу, что есть много способов получить/установить значение RGB пикселя. У меня есть еще одна идея от моего близкого друга - спасибо Бенни! Это очень просто и эффективно. Я думаю, что это вопрос вкуса, который вы выбираете.

Mat image;

(...)

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

И затем вы можете читать/записывать значения RGB с помощью:

p->x //B
p->y //G
p->z //R

Ответ 1

Попробуйте следующее:

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

image.at<cv::Vec3b>(y,x); дает вам вектор RGB (он может быть заказан как BGR) типа 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];

Ответ 2

Низкоуровневым способом будет прямой доступ к данным матрицы. В RGB-изображении (которое, как я полагаю, OpenCV обычно хранит как BGR), и, предполагая, что ваша переменная cv :: Mat называется frame, вы можете получить значение синего в местоположении (x, y) (слева вверху) следующим образом:

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

Аналогично, чтобы получить B, G и 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];

Обратите внимание, что этот код предполагает, что шаг равен ширине изображения.

Ответ 3

Часть кода проще для людей, у которых есть такая проблема. Я делюсь своим кодом, и вы можете использовать его напрямую. Обратите внимание: OpenCV сохраняет пиксели как 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.
}

Ответ 4

Текущая версия позволяет функции cv::Mat::at обрабатывать 3 измерения. Итак, для объекта Mat m, m.at<uchar>(0,0,0) должен работать.

Ответ 5

uchar * value = img2.data; //Pointer to the first pixel data ,it 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++;
}

Ответ 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;  
}