LAB,RGB,XYZ颜色转换不正确,反之亦然

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LAB,RGB,XYZ颜色转换不正确,反之亦然相关的知识,希望对你有一定的参考价值。

我正在为项目创建自定义颜色选择器,它采用的是Photoshop风格,我可以使所有其他转换按预期方式工作,但我无法使RGBToLAB和LABToRGB正常工作。

问题不仅在于颜色显示不正确,而且转换也不完美。

样本:

  • LAB _ 58:0:0
  • XYZ _ 0.25960986510312:0.25960986510312:0.25960986510312
  • RGB _ {R:10 G:8 B:7 A:255}
  • XYZ _ 0.250358161840588:5.51162077338675:66.3836625496266
  • LAB _ 85.3739502460609:0:0

初始LAB与最后一个LAB不同,这表明转换存在缺陷。我不仅会得到错误的颜色,而且值也会发生变化,尤其是当LAB.L假定为常数时(在此示例中,因为这是滑块当前所控制的)]

上面的LAB-> RGB-> LAB转换有缺陷,但是XYZ-> RGB-> XYZ转换也有缺陷。

显然,我对转换LABToLAB不感兴趣,但以上内容确实指出了转换中的缺陷。

我尝试过的事情:

  1. This formula on wikipedia

  2. EasyRGB's code

  3. This javascript code on github

  4. This cginc code intended for unity, which is where i'm at now

       Private Function LABToXYZ(LAB As LAB) As XYZ
        Dim X, Y, Z As New Double
    
        Y = ((LAB.L + 16.0) / 116.0)
        X = ((LAB.A / 500.0) + Y)
        Z = (Y - (LAB.B / 200.0))
    
        Dim Less = 0.206897
    
        If (X > Less) Then
            X = Math.Pow(X, 3)
        Else
            X = ((X - 16.0 / 116.0) / 7.787)
        End If
        If (Y > Less) Then
            Y = Math.Pow(Y, 3)
        Else
            Y = ((Y - 16.0 / 116.0) / 7.787)
        End If
        If (Z > Less) Then
            Z = Math.Pow(Z, 3)
        Else
            Z = ((Z - 16.0 / 116.0) / 7.787)
        End If
    
        Return New XYZ(X, Y, Z)
    End Function
    
    Private Function XYZToRGB(XYZ As XYZ) As Color
        Dim R, G, B As New Double
        Dim X, Y, Z As New Double
    
        X = (XYZ.X / 100)
        Y = (XYZ.Y / 100)
        Z = (XYZ.Z / 100)
    
        R = ((X * 3.2406) + (Y * -1.5372) + (Z * -0.4986))
        G = ((X * -0.9689) + (Y * 1.8758) + (Z * 0.0415))
        B = ((X * 0.0557) + (Y * -0.204) + (Z * 1.057))
    
        Dim Less As Double = 0.0031308
    
        If (R > Less) Then
            X = ((1.055 * Math.Pow(R, (1.0 / 2.4))) - 0.055)
        Else
            X = (R * 12.92)
        End If
        If (G > Less) Then
            Y = ((1.055 * Math.Pow(G, (1.0 / 2.4))) - 0.055)
        Else
            Y = (G * 12.92)
        End If
        If (B > Less) Then
            Z = ((1.055 * Math.Pow(B, (1.0 / 2.4))) - 0.055)
        Else
            Z = (B * 12.92)
        End If
    
        Return New Color(CSng(X), CSng(Y), CSng(Z))
    End Function
    
    Private Function RGBToXYZ(Color As Color) As XYZ
        Dim RGB = ColorToRGB(Color)
        Dim X, Y, Z As New Double
        Dim Less As Double = 0.04045
    
        If (RGB.R > Less) Then
            X = Math.Pow(((RGB.R + 0.055) / 1.055), 2.4)
        Else
            X = (RGB.R / 12.92)
        End If
        If (RGB.G > Less) Then
            Y = Math.Pow(((RGB.G + 0.055) / 1.055), 2.4)
        Else
            Y = (RGB.G / 12.92)
        End If
        If (RGB.B > Less) Then
            Z = Math.Pow(((RGB.B + 0.055) / 1.055), 2.4)
        Else
            Z = (RGB.B / 12.92)
        End If
    
        X = (((X * 0.4124) + (Y * 0.3576) + (Z * 0.1805)) * 100.0)
        Y = (((X * 0.2126) + (Y * 0.7152) + (Z * 0.0722)) * 100.0)
        Z = (((X * 0.0193) + (Y * 0.1192) + (Z * 0.9505)) * 100.0)
    
        Return New XYZ(X, Y, Z)
    End Function
    
    Private Function XYZToLAB(XYZ As XYZ) As LAB
        Dim X, Y, Z As New Double
        Dim L, A, B As New Double
        Dim Less As Double = 0.008856
    
        X = ((XYZ.X / 95.047) + (XYZ.Y / 100) + (XYZ.Z / 108.883))
        Y = ((XYZ.X / 95.047) + (XYZ.Y / 100) + (XYZ.Z / 108.883))
        Z = ((XYZ.X / 95.047) + (XYZ.Y / 100) + (XYZ.Z / 108.883))
    
        If (X > Less) Then
            X = Math.Pow(X, (1.0 / 3.0))
        Else
            X = ((7.787 * X) + (16.0 / 116.0))
        End If
        If (Y > Less) Then
            Y = Math.Pow(Y, (1.0 / 3.0))
        Else
            Y = ((7.787 * Y) + (16.0 / 116.0))
        End If
        If (Z > Less) Then
            Z = Math.Pow(Z, (1.0 / 3.0))
        Else
            Z = ((7.787 * Z) + (16.0 / 116.0))
        End If
    
        L = ((116.0 * Y) - 16.0)
        A = (500.0 * (X - Y))
        B = (200.0 * (Y - Z))
    
        Return New LAB(L, A, B)
    End Function
    
    Function ColorToRGB(Color As Color) As RGB
        Return New RGB((Convert.ToInt32(Color.R) / 255), (Convert.ToInt32(Color.G) / 255), (Convert.ToInt32(Color.B) / 255))
    End Function
    Public Class RGB
    Public ReadOnly Min As Double = 0
    Public ReadOnly Max As Double = 1
    
    Public Sub New()
    End Sub
    
    Public Sub New(R As Double, G As Double, B As Double)
        Me.R = R
        Me.G = G
        Me.B = B
    End Sub
    
    Public Sub New(Color As Color)
        Me.R = (Convert.ToInt32(Color.R) / 255)
        Me.G = (Convert.ToInt32(Color.G) / 255)
        Me.B = (Convert.ToInt32(Color.B) / 255)
    End Sub
    
    Private _R As New Double
    Private _G As New Double
    Private _B As New Double
    
    Public Property R As Double
        Get
            Return _R
        End Get
        Set
            _R = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Public Property G As Double
        Get
            Return _G
        End Get
        Set
            _G = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Public Property B As Double
        Get
            Return _B
        End Get
        Set
            _B = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Overrides Function ToString() As String
        Return (_R.ToString & ":"c & _G.ToString & ":"c & _B.ToString)
    End Function
    End Class
    
    Public Class XYZ
    Public ReadOnly Min As Double = 0
    Public ReadOnly Max As Double = 100
    
    Public Sub New()
    End Sub
    
    Public Sub New(X As Double, Y As Double, Z As Double)
        Me.X = X
        Me.Y = Y
        Me.Z = Z
    End Sub
    
    Private _X As New Double
    Private _Y As New Double
    Private _Z As New Double
    
    Public Property X As Double
        Get
            Return _X
        End Get
        Set
            _X = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Public Property Y As Double
        Get
            Return _Y
        End Get
        Set
            _Y = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Public Property Z As Double
        Get
            Return _Z
        End Get
        Set
            _Z = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Overrides Function ToString() As String
        Return (_X.ToString & ":"c & _Y.ToString & ":"c & _Z.ToString)
    End Function
    End Class
    
    Public Class LAB
    Public ReadOnly Min As Double = -128
    Public ReadOnly Max As Double = 127
    
    Sub New()
    End Sub
    
    Sub New(L As Double, A As Double, B As Double)
        Me.L = L
        Me.A = A
        Me.B = B
    End Sub
    
    Private _L As New Double
    Private _A As New Double
    Private _B As New Double
    
    Property L As Double
        Get
            Return _L
        End Get
        Set
            _L = LimitInRange(Value, 0, 100)
        End Set
    End Property
    
    Property A As Double
        Get
            Return _A
        End Get
        Set
            _A = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Property B As Double
        Get
            Return _B
        End Get
        Set
            _B = LimitInRange(Value, Min, Max)
        End Set
    End Property
    
    Overrides Function ToString() As String
        Return (_L.ToString & ":"c & _A.ToString & ":"c & _B.ToString)
    End Function
    End Class
    
    Function LimitInRange(Value As Double, Min As Double, Max As Double) As Double
        Select Case Value
            Case <= Min
                Return Min
            Case >= Max
                Return Max
            Case Else
                Return Value
        End Select
    End Function
    

我需要VB.Net中的代码,这就是为什么我正在为我的项目转换和改编统一代码的原因,但是我遇到了麻烦,需要一些帮助。

[如果有人知道我在做什么错,我会很乐意听。

UPDATE 1:我试图通过不匹配两种转换方法来更正转换,但是我正接近完美的转换,但是我担心这么长时间解决这个问题可能会使我望而却步。

样本:

  • LAB _ 0:0:0
  • XYZ _ 0.262413383082537:0.262413383082537:0.262413383082537
  • RGB _ {R:10 G:8 B:7 A:255}
  • XYZ _ 0.250358161840588:0.253536089358344:0.236754082437929
  • LAB _ 2.29017121228677:-0.12373260790384:0.261362975778545

您看到的问题比以前少了,但仍然存在。

    Private Function LABToXYZ(LAB As LAB) As XYZ
        Dim X, Y, Z As New Double

        Y = ((LAB.L + 16.0) / 116.0)
        X = ((LAB.A / 500.0) + Y)
        Z = (Y - (LAB.B / 200.0))

        Dim Less = 0.008856

        If (X > Less) Then
            X = Math.Pow(X, 3)
        Else
            X = ((X - 16.0 / 116.0) / 7.787)
        End If
        If (Y > Less) Then
            Y = Math.Pow(Y, 3)
        Else
            Y = ((Y - 16.0 / 116.0) / 7.787)
        End If
        If (Z > Less) Then
            Z = Math.Pow(Z, 3)
        Else
            Z = ((Z - 16.0 / 116.0) / 7.787)
        End If

        Return New XYZ(X * 100, Y * 100, Z * 100)
    End Function

    Private Function XYZToRGB(XYZ As XYZ) As Color
        Dim R, G, B As New Double
        Dim X, Y, Z As New Double

        X = (XYZ.X / 100)
        Y = (XYZ.Y / 100)
        Z = (XYZ.Z / 100)

        R = ((X * 3.2406) + (Y * -1.5372) + (Z * -0.4986))
        G = ((X * -0.9689) + (Y * 1.8758) + (Z * 0.0415))
        B = ((X * 0.0557) + (Y * -0.204) + (Z * 1.057))

        Dim Less As Double = 0.0031308

        If (R > Less) Then
            R = ((1.055 * Math.Pow(R, (1.0 / 2.4))) - 0.055)
        Else
            R = (R * 12.92)
        End If
        If (G > Less) Then
            G = ((1.055 * Math.Pow(G, (1.0 / 2.4))) - 0.055)
        Else
            G = (G * 12.92)
        End If
        If (B > Less) Then
            B = ((1.055 * Math.Pow(B, (1.0 / 2.4))) - 0.055)
        Else
            B = (B * 12.92)
        End If

        Return New Color(CSng(R), CSng(G), CSng(B))
    End Function

    Private Function RGBToXYZ(Color As Color) As XYZ
        Dim RGB = ColorToRGB(Color)
        Dim X, Y, Z As New Double
        Dim R, G, B As New Double
        Dim Less As Double = 0.04045

        If (RGB.R > Less) Then
            r = Math.Pow(((RGB.R + 0.055) / 1.055), 2.4)
        Else
            R = (RGB.R / 12.92)
        End If
        If (RGB.G > Less) Then
            G = Math.Pow(((RGB.G + 0.055) / 1.055), 2.4)
        Else
            G = (RGB.G / 12.92)
        End If
        If (RGB.B > Less) Then
            B = Math.Pow(((RGB.B + 0.055) / 1.055), 2.4)
        Else
            B = (RGB.B / 12.92)
        End If

        R *= 100
        G *= 100
        B *= 100

        X = ((R * 0.4124) + (G * 0.3576) + (B * 0.1805))
        Y = ((R * 0.2126) + (G * 0.7152) + (B * 0.0722))
        Z = ((R * 0.0193) + (G * 0.1192) + (B * 0.9505))

        Return New XYZ(X, Y, Z)
    End Function

    Private Function XYZToLAB(XYZ As XYZ) As LAB
        Dim X, Y, Z As New Double
        Dim L, A, B As New Double
        Dim Less As Double = 0.008856

        X = XYZ.X / 100
        Y = XYZ.Y / 100
        Z = XYZ.Z / 100

        If (X > Less) Then
            X = Math.Pow(X, (1.0 / 3.0))
        Else
            X = ((7.787 * X) + (16.0 / 116.0))
        End If
        If (Y > Less) Then
            Y = Math.Pow(Y, (1.0 / 3.0))
        Else
            Y = ((7.787 * Y) + (16.0 / 116.0))
        End If
        If (Z > Less) Then
            Z = Math.Pow(Z, (1.0 / 3.0))
        Else
            Z = ((7.787 * Z) + (16.0 / 116.0))
        End If

        L = ((116.0 * Y) - 16.0)
        A = (500.0 * (X - Y))
        B = (200.0 * (Y - Z))

        Return New LAB(L, A, B)
    End Function

UPDATE 2:进一步的测试显示XNA.Framework.Color中异常异常的行为,导致任何分数都被解释为%。这意味着200.10将超过最大颜色值(255)的200%,这会将其限制为最大颜色值(255),因此,除非指定整数,否则最终可能会得到非常错误的输出。

我正在尝试使代码from this example as well不匹配。我觉得我正在进步,即使我不得不放弃在转换中使用XNA.Framework.Color类。

如果找到一个解决方案,我将提供最终解决方案。

UPDATE 3:在线测试here (source code here)here显示我的LABToXYZ不正确。

我的结果:

  • 实验室_ 100:0:0
  • XYZ _ 95.047:100:100

他们的结果:

  • 实验室_ 100:0:0
  • XYZ _ 95.05:100:108.88

    Public Function LABtoXYZ(LAB As LAB) As XYZ
        Dim X, Y, Z As Double
        Y = ((LAB.L + 16.0) / 116.0)
        X = ((LAB.A / 500.0) + Y)
        Z = (Y - (LAB.B / 200.0))
    
        Dim Pow_X = Math.Pow(X, 3.0)
        Dim Pow_Y = Math.Pow(Y, 3.0)
        Dim Pow_Z = Math.Pow(Z, 3.0)
    
        Dim Less = 216 / 24389
    
        If (Pow_X > Less) Then
            X = Pow_X
        Else
            X = ((X - (16.0 / 116.0)) / 7.787)
        End If
        If (Pow_Y > Less) Then
            Y = Pow_Y
        Else
            Y = ((Y - (16.0 / 116.0)) / 7.787)
        End If
        If (Pow_Z > Less) Then
            Z = Pow_Z
        Else
            Z = ((Z - (16.0 / 116.0)) / 7.787)
        End If
    
        Return New XYZ((X * 95.047), (Y * 100.0), (Z * 108.883))
    End Function
    

但是使用全0进行LAB会导致全0的XYZ,这是正确的行为,我无法判断出什么问题,是Z错误,但是我的代码中的错误在哪里?

更多示例here似乎表明我的代码是正确的,但是我仍然得到错误的Z。

UPDATE 4:进一步完善和重做所有代码,我发现对发现的示例here进行了转换和改编,给了我我想要的结果,即使示例中存在一些错误,尤其是^ 2.2,应该是^ 2.4。

我还发现了一些精度问题,必须将双精度数转换为整数才能使转换完美,但这可能是最终的更新,除非我遇到任何问题,否则我将在一段时间内继续解决这个问题在实践中测试代码。当我确信代码没有缺陷时,我会回来并将其标记为已回答。

样本:测试1

  • LAB _ 1:0:0
  • XYZ _ 0.105222895807779:0.110706172533356:0.120540201839494
  • RGB _ 4:4:4:255
  • XYZ _ 0.115400959145268:0.12141079341953535:0.132216354033874
  • LAB _ 1:0:0

测试2

  • LAB _ 10:0:0
  • XYZ _ 1.07024816003116:1.12601992701628:1.22604427713313
  • RGB _ 27:27:27:255
  • XYZ _ 1.04175693531671:1.09600940064882:1.19355423730657
  • LAB _ 10:0:0

测试3

  • LAB _ 100:0:0
  • XYZ _ 95.047:100:108.883
  • RGB _ 255:255:255:255
  • XYZ _ 95.05:100:108.9
  • LAB _ 100:0:0

测试4

  • LAB _ 11:0:0
  • XYZ _ 1.19854884694432:1.26100649883144:1.37302170612264
  • RGB _ 29:29:29:255
  • XYZ _ 1.16783071832485:1.22864883569159:1.33799858206814
  • LAB _ 11:0:0

如上所示,有一个很小的变化,如果不进行四舍五入,将导致不完美的转换。

[The Classes

  Public Class RGB
        Public ReadOnly Min As Double = 0.0
        Public ReadOnly Max As Double = 255.0

        Public Sub New()
        End Sub

        Public Sub New(R As Integer, G As Integer, B As Integer)
            Me.R = R
            Me.G = G
            Me.B = B
        End Sub

        Public Sub New(R As Integer, G As Integer, B As Integer, A As Integer)
            Me.R = R
            Me.G = G
            Me.B = B
            Me.A = A
        End Sub
        Public Sub New(R As Double, G As Double, B As Double, A As Double)
            Me.R = Convert.ToInt32(R)
            Me.G = Convert.ToInt32(G)
            Me.B = Convert.ToInt32(B)
            Me.A = Convert.ToInt32(A)
        End Sub
        Public Sub New(R As Double, G As Double, B As Double)
            Me.R = Convert.ToInt32(R * 255)
            Me.G = Convert.ToInt32(G * 255)
            Me.B = Convert.ToInt32(B * 255)
        End Sub
        Public Sub New(Color As Color)
            Me.R = Convert.ToInt32(Color.R)
            Me.G = Convert.ToInt32(Color.G)
            Me.B = Convert.ToInt32(Color.B)
            Me.A = Convert.ToInt32(Color.A)
        End Sub

        Private _R As New Double
        Private _G As New Double
        Private _B As New Double
        Private _A As Double = 255

        Public Property R As Double
            Get
                Return _R
            End Get
            Set
                _R = LimitInRange(Value, Min, Max)
            End Set
        End Property

        Public Property G As Double
            Get
                Return _G
            End Get
            Set
                _G = LimitInRange(Value, Min, Max)
            End Set
        End Property

        Public Property B As Double
            Get
                Return _B
            End Get
            Set
                _B = LimitInRange(Value, Min, Max)
            End Set
        End Property

        Public Property A As Double
            Get
                Return _A
            End Get
            Set
                _A = LimitInRange(Value, Min, Max)
            End Set
        End Property

        Overrides Function ToString() As String
            Return (_R.ToString & ":"c & _G.ToString & ":"c & _B.ToString & ":"c & _A.ToString)
        End Function

        Public Shared Operator =(Left As RGB, Right As RGB) As Boolean
            If ((Left.R = Right.R) AndAlso (Left.G = Right.G) AndAlso (Left.B = Right.B) AndAlso (Left.A = Right.A)) Then
                Return True
            Else
                Return False
            End If
        End Operator

        Public Shared Operator <>(Left As RGB, Right As RGB) As Boolean
            Return (Not (Left = Right))
        End Operator

    End Class

    Public Class XYZ
        Public ReadOnly Min As Double = 0

        Public Sub New()
        End Sub

        Public Sub New(X As Double, Y As Double, Z As Double)
            Me.X = X
            Me.Y = Y
            Me.Z = Z
        End Sub

        Private _X As New Double
        Private _Y As New Double
        Private _Z As New Double

        Public Property X As Double
            Get
                Return _X
            End Get
            Set
                _X = LimitInRange(Value, Min, 95.05)
            End Set
        End Property

        Public Property Y As Double
            Get
                Return _Y
            End Get
            Set
                _Y = LimitInRange(Value, Min, 100)
            End Set
        End Property

        Public Property Z As Double
            Get
                Return _Z
            End Get
            Set
                _Z = LimitInRange(Value, Min, 108.9)
            End Set
        End Property

        Overrides Function ToString() As String
            Return (_X.ToString & ":"c & _Y.ToString & ":"c & _Z.ToString)
        End Function

    End Class

    Public Class LAB
        Public ReadOnly Min As Double = -128
        Public ReadOnly Max As Double = 127

        Sub New()
        End Sub

        Sub New(L As Double, A As Double, B As Double)
            Me.L = L
            Me.A = A
            Me.B = B
        End Sub

        Private _L As New Double
        Private _A As New Double
        Private _B As New Double

        Property L As Double
            Get
                Return _L
            End Get
            Set
                _L = LimitInRange(Value, 0, 100)
            End Set
        End Property

        Property A As Double
            Get
                Return _A
            End Get
            Set
                _A = LimitInRange(Value, Min, Max)
            End Set
        End Property

        Property B As Double
            Get
                Return _B
            End Get
            Set
                _B = LimitInRange(Value, Min, Max)
            End Set
        End Property

        Overrides Function ToString() As String
            Return (_L.ToString & ":"c & _A.ToString & ":"c & _B.ToString)
        End Function

    End Class

转换器

Public Function LABtoXYZ(LAB As LAB) As XYZ
        Dim X, Y, Z As New Double
        Y = ((LAB.L + 16.0) / 116.0)
        X = ((LAB.A / 500.0) + Y)
        Z = (Y - (LAB.B / 200.0))

        Dim Pow_X = Math.Pow(X, 3.0)
        Dim Pow_Y = Math.Pow(Y, 3.0)
        Dim Pow_Z = Math.Pow(Z, 3.0)

        Dim Less = (216 / 24389)

        If (Pow_X > Less) Then
            X = Pow_X
        Else
            X = ((X - (16.0 / 116.0)) / 7.787)
        End If
        If (Pow_Y > Less) Then
            Y = Pow_Y
        Else
            Y = ((Y - (16.0 / 116.0)) / 7.787)
        End If
        If (Pow_Z > Less) Then
            Z = Pow_Z
        Else
            Z = ((Z - (16.0 / 116.0)) / 7.787)
        End If

        Return New XYZ((X * 95.047), (Y * 100.0), (Z * 108.883))
    End Function

    Private Function XYZToRGB(XYZ As XYZ) As RGB
        Dim X, Y, Z As New Double
        Dim R, G, B As New Double
        Dim Pow As Double = (1.0 / 2.4)
        Dim Less As Double = 0.0031308

        X = (XYZ.X / 100)
        Y = (XYZ.Y / 100)
        Z = (XYZ.Z / 100)

        R = ((X * 3.24071) + (Y * -1.53726) + (Z * -0.498571))
        G = ((X * -0.969258) + (Y * 1.87599) + (Z * 0.0415557))
        B = ((X * 0.0556352) + (Y * -0.203996) + (Z * 1.05707))

        If (R > Less) Then
            R = ((1.055 * Math.Pow(R, Pow)) - 0.055)
        Else
            R *= 12.92
        End If
        If (G > Less) Then
            G = ((1.055 * Math.Pow(G, Pow)) - 0.055)
        Else
            G *= 12.92
        End If
        If (B > Less) Then
            B = ((1.055 * Math.Pow(B, Pow)) - 0.055)
        Else
            B *= 12.92
        End If

        Return New RGB(R, G, B)
    End Function

    Private Function RGBToXYZ(RGB As RGB) As XYZ
        Dim X, Y, Z As New Double
        Dim R, G, B As New Double
        Dim Less As Double = 0.04045

        R = (RGB.R / 255)
        G = (RGB.G / 255)
        B = (RGB.B / 255)

        If (R > Less) Then
            R = Math.Pow(((R + 0.055) / 1.055), 2.4)
        Else
            R = (R / 12.92)
        End If
        If (G > Less) Then
            G = Math.Pow(((G + 0.055) / 1.055), 2.4)
        Else
            G = (G / 12.92)
        End If
        If (B > Less) Then
            B = Math.Pow(((B + 0.055) / 1.055), 2.4)
        Else
            B = (B / 12.92)
        End If

        X = ((R * 0.4124) + (G * 0.3576) + (B * 0.1805))
        Y = ((R * 0.2126) + (G * 0.7152) + (B * 0.0722))
        Z = ((R * 0.0193) + (G * 0.1192) + (B * 0.9505))

        Return New XYZ(X * 100, Y * 100, Z * 100)
    End Function

    Private Function XYZToLAB(XYZ As XYZ) As LAB
        Dim X, Y, Z As New Double
        Dim L, A, B As New Double
        Dim Less As Double = 0.008856
        Dim Pow As Double = (1.0 / 3.0)

        X = ((XYZ.X / 100) / 0.9505)
        Y = (XYZ.Y / 100)
        Z = ((XYZ.Z / 100) / 1.089)

        If (X > Less) Then
            X = Math.Pow(X, Pow)
        Else
            X = ((7.787 * X) + (16.0 / 116.0))
        End If
        If (Y > Less) Then
            Y = Math.Pow(Y, Pow)
        Else
            Y = ((7.787 * Y) + (16.0 / 116.0))
        End If
        If (Z > Less) Then
            Z = Math.Pow(Z, Pow)
        Else
            Z = ((7.787 * Z) + (16.0 / 116.0))
        End If

        L = ((116.0 * Y) - 16.0)
        A = (500.0 * (X - Y))
        B = (200.0 * (Y - Z))

        'We solve the precision problem by rounding to nearest integer
        'This makes the conversion perfect.
        Return New LAB(CInt(L), CInt(A), CInt(B))
    End Function

在将其标记为已解决之前,需要进行进一步测试。

UPDATE 5:到目前为止还没有任何问题...当仅发布问题时,我不知道如何将其标记为已回答。完整的免费代码和更多内容可以找到here

答案

我尚未解析您的所有代码,但在您的第一个代码块中,函数RGBToXYZ中存在问题。

    X = (((X * 0.4124) + (Y * 0.3576) + (Z * 0.1805)) * 100.0)
    Y = (((X * 0.2126) + (Y * 0.7152) + (Z * 0.0722)) * 100.0)
    Z = (((X * 0.0193) + (Y * 0.1192) + (Z * 0.9505)) * 100.0)

    Return New XYZ(X, Y, Z)

您为X做矩阵,然后对Y矩阵使用X 再次

,但是X现在是新值!这不是在变量上轻率的地方。

这应该是这样的:

    Dim Xout, Yout, Zout As New Double

    Xout = ((X * 0.4124) + (Y * 0.3576) + (Z * 0.1805))
    Yout = ((X * 0.2126) + (Y * 0.7152) + (Z * 0.0722))
    Zout = ((X * 0.0193) + (Y * 0.1192) + (Z * 0.9505))

    Return New XYZ(Xout, Yout, Zout)

此外,我建议将XYZ保持在0.0-1.0范围内。

还有其他用途:

LABToXYZ缺少所需的光源转换。它需要返回:

    X = (X * 0.95047)
    Z = (Z * 1.08883)

然后XYZtoLAB

具有:
    X = ((XYZ.X / 95.047) + (XYZ.Y / 100) + (XYZ.Z / 108.883))
    Y = ((XYZ.X / 95.047) + (XYZ.Y / 100) + (XYZ.Z / 108.883))
    Z = ((XYZ.X / 95.047) + (XYZ.Y / 100) + (XYZ.Z / 108.883))

哪个会使X Y和Z都相同...

应该(假设将XYZ保持为0-1):

    X = (XYZ.X / 0.95047)
    Y = (XYZ.Y)
    Z = (XYZ.Z / 1.08883)

[我刚刚意识到您已经解决了自己的问题,我会把它留在这里,以防万一有人碰到它来寻找相似的答案。

以上是关于LAB,RGB,XYZ颜色转换不正确,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章

RGB与Lab颜色空间互相转换

RGB、CMY、CMYK、YUV、HSV、HSI、LAB颜色空间详解

Reinhard颜色迁移理论基础(RGB与Lab颜色空间转换)与代码实现(附matlab代码)

pytorchtensor张量vector向量numpy array数组image图像RGB空间LAB空间之间相互转换大全

将十六进制颜色转换为RGB,反之亦然。

怎样用C语言实现图片的RGB颜色空间向Lab颜色空间的转化??