OpenCV中的imwrite在处理JPEG图像时会产生颜色失真的结果

7

我正在使用OpenCV 3.0,每当我读取一张图像并将其写回时,结果是一张褪色的图像。

代码:

cv::Mat img = cv::imread("dir/frogImage.jpg",-1);
cv::imwrite("dir/result.jpg",img);

有人知道这是什么原因导致的吗?

原文: enter image description here

结果: enter image description here


2
@HumamHelfawi 请检查代码。 - zindarod
1
欢迎来到有损压缩和无损压缩的区别。为了获得100%相同的图像数据,请保存为.png或其他无损压缩技术。 - Micka
你可以尝试添加jpeg压缩的图像质量信息。据我所知,在OpenCV中,如果没有手动指定,它的压缩率为95%。因此,将其增加到100%可能会给您带来预期的结果(但是在OpenCV中,您无法获得有关图像原始jpeg压缩质量的信息)。毕竟,我仍然相信迭代加载+保存jpeg图像(而不更改图像本身)可能会添加额外的压缩伪影。请记住,OpenCV不是用于“图像编辑”,而是用于“计算机视觉”,因此您不会找到所需的标签和质量信息。 - Micka
也可以看看这个:http://petapixel.com/2010/02/04/saving-jpeg-photos-hundreds-of-times/ - Micka
1
@Zindarod,如果我将您的两张图片保存到我的电脑上并使用IrfanView打开它们,它们看起来完全相同。但是在浏览器中它们看起来不同,所以可能存在某种奇怪的元信息或非典型的JPEG格式?! - Micka
显示剩余8条评论
3个回答

4
您可以尝试增加压缩质量参数,如OpenCV文档中的cv::imwrite所示:
cv::Mat img = cv::imread("dir/frogImage.jpg",-1);

std::vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(100);

cv::imwrite("dir/result.jpg",img, compression_params);

如果没有手动指定压缩质量,将应用95%的质量。

但是,1.您不知道原始图像的jpeg压缩质量(因此可能会增加图像大小),2.它仍然会引入额外的轻微伪影,因为毕竟这是一种有损压缩方法。

更新:您的问题似乎不是由于压缩伪影,而是由于使用了Adobe RGB 1998颜色格式的图像。OpenCV根据实际情况解释颜色值,但实际上应该将颜色值缩放到“真实”的RGB颜色空间中。浏览器和一些图像查看器正确应用颜色格式,而其他一些则不会(例如irfanView)。我使用GIMP进行验证。使用GIMP,您可以在启动时决定如何按格式解释颜色值,无论是获取所需的还是获取“褪色”的图像。OpenCV绝对不关心这些事情,因为它不是一个照片编辑库,因此在读取或写入时,都不会处理颜色格式。


1
这是正确的,但如果您必须向下滚动整个屏幕才能看到第二张图片,那就不是了 ;) - Micka
上次我检查过,即使质量达到100%,它仍然是有损的。 - Miki
@Micka 嗯,奇怪...听起来很有趣。 - Miki
1
第一张图片采用Adobe RGB 1998色彩空间。https://en.wikipedia.org/wiki/RGB_color_space - Micka
1
@Micka 问题实际上是由于不同的颜色空间。我通过使用Magick ++ sdk并将AdobeRGB1998颜色空间转换为sRGB颜色空间来解决了这个问题。谢谢您的时间。 - zindarod
显示剩余9条评论

2
这是因为你将图像保存为JPG格式。在这种情况下,OpenCV会压缩图像。 尝试将其保存为PNG或BMP格式,就不会有任何差别了。
然而,重要的问题是:我正在以jpg格式加载图像并将其保存为JPG格式。那么,为什么会有区别?!
是的,这是因为JPG格式存在许多不同的压缩/解压算法。
如果你想深入了解一些细节,请参考这个问题: 在OpenCV和C# Bitmap中读取jpg文件
编辑: 您可以在这里确切地看到我的意思:
auto bmp(cv::imread("c:/Testing/stack.bmp"));
cv::imwrite("c:/Testing/stack_OpenCV.jpg", bmp);
auto jpg_opencv(cv::imread("c:/Testing/stack_OpenCV.jpg"));

auto jpg_mspaint(cv::imread("c:/Testing/stack_mspaint.jpg"));
cv::imwrite("c:/Testing/stack_mspaint_opencv.jpg", jpg_mspaint);
jpg_mspaint=(cv::imread("c:/Testing/stack_mspaint_opencv.jpg"));

cv::Mat jpg_diff;
cv::absdiff(jpg_mspaint, jpg_opencv, jpg_diff);
std::cout << cv::mean(jpg_diff);

结果: [0.576938,0.466718,0.495106,0]

1
看起来问题在于Adobe JPEG格式与OpenCV JPEG格式的渲染方式不同。因此,我取消了我的负评和之前的评论,因为这不是关于JPEG压缩产生的伪影问题。 - Miki

0

正如 @Micha 的评论所述:

cv::Mat img = cv::imread("dir/frogImage.jpg",-1);
cv::imwrite("dir/result.bmp",img);

每当 mspaint.exe 对 JPEG 图像做同样的事情时,我总是感到很烦恼。特别是对于截图...它每次都会破坏它们。


1
他可能想要使用 jpeg。也许像这样的应用程序:1. 读取图像;2. 执行一些操作;3. 以旧格式保存,但重要的是要告诉 @Zindarod,在这种情况下,对于 jpeg 图像会有额外的伪影。这就是为什么 GIMP 等使用自己的图像格式并且只通过导出来创建 jpegs/pngs 等格式的原因之一。 - Micka
@William 谢谢你,但正如Micka所说,我确实需要结果为jpg格式。 - zindarod

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