Python 检查顶点是否在摄影机视图中可见并渲染或遮挡

Python 检查顶点是否在摄影机视图中可见并渲染或遮挡,python,neural-network,blender,raycasting,bounding-box,Python,Neural Network,Blender,Raycasting,Bounding Box,我正在处理一项机器学习任务,我正在尝试使用blender生成合成图像,作为神经网络的训练数据集。为此,我必须找到渲染图像中对象的边界框 到目前为止,我的代码主要基于建议的代码,但这并不考虑顶点是可见的还是被另一个对象遮挡。所期望的结果确实与所解释的完全相同。我试过那里的建议,但不起作用。我不明白这是因为我给了ray_cast函数错误的输入(因为bpy API真的很糟糕),还是因为函数性能差,正如我在其他地方读到的那样。我现在的代码是: import bpy import numpy as np

我正在处理一项机器学习任务,我正在尝试使用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
    )
导入bpy
将numpy作为np导入
def边界框(场景、摄影机、obj、限制=0.3):
#求逆变换矩阵。
矩阵=摄影机.matrix_world.normalized().inversed()
#创建新的网格数据块,使用逆变换矩阵撤消任何变换。
dg=bpy.context.evaluated_depsgraph_get()
#eval_obj=bpy.context.object.evaluated_get(dg)
评估对象=评估对象(dg)
网格=评估对象到网格()
网格变换(对象矩阵世界)
网格变换(矩阵)
#在进行任何变换之前,获取摄影机帧边界框的世界坐标。
frame=[-v代表摄影机中的v.data.view\u frame(场景=场景)[:3]]
原点=摄影机位置
lx=[]
ly=[]
对于网格顶点中的v:
co_local=v.co
z=-co_local.z
方向=(co_本地-原点)
结果=场景。光线投射(视图层=bpy.context.window.view层,原点=原点,
方向=方向)#只对第一个返回值感兴趣
交点=结果[0]
met_obj=结果[4]
如果是交叉口:
如果符合_obj.type==‘摄像头’:
交点=假
如果z限制):
#顶点位于摄影机或其他对象的后面;别理它。
持续
其他:
#透视图划分
帧=[(v/(v.z/z))表示帧中的v]
最小x,最大x=帧[1]。x,帧[2]。x
最小值y,最大值y=帧[0]。y,帧[1]。y
x=(co_local.x-min_x)/(max_x-min_x)
y=(co_local.y-min_y)/(max_y-min_y)
lx.追加(x)
ly.追加(y)
评估对象到网格清除()
#如果忽略所有网格顶点,则图像不在视图中
如果不是lx或不是ly:
一无所获
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)
#如果两个边界点存在于同一侧,则图像不在视图中
如果最小值x==最大值x或最小值y==最大值y:
一无所获
#计算渲染图像的大小
render=scene.render
fac=渲染分辨率×百分比*0.01
dim_x=render.resolution_x*fac
dim_y=render.resolution_y*fac
#表单中的返回框(左上角x,左上角y),(宽度,高度)
返回(
(圆形(最小x*尺寸x),#x
圆形(dim_y-max_y*dim_y)),#y
(圆形((最大x-最小x)*尺寸x),#宽度
圆形((最大值-最小值)*尺寸)高度
)

我还尝试将光线从顶点投射到摄影机位置(而不是做相反的操作),并按照说明使用小立方体解决方法,但没有效果。请有人帮我弄清楚如何正确地做这件事或提出另一种策略吗?

我不得不解决一个非常类似的问题

这是我使用的代码

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]
)

我试图在场景的渲染图像中找到对象的遮挡级别。 我所做的是,我创建了一种与渲染分辨率相同大小的贴图(简单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)
最后,您可以检查顶点(object
obj
的一部分)是否可见,只需在最终渲染图像中需要该顶点的投影,例如(x,y)。现在我们只需要检查map/2D数组在索引(x,y)处是否有
obj
的id。如果是,这意味着渲染图像中坐标(x,y)处的obj顶点可见,如果不是,即在(x,y)处,贴图/2d数组具有其他对象的id。在这种情况下,可以得出结论,坐标(x,y)处的渲染图像中的对象
obj
顶点被场景中的其他对象覆盖(在该特定顶点和摄影机之间有另一个对象)

这只是对数字的巧妙操纵,你会得到你想要的。 如果您需要更多的解释/代码,请在评论中告诉我。 如果你们中的任何人发现这种方法有任何错误,也请告诉我。
您的评论将不胜感激

您有没有找到答案?