由Xarray

时间:2019-02-18 18:20:57

标签: python pandas numpy python-xarray

背景:

我正在使用Xarray分析医学影像和区域定义的轮廓。我的xarray是像素值的3D数组,其坐标由患者坐标系(x,y,z)定义,单位为mm。

我有一系列坐标(以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 :(得分:0)

好吧,我想我明白了。不知道这是否是最好的方法。欢迎提出建议。

需要构造一个由顶点坐标定义的多边形,必须将其转换为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)

这是一个最低限度的示例!