Author Topic: CieDe2000 algorithm  (Read 7330 times)

guga

• Moderator
• Member
• Posts: 1282
• Assembly is a state of art.
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)))

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

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

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 * _

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
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
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]
[DeltaBigH: R\$ 0]
[lTickAvg: R\$ 0]
[cTickAvg: R\$ 0]
[hTickAvg: R\$ 0]
[c1_2TickAvg: R\$ 0]
[HDeltaAbs: 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) ) )

fld R\$GFactor | fadd R\$FloatOne | fmul R\$TempAFact1 | fstp R\$A1Factor
fld R\$GFactor | fadd R\$FloatOne | fmul R\$TempAFact2 | fstp R\$A2Factor

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

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

Fpu_If R\$c1_2TickAvg = R\$FloatZero
Fpu_Else_If R\$HDeltaAbs <= R\$Float180
fld R\$HDeltaAdd | fmul R\$FloatHalf | 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

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
.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: 1282
• Assembly is a state of art.
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:

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

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
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: 1282
• Assembly is a state of art.
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
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 ????
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 ?
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
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: 1282
• Assembly is a state of art.
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: 1282
• Assembly is a state of art.
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: 1282
• Assembly is a state of art.
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) ) ) )

fld1 | fadd R\$GFactor | fmul R\$TempAFact1 | fstp R\$A1Factor
fld1 | fadd R\$GFactor | fmul R\$TempAFact2 | fstp R\$A2Factor

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
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

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: 1282
• Assembly is a state of art.
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) ) ) )

fld1 | fadd R\$GFactor | fmul R\$TempAFact1 | fstp R\$A1Factor
fld1 | fadd R\$GFactor | fmul R\$TempAFact2 | fstp R\$A2Factor

; 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

; 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
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
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