Solved

Color Conversion Formula Math

Posted on 2007-03-29
5
985 Views
Last Modified: 2012-06-22
I have some color information (RGB values) that I need to convert.  Based on the formulas provided by EasyRGB (www.easyrgb.com), there are some non-language-specific code examples provided that I am trying to convert to VBScript.  I am taking the RGB values, and converting them to XYZ values, and then to CIE-L*ab values.

My conversion from RGB to XYZ seems to be working correctly (based on some calculated checks provided by the EasyRGB website), but it goes wrong when moving from XYZ to CIE-L*ab.  Here is the sample code that I am working from:

**************************************
var_X = X / ref_X          //ref_X =  95.047  Observer= 2°, Illuminant= D65
var_Y = Y / ref_Y          //ref_Y = 100.000
var_Z = Z / ref_Z          //ref_Z = 108.883

if ( var_X > 0.008856 ) var_X = var_X ^ ( 1/3 )
else                    var_X = ( 7.787 * var_X ) + ( 16 / 116 )
if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
else                    var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
if ( var_Z > 0.008856 ) var_Z = var_Z ^ ( 1/3 )
else                    var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )

CIE-L* = ( 116 * var_Y ) - 16
CIE-a* = 500 * ( var_X - var_Y )
CIE-b* = 200 * ( var_Y - var_Z )
**************************************
Here's my VBScript-translated code:

        'XYZ -> CIE-L*ab
        'Observer = 2 degrees, Iluminant = D65
       
        varRefX = 95.047
        varRefY = 100
        varRefZ = 108.883
       
        varX = varOutX / varRefX
        varY = varOutY / varRefY
        varZ = varOutZ / varRefZ
       
        If (varX > 0.008856) Then
            varX = varX ^ (1 / 3)
        Else
            varX = (7.787 * varX) + (16 / 116)
        End If
       
        If (varY > 0.008856) Then
            varY = varY ^ (1 / 3)
        Else
            varY = (7.787 * varY) + (16 / 116)
        End If
       
        If (varZ > 0.008856) Then
            varZ = varZ ^ (1 / 3)
        Else
            varZ = (7.787 * varZ) + (16 / 116)
        End If

        varOutL = (116 * varY) - 16
        varOuta = 500 * (varX - varY)
        varOutb = 200 * (varY - varZ)
**************************************
The 'var' variables refer to Variant type.

The problem seems to occur with the 'varOuta' and 'varOutb' calcs.  The resulting values seem to need to be divided by 1000, but the length of the calculated values seem to be truncated to hexidecimal.

To see the various color formulas, go to http://www.easyrgb.com/math.html.

I am using Access 2007, Win XP Pro.

Thanks!
0
Comment
Question by:Donovan Moore
  • 3
  • 2
5 Comments
 

Author Comment

by:Donovan Moore
ID: 18817779
For anyone who needs them, here are the test values I'm using to check the results (substitute "real" numbers for the variables):

varOutX = 1.23403722412354
varOutY = 1.2983032342173
varOutZ = 1.41385222206264

The "expected" results (rounded) should be as follows:

varOutL = 11.2636
varOuta = 0.0012
varOutb = -0.0024
0
 
LVL 28

Expert Comment

by:omgang
ID: 18818430
I created a function in Access 2003 - I converted all your Variant variables to Double data type.  The results are as you expect

Public Function TestRGB()

        'XYZ -> CIE-L*ab
        'Observer = 2 degrees, Iluminant = D65
       
        Dim dblRefX As Double, dblRefY As Double, dblRefZ As Double
        Dim dblOutX As Double, dblOutY As Double, dblOutZ As Double
        Dim dblX As Double, dblY As Double, dblZ As Double
        Dim dblOutL As Double, dblOuta As Double, dblOutb As Double
       
        dblRefX = 95.047
        dblRefY = 100
        dblRefZ = 108.883
       
        dblOutX = 1.23403722412354
        dblOutY = 1.2983032342173
        dblOutZ = 1.41385222206264
       
        dblX = dblOutX / dblRefX
        dblY = dblOutY / dblRefY
        dblZ = dblOutZ / dblRefZ
       
        If (dblX > 0.008856) Then
            dblX = dblX ^ (1 / 3)
        Else
            dblX = (7.787 * dblX) + (16 / 116)
        End If
       
        If (dblY > 0.008856) Then
            dblY = dblY ^ (1 / 3)
        Else
            dblY = (7.787 * dblY) + (16 / 116)
        End If
       
        If (dblZ > 0.008856) Then
            dblZ = dblZ ^ (1 / 3)
        Else
            dblZ = (7.787 * dblZ) + (16 / 116)
        End If

        dblOutL = (116 * dblY) - 16
        dblOuta = 500 * (dblX - dblY)
        dblOutb = 200 * (dblY - dblZ)
       
        Debug.Print dblX & " -- " & dblOutL
        Debug.Print dblY & " -- " & dblOuta
        Debug.Print dblZ & " -- " & dblOutb
       
       
End Function

Output
0.235033597912027 -- 11.2636105173512
0.235031125149579 -- 1.23638122394298E-03   <----(this is 0.0012363 etc.)
0.235043356386178 -- -2.44624731974841E-03  <----(this is -0.0024462 etc.)

OM Gang
0
 

Author Comment

by:Donovan Moore
ID: 18819266
Excuse my ignorance, but how do I convert the '1.23638122394298E-03 ' and '-2.44624731974841E-03' values into the correct values?
0
 
LVL 28

Accepted Solution

by:
omgang earned 500 total points
ID: 18819368
Use the Round function to round the output to the desired number of decimal places.
OM Gang

Public Function TestRGB()

        'XYZ -> CIE-L*ab
        'Observer = 2 degrees, Iluminant = D65
       
        Dim dblRefX As Double, dblRefY As Double, dblRefZ As Double
        Dim dblOutX As Double, dblOutY As Double, dblOutZ As Double
        Dim dblX As Double, dblY As Double, dblZ As Double
        Dim dblOutL As Double, dblOuta As Double, dblOutb As Double
       
        dblRefX = 95.047
        dblRefY = 100
        dblRefZ = 108.883
       
        dblOutX = 1.23403722412354
        dblOutY = 1.2983032342173
        dblOutZ = 1.41385222206264
       
        dblX = dblOutX / dblRefX
        dblY = dblOutY / dblRefY
        dblZ = dblOutZ / dblRefZ
       
        If (dblX > 0.008856) Then
            dblX = dblX ^ (1 / 3)
        Else
            dblX = (7.787 * dblX) + (16 / 116)
        End If
       
        If (dblY > 0.008856) Then
            dblY = dblY ^ (1 / 3)
        Else
            dblY = (7.787 * dblY) + (16 / 116)
        End If
       
        If (dblZ > 0.008856) Then
            dblZ = dblZ ^ (1 / 3)
        Else
            dblZ = (7.787 * dblZ) + (16 / 116)
        End If

        dblOutL = (116 * dblY) - 16
        dblOuta = 500 * (dblX - dblY)
        dblOutb = 200 * (dblY - dblZ)
       
        Debug.Print dblX & " -- " & dblOutL & " -- " & Round(dblOutL, 4)
        Debug.Print dblY & " -- " & dblOuta & " -- " & Round(dblOuta, 4)
        Debug.Print dblZ & " -- " & dblOutb & " -- " & Round(dblOutb, 4)
       
       
End Function


Output
0.235033597912027 -- 11.2636105173512 -- 11.2636
0.235031125149579 -- 1.23638122394298E-03 -- 0.0012
0.235043356386178 -- -2.44624731974841E-03 -- -0.0024
0
 

Author Comment

by:Donovan Moore
ID: 18819503
Thank you!
0

Featured Post

Back Up Your Microsoft Windows Server®

Back up all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Access 2016 7 35
How to get the closest date in a query in Access 2010 8 22
Criteria for Date for DCount 4 23
Part 2 to aggregate query solved qtn 12 32
When you are entering numbers in a speadsheet, and don't remember what 6×7 is, you just type “=6*7" instead. It works in every cell! This is not so in Access. To enter the elusive 42 in a text box, you have to find a calculator, and then copy the re…
Experts-Exchange is a great place to come for help with solutions for your database issues, and many problems are resolved within minutes of being posted.  Others take a little more time and effort and often providing a sample database is very helpf…
Learn how to number pages in an Access report over each group. Activate two pass printing by referencing the pages property: Add code to the Page Footers OnFormat event to capture the pages as there occur for each group. Use the pages property to …
In Microsoft Access, learn how to “cascade” or have the displayed data of one combo control depend upon what’s entered in another. Base the dependent combo on a query for its row source: Add a reference to the first combo on the form as criteria i…

773 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question