使用Python将图像从RGB转换为Lab

51

如今使用 PIL/Numpy/SciPy 进行转换的首选方法是什么?


我已经阅读了这个问题https://dev59.com/tHA75IYBdhLWcg3wkJ31,并且它给出了一个指向scipy trunk中缺失的color.py的损坏链接。 - Antony Hatchkins
是的,我在scipy git存储库的深处找到了这个文件,但我无法相信使用如此强大的工具没有标准的方法来完成这样一个简单的事情。 - Antony Hatchkins
是的,我知道关于code.google.com/p/python-colormath库的事情,但我仍然不明白为什么它没有进入这三个工具之一。 - Antony Hatchkins
5个回答

81
自从2010年问出此问题以来,相关代码已从scipy移动到一个独立的工具箱: http://scikit-image.org/ 这是我实际在寻找的代码:
from skimage import io, color
rgb = io.imread(filename)
lab = color.rgb2lab(rgb)

需要注意的是,由于Lab颜色空间的特点,srgb->lab转换还依赖于另一个参数:白点(whitepoint)。例如:
   • Photoshop使用一个名为D50的白点(这是icc标准)
   • OpenCV和skimage使用D65(这是srgb标准)
   • 默认的Matlab实现使用D50(可以使用其他白点,详见此处)。

在这个很棒的FAQ中这样解释:

除非你有充分的理由,否则应该使用D65。
印刷行业通常使用D50,而摄影则通常使用D55。
这些都是室内(钨丝灯)和日光下观看条件之间的折中。

您可以通过将RGB (0,0,255)转换为Lab来确定所使用的白点:
   • D50会得到 (30, 68, -112)
   • D55会得到 (30, 73, -110)
   • D65会得到 (32, 79, -108)

'D'后面的数字对应于白点内部使用的色温:D50 = 5003 K(偏黄),D65 = 6504 K(偏蓝)。

感谢Alex和Roman的答案,因为他们指导了我正确的方向。


2
skimage 中,您可以将白点更改为 D50 或其他某些值。https://dev59.com/jn7aa4cB1Zd3GeqPrIAA#22968744 - Pylyp
我相信D50=黄色偏暖,D65=蓝色偏冷是正确的缩写。 - eoyilmaz

36
我在旧的Adobe Cookbook site上找到了这段代码,并为Python进行了适应。它不需要任何第三方模块或组件:
def rgb2lab ( inputColor ) :

   num = 0
   RGB = [0, 0, 0]

   for value in inputColor :
       value = float(value) / 255

       if value > 0.04045 :
           value = ( ( value + 0.055 ) / 1.055 ) ** 2.4
       else :
           value = value / 12.92

       RGB[num] = value * 100
       num = num + 1

   XYZ = [0, 0, 0,]

   X = RGB [0] * 0.4124 + RGB [1] * 0.3576 + RGB [2] * 0.1805
   Y = RGB [0] * 0.2126 + RGB [1] * 0.7152 + RGB [2] * 0.0722
   Z = RGB [0] * 0.0193 + RGB [1] * 0.1192 + RGB [2] * 0.9505
   XYZ[ 0 ] = round( X, 4 )
   XYZ[ 1 ] = round( Y, 4 )
   XYZ[ 2 ] = round( Z, 4 )

   XYZ[ 0 ] = float( XYZ[ 0 ] ) / 95.047         # ref_X =  95.047   Observer= 2°, Illuminant= D65
   XYZ[ 1 ] = float( XYZ[ 1 ] ) / 100.0          # ref_Y = 100.000
   XYZ[ 2 ] = float( XYZ[ 2 ] ) / 108.883        # ref_Z = 108.883

   num = 0
   for value in XYZ :

       if value > 0.008856 :
           value = value ** ( 0.3333333333333333 )
       else :
           value = ( 7.787 * value ) + ( 16 / 116 )

       XYZ[num] = value
       num = num + 1

   Lab = [0, 0, 0]

   L = ( 116 * XYZ[ 1 ] ) - 16
   a = 500 * ( XYZ[ 0 ] - XYZ[ 1 ] )
   b = 200 * ( XYZ[ 1 ] - XYZ[ 2 ] )

   Lab [ 0 ] = round( L, 4 )
   Lab [ 1 ] = round( a, 4 )
   Lab [ 2 ] = round( b, 4 )

   return Lab

它并没有直接回答问题:我需要一行代码。但是它还是有帮助的。谢谢! - Antony Hatchkins
1
虽然我会参考原始的easyrgb网站,而不是Adobe Cookbook。 - Antony Hatchkins
你的代码算不上很Pythonic,我该说。至少我会使用enumerate代替num变量,并使用1/3.代替0.3333333333333333 - Antony Hatchkins
这段代码似乎执行伽马校正(** 2.4)。如果我知道我的伽马值是2.2而不是2.4,那么只将指数更改为2.2就足够了吗?还是需要对其他硬编码常量(如1.055)进行更改? - jez
2
@jez,这里看到的Gamma 2.4是sRGB标准。它与低值处的线性转换结合在一起,共同接近2.2 Gamma曲线。我不会改变任何东西。 - Mark Ransom
谢谢您解决了这个问题,我已经尝试了几个值,它们与http://colormine.org/convert/rgb-to-lab上的值匹配。 - imrek

8

编辑:示例pyCMS代码:

from PIL import Image
import pyCMS
im = Image.open(...)
im2 = pyCMS.profileToProfile(im, pyCMS.createProfile("sRGB"), pyCMS.createProfile("LAB"))

编辑:Pillow,即PIL的分支版本,似乎已经内置了pyCMS。

您可以使用与PIL图像配合使用的pyCMS(http://www.cazabon.com/pyCMS/)。

如果速度不是问题,请使用python-colormath(http://code.google.com/p/python-colormath/)。


pyCMS 处理 ICC 配置文件,颜色空间是“副作用”。我要求一个一行代码的解决方案。 - Antony Hatchkins
是的,我在回答中的第三个评论中提到了python-colormath。 - Antony Hatchkins
问题不在于是否有一行代码(在我的评论中提供了两个),而在于为什么这两个代码没有进入PIL/numpy/scipy,或者是否有更好的替代方案。 - Antony Hatchkins
此外,无需将colormath移植到numpy,因为它自从问世以来就一直在使用numpy。 - Antony Hatchkins
pyCMS看起来不错,但使用它是有风险的--似乎它将无法得到良好的维护。 - fchen
显示剩余4条评论

3

这里有一个类,用于将PIL图像的RGB<->LAB颜色空间进行转换:

from PIL import ImageCms

class ColorTrans:

    '''Class for transforming RGB<->LAB color spaces for PIL images.'''
    
    def __init__(self):
        self.srgb_p = ImageCms.createProfile("sRGB")
        self.lab_p  = ImageCms.createProfile("LAB")
        self.rgb2lab_trans = ImageCms.buildTransformFromOpenProfiles(srgb_p, lab_p, "RGB", "LAB")
        self.lab2rgb_trans = ImageCms.buildTransformFromOpenProfiles(lab_p, srgb_p, "LAB", "RGB")
    
    def rgb2lab(self, img):
        return ImageCms.applyTransform(img, self.rgb2lab_trans)

    def lab2rgb(self, img):
        return ImageCms.applyTransform(img, self.lab2rgb_trans)

使用示例:

color_trans = ColorTrans()
c_img = Image.open(FILENAME)
c_img_lab = color_trans.rgb2lab(c_img)
c_img_rgb = color_trans.lab2rgb(c_img_lab)

0

目前我还没有找到一个好的包来完成这个任务。你必须记住,RGB是一种设备相关的颜色空间,所以如果你没有一个配置文件,就不能精确地转换为XYZ或CIE Lab。

因此,请注意许多解决方案,在你看到从RGB转换为CIE Lab而没有指定颜色空间或导入颜色配置文件的情况下,必须仔细评估。大多数时候,看看底层代码,它们假设你正在处理sRGB颜色空间。


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