You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用Open3D RaycastingScene渲染Mesh深度图结果异常的修复

修复Open3D RaycastingScene深度图渲染异常的问题

问题描述

使用Open3D的RaycastingScene基于Mesh文件和相机内参渲染深度图时,得到的深度图几乎全黑,仅边缘有少量有效深度值,不符合预期。

问题原因及修复步骤

1. 相机外参与模型位置不匹配

Open3D的RaycastingScene.create_rays_pinhole中,extrinsic_matrix表示相机到世界坐标系的变换矩阵,默认相机看向-Z方向。若使用单位矩阵作为外参,相机位于世界原点,而模型可能不在相机的视锥范围内,导致大部分射线无法击中模型。

修复:调整相机位置,将相机沿Z轴正方向移动(让模型处于相机前方),同时对模型进行居中处理:

# 模型居中,确保在相机视野内
mesh.translate(-mesh.get_center())
# 设置相机外参:相机位于世界坐标系(0,0,2)位置,看向原点
extrens_ = np.array([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 2],  # 相机沿Z轴后移2单位
    [0, 0, 0, 1]
])

2. 深度值单位处理错误

代码中t_hit.numpy() / 1000.0的缩放可能不符合模型实际单位。先查看模型尺寸确认单位:

print("模型包围盒尺寸:", mesh.get_axis_aligned_bounding_box().get_extent())

若模型单位为米,则无需除以1000;若为毫米,再保留缩放。

3. Matplotlib可视化参数不合理

默认的颜色映射和范围设置会导致有效深度值被压缩,看起来全黑。

修复:设置合适的颜色范围和颜色映射:

# 过滤无效深度值(t_hit为0表示未击中,设为NaN便于可视化)
valid_depth = rendered_depth[~np.isnan(rendered_depth)]
if len(valid_depth) == 0:
    print("未检测到有效深度值")
else:
    plt.imshow(rendered_depth, cmap='jet', vmin=np.min(valid_depth), vmax=np.max(valid_depth))
    plt.colorbar(label='Depth (m)')
    plt.show()

完整修复后的代码

#!/usr/bin/env python3

import numpy as np
import open3d as o3d
import matplotlib.pyplot as plt


def render_depth(
    intrins: o3d.core.Tensor,
    width: int,
    height: int,
    extrins: o3d.core.Tensor,
    tmesh: o3d.t.geometry.TriangleMesh
) -> np.ndarray:
    """
    Render depth from mesh file

    Parameters
    ----------
    intrins : o3d.core.Tensor
        Camera Intrinsics matrix K: 3x3
    width : int
        image width
    height : int
        image height
    extrins : o3d.core.Tensor
        camera extrinsics matrix 4x4 (camera to world)
    tmesh : o3d.t.geometry.TriangleMesh
        TriangleMesh

    Returns
    -------
    np.ndarray
        Rendered depth image
    """
    scene = o3d.t.geometry.RaycastingScene()
    scene.add_triangles(tmesh)
    
    rays = scene.create_rays_pinhole(
        intrinsic_matrix=intrins,
        extrinsic_matrix=extrins,
        width_px=width, height_px=height
    )
    
    ans = scene.cast_rays(rays)
    # 根据模型单位调整缩放,此处假设模型单位为米,无需缩放
    t_hit = ans["t_hit"].numpy()
    # 将未击中的深度值设为NaN,便于可视化过滤
    t_hit[t_hit == 0] = np.nan

    return t_hit


if __name__ == "__main__":
    import os
    mesh_path = f"{os.getenv('HOME')}/bbq_sauce.ply"
    mesh = o3d.t.io.read_triangle_mesh(mesh_path)
    mesh.compute_vertex_normals()
    
    # 模型居中,确保在相机视野内
    mesh.translate(-mesh.get_center())
    # 查看模型尺寸,确认单位
    print("模型包围盒尺寸:", mesh.get_axis_aligned_bounding_box().get_extent())
    
    # 相机内参
    intrins_ = np.array([
            [606.9275512695312, 0.0, 321.9704895019531],
            [0.0, 606.3505859375, 243.5377197265625],
            [0.0, 0.0, 1.0]
            ])
    width_  = 640
    height_ = 480
    
    # 相机外参:相机位于(0,0,2),看向原点
    extrens_ = np.array([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 2],
        [0, 0, 0, 1]
    ])
    
    intrins_t = o3d.core.Tensor(intrins_)
    extrins_t = o3d.core.Tensor(extrens_)
    
    rendered_depth = render_depth(
        intrins=intrins_t, 
        width=width_, 
        height=height_, 
        extrins=extrins_t, 
        tmesh=mesh
    )
    
    # 可视化深度图
    valid_depth = rendered_depth[~np.isnan(rendered_depth)]
    if len(valid_depth) == 0:
        print("未检测到有效深度值,请检查相机外参和模型位置")
    else:
        plt.imshow(rendered_depth, cmap='jet', vmin=np.min(valid_depth), vmax=np.max(valid_depth))
        plt.colorbar(label='Depth (m)')
        plt.title('Rendered Depth Map')
        plt.show()

额外说明

  • 若模型尺寸过大或过小,可通过mesh.scale()调整缩放比例,确保模型在相机视锥内。
  • Open3D的RaycastingScene中,t_hit的值为射线原点到击中面的距离,单位与模型顶点坐标单位一致。

内容的提问来源于stack exchange,提问作者bhomaidan90

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 00:07:02