dcsimg
Results 1 to 6 of 6

Thread: RGB, XYZ, and Lab conversions

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Oct 2008
    Posts
    971

    RGB, XYZ, and Lab conversions

    This program converts images between RGB, XYZ, and Lab formats. It's quite a large program (due to the 2 huge lookup tables for RGB/Lab conversion), so instead of posting it as an attachment, I've uploaded it to Mediafire, and have posted the download link here.

    https://www.mediafire.com/?vdx3uy1z31g21as

  2. #2
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    805

    Re: RGB, XYZ, and Lab conversions

    Hi Ben. Thanks for sharing. You weren't joking about the download file being huge!

    There is a much easier way to do RGB / XYZ / Lab conversions. Code below (adopted from easyRGB.com). Note that certain assumptions have to be made when converting between RGB (which is just a color model) and an actual color space, like Lab. In these functions, sRGB and 6500k color temperature are assumed, as noted in the comments.

    Code:
    'This function is just a thin wrapper to RGBtoXYZ and XYZtoLAB.  There is no direct conversion from RGB to CieLAB.
    Public Sub RGBtoLAB(ByVal r As Long, ByVal g As Long, ByVal b As Long, ByRef labL As Double, ByRef labA As Double, ByRef labB As Double)
    
        Dim x As Double, y As Double, z As Double
        RGBtoXYZ r, g, b, x, y, z
        XYZtoLab x, y, z, labL, labA, labB
    
    End Sub
    
    'Convert RGB to XYZ space, using an sRGB conversion and the assumption of a D65 (e.g. color temperature of 6500k) illuminant
    ' Formula adopted from http://www.easyrgb.com/index.php?X=MATH&H=02#text2
    Public Sub RGBtoXYZ(ByVal r As Long, ByVal g As Long, ByVal b As Long, ByRef x As Double, ByRef y As Double, ByRef z As Double)
    
        'Normalize RGB to [0, 1]
        Dim rFloat As Double, gFloat As Double, bFloat As Double
        rFloat = r / 255
        gFloat = g / 255
        bFloat = b / 255
        
        'Convert RGB values to the sRGB color space
        If rFloat > 0.04045 Then
            rFloat = ((rFloat + 0.055) / (1.055)) ^ 2.2
        Else
            rFloat = rFloat / 12.92
        End If
        
        If gFloat > 0.04045 Then
            gFloat = ((gFloat + 0.055) / (1.055)) ^ 2.2
        Else
            gFloat = gFloat / 12.92
        End If
        
        If bFloat > 0.04045 Then
            bFloat = ((bFloat + 0.055) / (1.055)) ^ 2.2
        Else
            bFloat = bFloat / 12.92
        End If
        
        'Calculate XYZ using D65 correction
        x = rFloat * 0.4124 + gFloat * 0.3576 + bFloat * 0.1805
        y = rFloat * 0.2126 + gFloat * 0.7152 + bFloat * 0.0722
        z = rFloat * 0.0193 + gFloat * 0.1192 + bFloat * 0.9505
        
    End Sub
    
    'Convert an XYZ color to CIELab.  As with the original XYZ calculation, D65 is assumed.
    ' Formula adopted from http://www.easyrgb.com/index.php?X=MATH&H=07#text7, with minor changes by me (not re-applying D65 values until after
    '  fXYZ has been calculated)
    Public Sub XYZtoLab(ByVal x As Double, ByVal y As Double, ByVal z As Double, ByRef l As Double, ByRef a As Double, ByRef b As Double)
        l = 116 * fXYZ(y) - 16
        a = 500 * (fXYZ(x / 0.9505) - fXYZ(y))
        b = 200 * (fXYZ(y) - fXYZ(z / 1.089))
    End Sub
    
    Private Function fXYZ(ByVal t As Double) As Double
        If t > 0.008856 Then
            fXYZ = t ^ (1 / 3)
        Else
            fXYZ = (7.787 * t) + (16 / 116)
        End If
    End Function
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Oct 2008
    Posts
    971

    Re: RGB, XYZ, and Lab conversions

    Quote Originally Posted by Tanner_H View Post
    Hi Ben. Thanks for sharing. You weren't joking about the download file being huge!

    There is a much easier way to do RGB / XYZ / Lab conversions. Code below (adopted from easyRGB.com). Note that certain assumptions have to be made when converting between RGB (which is just a color model) and an actual color space, like Lab. In these functions, sRGB and 6500k color temperature are assumed, as noted in the comments.

    Code:
    'This function is just a thin wrapper to RGBtoXYZ and XYZtoLAB.  There is no direct conversion from RGB to CieLAB.
    Public Sub RGBtoLAB(ByVal r As Long, ByVal g As Long, ByVal b As Long, ByRef labL As Double, ByRef labA As Double, ByRef labB As Double)
    
        Dim x As Double, y As Double, z As Double
        RGBtoXYZ r, g, b, x, y, z
        XYZtoLab x, y, z, labL, labA, labB
    
    End Sub
    
    'Convert RGB to XYZ space, using an sRGB conversion and the assumption of a D65 (e.g. color temperature of 6500k) illuminant
    ' Formula adopted from http://www.easyrgb.com/index.php?X=MATH&H=02#text2
    Public Sub RGBtoXYZ(ByVal r As Long, ByVal g As Long, ByVal b As Long, ByRef x As Double, ByRef y As Double, ByRef z As Double)
    
        'Normalize RGB to [0, 1]
        Dim rFloat As Double, gFloat As Double, bFloat As Double
        rFloat = r / 255
        gFloat = g / 255
        bFloat = b / 255
        
        'Convert RGB values to the sRGB color space
        If rFloat > 0.04045 Then
            rFloat = ((rFloat + 0.055) / (1.055)) ^ 2.2
        Else
            rFloat = rFloat / 12.92
        End If
        
        If gFloat > 0.04045 Then
            gFloat = ((gFloat + 0.055) / (1.055)) ^ 2.2
        Else
            gFloat = gFloat / 12.92
        End If
        
        If bFloat > 0.04045 Then
            bFloat = ((bFloat + 0.055) / (1.055)) ^ 2.2
        Else
            bFloat = bFloat / 12.92
        End If
        
        'Calculate XYZ using D65 correction
        x = rFloat * 0.4124 + gFloat * 0.3576 + bFloat * 0.1805
        y = rFloat * 0.2126 + gFloat * 0.7152 + bFloat * 0.0722
        z = rFloat * 0.0193 + gFloat * 0.1192 + bFloat * 0.9505
        
    End Sub
    
    'Convert an XYZ color to CIELab.  As with the original XYZ calculation, D65 is assumed.
    ' Formula adopted from http://www.easyrgb.com/index.php?X=MATH&H=07#text7, with minor changes by me (not re-applying D65 values until after
    '  fXYZ has been calculated)
    Public Sub XYZtoLab(ByVal x As Double, ByVal y As Double, ByVal z As Double, ByRef l As Double, ByRef a As Double, ByRef b As Double)
        l = 116 * fXYZ(y) - 16
        a = 500 * (fXYZ(x / 0.9505) - fXYZ(y))
        b = 200 * (fXYZ(y) - fXYZ(z / 1.089))
    End Sub
    
    Private Function fXYZ(ByVal t As Double) As Double
        If t > 0.008856 Then
            fXYZ = t ^ (1 / 3)
        Else
            fXYZ = (7.787 * t) + (16 / 116)
        End If
    End Function

    Thanks for sharing that. I haven't tried it yet though.
    By the way, you are missing the inverse transformations. Also, is this actually faster than the techniques I used in my program, when used to convert an entire image? It seems that it would be slower, since there are a lot more operations being done in your program, than in the one I wrote. Also, why do you pre-process the RGB channels before applying the RGB to XYZ transformation matrix? I'm guessing it has something to do with linearity of the RGB values when compared to actual physical brightness levels of the pixels, and compensating for a lack of linearity. However for the sake of simplifying the operation in my program when converting between RGB and XYZ, I assume that the RGB values are already representing linear brightnesses of the 3 color channels and use them as-is (no pre-processing) as inputs to the transformation matrix.
    Last edited by Ben321; May 1st, 2014 at 02:37 PM.

  4. #4
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    805

    Re: RGB, XYZ, and Lab conversions

    Quote Originally Posted by Ben321 View Post
    By the way, you are missing the inverse transformations.
    Yep, I don't have those on hand, though they're trivially created from the formulas at this link.

    Quote Originally Posted by Ben321 View Post
    Also, is this actually faster than the techniques I used in my program, when used to convert an entire image? It seems that it would be slower, since there are a lot more operations being done in your program, than in the one I wrote.
    You'd have to test, but I wouldn't underestimate the overhead of loading those massive look-up tables into RAM, let alone the cost of shipping them with your project. The formulas I shared could probably be optimized further, but as-is they're fast enough for real-time conversion on screen-sized images. (I use them to render a green screen effect in real-time, and I haven't had any speed problems on modern PCs.)

    Quote Originally Posted by Ben321 View Post
    Also, why do you pre-process the RGB channels before applying the RGB to XYZ transformation matrix? I'm guessing it has something to do with linearity of the RGB values when compared to actual physical brightness levels of the pixels, and compensating for a lack of linearity. However for the sake of simplifying the operation in my program when converting between RGB and XYZ, I assume that the RGB values are already representing linear brightnesses of the 3 color channels and use them as-is (no pre-processing) as inputs to the transformation matrix.
    As you probably know, RGB is just a color model, not a color space. A color like RGB(255, 0, 0) will look completely different on different devices.

    Because CieLAB is an actual color space (that absolutely describes color), to get any use from it, you first have to convert your RGB data into an absolute RGB color space. Which RGB color space is up to you; sRGB is simple and straightforward, and your original RGB data was mostly likely designed against sRGB anyway. (More about sRGB here.) Adobe RGB or ProPhoto RGB are other common RGB spaces, but they're a lot more work to use.

    Since the primary purpose of the CieLAB space is accurate representation of color, it's probably not a good idea to convert raw 24bpp RGB data directly through XYZ into Lab, without first performing a proper RGB color space conversion. You could save some processing time, certainly, but your Lab values wouldn't be accurate... which defeats the reason for using Lab in the first place, I think!
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  5. #5
    Hyperactive Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    355

    Re: RGB, XYZ, and Lab conversions

    hi
    I use this:
    Code:
    Option Explicit
    'http://www.easyrgb.com/index.php?X=MATH&H=02#text2
    
    'MULTIPLICATION IS FASTER THAN DIVISION,
    'SO, SETUP SOME CONSTANTS:
    
    Private Const INV255 As Double = 1 / 255
    Private Const INV1p055 As Double = 1 / 1.055
    Private Const INV12p92 As Double = 1 / 12.92
    Private Const INV3 As Double = 1 / 3
    
    Private Const kX As Double = 100 / 95.047
    Private Const kY As Double = 100 / 100
    Private Const kZ As Double = 100 / 108.883
    
    Private Const INVkX As Double = 95.047 / 100
    Private Const INVkY As Double = 100 / 100
    Private Const INVkZ As Double = 108.883 / 100
    
    Private Const c16d116 As Double = 16 / 116
    
    Private Const INV7p787 As Double = 1 / 7.787
    
    Private Const INV2p4 As Double = 1 / 2.4
    
    Private Const INV116 As Double = 1 / 116
    Private Const INV200 As Double = 1 / 200
    Private Const INV500 As Double = 1 / 500
    
    Private Const INV2p55 As Double = 1 / 2.55
    Private Const INV1p275 As Double = 1 / 1.275
    
    
    
    Public Sub RGB2lab(R As Double, G As Double, B As Double, _
                       ByRef cL As Double, ByRef cA As Double, ByRef cB As Double)
    
        Dim RR     As Double
        Dim GG     As Double
        Dim BB     As Double
        Dim X      As Double
        Dim Y      As Double
        Dim Z      As Double
    
        RR = R * INV255
        GG = G * INV255
        BB = B * INV255
    
        If (RR > 0.04045) Then
            RR = ((RR + 0.055) * INV1p055) ^ 2.4
        Else
            RR = RR * INV12p92
        End If
    
        If (GG > 0.04045) Then
            GG = ((GG + 0.055) * INV1p055) ^ 2.4
        Else
            GG = GG * INV12p92
        End If
    
        If (BB > 0.04045) Then
            BB = ((BB + 0.055) * INV1p055) ^ 2.4
        Else
            BB = BB * INV12p92
        End If
    
    
        'RR = RR * 100
        'GG = GG * 100
        'BB = BB * 100
        '//Observer. = 2, Illuminant = D65
        X = RR * 0.4124 + GG * 0.3576 + BB * 0.1805
        Y = RR * 0.2126 + GG * 0.7152 + BB * 0.0722
        Z = RR * 0.0193 + GG * 0.1192 + BB * 0.9505
    
        '-----------------------------------------------------------
        'X = X / ref_X          '//ref_X =  95.047   Observer= 2, Illuminant= D65
        'Y = Y / ref_Y          '//ref_Y = 100.000
        'Z = Z / ref_Z          '//ref_Z = 108.883
        X = X * kX
        Y = Y * kY
        Z = Z * kZ
    
        If (X > 0.008856) Then X = X ^ (INV3) Else: X = (7.787 * X) + (c16d116)
        If (Y > 0.008856) Then Y = Y ^ (INV3) Else: Y = (7.787 * Y) + (c16d116)
        If (Z > 0.008856) Then Z = Z ^ (INV3) Else: Z = (7.787 * Z) + (c16d116)
    
        cL = (116 * Y) - 16                '0 to 100
        cA = 500 * (X - Y)                 'Circa -100 a 100
        cB = 200 * (Y - Z)
        'Debug.Print cb
    
    
        'Transfrom output Ranges (initialy from 0 to 100  &  -100 to 100 )
        'to [from 0 to 255]
    
        cL = cL * 2.55
        cA = 127.5 + cA * 1.275
        cB = 127.5 + cB * 1.275
        '-----------------------
    
    
        If cL > 255 Then cL = 255
        If cL < 0 Then cL = 0
        If cA > 255 Then cA = 255
        If cB > 255 Then cB = 255
    
        If cB < 0 Then cB = 0
        If cA < 0 Then cA = 0
    
    
    End Sub
    
    Public Sub LAB2RGB(ByVal cL As Double, ByVal cA As Double, ByVal cB As Double, _
                       ByRef R As Double, ByRef G As Double, ByRef B As Double)
    
        Dim X      As Double
        Dim Y      As Double
        Dim Z      As Double
        Dim X3     As Double
        Dim Y3     As Double
        Dim Z3     As Double
        
        'Check input Range
        'If cL > 255 Then Stop: cL = 255
        'If cL < 0 Then Stop: cL = 0
        'If cA > 255 Then Stop: cA = 255
        'If cA < 0 Then Stop: cA = 0
        'If cb > 255 Then Stop: cb = 255
        'If cb < 0 Then Stop: cb = 0
    
        'Reset input ranges
        'from 0 to 255
        'to [from 0 to 100] & [from -100 to 100]
        cL = cL * INV2p55    '/2.55
        cA = (cA - 127.5) * INV1p275    '/ 1.275
        cB = (cB - 127.5) * INV1p275    '/ 1.275
        '-------
    
        Y = (cL + 16) * INV116
        X = cA * INV500 + Y
        Z = Y - cB * INV200
    
        X3 = X * X * X
        Y3 = Y * Y * Y
        Z3 = Z * Z * Z
    
        If (Y3 > 0.008856) Then Y = Y3 Else: Y = (Y - c16d116) * INV7p787
        If (X3 > 0.008856) Then X = X3 Else: X = (X - c16d116) * INV7p787
        If (Z3 > 0.008856) Then Z = Z3 Else: Z = (Z - c16d116) * INV7p787
    
        'X = ref_X * x     //ref_X =  95.047     Observer= 2, Illuminant= D65
        'Y = ref_Y * y     //ref_Y = 100.000
        'Z = ref_Z * z     //ref_Z = 108.883
        X = X * INVkX
        Y = Y * INVkY
        Z = Z * INVkZ
    
        '--------------------------------------------------------------------------
        'x,y,z 0 to 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
    
        If (R > 0.0031308) Then R = 1.055 * (R ^ INV2p4) - 0.055 Else: R = 12.92 * R
        If (G > 0.0031308) Then G = 1.055 * (G ^ INV2p4) - 0.055 Else: G = 12.92 * G
        If (B > 0.0031308) Then B = 1.055 * (B ^ INV2p4) - 0.055 Else: B = 12.92 * B
    
        R = R * 255
        G = G * 255
        B = B * 255
    
        If R > 255 Then R = 255
        If G > 255 Then G = 255
        If B > 255 Then B = 255
        If R < 0 Then R = 0
        If G < 0 Then G = 0
        If B < 0 Then B = 0
    
    
    End Sub

    this should / could be useful
    Last edited by reexre; May 7th, 2014 at 04:37 PM.

  6. #6
    PowerPoster Nightwalker83's Avatar
    Join Date
    Dec 2001
    Location
    Adelaide, Australia
    Posts
    13,346

    Re: RGB, XYZ, and Lab conversions

    Quote Originally Posted by reexre View Post
    Private Const INVkX As Double = 95.047 / 100
    Private Const INVkY As Double = 100 / 100
    Private Const INVkZ As Double = 108.883 / 100
    Instead of that why not just?

    Code:
    Private Const INVkX As Double = .95047
    Private Const INVkY As Double = 1
    Private Const INVkZ As Double = 1.08883
    when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
    If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
    Please consider giving me some rep points if I help you a lot.
    Please rate my post if you find it helpful!
    Technology is a dangerous thing in the hands of an idiot! I am that idiot.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width