Notifications
Clear all

[Closed] Fastest way to get transparent image bounding box

Hi guys!

I have many PNG 24bits with transparency that have different graphic in it, circle, box, etc.
I need a method to get the first pixel that is not transparent in all 4 directions.
So that way I know where in the image the element start and end.

The getPixels do not return the transparency information.

Regards,

OZRay

12 Replies
 lo1

24bits means no transparency (only RGB).
Only 32bit PNGs can have transparency (RGBA).

And if they do, getPixels does return an RGBA color value.
You can access the alpha value using the .a property.

Yes sorry this is a 32bits PNG.

Where do you get the .a property?

When Im doing this:

img = openbitmap @"C:\Temp\Asterix_Test.png"
h = getPixels img [10,10] 1

It gives me black that is the background behind the transparency.

thanks

Sorry got it…

img = openbitmap @"C:\Temp\Asterix_Test.png"

h = getPixels img [10,10] 1
h[1].a

thanks

 lo1
h[1] --->> (color 0 0 0 0)
h[1].a --->> 0.0

Humm it’s easy and fast to find the Y from the top and the Y from the bottom because as soon that I get a value other then 0.0 in the alpha of getPixels img [0.0] img.width I stop there.
But it’s a more complicated to find it in X cause I have to scan the complet image to get the first transparent pixel in X and the last one…

 lo1

yes, you do.

fn getTrimmedCoords thebmp =
(
	local tTop = tBottom = tLeft = tRight = -1
	local coords = #()
	for i = 1 to thebmp.height do append coords (getPixels theBmp [0,i-1] thebmp.width)
	
	for top = 1 to coords.count while tTop==-1 do 
	for c in coords[top] do if c.a != 0 do tTop=top
	if tTop == -1 do tTop = 1
		
	for bottom = coords.count to tTop by -1 while tBottom == -1 do 
	for c in coords[bottom] do if c.a != 0 do tBottom = bottom
	if tBottom == -1 do tBottom = theBmp.height
		
	for left = 1 to coords[1].count while tLeft == -1 do
	for c = tTop to tBottom do if coords[c][left].a != 0 do tLeft = left
	if tLeft == -1 do tLeft = 1
		
	for right = coords[1].count to tLeft by -1 while tRight == -1 do
	for c = tTop to tBottom do if coords[c][right].a != 0 do tRight = right
	if tRight == -1 do tRight = theBmp.width	
		
	#(tTop, tBottom, tLeft, tRight)
)
 the [b]pastebitmap [/b]with function might be faster... not dramatically. my guess is ~15-20% faster.

EDITED:

i was wrong… LO’s method is algorithmically optimized and not going through all pixels. so it’s much faster than pasteBitmap which is processing every pixel… if you want to see the difference:


  fn getTrimmedCoords thebmp =
  (
  	local tTop = tBottom = tLeft = tRight = -1
  	local coords = #()
  	for i = 1 to thebmp.height do append coords (getPixels theBmp [0,i-1] thebmp.width)
  	
  	for top = 1 to coords.count while tTop==-1 do 
  	for c in coords[top] do if c.a != 0 do tTop=top
  	if tTop == -1 do tTop = 1
  		
  	for bottom = coords.count to tTop by -1 while tBottom == -1 do 
  	for c in coords[bottom] do if c.a != 0 do tBottom = bottom
  	if tBottom == -1 do tBottom = theBmp.height
  		
  	for left = 1 to coords[1].count while tLeft == -1 do
  	for c = tTop to tBottom do if coords[c][left].a != 0 do tLeft = left
  	if tLeft == -1 do tLeft = 1
  		
  	for right = coords[1].count to tLeft by -1 while tRight == -1 do
  	for c = tTop to tBottom do if coords[c][right].a != 0 do tRight = right
  	if tRight == -1 do tRight = theBmp.width	
  		
  	#([tLeft,tTop], [tRight, tBottom])
  )
  fn getBitmapAlphaBBox bmp =
  (
  	bbox = #([1e9,1e9],[-1e9,-1e9])
  	fn getMinMax c p _c _p bbox:bbox = 
  	(
  		if c.a != 0 do 
  		(
  			if p.x < bbox[1].x do bbox[1].x = p.x
  			if p.y < bbox[1].y do bbox[1].y = p.y
  			if p.x > bbox[2].x do bbox[2].x = p.x
  			if p.y > bbox[2].y do bbox[2].y = p.y
  		)
  		c
  	)
  	pasteBitmap bmp bmp [0,0] [0,0] type:#function function:getMinMax
  	bbox
  )
  
  (
  	bmp = openbitmap <any_texture_file_with_alpha>
  
  	t1 = timestamp()
  	m1 = heapfree
  	bb = getTrimmedCoords bmp
  	format "1 >> size:% bbox:% time:% memory:%
" [bmp.width,bmp.height] bb (timestamp() - t1) (m1 - heapfree)
  	
  	t1 = timestamp()
  	m1 = heapfree
  	bb = getBitmapAlphaBBox bmp
  	format "2 >> size:% bbox:% time:% memory:%
" [bmp.width,bmp.height] bb (timestamp() - t1) (m1 - heapfree)
  )
  

Thanks a lot guys!

So I will go with Lo’s algo.

 lo1

If performance is critical in your scenario, you might want to change all the loops to check every 2nd or 3rd pixel.
There are insanely few cases where the function will give a wrong result due to this, and if you are padding an extra 5-10% for your trimmed bitmap, it will matter even less.

Page 1 / 2