Нарисуйте треугольник в 3D numpy массив в python - PullRequest
2 голосов
/ 28 марта 2020

Допустим, у меня есть 3D-массив (прямоугольник angular кубоид) с некоторой формой, например (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-случае?

Ответы [ 2 ]

3 голосов
/ 03 апреля 2020

( EDITED : ранее я забыл включить код для full_triangle()).


Предположим, у вас есть алгоритм, который dr aws строк, как Алгоритм Брезенхема и предположим, что его можно обобщить на случай N-dim.

К счастью, пакет raster-geometry имеет такую ​​реализацию N-dim алгоритма Брезенхама.

(Отказ от ответственности: я являюсь основным автором пакета.)

Пусть A, B, C - координата вершин треугольника AB C.


Если вам нужно нарисовать только внешнюю фигуру, вы можете просто использовать алгоритм, используя различные комбинации точек для формирования линий: AB, B C, 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. Например, трехмерный треугольник, который вам нужен, может быть сгенерирован с помощью:

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 голосов
/ 28 марта 2020

Чтобы отобразить ваш 3d-треугольник, вы должны проецировать его на 2d, используя какое-то готовое решение, например, mplot3d, или вы можете вручную проецировать 3d-данные на 2d.

Простейшая проекция - орфография c. Вы можете добиться этого, просто игнорируя измерение 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]]

Затем вы можете использовать тот же треугольник, который вы указали в вашем вопросе. Некоторые соображения - это границы пространства, в котором вы находитесь, и масштаб любого проецируемого треугольника. Обратите внимание, что все проецируемые координаты довольно малы. В этом случае вы можете увеличить их на некоторый коэффициент (эквивалентный фокусному расстоянию в калибровочной матрице камеры).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...