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

2D-3D-2D重投影出现畸变线问题技术求助

问题排查与修正

问题描述

我有一张图像、对应的深度图和相机内参矩阵K,正在用相机矩阵公式执行2D到3D的重投影操作。为验证重投影正确性,我将得到的3D点重新投影回2D,但生成的图像出现大量横竖畸变线。怀疑这与深度图中的0值有关,但无法确定,恳请协助排查。

原代码

import numpy as np
import cv2

# Load depth map
left_depth_map = np.loadtxt('Photometric_Stereo\\data\\example\\depth_left.txt', delimiter=',')

# Find the maximum depth value
max_depth = np.max(left_depth_map)

# Replace the missing depth values with zero
left_depth_map[left_depth_map < 1] = 1

# Normalize the depth map to the range [0, 1]
left_depth_map /= max_depth

# Define camera intrinsic matrix K
K = np.array([[576, 0, 511.5],
              [0, 576, 217.5],
              [0, 0, 1]])

# Initialize empty arrays for 3D points and corresponding 2D points
points_3d = []
points_2d = []

# Perform 2D-3D reprojection
height, width = left_depth_map.shape
for v in range(height):
    for u in range(width):
        depth = left_depth_map[v, u]
        if depth > 0:
            point_3d = np.linalg.inv(K) @ np.array([u, v, 1]) * depth
            point_2d = K @ (point_3d / point_3d[2])
            points_3d.append(point_3d)
            points_2d.append(point_2d[:2])

# Convert the lists of points to NumPy arrays
points_3d = np.array(points_3d)
points_2d = np.array(points_2d)

# Perform 3D-2D reprojection
reprojected_2d = []
for i in range(points_3d.shape[0]):
    point_2d = K @ (points_3d[i] / points_3d[i, 2])
    reprojected_2d.append(point_2d[:2])
reprojected_2d = np.array(reprojected_2d)

# Load the original image
left_image = cv2.imread('Photometric_Stereo\\data\\example\\im_left.jpg')

# Create a blank image with the same size and channels as the original image
synthesized_image = np.zeros_like(left_image)

# Copy RGB values from the original image to the synthesized image based on the reprojected 2D coordinates
for i, point in enumerate(reprojected_2d):
    x, y = point.astype(int)
    if 0 <= x < synthesized_image.shape[1] and 0 <= y < synthesized_image.shape[0]:
        synthesized_image[y, x] = left_image[y, x]

# Display the synthesized image
cv2.imshow("Synthesized Image", synthesized_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

相关图像

  • 原图像:
    原图像

  • 深度图:
    深度图

  • 重投影生成图像:
    重投影生成图像

问题根源分析

  1. 深度图处理逻辑矛盾:
    先将所有小于1的深度值设为1,随后又对整个深度图做归一化(除以max_depth),这会把原本缺失深度的无效点强制转换成有效深度值,这些点计算出的3D坐标不符合真实场景,重投影后会出现异常偏移,进而导致畸变线。

  2. 重投影赋值逻辑完全错误:
    合成图像时,用重投影得到的坐标(x,y)去读取原图像的left_image[y,x]再赋值给synthesized_image[y,x],等同于直接复制原图像的对应像素,完全没有利用重投影的对应关系(原像素(u,v)对应重投影后的(x,y),应该把left_image[v,u]赋值给synthesized_image[y,x])。当前逻辑下,只有深度异常的点被跳过,才会出现空白的畸变线。

  3. 循环索引混淆+效率低下:
    嵌套循环遍历像素时,容易混淆u(图像宽度方向,对应x轴)和v(图像高度方向,对应y轴)的索引关系,且循环处理单像素的方式效率极低,还容易引入人为错误。

修正后的代码

import numpy as np
import cv2

# 加载深度图与原图像
left_depth_map = np.loadtxt('Photometric_Stereo\\data\\example\\depth_left.txt', delimiter=',')
left_image = cv2.imread('Photometric_Stereo\\data\\example\\im_left.jpg')
height, width = left_depth_map.shape

# 过滤无效深度值(保留大于等于1的有效深度,避免强制赋值无效值)
valid_mask = left_depth_map >= 1
depth_valid = left_depth_map[valid_mask]

# 生成所有有效像素的2D坐标 (u, v)
u_coords, v_coords = np.meshgrid(np.arange(width), np.arange(height))
u_valid = u_coords[valid_mask]
v_valid = v_coords[valid_mask]

# 相机内参矩阵K
K = np.array([[576, 0, 511.5],
              [0, 576, 217.5],
              [0, 0, 1]])
K_inv = np.linalg.inv(K)

# 批量计算2D到3D坐标
# 构造齐次坐标 [u, v, 1],形状为(3, N)
hom_2d = np.stack([u_valid, v_valid, np.ones_like(u_valid)], axis=0)
points_3d = (K_inv @ hom_2d) * depth_valid  # 形状(3, N)
points_3d = points_3d.T  # 转为(N, 3)方便后续操作

# 批量执行3D到2D重投影
hom_3d = points_3d.T  # (3, N)
hom_3d /= hom_3d[2, :]  # 归一化z分量
reprojected_hom = K @ hom_3d
reprojected_2d = reprojected_hom[:2, :].T  # (N, 2),得到重投影后的(x, y)

# 生成合成图像
synthesized_image = np.zeros_like(left_image)
# 将原图像的有效像素赋值到重投影后的坐标位置
x_reproj = reprojected_2d[:, 0].astype(int)
y_reproj = reprojected_2d[:, 1].astype(int)
# 过滤掉超出图像范围的坐标
valid_reproj_mask = (x_reproj >= 0) & (x_reproj < width) & (y_reproj >= 0) & (y_reproj < height)
# 赋值
synthesized_image[y_reproj[valid_reproj_mask], x_reproj[valid_reproj_mask]] = left_image[v_valid[valid_reproj_mask], u_valid[valid_reproj_mask]]

# 显示结果
cv2.imshow("Corrected Synthesized Image", synthesized_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

修正说明

  • 保留深度图中有效深度值(>=1),直接过滤无效值,避免强制赋值带来的错误3D点。
  • 改用向量运算批量处理所有像素,提升效率的同时避免索引混淆。
  • 修正重投影赋值逻辑:将原图像中(u,v)位置的像素,赋值给合成图像中重投影后的(x,y)位置,真正体现重投影的对应关系。
  • 增加坐标有效性过滤,避免超出图像范围的赋值操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:15:16