python 中的 3D 图像旋转
3D image rotation in python
我有下图I1。我没有捕捉到它。我从 Google
下载
我将已知的单应性h应用到I1得到下面的图像I2。
我想假设相机已经拍摄了上面这张 I2 的照片。我找到了这个"camera"的相机矩阵。设这个相机矩阵为k
。现在,我想围绕相机轴旋转此图像 I2。根据中accepted answer中的解释,我需要设置旋转矩阵R,然后对图像I1进行k*R*inv(k)*h
得到需要的旋转图像I3。
我尝试设置这个旋转矩阵R时一直遇到问题。我已经使用this method设置了矩阵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
0.00006
0.00009
为什么旋转仅适用于 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 轴的旋转时,我得到了从 0 到 360 的所有 theta_in_degrees
值的正确旋转图像。但是,当我尝试通过更改 ux 绕 y 轴旋转图像时,上面代码中的 uy 和 uz 到下面,我得到荒谬的旋转结果:
ux=0.0
uy=1.0
uz=0.0
theta_in_degrees
的不同取值的一些示例以及绕y轴旋转的相应结果如下所示:
-10
-40
-90
-110
我哪里还错了?另外,为什么旋转图像中连续黄色条纹的长度和宽度会出现如此巨大的下降?为什么图像的一部分会环绕(例如旋转-90度和-110度的结果)?
我的问题的第二部分是这样的:我的旋转轴的矢量方程是(320, 0, -10)+t(0, 1, 0)
。为了使用this method,计算旋转矩阵,我需要定义旋转轴的ux
、uy
和uz
,使得ux^2+uy^2+uz^2=1
.如果需要围绕其中一个坐标轴进行旋转(正如我目前出于测试目的所做的那样),这将很简单。但是,如果我的旋转轴的矢量方程中的 t
是可变的,我如何获得 ux
、uy
和 uz
的这些值?我也乐于接受有关找到合适的旋转矩阵 R 的任何其他方法的建议,这样旋转就会围绕我提到的轴发生(比如,x 度)。
您遇到的困难是您的单应矩阵 h 与使用 sensible 透视相机获得的投影不一致。我认为有一个更简单的方法。
从根本上说,您需要非常清楚自己的技术目标,并将其与解决它的方法区分开来。每当您解决 任何 视力问题时,请始终这样做。
技术目标
所以我们要明确技术目标。您有平面的自上而下图像(也称为 校正 视图)。通常你会称这个表面为 model,在平面 z=0 上定义。你想渲染这个模型。具体来说,您想执行以下操作;
- 创建了一个从特定视点观察模型的虚拟透视相机。我们通过 R1,t1 定义这个模型到相机的刚性变换,具有一个内在矩阵 K.
- 相机通过围绕其投影中心旋转来移动。让我们用 R2 表示这个旋转。
- 使用 2 的视图渲染模型。我们将此图像称为 I2
为简单起见,我将使用 T(R,t) 表示一些旋转的 4x4 齐次刚性变换 R 和翻译t。 model-to-camera stage 3 的变换因此由 T=T(R2, (0,0,0)) x T(R1, t1).
渲染选项
有两个很好的创建方法I2
使用渲染引擎,例如 OpenGL 或 Ogre。这样做的好处是可以很容易地制作一个改变相机视点的GUI,并且可以添加其他复杂的渲染效果。
确定模型到图像的单应矩阵 并使用 warpPerspective
使用 OpenCV 进行渲染。这样做的好处是几行代码就可以完成,而无需进入渲染软件。缺点是如果单应性在渲染中有一个消失点(如您所观察的那样),您会得到一些奇怪的效果。稍后会详细介绍这一点。
模型到图像单应性的定义
为了使用 OpenCV 方法,我们将 model-to-image 单应性定义为 H2。这可以根据相机参数来定义。考虑模型平面上齐次坐标中的点 p=(x,y,1)。它在齐次坐标中 I2 中的位置 q 由 q=K M p 给出,其中 M 是。 M=(T00,T01,T03; T10,T11,T13; T20,T21,T23) 给出的 3x3 矩阵。使用透视相机模型可以直接得出这一点。因此,我们现在有 H2 =K M。
实例化单应矩阵
现在我们必须实例化单应性,与您提出的方法不同,我会使用特定的相机配置来定义它,通过指定 K、R1,t1,R2。这个选择由你!为了简化 K 的定义,您可以使用带有一个自由参数(焦距)的简单形式,并将主点设置为图像中心。对于典型的相机,f 的范围是图像宽度的 0.5 到 2 倍,但这取决于您。然后,您需要设置 R1 和 t1,具体取决于您想要的视角 angle/distance。
这与您当前的方法有何不同
我想强调的是,这与我之前给出的任何答案都不矛盾。这只是一种不同的方法,可能更容易管理。本质上,我在这里建议直接使用相机参数(您可以根据需要设置)来定义单应性。这保证您使用的是合理的内在矩阵(因为您自己设置了它)。这与您首先创建单应性然后想要找到匹配的相机参数(这可能是物理上合理也可能不合理)的方法不同。
我有下图I1。我没有捕捉到它。我从 Google
下载我将已知的单应性h应用到I1得到下面的图像I2。
我想假设相机已经拍摄了上面这张 I2 的照片。我找到了这个"camera"的相机矩阵。设这个相机矩阵为k
。现在,我想围绕相机轴旋转此图像 I2。根据k*R*inv(k)*h
得到需要的旋转图像I3。
我尝试设置这个旋转矩阵R时一直遇到问题。我已经使用this method设置了矩阵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
0.00006
0.00009
为什么旋转仅适用于 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 轴的旋转时,我得到了从 0 到 360 的所有 theta_in_degrees
值的正确旋转图像。但是,当我尝试通过更改 ux 绕 y 轴旋转图像时,上面代码中的 uy 和 uz 到下面,我得到荒谬的旋转结果:
ux=0.0
uy=1.0
uz=0.0
theta_in_degrees
的不同取值的一些示例以及绕y轴旋转的相应结果如下所示:
-10
-40
-90
-110
我哪里还错了?另外,为什么旋转图像中连续黄色条纹的长度和宽度会出现如此巨大的下降?为什么图像的一部分会环绕(例如旋转-90度和-110度的结果)?
我的问题的第二部分是这样的:我的旋转轴的矢量方程是(320, 0, -10)+t(0, 1, 0)
。为了使用this method,计算旋转矩阵,我需要定义旋转轴的ux
、uy
和uz
,使得ux^2+uy^2+uz^2=1
.如果需要围绕其中一个坐标轴进行旋转(正如我目前出于测试目的所做的那样),这将很简单。但是,如果我的旋转轴的矢量方程中的 t
是可变的,我如何获得 ux
、uy
和 uz
的这些值?我也乐于接受有关找到合适的旋转矩阵 R 的任何其他方法的建议,这样旋转就会围绕我提到的轴发生(比如,x 度)。
您遇到的困难是您的单应矩阵 h 与使用 sensible 透视相机获得的投影不一致。我认为有一个更简单的方法。
从根本上说,您需要非常清楚自己的技术目标,并将其与解决它的方法区分开来。每当您解决 任何 视力问题时,请始终这样做。
技术目标
所以我们要明确技术目标。您有平面的自上而下图像(也称为 校正 视图)。通常你会称这个表面为 model,在平面 z=0 上定义。你想渲染这个模型。具体来说,您想执行以下操作;
- 创建了一个从特定视点观察模型的虚拟透视相机。我们通过 R1,t1 定义这个模型到相机的刚性变换,具有一个内在矩阵 K.
- 相机通过围绕其投影中心旋转来移动。让我们用 R2 表示这个旋转。
- 使用 2 的视图渲染模型。我们将此图像称为 I2
为简单起见,我将使用 T(R,t) 表示一些旋转的 4x4 齐次刚性变换 R 和翻译t。 model-to-camera stage 3 的变换因此由 T=T(R2, (0,0,0)) x T(R1, t1).
渲染选项
有两个很好的创建方法I2
使用渲染引擎,例如 OpenGL 或 Ogre。这样做的好处是可以很容易地制作一个改变相机视点的GUI,并且可以添加其他复杂的渲染效果。
确定模型到图像的单应矩阵 并使用
warpPerspective
使用 OpenCV 进行渲染。这样做的好处是几行代码就可以完成,而无需进入渲染软件。缺点是如果单应性在渲染中有一个消失点(如您所观察的那样),您会得到一些奇怪的效果。稍后会详细介绍这一点。
模型到图像单应性的定义
为了使用 OpenCV 方法,我们将 model-to-image 单应性定义为 H2。这可以根据相机参数来定义。考虑模型平面上齐次坐标中的点 p=(x,y,1)。它在齐次坐标中 I2 中的位置 q 由 q=K M p 给出,其中 M 是。 M=(T00,T01,T03; T10,T11,T13; T20,T21,T23) 给出的 3x3 矩阵。使用透视相机模型可以直接得出这一点。因此,我们现在有 H2 =K M。
实例化单应矩阵
现在我们必须实例化单应性,与您提出的方法不同,我会使用特定的相机配置来定义它,通过指定 K、R1,t1,R2。这个选择由你!为了简化 K 的定义,您可以使用带有一个自由参数(焦距)的简单形式,并将主点设置为图像中心。对于典型的相机,f 的范围是图像宽度的 0.5 到 2 倍,但这取决于您。然后,您需要设置 R1 和 t1,具体取决于您想要的视角 angle/distance。
这与您当前的方法有何不同
我想强调的是,这与我之前给出的任何答案都不矛盾。这只是一种不同的方法,可能更容易管理。本质上,我在这里建议直接使用相机参数(您可以根据需要设置)来定义单应性。这保证您使用的是合理的内在矩阵(因为您自己设置了它)。这与您首先创建单应性然后想要找到匹配的相机参数(这可能是物理上合理也可能不合理)的方法不同。