Python旋转相机轴周围的图像

10
假设我有一张经过单应性变换 H 处理后得到的图片,原始的图片没有显示。单应性变换 H 应用在原始图片上的结果是这张图片:

enter image description here

我想将这张图片绕着适当的轴旋转30度(如果有相机的话,可能就是相机所在的位置),得到这张图片:

enter image description here

如果我不知道相机参数,该如何使用 Python 应用这个旋转变换?我只能指定我想要旋转的角度和大致的旋转轴。另外,如何利用单应性变换 H 和旋转变换推导出原始图片(在经过单应性变换之前)和最终旋转图片之间的单应性变换 H'?
2个回答

6
一个有趣的问题。为了帮助解释我的解决方案,我将定义一些符号:
- I1:原始图像。 - I2:通过变换I1得到的图像H。 - I3:通过3D相机旋转R(由您自己设置)变换I2得到的图像。 - 未知的相机内部矩阵K对应于I2。
因为相机旋转而不是平移,所以您可以通过使用相应的单应矩阵来扭曲图像来合成任何旋转矩阵R的虚拟视图。因此,您不需要尝试重建3D场景以合成这些视图。
现在,我假设我们已经估计出K并给出从I1到I3的单应矩阵的方程式。这回答了您问题的最后一部分。最后,我会提供一种估算K的好方法。然后你就有了所需的一切。
p =(px,py)是I1中的二维点。我们用向量p =(px,py,1)在齐次坐标中定义此点。同样,让点q =(qx,qy,1)是点p在I3中的位置。将点p变换为q的单应矩阵H'H' = K R inv(KH给出。对于您指定的任何R,您都将使用此方法计算H',然后可以使用例如OpenCV的warpPerspective函数扭曲I1以合成新视图。
推导:我们首先应用H将点放入I2中。接下来,我们通过inv(K)将该点转换为其在3D相机坐标中的位置。然后我们应用旋转R,最后用K投影回图像。如果您对应用这样的投影变换不确定,则强烈建议深入阅读Hartley和Zisserman的书《多视角几何》。

计算K矩阵。我提出了一种巧妙的方法,利用自由女神像进行平面相机标定。注意到她站在一个平台上,我们假定这是一个正方形。现在我们将使用这个正方形进行一个粗略的相机标定。假设没有镜头畸变,K 的简化形式为 K = [f,0,cx;0,f,cy;0,0,1]。这意味着纵横比为1(通常对于数码相机而言大致如此),主点位于图像中心:cx=w/2,cy=h/2,其中w和h分别是图像的宽度和高度。尝试估计镜头畸变和更复杂的K矩阵会非常困难。因为图像边缘都大致呈直线,所以可以忽略镜头畸变。

现在我们要计算f值。这将使用基于平面的相机标定来完成。这方面的著名参考资料是Zhang: A Flexible New Technique for Camera Calibration,位于https://www.microsoft.com/en-us/research/publication/a-flexible-new-technique-for-camera-calibration/

具体操作是先在I2中单击自由女神像平面的四个可见角落的四个点。我们称这些点为p1、p2、p3和p4,从左下角开始按顺时针方向标记。然后可以使用OpenCV的相机标定方法从这4个角点得到K的估计值。重要的是我们之所以能够这样做是因为我们知道平台是正方形。如果想深入了解基于平面的标定,请阅读张的论文。如果您有困难,我可以在几分钟内完成并发送K矩阵。

four corner points on the statue's square stand

最后,这种方法的一个小变化是使用原始图像进行标定(假设您仍然有它)。原因是H可能会使I2产生畸变,使其纵横比不接近1且主点不靠近图像中心。如果使用原始图像进行标定(我们将矩阵称为K1),则应使用K=HK1


使用I2方法得到的校准矩阵K为K = [723.6, 0, 326.0; 0, 723.6, 579.5, 0, 0, 1.0]。 - Toby Collins
谢谢!你能告诉我你是如何计算K矩阵的吗?当我计算时,得到的值几乎相同:[[720.19275782, 0, 326], [0, 130.41938028, 579.5], [0, 0, 1]]。然而,为什么你认为我得到了130.4这样一个非常不同的值,而不是720.19呢?fx和fy不应该是相同的吗? - RaviTej310
好的。我已经使用CALIB_FIX_ASPECT_RATIO修复了纵横比。然而,我得到的f值并不接近720,而是大约450左右。这是为什么?你是如何得到723.6的? - RaviTej310
当您调用calibrateCamera时,传递一个5x1的零矩阵作为distCoeffs,并设置标志CALIB_FIX_K1 CALIB_FIX_K2 CALIB_FIX_K3 CALIB_FIX_K4 CALIB_FIX_K5。 - Toby Collins
我已经添加了去除畸变的标志,但仍然面临问题。我可以使用最大的正方形,但应该考虑最大正方形的哪个位置?最大正方形的位置可能在整个图像中变化,而对于同一最大正方形的不同位置,我得到的k值是不同的。 - RaviTej310
显示剩余17条评论

5
为了应用单应性,我建议使用OpenCV,具体来说是使用warpPerspective函数。https://docs.opencv.org/3.0-beta/modules/imgproc/doc/geometric_transformations.html#warpperspective 因为我们正在讨论纯旋转,没有相机平移,所以您确实可以通过使用单应性来生成与此旋转对应的图像。但是,要找到作为轴方向和旋转角度函数的单应性参数,您需要知道相机内部参数,主要是焦距。
如果您有相机模型,您可以计算出方程,但另一种获得单应性矩阵的方法是计算变换后的目标点坐标,然后使用findHomography函数。或者您可以找到匹配点,然后计算单应性。
如果您没有相机模型和旋转参数或两个图像中的匹配点,则无能为力,您需要其中任何一个才能找到单应性。您可以尝试猜测相机模型。您具体拥有哪些信息?

我没有任何有关点对应的信息,因此无法使用它们。但是,我大致估计了相机旋转的量和相机与物体之间的距离。使用这些粗略的估计,是否有办法猜测一个合适的相机模型(只需要近似而不需要完美),然后执行旋转? - RaviTej310
焦距通常在图像宽度的一半到两倍之间。给定针孔相机模型,只需选择4个良好分布在图像内的任意点,使用该模型计算相应的3D坐标,将这些点在3D中旋转,然后再次使用相机模型将它们投影回图像平面。这将为您提供计算单应性所需的相应点。 - dividebyzero
谢谢!如果我对相机矩阵参数一无所知,有没有办法获得接近精确的焦距?焦距的单位是什么?图像尺寸是1160 x 653。在计算出焦距后,我该如何旋转3D点呢? - RaviTej310
1
焦距通常以像素为单位给出。要旋转3D点,只需将它们的坐标选为(x,y,f),然后应用3D旋转矩阵,再在f *(x'/z',y'/z')处重新投影它们。您可以轻松地在网络上找到有关3D旋转和针孔模型的参考资料。要猜测f,您应该真正地尝试一下,直到您对结果满意为止。该图像中平行水平线的角度也可能会指导您。如果这还不够,您应该进行适当的相机校准。 - dividebyzero
1
更进一步简单地确定你的焦距的方法是,仅仅看看雕像相对于角度的位置,或者只需将相机对准墙壁,看看视场在哪里结束。焦距是相机到墙壁的距离除以水平视场乘以图像宽度。 - dividebyzero

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