How to optimize this code?
Re: How to optimize this code?
So you mean I shouldn't call LimitMin and LimitMax within the loops? This should be doable.
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: How to optimize this code?
If they don't change per loop yes pull em out of the loop.
I did a test with the sepia routine my method was 3.5 times faster.
I did a test with the sepia routine my method was 3.5 times faster.
Re: How to optimize this code?
But they change for the border pixels. Otherwise I had to make separate loops for the border pixels.
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: How to optimize this code?
replace them with macros in that case.
Re: How to optimize this code?
Sorry, but how do I put this into a macro (we still don't have an If() function)? I can't think of a one line solution.
Best I can imagine is calculating it beforehand and then doing the for loops with variables (which contain the results).
Best I can imagine is calculating it beforehand and then doing the for loops with variables (which contain the results).
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: How to optimize this code?
Maybe something like this would work:jacdelad wrote: Wed Jul 26, 2023 11:10 pm Sorry, but how do I put this into a macro (we still don't have an If() function)? I can't think of a one line solution.
Best I can imagine is calculating it beforehand and then doing the for loops with variables (which contain the results).
Code: Select all
Case #Bin_Binarization_BlockMode
For x=0 To w-1
For y=0 To h-1
Pixel=Point(x,y)
Values(x,y)=((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Next
Next
BlockSize=Int(*Binarization\BlockSize/2)
;precalculate x clamp values
Dim xc(w - 1, 1)
For x = 0 To w - 1
xc(x, 0) = _LimitMin(x - BlockSize, 0)
xc(x, 1) = _LimitMax(x + BlockSize, w - 1)
Next
;precalculate y clamp values
Dim yc(h - 1, 1)
For y =0 To h - 1
yc(y, 0) = _LimitMin(y - BlockSize, 0)
yc(y, 1) = _LimitMax(y + BlockSize, h - 1)
Next
For x=0 To w-1
For y=0 To h-1
Count=0
Counter=-1
For xa= xc(x, 0) To xc(x, 1)
For ya= yc(y, 0) To yc(y, 1)
Counter+1
Count+Values(xa,ya)
Next
Next
If Values(x,y)*Counter>Count-Values(x,y)
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Re: How to optimize this code?
That's a good idea, thanks! I'll try this and make some benchmarks.
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: How to optimize this code?
Ok, so I optimized it as suggested from Demivec and idle. Also I added the Phansalkar algorithm, which offers a variety of parameters (that I don't fully understand).
Code: Select all
;Binarization algorithms (used parameters are written with CAPITAL LETTERS):
;- Relative:
;Converts the range of 8bit greyscale into a percentage scale. The given THRESHOLD defines which pixels are white (<threshold) or black (<=threshold).
;- Absolute:
;Same as relative, but THRESHOLD uses the whole 8bit range (0..255)
;- Range:
;Same as relative, but first finds the darkest and lightest pixel and narrows the range down. THRESHOLD is percentage within this found range.
;- Count:
;Creates a histogram and uses THRESHOLD as percentage (0..100) of how many pixels are drawn black.
;- Rasterize:
;Same as Absolute, but the picture is rasterized. This algorithm has no scientific foundation and I discovered it "accidently".
;It will be adapted IN the future, because For now it doesn't work as intended! More like a fun-mode.
;- BlockMode:
;Determines the threshold by adapting to the neighbourhood pixels. The BLOCKSIZE (3..255) defines the size of the block, e.g. a blocksize of 5 uses a 5x5 block.
;- OTSU:
;This algorithm doesn't need any parameters, because it defines the threshold by itself.
;It creates a histogram, finds the two highest peaks And SETS the threshold To the exact middle between them.
;- Niblack:
;Local intensity averagd and standard deviation. The BLOCKSIZE (3.255) defines the size of each block
;While a CONSTANT (Default=-0.2) defines the weight of the deviation. This algorithm tends To produce noisy results.
;- Sauvola:
;Improvement of the Niblack algorithm (less noisy). The BLOCKSIZE (3..255) defines the size of each block, CONSTANT is a measure for
;weighing the deviation (0.2..0.5, default=0.5) and DYNAMICRANGE defines the variance of the deviation (1..255, default=128).
;- Bernsen:
;Calculates a dynamic threshold based on the minimum and maximum intensities based on the neighbourhood pixels. The BLOCKSIZE (3..255) defines
;the size of each block while BACKGROUND defines whether the background is light or dark.
;Additionally And DYNAMICRANGE defines the local contrast limit (default=15).
;- Phansalkar:
;This algorithm is rather complex. It can behave like Sauvola, but is designed to deliver better results. To be honest I don't really understand all the parameters
;and it's advised to either experiment or leave them to their default values. BLOCKSIZE again defines the blocksize (3..255) of pixels to be looked around the current
;pixel. The MAGNITUDE effects the threshold (values between 0 and 1 behave like Sauvola, values higher than 5 may classify too many foreground pixels as
;background pixels, default is 3). PHANSALKARCONSTANT does...whatever, default is 10. The DYNAMICRANGE (0..255) is for the standard deviation
;(Default is 127) And CONSTANT is a parameter between 0.2 and 0.5 (default is 0.25).
;
;When using #Bin_Greyscale_Custom you can use fR, fG and fB to define the weight of each channel, otherwise use a predefined scheme.
EnableExplicit
Enumeration Binarization ;THRESHOLD:
#Bin_Binarization_Relative ;0..100: Range, percentage
#Bin_Binarization_Absolute ;0..255: Range, 8bit value
#Bin_Binarization_Range ;0..100: Range percentage, only within range of used colors
#Bin_Binarization_Count ;0..100: Percent of pixels that are black
#Bin_Binarization_Rasterize ;0..255: Range, 8bit value, rasterize image
#Bin_Binarization_BlockMode ; Adapts to neighbour pixels, blocksize (always odd numbers, not lower than 3!) to control the block size; speed decreases drastically with bigger block sizes!
#Bin_Binarization_OTSU ; Self adapting, doesn't need threshold
#Bin_Binarization_Sauvola ; Mean/deviation calculation, very cpu consuming, higher value=darker result
#Bin_Binarization_Bernsen ; Predecessor of Sauvola
#Bin_Binarization_Niblack ; Adapts to neighbour pixels, but noisier than Sauvola, blocksize (always odd numbers, not lower than 3!) to control the block size; speed decreases drastically with bigger block sizes!
#Bin_Binarization_Phansalkar; Successor of Sauvola
EndEnumeration
Enumeration Greyscale
#Bin_Greyscale_BT709
#Bin_Greyscale_Equal
#Bin_Greyscale_REC601
#Bin_Greyscale_BT2100
#Bin_Greyscale_RedChannel
#Bin_Greyscale_GreenChannel
#Bin_Greyscale_BlueChannel
#Bin_Greyscale_Custom
EndEnumeration
#Bin_Background_Dark = 255
#Bin_Background_Light = 0
Enumeration Sepia
#Bin_Sepia_Simple
EndEnumeration
Structure Binarization
Algorithm.a
PreProcessing.a
fR.f
fG.f
fB.f
Threshold.a
BlockSize.a
Background.a
Constant.f
DynamicRange.a
Magnitude.f
PhansalkarConstant.a
EndStructure
Structure sRGB
sr.f
sg.f
sb.f
sa.f
EndStructure
Structure mRGB
StructureUnion
col.l
b.a
g.a
r.a
a.a
EndStructureUnion
EndStructure
Procedure CopyMemoryToImage(Memory, ImageNumber)
Protected TemporaryDC, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
TemporaryBitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
TemporaryBitmapInfo\bmiHeader\biWidth = TemporaryBitmap\bmWidth
TemporaryBitmapInfo\bmiHeader\biHeight = -TemporaryBitmap\bmHeight
TemporaryBitmapInfo\bmiHeader\biPlanes = 1
TemporaryBitmapInfo\bmiHeader\biBitCount = 32
TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
SetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
DeleteDC_(TemporaryDC)
EndProcedure
Procedure CopyImageToMemory(ImageNumber, Memory)
Protected TemporaryDC, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
TemporaryBitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
TemporaryBitmapInfo\bmiHeader\biWidth = TemporaryBitmap\bmWidth
TemporaryBitmapInfo\bmiHeader\biHeight = -TemporaryBitmap\bmHeight
TemporaryBitmapInfo\bmiHeader\biPlanes = 1
TemporaryBitmapInfo\bmiHeader\biBitCount = 32
TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
GetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
DeleteDC_(TemporaryDC)
EndProcedure
Procedure Greyscale(Image.i,Algorithm.a=#Bin_Greyscale_BT709,fR.f=0,fG.f=0,fB.f=0)
Protected Result.i=-1,x.l,y.l,r.a,g.b,b.a,w.l,h.l,Pixel.l,Res.l
Protected srgb.sRGB,*mem.mRGB,*out, size,ct,col.f,ImageOut
If IsImage(Image)
ImageOut = CopyImage(0,-1)
size = (ImageWidth(image)*ImageHeight(image)) << 2
*mem = AllocateMemory(size)
*out = *mem
srgb\sa = 1.0
Select Algorithm
Case #Bin_Greyscale_BT709
srgb\sr = 0.2126 : srgb\sg = 0.7152 : srgb\sb = 0.0722
Case #Bin_Greyscale_Equal
srgb\sr = 1.0 : srgb\sg = 1.0 : srgb\sb = 1.0 : srgb\sa = 1.0 / 3.0
Case #Bin_Greyscale_REC601
srgb\sr = 0.299 : srgb\sg = 0.587 : srgb\sb = 0.114
Case #Bin_Greyscale_BT2100
srgb\sr = 0.2627 : srgb\sg = 0.678 : srgb\sb = 0.0593
Case #Bin_Greyscale_RedChannel
srgb\sr = 1.0 : srgb\sg = 0 : srgb\sb = 0
Case #Bin_Greyscale_GreenChannel
srgb\sr = 0 : srgb\sg = 1.0 : srgb\sb = 0
Case #Bin_Greyscale_BlueChannel
srgb\sr = 0 : srgb\sg = 0 : srgb\sb = 1.0
Case #Bin_Greyscale_Custom
srgb\sr = fr : srgb\sg = fg : srgb\sb = fb
EndSelect
CopyImageToMemory(Image,*mem)
While ct < size
col.f = ((*mem\r * srgb\sr) + (*mem\g * srgb\sg ) + (*mem\b * srgb\sb)) * srgb\sa
*mem\r = col
*mem\g = col
*mem\b = col
*mem+4
ct+4
Wend
CopyMemoryToImage(*out,Imageout)
FreeMemory(*out)
EndIf
ProcedureReturn imageout
EndProcedure
Procedure Sepia(Image.i,Algorithm.a=#Bin_Sepia_Simple)
Protected Result.i=-1,x.l,y.l,Pixel.l,R.a,G.a,B.a,wR.w,wG.w,wB.w,w.l=ImageWidth(Image)-1,h.l=ImageHeight(Image)-1
If IsImage(Image)
Result=CopyImage(Image,#PB_Any)
If Result<>0
StartDrawing(ImageOutput(Result))
Select Algorithm
Case #Bin_Sepia_Simple
For x=0 To w
For y=0 To h
Pixel=Point(x,y)
R=Red(Pixel)
G=Green(Pixel)
B=Blue(Pixel)
wR=0.393*R + 0.769*G + 0.189*B
If wR>255:wR=255:EndIf
wG=0.349*R + 0.686*G + 0.168*B
If wG>255:wG=255:EndIf
wB=0.272*R + 0.534*G + 0.131*B
If wB>255:wB=255:EndIf
Plot(x,y,RGB(wR,wG,wB))
Next
Next
EndSelect
StopDrawing()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure _LimitMin(a.l,b.l)
If a>b
ProcedureReturn a
Else
ProcedureReturn b
EndIf
EndProcedure
Procedure _LimitMax(a.l,b.l)
If a<b
ProcedureReturn a
Else
ProcedureReturn b
EndIf
EndProcedure
Procedure Binarize(Image.i,*Binarization.Binarization)
Protected Result.i=-1,x.l,y.l,Pixel.l,r.a,g.a,b.a,Res.a,Min.a=255,Max.a,mw.l=ImageWidth(Image)-1,mh.l=ImageHeight(Image)-1,Count.l,Counter.l
Protected srgb.srgb,xa.l,ya.l,Mean.a,Dev.q,Threshold.a=*Binarization\Threshold,BlockSize.a
Protected Dim LimitX(mw,1),Dim LimitY(mh,1),Dim Values.a(mw,mh),Dim Deviation.a(0),Dim Count.l(255)
Select *Binarization\Algorithm
Case #Bin_Binarization_BlockMode
Threshold=Threshold/2
Case #Bin_Binarization_Relative
Threshold=Threshold*2.55
EndSelect
If IsImage(Image)
Result=CopyImage(Image,#PB_Any)
If Result<>0
srgb\sa = 1.0
Select *Binarization\PreProcessing
Case #Bin_Greyscale_BT709
srgb\sr = 0.2126 : srgb\sg = 0.7152 : srgb\sb = 0.0722
Case #Bin_Greyscale_Equal
srgb\sr = 1.0 : srgb\sg = 1.0 : srgb\sb = 1.0 : sRGB\sa = 1.0 / 3.0
Case #Bin_Greyscale_REC601
srgb\sr = 0.299 : srgb\sg = 0.587 : srgb\sb = 0.114
Case #Bin_Greyscale_BT2100
srgb\sr = 0.2627 : srgb\sg = 0.678 : srgb\sb = 0.0593
Case #Bin_Greyscale_RedChannel
srgb\sr = 1.0 : srgb\sg = 0 : srgb\sb = 0
Case #Bin_Greyscale_GreenChannel
srgb\sr = 0 : srgb\sg = 1.0 : srgb\sb = 0
Case #Bin_Greyscale_BlueChannel
srgb\sr = 0 : srgb\sg = 0 : srgb\sb = 1.0
Case #Bin_Greyscale_Custom
srgb\sr = *Binarization\fR : srgb\sg = *Binarization\fG : srgb\sb = *Binarization\fB : srgb\sa=1/(*Binarization\fR+*Binarization\fG+*Binarization\fB)
EndSelect
StartDrawing(ImageOutput(Result))
Select *Binarization\Algorithm
Case #Bin_Binarization_Absolute,#Bin_Binarization_Relative
For x=0 To mw
For y=0 To mh
Pixel=Point(x,y)
If ((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa > Threshold
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Case #Bin_Binarization_Rasterize
For x=0 To mw
For y=0 To mh
Pixel=Point(x,y)
If ((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa > Threshold
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Threshold=Threshold*2.55
Next
Next
Case #Bin_Binarization_Range
For x=0 To mw
For y=0 To mh
Pixel=Point(x,y)
Res = ((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Values(x,y)=Res
If Res<Min:Min=Res:EndIf
If Res>Max:Max=Res:EndIf
Next
Next
Threshold=Min+Threshold*(Max-Min)/100
For x=0 To mw
For y=0 To mh
If Values(x,y)>Threshold
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Case #Bin_Binarization_Count
For x=0 To mw
For y=0 To mh
Pixel=Point(x,y)
Res = ((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Values(x,y)=Res
Count(Res)+1
Next
Next
Count=Threshold*(mw+1)*(mh+1)/100
Counter=0
For x=0 To 255
Counter+Count(x)
If Counter>Count
Threshold=x-1
Break
EndIf
Next
For x=0 To mw
For y=0 To mh
If Values(x,y)>Threshold
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Case #Bin_Binarization_OTSU
For x=0 To mw
For y=0 To mh
Pixel=Point(x,y)
Res = ((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Values(x,y)=Res
Count(Res)+1
Next
Next
Count=0
For x=0 To 255
If Count(x)>Count
Count=Count(x)
Max=x
EndIf
Next
Counter=0
For x=255 To 0 Step -1
If Count(x)>Counter And (Count(x)<Count Or x<>Max)
Counter=Count(x)
Min=x
EndIf
Next
Threshold=Max+(Min-Max)/2
For x=0 To mw
For y=0 To mh
If Values(x,y)>Threshold
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Case #Bin_Binarization_BlockMode
BlockSize=Int(*Binarization\BlockSize/2)
For x=0 To mw
LimitX(x,0)=_LimitMin(x-BlockSize,0)
LimitX(x,1)=_LimitMax(x+BlockSize,mw)
For y=0 To mh
Pixel=Point(x,y)
Values(x,y)=((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Next
Next
For y=0 To mh
LimitY(y,0)=_LimitMin(y-BlockSize,0)
LimitY(y,1)=_LimitMax(y+BlockSize,mh)
Next
For x=0 To mw
For y=0 To mh
Count=0
Counter=-1
For xa=LimitX(x,0) To LimitX(x,1)
For ya=LimitY(y,0) To LimitY(y,1)
Counter+1
Count+Values(xa,ya)
Next
Next
If Values(x,y)*Counter>Count-Values(x,y)
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Case #Bin_Binarization_Sauvola
ReDim Deviation(Int(Pow(*Binarization\BlockSize,2)-1))
BlockSize=Int(*Binarization\BlockSize/2)
For x=0 To mw
LimitX(x,0)=_LimitMin(x-BlockSize,0)
LimitX(x,1)=_LimitMax(x+BlockSize,mw)
For y=0 To mh
Pixel=Point(x,y)
Values(x,y)=((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Next
Next
For y=0 To mh
LimitY(y,0)=_LimitMin(y-BlockSize,0)
LimitY(y,1)=_LimitMax(y+BlockSize,mh)
Next
For x=0 To mw
For y=0 To mh
Count=0
Counter=0
For xa=LimitX(x,0) To LimitX(x,1)
For ya=LimitY(y,0) To LimitY(y,1)
Count+Values(xa,ya)
Deviation(counter)=Values(xa,ya)
Counter+1
Next
Next
Mean=Count/Counter
Dev=0
Counter-1
For xa=0 To Counter
Dev+Pow(Deviation(xa)-Mean,2)
Next
If Values(x,y)>Mean*(1+*Binarization\Constant*((Pow(Dev/Counter,0.5)/*Binarization\DynamicRange)-1))
Plot(x,y,#White)
Else
Plot(x,y,#Black)
EndIf
Next
Next
Case #Bin_Binarization_Bernsen
BlockSize=Int(*Binarization\BlockSize/2)
For x=0 To mw
LimitX(x,0)=_LimitMin(x-BlockSize,0)
LimitX(x,1)=_LimitMax(x+BlockSize,mw)
For y=0 To mh
Pixel=Point(x,y)
Values(x,y)=((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Next
Next
For y=0 To mh
LimitY(y,0)=_LimitMin(y-BlockSize,0)
LimitY(y,1)=_LimitMax(y+BlockSize,mh)
Next
For x=0 To mw
For y=0 To mh
Min=255
Max=0
For xa=LimitX(x,0) To LimitX(x,1)
For ya=LimitY(y,0) To LimitY(y,1)
If Values(xa,ya)<Min:Min=Values(xa,ya):EndIf
If Values(xa,ya)>Max:Max=Values(xa,ya):EndIf
Next
Next
If Max-Min<*Binarization\DynamicRange
Max=*Binarization\Background
Else
Max=(Min+Max)/2
EndIf
If Values(x,y)<Max
Plot(x,y,#Black)
Else
Plot(x,y,#White)
EndIf
Next
Next
Case #Bin_Binarization_Niblack
ReDim Deviation(Int(Pow(*Binarization\BlockSize,2)-1))
BlockSize=Int(*Binarization\BlockSize/2)
For x=0 To mw
LimitX(x,0)=_LimitMin(x-BlockSize,0)
LimitX(x,1)=_LimitMax(x+BlockSize,mw)
For y=0 To mh
Pixel=Point(x,y)
Values(x,y)=((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Next
Next
For y=0 To mh
LimitY(y,0)=_LimitMin(y-BlockSize,0)
LimitY(y,1)=_LimitMax(y+BlockSize,mh)
Next
For x=0 To mw
For y=0 To mh
Count=0
Counter=0
For xa=LimitX(x,0) To LimitX(x,1)
For ya=LimitY(y,0) To LimitY(y,1)
Count+Values(xa,ya)
Deviation(counter)=Values(xa,ya)
Counter+1
Next
Next
Mean=Count/Counter
Dev=0
Counter-1
For xa=0 To Counter
Dev+Pow(Deviation(xa)-Mean,2)
Next
If Values(x,y)<Mean+*Binarization\Constant*Pow(Dev/Counter,0.5)
Plot(x,y,#Black)
Else
Plot(x,y,#White)
EndIf
Next
Next
Case #Bin_Binarization_Phansalkar
ReDim Deviation(Int(Pow(*Binarization\BlockSize,2)-1))
BlockSize=Int(*Binarization\BlockSize/2)
For x=0 To mw
LimitX(x,0)=_LimitMin(x-BlockSize,0)
LimitX(x,1)=_LimitMax(x+BlockSize,mw)
For y=0 To mh
Pixel=Point(x,y)
Values(x,y)=((Red(Pixel) * srgb\sr) + (Green(Pixel) * srgb\sg) + (Blue(Pixel) * srgb\sb)) * srgb\sa
Next
Next
For y=0 To mh
LimitY(y,0)=_LimitMin(y-BlockSize,0)
LimitY(y,1)=_LimitMax(y+BlockSize,mh)
Next
For x=0 To mw
For y=0 To mh
Count=0
Counter=0
For xa=LimitX(x,0) To LimitX(x,1)
For ya=LimitY(y,0) To LimitY(y,1)
Count+Values(xa,ya)
Deviation(counter)=Values(xa,ya)
Counter+1
Next
Next
Mean=Count/Counter
Dev=0
Counter-1
For xa=0 To Counter
Dev+Pow(Deviation(xa)-Mean,2)
Next
If Values(x,y) < Round((Mean * (1 + *Binarization\Magnitude * Exp(-1* *Binarization\PhansalkarConstant * Mean) + *Binarization\Constant * ((Dev/*Binarization\DynamicRange) - 1))),#PB_Round_Nearest)
Plot(x,y,#Black)
Else
Plot(x,y,#White)
EndIf
Next
Next
EndSelect
StopDrawing()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Global Bin,XML$,MyBinarization.Binarization
Runtime Enumeration Windows
#Window
EndEnumeration
Runtime Enumeration Gadgets
#Image
#Checkbox1
#Combo1
#Combo2
#Text1
#Text2
#Text3
#Text4
#Text5
#Text6
#Text7
#String1
#String2
#String3
#String4
#String6
#String7
#Button1
#Button2
#Button3
EndEnumeration
Enumeration XML
#XML
EndEnumeration
Enumeration Dialogs
#Dialog
EndEnumeration
Procedure LiveEvents()
If GetGadgetState(#Button3)
If Bin And IsImage(Bin):FreeImage(Bin):EndIf
MyBinarization\Threshold=Val(GetGadgetText(#String1))
MyBinarization\Algorithm=GetGadgetState(#Combo2)
MyBinarization\PreProcessing=GetGadgetState(#Combo1)
MyBinarization\BlockSize=Val(GetGadgetText(#String2))
MyBinarization\Constant=Val(GetGadgetText(#String3))
MyBinarization\DynamicRange=Val(GetGadgetText(#String4))
If GetGadgetState(#Checkbox1)&#PB_Checkbox_Checked
MyBinarization\Background=#Bin_Background_Dark
Else
MyBinarization\Background=#Bin_Background_Light
EndIf
Bin=Binarize(0,MyBinarization)
SetGadgetState(#Image,ImageID(Bin))
EndIf
EndProcedure
UseJPEGImageDecoder()
LoadImage(0,OpenFileRequester("Load file","","*.jpg",0))
XML$="<window id='#Window' name='MainWindow' text='Binarization Test' flags='#PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget'>"+
"<hbox expand='item:1'>"+
"<image id='#Image' width='400' height='400'/>"+
"<vbox expand='item:14'>"+
"<combobox id='#Combo1' width='150'/>"+
"<combobox id='#Combo2' width='150'/>"+
"<hbox expand='item:1'>"+
"<text id='#Text1' text='Threshold:'/>"+
"<string id='#String1' text='50' width='50' flags='#PB_String_Numeric'/>"+
"</hbox>"+
"<hbox expand='item:1'>"+
"<text id='#Text2' text='Blocksize:'/>"+
"<string id='#String2' text='5' width='50' flags='#PB_String_Numeric'/>"+
"</hbox>"+
"<hbox expand='item:1'>"+
"<text id='#Text3' text='Constant:'/>"+
"<string id='#String3' text='0.2' width='50'/>"+
"</hbox>"+
"<hbox expand='item:1'>"+
"<text id='#Text4' text='Dynamic Range:'/>"+
"<string id='#String4' text='128' width='50' flags='#PB_String_Numeric'/>"+
"</hbox>"+
"<hbox expand='item:1'>"+
"<text id='#Text6' text='Magnitude:'/>"+
"<string id='#String6' text='3' width='50'/>"+
"</hbox>"+
"<hbox expand='item:1'>"+
"<text id='#Text7' text='Phansalkar Constant:'/>"+
"<string id='#String7' text='10' width='50' flags='#PB_String_Numeric'/>"+
"</hbox>"+
"<checkbox id='#Checkbox1' text='Background dark'/>"+
"<button id='#Button1' text='Lets go!'/>"+
"<button id='#Button2' text='Original'/>"+
"<button id='#Button3' text='Go live!' flags='#PB_Button_Toggle'/>"+
"<text id='#Text5' text=''/>"+
"<empty/>"+
"</vbox>"+
"</hbox>"+
"</window>"
If IsImage(0)
ParseXML(#Xml, XML$)
XMLStatus(#XML)
CreateDialog(#Dialog)
OpenXMLDialog(#Dialog, #Xml, "MainWindow")
AddGadgetItem(#Combo1,-1,"BT709")
AddGadgetItem(#Combo1,-1,"Equal")
AddGadgetItem(#Combo1,-1,"REC601")
AddGadgetItem(#Combo1,-1,"BT2100")
AddGadgetItem(#Combo1,-1,"Red Channel")
AddGadgetItem(#Combo1,-1,"Green Channel")
AddGadgetItem(#Combo1,-1,"Blue Channel")
SetGadgetState(#Combo1,0)
AddGadgetItem(#Combo2,-1,"Relative")
AddGadgetItem(#Combo2,-1,"Absolute")
AddGadgetItem(#Combo2,-1,"Range")
AddGadgetItem(#Combo2,-1,"Count")
AddGadgetItem(#Combo2,-1,"Rasterize")
AddGadgetItem(#Combo2,-1,"BlockMode")
AddGadgetItem(#Combo2,-1,"OTSU")
AddGadgetItem(#Combo2,-1,"Sauvola")
AddGadgetItem(#Combo2,-1,"Bernsen")
AddGadgetItem(#Combo2,-1,"Niblack")
AddGadgetItem(#Combo2,-1,"Phansalkar")
SetGadgetState(#Combo2,0)
BindGadgetEvent(#Combo1,@LiveEvents(),#PB_EventType_Change)
BindGadgetEvent(#Combo2,@LiveEvents(),#PB_EventType_Change)
BindGadgetEvent(#String1,@LiveEvents(),#PB_EventType_Change)
SetGadgetState(#Image,ImageID(0))
RefreshDialog(#Dialog)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case #Button1;Do binarization
If Bin And IsImage(Bin):FreeImage(Bin):EndIf
MyBinarization\Threshold=Val(GetGadgetText(#String1))
MyBinarization\Algorithm=GetGadgetState(#Combo2)
MyBinarization\PreProcessing=GetGadgetState(#Combo1)
MyBinarization\BlockSize=Val(GetGadgetText(#String2))
MyBinarization\Constant=Val(GetGadgetText(#String3))
MyBinarization\DynamicRange=Val(GetGadgetText(#String4))
MyBinarization\Magnitude=Val(GetGadgetText(#String6))
MyBinarization\PhansalkarConstant=Val(GetGadgetText(#String7))
If GetGadgetState(#Checkbox1)&#PB_Checkbox_Checked
MyBinarization\Background=#Bin_Background_Dark
Else
MyBinarization\Background=#Bin_Background_Light
EndIf
Bin=Binarize(0,MyBinarization)
;bin = Greyscale(0,GetGadgetState(#Combo1))
SetGadgetState(#Image,ImageID(Bin))
Case #Button2;Revert to original image
SetGadgetState(#Image,ImageID(0))
Case #Button3;Live view
If GetGadgetState(#Button3)
DisableGadget(#Button1,#True)
If Bin And IsImage(Bin):FreeImage(Bin):EndIf
MyBinarization\Threshold=Val(GetGadgetText(#String1))
MyBinarization\Algorithm=GetGadgetState(#Combo2)
MyBinarization\PreProcessing=GetGadgetState(#Combo1)
MyBinarization\BlockSize=Val(GetGadgetText(#String2))
MyBinarization\Constant=Val(GetGadgetText(#String3))
MyBinarization\DynamicRange=Val(GetGadgetText(#String4))
MyBinarization\Magnitude=Val(GetGadgetText(#String6))
MyBinarization\PhansalkarConstant=Val(GetGadgetText(#String7))
If GetGadgetState(#Checkbox1)&#PB_Checkbox_Checked
MyBinarization\Background=#Bin_Background_Dark
Else
MyBinarization\Background=#Bin_Background_Light
EndIf
Bin=Binarize(0,MyBinarization)
SetGadgetState(#Image,ImageID(Bin))
Else
DisableGadget(#Button1,#False)
EndIf
EndSelect
EndSelect
ForEver
Else
MessageRequester("Error","Image could not be loaded!",#PB_MessageRequester_Error)
EndIf
CompilerEndIf
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD