PIL的image.convert("RGB")会将图像转换为sRGB还是AdobeRGB?

12

我想使用Python中的PIL批量将各种模式的图像(例如RGBa、CMYK等)转换为sRGB。

但是,我不确定并且无法找到是否

image.convert("RGB") 

将图像转换为sRGB或Adobe RGB。 我的直觉是它会转换为sRGB。

如果它转换为sRGB并且我将Adobe RGB图像传递给convert函数,它能成功转换为sRGB吗?

1个回答

25

默认情况下,PIL 对颜色空间(如 sRGB 和 Adobe RGB)是不加区分的。

你可能知道,RGB 只是红色、绿色和蓝色三个 8 位值。CMYK 是四个 8 位值。当你使用 Image.convert('RGB') 时,它只是将每个像素转换为三个 8 位值。所以它从根本上改变了图像的表示和存储方式。

另一方面,sRGB 和 Adobe RGB 只是 RGB 颜色空间。基本上,这些是在显示器、打印机或任何其他物理输出设备上呈现这三个值的规则。这些规则可以通过诸如 Photoshop 等软件以 ICC 配置文件的形式添加到 JPEG 文件中。但是 PIL 通常在你只使用 Image.save 时不会附加任何 ICC 配置文件。

为了检查图像是否嵌入了 ICC 配置文件,你可以查找字典 image.info 中的键 'icc_profile',像这样 image.info.get('icc_profile', None)

为了使用 PIL 保存保留 ICC 配置文件的 JPEG 图像,你可以使用类似以下的代码:

img.save('image.jpg',
         format = 'JPEG',
         quality = 100,
         icc_profile = img.info.get('icc_profile',''))

为了将任何RGB JPEG图像从其颜色空间转换为sRGB,您可以使用此函数:

import io
from PIL import Image
from PIL import ImageCms

def convert_to_srgb(img):
    '''Convert PIL image to sRGB color space (if possible)'''
    icc = img.info.get('icc_profile', '')
    if icc:
        io_handle = io.BytesIO(icc)     # virtual file
        src_profile = ImageCms.ImageCmsProfile(io_handle)
        dst_profile = ImageCms.createProfile('sRGB')
        img = ImageCms.profileToProfile(img, src_profile, dst_profile)
    return img

因此,用于将图像转换为单个RGB颜色空间的代码可能如下所示:

img = Image.open('image_AdobeRGB.jpg')
img_conv = convert_to_srgb(img)
if img.info.get('icc_profile', '') != img_conv.info.get('icc_profile', ''):
    # ICC profile was changed -> save converted file
    img_conv.save('image_sRGB.jpg',
                  format = 'JPEG',
                  quality = 100,
                  icc_profile = img_conv.info.get('icc_profile',''))

注意:您可能希望使用略低于100的质量。

示例输入(Adobe RGB JPEG):

Adobe RGB JPG

示例输出(sRGB JPEG):

sRGB JPG


在这里提到的sRGB转Adobe RGB所需应用的矩阵变换怎么样呢:https://dev59.com/GVkS5IYBdhLWcg3wVlXC?rq=1 - Sabih
1
@SabihHasan,在我的例子中,这样的数学计算是由ImageCms.profileToProfile内部完成的。当您想要使两个具有不同颜色空间的图像在屏幕上看起来相同(或非常相似)时,就需要这样做。就像我的示例输入和示例输出一样。由于颜色空间不同,底层的RGB字节需要不同才能实现这一点。因此,这个数学计算只是为了让图片在不同的颜色空间中看起来相同而计算出RGB字节应该是什么。 (相反,如果两个图像具有相同的RGB字节,但具有不同的颜色空间,则它们在屏幕上看起来会不同。) - Andriy Makukha
这个解决方案似乎也适用于CMYK图像,只要在profileToProfile中添加选项renderingIntent=, outputMode='RGB' - mmj

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