Python 3.x 在给定点坐标和相机外部/内部坐标的情况下,哪个openCv函数可用于计算BEV透视变换?

Python 3.x 在给定点坐标和相机外部/内部坐标的情况下,哪个openCv函数可用于计算BEV透视变换?,python-3.x,matrix,computer-vision,cv2,camera-calibration,Python 3.x,Matrix,Computer Vision,Cv2,Camera Calibration,我有通过cv2.CalibleCamera()获得的相机的3x3intrinsics和4x3extrinsics矩阵 现在我想使用这些参数来计算从相机获得的帧中任何给定坐标的BEV(鸟瞰图)变换 哪个openCv函数可用于计算给定点坐标的BEV透视变换,以及相机外部和/或内部3x3矩阵 我在下面的帖子中发现了一些非常相关的东西:https://deepnote.com/article/social-distancing-detector/基于https://www.pyimagesearch.c

我有通过cv2.CalibleCamera()获得的相机的
3x3
intrinsics
4x3
extrinsics
矩阵

现在我想使用这些参数来计算从相机获得的帧中任何给定坐标的
BEV(鸟瞰图)
变换

哪个
openCv
函数可用于计算给定点坐标的
BEV
透视变换,以及相机
外部
和/或
内部
3x3矩阵

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

他们正在使用
cv2.getPerspectiveTransform()
来获得
3X3矩阵
,但我不知道这个矩阵是表示
内部
外部
还是其他什么。然后,他们通过以下方式使用该矩阵变换点列表:

#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
函数来计算转换,或者是否有其他更好的方法来使用
外部
内部
或两者,而不必重用帧,因为我已经将检测到的/选定的坐标保存在一个数组中。

答案是:如果没有图像像素的距离相关信息,就不可能计算场景的BEV

想一想:想象你有一个垂直屏幕的图片:鸟瞰图将是一条线。现在假设这个屏幕显示的是一幅风景画,并且这个屏幕上的图片与风景画本身是无法区分的。BEV仍然是一条线(尽管是彩色的)

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

最后,请允许我声明,OpenCV无法知道您的图片是否正在描述其他物体的平面(即使给定摄影机参数),因此,它无法计算场景的BEV。函数
cv2.perspectiveTransform
需要您向其传递一个单应矩阵(您可以使用
cv2.findHomography()
获得一个单应矩阵,但您还需要一些有关图像的距离信息)


很抱歉回答为否定,但鉴于相机的内在和外在校准矩阵,无法解决您的问题。

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

投影矩阵
外部
内部
摄像机矩阵之间的乘法

  • 由于
    外部
    4x3
    矩阵,而
    内部
    3x3
    矩阵,但我们需要
    投影矩阵
    3x3
    矩阵,因此我们需要在执行乘法之前将
    外部
    转换为
    3x3
cv2.getPerspectiveTransform()
在我们没有摄像机参数的情况下为我们提供了
投影矩阵

cv2.warpPerspective()

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

考虑到上述内容,我编写了一个函数,将
BEV
转换为一个点列表
list\u x\u y
,给定
intrinsics
extrinsics

    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]

如果您至少有3个点的3D坐标(我认为您只需要3个,但越多越好),那么您应该能够使用
cv2.findHomography
完成此操作。它没有什么技术性,所以我建议你找一些教程。我记得我在那里发现了一些非常有趣的东西:)例如,如果你的图片代表一个斜面(我认为道路足够像这样平面),我认为本教程将帮助你:非常感谢你的时间。每个点都有
x
y
width
height
。我想这行得通。不客气!祝你好运(顺便说一句,如果你能接受我的答案,我将非常感激,谢谢!):)透视变换需要四个点对(两个视图中各有四个点)。我会回答是的,因为如果你把“鸟瞰视图”理解为一个平面到平面的转换,那么getPerspectiveTransform和warpPerspective就可以了。只有在尝试扭曲非平面的3D场景图片时,才会出现故障。可以合理地假设“BEV”意味着映射平面。