【问题标题】:Draw triangle in 3D numpy array in python在python中的3D numpy数组中绘制三角形
【发布时间】:2020-03-28 13:39:35
【问题描述】:

假设我有一个具有某种形状的 3D 阵列(长方体),例如 (48, 32, 64)。我在这个立方体中有 3 个点和一些坐标。 x1 = (10, 20, 30) x2 = (21, 15, 34) x3 = (33, 1, 62)

我需要在这个受这些点限制的 3D 阵列中绘制填充平面,例如在 3D 数组中绘制三角形。在 2D 情况下,我们可以使用 openCV 来完成: Triangle Filling in opencv

import numpy as np
a = np.zeros((48, 32, 64), dtype=np.uint8)
x1 = (10, 20, 30)
x2 = (21, 15, 34)
x3 = (33, 1, 62)
a = draw_3D_triangle(a, x1, x2, x3)

但是在 3D 情况下最简单的方法是什么?

【问题讨论】:

    标签: python arrays numpy 3d


    【解决方案1】:

    已编辑:我之前忘记包含full_triangle() 的代码)。


    假设您有一个画线的算法,例如 Bresenham's Algorithm,并假设它可以推广到 N-dim 情况。

    幸运的是,raster-geometry 包有这样一个 Bresenham 算法的 N-dim 实现。

    (免责声明:我是该包的主要作者。)

    设A、B、C为三角形ABC的顶点坐标。


    如果你只需要绘制外形,你可以使用算法使用各种点的组合来形成线条:AB、BC、CA。

    在代码中,这只是:

    import numpy as np
    import raster_geometry as rg
    
    
    a, b, c = (1, 1), (3, 7), (6, 4)
    coords = set(rg.bresenham_lines((a, b, c), closed=True))
    print(coords)
    # {(1, 2), (6, 4), (3, 2), (4, 6), (5, 5), (2, 2), (2, 3), (3, 6), (2, 4), (4, 3), (3, 7), (2, 5), (1, 1), (5, 3)}
    arr = rg.render_at((10, 10), coords)
    print(arr.astype(int))
    # [[0 0 0 0 0 0 0 0 0 0]
    #  [0 1 1 0 0 0 0 0 0 0]
    #  [0 0 1 1 1 1 0 0 0 0]
    #  [0 0 1 0 0 0 1 1 0 0]
    #  [0 0 0 1 0 0 1 0 0 0]
    #  [0 0 0 1 0 1 0 0 0 0]
    #  [0 0 0 0 1 0 0 0 0 0]
    #  [0 0 0 0 0 0 0 0 0 0]
    #  [0 0 0 0 0 0 0 0 0 0]
    #  [0 0 0 0 0 0 0 0 0 0]]
    

    如果你需要画一个完整的三角形,你可以这样做:

    • 从 A 点到 B 点画一条线
    • 为线中的每个点画一条从 C 到 AB 线中的点的线。

    虽然这可能不是最有效的方法,但它的效果相当不错。 可能会错过顶点附近的某些点。 在这种情况下,重复相同的过程循环遍历所有三个顶点就足够了。

    在代码中,可以这样写:

    import numpy as np
    import raster_geometry as rg
    
    
    def full_triangle(a, b, c):
        ab = rg.bresenham_line(a, b, endpoint=True)
        for x in set(ab):
            yield from rg.bresenham_line(c, x, endpoint=True)
    
    
    a, b, c = (1, 1), (3, 7), (6, 4)
    coords = set(full_triangle(a, b, c))
    print(coords)
    # {(1, 2), (6, 4), (5, 4), (3, 2), (3, 3), (5, 5), (4, 6), (4, 5), (4, 4), (1, 1), (2, 3), (4, 3), (2, 2), (3, 6), (3, 7), (2, 5), (5, 3), (3, 4), (2, 4), (3, 5)}
    arr = rg.render_at((10, 10), coords)
    print(arr.astype(int))
    # [[0 0 0 0 0 0 0 0 0 0]
    #  [0 1 1 0 0 0 0 0 0 0]
    #  [0 0 1 1 1 1 0 0 0 0]
    #  [0 0 1 1 1 1 1 1 0 0]
    #  [0 0 0 1 1 1 1 0 0 0]
    #  [0 0 0 1 1 1 0 0 0 0]
    #  [0 0 0 0 1 0 0 0 0 0]
    #  [0 0 0 0 0 0 0 0 0 0]
    #  [0 0 0 0 0 0 0 0 0 0]
    #  [0 0 0 0 0 0 0 0 0 0]]
    

    请注意,虽然示例是 2D 的,但它们适用于 N-dim。 例如,您所追求的 3D 三角形可以通过以下方式生成:

    x1 = (10, 20, 30)
    x2 = (21, 15, 34)
    x3 = (33, 1, 62)
    coords = set(full_triangle(x1, x2, x3))
    arr = rg.render_at((48, 32, 64), coords)
    

    【讨论】:

      【解决方案2】:

      为了渲染 3d 三角形,您必须将其投影到 2d,或者使用一些现成的解决方案,例如 mplot3d,或者您可以手动将 3d 数据投影到 2d。

      最简单的投影是正交投影。您可以通过简单地忽略数据的 z 维度来实现这一点。

      对于透视投影,将 3d 数据除以 z 值:

      import numpy as np
      
      p1 = (10, 20, 30)
      p2 = (21, 15, 34)
      p3 = (33, 1, 62)
      
      tri3d = np.array([p1, p2, p3])
      ortho2d = tri3d[:, :2]
      proj2d = tri3d[:, :2] / tri3d[:, 2:]
      
      print(tri3d)
      print(ortho2d)
      print(proj2d)
      

      结果:

      [[10 20 30]
       [21 15 34]
       [33  1 62]]
      [[10 20]
       [21 15]
       [33  1]]
      [[0.33333333 0.66666667]
       [0.61764706 0.44117647]
       [0.53225806 0.01612903]]
      

      然后,您可以使用您在问题中提到的相同三角形填充。一些考虑因素是您所在空间的边界,以及任何投影三角形的比例。请注意,投影坐标都非常小。在这种情况下,您可以将它们按比例放大(相当于相机校准矩阵中的焦距)。

      【讨论】:

      • 我不确定您是否正确理解了这个问题。在输出上,我必须有相同形状的 3D 数组,点(体素)标记为 1,用于我需要绘制的训练。
      • 啊,可以渲染为由三角形定义的体素...为此,您需要找到三角形体素交点。这里有一个很好的答案:stackoverflow.com/a/21639350/10188737。 Plotly 有显示体素的方法:plotly.com/python/3d-volume-plots
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 1970-01-01
      • 2021-05-05
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      相关资源
      最近更新 更多