2

我正在尝试使用 Python 和 OpecCV 从两个图像中进行 3D 人脸重建。我设法使用此处链接中的指令执行相机校准,然后应用cv2.stereoCalibrate()cv2.stereoRectify()。之后,cv2.StereoSGBM用于计算视差图,最后cv2.reprojectImageTo3D用于生成点云。后者使用open3d库显示。但是,结果StereoSGBM.compute()非常嘈杂,生成的点云看起来不像它应该的那样。

我尝试过的事情:

  • 对视差图进行归一化:该算法输出一个二维数组,其值介于 -16 和 240 之间,因此我将其分别调整为 0 和 255 之间以及 0.0 和 1.0 之间。第一个选项更好
  • 将值除以 16(正如我在 C++ 实现中看到的那样)
  • 调整 StereoSGBM 的参数。我什至建立了一个 GUI 来调整参数,但结果仍然不令人满意
  • 使用 StereoBM,但没有太大区别
  • 使用不同的测试图像
  • 使用灰度图像
  • 将它们标准化在 0.0 -> 1.0 范围内
  • 裁剪未失真的图像
  • 重新实现cv2.reprojectImageTo3D,结果相同
  • 手动移除视差图中的背景
  • 使用 uint8 和 float32。使用浮点数重新投影效果更好

结果图像:

  • 最初的:
    左图 右图

  • 校准后:
    不失真的左 不失真的权利

  • 视差图(右侧的参数):
    差距 参数

  • 点云(从一个非常特定的角度看起来像人类):
    点云

我该怎么做才能获得可用的结果?我什至不知道图像应该是什么样子。我的校准似乎关闭了吗?我觉得图像真的很糟糕(因为透视失真很大),但不幸的是我必须处理这些

一些代码存根:

_, self.camera_matrix, self.distortion, _, _ = \
            cv2.calibrateCamera(self.object_points, self.image_points, self.image_size, None, None)

error, _, _, _, _, self.rotation, self.translation, _, _ = \
            cv2.stereoCalibrate(self.camera_left.object_points,
                                self.camera_left.image_points,
                                self.camera_right.image_points,
                                self.camera_left.camera_matrix,
                                self.camera_left.distortion,
                                self.camera_right.camera_matrix,
                                self.camera_right.distortion,
                                self.camera_left.image_size,
                                flags=cv2.CALIB_FIX_INTRINSIC)

self.rotation_left, self.rotation_right, self.perspective_left, self.perspective_right, self.Q, self.roi_left, self.roi_right = \
            cv2.stereoRectify(self.camera_left.camera_matrix,
                              self.camera_left.distortion,
                              self.camera_right.camera_matrix,
                              self.camera_right.distortion,
                              self.camera_left.image_size,
                              self.rotation,
                              self.translation,
                              flags=cv2.CALIB_ZERO_DISPARITY)

self.rotation_left, self.rotation_right, self.perspective_left, self.perspective_right, self.Q, self.roi_left, self.roi_right = \
            cv2.stereoRectify(self.camera_left.camera_matrix,
                              self.camera_left.distortion,
                              self.camera_right.camera_matrix,
                              self.camera_right.distortion,
                              self.camera_left.image_size,
                              self.rotation,
                              self.translation,
                              flags=cv2.CALIB_ZERO_DISPARITY)

self.block_matching = cv2.StereoSGBM().create() # params not mentioned here, but they are set
disparity = self.block_matching.compute(undistorted_left, undistorted_right)
disparity = cv2.convertScaleAbs(disparity, beta=16)

point_cloud = cv2.reprojectImageTo3D(disparity_image, Q)
point_cloud = point_cloud.reshape(-1, point_cloud.shape[-1])
point_cloud = point_cloud[~np.isinf(point_cloud).any(axis=1)]

pcl = open3d.geometry.PointCloud()
pcl.points = open3d.utility.Vector3dVector(point_cloud)
open3d.visualization.draw_geometries([pcl])
4

0 回答 0