在 pyBullet 中模拟具有失真的相机
Simulate camera with distortion in pyBullet
我正在尝试根据通过校准真实相机获得的内在和外在参数在 pyBullet 中配置相机。
我有什么
相机是用OpenCV标定的,给了我一个相机矩阵
|f_x 0 c_x|
| 0 f_y c_y|
| 0 0 1 |
和失真系数向量
(k_1, k_2, p_1, p_2, k_3)
(我还有相机的姿势,但这与实际问题无关,所以我把它放在这里。)
我已经做了什么
不幸的是,pyBullet 的 computeProjectionMatrix
功能有点受限。它假定 f_x = f_y
和 c_x, c_y
正好位于图像的中心,这对我的相机来说都是不正确的。因此我自己计算投影矩阵如下(基于this):
projection_matrix = [
[2/w * f_x, 0, (w - 2c_x)/w, 0],
[0, 2/h * f_y, (2c_y - h)/h, 0],
[0, 0, A, B],
[0, 0, -1, 0],
]
其中w,h
是图像的宽度和高度,A = (near + far)/(near - far)
和B = 2 * near * far / (near - far)
,near
和far
定义了z轴上的范围包含在图片中(参见 pybullet.computeProjectionMatrix
)。
还缺少什么(我的实际问题)
以上已经给了我更好的结果,但渲染图像仍然与真实图像不完全匹配。我怀疑造成这种情况的原因之一可能是没有考虑到失真。
所以终于来到我的问题:
如何使用校准真实相机得到的参数为模拟相机实现失真?
有什么方法可以将其集成到投影矩阵中吗?如果不行,还有别的办法吗?
正如评论中指出的那样,非线性失真不能集成到矩阵中。我现在正在做的是首先渲染图像而不失真,然后在第二步中使用 this answer.
中的代码扭曲生成的图像
由于失真,图像会缩小一点,因此在保持图像大小不变的情况下,图像边缘会出现一些空白区域。为了弥补这一点,我渲染图像的尺寸比需要的尺寸稍大,然后在扭曲后裁剪。请注意,中心点(c_x, c_y)
需要相应调整,当增加尺寸时。
用一些伪代码来说明:
desired_image_size = (width, height)
# add 10% padding on each size
padding = desired_image_size * 0.1
render_image_size = desired_image_size + 2 * padding
# shift the centre point accordingly (other camera parameters are not changed)
c_x += padding[0]
c_y += padding[1]
# render image using the projection_matrix as described in the question
image = render_without_distortion(projection_matrix, camera_pose)
image = distort_image(image)
# remove the padding
image = image[padding[0]:-padding[0], padding[1]:-padding[1]]
这样生成的图像与真实相机中的图像非常匹配。
可以找到完整的实现 here。
我正在尝试根据通过校准真实相机获得的内在和外在参数在 pyBullet 中配置相机。
我有什么
相机是用OpenCV标定的,给了我一个相机矩阵
|f_x 0 c_x|
| 0 f_y c_y|
| 0 0 1 |
和失真系数向量
(k_1, k_2, p_1, p_2, k_3)
(我还有相机的姿势,但这与实际问题无关,所以我把它放在这里。)
我已经做了什么
不幸的是,pyBullet 的 computeProjectionMatrix
功能有点受限。它假定 f_x = f_y
和 c_x, c_y
正好位于图像的中心,这对我的相机来说都是不正确的。因此我自己计算投影矩阵如下(基于this):
projection_matrix = [
[2/w * f_x, 0, (w - 2c_x)/w, 0],
[0, 2/h * f_y, (2c_y - h)/h, 0],
[0, 0, A, B],
[0, 0, -1, 0],
]
其中w,h
是图像的宽度和高度,A = (near + far)/(near - far)
和B = 2 * near * far / (near - far)
,near
和far
定义了z轴上的范围包含在图片中(参见 pybullet.computeProjectionMatrix
)。
还缺少什么(我的实际问题)
以上已经给了我更好的结果,但渲染图像仍然与真实图像不完全匹配。我怀疑造成这种情况的原因之一可能是没有考虑到失真。
所以终于来到我的问题:
如何使用校准真实相机得到的参数为模拟相机实现失真?
有什么方法可以将其集成到投影矩阵中吗?如果不行,还有别的办法吗?
正如评论中指出的那样,非线性失真不能集成到矩阵中。我现在正在做的是首先渲染图像而不失真,然后在第二步中使用 this answer.
中的代码扭曲生成的图像由于失真,图像会缩小一点,因此在保持图像大小不变的情况下,图像边缘会出现一些空白区域。为了弥补这一点,我渲染图像的尺寸比需要的尺寸稍大,然后在扭曲后裁剪。请注意,中心点(c_x, c_y)
需要相应调整,当增加尺寸时。
用一些伪代码来说明:
desired_image_size = (width, height)
# add 10% padding on each size
padding = desired_image_size * 0.1
render_image_size = desired_image_size + 2 * padding
# shift the centre point accordingly (other camera parameters are not changed)
c_x += padding[0]
c_y += padding[1]
# render image using the projection_matrix as described in the question
image = render_without_distortion(projection_matrix, camera_pose)
image = distort_image(image)
# remove the padding
image = image[padding[0]:-padding[0], padding[1]:-padding[1]]
这样生成的图像与真实相机中的图像非常匹配。
可以找到完整的实现 here。