OpenCV使用imread将RGB图像转换为灰度图像效果差劲

17

我从PNG文件中加载了一张24比特RGB图像到我的OpenCV应用程序中。

然而,如果直接使用imread以灰度方式加载图像,则结果非常糟糕。

Mat src1 = imread(inputImageFilename1.c_str(), 0);

将RGB图像作为RGB加载并将其转换为灰度图像可以得到更好的效果。

Mat src1 = imread(inputImageFilename1.c_str(), 1);
cvtColor(src1, src1Gray, CV_RGB2GRAY);

我在想我是否正确地使用了imread来处理我的图像类型。有人遇到过类似的问题吗?

这里展示了使用imread转换为灰度图像的图像: 错误结果

这里展示了使用cvtColor转换为灰度图像的图像: 正确结果


6
在OpenCV中,“Color”图像表示为BGR格式。因此,您代码的第二个版本是不正确的。应该使用CV_BGR2GRAY进行颜色转换。 - Andrey Kamaev
感谢您的评论。我尝试使用CV_BGR2GRAY而不是CV_RGB2GRAY将图像转换为灰度,但结果相同。 - tisch
您能否同时附上您的原始图片? - Andrey Kamaev
感谢提示。原始图像位于此处:https://picasaweb.google.com/lh/photo/F8iLVPIuFR5LiZJVe9sAqmfnfsOOxMA_38d73O1A0AM?feat=directlink - tisch
有没有特别的原因,使得灰度的PNG图像不能保存为灰度PNG图像? - Antonio
显示剩余6条评论
3个回答

20

今天我也遇到了同样的问题。最终,我比较了三种方法:

//method 1
cv::Mat gs = cv::imread(filename, CV_LOAD_IMAGE_GRAYSCALE);

//method 2
cv::Mat color = cv::imread(filename, 1); //loads color if it is available
cv::Mat gs_rgb(color.size(), CV_8UC1);
cv::cvtColor(color, gs_rgb, CV_RGB2GRAY);

//method 3
cv::Mat gs_bgr(color.size(), CV_8UC1);
cv::cvtColor(color, gs_bgr, CV_BGR2GRAY);

方法1(加载灰度图像)和方法3(CV_BGR2GRAY)产生相同的结果,而方法2产生不同的结果。出于自己的目的,我已经开始使用CV_BGR2GRAY。

我的输入文件是jpg格式,因此可能会涉及到特定图像格式的问题。


1
Opencv的imread函数返回BGR格式的图像,因此我认为正确的转换为灰度应该是CV_BGR2GRAY,就像你在第三种方法中提到的那样。 - evk1206

10

简单地说,openCV函数使用BGR格式。如果您使用imreadVideoCapture读取图像,它将始终为BGR格式。如果您使用RGB2GRAY,则会将蓝色通道与绿色通道互换。获取亮度的公式为

y = 0.587*green + 0.299*red + 0.114*blue

如果您更改绿色和蓝色,这将导致巨大的计算错误。

问候


1
那么这不也交换了红色通道吗?在这种情况下,将给定的“BGR”解释为“RGB”,这会导致(实际上的)“B”被错误地解释为“R”,而“R”则被解释为“B”?因此,根据您的答案,修复方法是将cvtColor调用中的CV_RGB2GRAY替换为CV_BGR2GRAY - Mark Gaensicke

1
我曾经遇到过类似的问题,与OpenGL着色器一起工作。似乎OpenCV读取图像时使用的第一个容器不支持所有颜色范围,因此您会看到图像是质量较差的灰度转换。但是,一旦您使用cvtColor将原始图像转换为灰度,第一个容器就不同了,并且支持所有范围。在我看来,第一个容器对灰度使用少于8位,或者转换为灰度使用了不好的方法。但第二个容器在灰度通道中具有更多位数,因此可以得到平滑的图像。

你找到支持这个推理的文档了吗?我遇到了类似的问题,我倾向于相信这可能是原因,但无法找到任何确凿的证据来支持我的推理。 - Ani
这是因为帧缓冲区对于每种颜色和单色光谱都包含了255的范围。你需要浮点数来支持更好的范围。 - Amir Zadeh

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