简体   繁体   English

由Xarray中的一系列坐标定义的多边形3D蒙版

[英]3D mask from polygon defined by series of coordinates in Xarray

Background: 背景:

I am using Xarray to analyze medical imaging and region defined contours. 我正在使用Xarray分析医学影像和区域定义的轮廓。 My xarray is a 3D array of pixel values with coordinates defined by the patient coordinate system (x, y, z) in mm. 我的xarray是像素值的3D数组,其坐标由患者坐标系(x,y,z)定义,单位为mm。

I have a series of coordinates (in x,y,z) which define the vertices of a complex polygon. 我有一系列坐标(以x,y,z表示),它们定义了复杂多边形的顶点。 It is a list of tuples, where each list defines all the vertices in the z-plane. 它是一个元组列表,其中每个列表定义了z平面中的所有顶点。 eg 例如

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

I made a figure, but my hopsital has blocked access to every image sharing website I tried. 我做了一个数字,但我的医院已禁止访问我尝试过的每个图像共享网站。 Sorry. 抱歉。

Help Request: 帮助请求:

I'd like to create a mask of the region defined by these polygon-coordinates. 我想为这些多边形坐标定义的区域创建一个遮罩。 I'm having a hard time figuring out how to do this. 我很难弄清楚该怎么做。 Guidance would be much appreciated!! 指导将不胜感激!

Here is some toy code to illustrate: 这是一些玩具代码说明:

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)

Array: 数组:

<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)]]

The x, y, and z coordinates in each tuple will always exactly match an x, y, z-coordinate in my data array. 每个元组中的x,y和z坐标将始终与我的数据数组中的x,y,z坐标完全匹配。

Ok, I think I figured it out. 好吧,我想我明白了。 Not sure if it's the best way. 不知道这是否是最好的方法。 Suggestions welcome. 欢迎提出建议。

Need to construct a polygon defined by the vertex coordinates, which have to be converted to index coordinates in the x,y dimensions. 需要构造一个由顶点坐标定义的多边形,必须将其转换为x,y维度中的索引坐标。 Once the polygon is constructed it's relatively simple to assign mask values. 构造完多边形后,分配遮罩值相对简单。 See below: 见下文:

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)

That's a minimally working example! 这是一个最低限度的工作示例!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM