Ejemplo n.º 1
0
def register_slicereg2d_rigid(fname_source, fname_dest, window_length=31, paramreg=Paramreg(step='0', type='im', algo='Rigid', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5'),
                              fname_mask='', warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', factor=2, remove_temp_files=1, verbose=0,
                              ants_registration_params={'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '','bspline': ',10', 'gaussiandisplacementfield': ',3,0',
                                                              'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3'}):
    """Slice-by-slice regularized registration (rigid) of two images.

    We first register slice-by-slice the two images using antsRegistration in 2D. Then we remove outliers using
    Median Absolute Deviation technique (MAD) and smooth the translations and angle of rotation along x and y axis using
    moving average hanning window. Eventually, we generate two warping fields (forward and inverse) resulting from this
    regularized registration technique.
    The images must be of same size (otherwise generate_warping_field will not work for forward or inverse
    creation).

    input:
        fname_source: name of moving image (type: string)
        fname_dest: name of fixed image (type: string)
        window_length[optional]: size of window for moving average smoothing (type: int)
        paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal)
        fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration)
        warp_forward_out[optional]: name of output forward warp (type: string)
        warp_inverse_out[optional]: name of output inverse warp (type: string)
        factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection)
            (type: int or float)
        remove_temp_files[optional]: 1 to remove, 0 to keep (type: int)
        verbose[optional]: display parameter (type: int, value: 0,1 or 2)
        ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary)

    output:
        creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'.
    """
    from msct_register_regularized import register_images, generate_warping_field
    from numpy import asarray
    from msct_smooth import smoothing_window, outliers_detection, outliers_completion

    # Calculate displacement
    x_disp, y_disp, theta_rot = register_images(fname_source, fname_dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params)
    # Change to array
    x_disp_a = asarray(x_disp)
    y_disp_a = asarray(y_disp)
    theta_rot_a = asarray(theta_rot)
    # Detect outliers
    mask_x_a = outliers_detection(x_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose)
    mask_y_a = outliers_detection(y_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose)
    mask_theta_a = outliers_detection(theta_rot_a, type='median', factor=2, return_filtered_signal='no', verbose=verbose)
    # Replace value of outliers by linear interpolation using closest non-outlier points
    x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0)
    y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0)
    theta_rot_a_no_outliers = outliers_completion(mask_theta_a, verbose=0)
    # Smooth results
    x_disp_smooth = smoothing_window(x_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose)
    y_disp_smooth = smoothing_window(y_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose)
    theta_rot_smooth = smoothing_window(theta_rot_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose)
    # Generate warping field
    generate_warping_field(fname_dest, x_disp_smooth, y_disp_smooth, theta_rot_smooth, fname=warp_forward_out)
    # Inverse warping field
    generate_warping_field(fname_source, -x_disp_smooth, -y_disp_smooth, -theta_rot_smooth, fname=warp_inverse_out)
Ejemplo n.º 2
0
def register_slicereg2d_pointwise(fname_source, fname_dest, window_length=31, paramreg=Paramreg(step='0', type='seg', algo='slicereg2d_pointwise', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5'),
                                  warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', factor=2, verbose=0):
    """Slice-by-slice regularized registration by translation of two segmentations.

    First we estimate for each slice the translation vector by calculating the difference of position of the two centers of
    mass of the two segmentations. Then we remove outliers using Median Absolute Deviation technique (MAD) and smooth
    the translation along x and y axis using moving average hanning window. Eventually, we generate two warping fields
    (forward and inverse) resulting from this regularized registration technique.
    The segmentations must be of same size (otherwise generate_warping_field will not work for forward or inverse
    creation).

    input:
        fname_source: name of moving image (type: string)
        fname_dest: name of fixed image (type: string)
        window_length: size of window for moving average smoothing (type: int)
        paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal)
        warp_forward_out: name of output forward warp (type: string)
        warp_inverse_out: name of output inverse warp (type: string)
        factor: sensibility factor for outlier detection (higher the factor, smaller the detection) (type: int or float)
        verbose: display parameter (type: int, value: 0,1 or 2)

    output:
        creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'.

    """
    if paramreg.type != 'seg':
        print '\nERROR: Algorithm slicereg2d_pointwise only operates for segmentation type.'
        sys.exit(2)
    else:
        from msct_register_regularized import register_seg, generate_warping_field
        from numpy import asarray
        from msct_smooth import smoothing_window, outliers_detection, outliers_completion
        # Calculate displacement
        x_disp, y_disp = register_seg(fname_source, fname_dest)
        # Change to array
        x_disp_a = asarray(x_disp)
        y_disp_a = asarray(y_disp)
        # Detect outliers
        mask_x_a = outliers_detection(x_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose)
        mask_y_a = outliers_detection(y_disp_a, type='median', factor=factor, return_filtered_signal='no', verbose=verbose)
        # Replace value of outliers by linear interpolation using closest non-outlier points
        x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0)
        y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0)
        # Smooth results
        x_disp_smooth = smoothing_window(x_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose)
        y_disp_smooth = smoothing_window(y_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose)
        # Generate warping field
        generate_warping_field(fname_dest, x_disp_smooth, y_disp_smooth, fname=warp_forward_out)  #name_warp= 'step'+str(paramreg.step)
        # Inverse warping field
        generate_warping_field(fname_source, -x_disp_smooth, -y_disp_smooth, fname=warp_inverse_out)
        from numpy import asarray
        from msct_smooth import smoothing_window

        # go to output folder
        print '\nGo to output folder ' + PATH_OUTPUT + '/subjects/' + subject + '/T1'
        os.chdir(PATH_OUTPUT + '/subjects/' + subject + '/T1')

        # Register seg to create first warping field and apply it
        print '\nUsing register_seg with centerlines to create first warping field and applying it...'
        x_disp, y_disp = register_seg('centerline_T1.nii.gz',
                                      'centerline_T2.nii.gz')
        x_disp_a = asarray(x_disp)
        y_disp_a = asarray(y_disp)
        x_disp_smooth = smoothing_window(x_disp_a,
                                         window_len=31,
                                         window='hanning',
                                         verbose=2)
        y_disp_smooth = smoothing_window(y_disp_a,
                                         window_len=31,
                                         window='hanning',
                                         verbose=2)

        generate_warping_field('centerline_T2.nii.gz',
                               x_disp_smooth,
                               y_disp_smooth,
                               fname='warping_field_seg.nii.gz')
        sct.run(
            'sct_apply_transfo -i data_RPI_registered.nii.gz -d data_T2_RPI.nii.gz -w warping_field_seg.nii.gz -o data_RPI_registered_reg1.nii.gz -x spline'
        )

        # Register_image to create second warping field and apply it
    for i in range(0, len(SUBJECTS_LIST)):
        subject = SUBJECTS_LIST[i][0]

        from numpy import asarray
        from msct_smooth import smoothing_window

        # go to output folder
        print "\nGo to output folder " + PATH_OUTPUT + "/subjects/" + subject + "/T1"
        os.chdir(PATH_OUTPUT + "/subjects/" + subject + "/T1")

        # Register seg to create first warping field and apply it
        print "\nUsing register_seg with centerlines to create first warping field and applying it..."
        x_disp, y_disp = register_seg("centerline_T1.nii.gz", "centerline_T2.nii.gz")
        x_disp_a = asarray(x_disp)
        y_disp_a = asarray(y_disp)
        x_disp_smooth = smoothing_window(x_disp_a, window_len=31, window="hanning", verbose=2)
        y_disp_smooth = smoothing_window(y_disp_a, window_len=31, window="hanning", verbose=2)

        generate_warping_field("centerline_T2.nii.gz", x_disp_smooth, y_disp_smooth, fname="warping_field_seg.nii.gz")
        sct.run(
            "sct_apply_transfo -i data_RPI_registered.nii.gz -d data_T2_RPI.nii.gz -w warping_field_seg.nii.gz -o data_RPI_registered_reg1.nii.gz -x spline"
        )

        # Register_image to create second warping field and apply it
        print "\nUsing register_image with images to create second warping field and applying it..."
        x_disp_2, y_disp_2 = register_images("data_RPI_registered_reg1.nii.gz", "data_T2_RPI.nii.gz")
        x_disp_2_a = asarray(x_disp_2)
        y_disp_2_a = asarray(y_disp_2)
        x_disp_2_smooth = smoothing_window(x_disp_2_a, window_len=31, window="hanning", verbose=2)
        y_disp_2_smooth = smoothing_window(y_disp_2_a, window_len=31, window="hanning", verbose=2)
                                        paramreg=Paramreg(step='0',
                                                          type='im',
                                                          algo='Rigid',
                                                          metric='MI',
                                                          iter='100',
                                                          shrink='1',
                                                          smooth='0',
                                                          gradStep='3'),
                                        remove_tmp_folder=1)

x_disp_a = asarray(x_disp)
y_disp_a = asarray(y_disp)
theta_a = asarray(theta)

x_disp_smooth = smoothing_window(x_disp_a,
                                 window_len=window_size,
                                 window='hanning',
                                 verbose=2)
y_disp_smooth = smoothing_window(y_disp_a,
                                 window_len=window_size,
                                 window='hanning',
                                 verbose=2)
theta_smooth = smoothing_window(theta_a,
                                window_len=window_size,
                                window='hanning',
                                verbose=2)
theta_smooth_inv = -theta_smooth

generate_warping_field(im_d,
                       x_disp_smooth,
                       y_disp_smooth,
                       theta_rot=theta_smooth,
def compute_csa(fname_segmentation, name_method, volume_output, verbose, remove_temp_files, step, smoothing_param, figure_fit, name_output, slices, vert_levels, path_to_template, algo_fitting = 'hanning', type_window = 'hanning', window_length = 80):

    # Extract path, file and extension
    fname_segmentation = os.path.abspath(fname_segmentation)
    path_data, file_data, ext_data = sct.extract_fname(fname_segmentation)

    # create temporary folder
    sct.printv('\nCreate temporary folder...', verbose)
    path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S"), 1)
    sct.run('mkdir '+path_tmp, verbose)

    # Copying input data to tmp folder and convert to nii
    sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose)
    sct.run('isct_c3d '+fname_segmentation+' -o '+path_tmp+'segmentation.nii')

    # go to tmp folder
    os.chdir(path_tmp)

    # Change orientation of the input segmentation into RPI
    sct.printv('\nChange orientation of the input segmentation into RPI...', verbose)
    fname_segmentation_orient = set_orientation('segmentation.nii', 'RPI', 'segmentation_orient.nii')

    # Get size of data
    sct.printv('\nGet data dimensions...', verbose)
    nx, ny, nz, nt, px, py, pz, pt = Image(fname_segmentation_orient).dim
    sct.printv('  ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose)

    # Open segmentation volume
    sct.printv('\nOpen segmentation volume...', verbose)
    file_seg = nibabel.load(fname_segmentation_orient)
    data_seg = file_seg.get_data()
    hdr_seg = file_seg.get_header()

    # # Extract min and max index in Z direction
    X, Y, Z = (data_seg > 0).nonzero()
    min_z_index, max_z_index = min(Z), max(Z)
    # Xp, Yp = (data_seg[:, :, 0] >= 0).nonzero()  # X and Y range

    # extract centerline and smooth it
    x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(fname_segmentation_orient, algo_fitting=algo_fitting, type_window=type_window, window_length=window_length, verbose=verbose)
    z_centerline_scaled = [x*pz for x in z_centerline]

    # Compute CSA
    sct.printv('\nCompute CSA...', verbose)

    # Empty arrays in which CSA for each z slice will be stored
    csa = np.zeros(max_z_index-min_z_index+1)
    # csa = [0.0 for i in xrange(0, max_z_index-min_z_index+1)]

    for iz in xrange(0, len(z_centerline)):

        # compute the vector normal to the plane
        normal = normalize(np.array([x_centerline_deriv[iz], y_centerline_deriv[iz], z_centerline_deriv[iz]]))

        # compute the angle between the normal vector of the plane and the vector z
        angle = np.arccos(np.dot(normal, [0, 0, 1]))

        # compute the number of voxels, assuming the segmentation is coded for partial volume effect between 0 and 1.
        number_voxels = sum(sum(data_seg[:, :, iz+min_z_index]))

        # compute CSA, by scaling with voxel size (in mm) and adjusting for oblique plane
        csa[iz] = number_voxels * px * py * np.cos(angle)

    if smoothing_param:
        from msct_smooth import smoothing_window
        sct.printv('\nSmooth CSA across slices...', verbose)
        sct.printv('.. Hanning window: '+str(smoothing_param)+' mm', verbose)
        csa_smooth = smoothing_window(csa, window_len=smoothing_param/pz, window='hanning', verbose=0)
        # display figure
        if verbose == 2:
            import matplotlib.pyplot as plt
            plt.figure()
            pltx, = plt.plot(z_centerline_scaled, csa, 'bo')
            pltx_fit, = plt.plot(z_centerline_scaled, csa_smooth, 'r', linewidth=2)
            plt.title("Cross-sectional area (CSA)")
            plt.xlabel('z (mm)')
            plt.ylabel('CSA (mm^2)')
            plt.legend([pltx, pltx_fit], ['Raw', 'Smoothed'])
            plt.show()
        # update variable
        csa = csa_smooth

    # Create output text file
    sct.printv('\nWrite text file...', verbose)
    file_results = open('csa.txt', 'w')
    for i in range(min_z_index, max_z_index+1):
        file_results.write(str(int(i)) + ',' + str(csa[i-min_z_index])+'\n')
        # Display results
        sct.printv('z='+str(i-min_z_index)+': '+str(csa[i-min_z_index])+' mm^2', verbose, 'bold')
    file_results.close()

    # output volume of csa values
    if volume_output:
        sct.printv('\nCreate volume of CSA values...', verbose)
        # get orientation of the input data
        orientation = get_orientation('segmentation.nii')
        data_seg = data_seg.astype(np.float32, copy=False)
        # loop across slices
        for iz in range(min_z_index, max_z_index+1):
            # retrieve seg pixels
            x_seg, y_seg = (data_seg[:, :, iz] > 0).nonzero()
            seg = [[x_seg[i],y_seg[i]] for i in range(0, len(x_seg))]
            # loop across pixels in segmentation
            for i in seg:
                # replace value with csa value
                data_seg[i[0], i[1], iz] = csa[iz-min_z_index]
        # create header
        hdr_seg.set_data_dtype('float32')  # set imagetype to uint8
        # save volume
        img = nibabel.Nifti1Image(data_seg, None, hdr_seg)
        nibabel.save(img, 'csa_RPI.nii')
        # Change orientation of the output centerline into input orientation
        fname_csa_volume = set_orientation('csa_RPI.nii', orientation, 'csa_RPI_orient.nii')

    # come back to parent folder
    os.chdir('..')

    # Generate output files
    sct.printv('\nGenerate output files...', verbose)
    from shutil import copyfile
    copyfile(path_tmp+'csa.txt', path_data+param.fname_csa)
    # sct.generate_output_file(path_tmp+'csa.txt', path_data+param.fname_csa)  # extension already included in param.fname_csa
    if volume_output:
        sct.generate_output_file(fname_csa_volume, path_data+name_output)  # extension already included in name_output

    # average csa across vertebral levels or slices if asked (flag -z or -l)
    if slices or vert_levels:

        if vert_levels and not path_to_template:
            sct.printv('\nERROR: Path to template is missing. See usage.\n', 1, 'error')
            sys.exit(2)
        elif vert_levels and path_to_template:
            abs_path_to_template = os.path.abspath(path_to_template)

        # go to tmp folder
        os.chdir(path_tmp)

        # create temporary folder
        sct.printv('\nCreate temporary folder to average csa...', verbose)
        path_tmp_extract_metric = sct.slash_at_the_end('label_temp', 1)
        sct.run('mkdir '+path_tmp_extract_metric, verbose)

        # Copying output CSA volume in the temporary folder
        sct.printv('\nCopy data to tmp folder...', verbose)
        sct.run('cp '+fname_segmentation+' '+path_tmp_extract_metric)

        # create file info_label
        path_fname_seg, file_fname_seg, ext_fname_seg = sct.extract_fname(fname_segmentation)
        create_info_label('info_label.txt', path_tmp_extract_metric, file_fname_seg+ext_fname_seg)

        # average CSA
        if slices:
            os.system("sct_extract_metric -i "+path_data+name_output+" -f "+path_tmp_extract_metric+" -m wa -o ../csa_mean.txt -z "+slices)
        if vert_levels:
            sct.run('cp -R '+abs_path_to_template+' .')
            os.system("sct_extract_metric -i "+path_data+name_output+" -f "+path_tmp_extract_metric+" -m wa -o ../csa_mean.txt -v "+vert_levels)

        os.chdir('..')

        # Remove temporary files
        print('\nRemove temporary folder used to average CSA...')
        sct.run('rm -rf '+path_tmp_extract_metric)

    # Remove temporary files
    if remove_temp_files:
        print('\nRemove temporary files...')
        sct.run('rm -rf '+path_tmp)
Ejemplo n.º 7
0
def compute_csa(fname_segmentation,
                name_method,
                volume_output,
                verbose,
                remove_temp_files,
                step,
                smoothing_param,
                figure_fit,
                name_output,
                slices,
                vert_levels,
                path_to_template,
                algo_fitting='hanning',
                type_window='hanning',
                window_length=80):

    # Extract path, file and extension
    fname_segmentation = os.path.abspath(fname_segmentation)
    path_data, file_data, ext_data = sct.extract_fname(fname_segmentation)

    # create temporary folder
    sct.printv('\nCreate temporary folder...', verbose)
    path_tmp = sct.slash_at_the_end('tmp.' + time.strftime("%y%m%d%H%M%S"), 1)
    sct.run('mkdir ' + path_tmp, verbose)

    # Copying input data to tmp folder and convert to nii
    sct.printv('\nCopying input data to tmp folder and convert to nii...',
               verbose)
    sct.run('isct_c3d ' + fname_segmentation + ' -o ' + path_tmp +
            'segmentation.nii')

    # go to tmp folder
    os.chdir(path_tmp)

    # Change orientation of the input segmentation into RPI
    sct.printv('\nChange orientation of the input segmentation into RPI...',
               verbose)
    fname_segmentation_orient = set_orientation('segmentation.nii', 'RPI',
                                                'segmentation_orient.nii')

    # Get size of data
    sct.printv('\nGet data dimensions...', verbose)
    nx, ny, nz, nt, px, py, pz, pt = Image(fname_segmentation_orient).dim
    sct.printv('  ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose)

    # Open segmentation volume
    sct.printv('\nOpen segmentation volume...', verbose)
    file_seg = nibabel.load(fname_segmentation_orient)
    data_seg = file_seg.get_data()
    hdr_seg = file_seg.get_header()

    # # Extract min and max index in Z direction
    X, Y, Z = (data_seg > 0).nonzero()
    min_z_index, max_z_index = min(Z), max(Z)
    # Xp, Yp = (data_seg[:, :, 0] >= 0).nonzero()  # X and Y range

    # extract centerline and smooth it
    x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(
        fname_segmentation_orient,
        algo_fitting=algo_fitting,
        type_window=type_window,
        window_length=window_length,
        verbose=verbose)
    z_centerline_scaled = [x * pz for x in z_centerline]

    # Compute CSA
    sct.printv('\nCompute CSA...', verbose)

    # Empty arrays in which CSA for each z slice will be stored
    csa = np.zeros(max_z_index - min_z_index + 1)
    # csa = [0.0 for i in xrange(0, max_z_index-min_z_index+1)]

    for iz in xrange(0, len(z_centerline)):

        # compute the vector normal to the plane
        normal = normalize(
            np.array([
                x_centerline_deriv[iz], y_centerline_deriv[iz],
                z_centerline_deriv[iz]
            ]))

        # compute the angle between the normal vector of the plane and the vector z
        angle = np.arccos(np.dot(normal, [0, 0, 1]))

        # compute the number of voxels, assuming the segmentation is coded for partial volume effect between 0 and 1.
        number_voxels = sum(sum(data_seg[:, :, iz + min_z_index]))

        # compute CSA, by scaling with voxel size (in mm) and adjusting for oblique plane
        csa[iz] = number_voxels * px * py * np.cos(angle)

    if smoothing_param:
        from msct_smooth import smoothing_window
        sct.printv('\nSmooth CSA across slices...', verbose)
        sct.printv('.. Hanning window: ' + str(smoothing_param) + ' mm',
                   verbose)
        csa_smooth = smoothing_window(csa,
                                      window_len=smoothing_param / pz,
                                      window='hanning',
                                      verbose=0)
        # display figure
        if verbose == 2:
            import matplotlib.pyplot as plt
            plt.figure()
            pltx, = plt.plot(z_centerline_scaled, csa, 'bo')
            pltx_fit, = plt.plot(z_centerline_scaled,
                                 csa_smooth,
                                 'r',
                                 linewidth=2)
            plt.title("Cross-sectional area (CSA)")
            plt.xlabel('z (mm)')
            plt.ylabel('CSA (mm^2)')
            plt.legend([pltx, pltx_fit], ['Raw', 'Smoothed'])
            plt.show()
        # update variable
        csa = csa_smooth

    # Create output text file
    sct.printv('\nWrite text file...', verbose)
    file_results = open('csa.txt', 'w')
    for i in range(min_z_index, max_z_index + 1):
        file_results.write(
            str(int(i)) + ',' + str(csa[i - min_z_index]) + '\n')
        # Display results
        sct.printv(
            'z=' + str(i - min_z_index) + ': ' + str(csa[i - min_z_index]) +
            ' mm^2', verbose, 'bold')
    file_results.close()

    # output volume of csa values
    if volume_output:
        sct.printv('\nCreate volume of CSA values...', verbose)
        # get orientation of the input data
        orientation = get_orientation('segmentation.nii')
        data_seg = data_seg.astype(np.float32, copy=False)
        # loop across slices
        for iz in range(min_z_index, max_z_index + 1):
            # retrieve seg pixels
            x_seg, y_seg = (data_seg[:, :, iz] > 0).nonzero()
            seg = [[x_seg[i], y_seg[i]] for i in range(0, len(x_seg))]
            # loop across pixels in segmentation
            for i in seg:
                # replace value with csa value
                data_seg[i[0], i[1], iz] = csa[iz - min_z_index]
        # create header
        hdr_seg.set_data_dtype('float32')  # set imagetype to uint8
        # save volume
        img = nibabel.Nifti1Image(data_seg, None, hdr_seg)
        nibabel.save(img, 'csa_RPI.nii')
        # Change orientation of the output centerline into input orientation
        fname_csa_volume = set_orientation('csa_RPI.nii', orientation,
                                           'csa_RPI_orient.nii')

    # come back to parent folder
    os.chdir('..')

    # Generate output files
    sct.printv('\nGenerate output files...', verbose)
    from shutil import copyfile
    copyfile(path_tmp + 'csa.txt', path_data + param.fname_csa)
    # sct.generate_output_file(path_tmp+'csa.txt', path_data+param.fname_csa)  # extension already included in param.fname_csa
    if volume_output:
        sct.generate_output_file(
            fname_csa_volume, path_data +
            name_output)  # extension already included in name_output

    # average csa across vertebral levels or slices if asked (flag -z or -l)
    if slices or vert_levels:

        if vert_levels and not path_to_template:
            sct.printv('\nERROR: Path to template is missing. See usage.\n', 1,
                       'error')
            sys.exit(2)
        elif vert_levels and path_to_template:
            abs_path_to_template = os.path.abspath(path_to_template)

        # go to tmp folder
        os.chdir(path_tmp)

        # create temporary folder
        sct.printv('\nCreate temporary folder to average csa...', verbose)
        path_tmp_extract_metric = sct.slash_at_the_end('label_temp', 1)
        sct.run('mkdir ' + path_tmp_extract_metric, verbose)

        # Copying output CSA volume in the temporary folder
        sct.printv('\nCopy data to tmp folder...', verbose)
        sct.run('cp ' + fname_segmentation + ' ' + path_tmp_extract_metric)

        # create file info_label
        path_fname_seg, file_fname_seg, ext_fname_seg = sct.extract_fname(
            fname_segmentation)
        create_info_label('info_label.txt', path_tmp_extract_metric,
                          file_fname_seg + ext_fname_seg)

        # average CSA
        if slices:
            os.system("sct_extract_metric -i " + path_data + name_output +
                      " -f " + path_tmp_extract_metric +
                      " -m wa -o ../csa_mean.txt -z " + slices)
        if vert_levels:
            sct.run('cp -R ' + abs_path_to_template + ' .')
            os.system("sct_extract_metric -i " + path_data + name_output +
                      " -f " + path_tmp_extract_metric +
                      " -m wa -o ../csa_mean.txt -v " + vert_levels)

        os.chdir('..')

        # Remove temporary files
        print('\nRemove temporary folder used to average CSA...')
        sct.run('rm -rf ' + path_tmp_extract_metric)

    # Remove temporary files
    if remove_temp_files:
        print('\nRemove temporary files...')
        sct.run('rm -rf ' + path_tmp)
def compute_csa(fname_segmentation, verbose, remove_temp_files, step, smoothing_param, figure_fit, file_csa_volume, slices, vert_levels, fname_vertebral_labeling='', algo_fitting = 'hanning', type_window = 'hanning', window_length = 80):

    # Extract path, file and extension
    fname_segmentation = os.path.abspath(fname_segmentation)
    path_data, file_data, ext_data = sct.extract_fname(fname_segmentation)

    # create temporary folder
    sct.printv('\nCreate temporary folder...', verbose)
    path_tmp = sct.slash_at_the_end('tmp.'+time.strftime("%y%m%d%H%M%S") + '_'+str(randint(1, 1000000)), 1)
    sct.run('mkdir '+path_tmp, verbose)

    # Copying input data to tmp folder
    sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose)
    sct.run('sct_convert -i '+fname_segmentation+' -o '+path_tmp+'segmentation.nii.gz', verbose)
    # go to tmp folder
    os.chdir(path_tmp)
    # Change orientation of the input segmentation into RPI
    sct.printv('\nChange orientation to RPI...', verbose)
    sct.run('sct_image -i segmentation.nii.gz -setorient RPI -o segmentation_RPI.nii.gz', verbose)

    # Open segmentation volume
    sct.printv('\nOpen segmentation volume...', verbose)
    im_seg = Image('segmentation_RPI.nii.gz')
    data_seg = im_seg.data
    # hdr_seg = im_seg.hdr

    # Get size of data
    sct.printv('\nGet data dimensions...', verbose)
    nx, ny, nz, nt, px, py, pz, pt = im_seg.dim
    sct.printv('  ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz), verbose)

    # # Extract min and max index in Z direction
    X, Y, Z = (data_seg > 0).nonzero()
    min_z_index, max_z_index = min(Z), max(Z)

    # extract centerline and smooth it
    x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline('segmentation_RPI.nii.gz', algo_fitting=algo_fitting, type_window=type_window, window_length=window_length, verbose=verbose)
    z_centerline_scaled = [x*pz for x in z_centerline]

    # Compute CSA
    sct.printv('\nCompute CSA...', verbose)

    # Empty arrays in which CSA for each z slice will be stored
    csa = np.zeros(max_z_index-min_z_index+1)

    for iz in xrange(min_z_index, max_z_index+1):

        # compute the vector normal to the plane
        normal = normalize(np.array([x_centerline_deriv[iz-min_z_index], y_centerline_deriv[iz-min_z_index], z_centerline_deriv[iz-min_z_index]]))

        # compute the angle between the normal vector of the plane and the vector z
        angle = np.arccos(np.dot(normal, [0, 0, 1]))

        # compute the number of voxels, assuming the segmentation is coded for partial volume effect between 0 and 1.
        number_voxels = np.sum(data_seg[:, :, iz])

        # compute CSA, by scaling with voxel size (in mm) and adjusting for oblique plane
        csa[iz-min_z_index] = number_voxels * px * py * np.cos(angle)

    sct.printv('\nSmooth CSA across slices...', verbose)
    if smoothing_param:
        from msct_smooth import smoothing_window
        sct.printv('.. Hanning window: '+str(smoothing_param)+' mm', verbose)
        csa_smooth = smoothing_window(csa, window_len=smoothing_param/pz, window='hanning', verbose=0)
        # display figure
        if verbose == 2:
            import matplotlib.pyplot as plt
            plt.figure()
            pltx, = plt.plot(z_centerline_scaled, csa, 'bo')
            pltx_fit, = plt.plot(z_centerline_scaled, csa_smooth, 'r', linewidth=2)
            plt.title("Cross-sectional area (CSA)")
            plt.xlabel('z (mm)')
            plt.ylabel('CSA (mm^2)')
            plt.legend([pltx, pltx_fit], ['Raw', 'Smoothed'])
            plt.show()
        # update variable
        csa = csa_smooth
    else:
        sct.printv('.. No smoothing!', verbose)


    # Create output text file
    sct.printv('\nWrite text file...', verbose)
    file_results = open('csa.txt', 'w')
    for i in range(min_z_index, max_z_index+1):
        file_results.write(str(int(i)) + ',' + str(csa[i-min_z_index])+'\n')
        # Display results
        sct.printv('z='+str(i-min_z_index)+': '+str(csa[i-min_z_index])+' mm^2', verbose, 'bold')
    file_results.close()

    # output volume of csa values
    sct.printv('\nCreate volume of CSA values...', verbose)
    data_csa = data_seg.astype(np.float32, copy=False)
    # loop across slices
    for iz in range(min_z_index, max_z_index+1):
        # retrieve seg pixels
        x_seg, y_seg = (data_csa[:, :, iz] > 0).nonzero()
        seg = [[x_seg[i],y_seg[i]] for i in range(0, len(x_seg))]
        # loop across pixels in segmentation
        for i in seg:
            # replace value with csa value
            data_csa[i[0], i[1], iz] = csa[iz-min_z_index]
    # replace data
    im_seg.data = data_csa
    # set original orientation
    # TODO: FIND ANOTHER WAY!!
    # im_seg.change_orientation(orientation) --> DOES NOT WORK!
    # set file name -- use .gz because faster to write
    im_seg.setFileName('csa_volume_RPI.nii.gz')
    im_seg.changeType('float32')
    # save volume
    im_seg.save()

    # get orientation of the input data
    im_seg_original = Image('segmentation.nii.gz')
    orientation = im_seg_original.orientation
    sct.run('sct_image -i csa_volume_RPI.nii.gz -setorient '+orientation+' -o '+file_csa_volume)

    # come back to parent folder
    os.chdir('..')

    # Generate output files
    sct.printv('\nGenerate output files...', verbose)
    copyfile(path_tmp+'csa.txt', path_data+param.fname_csa)
    # sct.generate_output_file(path_tmp+'csa.txt', path_data+param.fname_csa)  # extension already included in param.fname_csa
    sct.generate_output_file(path_tmp+file_csa_volume, path_data+file_csa_volume)  # extension already included in name_output

    # average csa across vertebral levels or slices if asked (flag -z or -l)
    if slices or vert_levels:
        from sct_extract_metric import save_metrics

        warning = ''
        if vert_levels and not fname_vertebral_labeling:
            sct.printv('\nERROR: Vertebral labeling file is missing. See usage.\n', 1, 'error')

        elif vert_levels and fname_vertebral_labeling:

            # from sct_extract_metric import get_slices_matching_with_vertebral_levels
            sct.printv('\tSelected vertebral levels... '+vert_levels)
            # convert the vertebral labeling file to RPI orientation
            im_vertebral_labeling = set_orientation(Image(fname_vertebral_labeling), 'RPI', fname_out=path_tmp+'vertebral_labeling_RPI.nii')

            # get the slices corresponding to the vertebral levels
            # slices, vert_levels_list, warning = get_slices_matching_with_vertebral_levels(data_seg, vert_levels, im_vertebral_labeling.data, 1)
            slices, vert_levels_list, warning = get_slices_matching_with_vertebral_levels_based_centerline(vert_levels, im_vertebral_labeling.data, x_centerline_fit, y_centerline_fit, z_centerline)

        elif not vert_levels:
            vert_levels_list = []

        sct.printv('Average CSA across slices...', type='info')

        # parse the selected slices
        slices_lim = slices.strip().split(':')
        slices_list = range(int(slices_lim[0]), int(slices_lim[1])+1)

        CSA_for_selected_slices = []
        # Read the file csa.txt and get the CSA for the selected slices
        with open(path_data+param.fname_csa) as openfile:
            for line in openfile:
                line_split = line.strip().split(',')
                if int(line_split[0]) in slices_list:
                    CSA_for_selected_slices.append(float(line_split[1]))

        # average the CSA
        mean_CSA = np.mean(np.asarray(CSA_for_selected_slices))
        std_CSA = np.std(np.asarray(CSA_for_selected_slices))

        sct.printv('Mean CSA: '+str(mean_CSA)+' +/- '+str(std_CSA)+' mm^2', type='info')

        # write result into output file
        save_metrics([0], [file_data], slices, [mean_CSA], [std_CSA], path_data + 'csa_mean.txt', path_data+file_csa_volume, 'nb_voxels x px x py x cos(theta) slice-by-slice (in mm^3)', '', actual_vert=vert_levels_list, warning_vert_levels=warning)

        # compute volume between the selected slices
        sct.printv('Compute the volume in between the selected slices...', type='info')
        nb_vox = np.sum(data_seg[:, :, slices_list])
        volume = nb_vox*px*py*pz
        sct.printv('Volume in between the selected slices: '+str(volume)+' mm^3', type='info')

        # write result into output file
        save_metrics([0], [file_data], slices, [volume], [np.nan], path_data + 'volume.txt', path_data+file_data, 'nb_voxels x px x py x pz (in mm^3)', '', actual_vert=vert_levels_list, warning_vert_levels=warning)

    # Remove temporary files
    if remove_temp_files:
        sct.printv('\nRemove temporary files...')
        sct.run('rm -rf '+path_tmp, error_exit='warning')
Ejemplo n.º 9
0
def register_slicereg2d_bsplinesyn(fname_source, fname_dest, window_length=31, paramreg=Paramreg(step='0', type='im', algo='BSplineSyN', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5'),
                                   fname_mask='', warp_forward_out='step0Warp.nii.gz', warp_inverse_out='step0InverseWarp.nii.gz', factor=2, remove_temp_files=1, verbose=0,
                                    ants_registration_params={'rigid': '', 'affine': '', 'compositeaffine': '', 'similarity': '', 'translation': '','bspline': ',10', 'gaussiandisplacementfield': ',3,0',
                                                              'bsplinedisplacementfield': ',5,10', 'syn': ',3,0', 'bsplinesyn': ',1,3'}):
    """Slice-by-slice regularized registration (bsplinesyn) of two images.

    We first register slice-by-slice the two images using antsRegistration in 2D (algo: bsplinesyn) and create 3D warping
    fields (forward and inverse) by merging the 2D warping fields along z. Then we directly detect outliers and smooth
    the 3d warping fields applying a moving average hanning window on each pixel of the plan xOy (i.e. we consider that
    for a position (x,y) in the plan xOy, the variation along z of the vector of displacement (xo, yo, zo) of the
    warping field should not be too abrupt). Eventually, we generate two warping fields (forward and inverse) resulting
    from this regularized registration technique.
    The images must be of same size (otherwise generate_warping_field will not work for forward or inverse
    creation).

    input:
        fname_source: name of moving image (type: string)
        fname_dest: name of fixed image (type: string)
        window_length[optional]: size of window for moving average smoothing (type: int)
        paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal)
        fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration)
        warp_forward_out[optional]: name of output forward warp (type: string)
        warp_inverse_out[optional]: name of output inverse warp (type: string)
        factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection)
            (type: int or float)
        remove_temp_files[optional]: 1 to remove, 0 to keep (type: int)
        verbose[optional]: display parameter (type: int, value: 0,1 or 2)
        ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary)

    output:
        creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'.
    """
    from nibabel import load, Nifti1Image, save
    from msct_smooth import smoothing_window, outliers_detection, outliers_completion
    from msct_register_regularized import register_images
    from numpy import apply_along_axis, zeros
    import sct_utils as sct
    from msct_image import Image

    name_warp_syn = 'Warp_total'
    # Registrating images
    register_images(fname_source, fname_dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params)
    print'\nRegularizing warping fields along z axis...'
    print'\n\tSplitting warping fields ...'
    # sct.run('isct_c3d -mcs ' + name_warp_syn + '.nii.gz -oo ' + name_warp_syn + '_x.nii.gz ' + name_warp_syn + '_y.nii.gz')
    # sct.run('isct_c3d -mcs ' + name_warp_syn + '_inverse.nii.gz -oo ' + name_warp_syn + '_x_inverse.nii.gz ' + name_warp_syn + '_y_inverse.nii.gz')
    sct.run('sct_maths -i ' + name_warp_syn + '.nii.gz -w -mcs -o ' + name_warp_syn + '_x.nii.gz,' + name_warp_syn + '_y.nii.gz')
    sct.run('sct_maths -i ' + name_warp_syn + '_inverse.nii.gz -w -mcs -o ' + name_warp_syn + '_x_inverse.nii.gz,' + name_warp_syn + '_y_inverse.nii.gz')
    data_warp_x = load(name_warp_syn + '_x.nii.gz').get_data()
    data_warp_y = load(name_warp_syn + '_y.nii.gz').get_data()
    hdr_warp = load(name_warp_syn + '_x.nii.gz').get_header()
    data_warp_x_inverse = load(name_warp_syn + '_x_inverse.nii.gz').get_data()
    data_warp_y_inverse = load(name_warp_syn + '_y_inverse.nii.gz').get_data()
    hdr_warp_inverse = load(name_warp_syn + '_x_inverse.nii.gz').get_header()
    #Outliers deletion
    print'\n\tDeleting outliers...'
    mask_x_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x)
    mask_y_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y)
    mask_x_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x_inverse)
    mask_y_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=factor, return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y_inverse)
    #Outliers replacement by linear interpolation using closest non-outlier points
    data_warp_x_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_a)
    data_warp_y_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_a)
    data_warp_x_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_inverse_a)
    data_warp_y_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_inverse_a)
    #Smoothing of results along z
    print'\n\tSmoothing results...'
    data_warp_x_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_no_outliers)
    data_warp_x_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_inverse_no_outliers)
    data_warp_y_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_no_outliers)
    data_warp_y_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_inverse_no_outliers)

    print'\nSaving regularized warping fields...'
    #Get image dimensions of destination image
    nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim
    data_warp_smooth = zeros(((((nx, ny, nz, 1, 3)))))
    data_warp_smooth[:,:,:,0,0] = data_warp_x_smooth
    data_warp_smooth[:,:,:,0,1] = data_warp_y_smooth
    data_warp_smooth_inverse = zeros(((((nx, ny, nz, 1, 3)))))
    data_warp_smooth_inverse[:,:,:,0,0] = data_warp_x_smooth_inverse
    data_warp_smooth_inverse[:,:,:,0,1] = data_warp_y_smooth_inverse
    # Force header's parameter to intent so that the file may be recognised as a warping field by ants
    hdr_warp.set_intent('vector', (), '')
    hdr_warp_inverse.set_intent('vector', (), '')
    img = Nifti1Image(data_warp_smooth, None, header=hdr_warp)
    img_inverse = Nifti1Image(data_warp_smooth_inverse, None, header=hdr_warp_inverse)
    save(img, filename=warp_forward_out)
    print'\tFile ' + warp_forward_out + ' saved.'
    save(img_inverse, filename=warp_inverse_out)
    print'\tFile ' + warp_inverse_out + ' saved.'
Ejemplo n.º 10
0
def register_slicereg2d(fname_source,
                        fname_dest,
                        fname_mask='',
                        window_length='0',
                        warp_forward_out='step0Warp.nii.gz',
                        warp_inverse_out='step0InverseWarp.nii.gz',
                        paramreg=None,
                        ants_registration_params=None,
                        detect_outlier='0',
                        remove_temp_files=1,
                        verbose=0):
    from msct_register_regularized import register_seg, register_images, generate_warping_field
    from numpy import asarray, apply_along_axis, zeros
    from msct_smooth import smoothing_window, outliers_detection, outliers_completion
    # Calculate displacement
    current_algo = paramreg.algo
    if paramreg.type == 'seg':
        # calculate translation of center of mass between source and destination in voxel space
        res_reg = register_seg(fname_source, fname_dest, verbose)

    elif paramreg.type == 'im':
        if paramreg.algo == 'slicereg2d_pointwise':
            sct.printv('\nERROR: Algorithm slicereg2d_pointwise only operates for segmentation type.', verbose, 'error')
            sys.exit(2)
        algo_dic = {'slicereg2d_pointwise': 'Translation', 'slicereg2d_translation': 'Translation', 'slicereg2d_rigid': 'Rigid', 'slicereg2d_affine': 'Affine', 'slicereg2d_syn': 'SyN', 'slicereg2d_bsplinesyn': 'BSplineSyN'}
        paramreg.algo = algo_dic[current_algo]
        res_reg = register_images(fname_source, fname_dest, mask=fname_mask, paramreg=paramreg, remove_tmp_folder=remove_temp_files, ants_registration_params=ants_registration_params)

    else:
        sct.printv('\nERROR: wrong registration type inputed. pleas choose \'im\', or \'seg\'.', verbose, 'error')
        sys.exit(2)

    # if algo is slicereg2d _pointwise, -translation or _rigid: x_disp and y_disp are displacement fields
    # if algo is slicereg2d _affine, _syn or _bsplinesyn: x_disp and y_disp are warping fields names

    if current_algo in ['slicereg2d_pointwise', 'slicereg2d_translation', 'slicereg2d_rigid']:
        # Change to array
        x_disp, y_disp, theta_rot = res_reg
        x_disp_a = asarray(x_disp)
        y_disp_a = asarray(y_disp)
        # Detect outliers
        if not detect_outlier == '0':
            mask_x_a = outliers_detection(x_disp_a, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=verbose)
            mask_y_a = outliers_detection(y_disp_a, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=verbose)
            # Replace value of outliers by linear interpolation using closest non-outlier points
            x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0)
            y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0)
        else:
            x_disp_a_no_outliers = x_disp_a
            y_disp_a_no_outliers = y_disp_a
        # Smooth results
        if not window_length == '0':
            x_disp_smooth = smoothing_window(x_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose)
            y_disp_smooth = smoothing_window(y_disp_a_no_outliers, window_len=int(window_length), window='hanning', verbose=verbose)
        else:
            x_disp_smooth = x_disp_a_no_outliers
            y_disp_smooth = y_disp_a_no_outliers

        if theta_rot is not None:
            # same steps for theta_rot:
            theta_rot_a = asarray(theta_rot)
            mask_theta_a = outliers_detection(theta_rot_a, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=verbose)
            theta_rot_a_no_outliers = outliers_completion(mask_theta_a, verbose=0)
            theta_rot_smooth = smoothing_window(theta_rot_a_no_outliers, window_len=int(window_length), window='hanning', verbose = verbose)
        else:
            theta_rot_smooth = None

        # Generate warping field
        generate_warping_field(fname_dest, x_disp_smooth, y_disp_smooth, theta_rot_smooth, fname=warp_forward_out)  #name_warp= 'step'+str(paramreg.step)
        # Inverse warping field
        generate_warping_field(fname_source, -x_disp_smooth, -y_disp_smooth, -theta_rot_smooth if theta_rot_smooth is not None else None, fname=warp_inverse_out)

    elif current_algo in ['slicereg2d_affine', 'slicereg2d_syn', 'slicereg2d_bsplinesyn']:
        from msct_image import Image
        warp_x, inv_warp_x, warp_y, inv_warp_y = res_reg
        im_warp_x = Image(warp_x)
        im_inv_warp_x = Image(inv_warp_x)
        im_warp_y = Image(warp_y)
        im_inv_warp_y = Image(inv_warp_y)

        data_warp_x = im_warp_x.data
        data_warp_x_inverse = im_inv_warp_x.data
        data_warp_y = im_warp_y.data
        data_warp_y_inverse = im_inv_warp_y.data

        hdr_warp = im_warp_x.hdr
        hdr_warp_inverse = im_inv_warp_x.hdr

        #Outliers deletion
        print'\n\tDeleting outliers...'
        mask_x_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x)
        mask_y_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y)
        mask_x_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_x_inverse)
        mask_y_inverse_a = apply_along_axis(lambda m: outliers_detection(m, type='median', factor=int(detect_outlier), return_filtered_signal='no', verbose=0), axis=-1, arr=data_warp_y_inverse)
        #Outliers replacement by linear interpolation using closest non-outlier points
        data_warp_x_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_a)
        data_warp_y_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_a)
        data_warp_x_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_inverse_a)
        data_warp_y_inverse_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_inverse_a)
        #Smoothing of results along z
        print'\n\tSmoothing results...'
        data_warp_x_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_no_outliers)
        data_warp_x_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_x_inverse_no_outliers)
        data_warp_y_smooth = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_no_outliers)
        data_warp_y_smooth_inverse = apply_along_axis(lambda m: smoothing_window(m, window_len=int(window_length), window='hanning', verbose=0), axis=-1, arr=data_warp_y_inverse_no_outliers)

        print'\nSaving regularized warping fields...'
        # TODO: MODIFY NEXT PART
        #Get image dimensions of destination image
        from msct_image import Image
        from nibabel import load, Nifti1Image, save
        nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim
        data_warp_smooth = zeros(((((nx, ny, nz, 1, 3)))))
        data_warp_smooth[:,:,:,0,0] = data_warp_x_smooth
        data_warp_smooth[:,:,:,0,1] = data_warp_y_smooth
        data_warp_smooth_inverse = zeros(((((nx, ny, nz, 1, 3)))))
        data_warp_smooth_inverse[:,:,:,0,0] = data_warp_x_smooth_inverse
        data_warp_smooth_inverse[:,:,:,0,1] = data_warp_y_smooth_inverse
        # Force header's parameter to intent so that the file may be recognised as a warping field by ants
        hdr_warp.set_intent('vector', (), '')
        hdr_warp_inverse.set_intent('vector', (), '')
        img = Nifti1Image(data_warp_smooth, None, header=hdr_warp)
        img_inverse = Nifti1Image(data_warp_smooth_inverse, None, header=hdr_warp_inverse)
        save(img, filename=warp_forward_out)
        print'\tFile ' + warp_forward_out + ' saved.'
        save(img_inverse, filename=warp_inverse_out)
        print'\tFile ' + warp_inverse_out + ' saved.'
        return warp_forward_out, warp_inverse_out
def smooth_centerline(fname_centerline, algo_fitting="hanning", type_window="hanning", window_length=80, verbose=0):
    """
    :param fname_centerline: centerline in RPI orientation
    :return: a bunch of useful stuff
    """
    # window_length = param.window_length
    # type_window = param.type_window
    # algo_fitting = param.algo_fitting

    sct.printv("\nSmooth centerline/segmentation...", verbose)

    # get dimensions (again!)
    nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(fname_centerline)

    # open centerline
    file = load(fname_centerline)
    data = file.get_data()

    # loop across z and associate x,y coordinate with the point having maximum intensity
    # N.B. len(z_centerline) = nz_nonz can be smaller than nz in case the centerline is smaller than the input volume
    z_centerline = [iz for iz in range(0, nz, 1) if data[:, :, iz].any()]
    nz_nonz = len(z_centerline)
    x_centerline = [0 for iz in range(0, nz_nonz, 1)]
    y_centerline = [0 for iz in range(0, nz_nonz, 1)]
    x_centerline_deriv = [0 for iz in range(0, nz_nonz, 1)]
    y_centerline_deriv = [0 for iz in range(0, nz_nonz, 1)]
    z_centerline_deriv = [0 for iz in range(0, nz_nonz, 1)]

    # get center of mass of the centerline/segmentation
    sct.printv(".. Get center of mass of the centerline/segmentation...", verbose)
    for iz in range(0, nz_nonz, 1):
        x_centerline[iz], y_centerline[iz] = ndimage.measurements.center_of_mass(array(data[:, :, z_centerline[iz]]))

        # import matplotlib.pyplot as plt
        # fig = plt.figure()
        # ax = fig.add_subplot(111)
        # data_tmp = data
        # data_tmp[x_centerline[iz], y_centerline[iz], z_centerline[iz]] = 10
        # implot = ax.imshow(data_tmp[:, :, z_centerline[iz]].T)
        # implot.set_cmap('gray')
        # plt.show()

    sct.printv(".. Smoothing algo = " + algo_fitting, verbose)
    if algo_fitting == "hanning":
        # 2D smoothing
        sct.printv(".. Windows length = " + str(window_length), verbose)

        # change to array
        x_centerline = asarray(x_centerline)
        y_centerline = asarray(y_centerline)

        # Smooth the curve
        x_centerline_smooth = smoothing_window(
            x_centerline, window_len=window_length / pz, window=type_window, verbose=verbose
        )
        y_centerline_smooth = smoothing_window(
            y_centerline, window_len=window_length / pz, window=type_window, verbose=verbose
        )

        # convert to list final result
        x_centerline_smooth = x_centerline_smooth.tolist()
        y_centerline_smooth = y_centerline_smooth.tolist()

        # clear variable
        del data

        x_centerline_fit = x_centerline_smooth
        y_centerline_fit = y_centerline_smooth
        z_centerline_fit = z_centerline

        # get derivative
        x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = evaluate_derivative_3D(
            x_centerline_fit, y_centerline_fit, z_centerline, px, py, pz
        )

        x_centerline_fit = asarray(x_centerline_fit)
        y_centerline_fit = asarray(y_centerline_fit)
        z_centerline_fit = asarray(z_centerline_fit)

    elif algo_fitting == "nurbs":
        from msct_smooth import b_spline_nurbs

        x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = b_spline_nurbs(
            x_centerline, y_centerline, z_centerline, nbControl=None, verbose=verbose
        )

    else:
        sct.printv("ERROR: wrong algorithm for fitting", 1, "error")

    return (
        x_centerline_fit,
        y_centerline_fit,
        z_centerline_fit,
        x_centerline_deriv,
        y_centerline_deriv,
        z_centerline_deriv,
    )
# generate_warping_field(im_d_3, x_, y_, theta, center_rotation=None, fname='warping_field_15transx.nii.gz')
# sct.run('sct_apply_transfo -i '+im_d_3+' -d '+im_d_3+' -w warping_field_15transx.nii.gz -o ' + im_d_5 + ' -x nn')



# im and algo rigid
im_i = im_T1
im_d = im_T2
window_size = 31
x_disp, y_disp, theta = register_images(im_i, im_d, paramreg=Paramreg(step='0', type='im', algo='Rigid', metric='MI', iter='100', shrink='1', smooth='0', gradStep='3'), remove_tmp_folder=1)

x_disp_a = asarray(x_disp)
y_disp_a = asarray(y_disp)
theta_a = asarray(theta)

x_disp_smooth = smoothing_window(x_disp_a, window_len=window_size, window='hanning', verbose = 2)
y_disp_smooth = smoothing_window(y_disp_a, window_len=window_size, window='hanning', verbose = 2)
theta_smooth = smoothing_window(theta_a, window_len=window_size, window='hanning', verbose = 2)
theta_smooth_inv = -theta_smooth

generate_warping_field(im_d, x_disp_smooth, y_disp_smooth, theta_rot=theta_smooth, fname='warping_field_seg_rigid.nii.gz')
generate_warping_field(im_i, -x_disp_smooth, -y_disp_smooth, theta_rot=theta_smooth_inv, fname='warping_field_seg_rigid_inv.nii.gz')

sct.run('sct_apply_transfo -i '+ im_i +' -d ' +im_d+ ' -w warping_field_seg_rigid.nii.gz -o output_im_rigid.nii.gz -x nn')
sct.run('sct_apply_transfo -i '+ im_d +' -d ' +im_i+ ' -w warping_field_seg_rigid_inv.nii.gz -o output_im_rigid_inv.nii.gz -x nn')



# # im and algo affine
# im_i = im_T1
# im_d = im_T2
# tck_x = splrep(z_index, x_displacement, s=smoothing_param_x)
# x_disp_smooth = splev(z_index, tck_x)
# # For y
# y_for_fitting = [-i for i in y_displacement]
# m_y =mean(y_for_fitting)
# sigma_y = std(y_for_fitting)
# smoothing_param_y = m_y * sigma_y**2 #Equivalent to : m*sigma**2
# tck_y = splrep(z_index, y_for_fitting, s=smoothing_param_y)
# y_disp_smooth = splev(z_index, tck_y)
# y_disp_smooth *= -1

#with hanning and mirror
from msct_smooth import smoothing_window
x_displacement_array = asarray(x_displacement)
y_displacement_array = asarray(y_displacement)
x_disp_smooth = smoothing_window(x_displacement_array, window_len=31)
y_disp_smooth = smoothing_window(y_displacement_array, window_len=31)

# #with hanning and no mirror
# window = 'hanning'
# window_len_int = 30
# w = eval(window+'(window_len_int)')
# x_disp_smooth = convolve(x_displacement, w/w.sum(), mode='same')
# y_disp_smooth = convolve(y_displacement, w/w.sum(), mode='same')

plt.figure()
plt.subplot(2, 1, 1)
plt.plot(z_index, x_displacement, "ro")
plt.plot(z_index, x_disp_smooth)
plt.subplot(2, 1, 2)
plt.plot(z_index, y_displacement, "ro")
# tck_x = splrep(z_index, x_displacement, s=smoothing_param_x)
# x_disp_smooth = splev(z_index, tck_x)
# # For y
# y_for_fitting = [-i for i in y_displacement]
# m_y =mean(y_for_fitting)
# sigma_y = std(y_for_fitting)
# smoothing_param_y = m_y * sigma_y**2 #Equivalent to : m*sigma**2
# tck_y = splrep(z_index, y_for_fitting, s=smoothing_param_y)
# y_disp_smooth = splev(z_index, tck_y)
# y_disp_smooth *= -1

#with hanning and mirror
from msct_smooth import smoothing_window
x_displacement_array = asarray(x_displacement)
y_displacement_array = asarray(y_displacement)
x_disp_smooth = smoothing_window(x_displacement_array, window_len=31)
y_disp_smooth = smoothing_window(y_displacement_array, window_len=31)

# #with hanning and no mirror
# window = 'hanning'
# window_len_int = 30
# w = eval(window+'(window_len_int)')
# x_disp_smooth = convolve(x_displacement, w/w.sum(), mode='same')
# y_disp_smooth = convolve(y_displacement, w/w.sum(), mode='same')

plt.figure()
plt.subplot(2,1,1)
plt.plot(z_index,x_displacement, "ro")
plt.plot(z_index,x_disp_smooth)
plt.subplot(2,1,2)
plt.plot(z_index,y_displacement, "ro")
def register_slicereg2d_bsplinesyn(
    src,
    dest,
    window_length=31,
    paramreg=Paramreg(
        step="0", type="im", algo="BSplineSyN", metric="MeanSquares", iter="10", shrink="1", smooth="0", gradStep="0.5"
    ),
    fname_mask="",
    warp_forward_out="step0Warp.nii.gz",
    warp_inverse_out="step0InverseWarp.nii.gz",
    factor=2,
    remove_temp_files=1,
    verbose=0,
    ants_registration_params={
        "rigid": "",
        "affine": "",
        "compositeaffine": "",
        "similarity": "",
        "translation": "",
        "bspline": ",10",
        "gaussiandisplacementfield": ",3,0",
        "bsplinedisplacementfield": ",5,10",
        "syn": ",3,0",
        "bsplinesyn": ",1,3",
    },
):
    """Slice-by-slice regularized registration (bsplinesyn) of two images.

    We first register slice-by-slice the two images using antsRegistration in 2D (algo: bsplinesyn) and create 3D warping
    fields (forward and inverse) by merging the 2D warping fields along z. Then we directly detect outliers and smooth
    the 3d warping fields applying a moving average hanning window on each pixel of the plan xOy (i.e. we consider that
    for a position (x,y) in the plan xOy, the variation along z of the vector of displacement (xo, yo, zo) of the
    warping field should not be too abrupt). Eventually, we generate two warping fields (forward and inverse) resulting
    from this regularized registration technique.
    The images must be of same size (otherwise generate_warping_field will not work for forward or inverse
    creation).

    input:
        src: name of moving image (type: string)
        dest: name of fixed image (type: string)
        window_length[optional]: size of window for moving average smoothing (type: int)
        paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal)
        fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration)
        warp_forward_out[optional]: name of output forward warp (type: string)
        warp_inverse_out[optional]: name of output inverse warp (type: string)
        factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection)
            (type: int or float)
        remove_temp_files[optional]: 1 to remove, 0 to keep (type: int)
        verbose[optional]: display parameter (type: int, value: 0,1 or 2)
        ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary)

    output:
        creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'.
    """
    from nibabel import load, Nifti1Image, save
    from msct_smooth import smoothing_window, outliers_detection, outliers_completion
    from msct_register_regularized import register_images
    from numpy import apply_along_axis, zeros
    import sct_utils as sct

    name_warp_syn = "Warp_total"
    # Registrating images
    register_images(
        src,
        dest,
        mask=fname_mask,
        paramreg=paramreg,
        remove_tmp_folder=remove_temp_files,
        ants_registration_params=ants_registration_params,
    )
    print "\nRegularizing warping fields along z axis..."
    print "\n\tSplitting warping fields ..."
    sct.run(
        "isct_c3d -mcs " + name_warp_syn + ".nii.gz -oo " + name_warp_syn + "_x.nii.gz " + name_warp_syn + "_y.nii.gz"
    )
    sct.run(
        "isct_c3d -mcs "
        + name_warp_syn
        + "_inverse.nii.gz -oo "
        + name_warp_syn
        + "_x_inverse.nii.gz "
        + name_warp_syn
        + "_y_inverse.nii.gz"
    )
    data_warp_x = load(name_warp_syn + "_x.nii.gz").get_data()
    data_warp_y = load(name_warp_syn + "_y.nii.gz").get_data()
    hdr_warp = load(name_warp_syn + "_x.nii.gz").get_header()
    data_warp_x_inverse = load(name_warp_syn + "_x_inverse.nii.gz").get_data()
    data_warp_y_inverse = load(name_warp_syn + "_y_inverse.nii.gz").get_data()
    hdr_warp_inverse = load(name_warp_syn + "_x_inverse.nii.gz").get_header()
    # Outliers deletion
    print "\n\tDeleting outliers..."
    mask_x_a = apply_along_axis(
        lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0),
        axis=-1,
        arr=data_warp_x,
    )
    mask_y_a = apply_along_axis(
        lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0),
        axis=-1,
        arr=data_warp_y,
    )
    mask_x_inverse_a = apply_along_axis(
        lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0),
        axis=-1,
        arr=data_warp_x_inverse,
    )
    mask_y_inverse_a = apply_along_axis(
        lambda m: outliers_detection(m, type="median", factor=factor, return_filtered_signal="no", verbose=0),
        axis=-1,
        arr=data_warp_y_inverse,
    )
    # Outliers replacement by linear interpolation using closest non-outlier points
    data_warp_x_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_a)
    data_warp_y_no_outliers = apply_along_axis(lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_a)
    data_warp_x_inverse_no_outliers = apply_along_axis(
        lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_x_inverse_a
    )
    data_warp_y_inverse_no_outliers = apply_along_axis(
        lambda m: outliers_completion(m, verbose=0), axis=-1, arr=mask_y_inverse_a
    )
    # Smoothing of results along z
    print "\n\tSmoothing results..."
    data_warp_x_smooth = apply_along_axis(
        lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0),
        axis=-1,
        arr=data_warp_x_no_outliers,
    )
    data_warp_x_smooth_inverse = apply_along_axis(
        lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0),
        axis=-1,
        arr=data_warp_x_inverse_no_outliers,
    )
    data_warp_y_smooth = apply_along_axis(
        lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0),
        axis=-1,
        arr=data_warp_y_no_outliers,
    )
    data_warp_y_smooth_inverse = apply_along_axis(
        lambda m: smoothing_window(m, window_len=int(window_length), window="hanning", verbose=0),
        axis=-1,
        arr=data_warp_y_inverse_no_outliers,
    )

    print "\nSaving regularized warping fields..."
    # Get image dimensions of destination image
    nx, ny, nz, nt, px, py, pz, pt = sct.get_dimension(dest)
    data_warp_smooth = zeros(((((nx, ny, nz, 1, 3)))))
    data_warp_smooth[:, :, :, 0, 0] = data_warp_x_smooth
    data_warp_smooth[:, :, :, 0, 1] = data_warp_y_smooth
    data_warp_smooth_inverse = zeros(((((nx, ny, nz, 1, 3)))))
    data_warp_smooth_inverse[:, :, :, 0, 0] = data_warp_x_smooth_inverse
    data_warp_smooth_inverse[:, :, :, 0, 1] = data_warp_y_smooth_inverse
    # Force header's parameter to intent so that the file may be recognised as a warping field by ants
    hdr_warp.set_intent("vector", (), "")
    hdr_warp_inverse.set_intent("vector", (), "")
    img = Nifti1Image(data_warp_smooth, None, header=hdr_warp)
    img_inverse = Nifti1Image(data_warp_smooth_inverse, None, header=hdr_warp_inverse)
    save(img, filename=warp_forward_out)
    print "\tFile " + warp_forward_out + " saved."
    save(img_inverse, filename=warp_inverse_out)
    print "\tFile " + warp_inverse_out + " saved."
def register_slicereg2d_translation(
    src,
    dest,
    window_length=31,
    paramreg=Paramreg(
        step="0", type="im", algo="Translation", metric="MeanSquares", iter="10", shrink="1", smooth="0", gradStep="0.5"
    ),
    fname_mask="",
    warp_forward_out="step0Warp.nii.gz",
    warp_inverse_out="step0InverseWarp.nii.gz",
    factor=2,
    remove_temp_files=1,
    verbose=0,
    ants_registration_params={
        "rigid": "",
        "affine": "",
        "compositeaffine": "",
        "similarity": "",
        "translation": "",
        "bspline": ",10",
        "gaussiandisplacementfield": ",3,0",
        "bsplinedisplacementfield": ",5,10",
        "syn": ",3,0",
        "bsplinesyn": ",1,3",
    },
):
    """Slice-by-slice regularized registration by translation of two images.

    We first register slice-by-slice the two images using antsRegistration in 2D. Then we remove outliers using
    Median Absolute Deviation technique (MAD) and smooth the translations along x and y axis using moving average
    hanning window. Eventually, we generate two warping fields (forward and inverse) resulting from this regularized
    registration technique.
    The images must be of same size (otherwise generate_warping_field will not work for forward or inverse
    creation).

    input:
        src: name of moving image (type: string)
        dest: name of fixed image (type: string)
        window_length[optional]: size of window for moving average smoothing (type: int)
        paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal)
        fname_mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration)
        warp_forward_out[optional]: name of output forward warp (type: string)
        warp_inverse_out[optional]: name of output inverse warp (type: string)
        factor[optional]: sensibility factor for outlier detection (higher the factor, smaller the detection)
            (type: int or float)
        remove_temp_files[optional]: 1 to remove, 0 to keep (type: int)
        verbose[optional]: display parameter (type: int, value: 0,1 or 2)
        ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary)

    output:
        creation of warping field files of name 'warp_forward_out' and 'warp_inverse_out'.
    """
    from msct_register_regularized import register_images, generate_warping_field
    from numpy import asarray
    from msct_smooth import smoothing_window, outliers_detection, outliers_completion

    # Calculate displacement
    x_disp, y_disp = register_images(
        src,
        dest,
        mask=fname_mask,
        paramreg=paramreg,
        remove_tmp_folder=remove_temp_files,
        ants_registration_params=ants_registration_params,
    )
    # Change to array
    x_disp_a = asarray(x_disp)
    y_disp_a = asarray(y_disp)
    # Detect outliers
    mask_x_a = outliers_detection(x_disp_a, type="median", factor=factor, return_filtered_signal="no", verbose=verbose)
    mask_y_a = outliers_detection(y_disp_a, type="median", factor=factor, return_filtered_signal="no", verbose=verbose)
    # Replace value of outliers by linear interpolation using closest non-outlier points
    x_disp_a_no_outliers = outliers_completion(mask_x_a, verbose=0)
    y_disp_a_no_outliers = outliers_completion(mask_y_a, verbose=0)
    # Smooth results
    x_disp_smooth = smoothing_window(
        x_disp_a_no_outliers, window_len=int(window_length), window="hanning", verbose=verbose
    )
    y_disp_smooth = smoothing_window(
        y_disp_a_no_outliers, window_len=int(window_length), window="hanning", verbose=verbose
    )
    # Generate warping field
    generate_warping_field(dest, x_disp_smooth, y_disp_smooth, fname=warp_forward_out)
    # Inverse warping field
    generate_warping_field(src, -x_disp_smooth, -y_disp_smooth, fname=warp_inverse_out)