def register_images(
        fname_source,
        fname_dest,
        mask='',
        paramreg=Paramreg(step='0',
                          type='im',
                          algo='Translation',
                          metric='MI',
                          iter='5',
                          shrink='1',
                          smooth='0',
                          gradStep='0.5'),
        ants_registration_params={
            'rigid': '',
            'affine': '',
            'compositeaffine': '',
            'similarity': '',
            'translation': '',
            'bspline': ',10',
            'gaussiandisplacementfield': ',3,0',
            'bsplinedisplacementfield': ',5,10',
            'syn': ',3,0',
            'bsplinesyn': ',1,3'
        },
        remove_tmp_folder=1):
    """Slice-by-slice registration of two images.

    We first split the 3D images into 2D images (and the mask if inputted). Then we register slices of the two images
    that physically correspond to one another looking at the physical origin of each image. The images can be of
    different sizes but the destination image must be smaller thant the input image. We do that using antsRegistration
    in 2D. Once this has been done for each slices, we gather the results and return them.
    Algorithms implemented: translation, rigid, affine, syn and BsplineSyn.
    N.B.: If the mask is inputted, it must also be 3D and it must be in the same space as the destination image.

    input:
        fname_source: name of moving image (type: string)
        fname_dest: name of fixed image (type: string)
        mask[optional]: name of mask file (type: string) (parameter -x of antsRegistration)
        paramreg[optional]: parameters of antsRegistration (type: Paramreg class from sct_register_multimodal)
        ants_registration_params[optional]: specific algorithm's parameters for antsRegistration (type: dictionary)

    output:
        if algo==translation:
            x_displacement: list of translation along x axis for each slice (type: list)
            y_displacement: list of translation along y axis for each slice (type: list)
        if algo==rigid:
            x_displacement: list of translation along x axis for each slice (type: list)
            y_displacement: list of translation along y axis for each slice (type: list)
            theta_rotation: list of rotation angle in radian (and in ITK's coordinate system) for each slice (type: list)
        if algo==affine or algo==syn or algo==bsplinesyn:
            creation of two 3D warping fields (forward and inverse) that are the concatenations of the slice-by-slice
            warps.
    """
    # Extracting names
    path_i, root_i, ext_i = sct.extract_fname(fname_source)
    path_d, root_d, ext_d = sct.extract_fname(fname_dest)

    # set metricSize
    if paramreg.metric == 'MI':
        metricSize = '32'  # corresponds to number of bins
    else:
        metricSize = '4'  # corresponds to radius (for CC, MeanSquares...)

    # Get image dimensions and retrieve nz
    print '\nGet image dimensions of destination image...'
    nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim
    print '.. matrix size: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)
    print '.. voxel size:  ' + str(px) + 'mm x ' + str(py) + 'mm x ' + str(
        pz) + 'mm'

    # Define x and y displacement as list
    x_displacement = [0 for i in range(nz)]
    y_displacement = [0 for i in range(nz)]
    theta_rotation = [0 for i in range(nz)]

    # create temporary folder
    print('\nCreate temporary folder...')
    path_tmp = 'tmp.' + time.strftime("%y%m%d%H%M%S")
    sct.create_folder(path_tmp)
    print '\nCopy input data...'
    sct.run('cp ' + fname_source + ' ' + path_tmp + '/' + root_i + ext_i)
    sct.run('cp ' + fname_dest + ' ' + path_tmp + '/' + root_d + ext_d)
    if mask:
        sct.run('cp ' + mask + ' ' + path_tmp + '/mask.nii.gz')

    # go to temporary folder
    os.chdir(path_tmp)

    # Split input volume along z
    print '\nSplit input volume...'
    from sct_split_data import split_data
    split_data(fname_source, 2, '_z')

    # Split destination volume along z
    print '\nSplit destination volume...'
    split_data(fname_dest, 2, '_z')

    # Split mask volume along z
    if mask:
        print '\nSplit mask volume...'
        split_data('mask.nii.gz', 2, '_z')

    im_dest_img = Image(fname_dest)
    im_input_img = Image(fname_source)
    coord_origin_dest = im_dest_img.transfo_pix2phys([[0, 0, 0]])
    coord_origin_input = im_input_img.transfo_pix2phys([[0, 0, 0]])
    coord_diff_origin = (asarray(coord_origin_dest[0]) -
                         asarray(coord_origin_input[0])).tolist()
    [x_o, y_o, z_o] = [
        coord_diff_origin[0] * 1.0 / px, coord_diff_origin[1] * 1.0 / py,
        coord_diff_origin[2] * 1.0 / pz
    ]

    if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine':
        list_warp_x = []
        list_warp_x_inv = []
        list_warp_y = []
        list_warp_y_inv = []
        name_warp_final = 'Warp_total'  #if modified, name should also be modified in msct_register (algo slicereg2d_bsplinesyn and slicereg2d_syn)

    # loop across slices
    for i in range(nz):
        # set masking
        num = numerotation(i)
        num_2 = numerotation(int(num) + int(z_o))
        if mask:
            masking = '-x mask_z' + num + '.nii'
        else:
            masking = ''

        cmd = (
            'isct_antsRegistration '
            '--dimensionality 2 '
            '--transform ' + paramreg.algo + '[' + str(paramreg.gradStep) +
            ants_registration_params[paramreg.algo.lower()] + '] '
            '--metric ' + paramreg.metric + '[' + root_d + '_z' + num +
            '.nii' + ',' + root_i + '_z' + num_2 + '.nii' + ',1,' +
            metricSize +
            '] '  #[fixedImage,movingImage,metricWeight +nb_of_bins (MI) or radius (other)
            '--convergence ' + str(paramreg.iter) + ' '
            '--shrink-factors ' + str(paramreg.shrink) + ' '
            '--smoothing-sigmas ' + str(paramreg.smooth) + 'mm '
            #'--restrict-deformation 1x1x0 '    # how to restrict? should not restrict here, if transform is precised...?
            '--output [transform_' + num + ',' + root_i + '_z' + num_2 +
            'reg.nii] '  #--> file.mat (contains Tx,Ty, theta)
            '--interpolation BSpline[3] ' + masking)

        try:
            sct.run(cmd)

            if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation':
                f = 'transform_' + num + '0GenericAffine.mat'
                matfile = loadmat(f, struct_as_record=True)
                array_transfo = matfile['AffineTransform_double_2_2']
                x_displacement[i] = array_transfo[4][
                    0]  # Tx in ITK'S coordinate system
                y_displacement[i] = array_transfo[5][
                    0]  # Ty  in ITK'S and fslview's coordinate systems
                theta_rotation[i] = asin(
                    array_transfo[2]
                )  # angle of rotation theta in ITK'S coordinate system (minus theta for fslview)

            if paramreg.algo == 'Affine':
                # New process added for generating total nifti warping field from mat warp
                name_dest = root_d + '_z' + num + '.nii'
                name_reg = root_i + '_z' + num + 'reg.nii'
                name_output_warp = 'warp_from_mat_' + num_2 + '.nii.gz'
                name_output_warp_inverse = 'warp_from_mat_' + num + '_inverse.nii.gz'
                name_warp_null = 'warp_null_' + num + '.nii.gz'
                name_warp_null_dest = 'warp_null_dest' + num + '.nii.gz'
                name_warp_mat = 'transform_' + num + '0GenericAffine.mat'
                # Generating null nifti warping fields
                nx, ny, nz, nt, px, py, pz, pt = Image(name_reg).dim
                nx_d, ny_d, nz_d, nt_d, px_d, py_d, pz_d, pt_d = Image(
                    name_dest).dim
                x_trans = [0 for i in range(nz)]
                x_trans_d = [0 for i in range(nz_d)]
                y_trans = [0 for i in range(nz)]
                y_trans_d = [0 for i in range(nz_d)]
                generate_warping_field(name_reg,
                                       x_trans=x_trans,
                                       y_trans=y_trans,
                                       fname=name_warp_null,
                                       verbose=0)
                generate_warping_field(name_dest,
                                       x_trans=x_trans_d,
                                       y_trans=y_trans_d,
                                       fname=name_warp_null_dest,
                                       verbose=0)
                # Concatenating mat wrp and null nifti warp to obtain equivalent nifti warp to mat warp
                sct.run('isct_ComposeMultiTransform 2 ' + name_output_warp +
                        ' -R ' + name_reg + ' ' + name_warp_null + ' ' +
                        name_warp_mat)
                sct.run('isct_ComposeMultiTransform 2 ' +
                        name_output_warp_inverse + ' -R ' + name_dest + ' ' +
                        name_warp_null_dest + ' -i ' + name_warp_mat)
                # Split the warping fields into two for displacement along x and y before merge
                sct.run('isct_c3d -mcs ' + name_output_warp +
                        ' -oo transform_' + num + '0Warp_x.nii.gz transform_' +
                        num + '0Warp_y.nii.gz')
                sct.run('isct_c3d -mcs ' + name_output_warp_inverse +
                        ' -oo transform_' + num +
                        '0InverseWarp_x.nii.gz transform_' + num +
                        '0InverseWarp_y.nii.gz')
                # List names of warping fields for futur merge
                list_warp_x.append('transform_' + num + '0Warp_x.nii.gz')
                list_warp_x_inv.append('transform_' + num +
                                       '0InverseWarp_x.nii.gz')
                list_warp_y.append('transform_' + num + '0Warp_y.nii.gz')
                list_warp_y_inv.append('transform_' + num +
                                       '0InverseWarp_y.nii.gz')

            if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN':
                # Split the warping fields into two for displacement along x and y before merge
                # Need to separate the merge for x and y displacement as merge of 3d warping fields does not work properly
                sct.run('isct_c3d -mcs transform_' + num +
                        '0Warp.nii.gz -oo transform_' + num +
                        '0Warp_x.nii.gz transform_' + num + '0Warp_y.nii.gz')
                sct.run('isct_c3d -mcs transform_' + num +
                        '0InverseWarp.nii.gz -oo transform_' + num +
                        '0InverseWarp_x.nii.gz transform_' + num +
                        '0InverseWarp_y.nii.gz')
                # List names of warping fields for futur merge
                list_warp_x.append('transform_' + num + '0Warp_x.nii.gz')
                list_warp_x_inv.append('transform_' + num +
                                       '0InverseWarp_x.nii.gz')
                list_warp_y.append('transform_' + num + '0Warp_y.nii.gz')
                list_warp_y_inv.append('transform_' + num +
                                       '0InverseWarp_y.nii.gz')
        # if an exception occurs with ants, take the last value for the transformation
        except:
            if paramreg.algo == 'Rigid' or paramreg.algo == 'Translation':
                x_displacement[i] = x_displacement[i - 1]
                y_displacement[i] = y_displacement[i - 1]
                theta_rotation[i] = theta_rotation[i - 1]

            if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine':
                print 'Problem with ants for slice ' + str(
                    i) + '. Copy of the last warping field.'
                sct.run('cp transform_' + numerotation(i - 1) +
                        '0Warp.nii.gz transform_' + num + '0Warp.nii.gz')
                sct.run('cp transform_' + numerotation(i - 1) +
                        '0InverseWarp.nii.gz transform_' + num +
                        '0InverseWarp.nii.gz')
                # Split the warping fields into two for displacement along x and y before merge
                sct.run('isct_c3d -mcs transform_' + num +
                        '0Warp.nii.gz -oo transform_' + num +
                        '0Warp_x.nii.gz transform_' + num + '0Warp_y.nii.gz')
                sct.run('isct_c3d -mcs transform_' + num +
                        '0InverseWarp.nii.gz -oo transform_' + num +
                        '0InverseWarp_x.nii.gz transform_' + num +
                        '0InverseWarp_y.nii.gz')
                # List names of warping fields for futur merge
                list_warp_x.append('transform_' + num + '0Warp_x.nii.gz')
                list_warp_x_inv.append('transform_' + num +
                                       '0InverseWarp_x.nii.gz')
                list_warp_y.append('transform_' + num + '0Warp_y.nii.gz')
                list_warp_y_inv.append('transform_' + num +
                                       '0InverseWarp_y.nii.gz')

    if paramreg.algo == 'BSplineSyN' or paramreg.algo == 'SyN' or paramreg.algo == 'Affine':
        print '\nMerge along z of the warping fields...'
        # from sct_concat_data import concat_data
        sct.run('sct_concat_data -i ' + ','.join(list_warp_x) + ' -o ' +
                name_warp_final + '_x.nii.gz -dim z')
        sct.run('sct_concat_data -i ' + ','.join(list_warp_x_inv) + ' -o ' +
                name_warp_final + '_x_inverse.nii.gz -dim z')
        sct.run('sct_concat_data -i ' + ','.join(list_warp_y) + ' -o ' +
                name_warp_final + '_y.nii.gz -dim z')
        sct.run('sct_concat_data -i ' + ','.join(list_warp_y_inv) + ' -o ' +
                name_warp_final + '_y_inverse.nii.gz -dim z')
        # concat_data(','.join(list_warp_x), name_warp_final+'_x.nii.gz', 2)
        # concat_data(','.join(list_warp_x_inv), name_warp_final+'_x_inverse.nii.gz', 2)
        # concat_data(','.join(list_warp_y), name_warp_final+'_y.nii.gz', 2)
        # concat_data(','.join(list_warp_y_inv), name_warp_final+'_y_inverse.nii.gz', 2)
        # sct.run('fslmerge -z ' + name_warp_final + '_x ' + " ".join(list_warp_x))
        # sct.run('fslmerge -z ' + name_warp_final + '_x_inverse ' + " ".join(list_warp_x_inv))
        # sct.run('fslmerge -z ' + name_warp_final + '_y ' + " ".join(list_warp_y))
        # sct.run('fslmerge -z ' + name_warp_final + '_y_inverse ' + " ".join(list_warp_y_inv))
        print '\nChange resolution of warping fields to match the resolution of the destination image...'
        from sct_copy_header import copy_header
        copy_header(fname_dest, name_warp_final + '_x.nii.gz')
        copy_header(fname_source, name_warp_final + '_x_inverse.nii.gz')
        copy_header(fname_dest, name_warp_final + '_y.nii.gz')
        copy_header(fname_source, name_warp_final + '_y_inverse.nii.gz')
        print '\nMerge translation fields along x and y into one global warping field '
        sct.run('isct_c3d ' + name_warp_final + '_x.nii.gz ' +
                name_warp_final + '_y.nii.gz -omc 2 ' + name_warp_final +
                '.nii.gz')
        sct.run('isct_c3d ' + name_warp_final + '_x_inverse.nii.gz ' +
                name_warp_final + '_y_inverse.nii.gz -omc 2 ' +
                name_warp_final + '_inverse.nii.gz')
        print '\nCopy to parent folder...'
        sct.run('cp ' + name_warp_final + '.nii.gz ../')
        sct.run('cp ' + name_warp_final + '_inverse.nii.gz ../')

    #Delete tmp folder
    os.chdir('../')
    if remove_tmp_folder:
        print('\nRemove temporary files...')
        sct.run('rm -rf ' + path_tmp)
    if paramreg.algo == 'Rigid':
        return x_displacement, y_displacement, theta_rotation
    if paramreg.algo == 'Translation':
        return x_displacement, y_displacement
Exemplo n.º 2
0
        self.im_plot_frontal.set_interpolation('nearest')

        ax = self.fig.add_subplot(223)
        self.im_plot_sagittal = ax.imshow(self.image.data[:,:,int(self.im_size[2]/2)])
        self.im_plot_sagittal.set_cmap('gray')
        self.im_plot_sagittal.set_interpolation('nearest')

        trio = TrioPlot(self.im_plot_axial, self.im_plot_frontal, self.im_plot_sagittal, self.image)
        trio.connect()

        #slider_ax = self.fig.add_axes([0.15, 0.05, 0.75, 0.03])
        #slider_axial = Slider(slider_ax, 'Axial slices', 0, self.im_size[1], valinit=int(self.im_size[1]/2))
        #slider_axial.on_changed(self.updateAxial)

        plt.show()



#=======================================================================================================================
# Start program
#=======================================================================================================================
if __name__ == "__main__":
    parser = Parser(__file__)
    parser.usage.set_description('Volume Viewer')
    parser.add_option("-i", "file", "file", True)
    arguments = parser.parse(sys.argv[1:])

    image = Image(arguments["-i"])
    viewer = VolViewer(image)
    viewer.show()
def generate_warping_field(fname_dest,
                           x_trans,
                           y_trans,
                           theta_rot=None,
                           center_rotation=None,
                           fname='warping_field.nii.gz',
                           verbose=1):
    """Generation of a warping field towards an image and given transformation parameters.

    Given a destination image and transformation parameters this functions creates a NIFTI 3D warping field that can be
    applied afterwards. The transformation parameters corresponds to a slice-by-slice registration of images, thus the
    transformation parameters must be precised for each slice of the image.

    inputs:
        fname_dest: name of destination image (type: string)
        x_trans: list of translations along x axis for each slice (type: list, length: height of fname_dest)
        y_trans: list of translations along y axis for each slice (type: list, length: height of fname_dest)
        theta_rot[optional]: list of rotation angles in radian (and in ITK's coordinate system) for each slice (type: list)
        center_rotation[optional]: pixel coordinates in plan xOy of the wanted center of rotation (type: list,
            length: 2, example: [0,ny/2])
        fname[optional]: name of output warp (type: string)
        verbose: display parameter (type: int)

    output:
        creation of a warping field of name 'fname' with an header similar to the destination image.
    """
    from nibabel import load
    from math import cos, sin
    from sct_orientation import get_orientation

    #Make sure image is in rpi format
    sct.printv(
        '\nChecking if the image of destination is in RPI orientation for the warping field generation ...',
        verbose)
    orientation = get_orientation(fname_dest)
    if orientation != 'RPI':
        sct.printv(
            '\nWARNING: The image of destination is not in RPI format. Dimensions of the warping field might be inverted.',
            verbose)
    else:
        sct.printv('\tOK', verbose)

    sct.printv(
        '\n\nCreating warping field ' + fname +
        ' for transformations along z...', verbose)

    file_dest = load(fname_dest)
    hdr_file_dest = file_dest.get_header()
    hdr_warp = hdr_file_dest.copy()

    # Get image dimensions
    sct.printv('\nGet image dimensions of destination image...', verbose)
    nx, ny, nz, nt, px, py, pz, pt = Image(fname_dest).dim
    sct.printv(
        '.. matrix size: ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz),
        verbose)
    sct.printv(
        '.. voxel size:  ' + str(px) + 'mm x ' + str(py) + 'mm x ' + str(pz) +
        'mm', verbose)

    #Center of rotation
    if center_rotation == None:
        x_a = int(round(nx / 2))
        y_a = int(round(ny / 2))
    else:
        x_a = center_rotation[0]
        y_a = center_rotation[1]

    # Calculate displacement for each voxel
    data_warp = zeros(((((nx, ny, nz, 1, 3)))))
    # For translations
    if theta_rot == None:
        for i in range(nx):
            for j in range(ny):
                for k in range(nz):
                    data_warp[i, j, k, 0, 0] = x_trans[k]
                    data_warp[i, j, k, 0, 1] = y_trans[k]
                    data_warp[i, j, k, 0, 2] = 0
    # # For rigid transforms (not optimized)
    # if theta_rot != None:
    #     for k in range(nz):
    #         for i in range(nx):
    #             for j in range(ny):
    #                 # data_warp[i, j, k, 0, 0] = (cos(theta_rot[k])-1) * (i - x_a) - sin(theta_rot[k]) * (j - y_a) - x_trans[k]
    #                 # data_warp[i, j, k, 0, 1] = -(sin(theta_rot[k]) * (i - x_a) + (cos(theta_rot[k])-1) * (j - y_a)) + y_trans[k]
    #
    #                 data_warp[i, j, k, 0, 0] = (cos(theta_rot[k]) - 1) * (i - x_a) - sin(theta_rot[k]) * (j - y_a) + x_trans[k] #+ sin(theta_rot[k]) * (int(round(nx/2))-x_a)
    #                 data_warp[i, j, k, 0, 1] = - sin(theta_rot[k]) * (i - x_a) - (cos(theta_rot[k]) - 1) * (j - y_a) + y_trans[k] #- sin(theta_rot[k]) * (int(round(nx/2))-x_a)
    #                 data_warp[i, j, k, 0, 2] = 0

    # For rigid transforms with array (time optimization)
    if theta_rot != None:
        vector_i = [[[i - x_a], [j - y_a]] for i in range(nx)
                    for j in range(ny)]
        for k in range(nz):
            matrix_rot_a = asarray([[cos(theta_rot[k]), -sin(theta_rot[k])],
                                    [-sin(theta_rot[k]), -cos(theta_rot[k])]])
            tmp = matrix_rot_a + array(((-1, 0), (0, 1)))
            result = dot(tmp,
                         array(vector_i).T[0]) + array([[x_trans[k]],
                                                        [y_trans[k]]])
            for i in range(nx):
                data_warp[i, :, k, 0, 0] = result[0][i * nx:i * nx + ny]
                data_warp[i, :, k, 0, 1] = result[1][i * nx:i * nx + ny]

    # Generate warp file as a warping field
    hdr_warp.set_intent('vector', (), '')
    hdr_warp.set_data_dtype('float32')
    img = nibabel.Nifti1Image(data_warp, None, hdr_warp)
    nibabel.save(img, fname)
    sct.printv('\nDONE ! Warping field generated: ' + fname, verbose)
Exemplo n.º 4
0
def main(args = None):

    orientation = ''
    change_header = ''
    fname_out = ''

    if not args:
        args = sys.argv[1:]

    # Building the command, do sanity checks
    parser = get_parser()
    arguments = parser.parse(sys.argv[1:])
    fname_in = arguments['-i']
    if '-o' in arguments:
        fname_out = arguments['-o']
    if '-s' in arguments:
        orientation = arguments['-s']
    if '-a' in arguments:
        change_header = arguments['-a']
    remove_tmp_files = int(arguments['-r'])
    verbose = int(arguments['-v'])
    inversion = False  # change orientation

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

    # copy file in temp folder
    sct.printv('\nCopy files to tmp folder...', verbose)
    convert(fname_in, path_tmp+'data.nii')

    # go to temp folder
    os.chdir(path_tmp)

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

    # if data are 3d, directly set or get orientation
    if nt == 1:
        if orientation != '':
            # set orientation
            sct.printv('\nChange orientation...', verbose)
            if change_header == '':
                set_orientation('data.nii', orientation, 'data_orient.nii')
            else:
                set_orientation('data.nii', change_header, 'data_orient.nii', True)
        else:
            # get orientation
            sct.printv('\nGet orientation...', verbose)
            print get_orientation('data.nii')
    else:
        # split along T dimension
        sct.printv('\nSplit along T dimension...', verbose)
        from sct_split_data import split_data
        split_data('data.nii', 3, '_T')
        if orientation != '':
            # set orientation
            sct.printv('\nChange orientation...', verbose)
            for it in range(nt):
                file_data_split = 'data_T'+str(it).zfill(4)+'.nii'
                file_data_split_orient = 'data_orient_T'+str(it).zfill(4)+'.nii'
                set_orientation(file_data_split, orientation, file_data_split_orient)
            # Merge files back
            sct.printv('\nMerge file back...', verbose)
            from sct_concat_data import concat_data
            from glob import glob
            concat_data(glob('data_orient_T*.nii'), 'data_orient.nii', dim=3)

        else:
            sct.printv('\nGet orientation...', verbose)
            print get_orientation('data_T0000.nii')

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

    # Generate output files
    if orientation != '':
        # Build fname_out
        if fname_out == '':
            path_data, file_data, ext_data = sct.extract_fname(fname_in)
            fname_out = path_data+file_data+'_'+orientation+ext_data
        sct.printv('\nGenerate output files...', verbose)
        sct.generate_output_file(path_tmp+'data_orient.nii', fname_out)

    # Remove temporary files
    if remove_tmp_files == 1:
        sct.printv('\nRemove temporary files...', verbose)
        sct.run('rm -rf '+path_tmp, verbose)
Exemplo n.º 5
0
    if '-bin' in arguments:
        fname_input1_bin = sct.add_suffix(fname_input1, '_bin')
        sct.run([
            'sct_maths', '-i', fname_input1, '-bin', '0', '-o',
            fname_input1_bin
        ])
        fname_input1 = fname_input1_bin
        fname_input2_bin = sct.add_suffix(fname_input2, '_bin')
        sct.run([
            'sct_maths', '-i', fname_input2, '-bin', '0', '-o',
            fname_input2_bin
        ])
        fname_input2 = fname_input2_bin

    # copy header of im_1 to im_2
    im_1, im_2 = Image(fname_input1), Image(fname_input2)
    im_2_cor = copy_header(im_1, im_2)
    im_2_cor.save()

    cmd = ['isct_dice_coefficient', fname_input1, fname_input2]

    if '-2d-slices' in arguments:
        cmd += ['-2d-slices', arguments['-2d-slices']]
    if '-b' in arguments:
        bounding_box = arguments['-b']
        cmd += ['-b'] + bounding_box
    if '-bmax' in arguments and arguments['-bmax'] == '1':
        cmd += ['-bmax']
    if '-bzmax' in arguments and arguments['-bzmax'] == '1':
        cmd += ['-bzmax']
    if '-o' in arguments:
Exemplo n.º 6
0
    def crop(self):
        """
        Crop image (change dimension)
        """

        # create command line
        self.cmd = [
            "isct_crop_image", "-i", self.input_filename, "-o",
            self.output_filename
        ]
        # Handling optional arguments

        # if mask is specified, find -start and -end arguments
        if self.mask is not None:
            # if user already specified -start or -end arguments, let him know they will be ignored
            if self.start is not None or self.end is not None:
                sct.printv(
                    'WARNING: Mask was specified for cropping. Arguments -start and -end will be ignored',
                    1, 'warning')
            self.start, self.end, self.dim = find_mask_boundaries(self.mask)

        if self.start is not None:
            self.cmd += ["-start", ','.join(map(str, self.start))]
        if self.end is not None:
            self.cmd += ["-end", ','.join(map(str, self.end))]
        if self.dim is not None:
            self.cmd += ["-dim", ','.join(map(str, self.dim))]
        if self.shift is not None:
            self.cmd += ["-shift", ','.join(map(str, self.shift))]
        if self.background is not None:
            self.cmd += ["-b", str(self.background)]
        if self.bmax is True:
            self.cmd += ["-bmax"]
        if self.ref is not None:
            self.cmd += ["-ref", self.ref]
        if self.mesh is not None:
            self.cmd += ["-mesh", self.mesh]

        verb = 0
        if self.verbose == 1:
            verb = 2
        if self.mask is not None and self.background is not None:
            self.crop_from_mask_with_background()
        else:
            # Run command line
            sct.run(self.cmd, verb)

        self.result = Image(self.output_filename, verbose=self.verbose)

        # removes the output file created by the script if it is not needed
        if self.rm_output_file:
            try:
                os.remove(self.output_filename)
            except OSError:
                sct.printv(
                    "WARNING : Couldn't remove output file. Either it is opened elsewhere or "
                    "it doesn't exist.", self.verbose, 'warning')
        else:
            sct.display_viewer_syntax([self.output_filename])

        return self.result
Exemplo n.º 7
0
def moco(param):

    # retrieve parameters
    fsloutput = 'export FSLOUTPUTTYPE=NIFTI; '  # for faster processing, all outputs are in NIFTI
    file_data = param.file_data
    file_target = param.file_target
    folder_mat = sct.slash_at_the_end(param.mat_moco,
                                      1)  # output folder of mat file
    todo = param.todo
    suffix = param.suffix
    #file_schedule = param.file_schedule
    verbose = param.verbose
    ext = '.nii'

    # get path of the toolbox
    status, path_sct = commands.getstatusoutput('echo $SCT_DIR')

    # sct.printv(arguments)
    sct.printv('\nInput parameters:', param.verbose)
    sct.printv('  Input file ............' + file_data, param.verbose)
    sct.printv('  Reference file ........' + file_target, param.verbose)
    sct.printv('  Polynomial degree .....' + param.poly, param.verbose)
    sct.printv('  Smoothing kernel ......' + param.smooth, param.verbose)
    sct.printv('  Gradient step .........' + param.gradStep, param.verbose)
    sct.printv('  Metric ................' + param.metric, param.verbose)
    sct.printv('  Sampling ..............' + param.sampling, param.verbose)
    sct.printv('  Todo ..................' + todo, param.verbose)
    sct.printv('  Mask  .................' + param.fname_mask, param.verbose)
    sct.printv('  Output mat folder .....' + folder_mat, param.verbose)

    # create folder for mat files
    sct.create_folder(folder_mat)

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

    # copy file_target to a temporary file
    sct.printv('\nCopy file_target to a temporary file...', verbose)
    sct.run('cp ' + file_target + ext + ' target.nii')
    file_target = 'target'

    # Split data along T dimension
    sct.printv('\nSplit data along T dimension...', verbose)
    data_split_list = split_data(data_im, dim=3)
    for im in data_split_list:
        im.save()
    file_data_splitT = file_data + '_T'

    # Motion correction: initialization
    index = np.arange(nt)
    file_data_splitT_num = []
    file_data_splitT_moco_num = []
    failed_transfo = [0 for i in range(nt)]
    file_mat = [[] for i in range(nt)]

    # Motion correction: Loop across T
    for indice_index in range(nt):

        # create indices and display stuff
        it = index[indice_index]
        file_data_splitT_num.append(file_data_splitT + str(it).zfill(4))
        file_data_splitT_moco_num.append(file_data + suffix + '_T' +
                                         str(it).zfill(4))
        sct.printv(('\nVolume ' + str((it)) + '/' + str(nt - 1) + ':'),
                   verbose)
        file_mat[it] = folder_mat + 'mat.T' + str(it)

        # run 3D registration
        failed_transfo[it] = register(param, file_data_splitT_num[it],
                                      file_target, file_mat[it],
                                      file_data_splitT_moco_num[it])

        # average registered volume with target image
        # N.B. use weighted averaging: (target * nb_it + moco) / (nb_it + 1)
        if param.iterative_averaging and indice_index < 10 and failed_transfo[
                it] == 0 and not param.todo == 'apply':
            sct.run('sct_maths -i ' + file_target + ext + ' -mul ' +
                    str(indice_index + 1) + ' -o ' + file_target + ext)
            sct.run('sct_maths -i ' + file_target + ext + ' -add ' +
                    file_data_splitT_moco_num[it] + ext + ' -o ' +
                    file_target + ext)
            sct.run('sct_maths -i ' + file_target + ext + ' -div ' +
                    str(indice_index + 2) + ' -o ' + file_target + ext)

    # Replace failed transformation with the closest good one
    sct.printv(('\nReplace failed transformations...'), verbose)
    fT = [i for i, j in enumerate(failed_transfo) if j == 1]
    gT = [i for i, j in enumerate(failed_transfo) if j == 0]
    for it in range(len(fT)):
        abs_dist = [abs(gT[i] - fT[it]) for i in range(len(gT))]
        if not abs_dist == []:
            index_good = abs_dist.index(min(abs_dist))
            sct.printv(
                '  transfo #' + str(fT[it]) + ' --> use transfo #' +
                str(gT[index_good]), verbose)
            # copy transformation
            sct.run('cp ' + file_mat[gT[index_good]] + 'Warp.nii.gz' + ' ' +
                    file_mat[fT[it]] + 'Warp.nii.gz')
            # apply transformation
            sct.run(
                'sct_apply_transfo -i ' + file_data_splitT_num[fT[it]] +
                '.nii -d ' + file_target + '.nii -w ' + file_mat[fT[it]] +
                'Warp.nii.gz' + ' -o ' + file_data_splitT_moco_num[fT[it]] +
                '.nii' + ' -x ' + param.interp, verbose)
        else:
            # exit program if no transformation exists.
            sct.printv(
                '\nERROR in ' + os.path.basename(__file__) +
                ': No good transformation exist. Exit program.\n', verbose,
                'error')
            sys.exit(2)

    # Merge data along T
    file_data_moco = file_data + suffix
    if todo != 'estimate':
        sct.printv('\nMerge data back along T...', verbose)
        from sct_image import concat_data
        # im_list = []
        fname_list = []
        for indice_index in range(len(index)):
            # im_list.append(Image(file_data_splitT_moco_num[indice_index] + ext))
            fname_list.append(file_data_splitT_moco_num[indice_index] + ext)
        im_out = concat_data(fname_list, 3)
        im_out.setFileName(file_data_moco + ext)
        im_out.save()

    # delete file target.nii (to avoid conflict if this function is run another time)
    sct.printv('\nRemove temporary file...', verbose)
    # os.remove('target.nii')
    sct.run('rm target.nii')
    def continuous_vertebral_levels(self):
        """
        This function transforms the vertebral levels file from the template into a continuous file.
        Instead of having integer representing the vertebral level on each slice, a continuous value that represents
        the position of the slice in the vertebral level coordinate system.
        The image must be RPI
        :return:
        """
        im_input = Image(self.image_input, self.verbose)
        im_output = Image(self.image_input, self.verbose)
        im_output.data *= 0

        # 1. extract vertebral levels from input image
        #   a. extract centerline
        #   b. for each slice, extract corresponding level
        nx, ny, nz, nt, px, py, pz, pt = im_input.dim
        from sct_straighten_spinalcord import smooth_centerline
        x_centerline_fit, y_centerline_fit, z_centerline_fit, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(
            self.image_input, algo_fitting='nurbs', verbose=0)
        value_centerline = np.array([
            im_input.data[int(x_centerline_fit[it]),
                          int(y_centerline_fit[it]),
                          int(z_centerline_fit[it])]
            for it in range(len(z_centerline_fit))
        ])

        # 2. compute distance for each vertebral level --> Di for i being the vertebral levels
        vertebral_levels = {}
        for slice_image, level in enumerate(value_centerline):
            if level not in vertebral_levels:
                vertebral_levels[level] = slice_image

        length_levels = {}
        for level in vertebral_levels:
            indexes_slice = np.where(value_centerline == level)
            length_levels[level] = np.sum([
                math.sqrt(
                    ((x_centerline_fit[indexes_slice[0][index_slice + 1]] -
                      x_centerline_fit[indexes_slice[0][index_slice]]) *
                     px)**2 +
                    ((y_centerline_fit[indexes_slice[0][index_slice + 1]] -
                      y_centerline_fit[indexes_slice[0][index_slice]]) *
                     py)**2 +
                    ((z_centerline_fit[indexes_slice[0][index_slice + 1]] -
                      z_centerline_fit[indexes_slice[0][index_slice]]) *
                     pz)**2)
                for index_slice in range(len(indexes_slice[0]) - 1)
            ])

        # 2. for each slice:
        #   a. identify corresponding vertebral level --> i
        #   b. calculate distance of slice from upper vertebral level --> d
        #   c. compute relative distance in the vertebral level coordinate system --> d/Di
        continuous_values = {}
        for it, iz in enumerate(z_centerline_fit):
            level = value_centerline[it]
            indexes_slice = np.where(value_centerline == level)
            indexes_slice = indexes_slice[0][indexes_slice[0] >= it]
            distance_from_level = np.sum([
                math.sqrt(((x_centerline_fit[indexes_slice[index_slice + 1]] -
                            x_centerline_fit[indexes_slice[index_slice]]) *
                           px * px)**2 +
                          ((y_centerline_fit[indexes_slice[index_slice + 1]] -
                            y_centerline_fit[indexes_slice[index_slice]]) *
                           py * py)**2 +
                          ((z_centerline_fit[indexes_slice[index_slice + 1]] -
                            z_centerline_fit[indexes_slice[index_slice]]) *
                           pz * pz)**2)
                for index_slice in range(len(indexes_slice) - 1)
            ])
            continuous_values[iz] = level + 2.0 * distance_from_level / float(
                length_levels[level])

        # 3. saving data
        # for each slice, get all non-zero pixels and replace with continuous values
        coordinates_input = self.image_input.getNonZeroCoordinates()
        im_output.changeType('float32')
        # for all points in input, find the value that has to be set up, depending on the vertebral level
        for i, coord in enumerate(coordinates_input):
            im_output.data[int(coord.x),
                           int(coord.y),
                           int(coord.z)] = continuous_values[coord.z]

        return im_output
def crop_image_around_segmentation(fname_in, fname_seg, path_output_im,
                                   path_output_seg, size_crop, offset,
                                   remove_tmp_files, verbose):
    # 1. Resample to 1mm^3 isotropic
    fname_in_resampled = sct.add_suffix(fname_in, 'r')
    sct.run('sct_resample -i ' + fname_in + ' -mm 1x1x1 -o ' +
            fname_in_resampled,
            verbose=verbose)
    fname_in = fname_in_resampled
    fname_seg_resample = sct.add_suffix(fname_seg, 'r')
    sct.run('sct_resample -i ' + fname_seg + ' -mm 1x1x1 -o ' +
            fname_seg_resample,
            verbose=verbose)
    fname_seg = fname_seg_resample

    # 2. Orient both input images to RPI for the sake of simplicity
    sct.run('sct_image -i ' + fname_in + ' -setorient RPI', verbose=verbose)
    fname_in = sct.add_suffix(fname_in, '_RPI')
    sct.run('sct_image -i ' + fname_seg + ' -setorient RPI', verbose=verbose)
    fname_seg = sct.add_suffix(fname_seg, '_RPI')

    # 3. Pad both images to avoid edge issues when cropping
    fname_in_pad = sct.add_suffix(fname_in, 'p')
    pad_image = str(int(int(size_crop) / 2))
    sct.run('sct_image -i ' + fname_in + ' -pad ' + pad_image + ',' +
            pad_image + ',0 -o ' + fname_in_pad,
            verbose=verbose)
    fname_in = fname_in_pad
    fname_seg_pad = sct.add_suffix(fname_seg, 'p')
    sct.run('sct_image -i ' + fname_seg + ' -pad ' + pad_image + ',' +
            pad_image + ',0 -o ' + fname_seg_pad,
            verbose=verbose)
    fname_seg = fname_seg_pad

    # 4. Extract centerline from segmentation
    fname_centerline = sct.add_suffix(fname_seg, '_centerline')
    sct.run('sct_process_segmentation -i ' + fname_seg + ' -p centerline',
            verbose=verbose)  # -o ' + fname_centerline)

    # 5. Create a square mask around the spinal cord centerline
    fname_mask_box = 'mask_box.nii.gz'
    sct.run('sct_create_mask -i ' + fname_in + ' -m centerline,' +
            fname_centerline + ' -s ' + str(size_crop) + ' -o ' +
            fname_mask_box + ' -f box -e 1 -k ' + offset,
            verbose=verbose)

    # 6. Crop image around the spinal cord and create a stack of square images
    sct.printv('Cropping around mask and stacking slices...', verbose=verbose)
    im_mask_box = Image(fname_mask_box)
    im_input = Image(fname_in)
    im_input.crop_and_stack(im_mask_box, suffix='_stack', save=True)
    im_seg = Image(fname_seg)
    im_seg.crop_and_stack(im_mask_box, suffix='_stack', save=True)

    # 6.5 Change name of images
    fname_stack_image = sct.add_suffix(fname_in, '_stack')
    fname_stack_seg = sct.add_suffix(fname_seg, '_stack')
    import random
    output_im_filename = str(random.randint(1, 1000000000000))
    output_im_fname = output_im_filename + '_im.nii.gz'
    output_seg_fname = output_im_filename + '_seg.nii.gz'
    sct.run('mv ' + fname_stack_image + ' ' + output_im_fname, verbose=verbose)
    sct.run('mv ' + fname_stack_seg + ' ' + output_seg_fname, verbose=verbose)

    # 7. Split the two stack images and save each slice
    sct.run('sct_image -i ' + output_im_fname + ' -split z', verbose=verbose)
    sct.run('sct_image -i ' + output_seg_fname + ' -split z', verbose=verbose)

    # 8. Move all images to output folders
    path_fname, file_fname, ext_fname = sct.extract_fname(output_im_fname)
    sct.run('mv ' + file_fname + '_* ' + path_output_im, verbose=verbose)
    path_fname, file_fname, ext_fname = sct.extract_fname(output_seg_fname)
    sct.run('mv ' + file_fname + '_* ' + path_output_seg, verbose=verbose)
Exemplo n.º 10
0
def main():

    # Initialization
    fname_mt0 = ''
    fname_mt1 = ''
    file_out = param.file_out
    # register = param.register
    # remove_tmp_files = param.remove_tmp_files
    # verbose = param.verbose

    # get path of the toolbox
    # status, path_sct = commands.getstatusoutput('echo $SCT_DIR')

    # Check input parameters
    parser = get_parser()
    arguments = parser.parse(sys.argv[1:])

    fname_mt0 = arguments['-mt0']
    fname_mt1 = arguments['-mt1']
    remove_tmp_files = int(arguments['-r'])
    verbose = int(arguments['-v'])

    # Extract path/file/extension
    path_mt0, file_mt0, ext_mt0 = sct.extract_fname(fname_mt0)
    path_out, file_out, ext_out = '', file_out, ext_mt0

    # create temporary folder
    path_tmp = sct.tmp_create()

    # Copying input data to tmp folder and convert to nii
    sct.printv('\nCopying input data to tmp folder and convert to nii...',
               verbose)
    from sct_convert import convert
    convert(fname_mt0, path_tmp + 'mt0.nii', type='float32')
    convert(fname_mt1, path_tmp + 'mt1.nii', type='float32')

    # go to tmp folder
    os.chdir(path_tmp)

    # compute MTR
    sct.printv('\nCompute MTR...', verbose)
    from msct_image import Image
    nii_mt1 = Image('mt1.nii')
    data_mt1 = nii_mt1.data
    data_mt0 = Image('mt0.nii').data
    data_mtr = 100 * (data_mt0 - data_mt1) / data_mt0
    # save MTR file
    nii_mtr = nii_mt1
    nii_mtr.data = data_mtr
    nii_mtr.setFileName('mtr.nii')
    nii_mtr.save()
    # sct.run(fsloutput+'fslmaths -dt double mt0.nii -sub mt1.nii -mul 100 -div mt0.nii -thr 0 -uthr 100 mtr.nii', verbose)

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

    # Generate output files
    sct.printv('\nGenerate output files...', verbose)
    sct.generate_output_file(path_tmp + 'mtr.nii',
                             path_out + file_out + ext_out)

    # Remove temporary files
    if remove_tmp_files == 1:
        print('\nRemove temporary files...')
        sct.run('rm -rf ' + path_tmp)

    # to view results
    sct.printv('\nDone! To view results, type:', verbose)
    sct.printv(
        'fslview ' + fname_mt0 + ' ' + fname_mt1 + ' ' + file_out + ' &\n',
        verbose, 'info')
Exemplo n.º 11
0
def main():

    # get default parameters
    step1 = Paramreg(step='1',
                     type='seg',
                     algo='slicereg',
                     metric='MeanSquares',
                     iter='10')
    step2 = Paramreg(step='2', type='im', algo='syn', metric='MI', iter='3')
    # step1 = Paramreg()
    paramreg = ParamregMultiStep([step1, step2])

    # step1 = Paramreg_step(step='1', type='seg', algo='bsplinesyn', metric='MeanSquares', iter='10', shrink='1', smooth='0', gradStep='0.5')
    # step2 = Paramreg_step(step='2', type='im', algo='syn', metric='MI', iter='10', shrink='1', smooth='0', gradStep='0.5')
    # paramreg = ParamregMultiStep([step1, step2])

    # Initialize the parser
    parser = Parser(__file__)
    parser.usage.set_description('Register anatomical image to the template.')
    parser.add_option(name="-i",
                      type_value="file",
                      description="Anatomical image.",
                      mandatory=True,
                      example="anat.nii.gz")
    parser.add_option(name="-s",
                      type_value="file",
                      description="Spinal cord segmentation.",
                      mandatory=True,
                      example="anat_seg.nii.gz")
    parser.add_option(
        name="-l",
        type_value="file",
        description=
        "Labels. See: http://sourceforge.net/p/spinalcordtoolbox/wiki/create_labels/",
        mandatory=True,
        default_value='',
        example="anat_labels.nii.gz")
    parser.add_option(name="-t",
                      type_value="folder",
                      description="Path to MNI-Poly-AMU template.",
                      mandatory=False,
                      default_value=param.path_template)
    parser.add_option(
        name="-p",
        type_value=[[':'], 'str'],
        description=
        """Parameters for registration (see sct_register_multimodal). Default:\n--\nstep=1\ntype="""
        + paramreg.steps['1'].type + """\nalgo=""" + paramreg.steps['1'].algo +
        """\nmetric=""" + paramreg.steps['1'].metric + """\npoly=""" +
        paramreg.steps['1'].poly + """\n--\nstep=2\ntype=""" +
        paramreg.steps['2'].type + """\nalgo=""" + paramreg.steps['2'].algo +
        """\nmetric=""" + paramreg.steps['2'].metric + """\niter=""" +
        paramreg.steps['2'].iter + """\nshrink=""" +
        paramreg.steps['2'].shrink + """\nsmooth=""" +
        paramreg.steps['2'].smooth + """\ngradStep=""" +
        paramreg.steps['2'].gradStep + """\n--""",
        mandatory=False,
        example=
        "step=2,type=seg,algo=bsplinesyn,metric=MeanSquares,iter=5,shrink=2:step=3,type=im,algo=syn,metric=MI,iter=5,shrink=1,gradStep=0.3"
    )
    parser.add_option(name="-r",
                      type_value="multiple_choice",
                      description="""Remove temporary files.""",
                      mandatory=False,
                      default_value='1',
                      example=['0', '1'])
    parser.add_option(
        name="-v",
        type_value="multiple_choice",
        description="""Verbose. 0: nothing. 1: basic. 2: extended.""",
        mandatory=False,
        default_value=param.verbose,
        example=['0', '1', '2'])
    if param.debug:
        print '\n*** WARNING: DEBUG MODE ON ***\n'
        fname_data = '/Users/julien/data/temp/sct_example_data/t2/t2.nii.gz'
        fname_landmarks = '/Users/julien/data/temp/sct_example_data/t2/labels.nii.gz'
        fname_seg = '/Users/julien/data/temp/sct_example_data/t2/t2_seg.nii.gz'
        path_template = param.path_template
        remove_temp_files = 0
        verbose = 2
        # speed = 'superfast'
        #param_reg = '2,BSplineSyN,0.6,MeanSquares'
    else:
        arguments = parser.parse(sys.argv[1:])

        # get arguments
        fname_data = arguments['-i']
        fname_seg = arguments['-s']
        fname_landmarks = arguments['-l']
        path_template = arguments['-t']
        remove_temp_files = int(arguments['-r'])
        verbose = int(arguments['-v'])
        if '-p' in arguments:
            paramreg_user = arguments['-p']
            # update registration parameters
            for paramStep in paramreg_user:
                paramreg.addStep(paramStep)

    # initialize other parameters
    file_template = param.file_template
    file_template_label = param.file_template_label
    file_template_seg = param.file_template_seg
    output_type = param.output_type
    zsubsample = param.zsubsample
    # smoothing_sigma = param.smoothing_sigma

    # start timer
    start_time = time.time()

    # get absolute path - TO DO: remove! NEVER USE ABSOLUTE PATH...
    path_template = os.path.abspath(path_template)

    # get fname of the template + template objects
    fname_template = sct.slash_at_the_end(path_template, 1) + file_template
    fname_template_label = sct.slash_at_the_end(path_template,
                                                1) + file_template_label
    fname_template_seg = sct.slash_at_the_end(path_template,
                                              1) + file_template_seg

    # check file existence
    sct.printv('\nCheck template files...')
    sct.check_file_exist(fname_template, verbose)
    sct.check_file_exist(fname_template_label, verbose)
    sct.check_file_exist(fname_template_seg, verbose)

    # print arguments
    sct.printv('\nCheck parameters:', verbose)
    sct.printv('.. Data:                 ' + fname_data, verbose)
    sct.printv('.. Landmarks:            ' + fname_landmarks, verbose)
    sct.printv('.. Segmentation:         ' + fname_seg, verbose)
    sct.printv('.. Path template:        ' + path_template, verbose)
    sct.printv('.. Output type:          ' + str(output_type), verbose)
    sct.printv('.. Remove temp files:    ' + str(remove_temp_files), verbose)

    sct.printv('\nParameters for registration:')
    for pStep in range(1, len(paramreg.steps) + 1):
        sct.printv('Step #' + paramreg.steps[str(pStep)].step, verbose)
        sct.printv('.. Type #' + paramreg.steps[str(pStep)].type, verbose)
        sct.printv(
            '.. Algorithm................ ' + paramreg.steps[str(pStep)].algo,
            verbose)
        sct.printv(
            '.. Metric................... ' +
            paramreg.steps[str(pStep)].metric, verbose)
        sct.printv(
            '.. Number of iterations..... ' + paramreg.steps[str(pStep)].iter,
            verbose)
        sct.printv(
            '.. Shrink factor............ ' +
            paramreg.steps[str(pStep)].shrink, verbose)
        sct.printv(
            '.. Smoothing factor......... ' +
            paramreg.steps[str(pStep)].smooth, verbose)
        sct.printv(
            '.. Gradient step............ ' +
            paramreg.steps[str(pStep)].gradStep, verbose)
        sct.printv(
            '.. Degree of polynomial..... ' + paramreg.steps[str(pStep)].poly,
            verbose)

    path_data, file_data, ext_data = sct.extract_fname(fname_data)

    sct.printv('\nCheck input labels...')
    # check if label image contains coherent labels
    image_label = Image(fname_landmarks)
    # -> all labels must be different
    labels = image_label.getNonZeroCoordinates(sorting='value')
    hasDifferentLabels = True
    for lab in labels:
        for otherlabel in labels:
            if lab != otherlabel and lab.hasEqualValue(otherlabel):
                hasDifferentLabels = False
                break
    if not hasDifferentLabels:
        sct.printv(
            'ERROR: Wrong landmarks input. All labels must be different.',
            verbose, 'error')
    # all labels must be available in tempalte
    image_label_template = Image(fname_template_label)
    labels_template = image_label_template.getNonZeroCoordinates(
        sorting='value')
    if labels[-1].value > labels_template[-1].value:
        sct.printv(
            'ERROR: Wrong landmarks input. Labels must have correspondance in tempalte space. \nLabel max '
            'provided: ' + str(labels[-1].value) +
            '\nLabel max from template: ' + str(labels_template[-1].value),
            verbose, 'error')

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

    # copy files to temporary folder
    sct.printv('\nCopy files...', verbose)
    sct.run('isct_c3d ' + fname_data + ' -o ' + path_tmp + '/data.nii')
    sct.run('isct_c3d ' + fname_landmarks + ' -o ' + path_tmp +
            '/landmarks.nii.gz')
    sct.run('isct_c3d ' + fname_seg + ' -o ' + path_tmp +
            '/segmentation.nii.gz')
    sct.run('isct_c3d ' + fname_template + ' -o ' + path_tmp + '/template.nii')
    sct.run('isct_c3d ' + fname_template_label + ' -o ' + path_tmp +
            '/template_labels.nii.gz')
    sct.run('isct_c3d ' + fname_template_seg + ' -o ' + path_tmp +
            '/template_seg.nii.gz')

    # go to tmp folder
    os.chdir(path_tmp)

    # resample data to 1mm isotropic
    sct.printv('\nResample data to 1mm isotropic...', verbose)
    sct.run(
        'isct_c3d data.nii -resample-mm 1.0x1.0x1.0mm -interpolation Linear -o datar.nii'
    )
    sct.run(
        'isct_c3d segmentation.nii.gz -resample-mm 1.0x1.0x1.0mm -interpolation NearestNeighbor -o segmentationr.nii.gz'
    )
    # N.B. resampling of labels is more complicated, because they are single-point labels, therefore resampling with neighrest neighbour can make them disappear. Therefore a more clever approach is required.
    resample_labels('landmarks.nii.gz', 'datar.nii', 'landmarksr.nii.gz')
    # # TODO
    # sct.run('sct_label_utils -i datar.nii -t create -x 124,186,19,2:129,98,23,8 -o landmarksr.nii.gz')

    # Change orientation of input images to RPI
    sct.printv('\nChange orientation of input images to RPI...', verbose)
    set_orientation('datar.nii', 'RPI', 'data_rpi.nii')
    set_orientation('landmarksr.nii.gz', 'RPI', 'landmarks_rpi.nii.gz')
    set_orientation('segmentationr.nii.gz', 'RPI', 'segmentation_rpi.nii.gz')

    # # Change orientation of input images to RPI
    # sct.printv('\nChange orientation of input images to RPI...', verbose)
    # set_orientation('data.nii', 'RPI', 'data_rpi.nii')
    # set_orientation('landmarks.nii.gz', 'RPI', 'landmarks_rpi.nii.gz')
    # set_orientation('segmentation.nii.gz', 'RPI', 'segmentation_rpi.nii.gz')

    # get landmarks in native space
    # crop segmentation
    # output: segmentation_rpi_crop.nii.gz
    sct.run(
        'sct_crop_image -i segmentation_rpi.nii.gz -o segmentation_rpi_crop.nii.gz -dim 2 -bzmax'
    )

    # straighten segmentation
    sct.printv('\nStraighten the spinal cord using centerline/segmentation...',
               verbose)
    sct.run(
        'sct_straighten_spinalcord -i segmentation_rpi_crop.nii.gz -c segmentation_rpi_crop.nii.gz -r 0 -v '
        + str(verbose), verbose)
    # re-define warping field using non-cropped space (to avoid issue #367)
    sct.run(
        'sct_concat_transfo -w warp_straight2curve.nii.gz -d data_rpi.nii -o warp_straight2curve.nii.gz'
    )

    # Label preparation:
    # --------------------------------------------------------------------------------
    # Remove unused label on template. Keep only label present in the input label image
    sct.printv(
        '\nRemove unused label on template. Keep only label present in the input label image...',
        verbose)
    sct.run(
        'sct_label_utils -t remove -i template_labels.nii.gz -o template_label.nii.gz -r landmarks_rpi.nii.gz'
    )

    # Make sure landmarks are INT
    sct.printv('\nConvert landmarks to INT...', verbose)
    sct.run(
        'isct_c3d template_label.nii.gz -type int -o template_label.nii.gz',
        verbose)

    # Create a cross for the template labels - 5 mm
    sct.printv('\nCreate a 5 mm cross for the template labels...', verbose)
    sct.run(
        'sct_label_utils -t cross -i template_label.nii.gz -o template_label_cross.nii.gz -c 5'
    )

    # Create a cross for the input labels and dilate for straightening preparation - 5 mm
    sct.printv(
        '\nCreate a 5mm cross for the input labels and dilate for straightening preparation...',
        verbose)
    sct.run(
        'sct_label_utils -t cross -i landmarks_rpi.nii.gz -o landmarks_rpi_cross3x3.nii.gz -c 5 -d'
    )

    # Apply straightening to labels
    sct.printv('\nApply straightening to labels...', verbose)
    sct.run(
        'sct_apply_transfo -i landmarks_rpi_cross3x3.nii.gz -o landmarks_rpi_cross3x3_straight.nii.gz -d segmentation_rpi_crop_straight.nii.gz -w warp_curve2straight.nii.gz -x nn'
    )

    # Convert landmarks from FLOAT32 to INT
    sct.printv('\nConvert landmarks from FLOAT32 to INT...', verbose)
    sct.run(
        'isct_c3d landmarks_rpi_cross3x3_straight.nii.gz -type int -o landmarks_rpi_cross3x3_straight.nii.gz'
    )

    # Remove labels that do not correspond with each others.
    sct.printv('\nRemove labels that do not correspond with each others.',
               verbose)
    sct.run(
        'sct_label_utils -t remove-symm -i landmarks_rpi_cross3x3_straight.nii.gz -o landmarks_rpi_cross3x3_straight.nii.gz,template_label_cross.nii.gz -r template_label_cross.nii.gz'
    )

    # Estimate affine transfo: straight --> template (landmark-based)'
    sct.printv(
        '\nEstimate affine transfo: straight anat --> template (landmark-based)...',
        verbose)
    # converting landmarks straight and curved to physical coordinates
    image_straight = Image('landmarks_rpi_cross3x3_straight.nii.gz')
    landmark_straight = image_straight.getNonZeroCoordinates(sorting='value')
    image_template = Image('template_label_cross.nii.gz')
    landmark_template = image_template.getNonZeroCoordinates(sorting='value')
    # Reorganize landmarks
    points_fixed, points_moving = [], []
    landmark_straight_mean = []
    for coord in landmark_straight:
        if coord.value not in [c.value for c in landmark_straight_mean]:
            temp_landmark = coord
            temp_number = 1
            for other_coord in landmark_straight:
                if coord.hasEqualValue(other_coord) and coord != other_coord:
                    temp_landmark += other_coord
                    temp_number += 1
            landmark_straight_mean.append(temp_landmark / temp_number)

    for coord in landmark_straight_mean:
        point_straight = image_straight.transfo_pix2phys(
            [[coord.x, coord.y, coord.z]])
        points_moving.append(
            [point_straight[0][0], point_straight[0][1], point_straight[0][2]])
    for coord in landmark_template:
        point_template = image_template.transfo_pix2phys(
            [[coord.x, coord.y, coord.z]])
        points_fixed.append(
            [point_template[0][0], point_template[0][1], point_template[0][2]])

    # Register curved landmarks on straight landmarks based on python implementation
    sct.printv(
        '\nComputing rigid transformation (algo=translation-scaling-z) ...',
        verbose)
    import msct_register_landmarks
    (rotation_matrix, translation_array, points_moving_reg, points_moving_barycenter) = \
        msct_register_landmarks.getRigidTransformFromLandmarks(
            points_fixed, points_moving, constraints='translation-scaling-z', show=False)

    # writing rigid transformation file
    text_file = open("straight2templateAffine.txt", "w")
    text_file.write("#Insight Transform File V1.0\n")
    text_file.write("#Transform 0\n")
    text_file.write(
        "Transform: FixedCenterOfRotationAffineTransform_double_3_3\n")
    text_file.write(
        "Parameters: %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f\n"
        % (1.0 / rotation_matrix[0, 0], rotation_matrix[0, 1],
           rotation_matrix[0, 2], rotation_matrix[1, 0],
           1.0 / rotation_matrix[1, 1], rotation_matrix[1, 2],
           rotation_matrix[2, 0], rotation_matrix[2, 1],
           1.0 / rotation_matrix[2, 2], translation_array[0, 0],
           translation_array[0, 1], -translation_array[0, 2]))
    text_file.write("FixedParameters: %.9f %.9f %.9f\n" %
                    (points_moving_barycenter[0], points_moving_barycenter[1],
                     points_moving_barycenter[2]))
    text_file.close()

    # Apply affine transformation: straight --> template
    sct.printv('\nApply affine transformation: straight --> template...',
               verbose)
    sct.run(
        'sct_concat_transfo -w warp_curve2straight.nii.gz,straight2templateAffine.txt -d template.nii -o warp_curve2straightAffine.nii.gz'
    )
    sct.run(
        'sct_apply_transfo -i data_rpi.nii -o data_rpi_straight2templateAffine.nii -d template.nii -w warp_curve2straightAffine.nii.gz'
    )
    sct.run(
        'sct_apply_transfo -i segmentation_rpi.nii.gz -o segmentation_rpi_straight2templateAffine.nii.gz -d template.nii -w warp_curve2straightAffine.nii.gz -x linear'
    )

    # threshold to 0.5
    nii = Image('segmentation_rpi_straight2templateAffine.nii.gz')
    data = nii.data
    data[data < 0.5] = 0
    nii.data = data
    nii.setFileName('segmentation_rpi_straight2templateAffine_th.nii.gz')
    nii.save()
    # find min-max of anat2template (for subsequent cropping)
    zmin_template, zmax_template = find_zmin_zmax(
        'segmentation_rpi_straight2templateAffine_th.nii.gz')

    # crop template in z-direction (for faster processing)
    sct.printv('\nCrop data in template space (for faster processing)...',
               verbose)
    sct.run(
        'sct_crop_image -i template.nii -o template_crop.nii -dim 2 -start ' +
        str(zmin_template) + ' -end ' + str(zmax_template))
    sct.run(
        'sct_crop_image -i template_seg.nii.gz -o template_seg_crop.nii.gz -dim 2 -start '
        + str(zmin_template) + ' -end ' + str(zmax_template))
    sct.run(
        'sct_crop_image -i data_rpi_straight2templateAffine.nii -o data_rpi_straight2templateAffine_crop.nii -dim 2 -start '
        + str(zmin_template) + ' -end ' + str(zmax_template))
    sct.run(
        'sct_crop_image -i segmentation_rpi_straight2templateAffine.nii.gz -o segmentation_rpi_straight2templateAffine_crop.nii.gz -dim 2 -start '
        + str(zmin_template) + ' -end ' + str(zmax_template))
    # sub-sample in z-direction
    sct.printv('\nSub-sample in z-direction (for faster processing)...',
               verbose)
    sct.run(
        'sct_resample -i template_crop.nii -o template_crop_r.nii -f 1x1x' +
        zsubsample, verbose)
    sct.run(
        'sct_resample -i template_seg_crop.nii.gz -o template_seg_crop_r.nii.gz -f 1x1x'
        + zsubsample, verbose)
    sct.run(
        'sct_resample -i data_rpi_straight2templateAffine_crop.nii -o data_rpi_straight2templateAffine_crop_r.nii -f 1x1x'
        + zsubsample, verbose)
    sct.run(
        'sct_resample -i segmentation_rpi_straight2templateAffine_crop.nii.gz -o segmentation_rpi_straight2templateAffine_crop_r.nii.gz -f 1x1x'
        + zsubsample, verbose)

    # Registration straight spinal cord to template
    sct.printv('\nRegister straight spinal cord to template...', verbose)

    # loop across registration steps
    warp_forward = []
    warp_inverse = []
    for i_step in range(1, len(paramreg.steps) + 1):
        sct.printv(
            '\nEstimate transformation for step #' + str(i_step) + '...',
            verbose)
        # identify which is the src and dest
        if paramreg.steps[str(i_step)].type == 'im':
            src = 'data_rpi_straight2templateAffine_crop_r.nii'
            dest = 'template_crop_r.nii'
            interp_step = 'linear'
        elif paramreg.steps[str(i_step)].type == 'seg':
            src = 'segmentation_rpi_straight2templateAffine_crop_r.nii.gz'
            dest = 'template_seg_crop_r.nii.gz'
            interp_step = 'nn'
        else:
            sct.printv('ERROR: Wrong image type.', 1, 'error')
        # if step>1, apply warp_forward_concat to the src image to be used
        if i_step > 1:
            # sct.run('sct_apply_transfo -i '+src+' -d '+dest+' -w '+','.join(warp_forward)+' -o '+sct.add_suffix(src, '_reg')+' -x '+interp_step, verbose)
            sct.run(
                'sct_apply_transfo -i ' + src + ' -d ' + dest + ' -w ' +
                ','.join(warp_forward) + ' -o ' + sct.add_suffix(src, '_reg') +
                ' -x ' + interp_step, verbose)
            src = sct.add_suffix(src, '_reg')
        # register src --> dest
        warp_forward_out, warp_inverse_out = register(src, dest, paramreg,
                                                      param, str(i_step))
        warp_forward.append(warp_forward_out)
        warp_inverse.append(warp_inverse_out)

    # Concatenate transformations:
    sct.printv('\nConcatenate transformations: anat --> template...', verbose)
    sct.run(
        'sct_concat_transfo -w warp_curve2straightAffine.nii.gz,' +
        ','.join(warp_forward) +
        ' -d template.nii -o warp_anat2template.nii.gz', verbose)
    # sct.run('sct_concat_transfo -w warp_curve2straight.nii.gz,straight2templateAffine.txt,'+','.join(warp_forward)+' -d template.nii -o warp_anat2template.nii.gz', verbose)
    warp_inverse.reverse()
    sct.run(
        'sct_concat_transfo -w ' + ','.join(warp_inverse) +
        ',-straight2templateAffine.txt,warp_straight2curve.nii.gz -d data.nii -o warp_template2anat.nii.gz',
        verbose)

    # Apply warping fields to anat and template
    if output_type == 1:
        sct.run(
            'sct_apply_transfo -i template.nii -o template2anat.nii.gz -d data.nii -w warp_template2anat.nii.gz -c 1',
            verbose)
        sct.run(
            'sct_apply_transfo -i data.nii -o anat2template.nii.gz -d template.nii -w warp_anat2template.nii.gz -c 1',
            verbose)

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

    # Generate output files
    sct.printv('\nGenerate output files...', verbose)
    sct.generate_output_file(path_tmp + '/warp_template2anat.nii.gz',
                             'warp_template2anat.nii.gz', verbose)
    sct.generate_output_file(path_tmp + '/warp_anat2template.nii.gz',
                             'warp_anat2template.nii.gz', verbose)
    if output_type == 1:
        sct.generate_output_file(path_tmp + '/template2anat.nii.gz',
                                 'template2anat' + ext_data, verbose)
        sct.generate_output_file(path_tmp + '/anat2template.nii.gz',
                                 'anat2template' + ext_data, verbose)

    # Delete temporary files
    if remove_temp_files:
        sct.printv('\nDelete temporary files...', verbose)
        sct.run('rm -rf ' + path_tmp)

    # display elapsed time
    elapsed_time = time.time() - start_time
    sct.printv(
        '\nFinished! Elapsed time: ' + str(int(round(elapsed_time))) + 's',
        verbose)

    # to view results
    sct.printv('\nTo view results, type:', verbose)
    sct.printv('fslview ' + fname_data + ' template2anat -b 0,4000 &', verbose,
               'info')
    sct.printv('fslview ' + fname_template + ' -b 0,5000 anat2template &\n',
               verbose, 'info')
    def compute_texture(self):

        offset = int(self.param_glcm.distance)
        printv('\nCompute texture metrics...', self.param.verbose, 'normal')

        # open image and re-orient it to RPI if needed
        im_tmp = Image(self.param.fname_im)
        if self.orientation_im != self.orientation_extraction:
            im_tmp = set_orientation(im_tmp, self.orientation_extraction)

        dct_metric = {}
        for m in self.metric_lst:
            im_2save = im_tmp.copy()
            im_2save.changeType(type='float64')
            im_2save.data *= 0
            dct_metric[m] = im_2save
            # dct_metric[m] = Image(self.fname_metric_lst[m])

        timer = Timer(number_of_iteration=len(self.dct_im_seg['im']))
        timer.start()

        for im_z, seg_z, zz in zip(self.dct_im_seg['im'],
                                   self.dct_im_seg['seg'],
                                   range(len(self.dct_im_seg['im']))):
            for xx in range(im_z.shape[0]):
                for yy in range(im_z.shape[1]):
                    if not seg_z[xx, yy]:
                        continue
                    if xx < offset or yy < offset:
                        continue
                    if xx > (im_z.shape[0] - offset -
                             1) or yy > (im_z.shape[1] - offset - 1):
                        continue  # to check if the whole glcm_window is in the axial_slice
                    if False in np.unique(seg_z[xx - offset:xx + offset + 1,
                                                yy - offset:yy + offset + 1]):
                        continue  # to check if the whole glcm_window is in the mask of the axial_slice

                    glcm_window = im_z[xx - offset:xx + offset + 1,
                                       yy - offset:yy + offset + 1]
                    glcm_window = glcm_window.astype(np.uint8)

                    dct_glcm = {}
                    for a in self.param_glcm.angle.split(
                            ','
                    ):  # compute the GLCM for self.param_glcm.distance and for each self.param_glcm.angle
                        dct_glcm[a] = greycomatrix(
                            glcm_window, [self.param_glcm.distance],
                            [radians(int(a))],
                            symmetric=self.param_glcm.symmetric,
                            normed=self.param_glcm.normed)

                    for m in self.metric_lst:  # compute the GLCM property (m.split('_')[0]) of the voxel xx,yy,zz
                        dct_metric[m].data[xx, yy, zz] = greycoprops(
                            dct_glcm[m.split('_')[2]],
                            m.split('_')[0])[0][0]

            timer.add_iteration()

        timer.stop()

        for m in self.metric_lst:
            fname_out = add_suffix(
                ''.join(extract_fname(self.param.fname_im)[1:]), '_' + m)
            dct_metric[m].setFileName(fname_out)
            dct_metric[m].save()
            self.fname_metric_lst[m] = fname_out
import sct_utils as sct
from msct_image import Image

# parameters
fname_wm = '/Users/julien/Dropbox/Public/sct/PAM50/template/PAM50_wm.nii.gz'
fname_gm = '/Users/julien/Dropbox/Public/sct/PAM50/template/PAM50_gm.nii.gz'
fname_cord = '/Users/julien/data/sct_dev/PAM50/template/PAM50_cord.nii.gz'

# create temporary folder
path_tmp = sct.tmp_create()

# go to temp folder
os.chdir(path_tmp)

# open volumes
im_wm = Image(fname_wm)
data_wm = im_wm.data
im_gm = Image(fname_gm)
data_gm = im_gm.data
im_cord = Image(fname_cord)
data_cord = im_cord.data
dim = im_cord.dim

# sum wm/gm
data_wmgm = data_wm + data_gm

# get min/max z slices from wm/gm
zsum = np.sum(np.sum(data_wmgm, 0), 0)
zmin_wm = np.min(np.nonzero(zsum))
zmax_wm = np.max(np.nonzero(zsum))
Exemplo n.º 14
0
def main():

    # initialization
    fname_mask = ''

    # Get parser info
    parser = get_parser()
    arguments = parser.parse(sys.argv[1:])
    fname_data = arguments['-i']
    fname_mask = arguments['-m']
    vert_label_fname = arguments["-vertfile"]
    vert_levels = arguments["-vert"]
    slices_of_interest = arguments["-z"]
    index_vol = arguments['-vol']
    method = arguments["-method"]
    verbose = int(arguments['-v'])

    # Check if data are in RPI
    input_im = Image(fname_data)
    input_orient = get_orientation(input_im)

    # If orientation is not RPI, change to RPI
    if input_orient != 'RPI':
        sct.printv(
            '\nCreate temporary folder to change the orientation of the NIFTI files into RPI...',
            verbose)
        path_tmp = sct.tmp_create()
        # change orientation and load data
        sct.printv('\nChange input image orientation and load it...', verbose)
        input_im_rpi = orientation(input_im,
                                   ori='RPI',
                                   set=True,
                                   fname_out=path_tmp + 'input_RPI.nii')
        input_data = input_im_rpi.data
        # Do the same for the mask
        sct.printv('\nChange mask orientation and load it...', verbose)
        mask_im_rpi = orientation(Image(fname_mask),
                                  ori='RPI',
                                  set=True,
                                  fname_out=path_tmp + 'mask_RPI.nii')
        mask_data = mask_im_rpi.data
        # Do the same for vertebral labeling if present
        if vert_levels != 'None':
            sct.printv(
                '\nChange vertebral labeling file orientation and load it...',
                verbose)
            vert_label_im_rpi = orientation(Image(vert_label_fname),
                                            ori='RPI',
                                            set=True,
                                            fname_out=path_tmp +
                                            'vert_labeling_RPI.nii')
            vert_labeling_data = vert_label_im_rpi.data
        # Remove the temporary folder used to change the NIFTI files orientation into RPI
        sct.printv('\nRemove the temporary folder...', verbose)
        shutil.rmtree(path_tmp, True)
    else:
        # Load data
        sct.printv('\nLoad data...', verbose)
        input_data = input_im.data
        mask_data = Image(fname_mask).data
        if vert_levels != 'None':
            vert_labeling_data = Image(vert_label_fname).data
    sct.printv('\tDone.', verbose)

    # Get slices corresponding to vertebral levels
    if vert_levels != 'None':
        from sct_extract_metric import get_slices_matching_with_vertebral_levels
        slices_of_interest, actual_vert_levels, warning_vert_levels = get_slices_matching_with_vertebral_levels(
            mask_data, vert_levels, vert_labeling_data, verbose)

    # Remove slices that were not selected
    if slices_of_interest == 'None':
        slices_of_interest = '0:' + str(mask_data.shape[2] - 1)
    slices_boundary = slices_of_interest.split(':')
    slices_of_interest_list = range(int(slices_boundary[0]),
                                    int(slices_boundary[1]) + 1)
    # Crop
    input_data = input_data[:, :, slices_of_interest_list, :]
    mask_data = mask_data[:, :, slices_of_interest_list]

    # if user selected all slices (-vol -1), then assign index_vol
    if index_vol[0] == -1:
        index_vol = range(0, input_data.shape[3], 1)

    # Get signal and noise
    indexes_roi = np.where(mask_data == 1)
    if method == 'mult':
        # get voxels in ROI to obtain a (x*y*z)*t 2D matrix
        input_data_in_roi = input_data[indexes_roi]
        # compute signal and STD across by averaging across time
        signal = np.mean(input_data_in_roi[:, index_vol])
        std_input_temporal = np.std(input_data_in_roi[:, index_vol], 1)
        noise = np.mean(std_input_temporal)
    elif method == 'diff':
        # if user did not select two volumes, then exit with error
        if not len(index_vol) == 2:
            sct.printv(
                'ERROR: ' + str(len(index_vol)) +
                ' volumes were specified. Method "diff" should be used with exactly two volumes.',
                1, 'error')
        data_1 = input_data[:, :, :, index_vol[0]]
        data_2 = input_data[:, :, :, index_vol[1]]
        # compute voxel-average of voxelwise sum
        signal = np.mean(np.add(data_1[indexes_roi], data_2[indexes_roi]))
        # compute voxel-STD of voxelwise substraction, multiplied by sqrt(2) as described in equation 7 of Dietrich et al.
        noise = np.std(np.subtract(data_1[indexes_roi],
                                   data_2[indexes_roi])) * np.sqrt(2)

    # compute SNR
    SNR = signal / noise

    # Display result
    sct.printv('\nSNR_' + method + ' = ' + str(SNR) + '\n', type='info')
Exemplo n.º 15
0
def register_landmarks(fname_src,
                       fname_dest,
                       dof,
                       fname_affine='affine.txt',
                       verbose=1,
                       path_qc=None):
    """
    Register two NIFTI volumes containing landmarks
    :param fname_src: fname of source landmarks
    :param fname_dest: fname of destination landmarks
    :param dof: degree of freedom. Separate with "_". Example: Tx_Ty_Tz_Rx_Ry_Sz
    :param fname_affine: output affine transformation
    :param verbose: 0, 1, 2
    :return:
    """
    from msct_image import Image
    # open src label
    im_src = Image(fname_src)
    # coord_src = im_src.getNonZeroCoordinates(sorting='value')  # landmarks are sorted by value
    coord_src = im_src.getCoordinatesAveragedByValue(
    )  # landmarks are sorted by value
    # open dest labels
    im_dest = Image(fname_dest)
    # coord_dest = im_dest.getNonZeroCoordinates(sorting='value')
    coord_dest = im_dest.getCoordinatesAveragedByValue()
    # Reorganize landmarks

    points_src, points_dest = [], []
    for coord in coord_src:
        point_src = im_src.transfo_pix2phys([[coord.x, coord.y, coord.z]])
        # convert NIFTI to ITK world coordinate
        # points_src.append([point_src[0][0], point_src[0][1], point_src[0][2]])
        points_src.append(
            [-point_src[0][0], -point_src[0][1], point_src[0][2]])
    for coord in coord_dest:
        point_dest = im_dest.transfo_pix2phys([[coord.x, coord.y, coord.z]])
        # convert NIFTI to ITK world coordinate
        # points_dest.append([point_dest[0][0], point_dest[0][1], point_dest[0][2]])
        points_dest.append(
            [-point_dest[0][0], -point_dest[0][1], point_dest[0][2]])

    # display
    sct.printv('Labels src: ' + str(points_src), verbose)
    sct.printv('Labels dest: ' + str(points_dest), verbose)
    sct.printv('Degrees of freedom (dof): ' + dof, verbose)

    if len(coord_src) != len(coord_dest):
        raise Exception(
            'Error: number of source and destination landmarks are not the same, so landmarks cannot be paired.'
        )

    # estimate transformation
    # N.B. points_src and points_dest are inverted below, because ITK uses inverted transformation matrices, i.e., src->dest is defined in dest instead of src.
    # (rotation_matrix, translation_array, points_moving_reg, points_moving_barycenter) = getRigidTransformFromLandmarks(points_dest, points_src, constraints=dof, verbose=verbose, path_qc=path_qc)
    (rotation_matrix, translation_array, points_moving_reg,
     points_moving_barycenter) = getRigidTransformFromLandmarks(
         points_src,
         points_dest,
         constraints=dof,
         verbose=verbose,
         path_qc=path_qc)
    # writing rigid transformation file
    # N.B. x and y dimensions have a negative sign to ensure compatibility between Python and ITK transfo
    text_file = open(fname_affine, 'w')
    text_file.write("#Insight Transform File V1.0\n")
    text_file.write("#Transform 0\n")
    text_file.write("Transform: AffineTransform_double_3_3\n")
    text_file.write(
        "Parameters: %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f %.9f\n"
        % (rotation_matrix[0, 0], rotation_matrix[0, 1], rotation_matrix[0, 2],
           rotation_matrix[1, 0], rotation_matrix[1, 1], rotation_matrix[1, 2],
           rotation_matrix[2, 0], rotation_matrix[2, 1], rotation_matrix[2, 2],
           translation_array[0, 0], translation_array[0, 1],
           translation_array[0, 2]))
    text_file.write("FixedParameters: %.9f %.9f %.9f\n" %
                    (points_moving_barycenter[0], points_moving_barycenter[1],
                     points_moving_barycenter[2]))
    text_file.close()
Exemplo n.º 16
0
def resample():

    fsloutput = 'export FSLOUTPUTTYPE=NIFTI; '  # for faster processing, all outputs are in NIFTI
    ext = '.nii'

    # display usage if a mandatory argument is not provided
    if param.fname_data == '' or param.factor == '':
        sct.printv('\nERROR: All mandatory arguments are not provided. See usage (add -h).\n', 1, 'error')

    # check existence of input files
    sct.printv('\nCheck existence of input files...', param.verbose)
    sct.check_file_exist(param.fname_data, param.verbose)

    # extract resampling factor
    sct.printv('\nParse resampling factor...', param.verbose)
    factor_split = param.factor.split('x')
    factor = [float(factor_split[i]) for i in range(len(factor_split))]
    # check if it has three values
    if not len(factor) == 3:
        sct.printv('\nERROR: factor should have three dimensions. E.g., 2x2x1.\n', 1, 'error')
    else:
        fx, fy, fz = [float(factor_split[i]) for i in range(len(factor_split))]

    # check interpolation
    if param.interpolation not in ['NearestNeighbor','Linear','Cubic','Sinc','Gaussian']:
        sct.printv('\nERROR: interpolation should be one of those:NearestNeighbor|Linear|Cubic|Sinc|Gaussian.\n', 1, 'error')

    # display input parameters
    sct.printv('\nInput parameters:', param.verbose)
    sct.printv('  data ..................'+param.fname_data, param.verbose)
    sct.printv('  resampling factor .....'+param.factor, param.verbose)

    # Extract path/file/extension
    path_data, file_data, ext_data = sct.extract_fname(param.fname_data)
    path_out, file_out, ext_out = '', file_data, ext_data

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

    # Copying input data to tmp folder and convert to nii
    # NB: cannot use c3d here because c3d cannot convert 4D data.
    sct.printv('\nCopying input data to tmp folder and convert to nii...', param.verbose)
    sct.run('cp '+param.fname_data+' '+path_tmp+'data'+ext_data, param.verbose)

    # go to tmp folder
    os.chdir(path_tmp)

    # convert to nii format
    convert('data'+ext_data, 'data.nii')

    # Get dimensions of data
    sct.printv('\nGet dimensions of data...', param.verbose)
    nx, ny, nz, nt, px, py, pz, pt = Image('data.nii').dim
    sct.printv('  ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), param.verbose)
    dim = 4  # by default, will be adjusted later
    if nt == 1:
        dim = 3
    if nz == 1:
        dim = 2
        sct.run('ERROR (sct_resample): Dimension of input data is different from 3 or 4. Exit program', param.verbose, 'error')

    # Calculate new dimensions
    sct.printv('\nCalculate new dimensions...', param.verbose)
    nx_new = int(round(nx*fx))
    ny_new = int(round(ny*fy))
    nz_new = int(round(nz*fz))
    sct.printv('  ' + str(nx_new) + ' x ' + str(ny_new) + ' x ' + str(nz_new)+ ' x ' + str(nt), param.verbose)

    # if dim=4, split data
    if dim == 4:
        # Split into T dimension
        sct.printv('\nSplit along T dimension...', param.verbose)
        from sct_split_data import split_data
        split_data('data.nii', 3, '_T')
    elif dim == 3:
        # rename file to have compatible code with 4d
        status, output = sct.run('cp data.nii data_T0000.nii', param.verbose)

    for it in range(nt):
        # identify current volume
        file_data_splitT = 'data_T'+str(it).zfill(4)
        file_data_splitT_resample = file_data_splitT+'r'

        # resample volume
        sct.printv(('\nResample volume '+str((it+1))+'/'+str(nt)+':'), param.verbose)
        sct.run('isct_c3d '+file_data_splitT+ext+' -interpolation '+param.interpolation+' -resample '+str(nx_new)+'x'+str(ny_new)+'x'+str(nz_new)+'vox -o '+file_data_splitT_resample+ext)

        # pad data (for ANTs)
        # # TODO: check if need to pad also for the estimate_and_apply
        # if program == 'ants' and todo == 'estimate' and slicewise == 0:
        #     sct.run('isct_c3d '+file_data_splitT_num[it]+' -pad 0x0x3vox 0x0x3vox 0 -o '+file_data_splitT_num[it]+'_pad.nii')
        #     file_data_splitT_num[it] = file_data_splitT_num[it]+'_pad'

    # merge data back along T
    file_data_resample = file_data+param.file_suffix
    sct.printv('\nMerge data back along T...', param.verbose)
    from sct_concat_data import concat_data
    import glob
    concat_data(glob.glob('data_T*r.nii'), file_data_resample, dim=3)

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

    # Generate output files
    sct.printv('\nGenerate output files...', param.verbose)
    if not param.fname_out:
        param.fname_out = path_out+file_out+param.file_suffix+ext_out
    sct.generate_output_file(path_tmp+file_data_resample+ext, param.fname_out)

    # Remove temporary files
    if param.remove_tmp_files == 1:
        print('\nRemove temporary files...')
        sct.run('rm -rf '+path_tmp, param.verbose)

    # to view results
    sct.printv('\nDone! To view results, type:', param.verbose)
    sct.printv('fslview '+param.fname_out+' &', param.verbose, 'info')
    print
Exemplo n.º 17
0
    # path_tmp = tmp_create()
    # tmp_copy_nifti(input_file, path_tmp, 'raw.nii')
    # run('cp '+warping_fields_filename[0]+' '+path_tmp)
    # chdir(path_tmp)
    run('mkdir images')
    run('mkdir niftis')
    while True:
        try:
            warping_fields[0].num_of_frames = number_of_frames
            image_output_iter, iteration = warping_fields[0].next()
            image_output_iter.save()
            filename_warp = image_output_iter.path + image_output_iter.file_name + image_output_iter.ext
            filename_output = "niftis/tmp.warped_image_" + str(
                iteration - 1) + image_output_iter.ext
            run("sct_apply_transfo -i " + input_file + " -d " +
                reference_image + " -w " + filename_warp + " -o " +
                filename_output)
            result = Image(filename_output)
            result.change_orientation()

            toimage(result.data[int(result.data.shape[0] / 2)].squeeze(),
                    cmin=0.0).save('images/' +
                                   extract_fname(filename_output)[1] + '.jpg')
            filenames_output.append(filename_output)
        except ValueError:
            printv('\nError during warping field generation...', 1, 'error')
        except StopIteration:
            printv('\nFinished iterations.')
            break
Exemplo n.º 18
0
    def crop_with_gui(self):
        import matplotlib.pyplot as plt
        import matplotlib.image as mpimg
        # Initialization
        fname_data = self.input_filename
        suffix_out = '_crop'
        remove_temp_files = self.rm_tmp_files
        verbose = self.verbose

        # Check file existence
        sct.printv('\nCheck file existence...', verbose)
        sct.check_file_exist(fname_data, verbose)

        # Get dimensions of data
        sct.printv('\nGet dimensions of data...', verbose)
        nx, ny, nz, nt, px, py, pz, pt = Image(fname_data).dim
        sct.printv('.. ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz),
                   verbose)
        # check if 4D data
        if not nt == 1:
            sct.printv(
                '\nERROR in ' + os.path.basename(__file__) +
                ': Data should be 3D.\n', 1, 'error')
            sys.exit(2)

        # sct.printv(arguments)
        sct.printv('\nCheck parameters:')
        sct.printv('  data ................... ' + fname_data)

        # Extract path/file/extension
        path_data, file_data, ext_data = sct.extract_fname(fname_data)
        path_out, file_out, ext_out = '', file_data + suffix_out, ext_data

        path_tmp = sct.tmp_create() + "/"

        # copy files into tmp folder
        from sct_convert import convert
        sct.printv('\nCopying input data to tmp folder and convert to nii...',
                   verbose)
        convert(fname_data, os.path.join(path_tmp, "data.nii"))

        # go to tmp folder
        curdir = os.getcwd()
        os.chdir(path_tmp)

        # change orientation
        sct.printv('\nChange orientation to RPI...', verbose)
        sct.run([
            'sct_image', '-i', 'data.nii', '-setorient', 'RPI', '-o',
            'data_rpi.nii'
        ])

        # get image of medial slab
        sct.printv('\nGet image of medial slab...', verbose)
        image_array = nibabel.load('data_rpi.nii').get_data()
        nx, ny, nz = image_array.shape
        scipy.misc.imsave('image.jpg', image_array[math.floor(nx / 2), :, :])

        # Display the image
        sct.printv('\nDisplay image and get cropping region...', verbose)
        fig = plt.figure()
        # fig = plt.gcf()
        # ax = plt.gca()
        ax = fig.add_subplot(111)
        img = mpimg.imread("image.jpg")
        implot = ax.imshow(img.T)
        implot.set_cmap('gray')
        plt.gca().invert_yaxis()
        # mouse callback
        ax.set_title(
            'Left click on the top and bottom of your cropping field.\n Right click to remove last point.\n Close window when your done.'
        )
        line, = ax.plot([], [], 'ro')  # empty line
        cropping_coordinates = LineBuilder(line)
        plt.show()
        # disconnect callback
        # fig.canvas.mpl_disconnect(line)

        # check if user clicked two times
        if len(cropping_coordinates.xs) != 2:
            sct.printv(
                '\nERROR: You have to select two points. Exit program.\n', 1,
                'error')
            sys.exit(2)

        # convert coordinates to integer
        zcrop = [int(i) for i in cropping_coordinates.ys]

        # sort coordinates
        zcrop.sort()

        # crop image
        sct.printv('\nCrop image...', verbose)
        nii = Image('data_rpi.nii')
        data_crop = nii.data[:, :, zcrop[0]:zcrop[1]]
        nii.data = data_crop
        nii.setFileName('data_rpi_crop.nii')
        nii.save()

        # come back
        os.chdir(curdir)

        sct.printv('\nGenerate output files...', verbose)
        sct.generate_output_file(os.path.join(path_tmp, "data_rpi_crop.nii"),
                                 os.path.join(path_out, file_out + ext_out))

        # Remove temporary files
        if remove_temp_files == 1:
            sct.printv('\nRemove temporary files...')
            sct.rmtree(path_tmp)

        sct.display_viewer_syntax(
            files=[os.path.join(path_out, file_out + ext_out)])