2012-01-19 2 views
62

Я искал интернет и тщательно StackOverflow, но я не нашел ответ на мой вопрос:Доступ к определенному пиксельному значению RGB в OpenCV

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

Да, я знаю, что уже была эта лента Pixel access in 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 

ответ

83

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

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

Можете ли вы предложить мне то же самое с использованием Ipl Image.? – Frankenstein

+1

Конечно! проверить cvGet2D http://docs.opencv.org/modules/core/doc/old_basic_structures.html?#CvScalar%20cvGet2D%28const%20CvArr%2a%20arr,%20int%20idx0,%20int%20idx1%29 – Boaz

+0

Можете ли вы Помогите мне написать то же самое с помощью IplImage ..? – Frankenstein

10

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

frame.data[frame.channels()*(frame.rows*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]; 

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

+0

Спасибо, это работает при чтении значения RGB. Я попытался установить frame.data [...] на определенные значения без везения, но решение, данное Boaz.Jan, работает. – Wookie88

+0

@aaedvarkk Удивительный, ты спас мой день! –

+0

не должно быть 'frame.data [frame.channels() * (frame.cols * y + x)];'? –

0

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

+5

На самом деле эта версия 'at' не будет работать на многоканальном Mat. Несмотря на то, что двухмерная многоканальная матрица имеет ту же схему памяти, что и трехмерная одноканальная матрица, метод будет вызывать исключение из-за различий в заголовке Mat. –

2

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

Как это отвечает на вопрос? – rayryeng

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

}

Смежные вопросы