在 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_yc_x,c_y 正好位于图像的中心,这对于我的相机来说都不是真的。因此我自己计算投影矩阵如下(基于 this):

projection_matrix = [
    [2/w * f_x,(w - 2c_x)/w,0],[0,2/h * f_y,(2c_y - h)/h,A,B],-1,]

其中 w,h 是图像的宽度和高度,A = (near + far)/(near - far)B = 2 * near * far / (near - far)nearfar 定义了 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 中找到完整的实现。