检查顶点是否在相机视图和渲染中可见或被遮挡。

7

我正在处理一个机器学习任务,尝试使用blender生成合成图像作为神经网络的训练数据集。为此,我必须找到渲染图像中对象的边界框。

到目前为止,我所使用的代码主要基于这个线程中建议的代码,但是它没有考虑顶点是否被另一个对象遮挡或可见。实际上,期望的结果正好与这里所解释的一样。我尝试了那里给出的建议,但它不起作用。我无法确定是因为我给ray_cast函数提供了错误的输入(因为bpy API确实很糟糕),还是因为函数性能差,如我在其他地方读到的那样。我的代码现在是:

import bpy
import numpy as np

def boundingbox(scene, camera, obj, limit = 0.3):
    #  Get the inverse transformation matrix.
    matrix = camera.matrix_world.normalized().inverted()
    #  Create a new mesh data block, using the inverse transform matrix to undo any transformations.
    dg = bpy.context.evaluated_depsgraph_get()
    #    eval_obj = bpy.context.object.evaluated_get(dg)
    eval_obj = obj.evaluated_get(dg)
    mesh = eval_obj.to_mesh()
    mesh.transform(obj.matrix_world)
    mesh.transform(matrix)

    #  Get the world coordinates for the camera frame bounding box, before any transformations.
    frame = [-v for v in camera.data.view_frame(scene=scene)[:3]]
    origin = camera.location
    lx = []
    ly = []

    for v in mesh.vertices:
        co_local = v.co
        z = -co_local.z
        direction =  (co_local - origin)


        result = scene.ray_cast(view_layer=bpy.context.window.view_layer, origin=origin,
                                      direction= direction) # interested only in the first return value
        intersection = result[0]
        met_obj = result[4]
        if intersection:
            if met_obj.type == 'CAMERA':
                intersection = False


        if z <= 0.0 or (intersection == True and (result[1] - co_local).length > limit):
            #  Vertex is behind the camera or another object; ignore it.
            continue
        else:
            # Perspective division
            frame = [(v / (v.z / z)) for v in frame]

        min_x, max_x = frame[1].x, frame[2].x
        min_y, max_y = frame[0].y, frame[1].y

        x = (co_local.x - min_x) / (max_x - min_x)
        y = (co_local.y - min_y) / (max_y - min_y)

        lx.append(x)
        ly.append(y)

    eval_obj.to_mesh_clear()

    #  Image is not in view if all the mesh verts were ignored
    if not lx or not ly:
        return None

    min_x = np.clip(min(lx), 0.0, 1.0)
    min_y = np.clip(min(ly), 0.0, 1.0)
    max_x = np.clip(max(lx), 0.0, 1.0)
    max_y = np.clip(max(ly), 0.0, 1.0)

    #  Image is not in view if both bounding points exist on the same side
    if min_x == max_x or min_y == max_y:
        return None

    # Figure out the rendered image size
    render = scene.render
    fac = render.resolution_percentage * 0.01
    dim_x = render.resolution_x * fac
    dim_y = render.resolution_y * fac

    # return box in the form (top left x, top left y),(width, height)
    return (
        (round(min_x * dim_x),  # X
         round(dim_y - max_y * dim_y)),  # Y
        (round((max_x - min_x) * dim_x),  # Width
         round((max_y - min_y) * dim_y))  # Height
    )

我还尝试过将光线从顶点投射到相机位置(而不是反过来),并使用如此处所解释的小正方体解决方法,但仍然无法成功。请问有人能帮助我找出正确的方法或提出其他策略吗?


你有没有运气弄清楚它? - user3087615
2个回答

0
我试图找到场景渲染图像中物体的遮挡级别。 我的做法是,创建了一个类似地图(简单的2D数组),大小与渲染分辨率相同。然后我按照以下步骤进行...
for each object in the scene:
    for each vertex of the object:
        (x', y', z') = convert the vertex from local(obj.data.vertices[i].co) to world view
        (x, y, z) = convert the world view vertex(x', y', ') to the 2d camera view
        # this x, y is the 2d coordinates and that z is the distance of the point from camera
        update the 2d array with the id(corresponding to the object closer to the camera)

在最后,您可以检查顶点(对象obj的一部分)是否可见,您需要做的就是需要该顶点在最终渲染图像中的投影,假设为(x, y)。现在我们只需要检查该地图/2D数组是否具有索引(x, y)处的obj的ID。如果是,则表示渲染图像中坐标为(x, y)的obj顶点可见;如果不是,则表示在(x, y)处的地图/2D数组具有其他对象的ID。在这种情况下,可以得出结论:对象obj在场景中的特定顶点和相机之间存在另一个对象,因此在渲染图像中坐标为(x, y)的对象obj的顶点被其他对象覆盖。

这只是数字的巧妙操作,您将获得想要的结果。 如果您需要更多的解释/代码,请在评论中让我知道。 如果您发现此方法有任何错误,请让我知道。 感谢您的评论。


0

我曾经需要解决一个非常类似的问题

这是我使用的代码

def BoundingBoxFinal(obj,cam):
from bpy_extras.object_utils import world_to_camera_view
scene = bpy.context.scene
# needed to rescale 2d coordinates
render = scene.render
render_scale = scene.render.resolution_percentage / 100
res_x = render.resolution_x *render_scale
res_y = render.resolution_y *render_scale
# use generator expressions () or list comprehensions []
mat = obj.matrix_world
verts = [vert.co for vert in obj.data.vertices]
for i in range(len(verts)):
    verts[i] = obj.matrix_world @ verts[i]


coords_2d = [world_to_camera_view(scene, cam, coord) for coord in verts]

# 2d data printout:
rnd = lambda i: round(i)


X_max = max(coords_2d[0])
Y_max = max(coords_2d[1])
X_min = min(coords_2d[0])
Y_min = min(coords_2d[1])

verts_2d =[]
for x, y, distance_to_lens in coords_2d:
    verts_2d.append(tuple((rnd(res_x*x), rnd(res_y-res_y*y))))

Y_max = max(verts_2d, key = lambda i : i[1])[1]
X_max = max(verts_2d, key = lambda i : i[0])[0]
Y_min = min(verts_2d, key = lambda i : i[1])[1]
X_min = min(verts_2d, key = lambda i : i[0])[0]

verts_2d.clear()

return(
    X_min,
    Y_min,
    X_max,
    Y_max,
    obj.data.name.split('.')[0]
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接