在openCV中访问特定像素的RGB值

83

我已经在互联网和stackoverflow上彻底搜索过,但是我没有找到答案:

如何在OpenCV中获取/设置(两者都是)给定x,y坐标的像素的RGB值?重要的是-我使用C++编写,图像存储在cv :: Mat变量中。我知道有一个IplImage()操作符,但是IplImage在使用中不是很方便-据我所知,它来自C API。

是的,我知道已经有这个Pixel access in OpenCV 2.2线程了,但它只涉及黑白位图。

编辑:

非常感谢您们的回答。我看到有很多方法可以获取/设置像素的RGB值。我从我的密友那里得到了另一个想法-感谢Benny! 它非常简单而且有效。我认为选择哪个方法只是个人口味问题。

Mat image;
抱歉,我的中文能力目前还没有达到熟练水平。
Point3_<uchar>* p = image.ptr<Point3_<uchar> >(y,x);

然后您可以使用以下方式读取/写入RGB值:

p->x //B
p->y //G
p->z //R
6个回答

104

尝试以下方法:

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

image.at<cv::Vec3b>(y,x);会返回类型为cv::Vec3b的RGB向量(它可能按BGR顺序排列)。

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

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
你能帮我用IplImage写同样的代码吗? - Frankenstein
@Boaz.Jan Vec3b实际上是什么意思?文档中没有给出确切的定义,我知道它是用于三维向量的,但是当我们需要使用它时,在这里我们将其用于二维,不是(y,x)吗? - AHF
2
@Ahmad 定义了一个名为Vec3b的数据类型,它是由三个uchar(0-255)组成的向量。RGB中的每个分量(R、G和B)都用0到255之间的数值表示。图像的“at”方法是cv::Mat类的方法,它表示一个二维矩阵。如果说cv::Mat的单元格类型为CV_8UC3,则意味着矩阵中的每个单元格将适合于每个通道为8位的3个通道。通过image.atcv::Vec3b(y,x)这句话,我们实际上是在说:“作为一个含有三个uchar的向量获取mat矩阵中的单元格(X,Y)”。每个向量单元格代表其中一个通道。 - Boaz
@Ahmad 因此,将“image.at<cv :: Vec3b>(y,x)[0]”变为“将矩阵mat中的单元格X,Y作为3个无符号字符的向量获取,然后选择第一个向量元素”-返回BGR单元格的“B”颜色通道(如原始答案所述,openCV将RBG表示为BGR-重新排序通道顺序)。 “(y,x)”适用于Mat,“[0]”适用于Vec3b。请参见http://en.cppreference.com/w/cpp/language/function_template。 - Boaz
显示剩余3条评论

19

一种低级的方法是直接访问矩阵数据。在一个RGB图像(我相信OpenCV通常以BGR格式存储),假设您的cv :: Mat变量名为frame,您可以通过以下方式获取位置(xy)(从左上角开始)的蓝色值:

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 真棒,你救了我的一天! - Jumabek Alikhanov
2
难道不应该是 frame.data[frame.channels()*(frame.cols*y + x)]; 吗? - Shmil The Cat

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

0
当前版本允许cv::Mat::at函数处理三维。因此,对于一个Mat对象mm.at<uchar>(0,0,0)应该可以工作。

5
实际上,这个 at 版本不能在多通道的 Mat 上使用。尽管二维多通道的 Mat 与三维单通道的 Mat 具有相同的存储布局,但由于 Mat 标头的差异,该方法将抛出异常。 - Andrey Kamaev

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

这个回答如何解决问题? - rayryeng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接