因此 png 是无损的 - 这意味着它们以某种方式压缩,因此它们代表的数据不会丢失。 因此,假设颜色深度和yadda yadda相同,从jpeg创建的png应该是像素相同的。 果然,这很容易证明,只需打开 Krita 或 GIMP,然后在像素级别手动检查 jpeg 与从 jpeg 创建的 png,读取相同任意像素的单独 RGB 值即可。
因此那么为什么我很难找到一种通过编程语言来证明这一点的方法呢? 我也在 Python 和 Go 中尝试了以下设置,结果相当 iirc。 所有这些都将显示从 jpeg 到 png 的单个 R、G 或 B 值的差异。
use image;
use std::env;
fn main() {
println!("Hello, world!");
let file1 = "image.png";
let file2 = "image.jpeg";
let img1 = image::open(file1).unwrap();
let img2 = image::open(file2).unwrap();
let img1_rgb = img1.to_rgb8();
let img2_rgb = img2.to_rgb8();
let mut img1_iter = img1_rgb.pixels();
let mut img2_iter = img2_rgb.pixels();
let mut i = 0;
let length = img1_iter.len();
while i < length {
let pixel1 = img1_iter.next();
let pixel2 = img2_iter.next();
println!("Pixel 1: {:?} Pixel 2: {:?}", pixel1, pixel2);
if pixel1 != pixel2 {
println!("Difference found: {:?}, {:?}", pixel1, pixel2);
}
println!();
i += 1;
}
}
这应该将两个图像存储为 8 位 RGB 值。 然而,当我通过 Krita 和 Gimp 考虑 jpeg 和 png 图像中的样本图像输入大部分都是纯黄色(R 和 G 255,蓝色 0)时,我的程序将报告 jpeg 为 254, 254, 0对于黄色像素。 在我的图像中发现的其他颜色也将每个颜色值偏离一位 - 有时它仅限于单个颜色值,有时它是多个颜色值(就像纯黄色的情况一样)。
这里是一个快速的 python 示例演示了相同的事情:
from PIL import Image
png = Image.open("cat.png")
jpg = Image.open("cat.jpg")
pngPixels = png.load()
jpgPixels = jpg.load()
width, height = png.size
print("Width: ", width, "Height: ", height)
for x in range(width):
for y in range(height):
if pngPixels[x,y] != jpgPixels[x,y]:
print("Discrepancy at: ", x, " y: ", y)
print("png: ", pngPixels[x,y], "jpeg: ", jpgPixels[x,y])
print()
我什至可以不做任何更改地添加这些行:
png = png.convert('RGB')
jpg = jpg.convert('RGB')
对我来说,我正在测试的所有三个编程库都不正确,这似乎很奇怪,但似乎更奇怪的是,Krita 和 GIMP 无法正确理解像素颜色之类的东西。 那么这里发生了什么?
我也尝试了从 jpeg 创建 png 的不同方法。 我尝试过从 GIMP、Krita 导出,使用不同的导出选项,甚至使用一两个命令行工具。 结果都是一样的,iirc。
我唯一的想法是,jpeg 中嵌入了一些颜色配置文件,这些库无法正确读取这些颜色配置文件,但 Krita/GIMP 仍在考虑这些颜色配置文件。 我该如何解决这个问题? 我可以采取哪些步骤来尝试解决此问题? 我知道这些图像在像素级别上确实是相同的,但我仍然想要一种通过编程问题“证明”这一点的方法。
你发现的区别是由于 JPEG 使用的有损压缩算法和用于表示颜色的不同色彩空间造成的。虽然你看到 Krita 和 GIMP 中的图像看起来相同,但这是因为这些应用程序处理颜色配置文件和在显示器上显示图像。
以下是分解发生的事情:
-
JPEG 压缩: JPEG 使用有损压缩算法,这会在一定程度上降低图像质量以减小文件大小。此过程涉及丢弃一些图像数据,这会导致解压缩图像时颜色值略有不同。
-
色彩空间: JPEG 图像通常以 YCbCr 色彩空间存储,该色彩空间将颜色信息分离成亮度(Y)和两个色差分量(Cb 和 Cr)。另一方面,PNG 使用 RGB 色彩空间。从 JPEG 到 PNG 的转换需要色彩空间转换,这可能会导致由于舍入和不同的颜色表示方法而导致轻微的颜色差异。
你用来打开和比较图像的图像库可能没有以完全相同的方式处理 JPEG 解压缩和色彩空间转换。这可能导致像素值存在细微差异,即使差异对于人眼来说并不明显。
以下是解决该问题的可能方法:
- 颜色容差: 与其比较像素的精确 RGB 值,不如使用颜色容差或阈值。这将允许颜色值存在较小的差异,考虑到由于压缩和色彩空间转换而产生的细微变化。
- 色彩空间转换: 确保在比较之前将两个图像都转换为相同的色彩空间(例如 sRGB)。这将最大程度地减少由于不同的色彩空间表示而产生的差异。
- 使用专门的图像比较库: 考虑使用专为图像比较而设计的库,例如 ImageMagick。这些库通常具有处理颜色容差、色彩空间和其他可能影响比较结果的因素的算法。
示例 Python 代码(使用颜色容差):
from PIL import Image
def compare_images(image1_path, image2_path, tolerance=3):
"""
使用给定的容差比较两个图像的像素。
Args:
image1_path (str):第一个图像的路径。
image2_path (str):第二个图像的路径。
tolerance (int):允许的颜色值差异(默认值为 3)。
Returns:
bool:如果图像在给定的容差范围内被认为相同,则为 True,否则为 False。
"""
image1 = Image.open(image1_path).convert('RGB')
image2 = Image.open(image2_path).convert('RGB')
if image1.size != image2.size:
return False
width, height = image1.size
for y in range(height):
for x in range(width):
pixel1 = image1.getpixel((x, y))
pixel2 = image2.getpixel((x, y))
for i in range(3): # 比较 RGB 值
if abs(pixel1[i] - pixel2[i]) > tolerance:
return False
return True
# 示例用法:
image1_path = "image.png"
image2_path = "image.jpeg"
if compare_images(image1_path, image2_path):
print("图像在容差范围内相同。")
else:
print("图像不同。")
这将比较两个图像的像素,允许每个 RGB 值之间存在小的差异(由
tolerance
参数定义)。通过调整容差,你可以控制比较的严格程度。