为什么打开和显示此图像时颜色会完全改变?如何将 ICC 配置文件添加到图像?

问题描述

这是原图:

Original image

这是我打开并用枕头展示后的图像:

Image opened in Pillow

原始图像是 JPEG,但我尝试将格式更改为 TIFF、PSD,但没有任何效果。我尝试将图像转换为 RGB、RGBA、CMYK,但没有看到任何改进。

如果我只是简单地截取图片,然后在 Pillow 中打开它,颜色就会保留。

然后我想我可能不需要 Pillow,我可以使用另一个库,并尝试了 OpenCV,但发生了同样的事情!结果与上图相同。

正如@HansHirse 在我上一个问题的评论中所建议的那样,这篇文章让我意识到,当我刚刚保存图像时,颜色会被保留。 (尽管只是在不使用 ICC 配置文件的情况下打开和保存,但无论如何都会生成准确的图像。)

from PIL import Image

i = Image.open("/Users/shashwataryal/Downloads/Tom Ford Rodeo.jpeg")

##Colours are preserved when I just save the image immediately after opening.
i.save("/Users/shashwataryal/Downloads/1.jpeg")

##however,if I create a new image and paste my image I have the same issue.
##The image is very saturated. (not dull like in the question @HansHirse suggested in my prevIoUs post)
layer = Image.new('RGB',i.size,"#faf8f8")
layer.show()
layer.paste(i)
layer.show()
layer.save('/Users/shashwataryal/Downloads/1.jpeg',icc_profile=i.info.get('icc_profile'))
layer.save('/Users/shashwataryal/Downloads/2.jpeg',icc_profile=i.info.get('icc_profile'))

我正在尝试将图像添加到新的空白枕头图像中,并且可能还添加其他图像。我不知道如何将 ICC 配置文件添加到新图像。如果我将它们粘贴到 Pillow 中创建的新图像上,是否会影响其他图像?

我之前的问题被标记为重复:

Color gets dull: opencv cv2.imread cv2.imwrite

虽然这个问题很相似,但它只是处理打开后立即保存图像,打开后立即保存它没有问题。我的问题是将它粘贴到一个大的空白画布上后保存它。

解决方法

您需要 Pillow 的 ImageCms 模块:

ImageCms 模块提供颜色配置文件管理支持 [...]

对于以下演示代码,我使用了来自 here 的具有不同嵌入式 ICC 配置文件的示例图像。

from matplotlib import pyplot as plt
from PIL import Image,ImageCms
from io import BytesIO

# Infices for test image
infices = ['sRGB','AdobeRGB','ColorMatch','ProPhoto','WideRGB']

# Initialize output visualization
plt.figure(1,figsize=(19,9))

# Iterate infices
for i_infix,infix in enumerate(infices,start=1):

    # Read image
    image = Image.open('Momiji-{}-yes.jpg'.format(infix))

    # Extract original ICC profile
    orig_icc = ImageCms.ImageCmsProfile(BytesIO(image.info.get('icc_profile')))
    desc = ImageCms.getProfileDescription(orig_icc)

    # Plot image with original ICC profile
    plt.subplot(2,len(infices),i_infix),plt.imshow(image)
    plt.title('Original ICC profile: {}'.format(desc))

    # Create sRGB ICC profile and convert image to sRGB
    srgb_icc = ImageCms.createProfile('sRGB')
    image = ImageCms.profileToProfile(image,orig_icc,srgb_icc)

    # Plot converted image with sRGB ICC profile
    plt.subplot(2,len(infices) + i_infix),plt.imshow(image)
    plt.title('sRGB ICC profile')

plt.tight_layout(),plt.show()

该代码提取每个示例图像的 ICC 配置文件,并将其存储为 CmsProfile 对象。使用 ImageCms.createProfile,您可以创建一个内置的 sRGB ICC 配置文件,我用它来使用 ImageCms.profileToProfile 校正所有输入图像:

Output sRGB

如您所见,输入图像具有非常显着的颜色差异,而输出图像非常相似(我没有检查像素相等性)。

如果您想保留特定输入图像的 ICC 配置文件,您可以在开始时简单地保存它,然后纠正所有输入图像 w.r.t.该ICC配置文件。例如,这将是将所有输入图像转换为“ProPhoto RGB”ICC 配置文件的输出:

ProPhoto RGB

因此,您需要打开图像,提取 ICC 配置文件,将图像粘贴到新的空白画布,然后将生成的图像转换为保存的 ICC 配置文件。如果您有来自不同来源的图像,因此可能有不同的嵌入 ICC 配置文件,您需要决定做什么:(1)纠正所有输入图像,如上所示,合并可能的颜色差异或(2)实际转换颜色您的输入图像,使它们具有相同的外观,但使用最终结果的 ICC 配置文件。后者将是一个单独的主题。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.1
Matplotlib:    3.4.2
Pillow:        8.2.0
----------------------------------------