Hi Guys
I´m trying to create a app to convert the different iluminants models but i´m failing to undersdtand the math on this.
Accordlying to http://brucelindbloom.com/index.html?Eqn_ChromAdapt.html, the convertion method from XYZ Scaling, Bradford and Von Kries is :
Method [MA]
XYZ Scaling
1.0000000 0.0000000 0.0000000
0.0000000 1.0000000 0.0000000
0.0000000 0.0000000 1.0000000
Bradford
0.8951000 0.2664000 -0.1614000
-0.7502000 1.7135000 0.0367000
0.0389000 -0.0685000 1.0296000
Von Kries
0.4002400 0.7076000 -0.0808100
-0.2263000 1.1653200 0.0457000
0.0000000 0.0000000 0.9182200
Followed by the inverted matrices
____________________________________________________________
And the illuminants are given by:
Illuminant X Y Z
A 1.09850 1.00000 0.35585
B 0.99072 1.00000 0.85223
C 0.98074 1.00000 1.18232
D50 0.96422 1.00000 0.82521
D55 0.95682 1.00000 0.92149
D65 0.95047 1.00000 1.08883
D75 0.94972 1.00000 1.22638
E 1.00000 1.00000 1.00000
F2 0.99186 1.00000 0.67393
F7 0.95041 1.00000 1.08747
F11 1.00962 1.00000 0.64350
____________________________________________________________
From the site, the convertion from Illuminat A to B using XYZ Scaling is (From the direct matrix and not the inverted one):
0.9018844 0.0000000 0.0000000
0.0000000 1.0000000 0.0000000
0.0000000 0.0000000 2.3949136
So, the 1st element 0.901884 was achieved from: 0.99072/1.09850 ?
But, on Bradfor, how did it achieved the value of ?
0.8905163 -0.0829136 0.2680945
-0.0971524 1.0754262 0.0879463
0.0538970 -0.0908558 2.4838553
Ok, guys. I suceeded to make it work. and shows the exact same result :)
I was forgetting to multiply the inverted matrix for each array of 3x1.
The steps are these:
1) Multiply the matrix Bradford (3x3) with the 3x1 matrix related to the white refereces from source and destionation (destination is the colorspace you want to convert to). Like:
[Bradford]*[Illuminant of white ref].
From Source we have:
Illuminant X Y Z
A 1.09850 1.00000 0.35585
Bradford: 0.8951000 0.2664000 -0.1614000
-0.7502000 1.7135000 0.0367000
0.0389000 -0.0685000 1.0296000
So... Bradford * Source = [0.8951, 0.2664, -0.1614, -0.7502......] * [1.09850, 1, 0.35585]
Then do the same for the destination:
Illuminant X Y Z
B 0.99072 1.00000 0.85223
Bradford:
0.8951000 0.2664000 -0.1614000
-0.7502000 1.7135000 0.0367000
0.0389000 -0.0685000 1.0296000
So... Bradford * Destination = [0.8951, 0.2664, -0.1614, -0.7502......] * [0.99072, 1.00000, 0.85223]
2) Put the resultant valuues of source and destination on a matrix 3x3 dividing destination from source, like:
Scaled = Destination/Source
Ex:
Destination = 0.5, 0.6, 0.3
Source = 0.9, 0.8, 0.7
Scaled = 0.5/0.9, 0.6/0.8, 0.3/0.7
Put the results on a matrix to become like this:
MatrixNew =
(0.5/0.9) 0 0
0 (0.6/0.8) 0
0 0 (0.3/0.7)
3) Multiply the inverted matrix of Bradford to the new Matrix and the resultant matrix multiply by the normal Bradford matrix. Like:
[Bradford Inverted]*[MatrixNew]*[Bradford]
The Inverted Bradford matrix is already given in the site, but i´ll later create a routine to compute it better, since the values on the site ar not accurated. So:
Inverted Bradford=
0.9869929 -0.1470543 0.1599627
0.4323053 0.5183603 0.0492912
-0.0085287 0.0400428 0.9684867
Which lead us to:
MatrixNew2 =
| 0.9869929 -0.1470543 0.1599627 | | (0.5/0.9) 0 0 |
| 0.4323053 0.5183603 0.0492912 | * | 0 (0.6/0.8) 0 |
|-0.0085287 0.0400428 0.9684867 | | 0 0 (0.3/0.7) |
3a) And finally, multiply this resultant 3x3 matrix to the normal bradford. Like this:
Final Matrix = [MatrixNew2]*[Bradford]
Say, Matrixnew2 results in:
| 0.521238 -0.12567489 0.102345 |
| 0.777777 0.5183603 0.01012341 |
| -0.012554 0.156459 0.914265478 |
Then the final matrix will result from the multiplication of:
| 0.521238 -0.12567489 0.102345 | | 0.8951000 0.2664000 -0.1614000 |
| 0.777777 0.5183603 0.01012341 | * |-0.7502000 1.7135000 0.0367000 |
| -0.012554 0.156459 0.914265478 | | 0.0389000 -0.0685000 1.0296000 |
Now, i need to figure it out a way to adapt the resultant matrix to the vertex martix on a regular ColorSpaces, Ex:
Transform a D65 Observer2 Adobe Matrix
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
Onto the new adapted matrix using those resultant values. Ex: Transforming the above values onto D50, C, A, B, D75, F, observer10 or 2 etc etc using whatever method needed (XYZ Scaling, Bradford or Von Kries). My plan is to make a huge table containing all the matrix values already adapted, rather then computing it on each time i need to use a function to convert RGB to CieLab or RGB to CieLCH etc. Making a huge table is better in terms of speed computation. So, i can make a vertex matrix for Adobe1998 on all adaptations, D50, A, B, etc etc on all methods....and also do the same for others, like; NTSC, Pal, Secam, WideGamut, sRGB, HDTV etc etc etc
If you want the function i made is this. (Not optimized. Written for RosAsm syntax)
;;
; http://brucelindbloom.com/index.html?Eqn_ChromAdapt.html
; Transformed values to convert from one illuminant to another
http://www.easyrgb.com/en/math.php
https://www.mathworks.com/matlabcentral/fileexchange/40640-computational-colour-science-using-matlab-2e
WHITE_SPACE_A_OBS2
;;
[ADAPT_XYZ_SCALING 0]
[ADAPT_BRADFORD 1]
[ADAPT_VON_KRIES 2]
[FloatXYZAdaptMatrices:
Adapt_XYZ_Scaling_Red_M1: R$ 1.0 Adapt_XYZ_Scaling_Green_M2: R$ 0.0 Adapt_XYZ_Scaling_Blue_M3: R$ 0.0
Adapt_XYZ_Scaling_Red_M4: R$ 0.0 Adapt_XYZ_Scaling_Green_M5: R$ 1.0 Adapt_XYZ_Scaling_Blue_M6: R$ 0.0
Adapt_XYZ_Scaling_Red_M7: R$ 0.0 Adapt_XYZ_Scaling_Green_M8: R$ 0.0 Adapt_XYZ_Scaling_Blue_M9: R$ 1.0
Adapt_Bradford_Red_M1: R$ 0.8951 Adapt_Bradford_Green_M2: R$ 0.2664 Adapt_Bradford_Blue_M3: R$ -0.1614
Adapt_Bradford_Red_M4: R$ -0.7502 Adapt_Bradford_Green_M5: R$ 1.7135 Adapt_Bradford_Blue_M6: R$ 0.0367
Adapt_Bradford_Red_M7: R$ 0.0389 Adapt_Bradford_Green_M8: R$ -0.0685 Adapt_Bradford_Blue_M9: R$ 1.0296
Adapt_Von_Kries_Red_M1: R$ 0.40024 Adapt_Von_Kries_Green_M2: R$ 0.7076 Adapt_Von_Kries_Blue_M3: R$ -0.08081
Adapt_Von_Kries_Red_M4: R$ -0.2263 Adapt_Von_Kries_Green_M5: R$ 1.16532 Adapt_Von_Kries_Blue_M6: R$ 0.0457
Adapt_Von_Kries_Red_M7: R$ 0.0 Adapt_Von_Kries_Green_M8: R$ 0.0 Adapt_Von_Kries_Blue_M9: R$ 0.91822]
[Float_XYZ_RGB_Inverted_AdaptMatrices:
Adapt_Inverted_XYZScaling_Red_M1: R$ 1.0 Adapt_Inverted_XYZScaling_Green_M2: R$ 0.0 Adapt_Inverted_XYZScaling_Blue_M3: R$ 0.0
Adapt_Inverted_XYZScaling_Red_M4: R$ 0.0 Adapt_Inverted_XYZScaling_Green_M5: R$ 1.0 Adapt_Inverted_XYZScaling_Blue_M6: R$ 0.0
Adapt_Inverted_XYZScaling_Red_M7: R$ 0.0 Adapt_Inverted_XYZScaling_Green_M8: R$ 0.0 Adapt_Inverted_XYZScaling_Blue_M9: R$ 1.0
; Adapt_Inverted_Bradford_Red_M1: R$ 0.9869929 Adapt_Inverted_Bradford_Green_M2: R$ -0.1470543 Adapt_Inverted_Bradford_Blue_M3: R$ 0.1599627
; Adapt_Inverted_Bradford_Red_M4: R$ 0.4323053 Adapt_Inverted_Bradford_Green_M5: R$ 0.5183603 Adapt_Inverted_Bradford_Blue_M6: R$ 0.0492912
; Adapt_Inverted_Bradford_Red_M7: R$ -0.0085287 Adapt_Inverted_Bradford_Green_M8: R$ 0.0400428 Adapt_Inverted_Bradford_Blue_M9: R$ 0.9684867
Adapt_Inverted_Bradford_Red_M1: R$ 0.9869929054667121899 Adapt_Inverted_Bradford_Green_M2: R$ -0.14705425642099010066 Adapt_Inverted_Bradford_Blue_M3: R$ 0.15996265166373123948
Adapt_Inverted_Bradford_Red_M4: R$ 0.43230526972339451002 Adapt_Inverted_Bradford_Green_M5: R$ 0.51836027153677753834 Adapt_Inverted_Bradford_Blue_M6: R$ 0.049291228212855612148
Adapt_Inverted_Bradford_Red_M7: R$ -0.0085286645751773312464 Adapt_Inverted_Bradford_Green_M8: R$ 0.040042821654084864313 Adapt_Inverted_Bradford_Blue_M9: R$ 0.96848669578754998478
Adapt_Inverted_Von_Kries_Red_M1: R$ 1.8599363874558397422 Adapt_Inverted_Von_Kries_Green_M2: R$ -1.1293816185800914784 Adapt_Inverted_Von_Kries_Blue_M3: R$ 0.21989740959619327624
Adapt_Inverted_Von_Kries_Red_M4: R$ 0.36119143624176752624 Adapt_Inverted_Von_Kries_Green_M5: R$ 0.63881246328504213303 Adapt_Inverted_Von_Kries_Blue_M6: R$ -0.0000063705968386570599758
Adapt_Inverted_Von_Kries_Red_M7: R$ 0.0 Adapt_Inverted_Von_Kries_Green_M8: R$ 0.0 Adapt_Inverted_Von_Kries_Blue_M9: R$ 1.0890636230968613186]
[ScaledFactor:
ScaledFactor_Red_M1: R$ 0 ScaledFactor_Green_M2: R$ 0 ScaledFactor_Blue_M3: R$ 0
ScaledFactor_Red_M4: R$ 0 ScaledFactor_Green_M5: R$ 0 ScaledFactor_Blue_M6: R$ 0
ScaledFactor_Red_M7: R$ 0 ScaledFactor_Green_M8: R$ 0 ScaledFactor_Blue_M9: R$ 0]
[TmpScaledFactor:
TmpScaledFactor_Red_M1: R$ 0 TmpScaledFactor_Green_M2: R$ 0 TmpScaledFactor_Blue_M3: R$ 0
TmpScaledFactor_Red_M4: R$ 0 TmpScaledFactor_Green_M5: R$ 0 TmpScaledFactor_Blue_M6: R$ 0
TmpScaledFactor_Red_M7: R$ 0 TmpScaledFactor_Green_M8: R$ 0 TmpScaledFactor_Blue_M9: R$ 0]
; call ChromaticAdaptation_XYXtoLab WHITE_SPACE_A_OBS2, WHITE_SPACE_C_OBS2, ADAPT_XYZ_SCALING, ScaledFactor
; http://lclevy.free.fr/cr2/srgbd50_xyz.txt
; https://player.slideplayer.com/24/7368067/
; http://etsitpab.github.io/JSM/doc/html/source/CIE.html
; Inverted Matrix calculated from: https://matrix.reshish.com/inverCalculation.php
; https://home.kpn.nl/vanadovv/color/ColorMath.html
; http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html#WSMatrices
; https://github.com/jkl1337/go-chromath/blob/master/chromath.go
[SigmaFrom: R$ 0 #3]
[Sigmato: R$ 0 #3]
Proc ChromaticAdaptation_XYXtoLab:
Arguments @WhiteRefFrom, @WhiteRefTo, @Method, @pOutMatrix
Structure @Reference 72, @pRefXFromDis 0, @pRefYFromDis 8, @pRefZFromDis 16, @pRefXtoDis, 24, @pRefYtoDis 32, @pRefZtoDis 40, @XScaledDis 48, @YScaledDis 56, @ZScaledDis 64
Uses ebx, ecx, edx
lea edx D@pRefZFromDis
lea ebx D@pRefYFromDis
lea eax D@pRefXFromDis
call FindWhiteRef D@WhiteRefFrom, eax, ebx, edx
lea edx D@pRefZtoDis
lea ebx D@pRefYtoDis
lea eax D@pRefXtoDis
call FindWhiteRef D@WhiteRefto, eax, ebx, edx
; calculate SigmaFrom https://github.com/jkl1337/go-chromath/blob/master/chromath.go
mov ebx D@Method | imul ebx Size_Of_FloatMatrices | add ebx FloatXYZAdaptMatrices
mov edi SigmaFrom
fld R$ebx+FloatMatrices.M1Dis | fmul R@pRefXFromDis | fld R$ebx+FloatMatrices.M2Dis | fmul R@pRefYFromDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M3Dis | fmul R@pRefZFromDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M1Dis
fld R$ebx+FloatMatrices.M4Dis | fmul R@pRefXFromDis | fld R$ebx+FloatMatrices.M5Dis | fmul R@pRefYFromDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M6Dis | fmul R@pRefZFromDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M2Dis
fld R$ebx+FloatMatrices.M7Dis | fmul R@pRefXFromDis | fld R$ebx+FloatMatrices.M8Dis | fmul R@pRefYFromDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M9Dis | fmul R@pRefZFromDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M3Dis
mov edi SigmaTo
fld R$ebx+FloatMatrices.M1Dis | fmul R@pRefXtoDis | fld R$ebx+FloatMatrices.M2Dis | fmul R@pRefYtoDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M3Dis | fmul R@pRefZtoDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M1Dis
fld R$ebx+FloatMatrices.M4Dis | fmul R@pRefXtoDis | fld R$ebx+FloatMatrices.M5Dis | fmul R@pRefYtoDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M6Dis | fmul R@pRefZtoDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M2Dis
fld R$ebx+FloatMatrices.M7Dis | fmul R@pRefXtoDis | fld R$ebx+FloatMatrices.M8Dis | fmul R@pRefYtoDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M9Dis | fmul R@pRefZtoDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M3Dis
fld R$SigmaTo+FloatMatrices.M1Dis | fdiv R$SigmaFrom+FloatMatrices.M1Dis | fstp R@XScaledDis
fld R$SigmaTo+FloatMatrices.M2Dis | fdiv R$SigmaFrom+FloatMatrices.M2Dis | fstp R@YScaledDis
fld R$SigmaTo+FloatMatrices.M3Dis | fdiv R$SigmaFrom+FloatMatrices.M3Dis | fstp R@ZScaledDis
; get the from method
mov ebx D@Method | imul ebx Size_Of_FloatMatrices | add ebx Float_XYZ_RGB_Inverted_AdaptMatrices;FloatXYZAdaptMatrices
mov edi TmpScaledFactor;D@pOutMatrix
fld R$ebx+FloatMatrices.M1Dis | fmul R@XScaledDis | fld R$ebx+FloatMatrices.M2Dis | fmul R$FloatZero | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M3Dis | fmul R$FloatZero | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M1Dis
fld R$ebx+FloatMatrices.M1Dis | fmul R$FloatZero | fld R$ebx+FloatMatrices.M2Dis | fmul R@YScaledDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M3Dis | fmul R$FloatZero | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M2Dis
fld R$ebx+FloatMatrices.M1Dis | fmul R$FloatZero | fld R$ebx+FloatMatrices.M2Dis | fmul R$FloatZero | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M3Dis | fmul R@ZScaledDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M3Dis
fld R$ebx+FloatMatrices.M4Dis | fmul R@XScaledDis | fld R$ebx+FloatMatrices.M5Dis | fmul R$FloatZero | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M6Dis | fmul R$FloatZero | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M4Dis
fld R$ebx+FloatMatrices.M4Dis | fmul R$FloatZero | fld R$ebx+FloatMatrices.M5Dis | fmul R@YScaledDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M6Dis | fmul R$FloatZero | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M5Dis
fld R$ebx+FloatMatrices.M4Dis | fmul R$FloatZero | fld R$ebx+FloatMatrices.M5Dis | fmul R$FloatZero | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M6Dis | fmul R@ZScaledDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M6Dis
fld R$ebx+FloatMatrices.M7Dis | fmul R@XScaledDis | fld R$ebx+FloatMatrices.M8Dis | fmul R$FloatZero | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M9Dis | fmul R$FloatZero | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M7Dis
fld R$ebx+FloatMatrices.M7Dis | fmul R$FloatZero | fld R$ebx+FloatMatrices.M8Dis | fmul R@YScaledDis | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M9Dis | fmul R$FloatZero | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M8Dis
fld R$ebx+FloatMatrices.M7Dis | fmul R$FloatZero | fld R$ebx+FloatMatrices.M8Dis | fmul R$FloatZero | faddp ST1 ST0 | fld R$ebx+FloatMatrices.M9Dis | fmul R@ZScaledDis | faddp ST1 ST0 | fstp R$edi+FloatMatrices.M9Dis
mov ebx D@Method | imul ebx Size_Of_FloatMatrices | add ebx FloatXYZAdaptMatrices
mov edx D@pOutMatrix
fld R$edi+FloatMatrices.M1Dis | fmul R$ebx+FloatMatrices.M1Dis | fld R$edi+FloatMatrices.M2Dis | fmul R$ebx+FloatMatrices.M4Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M3Dis | fmul R$ebx+FloatMatrices.M7Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M1Dis
fld R$edi+FloatMatrices.M1Dis | fmul R$ebx+FloatMatrices.M2Dis | fld R$edi+FloatMatrices.M2Dis | fmul R$ebx+FloatMatrices.M5Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M3Dis | fmul R$ebx+FloatMatrices.M8Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M2Dis
fld R$edi+FloatMatrices.M1Dis | fmul R$ebx+FloatMatrices.M3Dis | fld R$edi+FloatMatrices.M2Dis | fmul R$ebx+FloatMatrices.M6Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M3Dis | fmul R$ebx+FloatMatrices.M9Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M3Dis
fld R$edi+FloatMatrices.M4Dis | fmul R$ebx+FloatMatrices.M1Dis | fld R$edi+FloatMatrices.M5Dis | fmul R$ebx+FloatMatrices.M4Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M6Dis | fmul R$ebx+FloatMatrices.M7Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M4Dis
fld R$edi+FloatMatrices.M4Dis | fmul R$ebx+FloatMatrices.M2Dis | fld R$edi+FloatMatrices.M5Dis | fmul R$ebx+FloatMatrices.M5Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M6Dis | fmul R$ebx+FloatMatrices.M8Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M5Dis
fld R$edi+FloatMatrices.M4Dis | fmul R$ebx+FloatMatrices.M3Dis | fld R$edi+FloatMatrices.M5Dis | fmul R$ebx+FloatMatrices.M6Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M6Dis | fmul R$ebx+FloatMatrices.M9Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M6Dis
fld R$edi+FloatMatrices.M7Dis | fmul R$ebx+FloatMatrices.M1Dis | fld R$edi+FloatMatrices.M8Dis | fmul R$ebx+FloatMatrices.M4Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M9Dis | fmul R$ebx+FloatMatrices.M7Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M7Dis
fld R$edi+FloatMatrices.M7Dis | fmul R$ebx+FloatMatrices.M2Dis | fld R$edi+FloatMatrices.M8Dis | fmul R$ebx+FloatMatrices.M5Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M9Dis | fmul R$ebx+FloatMatrices.M8Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M8Dis
fld R$edi+FloatMatrices.M7Dis | fmul R$ebx+FloatMatrices.M3Dis | fld R$edi+FloatMatrices.M8Dis | fmul R$ebx+FloatMatrices.M6Dis | faddp ST1 ST0 | fld R$edi+FloatMatrices.M9Dis | fmul R$ebx+FloatMatrices.M9Dis | faddp ST1 ST0 | fstp R$edx+FloatMatrices.M9Dis
EndP
Example of usage (I´ll later change the function name, because it is not a XYZ to Lab converted ;) but a matrix adaptation to be used later on XYZ (and lab):
[ADAPT_XYZ_SCALING 0]
[ADAPT_BRADFORD 1]
[ADAPT_VON_KRIES 2]
[ScaledFactor:
ScaledFactor_Red_M1: R$ 0 ScaledFactor_Green_M2: R$ 0 ScaledFactor_Blue_M3: R$ 0
ScaledFactor_Red_M4: R$ 0 ScaledFactor_Green_M5: R$ 0 ScaledFactor_Blue_M6: R$ 0
ScaledFactor_Red_M7: R$ 0 ScaledFactor_Green_M8: R$ 0 ScaledFactor_Blue_M9: R$ 0]
; Create a adaptative matrix from WhiteRef A to C using XYZ Scaling method
call ChromaticAdaptation_XYXtoLab WHITE_SPACE_A_OBS2, WHITE_SPACE_C_OBS2, ADAPT_XYZ_SCALING, ScaledFactor
; Create a adaptative matrix from WhiteRef A to C using Bradford method
call ChromaticAdaptation_XYXtoLab WHITE_SPACE_A_OBS2, WHITE_SPACE_C_OBS2, ADAPT_BRADFORD, ScaledFactor
or...using Von Kries Method
; Create a adaptative matrix from WhiteRef A to C using Von Kries method
call ChromaticAdaptation_XYXtoLab WHITE_SPACE_A_OBS2, WHITE_SPACE_C_OBS2, ADAPT_VON_KRIES, ScaledFactor
:t :t :t :t
The function FindWhiteRef , i wrote it as:
__________________________________________________________________________________________________
; To Find the white reference correspondencies
[WHITE_SPACE_A_OBS2 0
WHITE_SPACE_C_OBS2 1
WHITE_SPACE_D50_OBS2 2
WHITE_SPACE_D55_OBS2 3
WHITE_SPACE_D65_OBS2 4
WHITE_SPACE_D75_OBS2 5
WHITE_SPACE_F2_OBS2 6
WHITE_SPACE_F7_OBS2 7
WHITE_SPACE_F11_OBS2 8
WHITE_SPACE_A_OBS10 9
WHITE_SPACE_C_OBS10 10
WHITE_SPACE_D50_OBS10 11
WHITE_SPACE_D55_OBS10 12
WHITE_SPACE_D65_OBS10 13
WHITE_SPACE_D75_OBS10 14
WHITE_SPACE_F2_OBS10 15
WHITE_SPACE_F7_OBS10 16
WHITE_SPACE_F11_OBS10 17]
[WHITE_SPACE_A_X2: R$ 109.850
WHITE_SPACE_A_Y2: R$ 100
WHITE_SPACE_A_Z2: R$ 35.585
WHITE_SPACE_C_X2: R$ 98.074
WHITE_SPACE_C_Y2: R$ 100
WHITE_SPACE_C_Z2: R$ 118.232
WHITE_SPACE_D50_X2: R$ 96.422
WHITE_SPACE_D50_Y2: R$ 100
WHITE_SPACE_D50_Z2: R$ 82.521
WHITE_SPACE_D55_X2: R$ 95.682
WHITE_SPACE_D55_Y2: R$ 100
WHITE_SPACE_D55_Z2: R$ 92.149
WHITE_SPACE_D65_X2: R$ 95.047
WHITE_SPACE_D65_Y2: R$ 100
WHITE_SPACE_D65_Z2: R$ 108.883
WHITE_SPACE_D75_X2: R$ 94.972
WHITE_SPACE_D75_Y2: R$ 100
WHITE_SPACE_D75_Z2: R$ 122.638
WHITE_SPACE_F2_X2: R$ 99.187
WHITE_SPACE_F2_Y2: R$ 100
WHITE_SPACE_F2_Z2: R$ 67.395
WHITE_SPACE_F7_X2: R$ 95.044
WHITE_SPACE_F7_Y2: R$ 100
WHITE_SPACE_F7_Z2: R$ 108.755
WHITE_SPACE_F11_X2: R$ 100.966
WHITE_SPACE_F11_Y2: R$ 100
WHITE_SPACE_F11_Z2: R$ 64.370
WHITE_SPACE_A_X10: R$ 111.144
WHITE_SPACE_A_Y10: R$ 100
WHITE_SPACE_A_Z10: R$ 35.200
WHITE_SPACE_C_X10: R$ 97.285
WHITE_SPACE_C_Y10: R$ 100
WHITE_SPACE_C_Z10: R$ 116.145
WHITE_SPACE_D50_X10: R$ 96.720
WHITE_SPACE_D50_Y10: R$ 100
WHITE_SPACE_D50_Z10: R$ 81.427
WHITE_SPACE_D55_X10: R$ 95.799
WHITE_SPACE_D55_Y10: R$ 100
WHITE_SPACE_D55_Z10: R$ 90.926
WHITE_SPACE_D65_X10: R$ 94.811
WHITE_SPACE_D65_Y10: R$ 100
WHITE_SPACE_D65_Z10: R$ 107.304
WHITE_SPACE_D75_X10: R$ 94.416
WHITE_SPACE_D75_Y10: R$ 100
WHITE_SPACE_D75_Z10: R$ 120.641
WHITE_SPACE_F2_X10: R$ 103.280
WHITE_SPACE_F2_Y10: R$ 100
WHITE_SPACE_F2_Z10: R$ 69.026
WHITE_SPACE_F7_X10: R$ 95.792
WHITE_SPACE_F7_Y10: R$ 100
WHITE_SPACE_F7_Z10: R$ 107.687
WHITE_SPACE_F11_X10: R$ 103.866
WHITE_SPACE_F11_Y10: R$ 100
WHITE_SPACE_F11_Z10: R$ 65.627]
;;
http://www.easyrgb.com/en/math.php
https://www.mathworks.com/matlabcentral/fileexchange/40640-computational-colour-science-using-matlab-2e
https://en.wikipedia.org/wiki/Standard_illuminant
XYZ (Tristimulus) Reference values of a perfect reflecting diffuser
Observer 2°(CIE 1931) 10° (CIE 1964) Note
Illuminant X2 Y2 Z2 X10 Y10 Z10
__________________________________________________________________________________________________________________
A 109.850 100.000 35.585 111.144 100.000 35.200 Incandescent/tungsten
B 99.0927 100.000 85.313 99.178 100.000 84.3493 Old direct sunlight at noon
C 98.074 100.000 118.232 97.285 100.000 116.145 Old daylight
D50 96.422 100.000 82.521 96.720 100.000 81.427 ICC profile PCS
D55 95.682 100.000 92.149 95.799 100.000 90.926 Mid-morning daylight
D65 95.047 100.000 108.883 94.811 100.000 107.304 Daylight, sRGB, Adobe-RGB
D75 94.972 100.000 122.638 94.416 100.000 120.641 North sky daylight
E 100.000 100.000 100.000 100.000 100.000 100.000 Equal energy
F1 92.834 100.000 103.665 94.791 100.000 103.191 Daylight Fluorescent
F2 99.187 100.000 67.395 103.280 100.000 69.026 Cool fluorescent
F3 103.754 100.000 49.861 108.968 100.000 51.965 White Fluorescent
F4 109.147 100.000 38.813 114.961 100.000 40.963 Warm White Fluorescent
F5 90.872 100.000 98.723 93.369 100.000 98.636 Daylight Fluorescent
F6 97.309 100.000 60.191 102.148 100.000 62.074 Lite White Fluorescent
F7 95.044 100.000 108.755 95.792 100.000 107.687 Daylight fluorescent, D65 simulator
F8 96.413 100.000 82.333 97.115 100.000 81.135 Sylvania F40, D50 simulator
F9 100.365 100.000 67.868 102.116 100.000 67.826 Cool White Fluorescent
F10 96.174 100.000 81.712 99.001 100.000 83.134 Ultralume 50, Philips TL85
F11 100.966 100.000 64.370 103.866 100.000 65.627 Ultralume 40, Philips TL84
F12 108.046 100.000 39.228 111.428 100.000 40.353 Ultralume 30, Philips TL83
;;
Proc FindWhiteRef:
Arguments @Flag, @pRefx, @pRefy, @pRefz
Uses ebx, ecx, esi
mov ebx D@pRefx, ecx D@pRefy, esi D@pRefz
.If D@Flag = WHITE_SPACE_A_OBS2
move D$ebx D$WHITE_SPACE_A_X2 | move D$ebx+4 D$WHITE_SPACE_A_X2+4
move D$ecx D$WHITE_SPACE_A_Y2 | move D$ecx+4 D$WHITE_SPACE_A_Y2+4
move D$esi D$WHITE_SPACE_A_Z2 | move D$esi+4 D$WHITE_SPACE_A_Z2+4
.Else_If D@Flag = WHITE_SPACE_C_OBS2
move D$ebx D$WHITE_SPACE_C_X2 | move D$ebx+4 D$WHITE_SPACE_C_X2+4
move D$ecx D$WHITE_SPACE_C_Y2 | move D$ecx+4 D$WHITE_SPACE_C_Y2+4
move D$esi D$WHITE_SPACE_C_Z2 | move D$esi+4 D$WHITE_SPACE_C_Z2+4
.Else_If D@Flag = WHITE_SPACE_D50_OBS2
move D$ebx D$WHITE_SPACE_D50_X2 | move D$ebx+4 D$WHITE_SPACE_D50_X2+4
move D$ecx D$WHITE_SPACE_D50_Y2 | move D$ecx+4 D$WHITE_SPACE_D50_Y2+4
move D$esi D$WHITE_SPACE_D50_Z2 | move D$esi+4 D$WHITE_SPACE_D50_Z2+4
.Else_If D@Flag = WHITE_SPACE_D55_OBS2
move D$ebx D$WHITE_SPACE_D55_X2 | move D$ebx+4 D$WHITE_SPACE_D55_X2+4
move D$ecx D$WHITE_SPACE_D55_Y2 | move D$ecx+4 D$WHITE_SPACE_D55_Y2+4
move D$esi D$WHITE_SPACE_D55_Z2 | move D$esi+4 D$WHITE_SPACE_D55_Z2+4
.Else_If D@Flag = WHITE_SPACE_D65_OBS2
move D$ebx D$WHITE_SPACE_D65_X2 | move D$ebx+4 D$WHITE_SPACE_D65_X2+4
move D$ecx D$WHITE_SPACE_D65_Y2 | move D$ecx+4 D$WHITE_SPACE_D65_Y2+4
move D$esi D$WHITE_SPACE_D65_Z2 | move D$esi+4 D$WHITE_SPACE_D65_Z2+4
.Else_If D@Flag = WHITE_SPACE_D75_OBS2
move D$ebx D$WHITE_SPACE_D75_X2 | move D$ebx+4 D$WHITE_SPACE_D75_X2+4
move D$ecx D$WHITE_SPACE_D75_Y2 | move D$ecx+4 D$WHITE_SPACE_D75_Y2+4
move D$esi D$WHITE_SPACE_D75_Z2 | move D$esi+4 D$WHITE_SPACE_D75_Z2+4
.Else_If D@Flag = WHITE_SPACE_F2_OBS2
move D$ebx D$WHITE_SPACE_F2_X2 | move D$ebx+4 D$WHITE_SPACE_F2_X2+4
move D$ecx D$WHITE_SPACE_F2_Y2 | move D$ecx+4 D$WHITE_SPACE_F2_Y2+4
move D$esi D$WHITE_SPACE_F2_Z2 | move D$esi+4 D$WHITE_SPACE_F2_Z2+4
.Else_If D@Flag = WHITE_SPACE_F7_OBS2
move D$ebx D$WHITE_SPACE_F7_X2 | move D$ebx+4 D$WHITE_SPACE_F7_X2+4
move D$ecx D$WHITE_SPACE_F7_Y2 | move D$ecx+4 D$WHITE_SPACE_F7_Y2+4
move D$esi D$WHITE_SPACE_F7_Z2 | move D$esi+4 D$WHITE_SPACE_F7_Z2+4
.Else_If D@Flag = WHITE_SPACE_F11_OBS2
move D$ebx D$WHITE_SPACE_F11_X2 | move D$ebx+4 D$WHITE_SPACE_F11_X2+4
move D$ecx D$WHITE_SPACE_F11_Y2 | move D$ecx+4 D$WHITE_SPACE_F11_Y2+4
move D$esi D$WHITE_SPACE_F11_Z2 | move D$esi+4 D$WHITE_SPACE_F11_Z2+4
.Else_If D@Flag = WHITE_SPACE_A_OBS10
move D$ebx D$WHITE_SPACE_A_X10 | move D$ebx+4 D$WHITE_SPACE_A_X10+4
move D$ecx D$WHITE_SPACE_A_Y10 | move D$ecx+4 D$WHITE_SPACE_A_Y10+4
move D$esi D$WHITE_SPACE_A_Z10 | move D$esi+4 D$WHITE_SPACE_A_Z10+4
.Else_If D@Flag = WHITE_SPACE_C_OBS10
move D$ebx D$WHITE_SPACE_C_X10 | move D$ebx+4 D$WHITE_SPACE_C_X10+4
move D$ecx D$WHITE_SPACE_C_Y10 | move D$ecx+4 D$WHITE_SPACE_C_Y10+4
move D$esi D$WHITE_SPACE_C_Z10 | move D$esi+4 D$WHITE_SPACE_C_Z10+4
.Else_If D@Flag = WHITE_SPACE_D50_OBS10
move D$ebx D$WHITE_SPACE_D50_X10 | move D$ebx+4 D$WHITE_SPACE_D50_X10+4
move D$ecx D$WHITE_SPACE_D50_Y10 | move D$ecx+4 D$WHITE_SPACE_D50_Y10+4
move D$esi D$WHITE_SPACE_D50_Z10 | move D$esi+4 D$WHITE_SPACE_D50_Z10+4
.Else_If D@Flag = WHITE_SPACE_D55_OBS10
move D$ebx D$WHITE_SPACE_D55_X10 | move D$ebx+4 D$WHITE_SPACE_D55_X10+4
move D$ecx D$WHITE_SPACE_D55_Y10 | move D$ecx+4 D$WHITE_SPACE_D55_Y10+4
move D$esi D$WHITE_SPACE_D55_Z10 | move D$esi+4 D$WHITE_SPACE_D55_Z10+4
.Else_If D@Flag = WHITE_SPACE_D65_OBS10
move D$ebx D$WHITE_SPACE_D65_X10 | move D$ebx+4 D$WHITE_SPACE_D65_X10+4
move D$ecx D$WHITE_SPACE_D65_Y10 | move D$ecx+4 D$WHITE_SPACE_D65_Y10+4
move D$esi D$WHITE_SPACE_D65_Z10 | move D$esi+4 D$WHITE_SPACE_D65_Z10+4
.Else_If D@Flag = WHITE_SPACE_D75_OBS10
move D$ebx D$WHITE_SPACE_D75_X10 | move D$ebx+4 D$WHITE_SPACE_D75_X10+4
move D$ecx D$WHITE_SPACE_D75_Y10 | move D$ecx+4 D$WHITE_SPACE_D75_Y10+4
move D$esi D$WHITE_SPACE_D75_Z10 | move D$esi+4 D$WHITE_SPACE_D75_Z10+4
.Else_If D@Flag = WHITE_SPACE_F2_OBS10
move D$ebx D$WHITE_SPACE_F2_X10 | move D$ebx+4 D$WHITE_SPACE_F2_X10+4
move D$ecx D$WHITE_SPACE_F2_Y10 | move D$ecx+4 D$WHITE_SPACE_F2_Y10+4
move D$esi D$WHITE_SPACE_F2_Z10 | move D$esi+4 D$WHITE_SPACE_F2_Z10+4
.Else_If D@Flag = WHITE_SPACE_F7_OBS10
move D$ebx D$WHITE_SPACE_F7_X10 | move D$ebx+4 D$WHITE_SPACE_F7_X10+4
move D$ecx D$WHITE_SPACE_F7_Y10 | move D$ecx+4 D$WHITE_SPACE_F7_Y10+4
move D$esi D$WHITE_SPACE_F7_Z10 | move D$esi+4 D$WHITE_SPACE_F7_Z10+4
.Else_If D@Flag = WHITE_SPACE_F11_OBS10
move D$ebx D$WHITE_SPACE_F11_X10 | move D$ebx+4 D$WHITE_SPACE_F11_X10+4
move D$ecx D$WHITE_SPACE_F11_Y10 | move D$ecx+4 D$WHITE_SPACE_F11_Y10+4
move D$esi D$WHITE_SPACE_F11_Z10 | move D$esi+4 D$WHITE_SPACE_F11_Z10+4
.End_If
EndP
Interesting. :t
Hi Siekmanski. Thanks :)
This is part of the routines i´m making to create a converter for Black and White Images (or movie) to Colored. During my studies i found out some very interesting properties regarding Luminance from CieLab (Or CieLCH which i prefer to use). For example, we can have more then 16 millions colors but, in fact, a huge amount of them are exactly the same. I mean, they are perceptually the same. During my tests i found that a gray value can result on a very limited amount of Luminance and grey is pratically only related to Luminance rather then color itself.
I built some routines to generate the proper luminance from a gray color, so, whenever a coloured image have XX value as Luminance, no matter what is the RGB combinations, they will always result on th same gray. So i built a table for that containing only a range of 256 luminance values that results on 256 gray colors.
I suceeded to make a test app to transport the colors form a reference image onto a gray image, but the results using the regular CieLab was bogus, because the values were being clipped someway. Since the RGBtoCielab (and the reverted one CieLabtoRGB) uses Whitereference. it is easy to some pixels result the wrong values since the actual formulas used only clip the exceeeding values. Ex. If the resultang Blue is more then 255 it is clipped to 255 etc etc.. Thios is inaccurate since, there shouldn´t be clipping at all in the 1st place :)
So, i faced this great Chromatic adaptation algortihms froim where i can try to use to create a better RGBtoCieLCH and CieLCHtoRGb functions without the needs of clipping anything. As you see on the attached image, the resultant colored values are clipped. The colorized image produces the same gray leves as the input, but during the convertion onto colors some pixels were clipped due to the actual failure of CieLab convertions.
My main problem while reading some publications on color convert is my lack of knowledge of complex math notations :( All the algorithms i read so far are way over my head and i can´t understand all those signs, so i´m making some of my own trying to interpret what the papers are actually trying to do. :greensml: :greensml: :greensml: :icon_mrgreen:
(https://i.imgur.com/aZmGsIF.jpg)
The actual algorithm colorizes an image on an unordered way. Ie, i made it simple as possible just trying to find the pixel from the reference that most match to the source (gray). Once i succeed to fix this adaptation algorithms i´ll try to create a way to organize the pixels, so when the colored image is being scanned it will correctly transfer a bunch of pixels that macthes exactly to the ones in the gray image.
In theory, this is not so hard to achieve since we have limited possibility of an error while trying to find the match but, still...i need to suceed to finish this adaptation algorithm before i go further on the colorization tests.
When i started creating this algorithm, the test image i posted for example, was taking something around 20 minutes to render depending on the size of the reference image (some tests took almost 50 minutes to conclude). Now, with my new routines, i could built up a table and convert to color in runtime. So, it takes less then a second to color a image of 960x480. (Still a bit slow, since i did not optimized it yet), but way better then the looooong time it was tooking when i started :)
My goal is make the convertion works in a few miliseconds per image, so i can be able to convert a full video (with, let´s say 45 minutes of duration) in less then 20 minutes :)
CieLCH colorspaace is particulary interesting using my modified method, since i found out also, that we can have a perfect limit on the relation between Chroma and Hue. Since all Luminance is specific to a certain range of gray, the formula i made up also, showed me that we have Chroma and Hue are related to each other, so it is easier to avoid clipping when knowing the proper Luma related to a pixel.
So, for example, when converting back from CieLCH to RGB, we can simply check the Luma range for the fractions (limits) of hue x chroma and, on this way we can avoid clipping. Ex: Say on Luma = 100 we have this formula for hue anc chroma. Hue = X*Chroma+Y*Luma. Once we know the proper Luma, we can simply see if the inputed Chroma macthes the maximum result when Luma is used. So, for luma = 100, the maximum relation between chroma and hue is===> Hue = X*Chroma+Y*100 and so on.....
This is to say that, each Hue have a specifi range of crhoma and vice-versa.
So, if our pixel have a Luminance of 100, we can create a routine to convert it back from Chroma and Hue properly and also allow shifting or not. For example, say that when Luma = 100 and the pixel have a Hue of 65º and we also inputed a Chroma of 80, but...if for Hue = 65º the maximum chroma is 30, we can easily clip the chroma to it fits the limit to that hue or...the other way we can keep the chroma to80 and see what is the hue that fit´s for it. In both cases, even if we clipp hue or chroma to it fits the limit, it will never result on bad RGB since we will never clip RGB whatsoever during the convertion backwards
Interesting and great work guga
I think you might be the right person to ask about an idea I have
Maybe it would be more efficient + more possibilities if I choose to work with cmyk color system with SIMD packed SSE
1 maybe can use the faster reciprocal sqrt instead
2 separate scalar use of k channel for darkness/ (brightness)
Tks Daydreamer
I did not used CMYK yet for the tests i´m making. For what i saw so far, the best colorspace is still CieLCH since it isolates almost completelly Luminance from chroma and hue. The main problem with all those algorithms XYZ, CieLab, HSI, HSV, CMYK etc etc, is that all of them works on a innacurate way, since they allows clipping on the converting back to RGB which is not desirable.
I tried several colorspaces from different apps, since gimp, photoshop, paintshoo pro etc etc, and almost all of them uses the same algorithms that on many cases does not uses white reference or even gamma adjust internally which tends to produce vbad results when converting back to RGB.
I´m not sure if using SSE for CMYK will fix those kind of problems, although it may be faster. The best would give a try on CieLCH functions and try to optimize it and then, convert to CMYK (If this colorspace is used).
I made a routine to convert RGB to LCH as bellow. It is not optimized yet, but produces an accurate result. (Dispites this small problems on the white reference adaptations i´m still working on). I can gain some speed if i suceed to fix this adaptation algorithm since i´ll no longer need to use another function to retrieve the values of White Reference, but still...i need to finish it before test to check if it is clipping or not. I´m prety sure that we can overcome the needs of 2 threshold checking on the function, but i´ll need to see if i can find those with only 1 single equation rather then those 2 routines used to check. And latrer, if suceed to make all of thiss works on a single equation, then can use a SSE to speed up a little bit (specially because it uses at the end the atan2 function which is kinda slow, though) and i don´t know a way to compute the atan of an angle with SSE to make it faster)
Anyway, try using CieLCH colorspace rather then CMYK. Dispites some minor speed problems, it is really worthfull.
Proc RGBtoCieLCH:
Arguments @Red, @Green, @Blue, @pLuminance, @pChroma, @pHue, @Flag, @WhiteRef
Local @MyPixelSrc
Structure @TempStorage 64, @pXDis 0, @pYDis 8, @pZDis 16, @TmpRedDis, 24, @TmpGreenDis 32, @TmpBlueDis 40, @pAFactorDis 48, @pBFactorDis 56
Uses esi, ebx, ecx, edx, edi
finit
If D@Flag > XYZ_Matrice_sRGB_D65_HDTV
mov D@Flag XYZ_Matrice_sRGB_D65_HDTV
End_If
;1st convert to XYZ colorspace. Same as RGBtoXYZ3
; double r = (double)((src & 0xff0000) >> 16)/255; RED
lea ecx D@TmpRedDis | fild F@Red | fmul R$FloatOne_255 | fstp R$ecx
; double g = (double)((src & 0xff00) >> 8)/255; GREEN
lea ecx D@TmpGreenDis | fild F@Green | fmul R$FloatOne_255 | fstp R$ecx
; double b = (double)(src & 0xff)/255; BLUE
lea ecx D@TmpBlueDis | fild F@Blue | fmul R$FloatOne_255 | fstp R$ecx
call GammaLinearEncodingEx F_gamma, F_Offset, F_Slope, F_Treshold, F_OffsetPlusOne, D@Flag
; newColorRed = ((R@Red+0.055)/1.055)^2.4 ; where2.4 = gamma, 0.055 = Offset, 1.055 = Offset+1. Better precalculating them as i did.
lea ecx D@TmpRedDis
.Fpu_If R$ecx > R$F_Treshold
fld R$F_gamma | fld R$F_Offset | fadd R$ecx | fmul R$F_OffsetPlusOne | fyl2x | fld1 | fld ST1 | fprem | f2xm1 | faddp ST1 ST0 | fscale | fxch | fstp ST0
.Fpu_Else
fld R$ecx | fdiv R$F_Slope
.Fpu_End_If
fmul R$Float100 | fstp R$ecx
; newColorGreen = ((R@Green+0.055)/1.055)^2.4
lea ecx D@TmpGreenDis
.Fpu_If R$ecx > R$F_Treshold
fld R$F_gamma | fld R$F_Offset | fadd R$ecx | fmul R$F_OffsetPlusOne | fyl2x | fld1 | fld ST1 | fprem | f2xm1 | faddp ST1 ST0 | fscale | fxch | fstp ST0
.Fpu_Else
fld R$ecx | fdiv R$F_Slope
.Fpu_End_If
fmul R$Float100 | fstp R$ecx
; newColorBlue = ((R@Blue+0.055)/1.055)^2.4
lea ecx D@TmpBlueDis
.Fpu_If R$ecx > R$F_Treshold
fld R$F_gamma | fld R$F_Offset | fadd R$ecx | fmul R$F_OffsetPlusOne | fyl2x | fld1 | fld ST1 | fprem | f2xm1 | faddp ST1 ST0 | fscale | fxch | fstp ST0
.Fpu_Else
fld R$ecx | fdiv R$F_Slope
.Fpu_End_If
fmul R$Float100 | fstp R$ecx
; probably mising the Normalize for D65 white point because the sum of FloatMatrices on X and Z does not lead to 1. See RGB2Lab4 and CieLabtoCieLCH. Hue for this varyes from 292 to 293 when RGB = 0 and RGB = 255 when it should be a fixed value
; Observer. = 2°, Illuminant = D65
xor edx edx
mov eax Size_Of_FloatMatrices
mul D@Flag
mov esi FloatXYZWorkSpacesMatrices
add esi eax
lea ecx D@pXDis | fld R@TmpRedDis | fmul R$esi+FloatMatrices.M1Dis | fld R@TmpGreenDis | fmul R$esi+FloatMatrices.M2Dis | faddp ST1 ST0 | fld R@TmpBlueDis | fmul R$esi+FloatMatrices.M3Dis | faddp ST1 ST0 | fstp R$ecx
lea ecx D@pYDis | fld R@TmpRedDis | fmul R$esi+FloatMatrices.M4Dis | fld R@TmpGreenDis | fmul R$esi+FloatMatrices.M5Dis | faddp ST1 ST0 | fld R@TmpBlueDis | fmul R$esi+FloatMatrices.M6Dis | faddp ST1 ST0 | fstp R$ecx
lea ecx D@pZDis | fld R@TmpRedDis | fmul R$esi+FloatMatrices.M7Dis | fld R@TmpGreenDis | fmul R$esi+FloatMatrices.M8Dis | faddp ST1 ST0 | fld R@TmpBlueDis | fmul R$esi+FloatMatrices.M9Dis | faddp ST1 ST0 | fstp R$ecx
; 2nd convert XYZ to Cielab as in XYZtoCieLab3
; Whiteref is the Yn term from https://en.wikipedia.org/wiki/Lab_color_space
call FindWhiteRef D@WhiteRef, Ref_X, Ref_Y, Ref_Z
; must be within the limits
lea ebx D@pXDis | fld R$ebx | fdiv R$Ref_X | fst R$ebx | fstp R$FPU_TempResult
Fpu_If R$FPU_TempResult > R$Float_One
fld R$Float_One | fstp R$ebx
Fpu_End_If
lea ebx D@pYDis | fld R$ebx | fdiv R$Ref_Y | fst R$ebx | fstp R$FPU_TempResult
Fpu_If R$FPU_TempResult > R$Float_One
fld R$Float_One | fstp R$ebx
Fpu_End_If
lea ebx D@pZDis | fld R$ebx | fdiv R$Ref_Z | fst R$ebx | fstp R$FPU_TempResult
Fpu_If R$FPU_TempResult > R$Float_One
fld R$Float_One | fstp R$ebx
Fpu_End_If
; We know that X+Y+Z = 1, therefore: Z = 1-(X+Y)
; var_X = var_X ^ ( 1/3 )
.Fpu_If R@pXDis > R$Float8856
fld R$FloatOneThird | fld R@pXDis | fyl2x | fld1 | fld ST1 | fprem | f2xm1 | faddp ST1 ST0 | fscale | fxch | fstp ST0
.Fpu_Else
fld R@pXDis | fmul R$Float_7787 | fadd R$Float_16_116
.Fpu_End_If
lea eax D@pXDis | fstp R$eax
; var_Y = var_Y ^ ( 1/3 )
.Fpu_If R@pYDis > R$Float8856
fld R$FloatOneThird | fld R@pYDis | fyl2x | fld1 | fld ST1 | fprem | f2xm1 | faddp ST1 ST0 | fscale | fxch | fstp ST0
.Fpu_Else
fld R@pYDis | fmul R$Float_7787 | fadd R$Float_16_116
.Fpu_End_If
lea eax D@pYDis | fstp R$eax
; var_Z = var_Z ^ ( 1/3 )
.Fpu_If R@pZDis > R$Float8856
fld R$FloatOneThird | fld R@pZDis | fyl2x | fld1 | fld ST1 | fprem | f2xm1 | faddp ST1 ST0 | fscale | fxch | fstp ST0
.Fpu_Else
fld R@pZDis | fmul R$Float_7787 | fadd R$Float_16_116
.Fpu_End_If
lea eax D@pZDis | fstp R$eax
mov eax D@pLuminance | fld R@pYDis | fmul R$Float_116 | fsub R$Float_16 | fabs | fstp R$eax ; luminance is always positive. we must be sure this result is >= 0. Same as in GraytoLuma
lea eax D@pAFactorDis | fld R@pXDis | fsub R@pYDis | fmul R$Float_500 | fstp R$eax
lea eax D@pBFactorDis | fld R@pYDis | fsub R@pZDis | fmul R$Float_200 | fstp R$eax
; 3rd finally convert to chroma and hue as in CieLabtoCieLCH
mov edi D@pChroma
lea eax D@pAFactorDis
lea ebx D@pBFactorDis
fld R$eax | fst St1 | fmulp ST1 ST0
fld R$ebx | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt
fstp R$edi
;call atan2 D@bFactor, D@aFactor, &TRUE
call atan2 ebx, eax, &TRUE
mov eax D@pHue | fstp R$eax
EndP
I dont know if atan taylor series should make it or LUT?
well its looks like an alternative,either K=blackness or L=luminance
Check my Rossler attractor thread in workshop, to see what I am working on
Looks like your pic example,it could be possible to add some psychedelic colors to a boring greyscale object
A taylor series for atan ? Hmm..maybe it wil speed up a little bit. I´ll give a try later when finishing it. :t :t :t
About LUT...i´m not sure. LUT filters are good for Sony Vegas for example or Premiere, or even VirtualDub but, at the end, it seems that they are only a array of Luminance Data and the main app (Vegas, etc etc) only uses them to replace the original luminance of a given image/video rather then fix the internal problems with the current CieLab functions they uses.
I suceeeded to make a function to adapt the different white references from the tristimulus values to convert from D65 to D50, to HD etc etc....but still needs to make the convertier works on their own Matrixes rather then only on Bradford . I´m struggling to understand how to use the Chromatic Adaptation in order to properly convert all those white references. Probably i need only a multipllication of a matrix by another one, but didn´t tested yet. Yesterday i got stuck trying to make the proper invert matrix 3x3 to use for example on the backwards computation from CieLab to RGB.
And yes..CieLCH is an alternative but needs to be fixed 1st as i told. The good thing for the CieLab and other perceptual colorspaces is that they can represent the colors correclty. Last year i started developing a new colorspace biased on the TSL one (Not HSL...the TSL - I made some fixes and adaptations of that on wiki: https://en.wikipedia.org/wiki/TSL_color_space) that is in short, a spherical colorspace that also can separate completelly the luminance from chroma and hue. I suceeded to create the algo for converting from RGB to it...but got stuck on the backwards computation. Once i have time, i´ll give a try again on the algorithm.
The good thing i notice is that, on the preliminary tests on my algo, there was no such a thing as a true black color, since the 3 points of the space coordinates (R, G, B) can never all be 0 at the same time meaning that even if only one of thhem reaches 0 it means absolutelly nothing except a bad pixels since 0 is not a isolated starting value for R, G, B but only a starting point of all of them. So a colorspace to be a bit more accurate can never consider 0 as a valid value for a pixel. And from the adjustements i´m making on the CieLCH/CieLab formulas, this assumption seems to be true meaning that whenever a pixel have value of 0, 0, 0 (or perhaps, even for the pure white 255,255,255) we are dealing, in fact with a bad pixel.
Btw...if you want a way to get the tristimulus values for the white reference, i made a function for it and posted on the RosAsm subforum. It is easy to follow. I named it as "FindWhiteRefEx"