【发布时间】:2014-12-09 12:09:59
【问题描述】:
首先,请注意我很喜欢Accessing certain pixel RGB value in openCV 和Pixel access in OpenCV 2.2。这些都不能解决我的问题。
我想做的是在 OpenCV 的IplImage 中可靠地读取/写入像素 RGB 值。到目前为止,我已经看到了这个:
uint8_t cr = CV_IMAGE_ELEM(color_img, uint8_t, y, x * color_img->nChannels + 2);
uint8_t cg = CV_IMAGE_ELEM(color_img, uint8_t, y, x * color_img->nChannels + 1);
uint8_t cb = CV_IMAGE_ELEM(color_img, uint8_t, y, x * color_img->nChannels + 0);
现在这对我来说显然是错误的。
const uint8_t *p_color_pixel = cvPtr2D(color_img, y, x, NULL);
uint8_t cr = p_color_pixel[2], cg = p_color_pixel[1], cb = p_color_pixel[0];
这仍然有点痛苦,但可能是最快的方法。也可以使用cvGet2D(),尽管这似乎还涉及将x 与频道数相乘的尴尬。
无论如何,我的问题是这些都非常“不安全”,因为图像可能是RGB 或BGR 或ARGB。此外,像素可能不是uint8_t。所以结果感觉仍然很随机,具体取决于我正在阅读的图像和格式。我实际上正在处理存储一些 24 位整数值的图像,打包到 RGB,因此正确的顺序至关重要(错误的顺序基本上会产生噪音)。到目前为止,我见过的唯一一种看起来“半安全”的方法是相当病态的,无论是代码还是性能方面:
CvSize t_image_size = cvGetSize(image);
IplImage *ir = cvCreateImage(t_image_size, 8, 1);
IplImage *ig = cvCreateImage(t_image_size, 8, 1);
IplImage *ib = cvCreateImage(t_image_size, 8, 1);
cvSplit(image, left_b, left_g, left_r, 0);
double cr = cvGetReal2D(ir, x, y),
cg = cvGetReal2D(ig, x, y), cvGetReal2D(ib, x, y);
cvReleaseImage(&ir);
cvReleaseImage(&ig);
cvReleaseImage(&ib);
我的意思是...拜托,我们是在 21 世纪,为什么要正确RGB 这么难?!
请注意,我更喜欢使用“C”接口,因为 C++ 接口目前非常不稳定。但如果 C++ 中有可靠的方法,我会接受。
【问题讨论】:
-
在c和c++中你不知道BGR/RGB是什么样的数据布局。你应该知道,从你得到图像的地方;)在 IplImages 我通常处理如下:
for(rows)for(cols)for(channels){compute array position and read pixel/channel value}(你可以在每个循环级别预先计算一个坐标的一部分) -
如果它是 RGB 而不是 BGR 和/或不是 24 位,您的“安全”代码示例也会失败?!?
-
@Micka 我认为应该在“安全”模式下正确处理颜色深度,因为使用需要执行转换的
cvGetReal2D访问像素(如果不是,那是 OpenCV 中的一个错误在那里)。确实cvSplit也需要我知道RGB的顺序,你说的没错。 -
“请注意,我更喜欢使用“C”接口,因为 C++ 接口目前非常不稳定” - 请不要。无论如何,您想要使用的过时的 c 包装器大多是围绕 c++ 功能的昂贵包装器。
-
@berak 嗯,有一个很大的代码库,使用“C”接口。我认为它不会很快消失。相反,在过去的几个
2.x版本中,C++ 接口发生了很大变化,我们不得不重写代码并将#ifdefs 到处放置。考虑到维护和兼容性,我看不出这是多么值得(如果有人试图用我们没有测试的 OpenCV 版本构建我们的代码会发生什么?)。这对我来说是不行的。也许几年后。