加载和保存JPEG图像会产生不同的文件内容



下面是一个脚本,读取一个JPG图像,然后写入两个JPG图像:

import cv2
# https://github.com/opencv/opencv/blob/master/samples/data/baboon.jpg 
input_path = './baboon.jpg'
# Read image
im = cv2.imread(input_path)
# Write image using default quality (95)
cv2.imwrite('./baboon_out.jpg', im)
# Write image using best quality
cv2.imwrite('./baboon_out_100.jpg', im, [cv2.IMWRITE_JPEG_QUALITY, 100])

运行上述脚本后,文件如下:

.
├── baboon.jpg
├── baboon_out.jpg
├── baboon_out_100.jpg
└── main.py

但是,脚本创建的jpg的MD5校验和与原始的不匹配:

>>> md5 ./baboon.jpg 
MD5 (./baboon.jpg) = 9a7171af1d6c6f0901d36d04e1bd68ad
>>> md5 ./baboon_out.jpg 
MD5 (./baboon_out.jpg) = 1014782b9e228e848bc63bfba3fb49d9
>>> md5 ./baboon_out_100.jpg 
MD5 (./baboon_out_100.jpg) = dbadd2fadad900e289e285393778ad89

是否有办法保留原始图像内容与OpenCV?数据在哪一步被修改?

这是一种简化,但图像可能总是会改变校验和,如果你正在读取JPEG图像,因为它是一种有损格式,被雪崩散列重新编码和读取,如果你对它做任何有意义的工作,肯定会改变校验和,即使(特别是如果)你直接操作文件的位,而不是将其作为图像加载

如果您希望哈希值相同,只需复制该文件!

如果你正在寻找像素完美的操作,尝试像PNG这样的无损格式,并了解你是否在比较像素或元属性a-la Exif(即。你的baboon.jpg中的Google、GitHub (Microsoft)和twitter附属字段应该包括在你的比较中吗?颜色数据或深度信息呢?)

$ exiftool baboon.jpg | grep Description
Description                     : Open Source Computer Vision Library. Contribute to opencv/opencv development by creating an account on GitHub.
Twitter Description             : Open Source Computer Vision Library. Contribute to opencv/opencv development by creating an account on GitHub.

最后,在使用MD5时要特别小心,因为它在很大程度上被认为是坏的——像SHA-256这样更现代的校验和可能有助于解决不可预见的问题

对于图像的存储方式和有损/无损的含义有一个基本的误解。

让我们假设我们有一个非常简单的1像素的灰色图像,该像素的亮度为100。让我们创建自己的格式来存储图像…我将选择把它存储为Python脚本。好的,这是我们的文件:

print(100)

现在,让我们做另一个无损版本,像PNG可能:

print(10*10)

现在我们已经无损地重新创建了我们的图像,因为我们仍然得到100,但是MD5哈希显然是不同的。PNG在压缩之前进行过滤,它检查每个像素是否与上面和左边的像素相似,以节省空间。一个编码器可能会认为它可以通过查看上面的像素做得更好,另一个编码器可能会认为它可以通过查看左边的像素做得更好。结果是一样的。

现在让我们创建一个存储图像的文件的新版本:

# Updated 2022-08-12T21:15:46.544Z
print(100)

现在有一个新的注释。关于图像的元数据发生了变化,MD5散列也发生了变化。但是没有像素数据改变,所以这是一个无损的改变。PNG图像通常像这样在文件中存储日期/时间,所以即使是两个完全相同的图像,如果相隔1秒保存,对于相同的像素也会有不同的哈希值。

现在让我们把我们的单像素图像做成JPEG格式:

print(99)

根据JPEG,这看起来非常相似,并且它缩短了1字节,所以它很好。你认为MD5哈希会如何比较?

现在有一个不同的JPEG库,它认为这也很接近:

print(98)

同样,图像将与原始图像无法区分,但您的MD5哈希值将不同。


TL/博士;

如果您想要一个完全相同的、按位完美的文件副本,请使用copy命令。


进一步思考…当你用OpenCV读取图像时,你实际上得到一个Numpy像素数组,不是吗?你图片里的评论在哪里?版权?GPS定位?相机的品牌、型号和快门速度?ICC颜色配置文件?它们不在你的Numpy像素数组中,是吗?他们迷路了。因此,即使PNG/JPEG编码器使完全与原始编码器相同的决策,您的MD5散列仍然会不同,因为所有其他数据都丢失了。

最新更新