Ejemplo n.º 1
0
    def __init__(self, fname_im, contrast, fname_seg, path_out, verbose):

        self.fname_im = fname_im
        self.contrast = contrast

        self.fname_seg = fname_seg

        self.path_out = path_out

        self.verbose = verbose

        self.tmp_dir = sct.tmp_create(
            verbose=self.verbose)  # path to tmp directory

        self.orientation_im = get_orientation(Image(
            self.fname_im))  # to re-orient the data at the end

        self.slice2D_im = sct.extract_fname(
            self.fname_im
        )[1] + '_midSag.nii'  # file used to do the detection, with only one slice
        self.dection_map_pmj = sct.extract_fname(
            self.fname_im)[1] + '_map_pmj'  # file resulting from the detection

        # path to the pmj detector
        path_sct = os.environ.get("SCT_DIR",
                                  os.path.dirname(os.path.dirname(__file__)))
        self.pmj_model = os.path.join(path_sct, 'data', 'pmj_models',
                                      '{}_model'.format(self.contrast))

        self.threshold = -0.75 if self.contrast == 't1' else 0.8  # detection map threshold, depends on the contrast

        self.fname_out = sct.extract_fname(self.fname_im)[1] + '_pmj.nii.gz'

        self.fname_qc = 'qc_pmj.png'
Ejemplo n.º 2
0
def check_if_rpi(fname):
    from sct_image import get_orientation
    if not get_orientation(fname, filename=True) == 'RPI':
        printv(
            '\nERROR: ' + fname +
            ' is not in RPI orientation. Use sct_image -setorient to reorient your data. Exit program.\n',
            1, 'error')
    def __init__(self, param=None, param_glcm=None):
        self.param = param if param is not None else Param()
        self.param_glcm = param_glcm if param_glcm is not None else ParamGLCM()

        # create tmp directory
        self.tmp_dir = tmp_create(verbose=self.param.verbose)  # path to tmp directory

        if self.param.dim == 'ax':
            self.orientation_extraction = 'RPI'
        elif self.param.dim == 'sag':
            self.orientation_extraction = 'IPR'
        else:
            self.orientation_extraction = 'IRP'

        # metric_lst=['property_distance_angle']
        self.metric_lst = []
        for m in list(itertools.product(self.param_glcm.feature.split(','), self.param_glcm.angle.split(','))):
            text_name = m[0] if m[0].upper() != 'asm'.upper() else m[0].upper()
            self.metric_lst.append(text_name + '_' + str(self.param_glcm.distance) + '_' + str(m[1]))

        # dct_im_seg{'im': list_of_axial_slice, 'seg': list_of_axial_masked_slice}
        self.dct_im_seg = {'im': None, 'seg': None}

        # to re-orient the data at the end if needed
        self.orientation_im = get_orientation(Image(self.param.fname_im))

        self.fname_metric_lst = {}
Ejemplo n.º 4
0
def resample_image(fname, suffix='_resampled.nii.gz', binary=False, npx=0.3, npy=0.3, thr=0.0, interpolation='spline'):
    """
    Resampling function: add a padding, resample, crop the padding
    :param fname: name of the image file to be resampled
    :param suffix: suffix added to the original fname after resampling
    :param binary: boolean, image is binary or not
    :param npx: new pixel size in the x direction
    :param npy: new pixel size in the y direction
    :param thr: if the image is binary, it will be thresholded at thr (default=0) after the resampling
    :param interpolation: type of interpolation used for the resampling
    :return: file name after resampling (or original fname if it was already in the correct resolution)
    """
    im_in = Image(fname)
    orientation = get_orientation(im_in)
    if orientation != 'RPI':
        im_in = set_orientation(im_in, 'RPI')
        im_in.save()
        fname = im_in.absolutepath
    nx, ny, nz, nt, px, py, pz, pt = im_in.dim

    if round(px, 2) != round(npx, 2) or round(py, 2) != round(npy, 2):
        name_resample = sct.extract_fname(fname)[1] + suffix
        if binary:
            interpolation = 'nn'

        if nz == 1:  # when data is 2d: we convert it to a 3d image in order to avoid nipy problem of conversion nifti-->nipy with 2d data
            sct.run(['sct_image', '-i', ','.join([fname, fname]), '-concat', 'z', '-o', fname])

        sct.run(['sct_resample', '-i', fname, '-mm', str(npx) + 'x' + str(npy) + 'x' + str(pz), '-o', name_resample, '-x', interpolation])

        if nz == 1:  # when input data was 2d: re-convert data 3d-->2d
            sct.run(['sct_image', '-i', name_resample, '-split', 'z'])
            im_split = Image(name_resample.split('.nii.gz')[0] + '_Z0000.nii.gz')
            im_split.setFileName(name_resample)
            im_split.save()

        if binary:
            sct.run(['sct_maths', '-i', name_resample, '-bin', str(thr), '-o', name_resample])

        if orientation != 'RPI':
            im_resample = Image(name_resample)
            im_resample = set_orientation(im_resample, orientation)
            im_resample.save()
            name_resample = im_resample.absolutepath
        return name_resample
    else:
        if orientation != 'RPI':
            im_in = set_orientation(im_in, orientation)
            im_in.save()
            fname = im_in.absolutepath
        sct.printv('Image resolution already ' + str(npx) + 'x' + str(npy) + 'xpz')
        return fname
    def orient2rpi(self):
        # save input image orientation
        self.orientation = get_orientation(Image(self.fname_mask))

        if not self.orientation == 'RPI':
            printv('\nOrient input image(s) to RPI orientation...', self.verbose, 'normal')
            self._orient(self.fname_mask, 'RPI')

            if self.fname_sc is not None:
                self._orient(self.fname_sc, 'RPI')
            if self.fname_ref is not None:
                self._orient(self.fname_ref, 'RPI')
            if self.path_template is not None:
                self._orient(self.path_levels, 'RPI')
                for fname_atlas in self.atlas_roi_lst:
                    self._orient(fname_atlas, 'RPI')
Ejemplo n.º 6
0
    def loadFromPath(self, path, verbose):
        """
        This function load an image from an absolute path using nibabel library
        :param path: path of the file from which the image will be loaded
        :return:
        """
        from nibabel import load, spatialimages
        from sct_utils import check_file_exist, printv, extract_fname, run
        from sct_image import get_orientation

        # check_file_exist(path, verbose=verbose)
        im_file = None
        try:
            im_file = load(path)
        except spatialimages.ImageFileError:
            printv('Error: make sure ' + path + ' is an image.', 1, 'error')
        self.orientation = get_orientation(path, filename=True)
        self.data = im_file.get_data()
        self.hdr = im_file.get_header()
        self.absolutepath = path
        self.path, self.file_name, self.ext = extract_fname(path)
        self.dim = get_dimension(im_file)
Ejemplo n.º 7
0
    def __init__(self, fname_im, contrast, fname_seg, path_out,
                 quality_control, verbose):

        self.fname_im = fname_im
        self.contrast = contrast

        self.fname_seg = fname_seg

        self.path_out = path_out

        self.quality_control = quality_control

        self.verbose = verbose

        self.tmp_dir = tmp_create(
            verbose=self.verbose)  # path to tmp directory

        self.orientation_im = get_orientation(Image(
            self.fname_im))  # to re-orient the data at the end

        self.slice2D_im = extract_fname(
            self.fname_im
        )[1] + '_midSag.nii'  # file used to do the detection, with only one slice
        self.dection_map_pmj = extract_fname(
            self.fname_im)[1] + '_map_pmj'  # file resulting from the detection

        # path to the pmj detector
        self.pmj_model = os.path.join(
            commands.getstatusoutput('echo $SCT_DIR')[1], 'data/pmj_models',
            '{}_model'.format(self.contrast))

        self.threshold = -0.75 if self.contrast == 't1' else 0.8  # detection map threshold, depends on the contrast

        self.fname_out = extract_fname(self.fname_im)[1] + '_pmj.nii.gz'

        self.fname_qc = 'qc_pmj.png'
    def process(self):
        # preprocessing
        os.chdir(self.tmp_dir)
        im_target = Image(self.original_target)
        im_sc_seg = Image(self.original_sc_seg)
        self.original_header = im_target.hdr
        self.original_orientation = im_target.orientation
        index_x = self.original_orientation.find('R') if 'R' in self.original_orientation else self.original_orientation.find('L')
        index_y = self.original_orientation.find('P') if 'P' in self.original_orientation else self.original_orientation.find('A')
        index_z = self.original_orientation.find('I') if 'I' in self.original_orientation else self.original_orientation.find('S')

        # resampling of the images
        nx, ny, nz, nt, px, py, pz, pt = im_target.dim

        pix_dim = [px, py, pz]
        self.original_px = pix_dim[index_x]
        self.original_py = pix_dim[index_y]

        if round(self.original_px, 2) != self.resample_to or round(self.original_py, 2) != self.resample_to:
            self.t2star = resample_image(self.original_target, npx=self.resample_to, npy=self.resample_to)
            self.sc_seg = resample_image(self.original_sc_seg, binary=True, npx=self.resample_to, npy=self.resample_to)

        # denoising (optional)
        im_target = Image(self.t2star)
        if self.denoising:
            from sct_maths import denoise_ornlm
            im_target.data = denoise_ornlm(im_target.data)
            im_target.save()
            self.t2star = im_target.file_name + im_target.ext

        box_size = int(22.5/self.resample_to)

        # Pad in case the spinal cord is too close to the edges
        pad_size = box_size/2 + 2
        self.pad = [str(pad_size)]*3

        self.pad[index_z] = str(0)

        t2star_pad = sct.add_suffix(self.t2star, '_pad')
        sc_seg_pad = sct.add_suffix(self.sc_seg, '_pad')
        sct.run('sct_image -i '+self.t2star+' -pad '+self.pad[0]+','+self.pad[1]+','+self.pad[2]+' -o '+t2star_pad)
        sct.run('sct_image -i '+self.sc_seg+' -pad '+self.pad[0]+','+self.pad[1]+','+self.pad[2]+' -o '+sc_seg_pad)
        self.t2star = t2star_pad
        self.sc_seg = sc_seg_pad

        # put data in RPI
        t2star_rpi = sct.add_suffix(self.t2star, '_RPI')
        sc_seg_rpi = sct.add_suffix(self.sc_seg, '_RPI')
        sct.run('sct_image -i '+self.t2star+' -setorient RPI -o '+t2star_rpi)
        sct.run('sct_image -i '+self.sc_seg+' -setorient RPI -o '+sc_seg_rpi)
        self.t2star = t2star_rpi
        self.sc_seg = sc_seg_rpi

        self.square_mask, self.processed_target = crop_t2_star(self.t2star, self.sc_seg, box_size=box_size)

        if self.t2 is not None:
            self.fname_level = compute_level_file(self.t2star, self.sc_seg, self.t2, self.t2_seg, self.t2_landmarks)
        elif self.fname_level is not None:
            level_orientation = get_orientation(self.fname_level, filename=True)
            if level_orientation != 'IRP':
                self.fname_level = set_orientation(self.fname_level, 'IRP', filename=True)

        os.chdir('..')
Ejemplo n.º 9
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"]
    remove_temp_files = int(arguments['-r'])
    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=os.path.join(
                                       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=os.path.join(
                                      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=os.path.join(
                                                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
        if remove_temp_files:
            sct.printv('\nRemove the temporary folder...', verbose)
            sct.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')
def main(fname_anat, fname_centerline, degree_poly, centerline_fitting, interp, remove_temp_files, verbose):
    
    # extract path of the script
    path_script = os.path.dirname(__file__)+'/'
    
    # Parameters for debug mode
    if param.debug == 1:
        print '\n*** WARNING: DEBUG MODE ON ***\n'
        status, path_sct_data = commands.getstatusoutput('echo $SCT_TESTING_DATA_DIR')
        fname_anat = path_sct_data+'/t2/t2.nii.gz'
        fname_centerline = path_sct_data+'/t2/t2_seg.nii.gz'
    
    # extract path/file/extension
    path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat)
    
    # Display arguments
    print '\nCheck input arguments...'
    print '  Input volume ...................... '+fname_anat
    print '  Centerline ........................ '+fname_centerline
    print ''
    
    # Get input image orientation
    im_anat = Image(fname_anat)
    input_image_orientation = get_orientation(im_anat)

    # Reorient input data into RL PA IS orientation
    im_centerline = Image(fname_centerline)
    im_anat_orient = set_orientation(im_anat, 'RPI')
    im_anat_orient.setFileName('tmp.anat_orient.nii')
    im_centerline_orient = set_orientation(im_centerline, 'RPI')
    im_centerline_orient.setFileName('tmp.centerline_orient.nii')

    # Open centerline
    #==========================================================================================
    print '\nGet dimensions of input centerline...'
    nx, ny, nz, nt, px, py, pz, pt = im_centerline_orient.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'
    
    print '\nOpen centerline volume...'
    data = im_centerline_orient.data

    X, Y, Z = (data>0).nonzero()
    min_z_index, max_z_index = min(Z), max(Z)
    
    
    # loop across z and associate x,y coordinate with the point having maximum intensity
    x_centerline = [0 for iz in range(min_z_index, max_z_index+1, 1)]
    y_centerline = [0 for iz in range(min_z_index, max_z_index+1, 1)]
    z_centerline = [iz for iz in range(min_z_index, max_z_index+1, 1)]

    # Two possible scenario:
    # 1. the centerline is probabilistic: each slices contains voxels with the probability of containing the centerline [0:...:1]
    # We only take the maximum value of the image to aproximate the centerline.
    # 2. The centerline/segmentation image contains many pixels per slice with values {0,1}.
    # We take all the points and approximate the centerline on all these points.

    X, Y, Z = ((data<1)*(data>0)).nonzero() # X is empty if binary image
    if (len(X) > 0): # Scenario 1
        for iz in range(min_z_index, max_z_index+1, 1):
            x_centerline[iz-min_z_index], y_centerline[iz-min_z_index] = numpy.unravel_index(data[:,:,iz].argmax(), data[:,:,iz].shape)
    else: # Scenario 2
        for iz in range(min_z_index, max_z_index+1, 1):
            x_seg, y_seg = (data[:,:,iz]>0).nonzero()
            if len(x_seg) > 0:
                x_centerline[iz-min_z_index] = numpy.mean(x_seg)
                y_centerline[iz-min_z_index] = numpy.mean(y_seg)

    # TODO: find a way to do the previous loop with this, which is more neat:
    # [numpy.unravel_index(data[:,:,iz].argmax(), data[:,:,iz].shape) for iz in range(0,nz,1)]
    
    # clear variable
    del data
    
    # Fit the centerline points with the kind of curve given as argument of the script and return the new smoothed coordinates
    if centerline_fitting == 'nurbs':
        try:
            x_centerline_fit, y_centerline_fit = b_spline_centerline(x_centerline,y_centerline,z_centerline)
        except ValueError:
            print "splines fitting doesn't work, trying with polynomial fitting...\n"
            x_centerline_fit, y_centerline_fit = polynome_centerline(x_centerline,y_centerline,z_centerline)
    elif centerline_fitting == 'polynome':
        x_centerline_fit, y_centerline_fit = polynome_centerline(x_centerline,y_centerline,z_centerline)

    #==========================================================================================
    # Split input volume
    print '\nSplit input volume...'
    im_anat_orient_split_list = split_data(im_anat_orient, 2)
    file_anat_split = []
    for im in im_anat_orient_split_list:
        file_anat_split.append(im.absolutepath)
        im.save()

    # initialize variables
    file_mat_inv_cumul = ['tmp.mat_inv_cumul_Z'+str(z).zfill(4) for z in range(0,nz,1)]
    z_init = min_z_index
    displacement_max_z_index = x_centerline_fit[z_init-min_z_index]-x_centerline_fit[max_z_index-min_z_index]

    # write centerline as text file
    print '\nGenerate fitted transformation matrices...'
    file_mat_inv_cumul_fit = ['tmp.mat_inv_cumul_fit_Z'+str(z).zfill(4) for z in range(0,nz,1)]
    for iz in range(min_z_index, max_z_index+1, 1):
        # compute inverse cumulative fitted transformation matrix
        fid = open(file_mat_inv_cumul_fit[iz], 'w')
        if (x_centerline[iz-min_z_index] == 0 and y_centerline[iz-min_z_index] == 0):
            displacement = 0
        else:
            displacement = x_centerline_fit[z_init-min_z_index]-x_centerline_fit[iz-min_z_index]
        fid.write('%i %i %i %f\n' %(1, 0, 0, displacement) )
        fid.write('%i %i %i %f\n' %(0, 1, 0, 0) )
        fid.write('%i %i %i %i\n' %(0, 0, 1, 0) )
        fid.write('%i %i %i %i\n' %(0, 0, 0, 1) )
        fid.close()

    # we complete the displacement matrix in z direction
    for iz in range(0, min_z_index, 1):
        fid = open(file_mat_inv_cumul_fit[iz], 'w')
        fid.write('%i %i %i %f\n' %(1, 0, 0, 0) )
        fid.write('%i %i %i %f\n' %(0, 1, 0, 0) )
        fid.write('%i %i %i %i\n' %(0, 0, 1, 0) )
        fid.write('%i %i %i %i\n' %(0, 0, 0, 1) )
        fid.close()
    for iz in range(max_z_index+1, nz, 1):
        fid = open(file_mat_inv_cumul_fit[iz], 'w')
        fid.write('%i %i %i %f\n' %(1, 0, 0, displacement_max_z_index) )
        fid.write('%i %i %i %f\n' %(0, 1, 0, 0) )
        fid.write('%i %i %i %i\n' %(0, 0, 1, 0) )
        fid.write('%i %i %i %i\n' %(0, 0, 0, 1) )
        fid.close()

    # apply transformations to data
    print '\nApply fitted transformation matrices...'
    file_anat_split_fit = ['tmp.anat_orient_fit_Z'+str(z).zfill(4) for z in range(0,nz,1)]
    for iz in range(0, nz, 1):
        # forward cumulative transformation to data
        sct.run(fsloutput+'flirt -in '+file_anat_split[iz]+' -ref '+file_anat_split[iz]+' -applyxfm -init '+file_mat_inv_cumul_fit[iz]+' -out '+file_anat_split_fit[iz]+' -interp '+interp)

    # Merge into 4D volume
    print '\nMerge into 4D volume...'
    from glob import glob
    im_to_concat_list = [Image(fname) for fname in glob('tmp.anat_orient_fit_Z*.nii')]
    im_concat_out = concat_data(im_to_concat_list, 2)
    im_concat_out.setFileName('tmp.anat_orient_fit.nii')
    im_concat_out.save()
    # sct.run(fsloutput+'fslmerge -z tmp.anat_orient_fit tmp.anat_orient_fit_z*')

    # Reorient data as it was before
    print '\nReorient data back into native orientation...'
    fname_anat_fit_orient = set_orientation(im_concat_out.absolutepath, input_image_orientation, filename=True)
    move(fname_anat_fit_orient, 'tmp.anat_orient_fit_reorient.nii')

    # Generate output file (in current folder)
    print '\nGenerate output file (in current folder)...'
    sct.generate_output_file('tmp.anat_orient_fit_reorient.nii', file_anat+'_flatten'+ext_anat)

    # Delete temporary files
    if remove_temp_files == 1:
        print '\nDelete temporary files...'
        sct.run('rm -rf tmp.*')

    # to view results
    print '\nDone! To view results, type:'
    print 'fslview '+file_anat+ext_anat+' '+file_anat+'_flatten'+ext_anat+' &\n'
Ejemplo n.º 11
0
def check_if_rpi(fname):
    from sct_image import get_orientation
    if not get_orientation(fname, filename=True) == 'RPI':
        printv('\nERROR: '+fname+' is not in RPI orientation. Use sct_image -setorient to reorient your data. Exit program.\n', 1, 'error')
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_image 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, filename=True)
    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] = px * x_trans[k]
                    data_warp[i, j, k, 0, 1] = py * 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)
def get_centerline_from_point(input_image, point_file, gap=4, gaussian_kernel=4, remove_tmp_files=1):

    # Initialization
    fname_anat = input_image
    fname_point = point_file
    slice_gap = gap
    remove_tmp_files = remove_tmp_files
    gaussian_kernel = gaussian_kernel
    start_time = time()
    verbose = 1

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

    # Parameters for debug mode
    if param.debug == 1:
        sct.printv('\n*** WARNING: DEBUG MODE ON ***\n\t\t\tCurrent working directory: '+os.getcwd(), 'warning')
        status, path_sct_testing_data = commands.getstatusoutput('echo $SCT_TESTING_DATA_DIR')
        fname_anat = path_sct_testing_data+'/t2/t2.nii.gz'
        fname_point = path_sct_testing_data+'/t2/t2_centerline_init.nii.gz'
        slice_gap = 5

    # check existence of input files
    sct.check_file_exist(fname_anat)
    sct.check_file_exist(fname_point)

    # extract path/file/extension
    path_anat, file_anat, ext_anat = sct.extract_fname(fname_anat)
    path_point, file_point, ext_point = sct.extract_fname(fname_point)

    # extract path of schedule file
    # TODO: include schedule file in sct
    # TODO: check existence of schedule file
    file_schedule = path_sct + param.schedule_file

    # Get input image orientation
    input_image_orientation = get_orientation(fname_anat, filename=True)

    # Display arguments
    print '\nCheck input arguments...'
    print '  Anatomical image:     '+fname_anat
    print '  Orientation:          '+input_image_orientation
    print '  Point in spinal cord: '+fname_point
    print '  Slice gap:            '+str(slice_gap)
    print '  Gaussian kernel:      '+str(gaussian_kernel)
    print '  Degree of polynomial: '+str(param.deg_poly)

    # create temporary folder
    print('\nCreate temporary folder...')
    path_tmp = 'tmp.'+strftime('%y%m%d%H%M%S')
    sct.create_folder(path_tmp)
    print '\nCopy input data...'
    sct.run('cp '+fname_anat+ ' '+path_tmp+'/tmp.anat'+ext_anat)
    sct.run('cp '+fname_point+ ' '+path_tmp+'/tmp.point'+ext_point)

    # go to temporary folder
    os.chdir(path_tmp)

    # convert to nii
    im_anat = convert('tmp.anat'+ext_anat, 'tmp.anat.nii')
    im_point = convert('tmp.point'+ext_point, 'tmp.point.nii')

    # Reorient input anatomical volume into RL PA IS orientation
    print '\nReorient input volume to RL PA IS orientation...'
    set_orientation(im_anat, 'RPI')
    im_anat.setFileName('tmp.anat_orient.nii')
    # Reorient binary point into RL PA IS orientation
    print '\nReorient binary point into RL PA IS orientation...'
    # sct.run(sct.fsloutput + 'fslswapdim tmp.point RL PA IS tmp.point_orient')
    set_orientation(im_point, 'RPI')
    im_point.setFileName('tmp.point_orient.nii')

    # Get image dimensions
    print '\nGet image dimensions...'
    nx, ny, nz, nt, px, py, pz, pt = Image('tmp.anat_orient.nii').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'

    # Split input volume
    print '\nSplit input volume...'
    im_anat_split_list = split_data(im_anat, 2)
    file_anat_split = []
    for im in im_anat_split_list:
        file_anat_split.append(im.absolutepath)
        im.save()

    im_point_split_list = split_data(im_point, 2)
    file_point_split = []
    for im in im_point_split_list:
        file_point_split.append(im.absolutepath)
        im.save()

    # Extract coordinates of input point
    data_point = Image('tmp.point_orient.nii').data
    x_init, y_init, z_init = unravel_index(data_point.argmax(), data_point.shape)
    sct.printv('Coordinates of input point: ('+str(x_init)+', '+str(y_init)+', '+str(z_init)+')', verbose)

    # Create 2D gaussian mask
    sct.printv('\nCreate gaussian mask from point...', verbose)
    xx, yy = mgrid[:nx, :ny]
    mask2d = zeros((nx, ny))
    radius = round(float(gaussian_kernel+1)/2)  # add 1 because the radius includes the center.
    sigma = float(radius)
    mask2d = exp(-(((xx-x_init)**2)/(2*(sigma**2)) + ((yy-y_init)**2)/(2*(sigma**2))))

    # Save mask to 2d file
    file_mask_split = ['tmp.mask_orient_Z'+str(z).zfill(4) for z in range(0, nz, 1)]
    nii_mask2d = Image('tmp.anat_orient_Z0000.nii')
    nii_mask2d.data = mask2d
    nii_mask2d.setFileName(file_mask_split[z_init]+'.nii')
    nii_mask2d.save()

    # initialize variables
    file_mat = ['tmp.mat_Z'+str(z).zfill(4) for z in range(0, nz, 1)]
    file_mat_inv = ['tmp.mat_inv_Z'+str(z).zfill(4) for z in range(0, nz, 1)]
    file_mat_inv_cumul = ['tmp.mat_inv_cumul_Z'+str(z).zfill(4) for z in range(0, nz, 1)]

    # create identity matrix for initial transformation matrix
    fid = open(file_mat_inv_cumul[z_init], 'w')
    fid.write('%i %i %i %i\n' % (1, 0, 0, 0))
    fid.write('%i %i %i %i\n' % (0, 1, 0, 0))
    fid.write('%i %i %i %i\n' % (0, 0, 1, 0))
    fid.write('%i %i %i %i\n' % (0, 0, 0, 1))
    fid.close()

    # initialize centerline: give value corresponding to initial point
    x_centerline = [x_init]
    y_centerline = [y_init]
    z_centerline = [z_init]
    warning_count = 0

    # go up (1), then down (2) in reference to the binary point
    for iUpDown in range(1, 3):

        if iUpDown == 1:
            # z increases
            slice_gap_signed = slice_gap
        elif iUpDown == 2:
            # z decreases
            slice_gap_signed = -slice_gap
            # reverse centerline (because values will be appended at the end)
            x_centerline.reverse()
            y_centerline.reverse()
            z_centerline.reverse()

        # initialization before looping
        z_dest = z_init  # point given by user
        z_src = z_dest + slice_gap_signed

        # continue looping if 0 <= z < nz
        while 0 <= z_src < nz:

            # print current z:
            print 'z='+str(z_src)+':'

            # estimate transformation
            sct.run(fsloutput+'flirt -in '+file_anat_split[z_src]+' -ref '+file_anat_split[z_dest]+' -schedule ' +
                    file_schedule + ' -verbose 0 -omat ' + file_mat[z_src] +
                    ' -cost normcorr -forcescaling -inweight ' + file_mask_split[z_dest] +
                    ' -refweight '+file_mask_split[z_dest])

            # display transfo
            status, output = sct.run('cat '+file_mat[z_src])
            print output

            # check if transformation is bigger than 1.5x slice_gap
            tx = float(output.split()[3])
            ty = float(output.split()[7])
            norm_txy = linalg.norm([tx, ty], ord=2)
            if norm_txy > 1.5*slice_gap:
                print 'WARNING: Transformation is too large --> using previous one.'
                warning_count = warning_count + 1
                # if previous transformation exists, replace current one with previous one
                if os.path.isfile(file_mat[z_dest]):
                    sct.run('cp '+file_mat[z_dest]+' '+file_mat[z_src])

            # estimate inverse transformation matrix
            sct.run('convert_xfm -omat '+file_mat_inv[z_src]+' -inverse '+file_mat[z_src])

            # compute cumulative transformation
            sct.run('convert_xfm -omat '+file_mat_inv_cumul[z_src]+' -concat '+file_mat_inv[z_src]+' '+file_mat_inv_cumul[z_dest])

            # apply inverse cumulative transformation to initial gaussian mask (to put it in src space)
            sct.run(fsloutput+'flirt -in '+file_mask_split[z_init]+' -ref '+file_mask_split[z_init]+' -applyxfm -init '+file_mat_inv_cumul[z_src]+' -out '+file_mask_split[z_src])

            # open inverse cumulative transformation file and generate centerline
            fid = open(file_mat_inv_cumul[z_src])
            mat = fid.read().split()
            x_centerline.append(x_init + float(mat[3]))
            y_centerline.append(y_init + float(mat[7]))
            z_centerline.append(z_src)
            #z_index = z_index+1

            # define new z_dest (target slice) and new z_src (moving slice)
            z_dest = z_dest + slice_gap_signed
            z_src = z_src + slice_gap_signed


    # Reconstruct centerline
    # ====================================================================================================

    # reverse back centerline (because it's been reversed once, so now all values are in the right order)
    x_centerline.reverse()
    y_centerline.reverse()
    z_centerline.reverse()

    # fit centerline in the Z-X plane using polynomial function
    print '\nFit centerline in the Z-X plane using polynomial function...'
    coeffsx = polyfit(z_centerline, x_centerline, deg=param.deg_poly)
    polyx = poly1d(coeffsx)
    x_centerline_fit = polyval(polyx, z_centerline)
    # calculate RMSE
    rmse = linalg.norm(x_centerline_fit-x_centerline)/sqrt( len(x_centerline) )
    # calculate max absolute error
    max_abs = max(abs(x_centerline_fit-x_centerline))
    print '.. RMSE (in mm): '+str(rmse*px)
    print '.. Maximum absolute error (in mm): '+str(max_abs*px)

    # fit centerline in the Z-Y plane using polynomial function
    print '\nFit centerline in the Z-Y plane using polynomial function...'
    coeffsy = polyfit(z_centerline, y_centerline, deg=param.deg_poly)
    polyy = poly1d(coeffsy)
    y_centerline_fit = polyval(polyy, z_centerline)
    # calculate RMSE
    rmse = linalg.norm(y_centerline_fit-y_centerline)/sqrt( len(y_centerline) )
    # calculate max absolute error
    max_abs = max( abs(y_centerline_fit-y_centerline) )
    print '.. RMSE (in mm): '+str(rmse*py)
    print '.. Maximum absolute error (in mm): '+str(max_abs*py)

    # display
    if param.debug == 1:
        import matplotlib.pyplot as plt
        plt.figure()
        plt.plot(z_centerline,x_centerline,'.',z_centerline,x_centerline_fit,'r')
        plt.legend(['Data','Polynomial Fit'])
        plt.title('Z-X plane polynomial interpolation')
        plt.show()

        plt.figure()
        plt.plot(z_centerline,y_centerline,'.',z_centerline,y_centerline_fit,'r')
        plt.legend(['Data','Polynomial Fit'])
        plt.title('Z-Y plane polynomial interpolation')
        plt.show()

    # generate full range z-values for centerline
    z_centerline_full = [iz for iz in range(0, nz, 1)]

    # calculate X and Y values for the full centerline
    x_centerline_fit_full = polyval(polyx, z_centerline_full)
    y_centerline_fit_full = polyval(polyy, z_centerline_full)

    # Generate fitted transformation matrices and write centerline coordinates in text file
    print '\nGenerate fitted transformation matrices and write centerline coordinates in text file...'
    file_mat_inv_cumul_fit = ['tmp.mat_inv_cumul_fit_z'+str(z).zfill(4) for z in range(0,nz,1)]
    file_mat_cumul_fit = ['tmp.mat_cumul_fit_z'+str(z).zfill(4) for z in range(0,nz,1)]
    fid_centerline = open('tmp.centerline_coordinates.txt', 'w')
    for iz in range(0, nz, 1):
        # compute inverse cumulative fitted transformation matrix
        fid = open(file_mat_inv_cumul_fit[iz], 'w')
        fid.write('%i %i %i %f\n' % (1, 0, 0, x_centerline_fit_full[iz]-x_init))
        fid.write('%i %i %i %f\n' % (0, 1, 0, y_centerline_fit_full[iz]-y_init))
        fid.write('%i %i %i %i\n' % (0, 0, 1, 0))
        fid.write('%i %i %i %i\n' % (0, 0, 0, 1))
        fid.close()
        # compute forward cumulative fitted transformation matrix
        sct.run('convert_xfm -omat '+file_mat_cumul_fit[iz]+' -inverse '+file_mat_inv_cumul_fit[iz])
        # write centerline coordinates in x, y, z format
        fid_centerline.write('%f %f %f\n' %(x_centerline_fit_full[iz], y_centerline_fit_full[iz], z_centerline_full[iz]) )
    fid_centerline.close()


    # Prepare output data
    # ====================================================================================================

    # write centerline as text file
    for iz in range(0, nz, 1):
        # compute inverse cumulative fitted transformation matrix
        fid = open(file_mat_inv_cumul_fit[iz], 'w')
        fid.write('%i %i %i %f\n' % (1, 0, 0, x_centerline_fit_full[iz]-x_init))
        fid.write('%i %i %i %f\n' % (0, 1, 0, y_centerline_fit_full[iz]-y_init))
        fid.write('%i %i %i %i\n' % (0, 0, 1, 0))
        fid.write('%i %i %i %i\n' % (0, 0, 0, 1))
        fid.close()

    # write polynomial coefficients
    savetxt('tmp.centerline_polycoeffs_x.txt',coeffsx)
    savetxt('tmp.centerline_polycoeffs_y.txt',coeffsy)

    # apply transformations to data
    print '\nApply fitted transformation matrices...'
    file_anat_split_fit = ['tmp.anat_orient_fit_z'+str(z).zfill(4) for z in range(0, nz, 1)]
    file_mask_split_fit = ['tmp.mask_orient_fit_z'+str(z).zfill(4) for z in range(0, nz, 1)]
    file_point_split_fit = ['tmp.point_orient_fit_z'+str(z).zfill(4) for z in range(0, nz, 1)]
    for iz in range(0, nz, 1):
        # forward cumulative transformation to data
        sct.run(fsloutput+'flirt -in '+file_anat_split[iz]+' -ref '+file_anat_split[iz]+' -applyxfm -init '+file_mat_cumul_fit[iz]+' -out '+file_anat_split_fit[iz])
        # inverse cumulative transformation to mask
        sct.run(fsloutput+'flirt -in '+file_mask_split[z_init]+' -ref '+file_mask_split[z_init]+' -applyxfm -init '+file_mat_inv_cumul_fit[iz]+' -out '+file_mask_split_fit[iz])
        # inverse cumulative transformation to point
        sct.run(fsloutput+'flirt -in '+file_point_split[z_init]+' -ref '+file_point_split[z_init]+' -applyxfm -init '+file_mat_inv_cumul_fit[iz]+' -out '+file_point_split_fit[iz]+' -interp nearestneighbour')

    # Merge into 4D volume
    print '\nMerge into 4D volume...'
    im_anat_list = [Image(fname) for fname in glob.glob('tmp.anat_orient_fit_z*.nii')]
    im_anat_concat = concat_data(im_anat_list, 2)
    im_anat_concat.setFileName('tmp.anat_orient_fit.nii')
    im_anat_concat.save()

    im_mask_list = [Image(fname) for fname in glob.glob('tmp.mask_orient_fit_z*.nii')]
    im_mask_concat = concat_data(im_mask_list, 2)
    im_mask_concat.setFileName('tmp.mask_orient_fit.nii')
    im_mask_concat.save()

    im_point_list = [Image(fname) for fname in 	glob.glob('tmp.point_orient_fit_z*.nii')]
    im_point_concat = concat_data(im_point_list, 2)
    im_point_concat.setFileName('tmp.point_orient_fit.nii')
    im_point_concat.save()

    # Copy header geometry from input data
    print '\nCopy header geometry from input data...'
    im_anat = Image('tmp.anat_orient.nii')
    im_anat_orient_fit = Image('tmp.anat_orient_fit.nii')
    im_mask_orient_fit = Image('tmp.mask_orient_fit.nii')
    im_point_orient_fit = Image('tmp.point_orient_fit.nii')
    im_anat_orient_fit = copy_header(im_anat, im_anat_orient_fit)
    im_mask_orient_fit = copy_header(im_anat, im_mask_orient_fit)
    im_point_orient_fit = copy_header(im_anat, im_point_orient_fit)
    for im in [im_anat_orient_fit, im_mask_orient_fit, im_point_orient_fit]:
        im.save()

    # Reorient outputs into the initial orientation of the input image
    print '\nReorient the centerline into the initial orientation of the input image...'
    set_orientation('tmp.point_orient_fit.nii', input_image_orientation, 'tmp.point_orient_fit.nii')
    set_orientation('tmp.mask_orient_fit.nii', input_image_orientation, 'tmp.mask_orient_fit.nii')

    # Generate output file (in current folder)
    print '\nGenerate output file (in current folder)...'
    os.chdir('..')  # come back to parent folder
    fname_output_centerline = sct.generate_output_file(path_tmp+'/tmp.point_orient_fit.nii', file_anat+'_centerline'+ext_anat)

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

    # print number of warnings
    print '\nNumber of warnings: '+str(warning_count)+' (if >10, you should probably reduce the gap and/or increase the kernel size'

    # display elapsed time
    elapsed_time = time() - start_time
    print '\nFinished! \n\tGenerated file: '+fname_output_centerline+'\n\tElapsed time: '+str(int(round(elapsed_time)))+'s\n'
def get_centerline_from_labels(fname_in, list_fname_labels, param, output_file_name=None, remove_temp_files=1, verbose=0):

    path, file, ext = sct.extract_fname(fname_in)

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

    # Copying input data to tmp folder
    sct.printv('\nCopying input data to tmp folder...', verbose)
    sct.run('sct_convert -i '+fname_in+' -o '+path_tmp+'data.nii')
    file_labels = []
    for i in range(len(list_fname_labels)):
        file_labels.append('labels_'+str(i)+'.nii.gz')
        sct.run('sct_convert -i '+list_fname_labels[i]+' -o '+path_tmp+file_labels[i])

    # go to tmp folder
    os.chdir(path_tmp)

    ## Concatenation of the files

    # Concatenation : sum of matrices
    file_0 = Image('data.nii')
    data_concatenation = file_0.data
    hdr_0 = file_0.hdr
    orientation_file_0 = get_orientation(file_0)
    if len(list_fname_labels) > 0:
       for i in range(0, len(list_fname_labels)):
            orientation_file_temp = get_orientation(file_labels[i], filename=True)
            if orientation_file_0 != orientation_file_temp :
                print 'ERROR: The files ', fname_in, ' and ', file_labels[i], ' are not in the same orientation. Use sct_image -setorient to change the orientation of a file.'
                sys.exit(2)
            file_temp = load(file_labels[i])
            data_temp = file_temp.get_data()
            data_concatenation = data_concatenation + data_temp

    # Save concatenation as a file
    print '\nWrite NIFTI volumes...'
    img = Nifti1Image(data_concatenation, None, hdr_0)
    save(img, 'concatenation_file.nii.gz')

    # Applying nurbs to the concatenation and save file as binary file
    fname_output = extract_centerline('concatenation_file.nii.gz', remove_temp_files = remove_temp_files, verbose = verbose, algo_fitting=param.algo_fitting, type_window=param.type_window, window_length=param.window_length)

    # Rename files after processing
    if output_file_name != None:
       output_file_name = output_file_name
    else : output_file_name = 'generated_centerline.nii.gz'

    os.rename(fname_output, output_file_name)
    path_binary, file_binary, ext_binary = sct.extract_fname(output_file_name)
    os.rename('concatenation_file_centerline.txt', file_binary+'.txt')

    # Process for a binary file as output:
    sct.run('cp '+output_file_name+' ../')

    # Process for a text file as output:
    sct.run('cp '+file_binary+ '.txt'+ ' ../')

    os.chdir('../')
    # Remove temporary files
    if remove_temp_files:
       print('\nRemove temporary files...')
       sct.run('rm -rf '+path_tmp)
Ejemplo n.º 15
0
def create_mask():
    fsloutput = 'export FSLOUTPUTTYPE=NIFTI; '  # for faster processing, all outputs are in NIFTI

    # parse argument for method
    method_type = param.process[0]
    # check method val
    if not method_type == 'center':
        method_val = param.process[1]

    # check existence of input files
    if method_type == 'centerline':
        sct.check_file_exist(method_val, param.verbose)

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

    # Get output folder and file name
    if param.fname_out == '':
        param.fname_out = param.file_prefix+file_data+ext_data

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

    sct.printv('\nCheck orientation...', param.verbose)
    orientation_input = get_orientation(Image(param.fname_data))
    sct.printv('.. '+orientation_input, param.verbose)
    reorient_coordinates = False

    # copy input data to tmp folder
    convert(param.fname_data, path_tmp+'data.nii')
    if method_type == 'centerline':
        convert(method_val, path_tmp+'centerline.nii.gz')
    if method_type == 'point':
        convert(method_val, path_tmp+'point.nii.gz')

    # go to tmp folder
    os.chdir(path_tmp)

    # reorient to RPI
    sct.printv('\nReorient to RPI...', param.verbose)
    # if not orientation_input == 'RPI':
    sct.run('sct_image -i data.nii -o data_RPI.nii -setorient RPI -v 0', verbose=False)
    if method_type == 'centerline':
        sct.run('sct_image -i centerline.nii.gz -o centerline_RPI.nii.gz -setorient RPI -v 0', verbose=False)
    if method_type == 'point':
        sct.run('sct_image -i point.nii.gz -o point_RPI.nii.gz -setorient RPI -v 0', verbose=False)
    #
    # if method_type == 'centerline':
    #     orientation_centerline = get_orientation_3d(method_val, filename=True)
    #     if not orientation_centerline == 'RPI':
    #         sct.run('sct_image -i ' + method_val + ' -o ' + path_tmp + 'centerline.nii.gz' + ' -setorient RPI -v 0', verbose=False)
    #     else:
    #         convert(method_val, path_tmp+'centerline.nii.gz')

    # Get dimensions of data
    sct.printv('\nGet dimensions of data...', param.verbose)
    nx, ny, nz, nt, px, py, pz, pt = Image('data_RPI.nii').dim
    sct.printv('  ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz)+ ' x ' + str(nt), param.verbose)
    # in case user input 4d data
    if nt != 1:
        sct.printv('WARNING in '+os.path.basename(__file__)+': Input image is 4d but output mask will 3D.', param.verbose, 'warning')
        # extract first volume to have 3d reference
        nii = Image('data_RPI.nii')
        data3d = nii.data[:,:,:,0]
        nii.data = data3d
        nii.save()

    if method_type == 'coord':
        # parse to get coordinate
        coord = map(int, method_val.split('x'))

    if method_type == 'point':
        # get file name
        fname_point = method_val
        # extract coordinate of point
        sct.printv('\nExtract coordinate of point...', param.verbose)
        # TODO: change this way to remove dependence to sct.run. ProcessLabels.display_voxel returns list of coordinates
        status, output = sct.run('sct_label_utils -i point_RPI.nii.gz -display', param.verbose)
        # parse to get coordinate
        coord = output[output.find('Position=')+10:-17].split(',')

    if method_type == 'center':
        # set coordinate at center of FOV
        coord = round(float(nx)/2), round(float(ny)/2)

    if method_type == 'centerline':
        # get name of centerline from user argument
        fname_centerline = 'centerline_RPI.nii.gz'
    else:
        # generate volume with line along Z at coordinates 'coord'
        sct.printv('\nCreate line...', param.verbose)
        fname_centerline = create_line('data_RPI.nii', coord, nz)

    # create mask
    sct.printv('\nCreate mask...', param.verbose)
    centerline = nibabel.load(fname_centerline)  # open centerline
    hdr = centerline.get_header()  # get header
    hdr.set_data_dtype('uint8')  # set imagetype to uint8
    spacing = hdr.structarr['pixdim']
    data_centerline = centerline.get_data()  # get centerline
    z_centerline_not_null = [iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()]
    # get center of mass of the centerline
    cx = [0] * nz
    cy = [0] * nz
    for iz in range(0, nz, 1):
        if iz in z_centerline_not_null:
            cx[iz], cy[iz] = ndimage.measurements.center_of_mass(numpy.array(data_centerline[:, :, iz]))
    # create 2d masks
    file_mask = 'data_mask'
    for iz in range(nz):
        if iz not in z_centerline_not_null:
            # write an empty nifty volume
            img = nibabel.Nifti1Image(data_centerline[:, :, iz], None, hdr)
            nibabel.save(img, (file_mask + str(iz) + '.nii'))
        else:
            center = numpy.array([cx[iz], cy[iz]])
            mask2d = create_mask2d(center, param.shape, param.size, nx, ny, even=param.even, spacing=spacing)
            # Write NIFTI volumes
            img = nibabel.Nifti1Image(mask2d, None, hdr)
            nibabel.save(img, (file_mask+str(iz)+'.nii'))
    # merge along Z
    # cmd = 'fslmerge -z mask '

    # CHANGE THAT CAN IMPACT SPEED:
    # related to issue #755, we cannot open more than 256 files at one time.
    # to solve this issue, we do not open more than 100 files
    '''
    im_list = []
    im_temp = []
    for iz in range(nz_not_null):
        if iz != 0 and iz % 100 == 0:
            im_temp.append(concat_data(im_list, 2))
            im_list = [Image(file_mask + str(iz) + '.nii')]
        else:
            im_list.append(Image(file_mask+str(iz)+'.nii'))

    if im_temp:
        im_temp.append(concat_data(im_list, 2))
        im_out = concat_data(im_temp, 2, no_expand=True)
    else:
        im_out = concat_data(im_list, 2)
    '''
    fname_list = [file_mask + str(iz) + '.nii' for iz in range(nz)]
    im_out = concat_data(fname_list, dim=2)
    im_out.setFileName('mask_RPI.nii.gz')
    im_out.save()

    # reorient if necessary
    # if not orientation_input == 'RPI':
    sct.run('sct_image -i mask_RPI.nii.gz -o mask.nii.gz -setorient ' + orientation_input, param.verbose)

    # copy header input --> mask
    im_dat = Image('data.nii')
    im_mask = Image('mask.nii.gz')
    im_mask = copy_header(im_dat, im_mask)
    im_mask.save()

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

    # Generate output files
    sct.printv('\nGenerate output files...', param.verbose)
    sct.generate_output_file(path_tmp+'mask.nii.gz', param.fname_out)

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

    # to view results
    sct.printv('\nDone! To view results, type:', param.verbose)
    sct.printv('fslview '+param.fname_data+' '+param.fname_out+' -l Red -t 0.5 &', param.verbose, 'info')
    print
Ejemplo n.º 16
0
def create_mask():
    fsloutput = 'export FSLOUTPUTTYPE=NIFTI; '  # for faster processing, all outputs are in NIFTI

    # parse argument for method
    method_type = param.process[0]
    # check method val
    if not method_type == 'center':
        method_val = param.process[1]

    # check existence of input files
    if method_type == 'centerline':
        sct.check_file_exist(method_val, param.verbose)

    # check if orientation is RPI
    sct.printv('\nCheck if orientation is RPI...', param.verbose)
    ori = get_orientation(param.fname_data, filename=True)
    if not ori == 'RPI':
        sct.printv('\nERROR in '+os.path.basename(__file__)+': Orientation of input image should be RPI. Use sct_image -setorient to put your image in RPI.\n', 1, 'error')

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

    # Get output folder and file name
    if param.fname_out == '':
        param.fname_out = param.file_prefix+file_data+ext_data
    #fname_out = os.path.abspath(path_out+file_out+ext_out)

    # 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
    sct.printv('\nCopying input data to tmp folder and convert to nii...', param.verbose)
    convert(param.fname_data, path_tmp+'data.nii')
    # sct.run('cp '+param.fname_data+' '+path_tmp+'data'+ext_data, param.verbose)
    if method_type == 'centerline':
        convert(method_val, path_tmp+'centerline.nii.gz')

    # go to tmp folder
    os.chdir(path_tmp)

    # 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)
    # in case user input 4d data
    if nt != 1:
        sct.printv('WARNING in '+os.path.basename(__file__)+': Input image is 4d but output mask will 3D.', param.verbose, 'warning')
        # extract first volume to have 3d reference
        nii = Image('data.nii')
        data3d = nii.data[:,:,:,0]
        nii.data = data3d
        nii.save()

    if method_type == 'coord':
        # parse to get coordinate
        coord = map(int, method_val.split('x'))

    if method_type == 'point':
        # get file name
        fname_point = method_val
        # extract coordinate of point
        sct.printv('\nExtract coordinate of point...', param.verbose)
        status, output = sct.run('sct_label_utils -i '+fname_point+' -p display-voxel', param.verbose)
        # parse to get coordinate
        coord = output[output.find('Position=')+10:-17].split(',')

    if method_type == 'center':
        # set coordinate at center of FOV
        coord = round(float(nx)/2), round(float(ny)/2)

    if method_type == 'centerline':
        # get name of centerline from user argument
        fname_centerline = 'centerline.nii.gz'
    else:
        # generate volume with line along Z at coordinates 'coord'
        sct.printv('\nCreate line...', param.verbose)
        fname_centerline = create_line('data.nii', coord, nz)

    # create mask
    sct.printv('\nCreate mask...', param.verbose)
    centerline = nibabel.load(fname_centerline)  # open centerline
    hdr = centerline.get_header()  # get header
    hdr.set_data_dtype('uint8')  # set imagetype to uint8
    data_centerline = centerline.get_data()  # get centerline
    z_centerline = [iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()]
    nz = len(z_centerline)
    # get center of mass of the centerline
    cx = [0] * nz
    cy = [0] * nz
    for iz in range(0, nz, 1):
        cx[iz], cy[iz] = ndimage.measurements.center_of_mass(numpy.array(data_centerline[:, :, z_centerline[iz]]))
    # create 2d masks
    file_mask = 'data_mask'
    for iz in range(nz):
        center = numpy.array([cx[iz], cy[iz]])
        mask2d = create_mask2d(center, param.shape, param.size, nx, ny, param.even)
        # Write NIFTI volumes
        img = nibabel.Nifti1Image(mask2d, None, hdr)
        nibabel.save(img, (file_mask+str(iz)+'.nii'))
    # merge along Z
    # cmd = 'fslmerge -z mask '
    im_list = []
    for iz in range(nz):
        im_list.append(Image(file_mask+str(iz)+'.nii'))
    im_out = concat_data(im_list, 2)
    im_out.setFileName('mask.nii.gz')
    im_out.save()

    # copy geometry
    im_dat = Image('data.nii')
    im_mask = Image('mask.nii.gz')
    im_mask = copy_header(im_dat, im_mask)
    im_mask.save()

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

    # Generate output files
    sct.printv('\nGenerate output files...', param.verbose)
    sct.generate_output_file(path_tmp+'mask.nii.gz', param.fname_out)

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

    # to view results
    sct.printv('\nDone! To view results, type:', param.verbose)
    sct.printv('fslview '+param.fname_data+' '+param.fname_out+' -l Red -t 0.5 &', param.verbose, 'info')
    print
Ejemplo n.º 17
0
def create_mask():
    fsloutput = 'export FSLOUTPUTTYPE=NIFTI; '  # for faster processing, all outputs are in NIFTI

    # parse argument for method
    method_type = param.process[0]
    # check method val
    if not method_type == 'center':
        method_val = param.process[1]

    # check existence of input files
    if method_type == 'centerline':
        sct.check_file_exist(method_val, param.verbose)

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

    # Get output folder and file name
    if param.fname_out == '':
        param.fname_out = param.file_prefix + file_data + ext_data

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

    sct.printv('\nCheck orientation...', param.verbose)
    orientation_input = get_orientation(Image(param.fname_data))
    sct.printv('.. ' + orientation_input, param.verbose)
    reorient_coordinates = False

    # copy input data to tmp folder
    convert(param.fname_data, path_tmp + 'data.nii')
    if method_type == 'centerline':
        convert(method_val, path_tmp + 'centerline.nii.gz')
    if method_type == 'point':
        convert(method_val, path_tmp + 'point.nii.gz')

    # go to tmp folder
    os.chdir(path_tmp)

    # reorient to RPI
    sct.printv('\nReorient to RPI...', param.verbose)
    # if not orientation_input == 'RPI':
    sct.run('sct_image -i data.nii -o data_RPI.nii -setorient RPI -v 0',
            verbose=False)
    if method_type == 'centerline':
        sct.run(
            'sct_image -i centerline.nii.gz -o centerline_RPI.nii.gz -setorient RPI -v 0',
            verbose=False)
    if method_type == 'point':
        sct.run(
            'sct_image -i point.nii.gz -o point_RPI.nii.gz -setorient RPI -v 0',
            verbose=False)
    #
    # if method_type == 'centerline':
    #     orientation_centerline = get_orientation_3d(method_val, filename=True)
    #     if not orientation_centerline == 'RPI':
    #         sct.run('sct_image -i ' + method_val + ' -o ' + path_tmp + 'centerline.nii.gz' + ' -setorient RPI -v 0', verbose=False)
    #     else:
    #         convert(method_val, path_tmp+'centerline.nii.gz')

    # Get dimensions of data
    sct.printv('\nGet dimensions of data...', param.verbose)
    nx, ny, nz, nt, px, py, pz, pt = Image('data_RPI.nii').dim
    sct.printv(
        '  ' + str(nx) + ' x ' + str(ny) + ' x ' + str(nz) + ' x ' + str(nt),
        param.verbose)
    # in case user input 4d data
    if nt != 1:
        sct.printv(
            'WARNING in ' + os.path.basename(__file__) +
            ': Input image is 4d but output mask will 3D.', param.verbose,
            'warning')
        # extract first volume to have 3d reference
        nii = Image('data_RPI.nii')
        data3d = nii.data[:, :, :, 0]
        nii.data = data3d
        nii.save()

    if method_type == 'coord':
        # parse to get coordinate
        coord = map(int, method_val.split('x'))

    if method_type == 'point':
        # get file name
        fname_point = method_val
        # extract coordinate of point
        sct.printv('\nExtract coordinate of point...', param.verbose)
        # TODO: change this way to remove dependence to sct.run. ProcessLabels.display_voxel returns list of coordinates
        status, output = sct.run(
            'sct_label_utils -i point_RPI.nii.gz -display', param.verbose)
        # parse to get coordinate
        coord = output[output.find('Position=') + 10:-17].split(',')

    if method_type == 'center':
        # set coordinate at center of FOV
        coord = round(float(nx) / 2), round(float(ny) / 2)

    if method_type == 'centerline':
        # get name of centerline from user argument
        fname_centerline = 'centerline_RPI.nii.gz'
    else:
        # generate volume with line along Z at coordinates 'coord'
        sct.printv('\nCreate line...', param.verbose)
        fname_centerline = create_line('data_RPI.nii', coord, nz)

    # create mask
    sct.printv('\nCreate mask...', param.verbose)
    centerline = nibabel.load(fname_centerline)  # open centerline
    hdr = centerline.get_header()  # get header
    hdr.set_data_dtype('uint8')  # set imagetype to uint8
    spacing = hdr.structarr['pixdim']
    data_centerline = centerline.get_data()  # get centerline
    # if data is 2D, reshape with empty third dimension
    if len(data_centerline.shape) == 2:
        data_centerline_shape = list(data_centerline.shape)
        data_centerline_shape.append(1)
        data_centerline = data_centerline.reshape(data_centerline_shape)
    z_centerline_not_null = [
        iz for iz in range(0, nz, 1) if data_centerline[:, :, iz].any()
    ]
    # get center of mass of the centerline
    cx = [0] * nz
    cy = [0] * nz
    for iz in range(0, nz, 1):
        if iz in z_centerline_not_null:
            cx[iz], cy[iz] = ndimage.measurements.center_of_mass(
                numpy.array(data_centerline[:, :, iz]))
    # create 2d masks
    file_mask = 'data_mask'
    for iz in range(nz):
        if iz not in z_centerline_not_null:
            # write an empty nifty volume
            img = nibabel.Nifti1Image(data_centerline[:, :, iz], None, hdr)
            nibabel.save(img, (file_mask + str(iz) + '.nii'))
        else:
            center = numpy.array([cx[iz], cy[iz]])
            mask2d = create_mask2d(center,
                                   param.shape,
                                   param.size,
                                   nx,
                                   ny,
                                   even=param.even,
                                   spacing=spacing)
            # Write NIFTI volumes
            img = nibabel.Nifti1Image(mask2d, None, hdr)
            nibabel.save(img, (file_mask + str(iz) + '.nii'))
    # merge along Z
    # cmd = 'fslmerge -z mask '

    # CHANGE THAT CAN IMPACT SPEED:
    # related to issue #755, we cannot open more than 256 files at one time.
    # to solve this issue, we do not open more than 100 files
    '''
    im_list = []
    im_temp = []
    for iz in range(nz_not_null):
        if iz != 0 and iz % 100 == 0:
            im_temp.append(concat_data(im_list, 2))
            im_list = [Image(file_mask + str(iz) + '.nii')]
        else:
            im_list.append(Image(file_mask+str(iz)+'.nii'))

    if im_temp:
        im_temp.append(concat_data(im_list, 2))
        im_out = concat_data(im_temp, 2, no_expand=True)
    else:
        im_out = concat_data(im_list, 2)
    '''
    fname_list = [file_mask + str(iz) + '.nii' for iz in range(nz)]
    im_out = concat_data(fname_list, dim=2)
    im_out.setFileName('mask_RPI.nii.gz')
    im_out.save()

    # reorient if necessary
    # if not orientation_input == 'RPI':
    sct.run(
        'sct_image -i mask_RPI.nii.gz -o mask.nii.gz -setorient ' +
        orientation_input, param.verbose)

    # copy header input --> mask
    im_dat = Image('data.nii')
    im_mask = Image('mask.nii.gz')
    im_mask = copy_header(im_dat, im_mask)
    im_mask.save()

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

    # Generate output files
    sct.printv('\nGenerate output files...', param.verbose)
    sct.generate_output_file(path_tmp + 'mask.nii.gz', param.fname_out)

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

    # to view results
    sct.printv('\nDone! To view results, type:', param.verbose)
    sct.printv(
        'fslview ' + param.fname_data + ' ' + param.fname_out +
        ' -l Red -t 0.5 &', param.verbose, 'info')
    print
Ejemplo n.º 18
0
    def change_orientation(self, orientation='RPI', inversion_orient=False):
        """
        This function changes the orientation of the data by swapping the image axis.
        Warning: the nifti image header is not changed!!!
        :param orientation: string of three character representing the new orientation (ex: AIL, default: RPI)
               inversion_orient: boolean. If True, the data change to match the orientation in the header, based on the orientation provided as the argument orientation.
        :return:
        """
        opposite_character = {'L': 'R', 'R': 'L', 'A': 'P', 'P': 'A', 'I': 'S', 'S': 'I'}

        if self.orientation is None:
            from sct_image import get_orientation
            self.orientation = get_orientation(self)
        # get orientation to return at the end of function
        raw_orientation = self.orientation

        if inversion_orient:
            temp_orientation = self.orientation
            self.orientation = orientation
            orientation = temp_orientation

        # change the orientation of the image
        perm = [0, 1, 2]
        inversion = [1, 1, 1]
        for i, character in enumerate(self.orientation):
            try:
                perm[i] = orientation.index(character)
            except ValueError:
                perm[i] = orientation.index(opposite_character[character])
                inversion[i] = -1

        # axes inversion
        self.data = self.data[::inversion[0], ::inversion[1], ::inversion[2]]

        # axes manipulations
        from numpy import swapaxes

        if perm == [1, 0, 2]:
            self.data = swapaxes(self.data, 0, 1)
        elif perm == [2, 1, 0]:
            self.data = swapaxes(self.data, 0, 2)
        elif perm == [0, 2, 1]:
            self.data = swapaxes(self.data, 1, 2)
        elif perm == [2, 0, 1]:
            self.data = swapaxes(self.data, 0, 2)  # transform [2, 0, 1] to [1, 0, 2]
            self.data = swapaxes(self.data, 0, 1)  # transform [1, 0, 2] to [0, 1, 2]
        elif perm == [1, 2, 0]:
            self.data = swapaxes(self.data, 0, 2)  # transform [1, 2, 0] to [0, 2, 1]
            self.data = swapaxes(self.data, 1, 2)  # transform [0, 2, 1] to [0, 1, 2]
        elif perm == [0, 1, 2]:
            # do nothing
            pass
        else:
            print 'Error: wrong orientation'
        # update dim
        # http://math.stackexchange.com/questions/122916/what-is-the-inverse-cycle-of-permutation
        dim_temp = list(self.dim)
        dim_temp[0] = self.dim[[i for i, x in enumerate(perm) if x == 0][0]]  # nx
        dim_temp[1] = self.dim[[i for i, x in enumerate(perm) if x == 1][0]]  # ny
        dim_temp[2] = self.dim[[i for i, x in enumerate(perm) if x == 2][0]]  # nz
        dim_temp[4] = self.dim[[i for i, x in enumerate(perm) if x == 0][0]+4]  # px
        dim_temp[5] = self.dim[[i for i, x in enumerate(perm) if x == 1][0]+4]  # py
        dim_temp[6] = self.dim[[i for i, x in enumerate(perm) if x == 2][0]+4]  # pz
        self.dim = tuple(dim_temp)
        # update orientation
        self.orientation = orientation
        return raw_orientation