任意旋转角度下的透视变换

5
我有一张以某个角度拍摄的棋盘图像。现在我想进行透视变换,使得棋盘图像看起来就像是从正上方拍摄的一样。
我知道我可以尝试使用匹配点之间的'findHomography'方法,但我想避免它,并使用移动传感器的旋转数据等信息来构建自己的单应矩阵。我校准了我的相机以获取内部参数。然后假设以下图像以大约60度角度围绕x轴拍摄。我认为我要做的就是将相机矩阵乘以旋转矩阵,以获得单应矩阵。我尝试使用以下代码,但似乎我没有正确理解某些内容,因为结果图像完全是黑色或白色的。
import cv2
import numpy as np
import math 



camera_matrix = np.array([[ 5.7415988502105745e+02, 0., 2.3986181527877352e+02],
                           [0., 5.7473682183375217e+02, 3.1723734404756237e+02], 
                           [0., 0., 1.]])

distortion_coefficients = np.array([ 1.8662919398453856e-01, -7.9649812697463640e-01,
   1.8178068172317731e-03, -2.4296638847737923e-03,
   7.0519002388825025e-01 ])

theta = math.radians(60)

rotx = np.array([[1, 0, 0],
               [0, math.cos(theta), -math.sin(theta)],
               [0, math.sin(theta), math.cos(theta)]])   



homography = np.dot(camera_matrix, rotx)


im = cv2.imread('data/chess1.jpg')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

im_warped = cv2.warpPerspective(gray, homography, (480, 640), flags=cv2.WARP_INVERSE_MAP)
cv2.imshow('image', im_warped)
cv2.waitKey()
pass

我已经进行了校准,得到了畸变系数(distortion_coefficients)。如何将其融入代码中以改善结果?
3个回答

3

这个答案非常晚,已经过去好几年了,但在这里 ...

(免责声明:本答案中使用的术语可能不精确或不正确。请从其他更可靠的来源查阅此主题。)


记住:

  • 因为你只有一个图像(视图),所以你只能计算2D同态(在两个2D视图之间的透视对应关系),而不能计算完整的3D同态。
  • 因此,对于3D同态的良好直观理解(旋转矩阵、平移矩阵、焦距等),你是没有的。
  • 我们所说的是,使用2D同态无法将3x3矩阵分解为诸如3D同态的这些漂亮的直观组件。
  • 你只有一个矩阵 - (这是数个你不知道的矩阵的乘积) - 就是这样。

然而,

OpenCV提供了一个getPerspectiveTransform函数,用于解决两个平面四边形之间的2D同态的3x3透视矩阵(使用齐次坐标系统)。

链接到文档

要使用此函数,

  • 找到图像上棋盘的四个角落。 这些将是您的源坐标。
  • 提供您选择的四个矩形角落。 这些将是您的目标坐标。
  • 将源坐标和目标坐标传递到getPerspectiveTransform中,生成一个能够消除您的棋盘至正立矩形的3x3矩阵。

记住的注意事项:

  • 注意四个角落的排序。

    • 如果顺时针顺序选择源坐标,则目标也需要按顺时针顺序选择。
    • 同样,如果使用逆时针顺序,请始终如一地进行处理。
    • 同样,如果使用z顺序(左上,右上,左下,右下),请始终如一地进行处理。
    • 未能一致排序角落将生成执行点对点对应关系的矩阵(从数学上讲),但不会生成可用的输出图像。
  • 目标矩形的纵横比可以任意选择。 实际上,不可能推断出物体在世界坐标中的“原始纵横比”,因为“这是2D同态而不是3D”


1
一个问题是,要通过相机矩阵进行乘法运算,您需要一些关于z坐标的概念。在考虑畸变系数之前,您应该先让基本的图像扭曲(给定欧拉角)正常工作。请查看this答案,以获得稍微详细的解释,并尝试复制我的结果。将图像沿z轴向下移动,然后使用相机矩阵进行投影的想法可能会令人困惑,请告诉我其中任何部分不清楚的地方。

谢谢,这让我更好地理解了,但我仍然有两个问题:1)在#2中,“将图像置于原点中心”是否必要?我们所说的原点是指图像的中心吗?2)“#4将图像沿z轴向下移动”是什么意思?它是否意味着我们需要从相机到平面的距离?为什么您在示例中使用'image.rows'作为'z'值?这只是硬编码吗?我还阅读了StackExchange上的“逐步相机姿态估计”,但我仍然不明白应该为'Tz'放什么。我可以澄清一下,如果矩形被缩放,我不介意。我只需要矩形的角度为90度。 - pzo
如果您想让透视效果以图像中心为中心,则图像需要在世界空间中居中于0,0,0。 在OpenCV中,原点从左上角开始。 您可以像我一样手动移动它,或者乘以相机矩阵的逆矩阵也可以,并且可能更直观。 这里是另一个解释,它使该理论更加清晰吗? - Hammer

0

您不需要校准相机或估计相机方向(然而,在这种情况下,后者非常容易:只需找到那些正交线束的消失点,并取它们的叉积以找到平面的法线,有关详细信息请参见Hartley&Zisserman的圣经)。

您唯一需要做的就是估计将棋盘映射到正方形的单应性,然后将其应用于图像。


这是我想要做的事情:估计/构建单应性,但它不起作用。但我不想使用findHomography。原因是:1)我已经从传感器中知道了旋转矩阵,并希望节省计算时间。2)对于我来说,获取相应点可能很困难(而不是矩形,我可能有圆形)。 - pzo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接