Beispiel #1
0
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)])
Beispiel #2
0
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
Beispiel #4
0
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)])