1
$\begingroup$

I am drawing a line of vehicles on the image, how could I get the coordinates and bounds of each vehicle in the image, since I want to crop the these vehicles one by one from this image?enter image description here

I found a snippet, but the values (x , y, width, height) seem to be like the global coordinates rather than the pixel position on the image.

def get_bounds(ob):
    mat = ob.matrix_world
    bbox = [mat * Vector(b) for b in ob.bound_box]

    min_x = min(b.x for b in bbox)
    max_x = max(b.x for b in bbox)
    min_y = min(b.y for b in bbox)
    max_y = max(b.y for b in bbox)

    top_left = Vector((min_x, max_y))
    bottom_right = Vector((max_x, min_y))

    # make flat tuple, x y width height
    return top_left.to_tuple() + tuple(map(abs, (top_left - bottom_right)))
$\endgroup$
1
$\begingroup$

You can do this by analyzing each isolated object in the compositor after rendering, via an object ID mask.

The compositor gives you access to the pixels of the viewer node, which can be manipulated quickly in Numpy.

Blendfile here

This is the rendered image: Image

I gave each of the objects a different pass index, so we generate a mask that isolates each in turn with the ID mask node.

Node setup

By changing the index in the ID mask node you can iterate between the objects. Here's object 1's mask: Obj1 mask

Now, to get the bounding box coordinates all you need to do is run this script (partially based on this nice method for producing a bounding box):

import bpy
import numpy as np

S = bpy.context.scene
width  = int( S.render.resolution_x * S.render.resolution_percentage / 100 )
height = int( S.render.resolution_y * S.render.resolution_percentage / 100 )
depth  = 4

pixels = np.array( bpy.data.images['Viewer Node'].pixels[:] ).reshape( [height, width, depth] )

# Keep only one value for each pixel (white pixels have 1 in all RGBA channels anyway), thus converting the image to black and white
pixels = np.array( [ [ pixel[0] for pixel in row ] for row in pixels ] )

bbox = np.argwhere( pixels )
(ystart, xstart), (ystop, xstop) = bbox.min(0), bbox.max(0) + 1 

Output I got for this image:

>>> ystart
157

>>> xstart
273

>>> ystop
380

>>> xstop
398
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.