3D маска из многоугольника, определяемая серией координат в Xarray - PullRequest
0 голосов
/ 18 февраля 2019

Фон:

Я использую Xarray для анализа медицинской визуализации и контуров, определенных в регионе.Мой xarray - это трехмерный массив значений пикселей с координатами, определенными системой координат пациента (x, y, z) в мм.

У меня есть ряд координат (в x, y, z), которые определяют вершины комплексного многоугольника.Это список кортежей, где каждый список определяет все вершины в z-плоскости.например,

[[(x1, y1, z1),..(xN, yN, z1)], [(x1, y1, z2),..(xM, yM, z2)], ...]

Я сделал цифру, но мой хопситал заблокировал доступ ко всем веб-сайтам обмена изображениями, которые я пробовал.Сожалею.

Запрос справки:

Я хотел бы создать маску области, определяемой этими многоугольными координатами.Мне трудно понять, как это сделать.Руководство будет высоко оценено !!

Вот некоторый игрушечный код для иллюстрации:

pixel_data = np.ones((5,5,5))
x_coords = np.arange(2.4, 7.4, 1)
y_coords = np.arange(-3.6, 1.4, 1)
z_coords = np.arange(202.7, 207.7, 1)[::-1]
coords = {'x': x_coords, 'y': y_coords, 'z': z_coords}

example = xr.DataArray(pixel_data, dims=('y','x','z'), coords=coords)

Массив:

<xarray.DataArray (y: 5, x: 5, z: 5)>
    array([[[1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1.],
            [1., 1., 1., 1., 1.]],
                  ...

Coordinates:
* x        (x) float64 2.4 3.4 4.4 5.4 6.4
* y        (y) float64 -3.6 -2.6 -1.6 -0.6 0.4
* z        (z) float64 206.7 205.7 204.7 203.7 202.7

contours = [[(2.4, -3.6, 203.7),(3.4, 0.4, 203.7),(6.4, -1.6, 203.7)],
            [(2.4, -2.6, 204.7),(4.4, 0.4, 204.7),(6.4, -3.6, 204.7)]]

Координаты x, y и z вкаждый кортеж всегда будет точно соответствовать координатам x, y, z в моем массиве данных.

1 Ответ

0 голосов
/ 19 февраля 2019

Хорошо, думаю, я понял это.Не уверен, что это лучший способ.Предложения приветствуются.

Необходимо построить многоугольник, определяемый координатами вершины, который необходимо преобразовать в координаты индекса в измерениях x, y.После построения многоугольника относительно просто назначить значения маски.Смотрите ниже:

from PIL import Image, ImageDraw
import xarray as xr
import numpy as np

pixel_data = np.ones((5,5,5))
x_coords = np.arange(2.4, 7.4, 1)
y_coords = np.arange(-3.6, 1.4, 1)
z_coords = np.arange(202.7, 207.7, 1)[::-1]
coords = {'x': x_coords, 'y': y_coords, 'z': z_coords}

example = xr.DataArray(pixel_data, dims=('y','x','z'), coords=coords)

contours = [[(2.4, -3.6, 203.7),(3.4, 0.4, 203.7),(6.4, -1.6, 203.7)],
            [(2.4, -2.6, 204.7),(4.4, 0.4, 204.7),(6.4, -3.6, 204.7)]]

def create_mask(array, contour_list):
    'Takes in an Array we want to mask, and a contour'
    'coordinate nested list.'
    mask_array = xr.zeros_like(array)
    slice_dict = {}
    mask_dict = {}

    for i, coord in enumerate(contour_list):
        'Each list inside contour_list is a list of (x,y,z)'
        'coordinates defining the contour on each slice. For each'
        'sequence, the z coord is constant. This for-loop builds'
        'a numpy array for each series of (x,y) coordinates and'
        'stores them in a dict where the corresponding key is the'
        'z-coordinate.'
        x_start = float(example.x[0].values)
        y_start = float(example.y[0].values)
        spacing = float(example.x[0].values) - float(example.x[1].values)
        resized = np.resize(coord, (int(np.size(coord) / 3), 3))
        rtstruct_pixelArray = (resized[:,:2] - [x_start, y_start]) / spacing
        rtstruct_pixelArray = np.rint(rtstruct_pixelArray)
        slice_dict[coord[0][2]] = rtstruct_pixelArray


    for z_slc in slice_dict.keys():
        'For each z-slice, we need to draw a polygon defined by'
        'the points we pulled above. We can do this with ImageDraw.'
        polygon = slice_dict[z_slc].flatten().tolist()
        img = Image.new('L', (example.shape[0], example.shape[1]), 0)
        ImageDraw.Draw(img).polygon(polygon, outline=255, fill=255)
        mask = np.array(img)
        mask_dict[z_slc] = mask

    for z_slc in mask_dict.keys():
        'We can reassign values in mask_array with indexing.'
        'We rely on sel to give us the slice we need. This works'
        'because xarray does not copy the data with sel.'
        mask_slice = mask_array.sel(z=z_slc, method='nearest')
        mask_slice[:,:] = mask_dict[z_slc]

    return mask_array

mask = create_mask(example, contours)

Это минимально работающий пример!

...