基于OpenCV的透视图转化为不同平面
重磅干货,第一时间送达
由于相机技术的进步,相机能够以各种角度和视角拍摄照片。无人机的广角,鸟瞰图,侧视图等不同的角度,鱼眼镜头之类的不同相机镜头将场景投射到相机图像平面上的方式与对象在世界上的实际位置不同。这种现象被称为摄影中的透视变形。
雷梅霍夫写到“镜子中物体的距离小于它们的实际距离”,总是在侧视镜其中大部分是倾斜,稍弯曲。由于这种曲率,我们在镜子中看到的图像中会发生透视失真。
形式上,透视失真是对象及其周围区域的扭曲或变形,由于附近和远处特征的相对比例,该扭曲或变形与对象在正常焦距下的外观明显不同。我们将介绍如何根据给定的2D摄影机图像(在特定的假设下)校正这些变形,以找出物体在世界上的实际位置。
首先,我们必须了解世界上的3d对象如何投影到相机的图像平面上。
从本质上讲,光线是通过相机的针孔投射到物体上的。当从物体反射时,该光会投射在相机内部的图像平面上,并给出倒置的图像。为了获得实际视图,请将该图像平面反转(上图中的虚拟图像平面)。
无需深入研究数学细节,就可以将对象在3d世界中的坐标转换为2d平面平面。
在数学上,将3d坐标乘以3x4矩阵(称为透视矩阵)可得到图像平面中的2d坐标。
使用3x4透视矩阵将3d世界坐标系中的点(x,y,z)转换为2d相机图像平面上的点(u,v)。
但是在这篇文章中,我们想找到一个从2d图像平面到世界坐标的矩阵。直观地讲,这是不可能的,因为在2d图像平面中,我们丢失了深度尺寸,并且在没有任何额外知识的情况下也无法恢复3d尺寸(这就是RGB-D相机退出的原因)。同样在数学上,3x4投影矩阵不是正方形的,因此是不可逆的。
但是,如果我们仅对固定z的对象的(x,y)世界坐标感兴趣,则可以找到这些坐标。例如,如果我们在无人机的顶部有一个安全摄像机,并且我们想从摄像机图像中知道人在地板上的实际位置(将固定z = 0作为地板平面),则有可能有两种方法可以做到这一点:
如果需要(x,y)世界坐标的平面在系统的z = 0处,则地板平面上的任何点都将具有坐标<x,y,0>,这有效地消除了第三个坐标的影响透视矩阵从等式1开始的一列。现在,透视矩阵P可以简化为3x3矩阵,因此变为可逆的(如下所示)。
现在要从(u,v)得到(x,y),我们只需要找到3x3透视矩阵P的逆,就可以从像平面找到地板平面上的对应点。但是,如果我们想在z不等于0的任意平面上找到(x,y)坐标,该怎么办。我们可以使用Homography来实现这一点。
单应矩阵涉及从一个平面到另一平面的变换。本质上,如果我们在一个平面中具有<u,v>点,而在另一平面中具有<x,y>,则从<u,v>到<x,y>的转换可以写为
但是要获得单应性矩阵,我们必须在一个平面上至少需要4个点,而在另一平面上至少需要它们的映射点。给定透视矩阵P,我们可以轻松找到任意3d世界平面(保持固定的z)和2d平面之间的4个对应点。
在OpenCV中,可以cv2.findHomography通过在源平面和目标平面中提供4个或更多点来使用函数查找单应矩阵。
下面是使用OpenCV的代码。
import cv2
import numpy as np
defget_inverse_pespective(perspective_matrix: np.array)-> np.array:
"""
This method calculates the inverse of prespective matrix by homography.
-Takes 4 random points on the floor plane(destination_plane) and calculates thecorresponding points
onthe camera image plane(src_plane) using perspective matrix.
-Calculates the Homography matrix to map any point in image plane to floorplane.
Parameters
----------
perspective_matrix: 3 x 4 camera prespective matrix to convert 3dhomogeneous world coordinates to
2dhomogeneous camera coordinates.
Returns
----------
3x3homography matrix for moving from 2d homogeneous image plane to world floorplane(at z=0)
"""
#Take 5 homogenous points on the floor(Unit is in Meters)
pts_dst = np.array([[0,0,0,1],
[0,1,0,1],
[1,0,0,1],
[1,1,0,1],
[0,0,0,1]
])
#Obtain respective homogenous points on the image plane
pts_src = (perspective_matrix @ pts_dst.T).T
#convert homogenous coordinates to cartesian coorndinates
pts_src_cart = np.array([[x/w, y/w] for x,y,w in pts_src])
pts_dst_cart = np.array([[x/w, y/w] for x,y,z,w in pts_dst])
#find the 3x3 Homography Matrix for transforming image plane to floorplane
H,status = cv2.findHomography(pts_src_cart, pts_dst_cart)
return H
def project_to_floor(image_coordinates:List[int], H: np.array) -> List[int]:
"""
This method takes the Homography matrix and the 2d image cartesiancoordinates. It returns the (x, y)
cartesian coordinates in 3d cartesian world coordinates on floorplane(at z=0). Notice that z coordinate is omitted
here and added inside the tracking funtion.
Parameters
----------
image_coordinates: 2d pixel coordinates (x,y)
h:3x3 Homography matrix np.array[3x3]
Returns
----------
floor_coordinates: List of x, y coordinates in 3d world of same pixel onfloor plane i.e. (x,y,z) Considering z=0 and
ommitted here.
"""
#adding 1 for homogenous coordinate system
x,y, w = H @ np.array([[*image_coordinates, 1]]).T
return [x/w, y/w]
p = np.random.rand(3,4)
H = get_inverse_pespective(p)
src_point = (5,10)
dst_point = project_to_floor(src_point, H)
一旦获得了单应性矩阵,就可以使用等式2从像平面移动到所需平面。这些方法并不暗示有关世界坐标系中沿z轴的位置的任何信息,并认为它是固定的。
需要注意:
1.对于在世界坐标中从“图像”平面到固定平面的“透视”转换,可以使用两种方法。
2.如果平面方程为z = 0,则可以通过完全忽略第3列将3x4透视矩阵简化为3x3矩阵,并且可以使用此3x3矩阵的逆矩阵。
3.对于任何其他任意平面,应使用单应性矩阵。为了找到单应矩阵,该cv.findhomography方法在两个平面中至少需要4个对应点。