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)
;;
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:
[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.
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:
[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]
it's very nice to know there is a precise method available :t
i use an approximation
(http://img692.imageshack.us/img692/5482/colordiffapproxmod.png)
it is a slightly modified version of Thiadmer's equation found here...
http://www.compuphase.com/cmetric.htm (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
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
(http://oi58.tinypic.com/6o0gtw.jpg)
can be translated as:
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:
; 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 ?
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
i finally got the PDF to d/l - lol
the correct URL is
http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf (http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf)
did you read the notes on page 23 ?
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 ?
Is this one is more correct to the paper ?
http://cpansearch.perl.org/src/EWATERS/PDL-Graphics-ColorDistance-0.0.1/color_distance.c
Quote from: guga on May 24, 2014, 04:42:32 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.
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.
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.
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:
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
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 (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