GDIP AutoCrop

Post your working scripts, libraries and tools for AHK v1.1 and older
AHK_user
Posts: 515
Joined: 04 Dec 2015, 14:52
Location: Belgium

GDIP AutoCrop

25 Feb 2020, 14:44

This code automatically extracts the first object from an image and automatically crops the background away.

Does anybody knows a similar script that is maybe faster?
If interested, I cann add that it allows a gradient background, but this would reduce the speed.

Input:
IMG_0203 - kopie.JPG
IMG_0203 - kopie.JPG (184.93 KiB) Viewed 781 times
Output:
output.JPG
output.JPG (162.66 KiB) Viewed 781 times

Code: Select all

; Script to auto-crop image of screnshot image File
; Possible improvements:
; 1. Handling gradient backgrounds (horizontal or vertical).
; 2. Finding multiple Images.

#SingleInstance, Force
#Include <Gdip>
SetBatchLines -1

FilePath:= A_ScriptDir "\Images\IMG_0203 - kopie.JPG"

if !FileExist(FilePath){
	FileSelectFile, FilePath
}

DebugWindow( "FilePath:" FilePath "`n")
FileNew := A_ScriptDir "\output.JPG"
FileDelete, %FileNew%
pToken := Gdip_Startup()
pBitmap1 := Gdip_CreateBitmapFromFile(FilePath)

pBitmap2 := GdipCrop_Auto(pBitmap1, "50")

Gdip_DisposeImage(pBitmap1)
Gdip_SaveBitmapToFile(pBitmap2, FileNew, "100")
Gdip_DisposeImage(pBitmap2)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)

Run, Edit %FileNew%
return

GdipCrop_Auto(pBitmap1, ColorVar:="50"){
	ST := A_TickCount
	Gdip_GetDimensions(pBitmap1, XWidth_Img_1, YHeight_Img_1)
	DebugWindow( "xWidth:" XWidth_Img_1 "`nyHeight:" YHeight_Img_1 "`n")
	
	; loop to search for pixels that are not like the previous pixel
	; I start with a rough loop to make the searching faster
	Accuracy := 1
	Pixel_BackGround := Gdip_GetPixel(pBitmap1, 1, 1)
	loop, % YHeight_Img_1/Accuracy
	{
		Y_Coord := A_Index*Accuracy
		loop, % XWidth_Img_1/Accuracy
		{
			X_Coord := A_Index*Accuracy
			Pixel_Current := Gdip_GetPixel(pBitmap1, X_Coord, Y_Coord)
			if ((Pixel_Current - Pixel_BackGround > 10 or Pixel_Current - Pixel_BackGround < -10) and Pixel_Current!=0){
				if (CompareRAGBColors(Pixel_BackGround, Pixel_Current, ColorVar)){
					Continue
				}
				break 2
			}
		}
	}
	X0_Coord:=X_Coord
	Y0_Coord:=Y_Coord
	
	X0_Coord:=X_Coord-accuracy
	Y0_Coord:=Y_Coord-accuracy
	
	; doing a more accurate loop to find the first pixel that is different
	loop, % Accuracy
	{
		Y_Coord := Y0_Coord+A_Index
		loop, % Accuracy
		{
			X_Coord := X0_Coord+A_Index
			Pixel_Current := Gdip_GetPixel(pBitmap1, X_Coord, Y_Coord)
			if (Pixel_Current!=Pixel_BackGround and Pixel_Current!=0){
				if (CompareRAGBColors(Pixel_BackGround, Pixel_Current, ColorVar)){
					Continue
				}
				X0_Coord:=X_Coord
				Y0_Coord:=Y_Coord
				break 2
			}
		}
	}
	DebugWindow( "Found`nx0:" X0_Coord "`ny0:" Y0_Coord "`n" Pixel_Current "`n")
	DebugWindow("Time: " A_TickCount - ST " msec`n`n")
	dx:=-1
	dy:=1
	X_max := X_Coord
	Y_max := Y_Coord
	X_min := X_Coord
	Y_min := Y_Coord

	ST := A_TickCount
	loop, % (XWidth_Img_1+YHeight_Img_1)*20 ; loop to "walk" arround opject
	{
		Pixel_Current := Gdip_GetPixel(pBitmap1, X_Coord+dx, Y_Coord+dy)
		
		if (!CompareRAGBColors(Pixel_BackGround, Pixel_Current, ColorVar)){
			; Non-background color is found, go to the pixel.
			X_Coord:=X_Coord+dx
			Y_Coord:=Y_Coord+dy
			
			if (X0_Coord=X_Coord and Y0_Coord=Y_Coord){
				DebugWindow( "X_min:" X_min "`nX_max:" X_max "`nY_min:" Y_min "`nY_max:" Y_max "`nLoop ended by returning to X0 Y0`nA_Index:" A_Index "`n`n")
				break
			}
			X_max := Max(X_max, X_Coord)
			Y_max := Max(Y_max, Y_Coord)
			X_min := Min(X_min, X_Coord)
			Y_min := Min(Y_min, Y_Coord)
			
			; Changing the search direction (counterclockwise).
			if ((dx=1 or dx=0) and dy=1){
				dx-=1
			}
			else if (dx=-1 and (dy=1 or dy=0)){
				dy-=1
			}
			else if ((dx=-1 or dx=0) and dy=-1){
				dx+=1
			}
			else if (dx=1 and (dy=-1 or dy=0)){
				dy+=1
			}
			Continue
		}
		
		; Changing the search direction if non-background color is not found  (clockwise).
		if ((dx=-1 or dx=0) and dy=1){
			dx+=1
		}
		else if (dx=1 and (dy=1 or dy=0)){
			dy-=1
		}
		else if ((dx=1 or dx=0) and dy=-1){
			dx-=1
		}
		else if (dx=-1 and (dy=-1 or dy=0)){
			dy+=1
		}
		
	}
	DebugWindow( "X_min:" X_min "`nX_max:" X_max "`nY_min:" Y_min "`nY_max:" Y_max "`nTime: " A_TickCount - ST " msec`n")
	
	w := X_max-X_min
	h := Y_max-Y_min
	
	; Cropping the image
	pBitmap2 := Gdip_CreateBitmap(w, h)
	G2 := Gdip_GraphicsFromImage(pBitmap2)
	Gdip_DrawImage(G2, pBitmap1, 0, 0, w, h, X_min, Y_min, w, h)
	Gdip_DeleteGraphics(G2)
	
	Return % pBitmap2
}

Gdip_CropImage(pBitmap, x, y, w, h){
	pBitmap2 := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmap2)
	Gdip_DrawImage(G2, pBitmap, 0, 0, w, h, x, y, w, h)
	Gdip_DeleteGraphics(G2)
	return pBitmap2
}

ARGBtoRGB( ARGB ) {
	VarSetCapacity( RGB,6,0 )
	DllCall( "msvcrt.dll\sprintf", Str,RGB, Str,"%06X", UInt,ARGB<<8 )
	Return "0x" RGB
}

DebugWindow(Text,Clear:=0,LineBreak:=0,Sleep:=0,AutoHide:=0,MsgBox:=0){
	if WinExist("AHK Studio - "){
		x:=ComObjActive("{DBD5A90A-A85C-11E4-B0C7-43449580656B}"),x.DebugWindow(Text,Clear,LineBreak,Sleep,AutoHide,MsgBox)
	}
	Else{
		MsgBox,  % text
	}
	return
}

DEC2HEX(DEC, RARGB="false") {
    SetFormat, IntegerFast, hex
    RGB += DEC ;Converts the decimal to hexidecimal
	if(RARGB=="true")
		RGB := RGB & 0x00ffffff
	SetFormat Integer, D
    return RGB
}

CompareRAGBColors(cRAGB1, cRAGB2, Vary="20") {
	
	cARGB1 := DEC2HEX(cRAGB1, true)
	cARGB2 := DEC2HEX(cRAGB2, true)
	B1 := cARGB1 & 255
	G1 := (cARGB1 >> 8) & 255
	R1 := (cARGB1 >> 16) & 255
	
	B2 := cARGB2 & 255
	G2 := (cARGB2 >> 8) & 255
	R2 := (cARGB2 >> 16) & 255
	
    rdiff := Abs(B1-B2)
    gdiff := Abs(G1-G2)
    bdiff := Abs(R1-R2)
	
    return rdiff <= Vary && gdiff <= Vary && bdiff <= Vary
}

put:
User avatar
Delta Pythagorean
Posts: 627
Joined: 13 Feb 2017, 13:44
Location: Somewhere in the US
Contact:

Re: GDIP AutoCrop

26 Feb 2020, 01:03

Not bad, I don't see a use for myself anytime soon, but this could come in handy at some point!

[AHK]......: v2.0.12 | 64-bit
[OS].......: Windows 11 | 23H2 (OS Build: 22621.3296)
[GITHUB]...: github.com/DelPyth
[PAYPAL]...: paypal.me/DelPyth
[DISCORD]..: tophatcat


Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: sanmaodo and 169 guests