如何从深度图像和边界框创建 OrientedBoundingBox

How to create an OrientedBoundingBox from Depth image and bounding box

提问人:bhomaidan90 提问时间:10/25/2023 最后编辑:bhomaidan90 更新时间:10/26/2023 访问量:79

问:

我想使用分段蒙版(矩形)和深度图像裁剪 poincloud,(我可以认为现在没有旋转)。

import open3d as o3d

## dummy pointcloud
demo_icp_pcds = o3d.data.DemoICPPointClouds()
pcd = o3d.io.read_point_cloud(demo_icp_pcds.paths[0])

## dummy depth mask
depth_mask = np.ones((640, 480), dtype=np.uint8)

## Crop PCD

## mask boundaries: [(xmin, xmax), (y_min, y_max)]
rect = [(20, 50), (70, 75)]

o_box = o3d.geometry.OrientedBoundingBox()
o_box.center = [0.0, 0.0, 0.0]
o_box.extent = [1.0, 2.0, 3.0]
o_box.R = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]

cropped_pcd = pcd.crop(o_box)

我想将矩形 (x, y) 和深度 z 的信息提供给 orietned 边界框。谁能告诉我怎么做?谢谢。

Python 几何体 裁剪 点云 Open3D

评论

0赞 saurabheights 10/25/2023
这里有很多问题。为什么你认为你可以从图像中制作一个定向边界框?o3d.geometry.OrientedBoundingBox(depth_mask)
0赞 bhomaidan90 10/25/2023
@saurabheights可能不是,但是我如何使用深度蒙版裁剪点云呢?任何建议都是值得赞赏的。
0赞 saurabheights 10/26/2023
首先,定义什么是根据深度图像均值裁剪点云。这句话没有任何意义。
1赞 saurabheights 10/26/2023
我会在下班后检查,但在那之前只是提出一个问题 - 为什么要使用而不是?o3d.geometry.OrientedBoundingBoxo3d.geometry.AxisAlignedBoundingBox
0赞 bhomaidan90 10/26/2023
@saurabheights我对 Open3D 不太熟悉,这就是我选择面向 Open3D 的原因。

答:

0赞 bhomaidan90 10/26/2023 #1

这是我的解决方案供参考:

def obbs_from_depth_mask(
    depth: np.ndarray, rects: List[List]
) -> List[o3d.geometry.OrientedBoundingBox]:
    obbs = []
    for rect in rects:
        obb = o3d.geometry.OrientedBoundingBox()
        ## [xmin, xmax, ymin, ymax]
        x_min = rect[0]
        y_min = rect[2]
        z_min = depth[y_min, x_min]
        ##
        x_max = rect[1]
        y_max = rect[3]
        z_max = depth[y_max, x_max]

        center = [
            (x_min + x_max) / 2,
            (y_min + y_max) / 2,
            (z_min + z_max) / 2,
        ]
        extent = [
            math.abs(x_max - x_min),
            math.abs(y_max - y_min),
            math.abs(z_max - z_min),
        ]
        ## Get rotation
        P1= np.array([x_min, y_min, z_min])
        P2= np.array([x_max, y_max, z_max])
        D = P2 - P1
        U = D / np.linalg.norm(D)
        X = np.array([1, 0, 0])
        V = np.cross(U, X)
        if np.linalg.norm(V) == 0:
            X = np.array([0, 1, 0])
            V = np.cross(U, X)
        rotation_matrix = np.column_stack((U, V, X))
        obb.center = center
        obb.extent = extent
        obb.R = rotation_matrix
        obbs.append(obb)

    return obbs

评论

1赞 saurabheights 10/26/2023
您应该删除此代码。 不正确。并使用 obb 等类的构造函数正确初始化,以后不要更改这些值。obb.extent = half_extent
1赞 saurabheights 10/26/2023
另外,我希望不是像素位置,而是相机坐标系中反向投影位置的位置。xmin, xmax, ymin, ymax
0赞 bhomaidan90 10/26/2023
@saurabheights感谢您的注意,我已经将其修复到全部而不是一半
1赞 saurabheights 10/26/2023 #2

如果您的裁剪体积是长方体并与 x,y,z 轴对齐的轴对齐,则使用轴对齐的边界框进行裁剪要容易得多。无论如何,以旋转为标识的定向边界框是等价的。有关裁剪示例,请参阅以下代码。

import open3d as o3d

lower_b = [-2.0, -2.0, 1.0]
upper_b = [4.0, 2.0, 2.0]
bbox = o3d.geometry.AxisAlignedBoundingBox(min_bound=lower_b, max_bound=upper_b)
bbox.color = [0.46, 0.32, 1.0]
print(bbox, bbox.get_extent(), bbox.volume(), bbox.color)

ply_point_cloud = o3d.data.PLYPointCloud()
pcd = o3d.io.read_point_cloud(ply_point_cloud.path)

origin = o3d.geometry.TriangleMesh.create_coordinate_frame(size=1, origin=[0, 0, 0])
o3d.visualization.draw_geometries([origin, bbox, pcd],
                                  zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])
pcd1 = pcd.crop(bbox)
o3d.visualization.draw_geometries([origin, bbox, pcd1],
                                  zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])

obbox = o3d.geometry.OrientedBoundingBox(center=[2.0, 1.0, 1.5], extent=[1.0, 2.0, 3.0],
                                         R=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
pcd2 = pcd.crop(obbox)
obbox.color = [0.46, 0.32, 1.0]
o3d.visualization.draw_geometries([origin, obbox, pcd],
                                  zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])
o3d.visualization.draw_geometries([origin, obbox, pcd2],
                                  zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])

另外,请遵循 2 个提示:-

  • 添加坐标轴,用于可视化 x、y、z 轴。XYZ = RGB,即红轴为 X。
  • 展示台的背景是白色的,不幸的是,边界框的默认颜色是白色。我正在尝试改变这一点,但最终决定将取决于 repo 维护者。

此外,如果使用轴对齐的边界框,请小心。确保在所有三个轴上都min_bound < max_bound。这已经由我最近的 PR 修复 - https://github.com/isl-org/Open3D/pull/6444,但是更改仅在开发版本中可用。