The MASM Forum

Miscellaneous => The Orphanage => Topic started by: guga on January 21, 2019, 09:00:28 AM

Title: Chromatic Adaptation problem
Post by: guga on January 21, 2019, 09:00:28 AM
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
Title: Re: Chromatic Adaptation problem
Post by: guga on January 22, 2019, 02:24:17 AM
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
Title: Re: Chromatic Adaptation problem
Post by: guga on January 22, 2019, 02:33:40 AM
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


Title: Re: Chromatic Adaptation problem
Post by: Siekmanski on January 22, 2019, 03:38:13 AM
Interesting.  :t
Title: Re: Chromatic Adaptation problem
Post by: guga on January 22, 2019, 04:13:45 AM
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
Title: Re: Chromatic Adaptation problem
Post by: daydreamer on January 22, 2019, 05:58:09 AM
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)
Title: Re: Chromatic Adaptation problem
Post by: guga on January 22, 2019, 06:56:13 AM
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

Title: Re: Chromatic Adaptation problem
Post by: daydreamer on January 23, 2019, 05:41:02 AM
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
Title: Re: Chromatic Adaptation problem
Post by: guga on January 23, 2019, 06:18:58 AM
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"