Author Topic: CieDe2000 algorithm  (Read 7259 times)

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
CieDe2000 algorithm
« on: May 24, 2014, 05:08:56 AM »
The cieDe2000 is a excellent algorithm function to compute the distance between 2 colors. It is used in color-matching softwares.
You can use it to see if a given color is chromatically similar to another one.

The resultant value can be used to you setup a limit to similarity. Ex: If it returns values smaller then 1 the color matches.

The code is not pretty and was ported , but...it works perfectly. I didn´t optimized it yet (It is a bit slow due to heavy computations and lack of optimization). To use it, activate the equal preparse routine on rosasm. Remember that all parameters must be a pointer to a double variable (float R$ type)

Code: [Select]

;;
    http://ramblings.mcpher.com/Home/excelquirks/colorfiesta/nearest
    calculates the distance between 2 colors using CIEDE200
    see http://www.ece.rochester.edu/~gsharma/cieDe2000/cieDe2000noteCRNA.pdf


Public Function cieDe2000(p1 As colorProps, p2 As colorProps) As Double
    ' calculates the distance between 2 colors using CIEDE200
    ' see http://www.ece.rochester.edu/~gsharma/cieDe2000/cieDe2000noteCRNA.pdf
    Dim c1 As Double, c2 As Double, _
        c As Double, g As Double, a1 As Double, b1 As Double, _
        a2 As Double, b2 As Double, c1Tick As Double, c2Tick As Double, _
        h1 As Double, h2 As Double, dh As Double, dl As Double, dc As Double, _
        lTickAvg As Double, cTickAvg As Double, hTickAvg As Double, l50 As Double, sl As Double, _
        sc As Double, t As Double, sh As Double, dTheta As Double, kp As Double, _
        rc As Double, kl As Double, kc As Double, kh As Double, dlk As Double, _
        dck As Double, dhk As Double, rt As Double, dBigH As Double
   
    kp = 25 ^ 7
    kl = 1
    kc = 1
    kh = 1
   
    ' calculate c & g values
    c1 = Sqr(p1.aStar ^ 2 + p1.bStar ^ 2)
    c2 = Sqr(p2.aStar ^ 2 + p2.bStar ^ 2)
    c = (c1 + c2) / 2
    g = 0.5 * (1 - Sqr(c ^ 7 / (c ^ 7 + kp)))

    ' adjusted ab*
    a1 = (1 + g) * p1.aStar
    a2 = (1 + g) * p2.aStar

    ' adjusted cs
    c1Tick = Sqr(a1 ^ 2 + p1.bStar ^ 2)
    c2Tick = Sqr(a2 ^ 2 + p2.bStar ^ 2)

    ' adjusted h
    h1 = computeH(a1, p1.bStar)
    h2 = computeH(a2, p2.bStar)

   
    ' deltas
    If (h2 - h1 > 180) Then '1
        dh = h2 - h1 - 360
    ElseIf (h2 - h1 < -180) Then ' 2
        dh = h2 - h1 + 360
    Else '0
        dh = h2 - h1
    End If

    dl = p2.LStar - p1.LStar
    dc = c2Tick - c1Tick
    dBigH = (2 * Sqr(c1Tick * c2Tick) * sIn(toRadians(dh / 2)))

    ' averages
    lTickAvg = (p1.LStar + p2.LStar) / 2
    cTickAvg = (c1Tick + c2Tick) / 2

   
    If (c1Tick * c2Tick = 0) Then '3
        hTickAvg = h1 + h2
   
    ElseIf (Abs(h2 - h1) <= 180) Then '0
        hTickAvg = (h1 + h2) / 2
   
    ElseIf (h2 + h1 < 360) Then '1
        hTickAvg = (h1 + h2) / 2 + 180
   
    Else '2
        hTickAvg = (h1 + h2) / 2 - 180
    End If
   
    l50 = (lTickAvg - 50) ^ 2
    sl = 1 + (0.015 * l50 / Sqr(20 + l50))
    sc = 1 + 0.045 * cTickAvg
    t = 1 - 0.17 * Cos(toRadians(hTickAvg - 30)) + 0.24 * _
            Cos(toRadians(2 * hTickAvg)) + 0.32 * _
            Cos(toRadians(3 * hTickAvg + 6)) - 0.2 * _
            Cos(toRadians(4 * hTickAvg - 63))

    sh = 1 + 0.015 * cTickAvg * t

    dTheta = 30 * Exp(-1 * ((hTickAvg - 275) / 25) ^ 2)
    rc = 2 * Sqr(cTickAvg ^ 7 / (cTickAvg ^ 7 + kp))
    rt = -sIn(toRadians(2 * dTheta)) * rc
    dlk = dl / sl / kl
    dck = dc / sc / kc
    dhk = dBigH / sh / kh
    cieDe2000 = Sqr(dlk ^ 2 + dck ^ 2 + dhk ^ 2 + rt * dck * dhk)
   
End Function
Public Function compareColors(rgb1 As Long, rgb2 As Long, _
            Optional compareType As eCompareColor = eCompareColor.eccieDe2000) As Double
    Dim p1 As colorProps, p2 As colorProps
    p1 = makeColorProps(rgb1)
    p2 = makeColorProps(rgb2)
    Select Case compareType
        Case eCompareColor.eccieDe2000
            compareColors = cieDe2000(p1, p2)
           
        Case Else
            Debug.Assert False
   
    End Select
   
End Function
Private Function computeH(a As Double, b As Double) As Double
    If (a = 0 And b = 0) Then
        computeH = 0
    ElseIf (b >= 0) Then
        computeH = Application.WorksheetFunction.Degrees(Application.WorksheetFunction.Atan2(a, b))
    Else
        computeH = Application.WorksheetFunction.Degrees(Application.WorksheetFunction.Atan2(a, b)) + 360
    End If
End Function
Private Function rgbToLab(rgbColor As Long) As colorProps
    ' adapted from // http://www.easyrgb.com/
    Dim x As Double, y As Double, z As Double, _
        p As colorProps

    p = rgbToXyz(rgbColor)
   
    x = xyzCIECorrection(p.x / refWhiteX)
    y = xyzCIECorrection(p.y / refWhiteY)
    z = xyzCIECorrection(p.z / refWhiteZ)

    p.LStar = (116 * y) - 16
    p.aStar = 500 * (x - y)
    p.bStar = 200 * (y - z)

    rgbToLab = p
End Function
Private Function rgbToXyz(rgbColor As Long) As colorProps
    ' adapted from // http://www.easyrgb.com/
    Dim r As Double, g As Double, b As Double, _
        p As colorProps
   
    r = xyzCorrection(rgbRed(rgbColor) / 255) * 100
    g = xyzCorrection(rgbGreen(rgbColor) / 255) * 100
    b = xyzCorrection(rgbBlue(rgbColor) / 255) * 100
   
    p.x = r * 0.4124 + g * 0.3576 + b * 0.1805
    p.y = r * 0.2126 + g * 0.7152 + b * 0.0722
    p.z = r * 0.0193 + g * 0.1192 + b * 0.9505

    rgbToXyz = p
End Function
Private Function xyzCIECorrection(v As Double) As Double
    If (v > 0.008856) Then
        xyzCIECorrection = (v ^ (1 / 3))
    Else
        xyzCIECorrection = (7.787 * v) + (16 / 116)
    End If
End Function
Private Function xyzCorrection(v As Double) As Double
    If (v > 0.04045) Then
        xyzCorrection = ((v + 0.055) / 1.055) ^ 2.4
    Else
        xyzCorrection = v / 12.92
    End If
End Function



;;
________________________________________________________________________________________

[FLoatMinus180: R$ -180]
[kp: R$ 6103515625]; 25^7
[kl: R$ 1]
[kc: R$ 1]
[kh: R$ 1]
[GFactor: R$ 0]
[TempLuma1: R$ 0]
[TempAFact1: R$ 0]
[TempBFact1: R$ 0]
[TempLuma2: R$ 0]
[TempAFact2: R$ 0]
[TempBFact2: R$ 0]
[CFactor: R$ 0]
[A1Factor: R$ 0]
[A2Factor: R$ 0]
[c1Tick: R$ 0]
[c2Tick: R$ 0]
[H1Factor: R$ 0]
[H2Factor: R$ 0]
[HDelta: R$ 0]
[HDeltaMax: R$ 0]
[DeltaL: R$ 0]
[DeltaC: R$ 0]
[Degree_Radian: R$ 0.0174532925199432957692369076848861271344287188854172] ; PI/180
[DeltaBigH: R$ 0]
[lTickAvg: R$ 0]
[cTickAvg: R$ 0]
[hTickAvg: R$ 0]
[c1_2TickAvg: R$ 0]
[HDeltaAbs: R$ 0]
[HDeltaAdd: R$ 0]
[Light50: R$ 0]
[Float50: R$ 50]
[slFactor: R$ 0]
[scFactor: R$ 0]
[TFactor: R$ 0]
[Float0015: R$ 0.015]
[Float0045: R$ 0.045]
[FloatOneSeventeen: R$ 0.17]
[Float20: R$ 20]
[CosFactor1: R$ 0]
[CosFactor2: R$ 0]
[CosFactor3: R$ 0]
[CosFactor4: R$ 0]
[Float30: R$ 30]
[FloatOne24: R$ 0.24]
[FloatOne32: R$ 0.32]
[Float63: R$ 63]
[FloatOneTwo: R$ 0.2]
[shFactor: R$ 0]
[dTheta: R$ 0]
[Float275: R$ 275]
[Float25: R$ 25]
[rcFactor: R$ 0]

[rtFactor: R$ 0]
[dlkFactor: R$ 0]
[dckFactor: R$ 0]
[dhkFactor: R$ 0]

Proc cieDe2000:
    Arguments @Luma1, @Afact1, @BFact1, @Luma2, @AFact2, @BFact2
    Uses ebx, eax, edx

    mov ebx D@Luma1 | fld R$ebx | fstp R$TempLuma1
    mov ebx D@Afact1 | fld R$ebx | fstp R$TempAFact1
    mov ebx D@Bfact2 | fld R$ebx | fstp R$TempBFact1
    mov ebx D@Luma2 | fld R$ebx | fstp R$TempLuma2
    mov ebx D@Afact2 | fld R$ebx | fstp R$TempAFact2
    mov ebx D@Bfact2 | fld R$ebx | fstp R$TempBFact2

    ; calculate c and g values
    fld R$TempAFact1 | fmul ST0 ST0 | fld R$TempBFact1 | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt
    fld R$TempAFact2 | fmul ST0 ST0 | fld R$TempBFact2 | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt
    faddp ST1 ST0 | fmul R$FLoatHalf | fstp R$CFactor

    R$GFactor = R$FloatHalf * (R$FLoatOne - sqrt( (R$CFactor^7)/( (R$CFactor^7)+R$kp) ) )

    ; adjusted ab
    fld R$GFactor | fadd R$FloatOne | fmul R$TempAFact1 | fstp R$A1Factor
    fld R$GFactor | fadd R$FloatOne | fmul R$TempAFact2 | fstp R$A2Factor

    ; adjusted cs
    fld R$A1Factor | fmul ST0 ST0 | fld R$TempBFact1 | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt | fstp R$c1Tick
    fld R$A2Factor | fmul ST0 ST0 | fld R$TempBFact2 | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt | fstp R$c2Tick

    ; adjusted h
    call ComputedH A1Factor, TempBFact1, H1Factor
    call ComputedH A2Factor, TempBFact2, H2Factor

    ; deltas
    fld R$H2Factor | fsub R$H1Factor | fstp R$HDelta

    Fpu_If R$HDelta > R$FLoat180
        fld R$HDelta | fsub R$Float360 | fstp R$HDeltaMax
    Fpu_Else_If R$HDelta > R$FLoatMinus180
        fld R$HDelta | fadd R$Float360 | fstp R$HDeltaMax
    Fpu_Else
        fld R$HDelta | fstp R$HDeltaMax
    Fpu_End_If

    fld R$TempLuma2 | fsub R$TempLuma1 | fstp R$DeltaL
    fld R$c2Tick | fsub R$c1Tick | fstp R$DeltaC

    fld R$c1Tick | fmul R$c2Tick | fsqrt | fmul R$FloatTwo | fld R$HDeltaMax | fmul R$FloatHalf | fmul R$Degree_Radian | fsin
    fmulp ST1 ST0 | fstp R$DeltaBigH

    ; averages
    fld R$TempLuma1 | fadd R$TempLuma2 | fmul R$FloatHalf | fstp R$lTickAvg
    fld R$c1Tick | fadd R$c2Tick | fmul R$FloatHalf | fstp R$cTickAvg

    fld R$c1Tick | fmul R$c2Tick | fstp R$c1_2TickAvg
    fld R$HDelta | fabs | fstp R$HDeltaAbs
    fld R$H2Factor | fadd R$H1Factor | fstp R$HDeltaAdd

    Fpu_If R$c1_2TickAvg = R$FloatZero
        fld R$HDeltaAdd | fstp R$hTickAvg
    Fpu_Else_If R$HDeltaAbs <= R$Float180
        fld R$HDeltaAdd | fmul R$FloatHalf | fstp R$hTickAvg
    Fpu_Else_If R$HDeltaAdd < R$Float360
        fld R$HDeltaAdd | fmul R$FloatHalf | fadd R$Float180 | fstp R$hTickAvg
    Fpu_Else
        fld R$HDeltaAdd | fmul R$FloatHalf | fsub R$Float180 | fstp R$hTickAvg
    Fpu_End_If

    fld R$lTickAvg | fsub R$Float50 | fmul ST0 ST0 | fstp R$Light50

    fld R$Light50 | fadd R$Float20 | fsqrt | fld R$Light50 | fmul R$Float0015 | fdivrp ST1 ST0 | fadd R$FloatOne | fstp R$slFactor

    fld R$cTickAvg | fmul R$Float0045 | fadd R$FloatOne | fstp R$scFactor

    ; calc T
    fld R$hTickAvg | fsub R$Float30 | fmul R$Degree_Radian | fcos | fmul R$FloatOneSeventeen | fstp R$CosFactor1
    fld R$hTickAvg | fmul R$FloatTwo | fmul R$Degree_Radian | fcos | fmul R$FloatOne24 | fstp R$CosFactor2
    fld R$hTickAvg | fmul R$FloatThree | fadd R$FloatSix | fmul R$Degree_Radian | fcos | fmul R$FloatOne32 | fstp R$CosFactor3
    fld R$hTickAvg | fmul R$FloatFour | fsub R$Float63 | fmul R$Degree_Radian | fcos | fmul R$FloatOneTwo | fstp R$CosFactor4
    fld1 | fsub R$CosFactor1 | fadd R$CosFactor2 | fadd R$CosFactor3 | fsub R$CosFactor4 | fstp R$TFactor

    fld R$cTickAvg | fmul R$TFactor | fmul R$Float0015 | fadd R$FloatOne | fstp R$shFactor

    ; calc dtheta
    R$dTheta = R$Float30 * (exp(R$FloatMinusOne * (((R$hTickAvg - R$Float275) / R$Float25)^2)))

    R$rcFactor = R$FloatTwo*(sqrt( (R$cTickAvg^7)/( (R$cTickAvg^7)+R$kp) ))

    fld R$dTheta | fmul R$FloatTwo | fmul R$Degree_Radian | fsin | fmul R$rcFactor | fmul R$FloatMinusOne | fstp R$rtFactor

    fld R$DeltaL | fdiv R$slFactor | fdiv R$kl | fstp R$dlkFactor
    fld R$DeltaC | fdiv R$scFactor | fdiv R$kc | fstp R$dckFactor
    fld R$DeltaBigH | fdiv R$shFactor | fdiv R$kh | fstp R$dhkFactor

    fld R$dlkFactor | fmul ST0 ST0 | fld R$dckFactor | fmul ST0 ST0 | faddp ST1 ST0
    fld R$dhkFactor | fmul ST0 ST0 | faddp ST1 ST0
    fld R$dckFactor | fmul R$dhkFactor | fmul R$rtFactor
    faddp ST1 ST0 | fsqrt

EndP
____________________________________________

Proc ComputedH:
    Arguments @aFact, @bFact, @HFact
    Uses ebx, esi, ecx, edi, eax

    mov ebx D@aFact
    mov esi D@bFact
    mov edi D@HFact

    .Fpu_If_And R$ebx = R$FloatZero, R$esi = R$FloatZero
        fldz | fstp R$edi
    .Fpu_Else_If R$esi >= R$FloatZero
        C_call 'msvcrt.atan2' D$ebx, D$ebx+4, D$esi, D$esi+4 | fstp R$edi
    .Fpu_Else
        C_call 'msvcrt.atan2' D$ebx, D$ebx+4, D$esi, D$esi+4
        fadd R$Float360 | fstp R$edi
    .Fpu_End_If

EndP


example of usage:

Code: [Select]
[ColorDistance: R$ 0]

; for perceptual similarity
[LumaPercep: R$ 0]
[aFactPercep: R$ 0]
[bFactPercep: R$ 0]

    call cieDe2000 D@OldLuma, D@OldaFactor, D@OldbFactor, LumaPercep, aFactPercep, bFactPercep
    fstp R$ColorDistance


Note by me: Another way to compute the similarity of 2 colors on a much much faster way is simply comparing the delta values os Luma, aFactor and bFactor.
The Ciede2000 algorithm is very very precise, but a raw computation for similarity can be done, analysing if all of the values of delta from CieLab are smaller then 80% of the CieLab result values

Example:
DeltaLuma = abs (Luma1-Luma2)*80%
DeltaaFactor = abs (aFactor1-aFactor2)*80%
DeltabFactor = abs (bFactor1-bFactor2)*80%

If DeltaLuma and DeltaaFactor and DeltabFactor are smaller or equal to 1, you can safelly says that the color matches.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
Re: CieDe2000 algorithm
« Reply #1 on: May 24, 2014, 05:29:12 AM »
Btw: The CieDE2000 algo is way more precise when you compute the values from CieLab using the whitepoint referencies. I.e: using the XYZ matrices such as:

Code: [Select]
[FloatXYZWorkSpacesMatrices:
 FloatAdobe_RGB_1998_D65_Red_M1: R$ 0.5767309  FloatAdobe_RGB_1998_D65_Green_M2: R$ 0.185554     FloatAdobe_RGB_1998_D65_Blue_M3: R$ 0.1881852
 FloatAdobe_RGB_1998_D65_Red_M4: R$ 0.2973769  FloatAdobe_RGB_1998_D65_Green_M5: R$ 0.6273491    FloatAdobe_RGB_1998_D65_Blue_M6: R$ 0.0752741
 FloatAdobe_RGB_1998_D65_Red_M7: R$ 0.0270343  FloatAdobe_RGB_1998_D65_Green_M8: R$ 0.0706872    FloatAdobe_RGB_1998_D65_Blue_M9: R$ 0.9911085

 FloatAppleRGB_D65_Red_M1: R$ 0.4497288        FloatAppleRGB_D65_Green_M2: R$ 0.3162486          FloatAppleRGB_D65_Blue_M3: R$ 0.1844926
 FloatAppleRGB_D65_Red_M4: R$ 0.2446525        FloatAppleRGB_D65_Green_M5: R$ 0.6720283          FloatAppleRGB_D65_Blue_M6: R$ 0.0833192
 FloatAppleRGB_D65_Red_M7: R$ 0.0251848        FloatAppleRGB_D65_Green_M8: R$ 0.1411824          FloatAppleRGB_D65_Blue_M9: R$ 0.9224628

 FloatBest_RGB_D50_Red_M1: R$ 0.6326696        FloatBest_RGB_D50_Green_M2: R$ 0.2045558          FloatBest_RGB_D50_Blue_M3: R$ 0.1269946
 FloatBest_RGB_D50_Red_M4: R$ 0.2284569        FloatBest_RGB_D50_Green_M5: R$ 0.7373523          FloatBest_RGB_D50_Blue_M6: R$ 0.0341908
 FloatBest_RGB_D50_Red_M7: R$ 0                FloatBest_RGB_D50_Green_M8: R$ 0.0095142          FloatBest_RGB_D50_Blue_M9: R$ 0.8156958

 FloatBeta_RGB_D50_Red_M1: R$ 0.6712537        FloatBeta_RGB_D50_Green_M2: R$ 0.1745834          FloatBeta_RGB_D50_Blue_M3: R$ 0.1183829
 FloatBeta_RGB_D50_Red_M4: R$ 0.3032726        FloatBeta_RGB_D50_Green_M5: R$ 0.6637861          FloatBeta_RGB_D50_Blue_M6: R$ 0.0329413
 FloatBeta_RGB_D50_Red_M7: R$ 0                FloatBeta_RGB_D50_Green_M8: R$ 0.040701           FloatBeta_RGB_D50_Blue_M9: R$ 0.784509

 FloatBruce_RGB_D65_Red_M1: R$ 0.4674162       FloatBruce_RGB_D65_Green_M2: R$ 0.2944512         FloatBruce_RGB_D65_Blue_M3: R$ 0.1886026
 FloatBruce_RGB_D65_Red_M4: R$ 0.2410115       FloatBruce_RGB_D65_Green_M5: R$ 0.6835475         FloatBruce_RGB_D65_Blue_M6: R$ 0.075441
 FloatBruce_RGB_D65_Red_M7: R$ 0.0219101       FloatBruce_RGB_D65_Green_M8: R$ 0.0736128         FloatBruce_RGB_D65_Blue_M9: R$ 0.9933071

 FloatCIE_RGB_E_Red_M1: R$ 0.488718            FloatCIE_RGB_E_Green_M2: R$ 0.3106803             FloatCIE_RGB_E_Blue_M3: R$ 0.2006017
 FloatCIE_RGB_E_Red_M4: R$ 0.1762044           FloatCIE_RGB_E_Green_M5: R$ 0.8129847             FloatCIE_RGB_E_Blue_M6: R$ 0.0108109
 FloatCIE_RGB_E_Red_M7: R$ 0                   FloatCIE_RGB_E_Green_M8: R$ 0.0102048             FloatCIE_RGB_E_Blue_M9: R$ 0.9897952

 FloatColorMatch_RGB_D50_Red_M1: R$ 0.5093439  FloatColorMatch_RGB_D50_Green_M2: R$ 0.3209071    FloatColorMatch_RGB_D50_Blue_M3: R$ 0.1339691
 FloatColorMatch_RGB_D50_Red_M4: R$ 0.274884   FloatColorMatch_RGB_D50_Green_M5: R$ 0.6581315    FloatColorMatch_RGB_D50_Blue_M6: R$ 0.0669845
 FloatColorMatch_RGB_D50_Red_M7: R$ 0.0242545  FloatColorMatch_RGB_D50_Green_M8: R$ 0.1087821    FloatColorMatch_RGB_D50_Blue_M9: R$ 0.6921735

 FloatDon_RGB_4_D50_Red_M1: R$ 0.6457711       FloatDon_RGB_4_D50_Green_M2: R$ 0.1933511         FloatDon_RGB_4_D50_Blue_M3: R$ 0.1250978
 FloatDon_RGB_4_D50_Red_M4: R$ 0.2783496       FloatDon_RGB_4_D50_Green_M5: R$ 0.6879702         FloatDon_RGB_4_D50_Blue_M6: R$ 0.0336802
 FloatDon_RGB_4_D50_Red_M7: R$ 0.0037113       FloatDon_RGB_4_D50_Green_M8: R$ 0.0179861         FloatDon_RGB_4_D50_Blue_M9: R$ 0.8035125

 FloatECI_RGB_D50_Red_M1: R$ 0.6502043         FloatECI_RGB_D50_Green_M2: R$ 0.1780774           FloatECI_RGB_D50_Blue_M3: R$ 0.1359384
 FloatECI_RGB_D50_Red_M4: R$ 0.3202499         FloatECI_RGB_D50_Green_M5: R$ 0.6020711           FloatECI_RGB_D50_Blue_M6: R$ 0.0776791
 FloatECI_RGB_D50_Red_M7: R$ 0                 FloatECI_RGB_D50_Green_M8: R$ 0.067839            FloatECI_RGB_D50_Blue_M9: R$ 0.757371

 FloatEkta_Space_PS5_D50_Red_M1: R$ 0.5938914  FloatEkta_Space_PS5_D50_Green_M2: R$ 0.2729801    FloatEkta_Space_PS5_D50_Blue_M3: R$ 0.0973485
 FloatEkta_Space_PS5_D50_Red_M4: R$ 0.2606286  FloatEkta_Space_PS5_D50_Green_M5: R$ 0.7349465    FloatEkta_Space_PS5_D50_Blue_M6: R$ 0.0044249
 FloatEkta_Space_PS5_D50_Red_M7: R$ 0          FloatEkta_Space_PS5_D50_Green_M8: R$ 0.0419969    FloatEkta_Space_PS5_D50_Blue_M9: R$ 0.7832131

 FloatNTSC_RGB_C_Red_M1: R$ 0.6068909          FloatNTSC_RGB_C_Green_M2: R$ 0.1735011            FloatNTSC_RGB_C_Blue_M3: R$ 0.200348
 FloatNTSC_RGB_C_Red_M4: R$ 0.2989164          FloatNTSC_RGB_C_Green_M5: R$ 0.586599             FloatNTSC_RGB_C_Blue_M6: R$ 0.1144845
 FloatNTSC_RGB_C_Red_M7: R$ 0                  FloatNTSC_RGB_C_Green_M8: R$ 0.0660957            FloatNTSC_RGB_C_Blue_M9: R$ 1.1162243

 FloatPAL_SECAM_RGB_D65_Red_M1: R$ 0.430619    FloatPAL_SECAM_RGB_D65_Green_M2: R$ 0.3415419     FloatPAL_SECAM_RGB_D65_Blue_M3: R$ 0.1783091
 FloatPAL_SECAM_RGB_D65_Red_M4: R$ 0.2220379   FloatPAL_SECAM_RGB_D65_Green_M5: R$ 0.7066384     FloatPAL_SECAM_RGB_D65_Blue_M6: R$ 0.0713236
 FloatPAL_SECAM_RGB_D65_Red_M7: R$ 0.0201853   FloatPAL_SECAM_RGB_D65_Green_M8: R$ 0.1295504     FloatPAL_SECAM_RGB_D65_Blue_M9: R$ 0.9390944

 FloatProPhoto_RGB_D50_Red_M1: R$ 0.7976749    FloatProPhoto_RGB_D50_Green_M2: R$ 0.1351917      FloatProPhoto_RGB_D50_Blue_M3: R$ 0.0313534
 FloatProPhoto_RGB_D50_Red_M4: R$ 0.2880402    FloatProPhoto_RGB_D50_Green_M5: R$ 0.7118741      FloatProPhoto_RGB_D50_Blue_M6: R$ 0.0000857
 FloatProPhoto_RGB_D50_Red_M7: R$ 0            FloatProPhoto_RGB_D50_Green_M8: R$ 0              FloatProPhoto_RGB_D50_Blue_M9: R$ 0.82521

 FloatSMPTE_C_RGB_D65_Red_M1: R$ 0.3935891     FloatSMPTE_C_RGB_D65_Green_M2: R$ 0.3652497       FloatSMPTE_C_RGB_D65_Blue_M3: R$ 0.1916313
 FloatSMPTE_C_RGB_D65_Red_M4: R$ 0.2124132     FloatSMPTE_C_RGB_D65_Green_M5: R$ 0.7010437       FloatSMPTE_C_RGB_D65_Blue_M6: R$ 0.0865432
 FloatSMPTE_C_RGB_D65_Red_M7: R$ 0.0187423     FloatSMPTE_C_RGB_D65_Green_M8: R$ 0.1119313       FloatSMPTE_C_RGB_D65_Blue_M9: R$ 0.9581563

 FloatsRGB_D65_Red_M1: R$ 0.4124564            FloatsRGB_D65_Green_M2: R$ 0.3575761              FloatsRGB_D65_Blue_M3: R$ 0.1804375
 FloatsRGB_D65_Red_M4: R$ 0.2126729            FloatsRGB_D65_Green_M5: R$ 0.7151522              FloatsRGB_D65_Blue_M6: R$ 0.0721750
 FloatsRGB_D65_Red_M7: R$ 0.0193339            FloatsRGB_D65_Green_M8: R$ 0.1191920              FloatsRGB_D65_Blue_M9: R$ 0.9503041

 FloatWide_Gamut_RGB_D50_Red_M1: R$ 0.7161046  FloatWide_Gamut_RGB_D50_Green_M2: R$ 0.1009296    FloatWide_Gamut_RGB_D50_Blue_M3: R$ 0.1471858
 FloatWide_Gamut_RGB_D50_Red_M4: R$ 0.2581874  FloatWide_Gamut_RGB_D50_Green_M5: R$ 0.7249378    FloatWide_Gamut_RGB_D50_Blue_M6: R$ 0.0168748
 FloatWide_Gamut_RGB_D50_Red_M7: R$ 0          FloatWide_Gamut_RGB_D50_Green_M8: R$ 0.0517813    FloatWide_Gamut_RGB_D50_Blue_M9: R$ 0.7734287


 FloatAdobe_RGB_1998_D50_M1: R$ 0.6097559      FloatAdobe_RGB_1998_D50_M2: R$ 0.2052401          FloatAdobe_RGB_1998_D50_M3: R$ 0.1492240
 FloatAdobe_RGB_1998_D50_M4: R$ 0.3111242      FloatAdobe_RGB_1998_D50_M5: R$ 0.6256560          FloatAdobe_RGB_1998_D50_M6: R$ 0.0632197
 FloatAdobe_RGB_1998_D50_M7: R$ 0.0194811      FloatAdobe_RGB_1998_D50_M8: R$ 0.0608902          FloatAdobe_RGB_1998_D50_M9: R$ 0.7448387

 FloatAppleRGB_D50_M1: R$ 0.4755678            FloatAppleRGB_D50_M2: R$ 0.3396722                FloatAppleRGB_D50_M3: R$ 0.1489800
 FloatAppleRGB_D50_M4: R$ 0.2551812            FloatAppleRGB_D50_M5: R$ 0.6725693                FloatAppleRGB_D50_M6: R$ 0.0722496
 FloatAppleRGB_D50_M7: R$ 0.0184697            FloatAppleRGB_D50_M8: R$ 0.1133771                FloatAppleRGB_D50_M9: R$ 0.6933632

 FloatBruce_RGB_D50_M1: R$ 0.4941816           FloatBruce_RGB_D50_M2: R$ 0.3204834               FloatBruce_RGB_D50_M3: R$ 0.1495550
 FloatBruce_RGB_D50_M4: R$ 0.2521531           FloatBruce_RGB_D50_M5: R$ 0.6844869               FloatBruce_RGB_D50_M6: R$ 0.0633600
 FloatBruce_RGB_D50_M7: R$ 0.0157886           FloatBruce_RGB_D50_M8: R$ 0.0629304               FloatBruce_RGB_D50_M9: R$ 0.7464909

 FloatCIE_RGB_D50_M1: R$ 0.4868870             FloatCIE_RGB_D50_M2: R$ 0.3062984                 FloatCIE_RGB_D50_M3: R$ 0.1710347
 FloatCIE_RGB_D50_M4: R$ 0.1746583             FloatCIE_RGB_D50_M5: R$ 0.8247541                 FloatCIE_RGB_D50_M6: R$ 0.0005877
 FloatCIE_RGB_D50_M7: R$ -0.0012563            FloatCIE_RGB_D50_M8: R$ 0.0169832                 FloatCIE_RGB_D50_M9: R$ 0.8094831

 FloatNTSC_RGB_D50_M1: R$ 0.6343706            FloatNTSC_RGB_D50_M2: R$ 0.1852204                FloatNTSC_RGB_D50_M3: R$ 0.1446290
 FloatNTSC_RGB_D50_M4: R$ 0.3109496            FloatNTSC_RGB_D50_M5: R$ 0.5915984                FloatNTSC_RGB_D50_M6: R$ 0.0974520
 FloatNTSC_RGB_D50_M7: R$ -0.0011817           FloatNTSC_RGB_D50_M8: R$ 0.0555518                FloatNTSC_RGB_D50_M9: R$ 0.7708399

 FloatPAL_SECAM_RGB_D50_M1: R$ 0.4552773       FloatPAL_SECAM_RGB_D50_M2: R$ 0.3675500           FloatPAL_SECAM_RGB_D50_M3: R$ 0.1413926
 FloatPAL_SECAM_RGB_D50_M4: R$ 0.2323025       FloatPAL_SECAM_RGB_D50_M5: R$ 0.7077956           FloatPAL_SECAM_RGB_D50_M6: R$ 0.0599019
 FloatPAL_SECAM_RGB_D50_M7: R$ 0.0145457       FloatPAL_SECAM_RGB_D50_M8: R$ 0.1049154           FloatPAL_SECAM_RGB_D50_M9: R$ 0.7057489

 FloatSMPTE_C_RGB_D50_M1: R$ 0.4163290         FloatSMPTE_C_RGB_D50_M2: R$ 0.3931464             FloatSMPTE_C_RGB_D50_M3: R$ 0.1547446
 FloatSMPTE_C_RGB_D50_M4: R$ 0.2216999         FloatSMPTE_C_RGB_D50_M5: R$ 0.7032549             FloatSMPTE_C_RGB_D50_M6: R$ 0.0750452
 FloatSMPTE_C_RGB_D50_M7: R$ 0.0136576         FloatSMPTE_C_RGB_D50_M8: R$ 0.0913604             FloatSMPTE_C_RGB_D50_M9: R$ 0.7201920

 FloatsRGB_D50_M1: R$ 0.4360747                FloatsRGB_D50_M2: R$ 0.3850649                    FloatsRGB_D50_M3: R$ 0.1430804
 FloatsRGB_D50_M4: R$ 0.2225045                FloatsRGB_D50_M5: R$ 0.7168786                    FloatsRGB_D50_M6: R$ 0.0606169
 FloatsRGB_D50_M7: R$ 0.0139322                FloatsRGB_D50_M8: R$ 0.0971045                    FloatsRGB_D50_M9: R$ 0.7141733

 FloatsRGB_D65_Red_HDTV_M1: R$ 0.4124564       FloatsRGB_D65_Green_HDTV_M2: R$ 0.3575761         FloatsRGB_D65_Blue_HDTV_M3: R$ 0.1804375
 FloatsRGB_D65_Red_HDTV_M4: R$ 0.2126729       FloatsRGB_D65_Green_HDTV_M5: R$ 0.7151522         FloatsRGB_D65_Blue_HDTV_M6: R$ 0.0721750
 FloatsRGB_D65_Red_HDTV_M7: R$ 0.0193339       FloatsRGB_D65_Green_HDTV_M8: R$ 0.1191920         FloatsRGB_D65_Blue_HDTV_M9: R$ 0.9503041]
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

  • Member
  • *****
  • Posts: 8827
  • Still using Abacus 2.0
    • DednDave
Re: CieDe2000 algorithm
« Reply #2 on: May 24, 2014, 05:47:49 AM »
it's very nice to know there is a precise method available   :t

i use an approximation



it is a slightly modified version of Thiadmer's equation found here...

http://www.compuphase.com/cmetric.htm

basically, i changed the divisors from 256 to 255 to simplify FPU register usage   :P

Thiadmer based it on previous work by Charles Poynton, who is a guru for such things
then, he did some experimentation and testing to arrive at that equation

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
Re: CieDe2000 algorithm
« Reply #3 on: May 24, 2014, 10:38:02 AM »
Hi dedndave

Many tks.

I´m making some tests on this routine, but i may be translated something incorrect. On the delta Hue values.

I´m not sure if this


can be translated as:
Code: [Select]
    Fpu_If R$HDelta > R$FLoat180
        fld R$HDelta | fsub R$Float360 | fstp R$HDeltaMax
    Fpu_Else_If R$HDelta > R$FLoatMinus180
        fld R$HDelta | fadd R$Float360 | fstp R$HDeltaMax
    Fpu_Else
        fld R$HDelta | fstp R$HDeltaMax
    Fpu_End_If
The problem is that when h2 is smaller then h1 it will lead to negative hue value and when the function computes "dTheta" it will lead to an infinite FPU value

when delta is positive, the function works ok, but´m not quite sure if the routine is teh same as the image.

Do you know the intervals accordying to the image ?

I mean...
If C1*C2, it returns 0
If abs (h2-h1) is smaller or equal to 180, returns h2-h1 --> this can be negative

the problem relies here (Those cannot be negative)
If (h2-h1) > 180, returns (h2-h1)+360

and

If (h2-h1) < -180, returns (h2-h1)-360

Considering that "|" means absolute, what are the parenthesis "(" notation ???

I rewrote it as:

Code: [Select]
; modl=ulus interval
; -180 0 180 ==> h2-h1
; 180 0 -180 ===> ???
; 360 to ??? ===> ???

    Fpu_If R$HDelta = R$FloatZero
        fldz
    Fpu_Else_If R$c1_2TickAvg = R$FloatZero
        fldz
    Fpu_Else_If R$HDeltaAbs < R$FLoatMinus180
        fld R$HDelta | fadd R$Float360
    Fpu_Else_If_And R$HDelta > R$FLoat180, R$HDelta > R$FloatZero
        fld R$HDelta | fabs | fsub R$Float360
    Fpu_Else;_If R$HDelta < -180 ????
        fld R$HDelta | fadd R$Float360
    Fpu_End_If
    fstp R$HDeltaMax

But it still don´t seems right. An infinite value is still going on.

I´m pretty sure that the error is due to the way i´m interpreting the delta Hue values from the pdf.

or maybe perhaps this is the proper intervals ?
Code: [Select]
    Fpu_If R$HDelta = R$FloatZero
        fldz
    Fpu_Else_If R$c1_2TickAvg = R$FloatZero
        fldz
    Fpu_Else_If R$HDelta < R$FLoatMinus180 ; interval -181 to -360 ?
        fld R$HDelta | fadd R$Float360
    Fpu_Else_If_And R$HDelta > R$FLoat180; interval 181 to 360 ?
        fld R$HDelta | fabs | fsub R$Float360
    Fpu_Else ; interval -180 to 180 ?
        fld R$HDelta
    Fpu_End_If
    fstp R$HDeltaMax
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

  • Member
  • *****
  • Posts: 8827
  • Still using Abacus 2.0
    • DednDave
Re: CieDe2000 algorithm
« Reply #4 on: May 24, 2014, 12:37:39 PM »
i finally got the PDF to d/l - lol
the correct URL is
http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf

did you read the notes on page 23 ?

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
Re: CieDe2000 algorithm
« Reply #5 on: May 24, 2014, 03:41:53 PM »
yes, but i didn´t understand. Does it means that for the hue difference it is always needed to use the absolut value of it ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
Re: CieDe2000 algorithm
« Reply #6 on: May 24, 2014, 04:42:32 PM »
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

MichaelW

  • Global Moderator
  • Member
  • *****
  • Posts: 1209
Re: CieDe2000 algorithm
« Reply #7 on: May 24, 2014, 08:43:07 PM »
Is this one is more correct to the paper?

For the few pairs of color values from Table 1 that I tried, the function delta_e result matched the expected result, but I did not bother with displaying any of the internal variables. C source and gcc-compiled exe in the attachment.

Edit: After 5 downloads I cleaned up the source and modified makeit.bat to also output an Intel-syntax assembly file. New attachment.
« Last Edit: May 25, 2014, 01:19:36 AM by MichaelW »
Well Microsoft, here’s another nice mess you’ve gotten us into.

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
Re: CieDe2000 algorithm
« Reply #8 on: May 25, 2014, 09:19:43 AM »
Hi Michael, thanks for testing it.

Indeed this version seems more precise and a bit faster.

I managed to translate them both and built a new one.

Code: [Select]
Proc cieDe2000a:
    Arguments @Luma1, @Afact1, @BFact1, @Luma2, @AFact2, @BFact2
    Uses ebx, esi, edi, ecx, edx, eax

    mov ebx D@Luma1 | fld R$ebx | fstp R$TempLuma1
    mov ebx D@Afact1 | fld R$ebx | fstp R$TempAFact1
    mov ebx D@Bfact2 | fld R$ebx | fstp R$TempBFact1
    mov ebx D@Luma2 | fld R$ebx | fstp R$TempLuma2
    mov ebx D@Afact2 | fld R$ebx | fstp R$TempAFact2
    mov ebx D@Bfact2 | fld R$ebx | fstp R$TempBFact2

    fld1 | fstp R$kl
    fld1 | fstp R$kc
    fld1 | fstp R$kh

    fld R$TempAFact1 | fmul R$TempAFact1 | fld R$TempBFact1 | fmul R$TempBFact1 | faddp ST1 ST0 | fsqrt | fstp R$C1Factor
    fld R$TempAFact2 | fmul R$TempAFact2 | fld R$TempBFact2 | fmul R$TempBFact2 | faddp ST1 ST0 | fsqrt | fstp R$C2Factor

    fld R$C1Factor | fadd R$C2Factor | fmul R$FloatHalf | fstp R$CFactorMean

    R$GFactor = 0.5 * (1 - sqrt( (R$CFactorMean^7)/( (R$CFactorMean^7)+(25^7) ) ) )

    ; adjusted ab
    fld1 | fadd R$GFactor | fmul R$TempAFact1 | fstp R$A1Factor
    fld1 | fadd R$GFactor | fmul R$TempAFact2 | fstp R$A2Factor

    ; adjusted cs
    fld R$A2Factor | fmul R$A2Factor | fld R$TempBFact2 | fmul R$TempBFact2 | faddp ST1 ST0 | fsqrt | fstp R$c2Tick
    fld R$A1Factor | fmul R$A1Factor | fld R$TempBFact1 | fmul R$TempBFact1 | faddp ST1 ST0 | fsqrt | fstp R$c1Tick

    ; Compute product of chromas
    fld R$c2Tick | fmul R$c1Tick | fstp R$Cpprod

    ; Ensure hue is between 0 and 2pi
    C_call 'msvcrt.atan2' D$TempBFact1, D$TempBFact1+4, D$A1Factor, D$A1Factor+4 | fstp R$H1Factor

    ; rollover ones that comes negative
    Fpu_If R$H1Factor < R$FloatZero
        fld R$H1Factor | fadd R$Float_DoublePI | fstp R$H1Factor
    Fpu_End_If

    C_call 'msvcrt.atan2' D$TempBFact2, D$TempBFact2+4, D$A2Factor, D$A2Factor+4 | fstp R$H2Factor

    ; rollover ones that comes negative
    Fpu_If R$H2Factor < R$FloatZero
        fld R$H2Factor | fadd R$Float_DoublePI | fstp R$H2Factor
    Fpu_End_If

    fld R$A2Factor | fabs | fld R$TempBFact2 | fabs | faddp ST1 ST0 | fstp R$HDeltaAdd
    Fpu_If R$HDeltaAdd = R$FloatZero
        fldz | fstp R$H2Factor
    Fpu_End_If

    fld R$TempLuma2 | fsub R$TempLuma1 | fstp R$DeltaL
    fld R$c2Tick | fsub R$c1Tick | fstp R$DeltaC

    ; Computation of hue difference
    fld R$H2Factor | fsub R$H1Factor | fstp R$dhp

    Fpu_If R$dhp > R$Float_PI
        fld R$dhp | fsub R$Float_DoublePI | fstp R$dhp
    Fpu_End_If

    Fpu_If R$dhp < R$Float_PI
        fld R$dhp | fadd R$Float_DoublePI | fstp R$dhp
    Fpu_End_If

    ; set chroma difference to zero if the product of chromas is zero
    Fpu_If R$Cpprod = R$FloatZero
        fldz | fstp R$dhp
    Fpu_End_If

    ;  Note that the defining equations actually need signed Hue and chroma differences which is different
    ;  from prior color difference formulae

    R$DeltaBigH = R$FloatTwo * sqrt(R$Cpprod) * sin((R$dhp*R$FloatHalf))

    ; weighting functions

    fld R$TempLuma2 | fadd R$TempLuma1 | fmul R$FloatHalf | fstp R$lTickAvg
    fld R$c1Tick | fadd R$c2Tick | fdiv R$FloatTwo | fstp R$cTickAvg

    ; Average Hue Computation
    ; This is equivalent to that in the paper but simpler programmatically.
    ; Note average hue is computed in radians and converted to degrees only where needed

    fld R$H1Factor | fadd R$H2Factor | fmul R$FLoatHalf | fstp R$hTickAvg

    ; Identify positions for which abs hue diff exceeds 180 degrees

    fld R$H1Factor | fsub R$H2Factor | fabs | fstp R$HDeltaAbs
    Fpu_If R$HDeltaAbs > R$Float_PI
        fld R$hTickAvg | fsub R$Float_PI | fstp R$hTickAvg
    Fpu_End_If

    ; rollover ones that comes negative

    Fpu_If R$hTickAvg < R$FloatZero
        fld R$hTickAvg | fadd R$Float_DoublePI | fstp R$hTickAvg
    Fpu_End_If

    ; Check if one of the chroma values is zero, in which case set mean hue
    ; to the sum which is equivalent to other value
    Fpu_If R$Cpprod = R$FloatZero
        fld R$H2Factor | fadd R$H1Factor | fstp R$hTickAvg
    Fpu_End_If

    fld R$lTickAvg | fsub R$Float50 | fmul ST0 ST0 | fstp R$Light50

    R$slFactor = 1+0.015*R$Light50/sqrt(20+R$Light50)

    fld R$cTickAvg | fmul R$Float0045 | fadd R$FloatOne | fstp R$scFactor

    R$TFactor = 1.0 - 0.17*cos(R$hTickAvg - (R$FloatPI/6.0)) + 0.24*cos(2.0*R$hTickAvg) + 0.32*cos(3.0*R$hTickAvg+R$FloatPI/30.0) - 0.20*cos(4.0*R$hTickAvg-(63.0*R$FloatPI/180.0))

    fld R$cTickAvg | fmul R$TFactor | fmul R$Float0015 | fadd R$FloatOne | fstp R$shFactor

    ; calc dtheta
    fld R$Float180_Div_PI | fmul R$hTickAvg | fsub R$Float275 | fmul R$Float_One25 | fmul ST0 ST0 | fchs | fstp R$PowResult
    R$dTheta = exp(R$PowResult)*R$FloatPI_Div_6

    R$rcFactor = 2*(sqrt( (R$cTickAvg^7)/( (R$cTickAvg^7)+R$kp) ))

    fld R$dTheta | fmul R$FloatTwo | fsin | fmul R$rcFactor | fchs | fstp R$rtFactor

    ; The CIE 00 color difference

    fld R$DeltaL | fdiv R$slFactor | fmul R$kl | fstp R$dlkFactor
    fld R$DeltaC | fdiv R$scFactor | fmul R$kc | fstp R$dckFactor
    fld R$DeltaBigH | fdiv R$shFactor | fmul R$kh | fstp R$dhkFactor

    fld R$dlkFactor | fmul ST0 ST0 | fld R$dckFactor | fmul ST0 ST0 | faddp ST1 ST0
    fld R$dhkFactor | fmul ST0 ST0 | faddp ST1 ST0
    fld R$dckFactor | fmul R$dhkFactor | fmul R$rtFactor
    faddp ST1 ST0 | fsqrt

EndP


I´ll clean up the code later and will try to optimze it a bit. It seems that the threshold function
    R$TFactor = 1.0 - 0.17*cos(R$hTickAvg - (R$FloatPI/6.0)) + 0.24*cos(2.0*R$hTickAvg) + 0.32*cos(3.0*R$hTickAvg+R$FloatPI/30.0) - 0.20*cos(4.0*R$hTickAvg-(63.0*R$FloatPI/180.0))
can be optimized to use a constant and a single cos. I´ll use http://www.wolframalpha.com site to simplify the function and will post the result once it is done.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

  • Moderator
  • Member
  • *****
  • Posts: 1237
  • Assembly is a state of art.
    • RosAsm
Re: CieDe2000 algorithm
« Reply #9 on: May 27, 2014, 07:33:18 AM »
OK, a few thoughts.

Ciede200 assumes that a color is similar with each other after analysing mainly the Luma and afactor and bfactor of 2 color pixels.

But....internally, it transfoms the a b factor to their correspondending hue angles.

The problem is that, the resultant values can implies that different hue colors may be similiar if they have similars chromacity and luma.

When we want precision, we can safely assume that a color to be equal to each other must have also be on the same hue angle. Thinking on that i made a variation of the ciede200 that assumes that the hue from pixel 1 is the same as in pixel 2. So, it lead me to this function:

Code: [Select]
Proc RetrieveChromaFactor:
    Arguments @Luma1, @Afact1, @BFact1, @Luma2, @AFact2, @BFact2
    Uses ebx, esi, edi, ecx, edx, eax

    mov ebx D@Luma1 | fld R$ebx | fstp R$TempLuma1
    mov ebx D@Afact1 | fld R$ebx | fstp R$TempAFact1
    mov ebx D@Bfact2 | fld R$ebx | fstp R$TempBFact1
    mov ebx D@Luma2 | fld R$ebx | fstp R$TempLuma2
    mov ebx D@Afact2 | fld R$ebx | fstp R$TempAFact2
    mov ebx D@Bfact2 | fld R$ebx | fstp R$TempBFact2

    fld1 | fstp R$kl
    fld1 | fstp R$kc
    fld1 | fstp R$kh

    fld R$TempAFact1 | fmul R$TempAFact1 | fld R$TempBFact1 | fmul R$TempBFact1 | faddp ST1 ST0 | fsqrt | fstp R$C1Factor
    fld R$TempAFact2 | fmul R$TempAFact2 | fld R$TempBFact2 | fmul R$TempBFact2 | faddp ST1 ST0 | fsqrt | fstp R$C2Factor

    fld R$C1Factor | fadd R$C2Factor | fmul R$FloatHalf | fstp R$CFactorMean

    R$GFactor = 0.5 * (1 - sqrt( (R$CFactorMean^7)/( (R$CFactorMean^7)+(25^7) ) ) )

    ; adjusted ab
    fld1 | fadd R$GFactor | fmul R$TempAFact1 | fstp R$A1Factor
    fld1 | fadd R$GFactor | fmul R$TempAFact2 | fstp R$A2Factor

    ; adjusted cs
    ; c2Tick = sqrt(A2Factor^2+TempBFact2^2)
    fld R$A2Factor | fmul R$A2Factor | fld R$TempBFact2 | fmul R$TempBFact2 | faddp ST1 ST0 | fsqrt | fstp R$c2Tick
    fld R$A1Factor | fmul R$A1Factor | fld R$TempBFact1 | fmul R$TempBFact1 | faddp ST1 ST0 | fsqrt | fstp R$c1Tick

    ; Compute product of chromas
    ;fld R$c2Tick | fmul R$c1Tick | fstp R$Cpprod irrelevant since it was only to define hue
    fld R$c2Tick | fsub R$c1Tick | fstp R$DeltaC

    ; weighting functions
    fld R$c1Tick | fadd R$c2Tick | fdiv R$FloatTwo; | fstp R$cTickAvg
    ;fld R$cTickAvg |
    fmul R$Float0045 | fadd R$FloatOne | fstp R$scFactor
    fld R$DeltaC | fdiv R$scFactor | fmul R$kc | fstp R$dckFactor

    ; dckFactor = deltaC/((c1Tick+c2Tick)*0.5*0.045+1)
    ; dckFactor = (c2Tick-c1Tick)/((c1Tick+c2Tick)*0.5*0.045+1)


;;
    dlkFactor/kl = DeltaL/slFactor = (TempLuma2-TempLuma1)/slFactor
    = (TempLuma2-TempLuma1)*sqrt(20+R$Light50) / (1+0.015*R$Light50)
    ; Light50 = ((0.5*(TempLuma2+TempLuma1) - 50)^2)

    = (TempLuma2-TempLuma1)*sqrt(20+(((0.5*(TempLuma2+TempLuma1) - 50)^2))) / (1+0.015*(((0.5*(TempLuma2+TempLuma1) - 50)^2)))
   
    = (b-a)*sqrt(20+(((0.5*(b+a) - 50)^2))) / (1+0.015*(((0.5*(b+a) - 50)^2))) ; where a = TempLuma1, b = TempLuma2
    = (b-a)*sqrt(20+((c)) / (1+0.015*((c)) ; where a = TempLuma1, b = TempLuma2, c = (0.5*(b+a) - 50)^2)

; solutions for this is
a~~41.8349,   b~~41.8356
a~~41.835,   b~~41.8364
a~~58.165,   b~~58.1636
a~~58.1651,   b~~58.1644

; b = -a+4*i*sqrt(5)+100
; if LUma1 not equal to Luma2. The result that most approaches to zerois this equation
; b = 108.9442719099991587856366946749251049417624734384461028970835 - a

;;

    fld R$TempLuma2 | fadd R$TempLuma1 | fmul R$FloatHalf | fstp R$lTickAvg
    fld R$lTickAvg | fsub R$Float50 | fmul ST0 ST0 | fstp R$Light50
    R$slFactor = 1+0.015*R$Light50/sqrt(20+R$Light50)
    fld R$TempLuma2 | fsub R$TempLuma1 | fstp R$DeltaL
    fld R$DeltaL | fdiv R$slFactor | fmul R$kl | fstp R$dlkFactor

    ; Adjustments for Chroma

    ; what is important is only DeltaC and scFactor
    ;fld R$DeltaC | fdiv R$scFactor | fmul R$kc | fstp R$dckFactor
    ;fld R$DeltaBigH | fdiv R$shFactor | fmul R$kh | fstp R$dhkFactor; 0

    fld R$dlkFactor | fmul ST0 ST0 | fld R$dckFactor | fmul ST0 ST0 | faddp ST1 ST0
    ;fld R$dhkFactor | fmul ST0 ST0 | faddp ST1 ST0
    ;fld R$dckFactor | fmul R$dhkFactor | fmul R$rtFactor
    ;faddp ST1 ST0 |
    fsqrt

EndP

What i done is simply, assumes on ciede200 algo above that H1Factor and H2Factor are the same. So it after unrolling the function. It completelly removed the need of a hue analysis in order to fully compare 2 pixels.

It also, seems to be a very good indicator of poorly saturated or over saturated files that lad to the mistake that 2 pixels can be the same. For instance, if ´m analysing 2 pixels they can have a huge delta variation of hue (EX: pixel1 hue = 162, pixel2 = 81)....and yet the algo (and also ciede2000 will think that it is the same color, when they areoversaturated (brighten) or poorly saturated (grayed).

I´ll try to make some further tests on the function, because it seems that it can retrieve the a and b factor from one pixel to another on the same hue.
For this, i´ll part to the principle that dckFactor = (c2Tick-c1Tick)/((c1Tick+c2Tick)*0.5*0.045+1) = 0
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

  • Member
  • *****
  • Posts: 8827
  • Still using Abacus 2.0
    • DednDave
Re: CieDe2000 algorithm
« Reply #10 on: May 27, 2014, 10:08:57 PM »
the fact that it's not really an "exact science" is why i went with the simpler approximation
i don't think it's worthwhile to perform too much calculation that yields subjective results

some background material

http://www.oculist.net/downaton502/prof/ebook/duanes/pages/v1/v1c033.html

you can google the term "Just Noticeable Difference" and find a lot of interesting reading
not surprisingly, many advances come from the astronomy area   :P
many of the techniques they have developed influence all kinds of image enhancement fields