Skip to content

Commit

Permalink
Rework thresholding
Browse files Browse the repository at this point in the history
  • Loading branch information
ollydev committed May 21, 2024
1 parent ce91dfd commit 1b87ba6
Show file tree
Hide file tree
Showing 9 changed files with 430 additions and 365 deletions.
6 changes: 4 additions & 2 deletions DocGen/docgen.simba
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,18 @@ var
I: Integer;
Lines: TStringArray;
begin
Lines := Str.Split(LINE_SEP);
Lines := Str.SplitLines;
while (I < Length(Lines)) do
begin
if Lines[I].StartsWith('> ') then
begin
Lines[I].Delete(1,2);
Lines[I].Delete(1, 2);
Lines.Insert('```', I);
Lines.Insert('```', I+2);

Inc(I, 2);
end;

Inc(I);
end;

Expand Down
2 changes: 1 addition & 1 deletion Source/ide/simba.form_output.pas
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ function TSimbaOutputBox.Add(const S: String): String;
Line: String;
Flags: EDebugLnFlags;
begin
Arr := S.Split(LineEnding);
Arr := S.Split(LineEnding, False);
if (Length(Arr) = 0) then
Result := ''
else
Expand Down
50 changes: 30 additions & 20 deletions Source/script/imports/simba.import_image.pas
Original file line number Diff line number Diff line change
Expand Up @@ -1091,28 +1091,31 @@ procedure _LapeImage_Convolute(const Params: PParamArray; const Result: Pointer)
end;

(*
TImage.ThresholdAdaptive
------------------------
> function TImage.ThresholdAdaptive(Inv: Boolean; Method: EImageThreshMethod; k: Integer): TImage;
TImage.Threshold
----------------
> function TImage.Threshold(Inv: Boolean): TImage;
Otsu threshold algorithm.
*)
procedure _LapeImage_ThresholdAdaptive(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
procedure _LapeImage_Threshold(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PSimbaImage(Result)^ := PSimbaImage(Params^[0])^.ThresholdAdaptive(PBoolean(Params^[0])^, EImageThreshMethod(Params^[1]^), PInteger(Params^[2])^);
PSimbaImage(Result)^ := PSimbaImage(Params^[0])^.Threshold(PBoolean(Params^[1])^);
end;

(*
TImage.ThresholdSauvola
-----------------------
> function TImage.ThresholdSauvola(Radius: Integer; Invert: Boolean; R: Single = 128; K: Single = 0.5): TImage;
TImage.ThresholdAdaptive
------------------------
> function TImage.ThresholdAdaptive(Inv: Boolean; Radius: Integer = 25; C: Double = 0.1): TImage;
Radius = Window size
Invert = Invert output
R = dynamic range of standard deviation (default = 128)
K = constant value in range 0.2..0.5 (default = 0.5)
Sauvola binarization algorithm.
Invert = Invert output
Radius = Window size (default = 25)
K = Constant value (default = 0.1). Typical values are between 0.1 and 0.5.
*)
procedure _LapeImage_ThresholdSauvola(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
procedure _LapeImage_ThresholdAdaptive(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PSimbaImage(Result)^ := PSimbaImage(Params^[0])^.ThresholdSauvola(PInteger(Params^[1])^, PBoolean(Params^[2])^, PSingle(Params^[3])^, PSingle(Params^[4])^);
PSimbaImage(Result)^ := PSimbaImage(Params^[0])^.ThresholdAdaptive(PBoolean(Params^[1])^, PInteger(Params^[2])^, PDouble(Params^[3])^);
end;

(*
Expand Down Expand Up @@ -1140,11 +1143,19 @@ procedure _LapeImage_Blend2(const Params: PParamArray; const Result: Pointer); L
(*
TImage.Blur
-----------
> function TImage.Blur(Algo: EImageBlurAlgo; Radius: Single): TSimbaImage;
> function TImage.Blur(Algo: EImageBlurAlgo; Radius: Integer): TSimbaImage;
Algo can be either EImageBlurAlgo.BOX, EImageBlurAlgo.GAUSS.
```{note}
EImageBlurAlgo.GAUSS is not true gaussian blur it's an approximation (in linear time).
<https://blog.ivank.net/fastest-gaussian-blur.html>
```
*)
procedure _LapeImage_Blur(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PSimbaImage(Result)^ := PSimbaImage(Params^[0])^.Blur(EImageBlurAlgo(Params^[1]^), PSingle(Params^[2])^);
PSimbaImage(Result)^ := PSimbaImage(Params^[0])^.Blur(EImageBlurAlgo(Params^[1]^), PInteger(Params^[2])^);
end;

(*
Expand Down Expand Up @@ -1504,7 +1515,6 @@ procedure ImportSimbaImage(Compiler: TSimbaScript_Compiler);

addGlobalType('array of TImage', 'TImageArray');
addGlobalType('enum(WIDTH, HEIGHT, LINE)', 'EImageMirrorStyle');
addGlobalType('enum(MEAN, MIN_MAX)', 'EImageThreshMethod');
addGlobalType('enum(NEAREST_NEIGHBOUR, BILINEAR)', 'EImageResizeAlgo');
addGlobalType('enum(NEAREST_NEIGHBOUR, BILINEAR)', 'EImageRotateAlgo');
addGlobalType('enum(BOX, GAUSS)', 'EImageBlurAlgo');
Expand Down Expand Up @@ -1626,11 +1636,11 @@ procedure ImportSimbaImage(Compiler: TSimbaScript_Compiler);
addGlobalFunc('function TImage.Invert: TImage', @_LapeImage_Invert);
addGlobalFunc('function TImage.Posterize(Value: Integer): TImage', @_LapeImage_Posterize);
addGlobalFunc('function TImage.Convolute(Matrix: TDoubleMatrix): TImage', @_LapeImage_Convolute);
addGlobalFunc('function TImage.ThresholdAdaptive(Inv: Boolean; Method: EImageThreshMethod; k: Integer): TImage', @_LapeImage_ThresholdAdaptive);
addGlobalFunc('function TImage.ThresholdSauvola(Radius: Integer; Invert: Boolean = False; R: Single = 128; K: Single = 0.5): TImage', @_LapeImage_ThresholdSauvola);
addGlobalFunc('function TImage.Threshold(Inv: Boolean): TImage', @_LapeImage_Threshold);
addGlobalFunc('function TImage.ThresholdAdaptive(Inv: Boolean; Radius: Integer = 25; C: Double = 0.1): TImage', @_LapeImage_ThresholdAdaptive);
addGlobalFunc('function TImage.Blend(Points: TPointArray; Radius: Integer): TImage; overload', @_LapeImage_Blend1);
addGlobalFunc('function TImage.Blend(Points: TPointArray; Radius: Integer; IgnorePoints: TPointArray): TImage; overload', @_LapeImage_Blend2);
addGlobalFunc('function TImage.Blur(Algo: EImageBlurAlgo; Radius: Single): TImage;', @_LapeImage_Blur);
addGlobalFunc('function TImage.Blur(Algo: EImageBlurAlgo; Radius: Integer): TImage;', @_LapeImage_Blur);

addGlobalFunc('function TImage.ToMatrix: TIntegerMatrix; overload', @_LapeImage_ToMatrix1);
addGlobalFunc('function TImage.ToMatrix(Box: TBox): TIntegerMatrix; overload', @_LapeImage_ToMatrix2);
Expand Down
6 changes: 3 additions & 3 deletions Source/script/imports/simba.import_string.pas
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ procedure _LapeString_Join(const Params: PParamArray; const Result: Pointer); LA
(*
String.Split
------------
> function String.Split(Seperator: String): TStringArray;
> function String.Split(Seperator: String; ExcludeEmpty: Boolean = True): TStringArray;
*)
procedure _LapeString_Split(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PStringArray(Result)^ := PString(Params^[0])^.Split(PString(Params^[1])^);
PStringArray(Result)^ := PString(Params^[0])^.Split(PString(Params^[1])^, PBoolean(Params^[2])^);
end;

(*
Expand Down Expand Up @@ -1019,7 +1019,7 @@ procedure ImportString(Compiler: TSimbaScript_Compiler);
addGlobalFunc('function String.CountAll(Values: TStringArray): TIntegerArray;', @_LapeString_CountAll);

addGlobalFunc('function String.Join(Values: TStringArray): String;', @_LapeString_Join);
addGlobalFunc('function String.Split(Seperator: String): TStringArray;', @_LapeString_Split);
addGlobalFunc('function String.Split(Seperator: String; ExcludeEmpty: Boolean = True): TStringArray;', @_LapeString_Split);
addGlobalFunc('function String.SplitLines: TStringArray;', @_LapeString_SplitLines);

addGlobalFunc('function String.CopyRange(StartIndex, EndIndex: Integer): String;', @_LapeString_CopyRange);
Expand Down
64 changes: 53 additions & 11 deletions Source/simba.image.pas
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ TSimbaImage = class(TSimbaBaseClass)

procedure SplitChannels(var B,G,R,A: TByteArray); overload;
procedure SplitChannels(var B,G,R: TByteArray); overload;
procedure FromChannels(const B,G,R: TByteArray; W, H: Integer);

procedure ReplaceColor(OldColor, NewColor: TColor); overload;
procedure ReplaceColor(OldColor, NewColor: TColor; Tolerance: Single); overload;
Expand Down Expand Up @@ -219,16 +220,17 @@ TSimbaImage = class(TSimbaBaseClass)
function Brightness(Value: Integer): TSimbaImage;
function Invert: TSimbaImage;
function Posterize(Value: Integer): TSimbaImage;
function ThresholdAdaptive(Inv: Boolean; Method: EImageThreshMethod; K: Integer): TSimbaImage;
function ThresholdSauvola(Radius: Integer; Inv: Boolean = False; R: Single = 128; K: Single = 0.5): TSimbaImage;
function Threshold(Inv: Boolean): TSimbaImage;
function ThresholdAdaptive(Inv: Boolean; Radius: Integer; C: Double): TSimbaImage;
function Blend(Points: TPointArray; Radius: Integer): TSimbaImage; overload;
function Blend(Points: TPointArray; Radius: Integer; IgnorePoints: TPointArray): TSimbaImage; overload;
function Blur(Algo: EImageBlurAlgo; Radius: Single): TSimbaImage;
function Blur(Algo: EImageBlurAlgo; Radius: Integer): TSimbaImage;

// Matrix
procedure LoadFromMatrix(Matrix: TIntegerMatrix); overload;
procedure LoadFromMatrix(Matrix: TSingleMatrix; ColorMapType: Integer = 0); overload;

function ToGreyArray: TByteArray;
function ToGreyMatrix: TByteMatrix;
function ToMatrix: TIntegerMatrix; overload;
function ToMatrix(Box: TBox): TIntegerMatrix; overload;
Expand Down Expand Up @@ -347,6 +349,16 @@ function TSimbaImage.ToLazBitmap: TBitmap;
Result := SimbaImage_ToLazImage(Self);
end;

function TSimbaImage.ToGreyArray: TByteArray;
var
I: Integer;
begin
SetLength(Result, FWidth * FHeight);
for I := 0 to High(Result) do
with FData[I] do
Result[I] := Round(R * 0.299 + G * 0.587 + B * 0.114);
end;

function TSimbaImage.ToGreyMatrix: TByteMatrix;
var
X, Y: Integer;
Expand Down Expand Up @@ -1431,6 +1443,36 @@ procedure TSimbaImage.SplitChannels(var B,G,R: TByteArray);
end;
end;

procedure TSimbaImage.FromChannels(const B,G,R: TByteArray; W, H: Integer);
var
Dst: PColorBGRA;
SrcB, SrcG, SrcR: PByte;
Upper: PtrUInt;
begin
SetSize(W, H);
if (Length(B) <> W*H) or (Length(G) <> W*H) or (Length(R) <> W*H) then
SimbaException('Channel size does not match image size');

Dst := FData;
SrcB := @B[0];
SrcG := @G[0];
SrcR := @R[0];

Upper := PtrUInt(FData) + FDataSize;
while (PtrUInt(Dst) < Upper) do
begin
Dst^.A := ALPHA_OPAQUE;
Dst^.B := SrcB^;
Dst^.G := SrcG^;
Dst^.R := SrcR^;

Inc(Dst);
Inc(SrcB);
Inc(SrcG);
Inc(SrcR);
end;
end;

procedure TSimbaImage.DrawImage(Image: TSimbaImage; Location: TPoint);
begin
if (FDrawAlpha = ALPHA_OPAQUE) then
Expand Down Expand Up @@ -1529,6 +1571,11 @@ function TSimbaImage.Posterize(Value: Integer): TSimbaImage;
Result := SimbaImage_Posterize(Self, Value);
end;

function TSimbaImage.Threshold(Inv: Boolean): TSimbaImage;
begin
Result := SimbaImage_Threshold(Self, Inv);
end;

function TSimbaImage.Convolute(Matrix: TDoubleMatrix): TSimbaImage;
var
X, Y, YY, XX, CX, CY: Integer;
Expand Down Expand Up @@ -1850,7 +1897,7 @@ function TSimbaImage.Rotate(Algo: EImageRotateAlgo; Radians: Single; Expand: Boo
end;
end;

function TSimbaImage.Blur(Algo: EImageBlurAlgo; Radius: Single): TSimbaImage;
function TSimbaImage.Blur(Algo: EImageBlurAlgo; Radius: Integer): TSimbaImage;
begin
case Algo of
EImageBlurAlgo.BOX: Result := SimbaImage_BlurBox(Self, Radius);
Expand Down Expand Up @@ -1910,14 +1957,9 @@ procedure TSimbaImage.SetPixels(Points: TPointArray; Colors: TColorArray);
end;
end;

function TSimbaImage.ThresholdAdaptive(Inv: Boolean; Method: EImageThreshMethod; K: Integer): TSimbaImage;
begin
Result := SimbaImage_ThresholdAdaptive(Self, Inv, Method, K);
end;

function TSimbaImage.ThresholdSauvola(Radius: Integer; Inv: Boolean; R: Single; K: Single): TSimbaImage;
function TSimbaImage.ThresholdAdaptive(Inv: Boolean; Radius: Integer; C: Double): TSimbaImage;
begin
Result := SimbaImage_ThresholdSauvola(Self, Radius, Inv, R, K);
Result := SimbaImage_ThresholdAdaptive(Self, Inv, Radius, C);
end;

procedure TSimbaImage.DrawData(TheData: PColorBGRA; DataW, DataH: Integer; P: TPoint);
Expand Down
Loading

0 comments on commit 1b87ba6

Please sign in to comment.