The MASM Forum

Projects => Rarely Used Projects => RosAsm => Topic started by: guga on July 30, 2020, 04:42:38 AM

Title: Sobel Function
Post by: guga on July 30, 2020, 04:42:38 AM
new Sobel Function


; Equates used  as flags to the type of fix we want onto the sobel operator.
[SOBEL_FIX_TRUNCATE 0] ; Normal result. Only truncated all above the limits of -255 and 255
[SOBEL_FIX_SIMPLE 1] ; common adjust of the edges. Much better.

; Equates used on the matrix
[FloatMatricesInt.M1Dis 0
FloatMatricesInt.M2Dis 4
FloatMatricesInt.M3Dis 8
FloatMatricesInt.M4Dis 12
FloatMatricesInt.M5Dis 16
FloatMatricesInt.M6Dis 20
FloatMatricesInt.M7Dis 24
FloatMatricesInt.M8Dis 28
FloatMatricesInt.M9Dis 32]

[Size_Of_FloatMatricesInt 36]

[Float_SobleVarG: R$ 180.3122292025696187222153123367365]; 255/sqrt(2)) . This is a variable used to speed up the math when computing the G

;;

    SobelGetGPLusEx
        Calculates the Sobel operator for a given amount of pixels stored opn a 3x3 matrix
   
    Parameters:

        pMatrix(In):    The Inputed pixels stored on a 3x3 matrix where the Sobel edges are calculated. The input values must be in Real4 format from 0 to 255. (No integer yet. I´ll adapt to handle integers later)
                        To make easier understand, the matrix is written using equates and the values must be previously calculated and filled.
                        The format of the matrix is:
                       
                        M1 M2 M3
                        M4 M5 M6
                        M7 M8 M9
                       
                        So, at Point M1, Pixel at pos X0, Y0
                               Point M2, Pixel at pos X1, Y0
                               Point M3, Pixel at pos X2, Y0
                               Point M4, Pixel at pos X0, Y1
                               Point M5, Pixel at pos X1, Y1
                               Point M6, Pixel at pos X2, Y1
                               Point M7, Pixel at pos X0, Y2
                               Point M8, Pixel at pos X1, Y2
                               Point M9, Pixel at pos X2, Y2

        pOutSobelX(out): Pointer to a variable that will Store the SobelX value (Magnitude in X direction. I.e.: Gx).
                         The stored value can be negative, positive or zero. All in Real4 format from -1 to 1

        pOutSobelY(out): Pointer to a variable that will Store the SobelY value (Magnitude in Y direction. I.e.: Gy).
                        The stored value can be negative, positive or zero. All in Real4 format from -1 to 1

        pOutSobel(Out): Pointer to a variable that will Store the Sobel value (Total Magnitude of the pixel. I.e.: G).
                        The output is a positive Integer value from 0 to 255. The magnitude of Sobel operator is given by:
                            G = sqrt(Gx^2+Gy^2)

        FixType(In):    A flag able to fix the Sobel operator when it exceeds the limits of -1 to 1 (Normalized)
                        It´s common to the Sobel Operator extrapolates the resultant limits (-255 to 255. Or -1 to 1, normalized)
                        We can see values (unormalized) in the order of -600, 482, 265, -258, -780 etc etc
                       
                        Currently, in order to fix that 2 Flags can be used:
                       
                        SOBEL_FIX_TRUNCATE (Value = 0). Simply truncates the values of Gx and Gy to -1 (if the result is too dark) or 1 (If the result is too bright)
                        SOBEL_FIX_SIMPLE  (Value = 1). Fix the values adjusting the extrapolation to it stays within the limits.
                                                       The math envolving is this fix is: FixedValue = OldValue/(255*(floor(|OldValue|/255)+1))
                       
        pDegree(Out/Optional): A Pointer to a variable to store the Angle formed by the pixel. Sobel Operator can be used to calculate the angle (direction) of the Pixel.
                               It outputs the angle in Degrees. The format of the output is always in real4 format from 0º to 360º.
                               This parameter can be &NULL if you don´t want to exprt the angle.

        Return Values:
                    The function does not return any value.

    Example of usage:

    [MyMatrix: F$ 25, 200, 30
                  100, 45, 75
                  0, 81, 255]

        call SobelGetGPlusEx MyMatrix, MySobelX, MySobelY, MySobel, SOBEL_FIX_SIMPLE, &NULL
   
;;

Proc SobelGetGPLusEx:
    Arguments @pMatrix, @pOutSobelX, @pOutSobelY, @pOutSobel, @FixType, @pDegree
    Local @pReturn, @DataCheck, @Divisor, @FractionX, @FractionY, @Floor, @YAxis, @XAxis
    Structure @TempAxis 16, @SobelYAxisDis 0, @SobelXAxisDis 8
    Uses edi, edx, ecx, eax

    finit

    mov edi D@pMatrix

    ; To calculate Gx^2 later. Therefore Gx = M3+M9 + 2*(M6-M4) - (M7+M1)
    fld F$edi+FloatMatricesInt.M6Dis | fsub F$edi+FloatMatricesInt.M4Dis | fmul R$Float_Two
    fadd F$edi+FloatMatricesInt.M3Dis | fadd F$edi+FloatMatricesInt.M9Dis
    fsub F$edi+FloatMatricesInt.M7Dis | fsub F$edi+FloatMatricesInt.M1Dis
    lea ecx D@DataCheck | fistp F$ecx
    .If D@DataCheck = 0

        fldz | fstp F@FractionX

    .Else_If D@DataCheck <s 0-255 ; Blacks. Edge too dark.

        If D@FixType = SOBEL_FIX_TRUNCATE ;  Truncate the value to -1. The default Sobel behaviour (It truncates to -255 or 255. But, since we are using normalized version we set the limits to -1 and 1)
            fld R$Float_MinusOne | fstp F@FractionX
        Else ; SOBEL_FIX_SIMPLE. FixedValue = OldValue/(255*(floor(|OldValue|/255)+1))
            xor edx edx | mov ecx 255 | mov eax D@DataCheck | neg eax | div ecx | inc eax | imul eax 255 | mov D@Divisor eax
            fild D@DataCheck | fidiv F@Divisor |  fstp F@FractionX
        End_If

    .Else_If D@DataCheck >s 255 ; Whites. Edge too brigth.

        If D@FixType = SOBEL_FIX_TRUNCATE ;  Truncate the value to -1. The default Sobel behaviour (It truncates to -255 or 255. But, since we are using normalized version we set the limits to -1 and 1)
            fld1 | fstp F@FractionX
        Else ;  SOBEL_FIX_SIMPLE. FixedValue = OldValue/(255*(floor(OldValue/255)+1))
            xor edx edx | mov ecx 255 | mov eax D@DataCheck | div ecx | inc eax | imul eax 255 | mov D@Divisor eax
            fild D@DataCheck | fidiv F@Divisor |  fstp F@FractionX
        End_If

    .Else
        fild D@DataCheck | fmul R$Float_One_255 | fstp F@FractionX
    .End_If
    mov eax D@pOutSobelX | mov ecx D@FractionX | mov D$eax ecx

    ; To calculate Gy^2 later. Therefore Gy = M7+M9 + 2*(M8-M2) - (M3+M1)
    fld F$edi+FloatMatricesInt.M8Dis | fsub F$edi+FloatMatricesInt.M2Dis | fmul R$Float_Two
    fadd F$edi+FloatMatricesInt.M7Dis | fadd F$edi+FloatMatricesInt.M9Dis
    fsub F$edi+FloatMatricesInt.M3Dis | fsub F$edi+FloatMatricesInt.M1Dis
    lea ecx D@DataCheck | fistp F$ecx
    .If D@DataCheck = 0
        fldz | fstp F@FractionY
    .Else_If D@DataCheck <s 0-255 ; Blacks. Edge too dark. FixedValue = OldValue/(255*(floor(|OldValue|/255)+1))
        If D@FixType = SOBEL_FIX_TRUNCATE ;  Truncate the value to -1. The default Sobel behaviour (It truncates to -255 or 255. But, since we are using normalized version we set the limits to -1 and 1)
            fld R$Float_MinusOne | fstp F@FractionY
        Else ; SOBEL_FIX_SIMPLE ;  FixedValue = OldValue/(255*(floor(|OldValue|/255)+1))
            xor edx edx | mov ecx 255 | mov eax D@DataCheck | neg eax | div ecx | inc eax | imul eax 255 | mov D@Divisor eax
            fild D@DataCheck | fidiv F@Divisor |  fstp F@FractionY
        End_If
    .Else_If D@DataCheck >s 255 ; Whites. Edge too brigth. FixedValue = OldValue/(255*(floor(OldValue/255)+1))
        If D@FixType = SOBEL_FIX_TRUNCATE ;  Truncate the value to -1. The default Sobel behaviour (It truncates to -255 or 255. But, since we are using normalized version we set the limits to -1 and 1)
            fld1 | fstp F@FractionY
        Else ; SOBEL_FIX_SIMPLE;  FixedValue = OldValue/(255*(floor(OldValue/255)+1))
            xor edx edx | mov ecx 255 | mov eax D@DataCheck | div ecx | inc eax | imul eax 255 | mov D@Divisor eax
            fild D@DataCheck | fidiv F@Divisor |  fstp F@FractionY
        End_If
    .Else
        fild D@DataCheck | fmul R$Float_One_255 | fstp F@FractionY
    .End_If
    mov eax D@pOutSobelY | mov ecx D@FractionY | mov D$eax ecx

    ; Output the Angle (in degrees) if needed
    If D@pDegree <> 0
        lea eax D@SobelYAxisDis | fld F@FractionY | fstp R$eax
        lea edx D@SobelXAxisDis | fld F@FractionX | fstp R$edx
        call atan2 eax, edx, &True
        mov eax D@pDegree | fstp F$eax
    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@FractionX | fmul ST0 ST0 | fld F@FractionY | fmul ST0 ST0 | faddp ST1 ST0 | fsqrt | fmul R$Float_SobleVarG
    lea edx D@pReturn
    fistp F$edx
    mov eax D@pReturn
    If eax > 255
        mov eax 255
    End_If
    mov ecx D@pOutSobel | mov D$ecx eax

EndP



Atan function used:


[Float_AtanPiFactor: R$ (180/3.1415926535897932384626433832795)]
[Float360: R$ 360]

; Macros used to simulate If/Else/EndIf using Fpu
[Fpu_If | fld #3 | fld #1 | fcompp | fstsw ax | fwait | sahf | jn#2 R0>>]
[Fpu_Else_If | jmp R5>> | R0: | fld #3 | fld #1 | fcompp | fstsw ax | fwait | sahf | jn#2 R0>>]
[Fpu_Else | jmp R5>> | R0:]
[Fpu_End_If | R0: | R5:]


Proc atan2:
    Arguments @pY, @pX, @ConvDegree
    Structure @TempStorage 16, @HueDis 0
    Uses eax, ebx, ecx

    mov ebx D@pY
    mov ecx D@pX

    fld R$ebx
    fld R$ecx
    fpatan
    fstsw ax
    wait
    shr ax 1
    jnb L2>
        fclex | stc | xor eax eax | ExitP
L2:

    .If D@ConvDegree = &TRUE
        fmul R$Float_AtanPiFactor | fst R@HueDis
        Fpu_If R@HueDis < R$FloatZero
            fadd R$Float360
        Fpu_Else_If R@HueDis >= R$Float360
            fsub R$Float360
        Fpu_End_If
    .End_If

    clc
    mov eax &TRUE

EndP