首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建一个不失真的摄像机图像自顶向下视图

问创建一个不失真的摄像机图像自顶向下视图
EN

Stack Overflow用户
提问于 2022-07-26 09:50:29
回答 2查看 203关注 0票数 3

我有一个固定的摄像机安装在墙上,观看长方形草坪的角度。我的目标是获得一个不扭曲的,自上而下的草坪景观.

我有一个来自摄像机的图片,它是python数组,如下所示:

原始相机图像

我使用带有skimage.transform.warp的逆矩阵将图像更正为自顶向下视图:

自上而下变形

这是完美的工作,但相机镜头引入桶形畸变。

单独地,我可以使用和弦生成的查找表纠正失真,并根据描述的这里算法传递一个简单的、不失真的可调用函数。然后使用坐标生成图像。

不失真摄像机视角

这两个过程分别工作,但我如何组合它们来创建一个不失真的自上而下视图,而不创建一个中间图像?

我可以通过矩阵运行查找表中的每个点来创建一个新表,但是这个表很大,内存也很紧(Raspberry Pi Zero)。

我想把不失真定义为一个矩阵,只组合两个矩阵,但据我所知,射影单形矩阵是线性的,而非失真矩阵是非线性的,所以这是不可能的。由于资源的限制,我不能使用OpenCV,涉及多个棋盘图像的校准过程是不切实际的。目前,我用4个草坪角点进行标定,并从中生成矩阵,效果很好。

我本以为这是计算机视觉中常见的问题,但却找不到合适的解决方案。

EN

回答 2

Stack Overflow用户

发布于 2022-07-26 15:42:57

桶形变形是非线性的,但也是光滑的。这意味着它可以很好地通过一组分段线性逼近来逼近。所以你不需要一个大的,每像素查表的无失真位移.相反,您可以对其进行子采样(或将其缩小),并对中间像素使用双线性插值。

票数 1
EN

Stack Overflow用户

发布于 2022-08-11 07:07:42

我找到了一个解决方案,它似乎可以通过创建独立的函数来实现非扭曲和转换,然后将它们链接在一起。

skimage源代码这里具有从矩阵生成映射的_apply_mat方法。我的解曲功能的基础是:

代码语言:javascript
复制
def unwarp(coords, matrix):
    coords = np.array(coords, copy=False, ndmin=2)
    x, y = np.transpose(coords)
    src = np.vstack((x, y, np.ones_like(x)))
    dst = src.T @ matrix.T

    # below, we will divide by the last dimension of the homogeneous
    # coordinate matrix. In order to avoid division by zero,
    # we replace exact zeros in this column with a very small number.
    dst[dst[:, 2] == 0, 2] = np.finfo(float).eps
    # rescale to homogeneous coordinates
    dst[:, :2] /= dst[:, 2:3]

    return dst[:, :2]

我创建了一个类似的基于坦纳Hellands算法的非失真函数

代码语言:javascript
复制
def undistort(coords, cols, rows, correction_radius, zoom):
    half_width = cols / 2
    half_height = rows / 2
    new_x = coords[:, 0] - half_width
    new_y = coords[:, 1] - half_height
    distance = np.hypot(new_x, new_y)
    r = distance / correction_radius
    theta = np.ones_like(r)
    # only process non-zero values
    np.divide(np.arctan(r), r, out=theta, where=r!=0)
    source_x = half_width + theta * new_x * zoom
    source_y = half_height + theta * new_y * zoom
    result = np.column_stack([source_x, source_y])       
    return result

这里唯一棘手的一点是我们需要防止零除法的分歧。

一旦我们有了每个查找表,我们就可以将它们链接在一起:

代码语言:javascript
复制
def undistort_unwarp(coords):
    undistorted = undistort(coords)
    both = unwarp(undistorted)
    return both  

请注意,这些是传递给skimage.transform.warp_coords的可调用函数:

代码语言:javascript
复制
mymap = tf.warp_coords(undistort_unwarp, shape=(rows, cols), dtype=np.int16)

然后,映射可以传递给skimage.transform.warp函数。

Francesco的答案是有帮助的,但是我需要整个像素的分辨率来进行转换,所以我也将它用于非失真的转换,并寻找其他方法来减少内存消耗。

每一张地图

行* cols *字节-每项*2 (x和y)

字节。默认的数据类型是float64,它要求每项8字节,文档表明,正常的选择将是默认的,或者float32为每项4字节。我能够减少到每项使用int16的两个字节,没有明显的不良影响,但我怀疑样条插值没有被充分使用(?)

对于彩色RGB图像的每个通道,地图是相同的。然而,当我用warp_coords (行、科尔、3)调用shape=时,我得到了3个重复的映射,因此我创建了一个函数,通过分别处理每个通道来处理彩色图像:

代码语言:javascript
复制
def warp_colour(img_arr, coord_map):
    if img_arr.ndim == 3:
        # colour
        rows, cols, _chans = img_arr.shape
        r_arr = tf.warp(img_arr[:, :, 0], inverse_map=coord_map, output_shape=(rows, cols))
        g_arr = tf.warp(img_arr[:, :, 1], inverse_map=coord_map, output_shape=(rows, cols))
        b_arr = tf.warp(img_arr[:, :, 2], inverse_map=coord_map, output_shape=(rows, cols))
        rgb_arr = np.dstack([r_arr, g_arr, b_arr])
    else:
        # grayscale
        rows, cols = img_arr.shape
        rgb_arr = tf.warp(img_arr, inverse_map=coord_map, output_shape=(rows, cols))
    return rgb_arr

skimage.transform.warp_coords的一个问题是它没有skimage.transform.warp具有的map_args字典参数。我必须通过一个中间函数调用我的反扭曲和非扭曲函数来添加参数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73121247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档