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

如何移除三维重建点云中的黑色背景(OpenCV Python场景)

移除三维重建点云中的黑色遮罩

问题描述

我用Python结合OpenCV做三维重建,已经完成了官网步骤里的:

  • 单目和双目相机标定
  • 姿态估计
  • 极线几何计算
  • 从双目图像生成深度图
    最终得到了点云。我已经移除了原始图像的背景,但加载点云时还是能看到黑色遮罩,想只保留有球体的纸张工作区域,怎么移除点云中的黑色遮罩?

相关代码:

def get_3D_points(self, disparityMap, K1, K2, P2, t=np.array([0.0, 0.0, 0.0])):
    b = get_baseline(P2=P2)
    (
        C1,
        C2,
    ) = get_centers(P2, prnt=True)
    print(" -- baseline {0}".format(b))
    print("C1", C1)
    print("C2", C2)

    fx = K1[0, 0]
    fy = K2[1, 1]
    cx1 = K1[0, 2]
    cx2 = K2[0, 2]
    a1 = K1[0, 1]
    a2 = K2[0, 1]
    cy = K1[1, 2]

    Q = np.float64(
        [
            [1, 0, 0, -cx1],
            [0, 1, 0, -cy],
            [0, 0, 0, fx],
            [0, 0, -1 / t[0], (cx1 - cx2) / t[0]],
        ]
    )

    print("Q\n", Q)

    return cv2.reprojectImageTo3D(disparityMap, Q)


def filter_infinity(self, depth, filter):
    """Filter infinite distances from ``PointCloud.``"""
    # filter inf. points
    mask = depth > filter
    coords = self.vertices[mask]
    colors = self.colors[mask]

    mask = coords[:, 2] > coords[:, 2].min()
    coords = coords[mask]
    colors = colors[mask]
    return PointCloud(coords, colors)

解决方案

黑色遮罩对应的是背景区域的无效点,这些点要么颜色为纯黑、要么深度值异常,可从以下几个方向处理:

1. 基于颜色过滤黑色点

原始图像的黑色遮罩区域,对应点云的颜色也是纯黑(RGB值均为0),直接过滤这类点即可。修改你的filter_infinity函数,加入颜色过滤逻辑:

def filter_infinity_and_black(self, depth, filter):
    """过滤无穷远点和黑色遮罩点"""
    # 过滤无穷远点
    mask_depth = depth > filter
    # 过滤纯黑色点(RGB均为0),若遮罩有噪点可改成sum<10这类宽松条件
    mask_black = ~((self.colors[:,0] == 0) & (self.colors[:,1] == 0) & (self.colors[:,2] == 0))
    # 合并两个过滤条件
    mask = mask_depth & mask_black
    
    coords = self.vertices[mask]
    colors = self.colors[mask]

    # 过滤异常深度最小值
    mask_depth_valid = coords[:, 2] > coords[:, 2].min()
    coords = coords[mask_depth_valid]
    colors = colors[mask_depth_valid]
    return PointCloud(coords, colors)

2. 基于空间范围过滤

纸张工作区域的深度值通常比背景更集中,你可以先打印点云的深度统计值(比如print(coords[:,2].min(), coords[:,2].max(), coords[:,2].mean())),确定纸张的深度范围后,直接过滤超出范围的点:

# 在现有过滤逻辑后加入
min_depth = 0.5  # 示例值,根据实际情况调整
max_depth = 1.2  # 示例值,根据实际情况调整
mask_depth_range = (coords[:,2] > min_depth) & (coords[:,2] < max_depth)
coords = coords[mask_depth_range]
colors = colors[mask_depth_range]

3. 复用原始图像的前景掩码

如果你在移除原始图像背景时,已经得到了工作区域的二值掩码(前景为1,背景为0),可以直接把这个掩码映射到点云上:

# 假设mask_image是和原始图像同尺寸的二值前景掩码
mask_flat = mask_image.flatten()
# 只保留掩码为1的点
coords = self.vertices[mask_flat == 1]
colors = self.colors[mask_flat == 1]

这个方法最精准,直接复用你之前的背景分割结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:10:54