Заполненная 3D маска для лица - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть двоичный (0-1) массив массивов 3D, который я планирую использовать для маскировки 3D-изображения.Маска на данный момент состоит из области цилиндра.Два центра граней являются двумя произвольными точками, а ось не параллельна x, y или z.Как я могу заполнить цилиндр чистым раствором?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

РЕДАКТИРОВАТЬ : pymrt.geometry было удалено в пользу raster_geometry.


Учитывая, что цилиндр имеет выпуклую форму, онможно перебрать все, кроме 1 измерения и уменьшить проблему до 1D.Там (в 1D) легко написать эффективный способ заполнения пробелов, потому что все, что нужно, это, по сути, найти, где находятся границы (что можно сделать с помощью numpy.where()), а затем заполнить все от минимумаи максимальные координаты.

Это реализовано в pymrt.geometry.fill_convex() для N-мерных задач (пока недоступно в версии pypi, необходимо взять из репозитория Bitbucket).Отказ от ответственности, я являюсь основным автором этого.

Вкратце, (упрощенный) код (адаптированный к 3D) выглядит так:

def fill_convex(arr):
    for i in range(arr.shape[1]):
        for j in range(arr.shape[2]):
            mask = slice(None), slice(i, i + 1), slice(j, j + 1)
            line = arr[mask]
            k = np.where(line > 0)[0]
            if len(k):
                start, stop = np.min(k), np.max(k)
                line[start:stop] = 1
    return arr

Чтобы увидеть это в действии на бетоне (но2D и не цилиндрический / эллиптический) пример:

import numpy as np
import pymrt as mrt
import pymrt.geometry

# generate a convex border (although it is not elliptical)
points = ((1, 1), (0, 6), (5, 4), (4, 2))
line_points = tuple(x for x in mrt.geometry.bresenham_lines(points, True))
arr = mrt.geometry.render_at((8, 8), line_points)
print(arr.astype(int))
# [[0 0 0 0 1 1 1 0]
#  [0 1 1 1 0 0 1 0]
#  [0 1 0 0 0 1 0 0]
#  [0 0 1 0 0 1 0 0]
#  [0 0 1 0 1 0 0 0]
#  [0 0 0 1 1 0 0 0]
#  [0 0 0 0 0 0 0 0]
#  [0 0 0 0 0 0 0 0]]

# fill everything inside the convex shape
arr = mrt.geometry.fill_convex(arr)
print(arr.astype(int)
# [[0 0 0 0 1 1 1 0]
#  [0 1 1 1 1 1 1 0]
#  [0 1 1 1 1 1 0 0]
#  [0 0 1 1 1 1 0 0]
#  [0 0 1 1 1 0 0 0]
#  [0 0 0 1 1 0 0 0]
#  [0 0 0 0 0 0 0 0]
#  [0 0 0 0 0 0 0 0]]
0 голосов
/ 25 сентября 2018

Если у вас отмечены ячейки поверхности и нет дополнительной информации, то просканируйте массив слой за слоем, чтобы получить первую отмеченную ячейку (или получите некоторую ячейку поверхности, если они известны).

Когда вы отметилиЯчейка поверхности [z, y, x], заполнить строку в массиве последнего измерения (x) 1d, пока не встретится новая отмеченная ячейка.

Затем найдите соседнюю отмеченную ячейку в том же слое верхнего уровня (то же самое z, закройте y и x) и повторите, чтобы заполнить линии, пока не будет заполнен весь раздел (эллипс или вырезанный эллипс), затем переходите к следующему слою z

Edit
Возможно, я слишком усложняюпроблема, и алгоритм FloodFill является простым решением.

...