如何在Opencv中访问RGB值?

7

我对通道数的使用感到困惑。 以下哪个是正确的?

// roi is the image matrix

for(int i = 0; i < roi.rows; i++)
{
    for(int j = 0; j < roi.cols; j+=roi.channels())
    {
        int b = roi.at<cv::Vec3b>(i,j)[0];
        int g = roi.at<cv::Vec3b>(i,j)[1];
        int r = roi.at<cv::Vec3b>(i,j)[2];
        cout << r << " " << g << " " << b << endl ;
    }
}

或者,

for(int i = 0; i < roi.rows; i++)
{
    for(int j = 0; j < roi.cols; j++)
    {
        int b = roi.at<cv::Vec3b>(i,j)[0];
        int g = roi.at<cv::Vec3b>(i,j)[1];
        int r = roi.at<cv::Vec3b>(i,j)[2];
        cout << r << " " << g << " " << b << endl ;
    }
}

8
第二个是正确的。请查看文档以获取详细信息。 - Sam
查看更多 答案 1答案 2 - Nikson Kanti Paul
3个回答

2
第二个是正确的,Mat内部的行和列表示像素的数量,通道与行和列的数量无关。CV默认使用BGR,因此假设Mat未转换为RGB,则代码正确。
参考文献,个人经验,OpenCV文档

1
更快捷获取图像颜色分量的方法是将图像表示为一个 IplImage 结构,然后利用像素大小和通道数通过指针算术来迭代它。例如,如果您知道您的图像是一个每像素 1 字节的 3 通道图像,并且其格式为 BGR(OpenCV 中的默认格式),则以下代码将访问其组件:(在下面的代码中,img 的类型为 IplImage。)
for (int y = 0; y < img->height; y++) {
    for(int x = 0; x < img->width; x++) {
        uchar *blue = ((uchar*)(img->imageData + img->widthStep*y))[x*3];
        uchar *green = ((uchar*)(img->imageData + img->widthStep*y))[x*3+1];
        uchar *red = ((uchar*)(img->imageData + img->widthStep*y))[x*3+2];
    }
}

为了更灵活的方法,您可以使用在types_c.h中定义的CV_IMAGE_ELEM宏:

/* get reference to pixel at (col,row),
   for multi-channel images (col) should be multiplied by number of channels */
#define CV_IMAGE_ELEM( image, elemtype, row, col )       \
    (((elemtype*)((image)->imageData + (image)->widthStep*(row)))[(col)])

你为什么认为这不是从他的第二个示例编译出来的确切内容? - Christian Rau
1
停止使用旧的IplImage实现。'第二个'示例是有效的。然而,第2个示例不是超级快速的,但非常易读。为了加速,您可以首先拆分通道,然后使用指针读取。或者,如果您更聪明,请立即使用指针,考虑步长和位大小。 - TimZaman

0

我猜第二个是正确的,但是用那种方式获取数据非常耗时。

更快的方法是使用IplImage*数据结构,并通过roi中包含的数据大小递增指向的地址...


1
“以那种方式获取数据非常耗时。更快的方法是使用IplImage*数据结构,并通过roi中包含的数据大小递增指向的地址。” - 你确定吗?这不应该有任何显著差异(如果有的话)。那些方法都将被内联化。 - Christian Rau
我认为当你尝试访问元素i,j时,openCV会计算内存中该元素的位置并返回它(基于矩阵元素的宽度、通道数和大小)。这个计算(执行宽度*高度次)比将8位添加到你正在使用的地址更耗时。 - Julien Greard
不确定这真的很重要,除了编译器足够聪明之外。但好吧,可能确实如此,但是再次使用指向cv :: Vec3b数据的指针并将其增加1也不应该有任何区别,无需任何IplImage。无论如何,您无法跨越行边界,因为在OpenCV中行不需要连续(对于cv :: MatIplImage都是如此)。因此,嵌套循环仍然存在,但是您可以像您所说的那样优化乘以widthStep(如果编译器没有这样做)。 - Christian Rau

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