Extract 2D bounding box to txt file {Yolo}

Extract 2D bounding box to txt file {Yolo}

kantorovich1
Explorer Explorer
899 Views
2 Replies
Message 1 of 3

Extract 2D bounding box to txt file {Yolo}

kantorovich1
Explorer
Explorer

Hi folks,

I want to say first that I am a super beginner with 3ds-max and just start to learn these amazing tools.

I start some research that checks 3D data on object detection algorithms. I try to train NN using 3D studio images from some scenes.  I try to extract the bounding box of the object to the txt file that corresponds to jpg image so I need your help to find some script that extracts the txt file with Yolo format  " In yolo, a bounding box is represented by four values [x_center, y_center, width, height]. x_center and y_center are the normalized coordinates of the center of the bounding box... " 

Format:

<object-class > <X_center_Norm> <Y_center_Norm> <Width_Norm> <Height_Norm>

object-class = Integer for exam model_0,model_1 represent by 0, 1, ... N-models name

X_CENTER_NORM = X_CENTER_ABS/IMAGE_WIDTH

Y_CENTER_NORM = Y_CENTER_ABS/IMAGE_HEIGHT

WIDTH_NORM = WIDTH_OF_LABEL_ABS/IMAGE_WIDTH

HEIGHT_NORM = HEIGHT_OF_LABEL_ABS/IMAGE_HEIGHT

 

I will be glad to any help I very sure that I am not the first person that search this solution.

0 Likes
900 Views
2 Replies
Replies (2)
Message 2 of 3

Swordslayer
Advisor
Advisor

Depends what's the way you're getting the image, if it's viewport capture, something like this should work:

 

(
	local file = createFile @"D:\output.txt"
	gw.setTransform (Matrix3 1)
	local viewTM = inverse (viewport.getTM())

	for obj in selection do
	(
		local extremes = nodeGetBoundingBox obj viewTM
		local box2D = Box2 (gw.TransPoint (extremes[1] * viewTM)) (gw.TransPoint (extremes[2] * viewTM))

		local xCenter = box2D.center.x as float / gw.getWinSizeX()
		local yCenter = box2D.center.y as float / gw.getWinSizeY()
		local width = box2D.w as float / gw.getWinSizeX()
		local height = box2D.h as float / gw.getWinSizeY()

		format "% % % % %\n" "<object-class>" xCenter yCenter width height to:file
	)
	close file
)

 

meaning it would correspond to the image size as captured by gw.getViewportDib(), i.e. visually it would look like this for one selected object:

 

try destroyDialog test2DBBox catch()
rollout test2DBBox "2D BBox" width:400 height:300
(
  	imgTag itImage width:400 height:300 pos:[0,0]

	on test2DBBox open do if isKindOf $ Node then
	(
		gw.setTransform (Matrix3 1)
		local viewTM = inverse (viewport.getTM())
		local viewPic = gw.getViewportDib()
		local extremes = nodeGetBoundingBox $ viewTM
		local box2D = Box2 (gw.TransPoint (extremes[1] * viewTM)) (gw.TransPoint (extremes[2] * viewTM))
		local ratio = gw.getWinSizeY() as double / gw.getWinSizeX()
		local labelPic = Bitmap box2D.w box2D.h color:(blue + green)

		pasteBitmap labelPic viewPic [0,0] [box2D.x, box2D.y] type:#blend alphaMultiplier:.5
		if ratio > .75 then itImage.width = 300 / ratio else itImage.height = 400 * ratio
		itImage.bitmap = viewPic
	)
	else (destroyDialog test2DBBox; messageBox "Select one object")
)
createDialog test2DBBox

 

If you want the same for rendered image, I'd recommend checking the 'How To ... Develop a Vertex Renderer' chapter in the MAXScript reference which covers translating points in world space to rendered image space.

0 Likes
Message 3 of 3

kantorovich1
Explorer
Explorer

Hi Swordslayer,
thank you for the quick and informative answer.

I checked the first item you suggested and it seems to hit the nail right on the head! i.e., it produces a file with a 2D box of the selected item in the frame.
In order to fully complete the script's functionality, the following tweaks are still required:
1. Get a 2D box of all selected groups of objects and not of all selected objects.
2. Get the names of all selected groups
3. Get the current frame number

Any help in adding any of these to the script would be greatly appreciated!

0 Likes