给定点坐标和相机 extrinsics/intrinsics,哪个 openCv 函数可用于计算 BEV 透视变换?

Which openCv function can be used to compute BEV perspective transformation given a point coordinates and the camera extrinsics/intrinsics?

我有 3x3 intrinsics4x3 extrinsics 矩阵通过 cv2.calibrateCamera()

获得我的相机

现在我想使用这些参数为从相机获得的帧中的任何给定坐标计算 BEV (Bird Eye View) 变换。

哪个openCv函数可用于计算给定点坐标和相机的BEV透视变换extrinsicsand/orintrinsics3x3 matrices?

我在以下 post 中发现了一些非常相关的内容:https://deepnote.com/article/social-distancing-detector/ 基于 https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/

他们正在使用 cv2.getPerspectiveTransform() 得到一个 3X3 matrix,但我不知道这个矩阵是否代表 intrinsicsextrinsecs 或其他。然后他们通过以下方式使用此类矩阵转换点列表:

#Assuming list_downoids is the list of points to be transformed and matrix is the one obtained above
list_points_to_detect = np.float32(list_downoids).reshape(-1, 1, 2)
transformed_points = cv2.perspectiveTransform(list_points_to_detect, matrix)

我真的很想知道我是否可以使用这个 cv2.perspectiveTransform 函数来计算转换,或者是否有另一种更好的方法来使用 extrinsicsintrinsics 或两者,无需重复使用框架,因为我已经将 detected/selected 坐标保存在数组中。

答案是:如果没有关于图像像素的距离相关信息,则无法计算场景的 BEV。

想一想:假设您有一个垂直屏幕的图片:鸟瞰图将是一条线。现在假设这个屏幕显示的是风景图像,并且这个屏幕的图片与风景图片本身没有区别。 BEV 仍然是一条线(虽然是彩色的)。

现在,假设您有完全相同的图片,但这次不是屏幕图片,而是风景图片。然后,鸟瞰图不是一条线,更接近我们通常想象的BEV。

最后,让我声明 OpenCV 无法知道您的图片是否描述了其他东西的平面(即使给定相机参数),因此,它 无法 计算场景的 BEV。函数 cv2.perspectiveTransform 需要你传递给它一个 homography 矩阵(你可以使用 cv2.findHomography() 获得一个矩阵,但你还需要一些关于你的图像的距离信息) .

很抱歉给出否定的答案,但仅考虑相机的内部和外部校准矩阵,无法解决您的问题。

经过深入调查,我找到了一个很好的解决方案:

projection matrixextrinsicintrinsic 相机矩阵之间的乘积

当我们没有相机参数时,

cv2.getPerspectiveTransform() 给我们 Projection Matrix

cv2.warpPerspective() 变换图像本身。

对于上面的问题,我们不需要这两个函数,因为我们已经有了extrinsicsintrinsecs和图像中点的坐标。

考虑到上面的内容,我写了一个函数来转换成 BEV 一个点列表 list_x_y 给定 intrinsicsextrinsics:

    def compute_point_perspective_transformation(intrinsics, extrinsics, point_x_y):
    """Auxiliary function to project a specific point to BEV
        
        Parameters
        ----------
        intrinsics (array)     : The camera intrinsics matrix
        extrinsics (array)     : The camera extrinsics matrix
        point_x_y (tuple[x,y]) : The coordinates of the point to be projected to BEV
        
        Returns
        ----------
        tuple[x,y] : the projection of the point
    """
        # Using the camera calibration for Bird Eye View
        intrinsics_matrix = np.array(intrinsics, dtype='float32')
        #In the intrinsics we have parameters such as focal length and the principal point

        extrinsics_matrix = np.array(extrinsics, dtype='float32')
        #The extrinsic matrix stores the position of the camera in global space
        #The 1st 3 columns represents the rotation matrix and the last is a translation vector
        extrinsics = extrinsics[:, [0, 1, 3]]

        #We removed the 3rd column of the extrinsics because it represents the z coordinate (0)
        projection_matrix = np.matmul(intrinsics_matrix, extrinsics_matrix)

        # Compute the new coordinates of our points - cv2.perspectiveTransform expects shape 3
        list_points_to_detect = np.array([[point_x_y]], dtype=np.float32)
        transformed_points = cv2.perspectiveTransform(list_points_to_detect, projection_matrix)
        return transformed_points[0][0][0], transformed_points[0][0][1]

由于您拥有相机型号,现成(但不完整)的解决方案是使用 getTopViewOfImage function from the camera transform library