Доступ до певного піксельного значення RGB у openCV


78

Я ретельно шукав Інтернет та stackoverflow, але не знайшов відповіді на своє запитання:

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

Так, я знаю, що цей доступ до пікселів вже був у потоці OpenCV 2.2 , але мова йшла лише про чорно-білі растрові зображення.

РЕДАГУВАТИ:

Щиро дякую за всі ваші відповіді. Я бачу, що існує багато способів отримати / встановити значення RGB пікселя. Я отримав ще одну ідею від мого близького друга - дякую Бенні! Це дуже просто та ефективно. Я думаю, що справа смаку, який із них ви виберете.

Mat image;

(...)

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

І тоді ви можете читати / писати значення RGB за допомогою:

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

Відповіді:


99

Спробуйте наступне:

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

Чи можете ви запропонувати мені те саме за допомогою Ipl Image.?
Франкенштейн

1
Звичайно! перевірити cvGet2D docs.opencv.org/modules/core/doc/…
Боаз,

Чи можете ви допомогти мені написати те саме за допомогою IplImage ..?
Франкенштейн

@Frankenstein Подивіться мій коментар про cvGet2D
Боаз

2
@Ahmad typedef Vec <uchar, 3> Vec3b; - що означає вектор 3 символів (0-255), кожен компонент RGB (R, G і B) представлений числовим значенням від 0 до 255. Метод "at" зображення - це метод cv :: Mat, клас, що представляє двовимірну матрицю. Вимова cv :: Mat з типом комірки CV_8UC3 означає, що кожна комірка в матриці поміститься всередину 3-х каналів по 8 біт кожен, сказавши image.at <cv :: Vec3b) (y, x), ми фактично говоримо - Отримайте клітинку X, Y в матричній матриці у вигляді вектора 3 символів "кожна векторна комірка представляє один із зазначених каналів
Боаз

18

Низькорівневим способом буде безпосередній доступ до матричних даних. У зображенні 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];

Зверніть увагу, що цей код передбачає, що крок дорівнює ширині зображення.


Дякую, це працює при зчитуванні значення RGB. Я намагався встановити frame.data [...] для певних значень без удачі, але рішення, надане Boaz.Jan, працює.
Wookie88

@aaedvarkk Дивовижно, ти врятував мій день!
Джумабек Аліханов

2
чи не повинно бути frame.data[frame.channels()*(frame.cols*y + x)];?
Кот

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.
}

0

Поточна версія дозволяє cv::Mat::atфункції обробляти 3 виміри . Так що для Matоб'єкта m, m.at<uchar>(0,0,0)повинен працювати.


5
Насправді ця версія atне буде працювати на багатоканальному мат. Незважаючи на той факт, що двовимірний багатоканальний килимок має такий же макет пам'яті, як 3-мірний одноканальний килимок, метод видасть виняток через різницю в заголовку Mat.
Андрій Камаєв

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

-5
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;  
}

Як це відповідає на питання?
rayryeng
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.