def get_centerline(im_seg, algo_fitting='polyfit', minmax=True, param=ParamCenterline(), verbose=1): """ Extract centerline from an image (using optic) or from a binary or weighted segmentation (using the center of mass). :param im_seg: Image(): Input segmentation or series of points along the centerline. :param algo_fitting: str: polyfit: Polynomial fitting nurbs: optic: Automatic segmentation using SVM and HOG. See [Gros et al. MIA 2018]. :param minmax: Crop output centerline where the segmentation starts/end. If False, centerline will span all slices. :param param: ParamCenterline() :param verbose: int: verbose level :return: im_centerline: Image: Centerline in discrete coordinate (int) :return: arr_centerline: 3x1 array: Centerline in continuous coordinate (float) for each slice in RPI orientation. :return: arr_centerline_deriv: 3x1 array: Derivatives of x and y centerline wrt. z for each slice in RPI orient. """ if not isinstance(im_seg, Image): raise ValueError("Expecting an image") # Open image and change to RPI orientation native_orientation = im_seg.orientation im_seg.change_orientation('RPI') px, py, pz = im_seg.dim[4:7] # Take the center of mass at each slice to avoid: https://stackoverflow.com/questions/2009379/interpolate-question x_mean, y_mean, z_mean = find_and_sort_coord(im_seg) # Crop output centerline to where the segmentation starts/end if minmax: z_ref = np.array( range(z_mean.min().astype(int), z_mean.max().astype(int))) else: z_ref = np.array(range(im_seg.dim[2])) # Choose method if algo_fitting == 'polyfit': x_centerline_fit, x_centerline_deriv = curve_fitting.polyfit_1d( z_mean, x_mean, z_ref, deg=param.degree) y_centerline_fit, y_centerline_deriv = curve_fitting.polyfit_1d( z_mean, y_mean, z_ref, deg=param.degree) elif algo_fitting == 'bspline': x_centerline_fit, x_centerline_deriv = curve_fitting.bspline( z_mean, x_mean, z_ref, deg=param.degree) y_centerline_fit, y_centerline_deriv = curve_fitting.bspline( z_mean, y_mean, z_ref, deg=param.degree) elif algo_fitting == 'linear': # Simple linear interpolation x_centerline_fit = curve_fitting.linear(z_mean, x_mean, z_ref) y_centerline_fit = curve_fitting.linear(z_mean, y_mean, z_ref) # Compute derivatives using polynomial fit due to undefined derivatives using linear interpolation _, x_centerline_deriv = curve_fitting.polyfit_1d(z_mean, x_mean, z_ref, deg=5) _, y_centerline_deriv = curve_fitting.polyfit_1d(z_mean, y_mean, z_ref, deg=5) elif algo_fitting == 'nurbs': from spinalcordtoolbox.centerline.nurbs import b_spline_nurbs # Interpolate such that the output centerline has the same length as z_ref x_mean_interp = curve_fitting.linear(z_mean, x_mean, z_ref) y_mean_interp = curve_fitting.linear(z_mean, y_mean, z_ref) x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, \ z_centerline_deriv, error = b_spline_nurbs(x_mean_interp, y_mean_interp, z_ref, nbControl=None, point_number=3000, all_slices=True) elif algo_fitting == 'optic': # This method is particular compared to the previous ones, as here we estimate the centerline based on the # image itself (not the segmentation). Hence, we can bypass the fitting procedure and centerline creation # and directly output results. from spinalcordtoolbox.centerline import optic im_centerline = optic.detect_centerline(im_seg, param.contrast) x_centerline_fit, y_centerline_fit, z_centerline = find_and_sort_coord( im_centerline) # Compute derivatives using polynomial fit # TODO: Fix below with reorientation of axes _, x_centerline_deriv = curve_fitting.polyfit_1d(z_centerline, x_centerline_fit, z_centerline, deg=5) _, y_centerline_deriv = curve_fitting.polyfit_1d(z_centerline, y_centerline_fit, z_centerline, deg=5) return im_centerline.change_orientation(native_orientation), \ np.array([x_centerline_fit, y_centerline_fit, z_centerline]), \ np.array([x_centerline_deriv, y_centerline_deriv, np.ones_like(z_centerline)]), # Display fig of fitted curves if verbose == 2: from datetime import datetime import matplotlib matplotlib.use('Agg') # prevent display figure import matplotlib.pyplot as plt plt.figure() plt.subplot(2, 1, 1) plt.title("Algo=%s, Deg=%s" % (algo_fitting, param.degree)) plt.plot(z_ref * pz, x_centerline_fit * px) plt.plot(z_ref * pz, x_centerline_fit * px, 'b.') plt.plot(z_mean * pz, x_mean * px, 'ro') plt.ylabel("X [mm]") plt.subplot(2, 1, 2) plt.plot(z_ref, y_centerline_fit) plt.plot(z_ref, y_centerline_fit, 'b.') plt.plot(z_mean, y_mean, 'ro') plt.xlabel("Z [mm]") plt.ylabel("Y [mm]") plt.savefig('fig_centerline_' + datetime.now().strftime("%y%m%d%H%M%S%f") + '_' + algo_fitting + '.png') plt.close() # Create an image with the centerline im_centerline = im_seg.copy() im_centerline.data = np.zeros(im_centerline.data.shape) # Assign value=1 to centerline. Make sure to clip to avoid array overflow. # TODO: check this round and clip-- suspicious im_centerline.data[ round_and_clip(x_centerline_fit, clip=[0, im_centerline.data.shape[0]] ), round_and_clip(y_centerline_fit, clip=[0, im_centerline.data.shape[1]] ), z_ref] = 1 # reorient centerline to native orientation im_centerline.change_orientation(native_orientation) # TODO: Reorient centerline in native orientation. For now, we output the array in RPI. Note that it is tricky to # reorient in native orientation, because the voxel center is not in the middle, but in the top corner, so this # needs to be taken into accound during reorientation. The code below does not work properly. # # Get a permutation and inversion based on native orientation # perm, inversion = _get_permutations(im_seg.orientation, native_orientation) # # axes inversion (flip) # # ctl = np.array([x_centerline_fit[::inversion[0]], y_centerline_fit[::inversion[1]], z_ref[::inversion[2]]]) # ctl = np.array([x_centerline_fit, y_centerline_fit, z_ref]) # ctl_deriv = np.array([x_centerline_deriv[::inversion[0]], y_centerline_deriv[::inversion[1]], np.ones_like(z_ref)]) # return im_centerline, \ # np.array([ctl[perm[0]], ctl[perm[1]], ctl[perm[2]]]), \ # np.array([ctl_deriv[perm[0]], ctl_deriv[perm[1]], ctl_deriv[perm[2]]]) return im_centerline, \ np.array([x_centerline_fit, y_centerline_fit, z_ref]), \ np.array([x_centerline_deriv, y_centerline_deriv, np.ones_like(z_ref)])
def get_centerline(im_seg, param=ParamCenterline(), verbose=1): """ Extract centerline from an image (using optic) or from a binary or weighted segmentation (using the center of mass). :param im_seg: Image(): Input segmentation or series of points along the centerline. :param param: ParamCenterline() class: :param verbose: int: verbose level :return: im_centerline: Image: Centerline in discrete coordinate (int) :return: arr_centerline: 3x1 array: Centerline in continuous coordinate (float) for each slice in RPI orientation. :return: arr_centerline_deriv: 3x1 array: Derivatives of x and y centerline wrt. z for each slice in RPI orient. :return: fit_results: FitResults class """ if not isinstance(im_seg, Image): raise ValueError("Expecting an image") # Open image and change to RPI orientation native_orientation = im_seg.orientation im_seg.change_orientation('RPI') px, py, pz = im_seg.dim[4:7] # Take the center of mass at each slice to avoid: https://stackoverflow.com/questions/2009379/interpolate-question x_mean, y_mean, z_mean = find_and_sort_coord(im_seg) # Crop output centerline to where the segmentation starts/end if param.minmax: z_ref = np.array(range(z_mean.min().astype(int), z_mean.max().astype(int) + 1)) else: z_ref = np.array(range(im_seg.dim[2])) index_mean = np.array([list(z_ref).index(i) for i in z_mean]) # Choose method if param.algo_fitting == 'polyfit': x_centerline_fit, x_centerline_deriv = curve_fitting.polyfit_1d(z_mean, x_mean, z_ref, deg=param.degree) y_centerline_fit, y_centerline_deriv = curve_fitting.polyfit_1d(z_mean, y_mean, z_ref, deg=param.degree) fig_title = 'Algo={}, Deg={}'.format(param.algo_fitting, param.degree) elif param.algo_fitting == 'bspline': x_centerline_fit, x_centerline_deriv = curve_fitting.bspline(z_mean, x_mean, z_ref, param.smooth, pz=pz) y_centerline_fit, y_centerline_deriv = curve_fitting.bspline(z_mean, y_mean, z_ref, param.smooth, pz=pz) fig_title = 'Algo={}, Smooth={}'.format(param.algo_fitting, param.smooth) elif param.algo_fitting == 'linear': # Simple linear interpolation x_centerline_fit, x_centerline_deriv = curve_fitting.linear(z_mean, x_mean, z_ref, param.smooth, pz=pz) y_centerline_fit, y_centerline_deriv = curve_fitting.linear(z_mean, y_mean, z_ref, param.smooth, pz=pz) fig_title = 'Algo={}, Smooth={}'.format(param.algo_fitting, param.smooth) elif param.algo_fitting == 'nurbs': from spinalcordtoolbox.centerline.nurbs import b_spline_nurbs point_number = 3000 # Interpolate such that the output centerline has the same length as z_ref x_mean_interp, _ = curve_fitting.linear(z_mean, x_mean, z_ref, 0) y_mean_interp, _ = curve_fitting.linear(z_mean, y_mean, z_ref, 0) x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, \ z_centerline_deriv, error = b_spline_nurbs(x_mean_interp, y_mean_interp, z_ref, nbControl=None, point_number=point_number, all_slices=True) # Normalize derivatives to z_deriv x_centerline_deriv = x_centerline_deriv / z_centerline_deriv y_centerline_deriv = y_centerline_deriv / z_centerline_deriv fig_title = 'Algo={}, NumberPoints={}'.format(param.algo_fitting, point_number) elif param.algo_fitting == 'optic': # This method is particular compared to the previous ones, as here we estimate the centerline based on the # image itself (not the segmentation). Hence, we can bypass the fitting procedure and centerline creation # and directly output results. from spinalcordtoolbox.centerline import optic assert param.contrast is not None im_centerline = optic.detect_centerline(im_seg, param.contrast, verbose) x_centerline_fit, y_centerline_fit, z_centerline = find_and_sort_coord(im_centerline) # Compute derivatives using polynomial fit # TODO: Fix below with reorientation of axes _, x_centerline_deriv = curve_fitting.polyfit_1d(z_centerline, x_centerline_fit, z_centerline, deg=param.degree) _, y_centerline_deriv = curve_fitting.polyfit_1d(z_centerline, y_centerline_fit, z_centerline, deg=param.degree) return \ im_centerline.change_orientation(native_orientation), \ np.array([x_centerline_fit, y_centerline_fit, z_centerline]), \ np.array([x_centerline_deriv, y_centerline_deriv, np.ones_like(z_centerline)]), \ None else: logger.error('algo_fitting "' + param.algo_fitting + '" does not exist.') raise ValueError # Create an image with the centerline im_centerline = im_seg.copy() im_centerline.data = np.zeros(im_centerline.data.shape) # Assign value=1 to centerline. Make sure to clip to avoid array overflow. # TODO: check this round and clip-- suspicious im_centerline.data[round_and_clip(x_centerline_fit, clip=[0, im_centerline.data.shape[0]]), round_and_clip(y_centerline_fit, clip=[0, im_centerline.data.shape[1]]), z_ref] = 1 # reorient centerline to native orientation im_centerline.change_orientation(native_orientation) im_seg.change_orientation(native_orientation) # TODO: Reorient centerline in native orientation. For now, we output the array in RPI. Note that it is tricky to # reorient in native orientation, because the voxel center is not in the middle, but in the top corner, so this # needs to be taken into accound during reorientation. The code below does not work properly. # # Get a permutation and inversion based on native orientation # perm, inversion = _get_permutations(im_seg.orientation, native_orientation) # # axes inversion (flip) # # ctl = np.array([x_centerline_fit[::inversion[0]], y_centerline_fit[::inversion[1]], z_ref[::inversion[2]]]) # ctl = np.array([x_centerline_fit, y_centerline_fit, z_ref]) # ctl_deriv = np.array([x_centerline_deriv[::inversion[0]], y_centerline_deriv[::inversion[1]], np.ones_like(z_ref)]) # return im_centerline, \ # np.array([ctl[perm[0]], ctl[perm[1]], ctl[perm[2]]]), \ # np.array([ctl_deriv[perm[0]], ctl_deriv[perm[1]], ctl_deriv[perm[2]]]) # Compute fitting metrics fit_results = FitResults() fit_results.rmse = np.sqrt(np.mean((x_mean - x_centerline_fit[index_mean]) ** 2) * px + np.mean((y_mean - y_centerline_fit[index_mean]) ** 2) * py) fit_results.laplacian_max = np.max([ np.absolute(np.gradient(np.array(x_centerline_deriv * px))).max(), np.absolute(np.gradient(np.array(y_centerline_deriv * py))).max()]) fit_results.data.zmean = z_mean fit_results.data.zref = z_ref fit_results.data.xmean = x_mean fit_results.data.xfit = x_centerline_fit fit_results.data.ymean = y_mean fit_results.data.yfit = y_centerline_fit fit_results.param = param # Display fig of fitted curves if verbose == 2: from datetime import datetime import matplotlib matplotlib.use('Agg') # prevent display figure import matplotlib.pyplot as plt plt.figure(figsize=(16, 10)) plt.subplot(3, 1, 1) plt.title(fig_title + '\nRMSE[mm]={:0.2f}, LaplacianMax={:0.2f}'.format(fit_results.rmse, fit_results.laplacian_max)) plt.plot(z_mean * pz, x_mean * px, 'ro') plt.plot(z_ref * pz, x_centerline_fit * px, 'k') plt.plot(z_ref * pz, x_centerline_fit * px, 'k.') plt.ylabel("X [mm]") plt.legend(['Reference', 'Fitting', 'Fitting points']) plt.subplot(3, 1, 2) plt.plot(z_mean * pz, y_mean * py, 'ro') plt.plot(z_ref * pz, y_centerline_fit * py, 'b') plt.plot(z_ref * pz, y_centerline_fit * py, 'b.') plt.xlabel("Z [mm]") plt.ylabel("Y [mm]") plt.legend(['Reference', 'Fitting', 'Fitting points']) plt.subplot(3, 1, 3) plt.plot(z_ref * pz, x_centerline_deriv * px, 'k.') plt.plot(z_ref * pz, y_centerline_deriv * py, 'b.') plt.grid(axis='y', color='grey', linestyle=':', linewidth=1) plt.axhline(color='grey', linestyle='-', linewidth=1) # plt.plot(z_ref * pz, z_centerline_deriv * pz, 'r.') plt.ylabel("dX/dZ, dY/dZ") plt.xlabel("Z [mm]") plt.legend(['X-deriv', 'Y-deriv']) plt.savefig('fig_centerline_' + datetime.now().strftime("%y%m%d-%H%M%S%f") + '_' + param.algo_fitting + '.png') plt.close() return im_centerline, \ np.array([x_centerline_fit, y_centerline_fit, z_ref]), \ np.array([x_centerline_deriv, y_centerline_deriv, np.ones_like(z_ref)]), \ fit_results
def dummy_centerline(size_arr=(9, 9, 9), pixdim=(1, 1, 1), subsampling=1, dilate_ctl=0, hasnan=False, zeroslice=[], outlier=[], orientation='RPI', debug=False): """ Create a dummy Image centerline of small size. Return the full and sub-sampled version along z. Voxel resolution on fully-sampled data is 1x1x1 mm (so, 2x undersampled data along z would have resolution of 1x1x2 mm). :param size_arr: tuple: (nx, ny, nz) :param pixdim: tuple: (px, py, pz) :param subsampling: int >=1. Subsampling factor along z. 1: no subsampling. 2: centerline defined every other z. :param dilate_ctl: Dilation of centerline. E.g., if dilate_ctl=1, result will be a square of 3x3 per slice. if dilate_ctl=0, result will be a single pixel per slice. :param hasnan: Bool: Image has non-numerical values: nan, inf. In this case, do not subsample. :param zeroslice: list int: zero all slices listed in this param :param outlier: list int: replace the current point with an outlier at the corner of the image for the slices listed :param orientation: :param debug: Bool: Write temp files :return: """ nx, ny, nz = size_arr # create regularized curve, within X-Z plane, located at y=ny/4, passing through the following points: x = np.array([round(nx / 4.), round(nx / 2.), round(3 * nx / 4.)]) z = np.array([0, round(nz / 2.), nz - 1]) # we use bspline (instead of poly) in order to avoid bad extrapolation at edges # see: https://github.com/spinalcordtoolbox/spinalcordtoolbox/pull/2754 xfit, _ = bspline(z, x, range(nz), 10) # p = P.fit(z, x, 3) # p = np.poly1d(np.polyfit(z, x, deg=3)) data = np.zeros((nx, ny, nz)) arr_ctl = np.array( [xfit.astype(np.int), [round(ny / 4.)] * len(range(nz)), range(nz)], dtype=np.uint16) # Loop across dilation of centerline. E.g., if dilate_ctl=1, result will be a square of 3x3 per slice. for ixiy_ctl in itertools.product(range(-dilate_ctl, dilate_ctl + 1, 1), range(-dilate_ctl, dilate_ctl + 1, 1)): data[(arr_ctl[0] + ixiy_ctl[0]).tolist(), (arr_ctl[1] + ixiy_ctl[1]).tolist(), arr_ctl[2].tolist()] = 1 # Zero specified slices if zeroslice is not []: data[:, :, zeroslice] = 0 # Add outlier if outlier is not []: # First, zero all the slice data[:, :, outlier] = 0 # Then, add point in the corner data[0, 0, outlier] = 1 # Create image with default orientation LPI affine = np.eye(4) affine[0:3, 0:3] = affine[0:3, 0:3] * pixdim nii = nib.nifti1.Nifti1Image(data, affine) img = Image(data, hdr=nii.header, dim=nii.header.get_data_shape()) # subsample data img_sub = img.copy() img_sub.data = np.zeros((nx, ny, nz)) for iz in range(0, nz, subsampling): img_sub.data[..., iz] = data[..., iz] # Add non-numerical values at the top corner of the image if hasnan: img.data[0, 0, 0] = np.nan img.data[1, 0, 0] = np.inf # Update orientation img.change_orientation(orientation) img_sub.change_orientation(orientation) if debug: img_sub.save('tmp_dummy_seg_' + datetime.now().strftime("%Y%m%d%H%M%S%f") + '.nii.gz') return img, img_sub, arr_ctl
def get_centerline(im_seg, algo_fitting='polyfit', minmax=True, contrast=None, degree=5, smooth=10, verbose=1): """ Extract centerline from an image (using optic) or from a binary or weighted segmentation (using the center of mass). :param im_seg: Image(): Input segmentation or series of points along the centerline. :param algo_fitting: str: polyfit: Polynomial fitting nurbs: optic: Automatic segmentation using SVM and HOG. See [Gros et al. MIA 2018]. :param minmax: Crop output centerline where the segmentation starts/end. If False, centerline will span all slices. :param contrast: Contrast type for algo=optic. :param degree: int: Max degree for polynomial fitting. :param smooth: int: Smoothing factor for bspline fitting. 1: none, 10: moderate smoothing, 100: large smoothing :param verbose: int: verbose level :return: im_centerline: Image: Centerline in discrete coordinate (int) :return: arr_centerline: 3x1 array: Centerline in continuous coordinate (float) for each slice in RPI orientation. :return: arr_centerline_deriv: 3x1 array: Derivatives of x and y centerline wrt. z for each slice in RPI orient. """ if not isinstance(im_seg, Image): raise ValueError("Expecting an image") # Open image and change to RPI orientation native_orientation = im_seg.orientation im_seg.change_orientation('RPI') px, py, pz = im_seg.dim[4:7] # Take the center of mass at each slice to avoid: https://stackoverflow.com/questions/2009379/interpolate-question x_mean, y_mean, z_mean = find_and_sort_coord(im_seg) # Crop output centerline to where the segmentation starts/end if minmax: z_ref = np.array(range(z_mean.min().astype(int), z_mean.max().astype(int) + 1)) else: z_ref = np.array(range(im_seg.dim[2])) # Choose method if algo_fitting == 'polyfit': x_centerline_fit, x_centerline_deriv = curve_fitting.polyfit_1d(z_mean, x_mean, z_ref, deg=degree) y_centerline_fit, y_centerline_deriv = curve_fitting.polyfit_1d(z_mean, y_mean, z_ref, deg=degree) elif algo_fitting == 'bspline': x_centerline_fit, x_centerline_deriv = curve_fitting.bspline(z_mean, x_mean, z_ref, smooth=smooth) y_centerline_fit, y_centerline_deriv = curve_fitting.bspline(z_mean, y_mean, z_ref, smooth=smooth) elif algo_fitting == 'linear': # Simple linear interpolation x_centerline_fit = curve_fitting.linear(z_mean, x_mean, z_ref) y_centerline_fit = curve_fitting.linear(z_mean, y_mean, z_ref) # Compute derivatives using polynomial fit due to undefined derivatives using linear interpolation _, x_centerline_deriv = curve_fitting.polyfit_1d(z_mean, x_mean, z_ref, deg=degree) _, y_centerline_deriv = curve_fitting.polyfit_1d(z_mean, y_mean, z_ref, deg=degree) elif algo_fitting == 'nurbs': from spinalcordtoolbox.centerline.nurbs import b_spline_nurbs # Interpolate such that the output centerline has the same length as z_ref x_mean_interp = curve_fitting.linear(z_mean, x_mean, z_ref) y_mean_interp = curve_fitting.linear(z_mean, y_mean, z_ref) x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, \ z_centerline_deriv, error = b_spline_nurbs(x_mean_interp, y_mean_interp, z_ref, nbControl=None, point_number=3000, all_slices=True) elif algo_fitting == 'optic': # This method is particular compared to the previous ones, as here we estimate the centerline based on the # image itself (not the segmentation). Hence, we can bypass the fitting procedure and centerline creation # and directly output results. from spinalcordtoolbox.centerline import optic im_centerline = optic.detect_centerline(im_seg, contrast, verbose) x_centerline_fit, y_centerline_fit, z_centerline = find_and_sort_coord(im_centerline) # Compute derivatives using polynomial fit # TODO: Fix below with reorientation of axes _, x_centerline_deriv = curve_fitting.polyfit_1d(z_centerline, x_centerline_fit, z_centerline, deg=degree) _, y_centerline_deriv = curve_fitting.polyfit_1d(z_centerline, y_centerline_fit, z_centerline, deg=degree) return im_centerline.change_orientation(native_orientation), \ np.array([x_centerline_fit, y_centerline_fit, z_centerline]), \ np.array([x_centerline_deriv, y_centerline_deriv, np.ones_like(z_centerline)]), else: logging.error('algo_fitting "' + algo_fitting + '" does not exist.') raise ValueError # Display fig of fitted curves if verbose == 2: from datetime import datetime import matplotlib matplotlib.use('Agg') # prevent display figure import matplotlib.pyplot as plt plt.figure() plt.subplot(2, 1, 1) plt.title("Algo=%s, Deg=%s" % (algo_fitting, degree)) plt.plot(z_ref * pz, x_centerline_fit * px) plt.plot(z_ref * pz, x_centerline_fit * px, 'b.') plt.plot(z_mean * pz, x_mean * px, 'ro') plt.ylabel("X [mm]") plt.subplot(2, 1, 2) plt.plot(z_ref, y_centerline_fit) plt.plot(z_ref, y_centerline_fit, 'b.') plt.plot(z_mean, y_mean, 'ro') plt.xlabel("Z [mm]") plt.ylabel("Y [mm]") plt.savefig('fig_centerline_' + datetime.now().strftime("%y%m%d%H%M%S%f") + '_' + algo_fitting + '.png') plt.close() # Create an image with the centerline im_centerline = im_seg.copy() im_centerline.data = np.zeros(im_centerline.data.shape) # Assign value=1 to centerline. Make sure to clip to avoid array overflow. # TODO: check this round and clip-- suspicious im_centerline.data[round_and_clip(x_centerline_fit, clip=[0, im_centerline.data.shape[0]]), round_and_clip(y_centerline_fit, clip=[0, im_centerline.data.shape[1]]), z_ref] = 1 # reorient centerline to native orientation im_centerline.change_orientation(native_orientation) # TODO: Reorient centerline in native orientation. For now, we output the array in RPI. Note that it is tricky to # reorient in native orientation, because the voxel center is not in the middle, but in the top corner, so this # needs to be taken into accound during reorientation. The code below does not work properly. # # Get a permutation and inversion based on native orientation # perm, inversion = _get_permutations(im_seg.orientation, native_orientation) # # axes inversion (flip) # # ctl = np.array([x_centerline_fit[::inversion[0]], y_centerline_fit[::inversion[1]], z_ref[::inversion[2]]]) # ctl = np.array([x_centerline_fit, y_centerline_fit, z_ref]) # ctl_deriv = np.array([x_centerline_deriv[::inversion[0]], y_centerline_deriv[::inversion[1]], np.ones_like(z_ref)]) # return im_centerline, \ # np.array([ctl[perm[0]], ctl[perm[1]], ctl[perm[2]]]), \ # np.array([ctl_deriv[perm[0]], ctl_deriv[perm[1]], ctl_deriv[perm[2]]]) return im_centerline, \ np.array([x_centerline_fit, y_centerline_fit, z_ref]), \ np.array([x_centerline_deriv, y_centerline_deriv, np.ones_like(z_ref)])