在openCV中访问某些像素RGB值


78

我已经彻底搜索了互联网和stackoverflow,但是没有找到我的问题的答案:

如何在OpenCV中获取/设置(由x,y坐标给出)特定像素的RGB值?重要的是-我用C ++编写,图像存储在cv :: Mat变量中。我知道有一个IplImage()运算符,但据我所知IplImage来自C API,使用起来不太舒服。

是的,我知道OpenCV 2.2线程中已经有了Pixel访问权限,但是它只涉及黑白位图。

编辑:

非常感谢您的所有回答。我看到有很多方法可以获取/设置像素的RGB值。我的密友又给我带来了一个好主意-感谢本尼!这非常简单有效。我认为这是您选择哪种口味的问题。

Mat image;

(...)

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

然后,您可以使用以下命令读取/写入RGB值:

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

Answers:


98

请尝试以下操作:

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向我建议相同的内容吗?
Frankenstein 2013年

1
当然!查看cvGet2Ddocs.opencv.org/modules/core/doc/…–
Boaz

您能帮我用IplImage ..写同样的东西吗?
Frankenstein

@Frankenstein看到我对cvGet2D的评论
Boaz

2
@Ahmad typedef Vec <uchar,3> Vec3b; -表示3个uchar(0-255)的向量,使用0到255之间的数值表示RGB的每个分量(R,G和B)。图像的“ at”方法是cv :: Mat的方法,表示二维矩阵的类。用单元格类型为CV_8UC3的cv :: Mat表示,矩阵中的每个单元格都可容纳3个通道(每个通道8位),通过说image.at <cv :: Vec3b)(y,x)我们实际上是在说-将矩阵X中的单元格X,Y作为3个uchars的向量获取。“每个向量单元代表所述通道之一
Boaz

18

低级方法是直接访问矩阵数据。在RGB图像(我相信一般的OpenCV店为BGR),并假设你的简历::垫变量称为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

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


5
实际上,此版本的at不适用于多通道Mat。尽管2维多通道Mat与3维单通道Mat具有相同的内存布局,但由于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 '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.