News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Fast median algorithm

Started by guga, July 18, 2020, 02:22:35 AM

Previous topic - Next topic

guga

Hi MArinus...Ok, now i see. You sum up all pixels filling only the 1st col with 255 (putting it on the left side) and multiplying it by the edge operator, no matter what is it´s size. Great ! Easier then i thought :thumbsup: :thumbsup: :thumbsup:



Do the Matrix convolution with the maximum pixel value (255).

         [ 255 0 0 ]
Pixels = [ 255 0 0 ]
         [ 255 0 0 ]


     [+1  0 -1 ]            [ 255 0 0 ]
Gx = [+2  0 -2 ] * Pixels = [ 255 0 0 ] = 1*255 + 0*0 + -1*0 + 2*255 + 0*0 + -2*0 + 1*255 + 0*0 + -1*0 = 1020 ( we found a maximum edge on the X-axis )
     [+1  0 -1 ]            [ 255 0 0 ]


     [+1 +2 +1 ]            [ 255 0 0 ]
Gy = [ 0  0  0 ] * Pixels = [   255 0 0 ] = 1*255 + 2*0 + 1*0 + 0*255 + 0*0 + 0*0 + -1*255 + -2*0 + -1*0 = 0 ( we found no edge on the Y-axis )
     [-1 -2 -1 ]            [255 0 0 ]

As you can see here: 1020 is a maximum edge but also -1020 is a maximum edge.

         [ 0 0 255 ]
Pixels = [ 0 0 255 ] * Gx = -1020
         [ 0 0 255 ]


So, the final part to calculate Gx is:


         [ 0 0 255 ]
Pixels = [ 0 0 255 ] * Gx = -1020
         [ 0 0 255 ]


Putting the 255 on the right side and do the same thing as above, produces always the same result, right ?



     [+1  0 -1 ]            [ 0 0 255 ]
G = [+2  0 -2 ] * Pixels = [ 0 0 255 ] = 1*0 + 0*0 + -1*255 + 2*0 + 0*0 + -2*255 + 1*0 + 0*0 + -1*255 = -1020 ( we found a maximum edge on the Gx axis but in the opposed sign, because its´in the opposite direction)
     [+1  0 -1 ]            [ 0 0 255 ]


About the normalization, i did as you said. I just precalculated the value of the normalization previously to it always stays out of the loop that calculates the Sobel (or whataver other operator), so it could be a bit faster.

What i did was basically:


Proc SetSobelData:
    Arguments @pColorData, @ImgWidth, @ImgHeight, @pOutSobelX, @pOutSobelY
    Uses esi, edx, ecx, ebx, edi

    mov esi D@pColorData

    ; initialize min and max values
    mov D$EdgeSobelPlus+EdgeSobelPlus.SobelGMinDis 255
    mov D$EdgeSobelPlus+EdgeSobelPlus.SobelGMaxDis 0

    ; initialize SobelPlus structure
    call PrepareSobelEdges EdgeSobelPlus, 0, 0, EDGE_FILTER_SOBEL
(...)
    mov ebx D@Imgwidth | shl ebx 2 | mov D@NextLine ebx
    mov D@Y 0 | mov eax D@Y
    ...While eax < D@Imgheight
        mov D@X 0
        mov edx D@X
        ..While edx < D@Imgwidth

            ; fill our matrix with the inputed pixels
            call FillMatrix3_3 esi, edx, D@Y, TmpMatrix, D@ImgWidth, D@ImgHeight

            call FindSobelEdgesEx TmpMatrix, EdgeSobelPlus, &FALSE

            ; I´ll Optimize this later removing the labels and using registers, instead
            mov eax D$EdgeSobelPlus+EdgeSobelPlus.SobelGxDis | mov edi D@CurSobelX | mov D$edi eax | add D@CurSobelX 4
            mov eax D$EdgeSobelPlus+EdgeSobelPlus.SobelGyDis | mov edi D@CurSobelY | mov D$edi eax | add D@CurSobelY 4

            mov eax D$EdgeSobelPlus+EdgeSobelPlus.SobelGDis | mov edi D@CurSobel | add D@CurSobel 4
            On eax < D$EdgeSobelPlus+EdgeSobelPlus.SobelGMinDis, mov D$EdgeSobelPlus+EdgeSobelPlus.SobelGMinDis eax
            On eax > D$EdgeSobelPlus+EdgeSobelPlus.SobelGMaxDis, mov D$EdgeSobelPlus+EdgeSobelPlus.SobelGMaxDis eax

            ; Not necessary to set the output here for the scope of the watermar detector. I putted here only because i wanted to see the results 1st
            mov B$edi+BGRA.RedDis al
            mov B$edi+BGRA.GreenDis al
            mov B$edi+BGRA.BlueDis al
            mov B$edi+BGRA.AlphaDis 255

            inc edx
        ..End_While
        inc D@Y
        mov eax D@Y
        add esi D@NextLine
    ...End_While
(...)
EndP




;;
           PrepareSobelEdges
             This function precalculates the values of the normalization to be used on a edge detection function according to the operators values you feed in

          Parameters:

               pSobelStruct - Pointer to a EdgeSobelPlus Structure that will hold and deal with the several values retrieved during a sobel, scharr or any other edge operators we want

               SobelValA - Is the 'magic' numbers used in an edge operator. ex: In sobel, this value is 0-1, for scharr, this value is 47   and so on. It is the number related to the M1 position on the matrix index.
                                 You can set whatever value you want to create your own Edge operator indexes. To do that, you must define the TypeFlag member as EDGE_FILTER_USER.
                                 Otherwise, if you want a predefined operator (sobel), you can set this member to 0 and use the EDGE_FILTER_SOBEL equate in the  TypeFlag parameter.

               SobelValB - Is the 'magic' numbers used in an edge operator. ex: In sobel, this value is 0-2, for scharr, this value is 162  and so on. It is the number related to the M4 position on the matrix index.
                                 You can set whatever value you want to create your own Edge operator indexes. To do that, you must define the TypeFlag member as EDGE_FILTER_USER.
                                 Otherwise, if you want a predefined operator (sobel), you can set this member to 0 and use the EDGE_FILTER_SOBEL equate in the  TypeFlag parameter

               TypeFlag - A set of predefined Flags to use for specific operators. Currently, you can use any of these 3 equates:
                                Equate Name                Equate Value     Meaning
                                EDGE_FILTER_USER              0                  Use this flag, if you want to create your own pre-defined operator. You must fill the values on SobelValA and SobelValB
                                EDGE_FILTER_SOBEL            1                  Use this flag to enable only the Sobel Operator. The values on SobelValA and SobelValB will be ignored (you can, as well, simply set them to zero. But for convention, better is use 0 insetad)
                                EDGE_FILTER_SCHARR          2                  Use this flag to enable only the Sobel Operator. The values on SobelValA and SobelValB will be ignored (you can, as well, simply set them to zero. But for convention, better is use 0 insetad)
;;

Proc PrepareSobelEdges:
    Arguments @pSobelStruct, @SobelValA, @SobelValD, @TypeFlag
    Local @MatrixValA, @MatrixValD
    Uses edi

    mov eax D@SobelValA | mov D@MatrixValA eax
    mov eax D@SobelValD | mov D@MatrixValD eax

    .If D@TypeFlag = EDGE_FILTER_SOBEL
        mov D@MatrixValA 0-1
        mov D@MatrixValD 0-2
    .Else_If D@TypeFlag = EDGE_FILTER_SCHARR
        mov D@MatrixValA 47
        mov D@MatrixValD 161; 162 (official value). 161 is the best value i found because the sum of MatrixA+matrixB applying the formula below gives 255
    .Else
         ; if both are zero, avoid division by zero on the normalization ratio
        mov edi D@MatrixValA
        .Test_If_Not_And eax eax, edi edi
            mov edi D@pSobelStruct
            fldz | fst F$edi+EdgeSobelPlus.MatrixValADis | fst F$edi+EdgeSobelPlus.MatrixValBDis | fstp F$edi+EdgeSobelPlus.NormalizeRatioDis
            ExitP
        .Test_End
    .End_If

    mov edi D@pSobelStruct ; All Ok, let´s calculate and put their values
    fild D@MatrixValA | fst F$edi+EdgeSobelPlus.MatrixValADis | fabs | fmul R$Float_Two
    fild D@MatrixValD | fst F$edi+EdgeSobelPlus.MatrixValBDis | fabs | faddp ST1 ST0
    fmul R$Float_255 | fld1 | fdivrp ST0 ST1 | fstp F$edi+EdgeSobelPlus.NormalizeRatioDis

EndP


This is the main Structure used to store the necessary data to calculate thee sobel, Scharr or any other 3x3 operator (including user made). All values are stored in Real4 format.


[EdgeSobelPlus:
EdgeSobelPlus.ValA: F$ 0 ; Is the magic number used in Sobel in Position M1. Ex: 0-1
EdgeSobelPlus.ValB: F$ 0 ; Is the magic number used in Sobel in Position M4. Ex: 0-2
EdgeSobelPlus.NormalizeRatio: F$ 0 ; Is the ratio used to normalize the edge detection function.
EdgeSobelPlus.SobelGx: F$ 0 ; The value of Sobel Gx. Real4 format
EdgeSobelPlus.SobelGy: F$ 0 ; The value of Sobel Gy. Real4 format
EdgeSobelPlus.SobelG: F$ 0 ; The value of Sobel G. Real4 format
EdgeSobelPlus.Angle: F$ 0 ; The Angle (in degrees)of Sobel G. Real4 format
EdgeSobelPlus.SobelGxMin: F$ 0 ; The Minimum Value of Sobel Gx inside a image. Real4 format
EdgeSobelPlus.SobelGyMin: F$ 0 ; The Minimum Value of Sobel Gy inside a image. Real4 format
EdgeSobelPlus.SobelGMin: F$ 0 ; The Minimum Value of Sobel G inside a image. Real4 format
EdgeSobelPlus.SobelGxMax: F$ 0 ; The Maximum Value of Sobel Gx inside a image. Real4 format
EdgeSobelPlus.SobelGyMax: F$ 0 ; The Maximum Value of Sobel Gy inside a image. Real4 format
EdgeSobelPlus.SobelGMax: F$ 0 ; The Maximum Value of Sobel G inside a image. Real4 format
EdgeSobelPlus.AngleMin: F$ 0 ; The Maximum Value of Sobel G inside a image. Real4 format
EdgeSobelPlus.AngleMax: F$ 0 ; The Maximum Value of Sobel G inside a image. Real4 format
]

; Equates used


[EdgeSobelPlus.MatrixValADis 0
EdgeSobelPlus.MatrixValBDis 4
EdgeSobelPlus.NormalizeRatioDis 8
EdgeSobelPlus.SobelGxDis 12
EdgeSobelPlus.SobelGyDis 16
EdgeSobelPlus.SobelGDis 20
EdgeSobelPlus.AngleDis 24
EdgeSobelPlus.SobelGxMinDis 28
EdgeSobelPlus.SobelGyMinDis 32
EdgeSobelPlus.SobelGMinDis 36
EdgeSobelPlus.SobelGxMaxDis 40
EdgeSobelPlus.SobelGyMaxDis 44
EdgeSobelPlus.SobelGMaxDis 48
EdgeSobelPlus.AngleMinDis 52
EdgeSobelPlus.AngleMaxDis 56]

[Size_of_EdgeSobelPlus 60]





;;
             pMatrix (in)- Pointer to the inputed pixels stored on a 3x3 matrix
             pSobelStruct (in/out) - Pointer to a EdgeSobelPlus structure that will grab the values predefined to calcaulate the sobel, and fill thenecessay data accordlying.
                                                 The values that will be filled here are: SobelGx, SobelGy, Sobel G and Angle (in degrees). All value are stored on Real4 format, except Sobel G that is exported as integer
                                                  Sobel Gx and Sobel Gy (or shcarr gx/gy or whatever other operator you used), will be stored on the normalized values between -1 to 1 and always biased on 255.
                                                  So the range is, in fact from -255 to 255. To retrieve this values (the same as the pixel) all you have to do later is multiply the values found to 255.
             UseDegree - If yopu want the function to export the angle of the pixel set this flag to TRUE. Otherwise set it to FALSE.
;;

Proc FindSobelEdgesEx:
    Arguments @pMatrix, @pSobelStruct, @UseDegree
    Local @DataCheck
    Structure @TempAxis 16, @SobelYAxisDis 0, @SobelXAxisDis 8
    Uses esi, edi, edx, ecx, eax

    finit

    mov esi D@pMatrix

    ; calculate normalization is already done in PrepareSobelEdges function

    ;Gx = A*(M1+M7-M3-M9) + D*(M4-M6); where A = 47, D = 162

    mov edi D@pSobelStruct
    fld F$esi+FloatMatricesInt.M1Dis | fadd F$esi+FloatMatricesInt.M7Dis | fsub F$esi+FloatMatricesInt.M3Dis | fsub F$esi+FloatMatricesInt.M9Dis | fmul F$edi+EdgeSobelPlus.MatrixValADis;D@MatrixValA
    fld F$esi+FloatMatricesInt.M4Dis | fsub F$esi+FloatMatricesInt.M6Dis | fmul F$edi+EdgeSobelPlus.MatrixValBDis | faddp ST1 ST0
    ; normalize to 1020, 765 and multiply the result to 255 to we get the proper integer are already predefined in PrepareSobelEdges  function
    fmul F$edi+EdgeSobelPlus.NormalizeRatioDis | fstp F$edi+EdgeSobelPlus.SobelGxDis

    ; Gy = A*(M1+M3-M7-M9) + B*(M2-M8)
    fld F$esi+FloatMatricesInt.M1Dis | fadd F$esi+FloatMatricesInt.M3Dis | fsub F$esi+FloatMatricesInt.M7Dis | fsub F$esi+FloatMatricesInt.M9Dis | fmul F$edi+EdgeSobelPlus.MatrixValADis; | fmul D@MatrixValA
    fld F$esi+FloatMatricesInt.M2Dis | fsub F$esi+FloatMatricesInt.M8Dis | fmul F$edi+EdgeSobelPlus.MatrixValBDis | faddp ST1 ST0
    ; normalize to 1020, 765 etc and multiply the result to 255 to we get the proper integer are already predefined in PrepareSobelEdges function
    fmul F$edi+EdgeSobelPlus.NormalizeRatioDis | fstp F$edi+EdgeSobelPlus.SobelGyDis

    ; Calculate the angle if needed
    If D@UseDegree <> 0
        lea eax D@SobelYAxisDis | fld F$edi+EdgeSobelPlus.SobelGyDis | fstp R$eax
        lea edx D@SobelXAxisDis | fld F$edi+EdgeSobelPlus.SobelGxDis | fstp R$edx
        call atan2 eax, edx, &True
        fstp F$edi+EdgeSobelPlus.AngleDis
    End_If

    ; And finally create the Sobel G after Gx and Gy are already fixed

    ; Soble = sqrt((255*FractionX)^2+(255*FractionY)^2)) = G = sqrt(Gx^2+Gy^2)
    ; since FractionX and FractionY can have a maximum of 1 and -1, therefore sobleMax = (255/sqrt(2)) * sqrt(FractionX^2+FractionY^2)

    fld F$edi+EdgeSobelPlus.SobelGxDis | fmul ST0 ST0 | fld F$edi+EdgeSobelPlus.SobelGyDis | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt | fmul R$Float_SobleVarG
    fistp F$edi+EdgeSobelPlus.SobelGDis
    mov eax D$edi+EdgeSobelPlus.SobelGDis
    If eax > 255
        mov eax 255
    End_If
    mov D$edi+EdgeSobelPlus.SobelGDis eax

EndP


As you see, i made the necessary functions to work outside the maain loop to precalculate everything needed to initiate the sobel routine. This gained soime speed (although the fucntions are nopt yet optimized).


I´ll clean up the code and ppost here an small working example.



Some notes:

Scharr Operator defines the 'magic numbers" as: ValA = 47 and ValB = 162, but this lead to a bit of innacuracy, because the normalization is, therefore biased on 255 and it will produce a result slightly different. The better is used ValB as 161, instead

Also, we can use our own values to create a costumized operator. I found that using ValA = -300 and ValB as 120000 gives a slighly better result, since it calculates all edges and the image becomes prettier. (although, contains some noise as well, but prettier)
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

Siekmanski

QuotePutting the 255 on the right side and do the same thing as above, produces always the same result, right ?

The sign tells you if the edge is left or right, for Gx
Up or down for Gy.

I'm not that far yet with my programming.
Still at the stage of generating different gray color conversions.  :tongue: ( 4 pixels at once, and handle image widths not divisible by 4 )
I have written the code this way, that every stage can access all next stages etc. to see all the possibilities on screen.

stage 1: different gray color conversions
stage 2: different lowpass filters
stage 3: different types of edge detection operators ( Sobel, Scharr etc )
stage 4: creating a Gx,Gy table from one of the previous stages
stage 5: finding the directions per edge pixel and give it a color for that direction. ( stage 5: just for the fun, it should look awesome )

But first step is, getting the math correct ( think I got it covered, else, have to study it more ) then after that, optimize it.
Still thinking what to do with G, maybe clamp it to get a higher intensity color, I will experiment with that when I reach that stage.

Creative coders use backward thinking techniques as a strategy.

guga

Quote from: Siekmanski on August 03, 2020, 05:50:46 AM
QuotePutting the 255 on the right side and do the same thing as above, produces always the same result, right ?

The sign tells you if the edge is left or right, for Gx
Up or down for Gy.

I'm not that far yet with my programming.
Still at the stage of generating different gray color conversions.  :tongue: ( 4 pixels at once, and handle image widths not divisible by 4 )
I have written the code this way, that every stage can access all next stages etc. to see all the possibilities on screen.

stage 1: different gray color conversions
stage 2: different lowpass filters
stage 3: different types of edge detection operators ( Sobel, Scharr etc )
stage 4: creating a Gx,Gy table from one of the previous stages
stage 5: finding the directions per edge pixel and give it a color for that direction. ( stage 5: just for the fun, it should look awesome )

But first step is, getting the math correct ( think I got it covered, else, have to study it more ) then after that, optimize it.
Still thinking what to do with G, maybe clamp it to get a higher intensity color, I will experiment with that when I reach that stage.
.

Hi Marinus. About different color conversion of gray, it depends of which workspace you are using. Each workspace has his own set of gamma, offset  and matrix values to be settled.

I can´t put all of the code here, because the code i made to work with these is a kind of a mess and is big. But, if you want the values, i put them in one single structure with the matrices like this (Btw, R$ means Real8):


[NativeMatrix:
  WSData_NTSC_RGB_C.Name: D$ Sz_NTSC_RGB
  WsData_WhiteRef_NTSC_RGB: D$ WS_C_OBS2
  WSData_NTSC_RGB_C_Red_M1: R$ 0.6068909        WSData_NTSC_RGB_C_Green_M2: R$ 0.1735011        WSData_NTSC_RGB_C_Blue_M3: R$ 0.200348
  WSData_NTSC_RGB_C_Red_M4: R$ 0.2989164        WSData_NTSC_RGB_C_Green_M5: R$ 0.586599         WSData_NTSC_RGB_C_Blue_M6: R$ 0.1144846
  WSData_NTSC_RGB_C_Red_M7: R$ 0                WSData_NTSC_RGB_C_Green_M8: R$ 0.0660957        WSData_NTSC_RGB_C_Blue_M9: R$ 1.1162243
  WSData_GammaDecEnc_NTSC_RGB_C.Gamma: R$ 2.2
  WSData_GammaDecEnc_NTSC_RGB_C.Offset: R$ 0.055

  WSData_Best_RGB_D50.Name: D$ Sz_Best_RGB
  WsData_WhiteRef_Best_RGB: D$ WS_D50_OBS2
  WSData_Best_RGB_D50_Red_M1: R$ 0.6326696      WSData_Best_RGB_D50_Green_M2: R$ 0.2045558      WSData_Best_RGB_D50_Blue_M3: R$ 0.1269946
  WSData_Best_RGB_D50_Red_M4: R$ 0.2284569      WSData_Best_RGB_D50_Green_M5: R$ 0.7373523      WSData_Best_RGB_D50_Blue_M6: R$ 0.0341908
  WSData_Best_RGB_D50_Red_M7: R$ 0              WSData_Best_RGB_D50_Green_M8: R$ 0.0095142      WSData_Best_RGB_D50_Blue_M9: R$ 0.8156958
  WSData_GammaDecEnc_Best_RGB_D50.Gamma: R$ 2.2
  WSData_GammaDecEnc_Best_RGB_D50.Offset: R$ 0.055

  WSData_Beta_RGB_D50.Name: D$ Sz_Beta_RGB
  WsData_WhiteRef_Beta_RGB: D$ WS_D50_OBS2
  WSData_Beta_RGB_D50_Red_M1: R$ 0.6712537      WSData_Beta_RGB_D50_Green_M2: R$ 0.1745834      WSData_Beta_RGB_D50_Blue_M3: R$ 0.1183829
  WSData_Beta_RGB_D50_Red_M4: R$ 0.3032726      WSData_Beta_RGB_D50_Green_M5: R$ 0.6637861      WSData_Beta_RGB_D50_Blue_M6: R$ 0.0329413
  WSData_Beta_RGB_D50_Red_M7: R$ 0              WSData_Beta_RGB_D50_Green_M8: R$ 0.040701       WSData_Beta_RGB_D50_Blue_M9: R$ 0.784509
  WSData_GammaDecEnc_Beta_RGB_D50.Gamma: R$ 2.2
  WSData_GammaDecEnc_Beta_RGB_D50.Offset: R$ 0.055

  WSData_ColorMatch_RGB_D50.Name: D$ Sz_ColorMatch
  WsData_WhiteRef_ColorMatch_RGB: D$ WS_D50_OBS2
  WSData_ColorMatch_RGB_D50_Red_M1: R$ 0.5093439    WSData_ColorMatch_RGB_D50_Green_M2: R$ 0.3209071    WSData_ColorMatch_RGB_D50_Blue_M3: R$ 0.133969
  WSData_ColorMatch_RGB_D50_Red_M4: R$ 0.274884     WSData_ColorMatch_RGB_D50_Green_M5: R$ 0.6581315    WSData_ColorMatch_RGB_D50_Blue_M6: R$ 0.0669845
  WSData_ColorMatch_RGB_D50_Red_M7: R$ 0.0242545    WSData_ColorMatch_RGB_D50_Green_M8: R$ 0.108782     WSData_ColorMatch_RGB_D50_Blue_M9: R$ 0.6921735
  WSData_GammaDecEnc_ColorMatch_RGB_D50.Gamma: R$ 1.8
  WSData_GammaDecEnc_ColorMatch_RGB_D50.Offset: R$ 0.055

  WSData_Don_RGB_4_D50.Name: D$ Sz_Don_RGB4
  WsData_WhiteRef_Don_RGB_4: D$ WS_D50_OBS2
  WSData_Don_RGB_4_D50_Red_M1: R$ 0.6457711         WSData_Don_RGB_4_D50_Green_M2: R$ 0.1933511     WSData_Don_RGB_4_D50_Blue_M3: R$ 0.1250978
  WSData_Don_RGB_4_D50_Red_M4: R$ 0.2783496         WSData_Don_RGB_4_D50_Green_M5: R$ 0.6879702     WSData_Don_RGB_4_D50_Blue_M6: R$ 0.0336802
  WSData_Don_RGB_4_D50_Red_M7: R$ 0.0037113         WSData_Don_RGB_4_D50_Green_M8: R$ 0.0179861     WSData_Don_RGB_4_D50_Blue_M9: R$ 0.8035126
  WSData_GammaDecEnc_Don_RGB_4_D50.Gamma: R$ 2.2
  WSData_GammaDecEnc_Don_RGB_4_D50.Offset: R$ 0.055

  WSData_ECI_RGB_D50.Name: D$ Sz_ECI_RGB
  WsData_WhiteRef_ECI_RGB: D$ WS_D50_OBS2
  WSData_ECI_RGB_D50_Red_M1: R$ 0.6502043       WSData_ECI_RGB_D50_Green_M2: R$ 0.1780774       WSData_ECI_RGB_D50_Blue_M3: R$ 0.1359383
  WSData_ECI_RGB_D50_Red_M4: R$ 0.3202499       WSData_ECI_RGB_D50_Green_M5: R$ 0.6020711       WSData_ECI_RGB_D50_Blue_M6: R$ 0.077679
  WSData_ECI_RGB_D50_Red_M7: R$ 0               WSData_ECI_RGB_D50_Green_M8: R$ 0.067839        WSData_ECI_RGB_D50_Blue_M9: R$ 0.757371
  WSData_GammaDecEnc_ECI_RGB_D50.Gamma: R$ 1.8
  WSData_GammaDecEnc_ECI_RGB_D50.Offset: R$ 0.055

  WSData_Ekta_Space_PS5_D50.Name: D$ Sz_Ekta_Space_PS5
  WsData_WhiteRef_Ekta_Space_PS5: D$ WS_D50_OBS2
  WSData_Ekta_Space_PS5_D50_Red_M1: R$ 0.5938914    WSData_Ekta_Space_PS5_D50_Green_M2: R$ 0.2729801    WSData_Ekta_Space_PS5_D50_Blue_M3: R$ 0.0973485
  WSData_Ekta_Space_PS5_D50_Red_M4: R$ 0.2606286    WSData_Ekta_Space_PS5_D50_Green_M5: R$ 0.7349465    WSData_Ekta_Space_PS5_D50_Blue_M6: R$ 0.0044249
  WSData_Ekta_Space_PS5_D50_Red_M7: R$ 0            WSData_Ekta_Space_PS5_D50_Green_M8: R$ 0.0419969    WSData_Ekta_Space_PS5_D50_Blue_M9: R$ 0.7832131
  WSData_GammaDecEnc_Ekta_Space_PS5_D50.Gamma: R$ 2.2
  WSData_GammaDecEnc_Ekta_Space_PS5_D50.Offset: R$ 0.055

  WsData_ProPhoto_RGB.Name: D$ Sz_ProPhoto
  WsData_WhiteRef_ProPhoto_RGB: D$ WS_D50_OBS2
  WSData_ProPhoto_RGB_D50_Red_M1: R$ 0.7976749      WSData_ProPhoto_RGB_D50_Green_M2: R$ 0.1351917      WSData_ProPhoto_RGB_D50_Blue_M3: R$ 0.0313534
  WSData_ProPhoto_RGB_D50_Red_M4: R$ 0.2880402      WSData_ProPhoto_RGB_D50_Green_M5: R$ 0.7118741      WSData_ProPhoto_RGB_D50_Blue_M6: R$ 0.0000857
  WSData_ProPhoto_RGB_D50_Red_M7: R$ 0              WSData_ProPhoto_RGB_D50_Green_M8: R$ 0              WSData_ProPhoto_RGB_D50_Blue_M9: R$ 0.82521
  WSData_GammaDecEnc_ProPhoto_RGB_D50.Gamma: R$ 1.8
  WSData_GammaDecEnc_ProPhoto_RGB_D50.Offset: R$ 0.055

  WSData_Wide_Gamut_RGB_D50.Name: D$ Sz_Wide_Gamut
  WsData_WhiteRef_Wide_Gamut_RGB: D$ WS_D50_OBS2
  WSData_Wide_Gamut_RGB_D50_Red_M1: R$ 0.7161046    WSData_Wide_Gamut_RGB_D50_Green_M2: R$ 0.1009296    WSData_Wide_Gamut_RGB_D50_Blue_M3: R$ 0.1471858
  WSData_Wide_Gamut_RGB_D50_Red_M4: R$ 0.2581874    WSData_Wide_Gamut_RGB_D50_Green_M5: R$ 0.7249378    WSData_Wide_Gamut_RGB_D50_Blue_M6: R$ 0.0168748
  WSData_Wide_Gamut_RGB_D50_Red_M7: R$ 0            WSData_Wide_Gamut_RGB_D50_Green_M8: R$ 0.0517813    WSData_Wide_Gamut_RGB_D50_Blue_M9: R$ 0.7734287
  WSData_GammaDecEnc_Wide_Gamut_RGB_D50.Gamma: R$ 2.2
  WSData_GammaDecEnc_Wide_Gamut_RGB_D50.Offset: R$ 0.055

  WSData_Adobe_RGB_1998.Name: D$ Sz_Adobe_RGB_1998
  WsData_WhiteRef_Adobe_RGB_1998: D$ WS_D65_OBS2
  WSData_Adobe_RGB_1998_D65_Red_M1: R$ 0.5767309    WSData_Adobe_RGB_1998_D65_Green_M2: R$ 0.185554     WSData_Adobe_RGB_1998_D65_Blue_M3: R$ 0.1881851
  WSData_Adobe_RGB_1998_D65_Red_M4: R$ 0.2973769    WSData_Adobe_RGB_1998_D65_Green_M5: R$ 0.6273491    WSData_Adobe_RGB_1998_D65_Blue_M6: R$ 0.075274
  WSData_Adobe_RGB_1998_D65_Red_M7: R$ 0.0270343    WSData_Adobe_RGB_1998_D65_Green_M8: R$ 0.0706872    WSData_Adobe_RGB_1998_D65_Blue_M9: R$ 0.9911085
  WSData_GammaDecEnc_Adobe_RGB_1998_D65.Gamma: R$ 2.19921875
  WSData_GammaDecEnc_Adobe_RGB_1998_D65.Offset: R$ 0.055

  WSData_AppleRGB_D65.Name: D$ Sz_AppleRGB
  WsData_WhiteRef_AppleRGB: D$ WS_D65_OBS2
  WSData_AppleRGB_D65_Red_M1: R$ 0.4497288          WSData_AppleRGB_D65_Green_M2: R$ 0.3162486          WSData_AppleRGB_D65_Blue_M3: R$ 0.1844926
  WSData_AppleRGB_D65_Red_M4: R$ 0.2446525          WSData_AppleRGB_D65_Green_M5: R$ 0.6720283          WSData_AppleRGB_D65_Blue_M6: R$ 0.0833192
  WSData_AppleRGB_D65_Red_M7: R$ 0.0251848          WSData_AppleRGB_D65_Green_M8: R$ 0.1411824          WSData_AppleRGB_D65_Blue_M9: R$ 0.9224628
  WSData_GammaDecEnc_AppleRGB_D65.Gamma: R$ 1.8
  WSData_GammaDecEnc_AppleRGB_D65.Offset: R$ 0.055

  WSData_Bruce_RGB_D65.Name: D$ Sz_Bruce_RGB
  WsData_WhiteRef_Bruce_RGB: D$ WS_D65_OBS2
  WSData_Bruce_RGB_D65_Red_M1: R$ 0.4674162         WSData_Bruce_RGB_D65_Green_M2: R$ 0.2944512         WSData_Bruce_RGB_D65_Blue_M3: R$ 0.1886026
  WSData_Bruce_RGB_D65_Red_M4: R$ 0.2410115         WSData_Bruce_RGB_D65_Green_M5: R$ 0.6835475         WSData_Bruce_RGB_D65_Blue_M6: R$ 0.075441
  WSData_Bruce_RGB_D65_Red_M7: R$ 0.0219101         WSData_Bruce_RGB_D65_Green_M8: R$ 0.0736128         WSData_Bruce_RGB_D65_Blue_M9: R$ 0.9933071
  WSData_GammaDecEnc_Bruce_RGB_D65.Gamma: R$ 2.2
  WSData_GammaDecEnc_Bruce_RGB_D65.Offset: R$ 0.055

  WSData_PAL_SECAM_RGB_D65.Name: D$ Sz_PAL_SECAM
  WsData_WhiteRef_PAL_SECAM_RGB: D$ WS_D65_OBS2
  WSData_PAL_SECAM_RGB_D65_Red_M1: R$ 0.430619      WSData_PAL_SECAM_RGB_D65_Green_M2: R$ 0.3415419     WSData_PAL_SECAM_RGB_D65_Blue_M3: R$ 0.1783091
  WSData_PAL_SECAM_RGB_D65_Red_M4: R$ 0.2220379     WSData_PAL_SECAM_RGB_D65_Green_M5: R$ 0.7066384     WSData_PAL_SECAM_RGB_D65_Blue_M6: R$ 0.0713237
  WSData_PAL_SECAM_RGB_D65_Red_M7: R$ 0.0201853     WSData_PAL_SECAM_RGB_D65_Green_M8: R$ 0.1295504     WSData_PAL_SECAM_RGB_D65_Blue_M9: R$ 0.9390943
  WSData_GammaDecEnc_PAL_SECAM_RGB_D65.Gamma: R$ 2.2
  WSData_GammaDecEnc_PAL_SECAM_RGB_D65.Offset: R$ 0.055

  WSData_SMPTE_C_RGB_D65.Name: D$ Sz_SMPTE_C
  WsData_WhiteRef_SMPTE_C_RGB: D$ WS_D65_OBS2
  WSData_SMPTE_C_RGB_D65_Red_M1: R$ 0.3935891       WSData_SMPTE_C_RGB_D65_Green_M2: R$ 0.3652497       WSData_SMPTE_C_RGB_D65_Blue_M3: R$ 0.1916312
  WSData_SMPTE_C_RGB_D65_Red_M4: R$ 0.2124132       WSData_SMPTE_C_RGB_D65_Green_M5: R$ 0.7010437       WSData_SMPTE_C_RGB_D65_Blue_M6: R$ 0.0865431
  WSData_SMPTE_C_RGB_D65_Red_M7: R$ 0.0187423       WSData_SMPTE_C_RGB_D65_Green_M8: R$ 0.1119313       WSData_SMPTE_C_RGB_D65_Blue_M9: R$ 0.9581564
  WSData_GammaDecEnc_SMPTE_C_RGB_D65.Gamma: R$ 2.2
  WSData_GammaDecEnc_SMPTE_C_RGB_D65.Offset: R$ 0.055

  WSData_sRGB_D65.Name: D$ Sz_sRGB
  WsData_WhiteRef_sRGB: D$ WS_D65_OBS2
  WSData_sRGB_D65_Red_M1: R$ 0.4124564              WSData_sRGB_D65_Green_M2: R$ 0.3575761              WSData_sRGB_D65_Blue_M3: R$ 0.1804375
  WSData_sRGB_D65_Red_M4: R$ 0.2126729              WSData_sRGB_D65_Green_M5: R$ 0.7151522              WSData_sRGB_D65_Blue_M6: R$ 0.0721749
  WSData_sRGB_D65_Red_M7: R$ 0.0193339              WSData_sRGB_D65_Green_M8: R$ 0.1191920              WSData_sRGB_D65_Blue_M9: R$ 0.9503041
  WSData_GammaDecEnc_sRGB_D65.Gamma: R$ 2.4
  WSData_GammaDecEnc_sRGB_D65.Offset: R$ 0.055

  WSData_sRGB_D65_Red_HDTV.Name: D$ Sz_sRGB_HDTV
  WsData_WhiteRef_sRGB_HDTV: D$ WS_D65_OBS2
  WSData_sRGB_D65_Red_HDTV_M1: R$ 0.4124564         WSData_sRGB_D65_Green_HDTV_M2: R$ 0.3575761         WSData_sRGB_D65_Blue_HDTV_M3: R$ 0.1804375
  WSData_sRGB_D65_Red_HDTV_M4: R$ 0.2126729         WSData_sRGB_D65_Green_HDTV_M5: R$ 0.7151522         WSData_sRGB_D65_Blue_HDTV_M6: R$ 0.0721749
  WSData_sRGB_D65_Red_HDTV_M7: R$ 0.0193339         WSData_sRGB_D65_Green_HDTV_M8: R$ 0.1191920         WSData_sRGB_D65_Blue_HDTV_M9: R$ 0.9503041
  WSData_GammaDecEnc_sRGB_D65_HDTV.Gamma: R$ 2.2
  WSData_GammaDecEnc_sRGB_D65_HDTV.Offset: R$ 0.099

  WSData_CIE_RGB_E.Name: D$ Sz_CIE_RGB
  WsData_WhiteRef_CIE_RGB: D$ WS_E_OBS2
  WSData_CIE_RGB_E_Red_M1: R$ 0.488718              WSData_CIE_RGB_E_Green_M2: R$ 0.3106803             WSData_CIE_RGB_E_Blue_M3: R$ 0.2006017
  WSData_CIE_RGB_E_Red_M4: R$ 0.1762044             WSData_CIE_RGB_E_Green_M5: R$ 0.8129847             WSData_CIE_RGB_E_Blue_M6: R$ 0.0108109
  WSData_CIE_RGB_E_Red_M7: R$ 0                     WSData_CIE_RGB_E_Green_M8: R$ 0.0102048             WSData_CIE_RGB_E_Blue_M9: R$ 0.9897952
  WSData_GammaDecEnc_CIE_RGB_E.Gamma: R$ 2.2
  WSData_GammaDecEnc_CIE_RGB_E.Offset: R$ 0.055]



[Sz_NTSC_RGB: B$ "NTSC RGB", 0
Sz_Best_RGB: B$ "Best RGB", 0
Sz_Beta_RGB: B$ "Beta RGB", 0
Sz_ColorMatch: B$ "ColorMatch", 0
Sz_Don_RGB4: B$ "Don RGB4", 0
Sz_ECI_RGB: B$ "ECI RGB", 0
Sz_Ekta_Space_PS5: B$ "Ekta Space PS5", 0
Sz_ProPhoto: B$ "ProPhoto", 0
Sz_Wide_Gamut: B$ "Wide Gamut", 0
Sz_Adobe_RGB_1998: B$ "Adobe RGB (1998)", 0
Sz_AppleRGB: B$ "Apple RGB", 0
Sz_Bruce_RGB: B$ "Bruce RGB", 0
Sz_PAL_SECAM: B$ "PAL SECAM", 0
Sz_SMPTE_C: B$ "SMPTE-C", 0
Sz_sRGB: B$ "sRGB", 0
Sz_sRGB_HDTV: B$ "sRGB HDTV", 0
Sz_CIE_RGB: B$ "CIE RGB", 0]


And here is a list of all available White Reference that can be used per workspace or alone.



[WHITE_SPACE_A_X_OBS2: R$ 109.850       WHITE_SPACE_A_Y_OBS2: R$ 100        WHITE_SPACE_A_Z_OBS2: R$ 35.585     ; Incandescent/tungsten
WHITE_SPACE_A_X_OBS10: R$ 111.144      WHITE_SPACE_A_Y_OBS10: R$ 100       WHITE_SPACE_A_Z_OBS10: R$ 35.200    ; Incandescent/tungsten

WHITE_SPACE_B_X_OBS2: R$ 99.0927       WHITE_SPACE_B_Y_OBS2: R$ 100        WHITE_SPACE_B_Z_OBS2: R$ 85.313     ; Old direct sunlight at noon
WHITE_SPACE_B_X_OBS10: R$ 99.178       WHITE_SPACE_B_Y_OBS10: R$ 100       WHITE_SPACE_B_Z_OBS10: R$ 84.3493   ; Old direct sunlight at noon

WHITE_SPACE_C_X_OBS2: R$ 98.074        WHITE_SPACE_C_Y_OBS2: R$ 100        WHITE_SPACE_C_Z_OBS2: R$ 118.232    ; Old daylight
WHITE_SPACE_C_X_OBS10: R$ 97.285       WHITE_SPACE_C_Y_OBS10: R$ 100       WHITE_SPACE_C_Z_OBS10: R$ 116.145   ; Old daylight

WHITE_SPACE_D50_X_OBS2: R$ 96.422      WHITE_SPACE_D50_Y_OBS2: R$ 100      WHITE_SPACE_D50_Z_OBS2: R$ 82.521   ; ICC profile PCS
WHITE_SPACE_D50_X_OBS10: R$ 96.720     WHITE_SPACE_D50_Y_OBS10: R$ 100     WHITE_SPACE_D50_Z_OBS10: R$ 81.427  ; ICC profile PCS

WHITE_SPACE_D55_X_OBS2: R$ 95.682      WHITE_SPACE_D55_Y_OBS2: R$ 100      WHITE_SPACE_D55_Z_OBS2: R$ 92.149   ; Mid-morning daylight
WHITE_SPACE_D55_X_OBS10: R$ 95.799     WHITE_SPACE_D55_Y_OBS10: R$ 100     WHITE_SPACE_D55_Z_OBS10: R$ 90.926  ; Mid-morning daylight

WHITE_SPACE_D65_X_OBS2: R$ 95.047      WHITE_SPACE_D65_Y_OBS2: R$ 100      WHITE_SPACE_D65_Z_OBS2: R$ 108.883  ; Daylight, sRGB, Adobe-RGB
WHITE_SPACE_D65_X_OBS10: R$ 94.811     WHITE_SPACE_D65_Y_OBS10: R$ 100     WHITE_SPACE_D65_Z_OBS10: R$ 107.304 ; Daylight, sRGB, Adobe-RGB

WHITE_SPACE_D75_X_OBS2: R$ 94.972      WHITE_SPACE_D75_Y_OBS2: R$ 100      WHITE_SPACE_D75_Z_OBS2: R$ 122.638  ; North sky daylight
WHITE_SPACE_D75_X_OBS10: R$ 94.416     WHITE_SPACE_D75_Y_OBS10: R$ 100     WHITE_SPACE_D75_Z_OBS10: R$ 120.641 ; North sky daylight

WHITE_SPACE_E_X_OBS2: R$ 100           WHITE_SPACE_E_Y_OBS2: R$ 100        WHITE_SPACE_E_Z_OBS2: R$ 100        ; Equal energy
WHITE_SPACE_E_X_OBS10: R$ 100          WHITE_SPACE_E_Y_OBS10: R$ 100       WHITE_SPACE_E_Z_OBS10: R$ 100       ; Equal energy

WHITE_SPACE_F1_X_OBS2: R$ 92.834       WHITE_SPACE_F1_Y_OBS2: R$ 100       WHITE_SPACE_F1_Z_OBS2: R$ 103.665   ; Daylight Fluorescent
WHITE_SPACE_F1_X_OBS10: R$ 94.791      WHITE_SPACE_F1_Y_OBS10: R$ 100      WHITE_SPACE_F1_Z_OBS10: R$ 103.191  ; Daylight Fluorescent

WHITE_SPACE_F2_X_OBS2: R$ 99.187       WHITE_SPACE_F2_Y_OBS2: R$ 100       WHITE_SPACE_F2_Z_OBS2: R$ 67.395    ; Cool fluorescent
WHITE_SPACE_F2_X_OBS10: R$ 103.280     WHITE_SPACE_F2_Y_OBS10: R$ 100      WHITE_SPACE_F2_Z_OBS10: R$ 69.026   ; Cool fluorescent

WHITE_SPACE_F3_X_OBS2: R$ 103.754      WHITE_SPACE_F3_Y_OBS2: R$ 100       WHITE_SPACE_F3_Z_OBS2: R$ 49.861    ; White Fluorescent
WHITE_SPACE_F3_X_OBS10: R$ 108.968     WHITE_SPACE_F3_Y_OBS10: R$ 100      WHITE_SPACE_F3_Z_OBS10: R$ 51.965   ; White Fluorescent

WHITE_SPACE_F4_X_OBS2: R$ 109.147      WHITE_SPACE_F4_Y_OBS2: R$ 100       WHITE_SPACE_F4_Z_OBS2: R$ 38.813    ; Warm White Fluorescent
WHITE_SPACE_F4_X_OBS10: R$ 114.961     WHITE_SPACE_F4_Y_OBS10: R$ 100      WHITE_SPACE_F4_Z_OBS10: R$ 40.963   ; Warm White Fluorescent

WHITE_SPACE_F5_X_OBS2: R$ 90.872       WHITE_SPACE_F5_Y_OBS2: R$ 100       WHITE_SPACE_F5_Z_OBS2: R$ 98.723    ; Daylight Fluorescent
WHITE_SPACE_F5_X_OBS10: R$ 93.369      WHITE_SPACE_F5_Y_OBS10: R$ 100      WHITE_SPACE_F5_Z_OBS10: R$ 98.636   ; Daylight Fluorescent

WHITE_SPACE_F6_X_OBS2: R$ 97.309       WHITE_SPACE_F6_Y_OBS2: R$ 100       WHITE_SPACE_F6_Z_OBS2: R$ 60.191    ; Lite White Fluorescent
WHITE_SPACE_F6_X_OBS10: R$ 102.148     WHITE_SPACE_F6_Y_OBS10: R$ 100      WHITE_SPACE_F6_Z_OBS10: R$ 62.074   ; Lite White Fluorescent

WHITE_SPACE_F7_X_OBS2: R$ 95.044       WHITE_SPACE_F7_Y_OBS2: R$ 100       WHITE_SPACE_F7_Z_OBS2: R$ 108.755   ; Daylight fluorescent, D65 simulator
WHITE_SPACE_F7_X_OBS10: R$ 95.792      WHITE_SPACE_F7_Y_OBS10: R$ 100      WHITE_SPACE_F7_Z_OBS10: R$ 107.687  ; Daylight fluorescent, D65 simulator

WHITE_SPACE_F8_X_OBS2: R$ 96.413       WHITE_SPACE_F8_Y_OBS2: R$ 100       WHITE_SPACE_F8_Z_OBS2: R$ 82.333    ; Sylvania F40, D50 simulator
WHITE_SPACE_F8_X_OBS10: R$ 97.115      WHITE_SPACE_F8_Y_OBS10: R$ 100      WHITE_SPACE_F8_Z_OBS10: R$ 81.135   ; Sylvania F40, D50 simulator

WHITE_SPACE_F9_X_OBS2: R$ 100.365      WHITE_SPACE_F9_Y_OBS2: R$ 100       WHITE_SPACE_F9_Z_OBS2: R$ 67.868    ; Cool White Fluorescent
WHITE_SPACE_F9_X_OBS10: R$ 102.116     WHITE_SPACE_F9_Y_OBS10: R$ 100      WHITE_SPACE_F9_Z_OBS10: R$ 67.826   ; Cool White Fluorescent

WHITE_SPACE_F10_X_OBS2: R$ 96.174      WHITE_SPACE_F10_Y_OBS2: R$ 100      WHITE_SPACE_F10_Z_OBS2: R$ 81.712   ; Ultralume 50, Philips TL85
WHITE_SPACE_F10_X_OBS10: R$ 99.001     WHITE_SPACE_F10_Y_OBS10: R$ 100     WHITE_SPACE_F10_Z_OBS10: R$ 83.134  ; Ultralume 50, Philips TL85

WHITE_SPACE_F11_X_OBS2: R$ 100.966     WHITE_SPACE_F11_Y_OBS2: R$ 100      WHITE_SPACE_F11_Z_OBS2: R$ 64.370   ; Ultralume 40, Philips TL84
WHITE_SPACE_F11_X_OBS10: R$ 103.866    WHITE_SPACE_F11_Y_OBS10: R$ 100     WHITE_SPACE_F11_Z_OBS10: R$ 65.627  ; Ultralume 40, Philips TL84

WHITE_SPACE_F12_X_OBS2: R$ 108.046     WHITE_SPACE_F12_Y_OBS2: R$ 100      WHITE_SPACE_F12_Z_OBS2: R$ 39.228   ; Ultralume 30, Philips TL83
WHITE_SPACE_F12_X_OBS10: R$ 111.428    WHITE_SPACE_F12_Y_OBS10: R$ 100     WHITE_SPACE_F12_Z_OBS10: R$ 40.353] ; Ultralume 30, Philips TL83

[WhiteSpaceXDis 0
WhiteSpaceYDis 8
WhiteSpaceZDis 16]

[Size_Of_WhiteSpace 24]

[WS_A_OBS2 0
WS_A_OBS10 1
WS_B_OBS2 2
WS_B_OBS10 3
WS_C_OBS2 4
WS_C_OBS10 5
WS_D50_OBS2 6
WS_D50_OBS10 7
WS_D55_OBS2 8
WS_D55_OBS10 9
WS_D65_OBS2 10
WS_D65_OBS10 11
WS_D75_OBS2 12
WS_D75_OBS10 13
WS_E_OBS2 14
WS_E_OBS10 15
WS_F1_OBS2 16
WS_F1_OBS10 17
WS_F2_OBS2 18
WS_F2_OBS10 19
WS_F3_OBS2 20
WS_F3_OBS10 21
WS_F4_OBS2 22
WS_F4_OBS10 23
WS_F5_OBS2 24
WS_F5_OBS10 25
WS_F6_OBS2 26
WS_F6_OBS10 27
WS_F7_OBS2 28
WS_F7_OBS10 29
WS_F8_OBS2 30
WS_F8_OBS10 31
WS_F9_OBS2 32
WS_F9_OBS10 33
WS_F10_OBS2 34
WS_F10_OBS10 35
WS_F11_OBS2 36
WS_F11_OBS10 37
WS_F12_OBS2 38
WS_F12_OBS10 39]
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

; Native Matrix Structure format is like this and all the equates used are right below.

[NativeMatrix.Name: D$ 0 ; Pointer to the name of the model (camera, color space such as: Adobe, Pal/SECAM, Bruce etc)
NativeMatrix.WhiteRef: D$ 0
NativeMatrix.RedM1: R$ 0   NativeMatrix.GreenM2: R$ 0  NativeMatrix.BlueM3: R$ 0
NativeMatrix.RedM4: R$ 0   NativeMatrix.GreenM5: R$ 0  NativeMatrix.BlueM6: R$ 0
NativeMatrix.RedM7: R$ 0   NativeMatrix.GreenM8: R$ 0  NativeMatrix.BlueM9: R$ 0
NativeMatrix.GammaDecEnc.Gamma: R$ 0
NativeMatrix.GammaDecEnc.Offset: R$ 0]

Equates used in NativeMatrix structure


; Native Working Spaces and their Matrices

[CS_MATRIX_NTSC_RGB_C 0]
[CS_MATRIX_BEST_RGB_D50 1]
[CS_MATRIX_BETA_RGB_D50 2]
[CS_MATRIX_COLORMATCH_RGB_D50 3]
[CS_MATRIX_DON_RGB_4_D50 4]
[CS_MATRIX_ECI_RGB_D50 5]
[CS_MATRIX_EKTA_SPACE_PS5_D50 6]
[CS_MATRIX_PROPHOTO_RGB_D50 7]
[CS_MATRIX_WIDE_GAMUT_RGB_D50 8]
[CS_MATRIX_ADOBE_RGB_1998_D65 9]
[CS_MATRIX_APPLERGB_D65 10]
[CS_MATRIX_BRUCE_RGB_D65 11]
[CS_MATRIX_PAL_SECAM_RGB_D65 12]
[CS_MATRIX_SMPTE_C_RGB_D65 13]
[CS_MATRIX_SRGB_D65 14]
[CS_MATRIX_SRGB_D65_HDTV 15]
[CS_MATRIX_CIE_RGB_E 16]



[NativeMatrix.NameDis 0
NativeMatrix.WhiteRefDis 4
NativeMatrix.RedM1Dis 8
NativeMatrix.GreenM2Dis 16
NativeMatrix.BlueM3Dis 24
NativeMatrix.RedM4Dis 32
NativeMatrix.GreenM5Dis 40
NativeMatrix.BlueM6Dis 48
NativeMatrix.RedM7Dis 56
NativeMatrix.GreenM8Dis 64
NativeMatrix.BlueM9Dis 72
NativeMatrix.GammaDecEnc.GammaDis 80
NativeMatrix.GammaDecEnc.OffsetDis 88

Size_Of_NativeMatrix 96]





Btw...about the values of the matrices, their inverted form are also calculated inside a function i created for it. All the data used by workspaces are called in one single function called at once when an app starts, for example.

The function is called: "SetupWorkSpaceMatrixDataEx"

You call it once using whatever workspace needed, and it does the calculations of all necessary data (gamma, tresholds, offsets, luma ranges to be applied to gray etc etc)
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

Siekmanski

That's a big collection of color spaces.  :cool:
Creative coders use backward thinking techniques as a strategy.

guga

Hi Marinus

Any idea how to deal with Sobel G results applied to the luminosity of  image ?

I´m trying to create a equation to apply the sobel gradient G to the overall luminosity on a image to enhance the edges and the other non-edge areas.

The idea is like this:

SobelG properly identifies an edge when the G value is bigger then 127. Then the pixel are most likely belong to and edge.
When G value is below or equal to 127, it means that the pixel most likely is not an edge.

Therefore i create a equation similar to the one we compute the sobel G like this:

Target Pixel = The image we want to enhance the edges using sobel values.

If the Sobel Pixel G is bigger then 127 (meaning we have an edge) we apply this equation:

sqrt(((SobelG-128)*2)^2 + Luma^2)

Where Luma is the value of the target pixel (Luma = Gray, in fact).

It worked, but do have issues in colored images, because the Luma of the target pixel near the edge (not all of them) sometimes is too bright, resulting in a completely change of the original color.




The goal is calculate a new magnitude (luma/Gray) biased on the value found in Sobel (when it is an edge, thus, "G" is above 127) and, at the same time, knows what to do when the target pixel is excessively bright (> 127) or excessively dark (<= 127).

For example, if the target pixel also has a value above 127, then it will apply a sobel G upon it and decrease the level a little bit using the proposed equation.

And do the opposite when the target pixel is below or equal to 127, but, this time, increasing the luma/gray of it a little bit, biased also on what was found on the sobel value.

Plus, know what do to when the target pixel is an edge, but it is completely black (pix val = 0) and the sobel G is too high. Ex: We have a Sobel G of 255 and a pixel target of 0. We can´t simply take i´ts average (neither use the equation above) because we will end up transforming a pure black pixel in gray (127 or something)

All of the above is when it finds a Edge (so, when Sobel is above 127.)



And also, once it is fixed, do the same on the areas that are not edge. Using the values of sobel (which will be this time <= then 127 and increasing or decreasing the pixel luminosity a little bit too.


Any ideas on what could be a possible equation to handle all situations ? (edge and non-edge areas)


Note: In order to enhance the errors (so i could see where they are) i previously equalized the image before applying the sobel over it. The steps i did to magnify and find the errors were:
1 - Opened a colored image
2 - Converted to gray
3 - Applied a Histogram equalization on the gray image created.
4 - Applied Sobel over the equalized gray image
5 - Used the resultant values of  Sobel G as a luma guidance applied over the original image. (This step is where i used the equation)
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

Siekmanski

The range back from Sobel G = 0 to 1020.
I have thought about it how to turn it into a usable color. ( 0 to 255 )
We have to find out how the distribution is laid out in the G values.

Maybe clamp a value greater than 127 to 127?
Or move the values 0 - 127 to 128 - 255?
Or try other limits between 127 and 255?
Or stretch, shrink the values?
Or divide G by 1020*255?
Or whatever you can come up with....
I don't have a clue yet, but will see when we get there and use the best solution for our purpose.

I'm almost there in my coding progress, I'm not that fast anymore.  :biggrin:
I'll skip the lowpass filter for now, and do it later and start with the Sobel operator.
Then see what is best to do.

Have the gray (luminosity) conversions ready, PAL NTSC SECAM, HDTV and HDR for now.
In my code I load a bitmap image convert it to 32bit ARGB and save it to memory.
Then create a table of floating point luminosity conversions from the the ARGB values in memory and create a 4 pixel empty boundary around the luminosity table. ( to handle pixels near the edges of the bitmap image. )
So there is room for max. 5*5 matrices to play with.

When I have completed the Sobel-operator code, it is time to experiment.

Step by step, and check every step if the math is correct.

Creative coders use backward thinking techniques as a strategy.

Siekmanski

Example of the HDTV luminosity conversion with the 4 pixel boundary.

Creative coders use backward thinking techniques as a strategy.

guga

Hi Marinus,
About how to normalize it, i've done on the way you suggested and it worked like a charm.

The function is the one i posted on the previous comment:



;;
           PrepareSobelEdges
             This function precalculates the values of the normalization to be used on a edge detection function according to the operators values you feed in

          Parameters:

               pSobelStruct - Pointer to a EdgeSobelPlus Structure that will hold and deal with the several values retrieved during a sobel, scharr or any other edge operators we want

               SobelValA - Is the 'magic' numbers used in an edge operator. ex: In sobel, this value is 0-1, for scharr, this value is 47   and so on. It is the number related to the M1 position on the matrix index.
                                 You can set whatever value you want to create your own Edge operator indexes. To do that, you must define the TypeFlag member as EDGE_FILTER_USER.
                                 Otherwise, if you want a predefined operator (sobel), you can set this member to 0 and use the EDGE_FILTER_SOBEL equate in the  TypeFlag parameter.

               SobelValB - Is the 'magic' numbers used in an edge operator. ex: In sobel, this value is 0-2, for scharr, this value is 162  and so on. It is the number related to the M4 position on the matrix index.
                                 You can set whatever value you want to create your own Edge operator indexes. To do that, you must define the TypeFlag member as EDGE_FILTER_USER.
                                 Otherwise, if you want a predefined operator (sobel), you can set this member to 0 and use the EDGE_FILTER_SOBEL equate in the  TypeFlag parameter

               TypeFlag - A set of predefined Flags to use for specific operators. Currently, you can use any of these 3 equates:
                                Equate Name                Equate Value     Meaning
                                EDGE_FILTER_USER              0                  Use this flag, if you want to create your own pre-defined operator. You must fill the values on SobelValA and SobelValB
                                EDGE_FILTER_SOBEL            1                  Use this flag to enable only the Sobel Operator. The values on SobelValA and SobelValB will be ignored (you can, as well, simply set them to zero. But for convention, better is use 0 insetad)
                                EDGE_FILTER_SCHARR          2                  Use this flag to enable only the Sobel Operator. The values on SobelValA and SobelValB will be ignored (you can, as well, simply set them to zero. But for convention, better is use 0 insetad)

;;


; Equates used for the EdgeSobelPlus structure

[EdgeSobelPlus.MatrixValADis 0
EdgeSobelPlus.MatrixValBDis 4
EdgeSobelPlus.NormalizeRatioDis 8
EdgeSobelPlus.SobelGxDis 12
EdgeSobelPlus.SobelGyDis 16
EdgeSobelPlus.SobelGDis 20
EdgeSobelPlus.AngleDis 24
EdgeSobelPlus.SobelGxMinDis 28
EdgeSobelPlus.SobelGyMinDis 32
EdgeSobelPlus.SobelGMinDis 36
EdgeSobelPlus.SobelGxMaxDis 40
EdgeSobelPlus.SobelGyMaxDis 44
EdgeSobelPlus.SobelGMaxDis 48
EdgeSobelPlus.AngleMinDis 52
EdgeSobelPlus.AngleMaxDis 56]

[Size_of_EdgeSobelPlus 60]


; Equates Flags used to make easier the computation

[EDGE_FILTER_USER 0
EDGE_FILTER_SOBEL 1
EDGE_FILTER_SCHARR 2]


Proc PrepareSobelEdges:
    Arguments @pSobelStruct, @SobelValA, @SobelValD, @TypeFlag
    Local @MatrixValA, @MatrixValD
    Uses edi

    mov eax D@SobelValA | mov D@MatrixValA eax
    mov eax D@SobelValD | mov D@MatrixValD eax

    .If D@TypeFlag = EDGE_FILTER_SOBEL
        mov D@MatrixValA 0-1
        mov D@MatrixValD 0-2
    .Else_If D@TypeFlag = EDGE_FILTER_SCHARR
        mov D@MatrixValA 47
        mov D@MatrixValD 161; 162 (official value). 161 is the best value i found because the sum of MatrixA+matrixB applying the formula below gives 255
    .Else
         ; if both are zero, avoid division by zero on the normalization ratio. The ratio is, therefore: zero.
        mov edi D@MatrixValA
        .Test_If_Not_And eax eax, edi edi
            mov edi D@pSobelStruct
            fldz | fst F$edi+EdgeSobelPlus.MatrixValADis | fst F$edi+EdgeSobelPlus.MatrixValBDis | fstp F$edi+EdgeSobelPlus.NormalizeRatioDis
            ExitP
        .Test_End
    .End_If

    mov edi D@pSobelStruct ; All Ok, let´s calculate and put their values
    fild D@MatrixValA | fst F$edi+EdgeSobelPlus.MatrixValADis | fabs | fmul R$Float_Two
    fild D@MatrixValD | fst F$edi+EdgeSobelPlus.MatrixValBDis | fabs | faddp ST1 ST0
    fmul R$Float_255 | fld1 | fdivrp ST0 ST1 | fstp F$edi+EdgeSobelPlus.NormalizeRatioDis

EndP


The math is what you told me:

Normalization Ratio = 1/(255*(|ValA|*2 + |ValD|))

Where:
ValA is the Sobel Matrix Value at Position M1 = 0-1
ValD is the Sobel Matrix Value at Position M4 = 0-2

For Sobel, it results in: 1/(255*(|-1|*2 + |-2|)) = 1/1020

Or...for scharr it is
ValA = 47
ValD = 161 ; (The official value is 162, but i figure it out that using 161 is a bit more accurated)

For Scharr, it results in: 1/(255*(|47|*2 + |161|)) = 1/65025


Or..you can use whatever value you like on a 3x3 matrix on the style of a Sobel Operator.


I used the normalization ratio on other function which is the one that do the sobel computation. (FindSobelEdgesEx)

Basically, it does this:

Gx = (ValA*(M1+M7-M3-M9) + ValD*(M4-M6)) * Normalization Ratio.
Gy = (ValA*(M1+M3-M7-M9) + ValD*(M2-M8)))* Normalization Ratio.

Where M1 to M9 are the values of the pixels (in Real4 from 0 to 255). and ValA and ValD are the Sobel/Scharr values we use (or any other values we want. The sign is kept intact, btw). When we multiply this with the normalization ratio, the values of Gx and GY will already be normalized to -1 to 1 obeying the range of -255 to 255.


For the tests i made so far, there´s no need to clamp


The issue i was talking about was other test i´m currently doing. I´m checking to see how to apply the sobel values we´ve got on a normal picture to we enhance the edges and overall illumination of the image. I made a quick draw. the idea is it obey this rule:



When we are in a edge, we need to choose if we will increase the bright of the pixel or decrease it. Pixels too bright with a high Sobel G (64 in this case, representing 65 to 128 because we are already on a edge), we need to decrease a little bit. On the other hand, edge pixels too dark (from 0 to 127) needs to be brighten a little bit, also obeying the rule to the sobel G value (this time on a range of 0 to 64 meaning we need to increase the image pixel)

It basically compress a bit the pixel brightness. So, when you are on a edge, the goal is do something like this. (We are inside a edge, ok ? So, Sobel G range here is from 128 to 255):

Pixel image inside a edge, also varies from: 0.......255. So we need to find a way to recalculate their values taking onto account the fact we are on a edge (so, in Sobel G brighter values from 128 to 255)

Too dark..(need to increase a bit)                                     Too bright (need to decrease a bit)
----------------------------------------> New Edge Pixel Value <--------------------------------------------

Btw...I´m talking about this routine i´m rying to make to use sobel over a regular image, and not sobel itself.


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

Quote from: Siekmanski on August 04, 2020, 11:13:29 AM
Example of the HDTV luminosity conversion with the 4 pixel boundary.



Wow..Great !

But you applied sobel over it or only converted to GrayScale ? I see some black borders around 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

Siekmanski

No, only the luminosity conversion.
BTW both images are stretched to the same size
The gray version is in reality 8 by 8 pixels larger than the original image, because of the borders.

QuoteI see some black borders around it.

See Reply #141 , I have explained it there.
Creative coders use backward thinking techniques as a strategy.

guga

Ok :)


One thing...i´ll give a try on this equation


https://www.wolframalpha.com/input/?i=1%2F%28sqrt%2864%5E2%2B128%5E2%29%29+*+128+*+%28sqrt%28%28%28%28x-128%29%2B%28y-128%29%29%2F2%29%5E2%2B%28%28y-128%29%2F2%29%5E2%29%29+%2B128

1/(sqrt(64^2+128^2)) * 128 * (sqrt((((x-128)+(y-128))/2)^2+((y-128)/2)^2)) +128

where:

x = Sobel Value From 128 to 255
y = Pixel Value from 128 to 255

This seems to produce a somewhat compressed values. The graphic shows it produces some oval image, meaning that the edges of too bright pixels (above 127) maybe represented like this.

I´ll make a tests. If it works, i´ll give a try on other equation to work with darker pixels that also belongs to the edges.

If the results are ok...i´ll then try with non edge pixels
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

1st test

It found the high frequencies of Sobel applied only to the brighter pixels and balanced the luma pixels on them. It working in 4 different pieces when it is inside the edges. Edges too bright, it increases or decreases the pixel accord to the SObel Values and also will have to do the same when the pixels on the edges are too dark. I´ll test it to see if i can find a equations for that.

It do have a bit of noise (near the hair and borders) becausue the images was previously equalized. I did that too search for errors.



The edges were properly balanced on the higher frequencies on the cases where the values of the pixel is higher then 127.

I´ll now try to see if it also works for edges whose pixels are too dark.

Later i´ll try on the non-edge areas


Note: There´s a small error on mine CieLab function. Colored Pixels too close to gray (R G and B are not equal, but their distances are too close to each other) are turned onto a colored variation, because the chroma (a and b factors on CieLab)_ were readjusted. I´ll review this later. Probably i´ll use HSL just to see what it looks like without the tiny errors in cielab.
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

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

Siekmanski

 :biggrin:
Nice toad.

I don't calculate the complete colorspace because we only need the luma (Y') component.
They add up to 1.0 for the luma channel. ( I don't use the Chroma channels )

                                    ;   Blue    Green    Red ( Alpha,  unused = 0.0 )
Luma_PAL_SECAM_NTSC             real4  0.1140, 0.5870, 0.2990, 0.0  ; rec601 luma (Y') component
Luma_HDTV                       real4  0.0722, 0.7152, 0.2126, 0.0  ; ITU-R BT.709 standard luma (Y') component
Luma_HDR                        real4  0.0593, 0.6780, 0.2627, 0.0  ; ITU-R BT.2100 standard luma (Y') component


Think the Luma_HDTV coefficients are the best choice.....
Creative coders use backward thinking techniques as a strategy.