Image binarization — Bradley local thresholding

Share your advanced PureBasic knowledge/code with the community.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Image binarization — Bradley local thresholding

Post by Lunasole »

This stuff might be useful to recognize objects/text on scanned images, photos or other graphics. It has enough advantages against other black&white conversion algorithms

Code: Select all

EnableExplicit
; (c) Lunasole, 2016/03/10

Procedure RGBtoGray (RGB)
	ProcedureReturn (Red(RGB) * 0.3 + Green(RGB) * 0.59 + Blue(RGB) * 0.11) ; photoshop, GIMP?
	
	;; here comes more ^^
	; Gray = (Red + Green + Blue) / 3 ; averaging
	; Gray = (Red * 0.2126 + Green * 0.7152 + Blue * 0.0722)
	; Gray = (Red * 0.299 + Green * 0.587 + Blue * 0.114)
	
	; ; Max() returns max of 3 arguments, Min() does the same but minimal value returned
	; Gray = ( Max(Red, Green, Blue) + Min(Red, Green, Blue) ) / 2 ; desaturation
	; Gray = Max(Red, Green, Blue) ; maximum decomposition 
	; Gray = Min(Red, Green, Blue) ; minumum decomposition
	; Gray = Red ; Green/Blue ; single color channel
EndProcedure


;; Bradley local image thresholding
; hDC:			valid output handle (ImageID(), CanvasID() and so on)
; WhiteBound:	0.0 to 1.0
; Details:		0.0 to 1.0, the higher it is, the lesser is area size and more areas used
; RETURN:		none, original image modified
Procedure imageToWB(hDC, WhiteBound.f = 0.15, Details.f = 0.32)
	If Not StartDrawing(hDC)
		ProcedureReturn 
	EndIf
	
	Protected src_width = OutputWidth(), src_height = OutputHeight()
	Protected X, Y, X1, Y1, X2, Y2
	Protected Summ, AreaDim, AreaSize = ((src_width + src_height) / 2) * (1.0 - Details)
	
	Protected.L Dim IntegralImage (src_width - 1, src_height - 1)
	Protected.A Dim GrayImage (src_width - 1, src_height - 1)
	
	; building grayscale and integral images
	For X = 0 To src_width - 1
		Summ = 0
		For Y = 0 To src_height - 1
			GrayImage(X, Y) = RGBtoGray(Point(X, Y))
			Summ + GrayImage(X, Y)
			If X = 0
				IntegralImage(X, Y) = Summ
			Else
				IntegralImage(X, Y) = IntegralImage(X - 1, Y) + Summ
			EndIf
		Next Y
	Next X
	
	; walk to local areas
	For X = 0 To src_width - 1
		For Y = 0 To src_height - 1
			X1 = X - AreaSize
			X2 = X + AreaSize
			Y1 = Y - AreaSize
			Y2 = Y + AreaSize
			
			If x1 < 0 :	x1 = 0 : EndIf
			If x2 >= src_width  : x2 = src_width - 1 :	EndIf
			If y1 < 0 :	y1 = 0 : EndIf
			If y2 >= src_height : y2 = src_height - 1:	EndIf
			
			AreaDim = (X2 - X1) * (Y2 - Y1)
			
			Summ = IntegralImage(X2, Y2) - IntegralImage(X2, Y1) - IntegralImage(X1, Y2) + IntegralImage(X1, Y1) ; quickly get whole area brightness by calculating brightness values at area corners
			If (GrayImage(X, Y) * AreaDim) >= (Summ * (1.0 - WhiteBound))
				Plot(X, Y, #White)
			Else
				Plot(X, Y, #Black)
			EndIf
		Next Y
	Next X
	
	; cls
	StopDrawing()
	FreeArray(IntegralImage())
	FreeArray(GrayImage())
EndProcedure



;;;;;;;;;
UsePNGImageDecoder()
UseJPEGImageDecoder()
Define A = LoadImage(#PB_Any, #PB_Compiler_Home+"/Examples/Sources/data/purebasic.bmp")
OpenWindow(0, 0, 0, ImageWidth(A), ImageHeight(A) * 2, "Img", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)


CanvasGadget(0, 0, 0, ImageWidth(A), ImageHeight(A)) ; original image
CanvasGadget(1, 0, ImageHeight(A), ImageWidth(A), ImageHeight(A)) ; modified one

SetGadgetAttribute(0, #PB_Canvas_Image, ImageID(A))
SetGadgetAttribute(1, #PB_Canvas_Image, ImageID(A))

; the function params need to be tweaked depend of what you need
imageToWB (CanvasOutput(1), 0.27)

Repeat
	If WaitWindowEvent(256) = #PB_Event_CloseWindow
		End
	EndIf
ForEver
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
AAT
Enthusiast
Enthusiast
Posts: 259
Joined: Sun Jun 15, 2008 3:13 am
Location: Russia

Re: Image binarization — Bradley local thresholding

Post by AAT »

Hi, Lunasole!
Thanks for sharing!

The result looks like in "AForge.NET Framework": http://www.aforgenet.com/framework/docs ... 9c139f.htm

Image

Good luck!
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Image binarization — Bradley local thresholding

Post by Lunasole »

@AAT don't know about NET, it also can be used from OpenCV (here are API on forum), I just made more simple proc specially of this one
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
AAT
Enthusiast
Enthusiast
Posts: 259
Joined: Sun Jun 15, 2008 3:13 am
Location: Russia

Re: Image binarization — Bradley local thresholding

Post by AAT »

Lunasole, yes, i know about OpenCV topic :D
First of all, i've tried to get the same result with openCV. The result of cvAdaptiveThreshold is slightly different from Bradley local thresholding.

Image
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Image binarization — Bradley local thresholding

Post by Lunasole »

@AAT hm, I thought OpenCV uses the same thing. However, didn't checked by myself (was too lazy as usual), thanks for info
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Image binarization — Bradley local thresholding

Post by Keya »

very interesting! AAT that is a remarkable image, i find it amazing how good the recovery from those dark areas was (with both Bradley and adaptive)
AAT
Enthusiast
Enthusiast
Posts: 259
Joined: Sun Jun 15, 2008 3:13 am
Location: Russia

Re: Image binarization — Bradley local thresholding

Post by AAT »

Keya, many thanks to JHPJHP and his remarkable topic "PureBasic Interface to OpenCV"
The example is "cv_threshold_2.pb" with parameters

Code: Select all

cvAdaptiveThreshold(*reset, *gray, 255, #CV_ADAPTIVE_THRESH_MEAN_C, #CV_THRESH_BINARY_INV, 5, 3)
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Image binarization — Bradley local thresholding

Post by Lunasole »

There is one fun thing where this binarization can be applied: for example, if change code to draw RGB(252, 252, 252)) instead of #Black, you will get "empty" white image.
But then if you set gamma of that image to low value, the image contents becomes visible and painted black (or gray). A good way to add some "easter eggs" 8) The Photoshop CS3 had one made this way.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
Post Reply