【问题标题】:Mapping 3d points and their colors to 2D image w/o loops将 3d 点及其颜色映射到不带循环的 2D 图像
【发布时间】:2021-06-28 07:53:11
【问题描述】:

我正在使用点云,我正在尝试在图像平面上有效地渲染模型,而无需在 3d 点上循环。

输入: .ply模型

输出: 2d 图像

到目前为止我做了什么:

我已经构建了3x4 投影矩阵,使用 python 中的 open3d 库来获取点云的 3d 点及其颜色,加载模型后它只是(pcl.points 和 pcl.colors), 我通过将形状为(9729509,4) 的第 4 列添加将 3d 点 (pcl.points) 转换为齐次坐标,然后通过将投影矩阵乘以 (9729509,4) 的转置得到我的 2d 点并得到一个新矩阵(3, 9729509),然后将第一行和第二行除以第三行进行归一化,得到二维像素。

现在我有一个(3, #of_2d_pixels) 的矩阵,我什至可以去掉第三行,因为它只是标准化后的矩阵,我有(2, #of_2d_pixels),将其定义为P

问题是:如何使用 for 循环构造一个 2d 图像,并将颜色(来自 pcl.colors)分配给一个空的 2d array,其中分配的索引是P 矩阵中的值?最后我将展示如何使用 OpenCV 来渲染这个数组

使用 for 循环会花费大量时间,我相信有一种方法可以更快地完成,就像我在不使用 for 循环的情况下一次在所有点上使用投影矩阵所做的那样(循环 3d 点并将我收到的 2d 点附加到新数组需要很多时间)

【问题讨论】:

    标签: python numpy 3d computer-vision projection


    【解决方案1】:

    我的回答假设你是在 python 上写作。

    从理论上讲,我们可以把画点想象成一个卷积函数,通过对它的变换,我们可以实现关联性,这将允许我们使用并发计算。在实践中,这并不能很好地工作,因为这种卷积函数的计算成本很高,并且结果将与正常循环相当。因此,我决定在代码的 C 级别使用带有循环的函数,例如标准函数映射 (func, arr)。通过使用 numpy 对索引计算操作进行矢量化,我设法获得了约 4 倍的性能提升。 以便您了解代码的上下文:

    import numpy as np
    # image width = height
    width = 1000
    number_of_points = 1000000
    
    # ps = [(x,y,color),(x,y,color),(x,y,color),...]
    ps = np.random.randint(width,size=(number_of_points,3))
    
    # color buffer
    pixels = np.array([0]*width*width)
    
    • 正常循环:
    for (x,y,c) in ps:
        pixels[x+y*width] = c
    

    每个循环 1.24 秒 ± 37.5 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

    • 地图 + numpy:
    # f2(x)  <-> f2([idx,color])
    # x[0] = idx
    # x[1] = color
    def f2(x):
        global all_screen
        pixels[x[0]] = x[1]
    # unpack xs,ys,colors
    xs,ys,clrs = ps.T
    # calculate index in pixel array
    idxs = xs + ys*width
    # draw all
    list(map(f2,zip(idxs,clrs)))
    # cast to list use only for evaluate map function, because in default it lazy
    

    每个循环 306 毫秒 ± 31.3 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

    如果您对没有可变变量(赋值)的纯函数样式感兴趣,我们可以创建一个带有静态哈希表(python 中的字典)的 pixel_idx -> color 函数:

    # unpack xs,ys,colors
    xs,ys,clrs = ps.T
    # calculate index on pixel array
    idxs = xs + ys*width
    ddd = dict(zip(idxs,clrs))
    
    def f3(x):
        return ddd.get(x,0)
    
    # draw all
    pixels1 = list(map(f3,np.arange(0,width*width,1)))
    

    每个循环 809 毫秒 ± 21.5 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 1970-01-01
      • 2011-08-11
      • 2020-10-24
      相关资源
      最近更新 更多