我在墙上安装了一个固定的摄像机,从一个Angular 观察一个矩形的草坪,我的目标是获得一个不失真的,自上而下的草坪视图。
我有一个图像从相机作为一个python numpy阵列看起来像这样:
raw camera image
我使用skimage.transform.warp的逆矩阵将图像校正为自顶向下的视图:
top down distorted
这是完美的工作,但相机透镜引入桶形失真。
另外,我可以使用skimage.transform.warp_coords生成一个查找表,并根据here描述的算法传递一个简单的可调用函数来校正失真。然后使用scipy.ndimage.map_coordinates生成图像:
undistorted camera view
这两个过程分别工作,但我如何将它们结合起来,以创建一个不失真的自上而下的视图,而不创建一个中间图像?
我可以通过矩阵运行查找表中的每个点来创建一个新表,但该表很大,内存也很紧张(Raspberry Pi Zero)。
我想把无失真定义为一个矩阵,然后把两个矩阵组合起来,但据我所知,投影单应矩阵是线性的,而无失真是非线性的,所以这是不可能的。由于资源限制,我不能使用OpenCV,而且涉及多个棋盘图像的校准过程是不切实际的。目前,我通过取4个草坪角点进行校准,并从中生成矩阵。其工作良好。
我早就预料到这是计算机视觉中的一个常见问题,但却找不到任何合适的解决方案。
2条答案
按热度按时间wqlqzqxt1#
桶形失真是非线性的,但它也是平滑的。这意味着它可以通过一组分段线性近似来很好地近似。因此,您不需要一个大的、每个像素的未失真位移查找表。相反,您可以对其进行二次采样(或只是缩小),并对中间的像素使用双线性插值。
4smxwvx52#
我已经找到了一个解决方案,通过创建单独的函数来进行反扭曲和变换,然后将它们链接在一起。
这里的skimage源代码有一个_apply_mat方法,用于从一个矩阵生成一个Map,我的unwarp函数就是基于这个方法:
我基于Tanner Hellands algorithm创建了一个类似的函数来消除失真:
这里唯一需要注意的是除法,我们需要防止除以零。
一旦我们有了每个查找表,我们就可以将它们链接在一起:
请注意,以下是传递给skimage.transform.warp_coords的可调用函数:
然后可以将贴图传递给skimage.transform.warp函数。
Francesco的回答很有帮助,但是我需要全像素分辨率来进行转换,所以我也用它来进行反扭曲,并寻找其他方法来减少内存消耗。
每个Map消耗
行 * 列 * 每项字节数 * 2(x和y)
默认的数据类型是float64,它要求每项8个字节,文档建议明智的选择是默认的或者每项4个字节的float32。我能够使用int16将其减少到每项2个字节,没有明显的不良影响,但是我怀疑样条插值没有被充分使用(根本没有?)。
彩色RGB图像的每个通道的Map都是一样的。但是,当我用shape=(rows,cols,3)调用warp_coords时,我得到了3个重复的Map,所以我创建了一个函数,通过分别处理每个通道来处理彩色图像:
skimage.transform.warp_coords的一个问题是它没有skimage.transform.warp所具有的map_args字典参数。我不得不通过一个中间函数调用我的unwarp和undistort函数来添加这些参数。