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,随后又对整个深度图做归一化(除以max_depth),这会把原本缺失深度的无效点强制转换成有效深度值,这些点计算出的3D坐标不符合真实场景,重投影后会出现异常偏移,进而导致畸变线。重投影赋值逻辑完全错误:
合成图像时,用重投影得到的坐标(x,y)去读取原图像的left_image[y,x]再赋值给synthesized_image[y,x],等同于直接复制原图像的对应像素,完全没有利用重投影的对应关系(原像素(u,v)对应重投影后的(x,y),应该把left_image[v,u]赋值给synthesized_image[y,x])。当前逻辑下,只有深度异常的点被跳过,才会出现空白的畸变线。循环索引混淆+效率低下:
嵌套循环遍历像素时,容易混淆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
相关产品推荐
相关产品推荐

