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