Python中的3D图像旋转

10

我有一张名为I1的图片,不是我拍摄的,而是从Google下载得来。

enter image description here

我使用已知的单应性矩阵h对I1进行变换,得到以下图像I2。

enter image description here

我假设有一台相机拍摄了I2的上方图像。我已经找到了这个“相机”的相机矩阵。让这个相机矩阵为k。现在,我想围绕相机轴旋转这个图像I2。根据这个问题中被接受的答案中的解释,我需要设置旋转矩阵R,然后对图像I1执行k*R*inv(k)*h以获得所需的旋转图像I3。
当我尝试设置旋转矩阵R时,我遇到了问题。我使用这种方法来设置矩阵R。
为了测试我的代码,我最初尝试将图像沿z轴旋转10度,但我没有得到正确的输出。
我的部分Python代码:
theta_in_degrees = 10
theta_in_radians = theta_in_degrees*math.pi/180
ux=0.0 
uy=0.0 
uz=1.0 
vector_normalize_factor = math.sqrt(ux*ux+uy*uy+uz*uz)
ux=ux/vector_normalize_factor
uy=uy/vector_normalize_factor
uz=uz/vector_normalize_factor
print "ux*ux+uy*uy+uz*uz = ", ux*ux+uy*uy+uz*uz 
rotation_matrix = np.zeros([3,3])
c1 = math.cos(theta_in_radians)
c2 = 1-c1
s1 = math.sin(theta_in_radians)
rotation_matrix[0][0] = c1+ux*ux*c2
rotation_matrix[0][1] = ux*uy*c2-uz*s1
rotation_matrix[0][2] = ux*uz*c2+uy*s1
rotation_matrix[1][0] = uy*ux*c2+uz*s1
rotation_matrix[1][1] = c1+uy*uy*c2
rotation_matrix[1][2] = uy*uz*c2-ux*s1
rotation_matrix[2][0] = uz*ux*c2-uy*s1
rotation_matrix[2][1] = uz*uy*c2+ux*s1
rotation_matrix[2][2] = c1+uz*uz*c2
print "rotation_matrix = ", rotation_matrix
R = rotation_matrix
#Calculate homography H1 between reference top view and rotated frame
k_inv = np.linalg.inv(k)
Hi = k.dot(R)
Hii = k_inv.dot(h)
H1 = Hi.dot(Hii)
print "H1 = ", H1
im_out = cv2.warpPerspective(im_src, H1, (im_dst.shape[1],im_dst.shape[0]))

这里,img_src是I1的源。

当我尝试上述代码时,得到的结果是一张黑色的图片,没有任何部分可见。然而,当我将theta_in_degrees的值更改为以下值时,这些是我的输出:

0.00003

enter image description here

0.00006

enter image description here

0.00009

enter image description here

为什么旋转只对如此小的theta_in_degrees值起作用?另外,图像中可见的旋转实际上并没有围绕z轴发生。为什么图像不围绕z轴旋转?我做错了什么,如何解决这些问题?
h矩阵:
[[  1.71025842e+00  -7.51761942e-01   1.02803446e+02]
 [ -2.98552735e-16   1.39232576e-01   1.62792482e+02]
 [ -1.13518150e-18  -2.27094753e-03   1.00000000e+00]]

k矩阵:

[[  1.41009391e+09   0.00000000e+00   5.14000000e+02]
 [  0.00000000e+00   1.78412347e+02   1.17000000e+02]
 [  0.00000000e+00   0.00000000e+00   1.00000000e+00]]

编辑:

在采纳Toby Collins的建议后,我将k的左上角值设置为与k[1][1]相同。现在,当我绕z轴旋转时,对于theta_in_degrees从0到360的所有值,我都能得到正确的旋转图像。然而,当我尝试通过将上述代码中的ux、uy和uz更改为以下内容来绕y轴旋转图像时,结果却荒谬无比:

ux=0.0 
uy=1.0 
uz=0.0 

下面展示了不同 theta_in_degrees 值的示例以及绕 y 轴旋转的相应结果:

-10

enter image description here

-40

enter image description here

-90

enter image description here

-110

enter image description here

我还有哪些地方做错了?此外,为什么旋转图像中连续的黄色条纹的长度和宽度会大幅下降?而且为什么图像的一部分会环绕(例如,通过-90度和-110度的旋转结果)?

我的第二个问题是:我的旋转轴的向量方程是(320, 0, -10)+t(0, 1, 0)。为了使用这种方法计算旋转矩阵,我需要定义旋转轴的uxuyuz,使得ux^2+uy^2+uz^2=1。如果旋转需要围绕其中一个坐标轴进行(就像我目前正在为测试目的而做的那样),那么这将是直接的。但是,如果我的旋转轴的向量方程中的t是可变的,我该如何获取这些uxuyuz的值呢?如果要围绕我提到的轴(比如说,以x度)进行旋转,我也愿意听取关于寻找适当的旋转矩阵R的任何其他方法的建议。


1
尝试将K矩阵左上角的元素设置为1.78412347e + 02,这样你的相机就具有了宽高比为1,并再次运行代码。这将至少验证你的代码是否适用于更接近真实相机的K矩阵宽高比。 - Toby Collins
@TobyCollins 关于 h 矩阵第三行第一列的小值,如果我想要正确的转换,我相信这个值是正确的。我已经仔细验证过这个事实,并且有信心这是我将要使用的正确的 h 矩阵。 - RaviTej310
我已经按照您的建议更改了h矩阵左上角元素,并将其设置为fy值,使得纵横比变为1。虽然这对于绕z轴旋转显示了预期结果,但对于绕y轴旋转却显示出荒谬的结果。我一直在尝试找出我的错误,但到目前为止还没有成功。我已经在上面的问题编辑中包含了结果。您有什么想法为什么会发生这种情况吗?是因为更改h矩阵的左上角值使纵横比为1,还是其他原因? - RaviTej310
我看到你在这里仍然有一些困难。我们来退后一步。您能准确地定义您希望完整的应用程序做什么吗?为什么要以您现在的方式生成对应关系?您的应用程序是只旋转摄像机围绕平面物体旋转吗?还是您想在特定的摄像机位置下旋转摄像机轴(而不是平移摄像机)? - Toby Collins
是的,第二件事是我想要能够做的:我想在给定特定相机位置的情况下绕其轴旋转相机(而不是平移它)。我想记录该特定旋转的单应矩阵 H'。这个单应矩阵 H' 将把原始图像 I1 映射到旋转后的最终图像 I3。我假设我们通过将 I2 沿着相机轴旋转 x 度来获得 I3。所有这些都符合这个问题 - https://dev59.com/jFYN5IYBdhLWcg3wFksL. - RaviTej310
显示剩余6条评论
1个回答

6
你遇到的问题是你的单应矩阵h与使用合理透视相机获得的投影不匹配。我认为有一种更简单的方法。
从根本上讲,你需要非常清楚地了解你的技术目标,并将其与解决问题的方法分开。每当你解决任何视觉问题时都要这样做。

技术目标

所以让我们明确技术目标。你有一个平面表面的俯视图(也称为矫正视图)。通常你会称这个表面为模型,定义在平面z=0上。你想要渲染这个模型。具体来说,你想要做到以下几点:
  1. 创建一个虚拟透视相机,从特定视点查看模型。我们用R1、t1和内部矩阵K来定义这个模型到相机的刚性变换。
  2. 通过绕其投影中心旋转相机来移动相机。我们用R2表示这个旋转。
  3. 使用第2步中的视图渲染模型。我们将这个图像称为I2
为了简化,我将使用T(Rt)来表示某个旋转R和平移t的4x4齐次刚性变换。因此,在第3阶段的模型到相机变换由T=T(R2, (0,0,0)) x T(R1, t1)给出。

渲染选项

有两种好的方法可以创建I2
  1. 使用渲染引擎,如OpenGL或Ogre。这样做的优点是可以轻松制作GUI以更改相机视角,并且可以添加其他复杂的渲染效果。

  2. 确定模型到图像单应矩阵,并使用OpenCV中的warpPerspective进行渲染。这样做的优点是可以在不打破渲染软件的情况下用几行代码完成。缺点是如果单应矩阵在渲染中有一个消失点(正如你所观察到的),则可能会产生一些奇怪的效果。稍后再详细讨论这一点。

模型到图像单应矩阵的定义

为了使用OpenCV方法,我们定义模型到图像单应性矩阵为H2。这可以用相机参数来定义。考虑在齐次坐标系下模型平面上的点p=(x,y,1)。它在齐次坐标系下在I2中的位置qq=K M p给出,其中M是一个3x3矩阵,给定为M=(T00,T01,T03; T10,T11,T13; T20,T21,T23)。这很容易通过透视相机模型推导出来。因此,我们现在有H2 = K M

实例化单应性矩阵

现在我们必须实例化单应性矩阵,与您提出的方法不同,我会使用特定的相机配置来定义它,通过指定KR1、t1和R2。选择权在你手中!为了简化K的定义,您可以使用一个自由参数(焦距)的简单形式,并将主点设置为图像中心。对于典型相机,f的范围在0.5到2倍的图像宽度之间,但这取决于您。然后,您需要根据所需的视角/距离设置R1和t1。

与您当前的方法有何不同

我想强调的是,这并不与我之前给出的任何答案相矛盾。这只是一种不同的方法,可能更容易管理。本质上,我建议直接使用相机参数来定义您的单应性矩阵(您可以根据需要自己设置)。这保证了您使用合理的内部矩阵(因为您自己设置它)。这与您的方法不同,您首先创建一个单应性矩阵,然后想找到匹配的相机参数(可能或者不可能是物理上合理的)。

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