def compute(self):

        fname_data = self.fmri

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

        # # motion correct the fmri data
        # # sct.printv('\nMotion correct the fMRI data...', self.param.verbose, 'normal')
        # path_fmri, fname_fmri, ext_fmri = sct.extract_fname(self.fmri)
        # fname_fmri_moco = fname_fmri
        # # print sct.slash_at_the_end(path_fmri) + fname_fmri
        # # sct.run('mcflirt -in ' + sct.slash_at_the_end(path_fmri, 1) + fname_fmri + ' -out ' + fname_fmri_moco)

        # compute tsnr
        sct.printv('\nCompute the tSNR...', self.param.verbose, 'normal')
        fname_data_mean = sct.add_suffix(fname_data, '_mean')
        sct.run('fslmaths ' + fname_data + ' -Tmean ' + fname_data_mean)
        fname_data_std = sct.add_suffix(fname_data, '_std')
        sct.run('fslmaths ' + fname_data + ' -Tstd ' + fname_data_std)
        fname_tsnr = sct.add_suffix(fname_data, '_tsnr')
        sct.run('fslmaths ' + fname_data_mean + ' -div ' + fname_data_std + ' ' + fname_tsnr)

        # Remove temp files
        sct.printv('\nRemove temporary files...', self.param.verbose, 'normal')
        sct.run('rm ' + fname_data_std)

        # to view results
        sct.printv('\nDone! To view results, type:', self.param.verbose, 'normal')
        sct.printv('fslview '+fname_tsnr+' &\n', self.param.verbose, 'info')
Exemple #2
0
def _call_viewer_centerline(fname_in, interslice_gap=20.0):
    from spinalcordtoolbox.gui.base import AnatomicalParams
    from spinalcordtoolbox.gui.centerline import launch_centerline_dialog

    im_data = Image(fname_in)

    # Get the number of slice along the (IS) axis
    im_tmp = msct_image.change_orientation(im_data, 'RPI')
    _, _, nz, _, _, _, pz, _ = im_tmp.dim
    del im_tmp

    params = AnatomicalParams()
    # setting maximum number of points to a reasonable value
    params.num_points = np.ceil(nz * pz / interslice_gap) + 2
    params.interval_in_mm = interslice_gap
    params.starting_slice = 'top'

    im_mask_viewer = msct_image.zeros_like(im_data)
    im_mask_viewer.absolutepath = sct.add_suffix(fname_in, '_viewer')
    controller = launch_centerline_dialog(im_data, im_mask_viewer, params)
    fname_labels_viewer = sct.add_suffix(fname_in, '_viewer')

    if not controller.saved:
        sct.log.error(
            'The viewer has been closed before entering all manual points. Please try again.'
        )
        sys.exit(1)
    # save labels
    controller.as_niftii(fname_labels_viewer)

    return fname_labels_viewer
def pad_im(fname_im, nx_full, ny_full, nz_full, xi, xf, yi, yf, zi, zf):
    fname_im_pad = sct.add_suffix(fname_im, "_pad")
    pad_xi = str(xi)
    pad_xf = str(nx_full - (xf + 1))
    pad_yi = str(yi)
    pad_yf = str(ny_full - (yf + 1))
    pad_zi = str(zi)
    pad_zf = str(nz_full - (zf + 1))
    pad = ",".join([pad_xi, pad_xf, pad_yi, pad_yf, pad_zi, pad_zf])
    if len(Image(fname_im).data.shape) == 5:
        status, output = sct.run("sct_image -i " + fname_im + " -mcs")
        s = "Created file(s):\n-->"
        output_fnames = output[output.find(s) + len(s) :].split("\n")[0].split("'")
        fname_comp_list = [output_fnames[i] for i in range(1, len(output_fnames), 2)]
        fname_comp_pad_list = []
        for fname_comp in fname_comp_list:
            fname_comp_pad = sct.add_suffix(fname_comp, "_pad")
            sct.run("sct_image -i " + fname_comp + " -pad-asym " + pad + " -o " + fname_comp_pad)
            fname_comp_pad_list.append(fname_comp_pad)
        components = ",".join(fname_comp_pad_list)
        sct.run("sct_image -i " + components + " -omc -o " + fname_im_pad)
        sct.check_file_exist(fname_im_pad, verbose=1)
    else:
        sct.run("sct_image -i " + fname_im + " -pad-asym " + pad + " -o " + fname_im_pad)
    return fname_im_pad
def pad_im(fname_im, nx_full, ny_full, nz_full, xi, xf, yi, yf, zi, zf):
    fname_im_pad = sct.add_suffix(fname_im, '_pad')
    pad_xi = str(xi)
    pad_xf = str(nx_full - (xf + 1))
    pad_yi = str(yi)
    pad_yf = str(ny_full - (yf + 1))
    pad_zi = str(zi)
    pad_zf = str(nz_full - (zf + 1))
    pad = ','.join([pad_xi, pad_xf, pad_yi, pad_yf, pad_zi, pad_zf])
    if len(Image(fname_im).data.shape) == 5:
        status, output = sct.run('sct_image -i ' + fname_im + ' -mcs')
        s = 'Created file(s):\n-->'
        output_fnames = output[output.find(s) +
                               len(s):].split('\n')[0].split("'")
        fname_comp_list = [
            output_fnames[i] for i in range(1, len(output_fnames), 2)
        ]
        fname_comp_pad_list = []
        for fname_comp in fname_comp_list:
            fname_comp_pad = sct.add_suffix(fname_comp, '_pad')
            sct.run('sct_image -i ' + fname_comp + ' -pad-asym ' + pad +
                    ' -o ' + fname_comp_pad)
            fname_comp_pad_list.append(fname_comp_pad)
        components = ','.join(fname_comp_pad_list)
        sct.run('sct_image -i ' + components + ' -omc -o ' + fname_im_pad)
        sct.check_file_exist(fname_im_pad, verbose=1)
    else:
        sct.run('sct_image -i ' + fname_im + ' -pad-asym ' + pad + ' -o ' +
                fname_im_pad)
    return fname_im_pad
 def reorient_data(self):
     for f in self.fname_metric_lst:
         os.rename(self.fname_metric_lst[f], add_suffix(''.join(extract_fname(self.param.fname_im)[1:]), '_2reorient'))
         im = Image(add_suffix(''.join(extract_fname(self.param.fname_im)[1:]), '_2reorient'))
         im = set_orientation(im, self.orientation_im)
         im.setFileName(self.fname_metric_lst[f])
         im.save()
    def segment(self):
        self.copy_data_to_tmp()
        # go to tmp directory
        os.chdir(self.tmp_dir)
        # load model
        self.model.load_model()

        self.target_im, self.info_preprocessing = pre_processing(self.param_seg.fname_im, self.param_seg.fname_seg, self.param_seg.fname_level, new_res=self.param_data.axial_res, square_size_size_mm=self.param_data.square_size_size_mm, denoising=self.param_data.denoising, verbose=self.param.verbose, rm_tmp=self.param.rm_tmp)

        printv('\nRegister target image to model data...', self.param.verbose, 'normal')
        # register target image to model dictionary space
        path_warp = self.register_target()

        if self.param_data.normalization:
            printv('\nNormalize intensity of target image...', self.param.verbose, 'normal')
            self.normalize_target()

        printv('\nProject target image into the model reduced space...', self.param.verbose, 'normal')
        self.project_target()

        printv('\nCompute similarities between target slices and model slices using model reduced space...', self.param.verbose, 'normal')
        list_dic_indexes_by_slice = self.compute_similarities()

        printv('\nLabel fusion of model slices most similar to target slices...', self.param.verbose, 'normal')
        self.label_fusion(list_dic_indexes_by_slice)

        printv('\nWarp back segmentation into image space...', self.param.verbose, 'normal')
        self.warp_back_seg(path_warp)

        printv('\nPost-processing...', self.param.verbose, 'normal')
        self.im_res_gmseg, self.im_res_wmseg = self.post_processing()

        if (self.param_seg.path_results != './') and (not os.path.exists('../' + self.param_seg.path_results)):
            # create output folder
            printv('\nCreate output folder ...', self.param.verbose, 'normal')
            os.chdir('..')
            os.mkdir(self.param_seg.path_results)
            os.chdir(self.tmp_dir)

        if self.param_seg.fname_manual_gmseg is not None:
            # compute validation metrics
            printv('\nCompute validation metrics...', self.param.verbose, 'normal')
            self.validation()

        if self.param_seg.ratio is not '0':
            printv('\nCompute GM/WM CSA ratio...', self.param.verbose, 'normal')
            self.compute_ratio()

        # go back to original directory
        os.chdir('..')
        printv('\nSave resulting GM and WM segmentations...', self.param.verbose, 'normal')
        self.fname_res_gmseg = self.param_seg.path_results + add_suffix(''.join(extract_fname(self.param_seg.fname_im)[1:]), '_gmseg')
        self.fname_res_wmseg = self.param_seg.path_results + add_suffix(''.join(extract_fname(self.param_seg.fname_im)[1:]), '_wmseg')

        self.im_res_gmseg.setFileName(self.fname_res_gmseg)
        self.im_res_wmseg.setFileName(self.fname_res_wmseg)

        self.im_res_gmseg.save()
        self.im_res_wmseg.save()
    def segment(self):
        self.copy_data_to_tmp()
        # go to tmp directory
        curdir = os.getcwd()
        os.chdir(self.tmp_dir)
        # load model
        self.model.load_model()

        self.target_im, self.info_preprocessing = pre_processing(self.param_seg.fname_im, self.param_seg.fname_seg, self.param_seg.fname_level, new_res=self.param_data.axial_res, square_size_size_mm=self.param_data.square_size_size_mm, denoising=self.param_data.denoising, verbose=self.param.verbose, rm_tmp=self.param.rm_tmp)

        printv('\nRegister target image to model data...', self.param.verbose, 'normal')
        # register target image to model dictionary space
        path_warp = self.register_target()

        if self.param_data.normalization:
            printv('\nNormalize intensity of target image...', self.param.verbose, 'normal')
            self.normalize_target()

        printv('\nProject target image into the model reduced space...', self.param.verbose, 'normal')
        self.project_target()

        printv('\nCompute similarities between target slices and model slices using model reduced space...', self.param.verbose, 'normal')
        list_dic_indexes_by_slice = self.compute_similarities()

        printv('\nLabel fusion of model slices most similar to target slices...', self.param.verbose, 'normal')
        self.label_fusion(list_dic_indexes_by_slice)

        printv('\nWarp back segmentation into image space...', self.param.verbose, 'normal')
        self.warp_back_seg(path_warp)

        printv('\nPost-processing...', self.param.verbose, 'normal')
        self.im_res_gmseg, self.im_res_wmseg = self.post_processing()

        if (self.param_seg.path_results != './') and (not os.path.exists(os.path.join(curdir, self.param_seg.path_results))):
            # create output folder
            printv('\nCreate output folder ...', self.param.verbose, 'normal')
            os.chdir(curdir)
            os.mkdir(self.param_seg.path_results)
            os.chdir(self.tmp_dir)

        if self.param_seg.fname_manual_gmseg is not None:
            # compute validation metrics
            printv('\nCompute validation metrics...', self.param.verbose, 'normal')
            self.validation()

        # go back to original directory
        os.chdir(curdir)
        printv('\nSave resulting GM and WM segmentations...', self.param.verbose, 'normal')
        self.fname_res_gmseg = os.path.join(self.param_seg.path_results, add_suffix(''.join(extract_fname(self.param_seg.fname_im)[1:]), '_gmseg'))
        self.fname_res_wmseg = os.path.join(self.param_seg.path_results, add_suffix(''.join(extract_fname(self.param_seg.fname_im)[1:]), '_wmseg'))

        self.im_res_gmseg.absolutepath = self.fname_res_gmseg
        self.im_res_wmseg.absolutepath = self.fname_res_wmseg

        self.im_res_gmseg.save()
        self.im_res_wmseg.save()
Exemple #8
0
 def reorient_data(self):
     for f in self.fname_metric_lst:
         os.rename(
             self.fname_metric_lst[f],
             sct.add_suffix(
                 ''.join(sct.extract_fname(self.param.fname_im)[1:]),
                 '_2reorient'))
         im = Image(sct.add_suffix(''.join(sct.extract_fname(self.param.fname_im)[1:]), '_2reorient')) \
          .change_orientation(self.orientation_im) \
          .save(self.fname_metric_lst[f])
    def compute(self):

        fname_data = self.fmri

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

        # # motion correct the fmri data
        # # sct.printv('\nMotion correct the fMRI data...', self.param.verbose, 'normal')
        # path_fmri, fname_fmri, ext_fmri = sct.extract_fname(self.fmri)
        # fname_fmri_moco = fname_fmri
        # # print sct.slash_at_the_end(path_fmri) + fname_fmri
        # # sct.run('mcflirt -in ' + sct.slash_at_the_end(path_fmri, 1) + fname_fmri + ' -out ' + fname_fmri_moco)

        # compute tsnr
        sct.printv('\nCompute the tSNR...', self.param.verbose, 'normal')
        fname_data_mean = sct.add_suffix(fname_data, '_mean.nii')
        sct.run('sct_maths -i ' + fname_data + ' -o ' + fname_data_mean +
                ' -mean t')
        # if not average_data_across_dimension(fname_data, fname_data_mean, 3):
        #     sct.printv('ERROR in average_data_across_dimension', 1, 'error')
        # sct.run('fslmaths ' + fname_data + ' -Tmean ' + fname_data_mean)
        fname_data_std = sct.add_suffix(fname_data, '_std.nii')
        sct.run('sct_maths -i ' + fname_data + ' -o ' + fname_data_std +
                ' -mean t')
        # if not average_data_across_dimension(fname_data, fname_data_std, 3, 1):
        #     sct.printv('ERROR in average_data_across_dimension', 1, 'error')
        # sct.run('fslmaths ' + fname_data + ' -Tstd ' + fname_data_std)
        fname_tsnr = sct.add_suffix(fname_data, '_tsnr')
        from msct_image import Image
        nii_mean = Image(fname_data_mean)
        data_mean = nii_mean.data
        data_std = Image(fname_data_std).data
        data_tsnr = data_mean / data_std
        nii_tsnr = nii_mean
        nii_tsnr.data = data_tsnr
        nii_tsnr.setFileName(fname_tsnr)
        nii_tsnr.save()
        # sct.run('fslmaths ' + fname_data_mean + ' -div ' + fname_data_std + ' ' + fname_tsnr)

        # Remove temp files
        sct.printv('\nRemove temporary files...', self.param.verbose, 'normal')
        import os
        os.remove(fname_data_mean)
        os.remove(fname_data_std)

        # to view results
        sct.printv('\nDone! To view results, type:', self.param.verbose,
                   'normal')
        sct.printv('fslview ' + fname_tsnr + ' &\n', self.param.verbose,
                   'info')
    def compute(self):

        fname_data = self.fmri

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

        # # motion correct the fmri data
        # # sct.printv('\nMotion correct the fMRI data...', self.param.verbose, 'normal')
        # path_fmri, fname_fmri, ext_fmri = sct.extract_fname(self.fmri)
        # fname_fmri_moco = fname_fmri
        # # print sct.slash_at_the_end(path_fmri) + fname_fmri
        # # sct.run('mcflirt -in ' + sct.slash_at_the_end(path_fmri, 1) + fname_fmri + ' -out ' + fname_fmri_moco)

        # compute mean
        fname_data_mean = sct.add_suffix(fname_data, '_mean')
        sct_maths.main(
            args=['-i', fname_data, '-o', fname_data_mean, '-mean', 't'])

        # compute STD
        fname_data_std = sct.add_suffix(fname_data, '_std')
        sct_maths.main(
            args=['-i', fname_data, '-o', fname_data_std, '-std', 't'])

        # compute tSNR
        fname_tsnr = sct.add_suffix(fname_data, '_tsnr')
        from msct_image import Image
        nii_mean = Image(fname_data_mean)
        data_mean = nii_mean.data
        data_std = Image(fname_data_std).data
        data_tsnr = data_mean / data_std
        nii_tsnr = nii_mean
        nii_tsnr.data = data_tsnr
        nii_tsnr.setFileName(fname_tsnr)
        nii_tsnr.save()

        # Remove temp files
        sct.printv('\nRemove temporary files...', self.param.verbose, 'normal')
        import os
        os.remove(fname_data_mean)
        os.remove(fname_data_std)

        # to view results
        sct.printv('\nDone! To view results, type:', self.param.verbose,
                   'normal')
        sct.printv('fslview ' + fname_tsnr + ' &\n', self.param.verbose,
                   'info')
    def compute(self):

        fname_data = self.fmri

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

        # # motion correct the fmri data
        # # sct.printv('\nMotion correct the fMRI data...', self.param.verbose, 'normal')
        # path_fmri, fname_fmri, ext_fmri = sct.extract_fname(self.fmri)
        # fname_fmri_moco = fname_fmri
        # # print sct.slash_at_the_end(path_fmri) + fname_fmri
        # # sct.run('mcflirt -in ' + sct.slash_at_the_end(path_fmri, 1) + fname_fmri + ' -out ' + fname_fmri_moco)

        # compute tsnr
        sct.printv('\nCompute the tSNR...', self.param.verbose, 'normal')
        fname_data_mean = sct.add_suffix(fname_data, '_mean')
        sct.run('sct_maths -i '+fname_data+' -o '+fname_data_mean+' -mean t')
        # if not average_data_across_dimension(fname_data, fname_data_mean, 3):
        #     sct.printv('ERROR in average_data_across_dimension', 1, 'error')
        # sct.run('fslmaths ' + fname_data + ' -Tmean ' + fname_data_mean)
        fname_data_std = sct.add_suffix(fname_data, '_std')
        sct.run('sct_maths -i '+fname_data+' -o '+fname_data_std+' -mean t')
        # if not average_data_across_dimension(fname_data, fname_data_std, 3, 1):
        #     sct.printv('ERROR in average_data_across_dimension', 1, 'error')
        # sct.run('fslmaths ' + fname_data + ' -Tstd ' + fname_data_std)
        fname_tsnr = sct.add_suffix(fname_data, '_tsnr')
        from msct_image import Image
        nii_mean = Image(fname_data_mean)
        data_mean = nii_mean.data
        data_std = Image(fname_data_std).data
        data_tsnr = data_mean/data_std
        nii_tsnr = nii_mean
        nii_tsnr.data = data_tsnr
        nii_tsnr.setFileName(fname_tsnr)
        nii_tsnr.save()
        # sct.run('fslmaths ' + fname_data_mean + ' -div ' + fname_data_std + ' ' + fname_tsnr)

        # Remove temp files
        sct.printv('\nRemove temporary files...', self.param.verbose, 'normal')
        import os
        os.remove(fname_data_mean)
        os.remove(fname_data_std)

        # to view results
        sct.printv('\nDone! To view results, type:', self.param.verbose, 'normal')
        sct.printv('fslview '+fname_tsnr+' &\n', self.param.verbose, 'info')
def test_integrity(param_test):
    """
    Test integrity of function
    """

    fname_src = param_test.dict_args_with_path["-i"]
    fname_ref = param_test.dict_args_with_path["-d"]
    fname_dst = sct.add_suffix(os.path.basename(fname_src), "_reg")
    #fname_dst = "output.nii.gz"
    img_src = msct_image.Image(fname_src)
    img_ref = msct_image.Image(fname_ref)
    img_dst = msct_image.Image(fname_dst)

    if img_dst.orientation != img_ref.orientation:
        param_test.output += "\nImage has wrong orientation (%s -> %s)" \
         % (img_ref.orientation, img_dst.orientation)
        param_test.status = 1

    if len(img_src.data.shape) > 3:
        # Allowed failure for now
        return param_test

    if not (img_dst.data != 0).any():
        param_test.output += "\nImage is garbage (all zeros)"
        param_test.status = 1

    return param_test
def multicomponent_merge(fname_list):
    from numpy import zeros
    # WARNING: output multicomponent is not optimal yet, some issues may be related to the use of this function

    im_0 = Image(fname_list[0])
    new_shape = list(im_0.data.shape)
    if len(new_shape) == 3:
        new_shape.append(1)
    new_shape.append(len(fname_list))
    new_shape = tuple(new_shape)

    data_out = zeros(new_shape)
    for i, fname in enumerate(fname_list):
        im = Image(fname)
        dat = im.data
        if len(dat.shape) == 2:
            data_out[:, :, 0, 0, i] = dat.astype('float32')
        elif len(dat.shape) == 3:
            data_out[:, :, :, 0, i] = dat.astype('float32')
        elif len(dat.shape) == 4:
            data_out[:, :, :, :, i] = dat.astype('float32')
        del im
        del dat
    im_out = im_0.copy()
    im_out.data = data_out.astype('float32')
    im_out.hdr.set_intent('vector', (), '')
    im_out.absolutepath = sct.add_suffix(im_out.absolutepath, '_multicomponent')
    return im_out
def resample_file(fname_data, fname_out, new_size, new_size_type,
                  interpolation, verbose):
    """This function will resample the specified input
    image file to the target size.
    Can deal with 2d, 3d or 4d image objects.
    :param fname_data: The input image filename.
    :param fname_out: The output image filename.
    :param new_size: The target size, i.e. 0.25x0.25
    :param new_size_type: Unit of resample (mm, vox, factor)
    :param interpolation: The interpolation type
    :param verbose: verbosity level
    """

    # Load data
    sct.printv('\nLoad data...', verbose)
    nii = nipy.load_image(fname_data)

    nii_r = resample_image(nii, new_size, new_size_type, interpolation,
                           verbose)

    # build output file name
    if fname_out == '':
        fname_out = sct.add_suffix(fname_data, '_r')
    else:
        fname_out = fname_out

    # save data
    nipy.save_image(nii_r, fname_out)

    # to view results
    sct.display_viewer_syntax([fname_out], verbose=verbose)

    return nii_r
Exemple #15
0
def multicomponent_merge(fname_list):
    from numpy import zeros
    # WARNING: output multicomponent is not optimal yet, some issues may be related to the use of this function

    im_0 = Image(fname_list[0])
    new_shape = list(im_0.data.shape)
    if len(new_shape) == 3:
        new_shape.append(1)
    new_shape.append(len(fname_list))
    new_shape = tuple(new_shape)

    data_out = zeros(new_shape)
    for i, fname in enumerate(fname_list):
        im = Image(fname)
        dat = im.data
        if len(dat.shape) == 2:
            data_out[:, :, 0, 0, i] = dat.astype('float32')
        elif len(dat.shape) == 3:
            data_out[:, :, :, 0, i] = dat.astype('float32')
        elif len(dat.shape) == 4:
            data_out[:, :, :, :, i] = dat.astype('float32')
        del im
        del dat
    im_out = im_0.copy()
    im_out.data = data_out.astype('float32')
    im_out.hdr.set_intent('vector', (), '')
    im_out.absolutepath = sct.add_suffix(im_out.absolutepath,
                                         '_multicomponent')
    return im_out
def load_manual_gmseg(list_slices_target,
                      list_fname_manual_gmseg,
                      tmp_dir,
                      im_sc_seg_rpi,
                      new_res,
                      square_size_size_mm,
                      for_model=False,
                      fname_mask=None):
    if isinstance(list_fname_manual_gmseg, str):
        # consider fname_manual_gmseg as a list of file names to allow multiple manual GM segmentation
        list_fname_manual_gmseg = [list_fname_manual_gmseg]

    for fname_manual_gmseg in list_fname_manual_gmseg:
        os.chdir('..')
        shutil.copy(fname_manual_gmseg, tmp_dir)
        # change fname level to only file name (path = tmp dir now)
        path_gm, file_gm, ext_gm = extract_fname(fname_manual_gmseg)
        fname_manual_gmseg = file_gm + ext_gm
        os.chdir(tmp_dir)

        im_manual_gmseg = Image(fname_manual_gmseg)

        # reorient to RPI
        im_manual_gmseg = set_orientation(im_manual_gmseg, 'RPI')

        if fname_mask is not None:
            fname_gmseg_crop = add_suffix(im_manual_gmseg.absolutepath,
                                          '_pre_crop')
            crop_im = ImageCropper(input_file=im_manual_gmseg.absolutepath,
                                   output_file=fname_gmseg_crop,
                                   mask=fname_mask)
            im_manual_gmseg_crop = crop_im.crop()
            im_manual_gmseg = im_manual_gmseg_crop

        # assert gmseg has the right number of slices
        assert im_manual_gmseg.data.shape[2] == len(
            list_slices_target
        ), 'ERROR: the manual GM segmentation has not the same number of slices than the image.'

        # interpolate gm to reference image
        nz_gmseg, nx_gmseg, ny_gmseg, nt_gmseg, pz_gmseg, px_gmseg, py_gmseg, pt_gmseg = im_manual_gmseg.dim

        list_im_gm = interpolate_im_to_ref(im_manual_gmseg,
                                           im_sc_seg_rpi,
                                           new_res=new_res,
                                           sq_size_size_mm=square_size_size_mm,
                                           interpolation_mode=0)

        # load gm seg in list of slices
        n_poped = 0
        for im_gm, slice_im in zip(list_im_gm, list_slices_target):
            if im_gm.data.max() == 0 and for_model:
                list_slices_target.pop(slice_im.id - n_poped)
                n_poped += 1
            else:
                slice_im.gm_seg.append(im_gm.data)
                wm_slice = (slice_im.im > 0) - im_gm.data
                slice_im.wm_seg.append(wm_slice)

    return list_slices_target
Exemple #17
0
    def change_orientation(self,
                           orientation,
                           inverse=False,
                           generate_path=False):
        """
        Change orientation on image (in-place).

        :param orientation: orientation string (SCT "from" convention)

        :param inverse: if you think backwards, use this to specify that you actually
                        want to transform *from* the specified orientation, not *to*
                        it.
        :param generate_path: whether to create a derived path name from the
                              original absolutepath (note: while it will generate
                              a file suffix, don't expect the suffix but rather
                              use the Image's absolutepath.
                              If not set, the absolutepath is voided.

        """
        if orientation is not None:
            change_orientation(self, orientation, self, inverse=inverse)
        if generate_path and self._path is not None:
            self._path = sct.add_suffix(self._path,
                                        "_{}".format(orientation.lower()))
        else:
            # safe option: remove path to avoid overwrites
            self._path = None
        return self
Exemple #18
0
    def compute(self):

        fname_data = self.fmri

        # open data
        nii_data = Image(fname_data)
        data = nii_data.data

        # compute mean
        data_mean = np.mean(data, 3)
        # compute STD
        data_std = np.std(data, 3, ddof=1)
        # compute TSNR
        data_tsnr = data_mean / data_std

        # save TSNR
        fname_tsnr = sct.add_suffix(fname_data, '_tsnr')
        nii_tsnr = nii_data
        nii_tsnr.data = data_tsnr
        nii_tsnr.setFileName(fname_tsnr)
        nii_tsnr.save(type='float32')

        # to view results
        sct.printv('\nDone! To view results, type:', self.param.verbose, 'normal')
        sct.printv('fslview ' + fname_tsnr + ' &\n', self.param.verbose, 'info')
Exemple #19
0
def viewer_centerline(image_fname, interslice_gap, verbose):
    image_input_reoriented = Image(image_fname)
    nx, ny, nz, nt, px, py, pz, pt = image_input_reoriented.dim
    viewer = ClickViewerPropseg(image_input_reoriented)

    viewer.gap_inter_slice = int(
        interslice_gap /
        px)  # px because the image is supposed to be SAL orientation
    viewer.number_of_slices = 0
    viewer.calculate_list_slices()

    # start the viewer that ask the user to enter a few points along the spinal cord
    mask_points = viewer.start()

    if not mask_points and viewer.closed:
        mask_points = viewer.list_points_useful_notation

    if mask_points:
        # create the mask containing either the three-points or centerline mask for initialization
        mask_filename = sct.add_suffix(image_fname, "_mask_viewer")
        sct.run("sct_label_utils -i " + image_fname + " -create " +
                mask_points + " -o " + mask_filename,
                verbose=False)

        fname_output = mask_filename

    else:
        sct.printv(
            '\nERROR: the viewer has been closed before entering all manual points. Please try again.',
            1,
            type='error')
        fname_output = None

    return fname_output
Exemple #20
0
def func_rescale_header(fname_data, rescale_factor, verbose=0):
    """
    Rescale the voxel dimension by modifying the NIFTI header qform. Write the output file in a temp folder.
    :param fname_data:
    :param rescale_factor:
    :return: fname_data_rescaled
    """
    import nibabel as nib
    img = nib.load(fname_data)
    # get qform
    qform = img.header.get_qform()
    # multiply by scaling factor
    qform[0:3, 0:3] *= rescale_factor
    # generate a new nifti file
    header_rescaled = img.header.copy()
    header_rescaled.set_qform(qform)
    # the data are the same-- only the header changes
    img_rescaled = nib.nifti1.Nifti1Image(img.get_data(),
                                          None,
                                          header=header_rescaled)
    path_tmp = sct.tmp_create(basename="propseg", verbose=verbose)
    fname_data_rescaled = os.path.join(
        path_tmp, os.path.basename(sct.add_suffix(fname_data, "_rescaled")))
    nib.save(img_rescaled, fname_data_rescaled)
    return fname_data_rescaled
def resample_file(fname_data, fname_out, new_size, new_size_type,
                  interpolation, verbose):
    """This function will resample the specified input
    image file to the target size.

    :param fname_data: The input image filename.
    :param fname_out: The output image filename.
    :param new_size: The target size, i.e. 0.25x0.25
    :param new_size_type: Unit of resample (mm, vox, factor)
    :param interpolation: The interpolation type
    :param verbose: verbosity level
    """

    # Load data
    sct.printv('\nLoad data...', verbose)
    nii = nipy.load_image(fname_data)

    nii_r = resample_image(nii, new_size, new_size_type, interpolation,
                           verbose)

    # build output file name
    if fname_out == '':
        fname_out = sct.add_suffix(fname_data, '_r')
    else:
        fname_out = fname_out

    # save data
    nipy.save_image(nii_r, fname_out)

    # to view results
    sct.printv('\nDone! To view results, type:', verbose)
    sct.printv('fslview ' + fname_out + ' &', verbose, 'info')

    return nii_r
def test_integrity(param_test):
    """
    Test integrity of function
    """
    dice_segmentation = float('nan')
    # extract name of output segmentation: data_seg.nii.gz
    file_seg = os.path.join(param_test.path_output,
                            sct.add_suffix(param_test.file_input, '_seg'))
    # open output segmentation
    im_seg = Image(file_seg)
    # open ground truth
    im_seg_manual = Image(param_test.fname_gt)
    # compute dice coefficient between generated image and image from database
    dice_segmentation = compute_dice(im_seg,
                                     im_seg_manual,
                                     mode='3d',
                                     zboundaries=False)
    # display
    param_test.output += 'Computed dice: ' + str(dice_segmentation)
    param_test.output += '\nDice threshold (if computed Dice smaller: fail): ' + str(
        param_test.dice_threshold)

    if dice_segmentation < param_test.dice_threshold:
        param_test.status = 99
        param_test.output += '\n--> FAILED'
    else:
        param_test.output += '\n--> PASSED'

    # update Panda structure
    param_test.results['dice'] = dice_segmentation

    return param_test
def apply_transfo(im_src, im_dest, warp, interp='spline', rm_tmp=True):
    # create tmp dir and go in it
    tmp_dir = sct.tmp_create()
    # copy warping field to tmp dir
    sct.copy(warp, tmp_dir)
    warp = ''.join(extract_fname(warp)[1:])
    # go to tmp dir
    curdir = os.getcwd()
    os.chdir(tmp_dir)
    # save image and seg
    fname_src = 'src.nii.gz'
    im_src.save(fname_src)
    fname_dest = 'dest.nii.gz'
    im_dest.save(fname_dest)
    # apply warping field
    fname_src_reg = add_suffix(fname_src, '_reg')
    sct_apply_transfo.main(
        args=['-i', fname_src, '-d', fname_dest, '-w', warp, '-x', interp])

    im_src_reg = Image(fname_src_reg)
    # get out of tmp dir
    os.chdir(curdir)
    if rm_tmp:
        # remove tmp dir
        sct.rmtree(tmp_dir)
    # return res image
    return im_src_reg
def test_integrity(param_test):
    """
    Test integrity of function
    """

    fname_src = param_test.dict_args_with_path["-i"]
    fname_ref = param_test.dict_args_with_path["-d"]
    fname_dst = sct.add_suffix(os.path.basename(fname_src), "_reg")
    #fname_dst = "output.nii.gz"
    img_src = msct_image.Image(fname_src)
    img_ref = msct_image.Image(fname_ref)
    img_dst = msct_image.Image(fname_dst)

    if img_dst.orientation != img_ref.orientation:
        param_test.output += "\nImage has wrong orientation (%s -> %s)" \
         % (img_ref.orientation, img_dst.orientation)
        param_test.status = 1

    if len(img_src.data.shape) > 3:
        # Allowed failure for now
        return param_test

    if not (img_dst.data != 0).any():
        param_test.output += "\nImage is garbage (all zeros)"
        param_test.status = 1


    return param_test
def test_integrity(param_test):
    """
    Test integrity of function
    """
    dice_segmentation = float('nan')
    # extract name of output segmentation: data_seg.nii.gz
    file_seg = os.path.join(param_test.path_output, sct.add_suffix(param_test.file_input, '_seg'))
    # open output segmentation
    im_seg = Image(file_seg)
    # open ground truth
    im_seg_manual = Image(param_test.fname_gt)
    # compute dice coefficient between generated image and image from database
    dice_segmentation = compute_dice(im_seg, im_seg_manual, mode='3d', zboundaries=False)
    # display
    param_test.output += 'Computed dice: '+str(dice_segmentation)
    param_test.output += '\nDice threshold (if computed Dice smaller: fail): '+str(param_test.dice_threshold)

    if dice_segmentation < param_test.dice_threshold:
        param_test.status = 99
        param_test.output += '\n--> FAILED'
    else:
        param_test.output += '\n--> PASSED'

    # update Panda structure
    param_test.results['dice'] = dice_segmentation

    return param_test
Exemple #26
0
    def change_shape(self, shape, generate_path=False):
        """
        Change data shape (in-place)

        :param generate_path: whether to create a derived path name from the
                              original absolutepath (note: while it will generate
                              a file suffix, don't expect the suffix but rather
                              use the Image's absolutepath.
                              If not set, the absolutepath is voided.

        This is mostly useful for adding/removing a fourth dimension,
        you probably don't want to use this function.

        """
        if shape is not None:
            change_shape(self, shape, self)

        if generate_path and self._path is not None:
            self._path = sct.add_suffix(
                self._path,
                "_shape-{}".format("-".join([str(x) for x in shape])))
        else:
            # safe option: remove path to avoid overwrites
            self._path = None
        return self
Exemple #27
0
def register_data(im_src, im_dest, param_reg, path_copy_warp=None, rm_tmp=True):
    '''

    Parameters
    ----------
    im_src: class Image: source image
    im_dest: class Image: destination image
    param_reg: str: registration parameter
    path_copy_warp: path: path to copy the warping fields

    Returns: im_src_reg: class Image: source image registered on destination image
    -------

    '''
    # im_src and im_dest are already preprocessed (in theory: im_dest = mean_image)
    # binarize images to get seg
    im_src_seg = binarize(im_src, thr_min=1, thr_max=1)
    im_dest_seg = binarize(im_dest)
    # create tmp dir and go in it
    tmp_dir = tmp_create()
    os.chdir(tmp_dir)
    # save image and seg
    fname_src = 'src.nii.gz'
    im_src.setFileName(fname_src)
    im_src.save()
    fname_src_seg = 'src_seg.nii.gz'
    im_src_seg.setFileName(fname_src_seg)
    im_src_seg.save()
    fname_dest = 'dest.nii.gz'
    im_dest.setFileName(fname_dest)
    im_dest.save()
    fname_dest_seg = 'dest_seg.nii.gz'
    im_dest_seg.setFileName(fname_dest_seg)
    im_dest_seg.save()
    # do registration using param_reg
    sct_register_multimodal.main(args=['-i', fname_src,
                                       '-d', fname_dest,
                                       '-iseg', fname_src_seg,
                                       '-dseg', fname_dest_seg,
                                       '-param', param_reg])

    # get registration result
    fname_src_reg = add_suffix(fname_src, '_reg')
    im_src_reg = Image(fname_src_reg)
    # get out of tmp dir
    os.chdir('..')
    # copy warping fields
    if path_copy_warp is not None and os.path.isdir(os.path.abspath(path_copy_warp)):
        path_copy_warp = os.path.abspath(path_copy_warp)
        file_src = extract_fname(fname_src)[1]
        file_dest = extract_fname(fname_dest)[1]
        fname_src2dest = 'warp_' + file_src +'2' + file_dest +'.nii.gz'
        fname_dest2src = 'warp_' + file_dest +'2' + file_src +'.nii.gz'
        shutil.copy(tmp_dir +'/' + fname_src2dest, path_copy_warp + '/')
        shutil.copy(tmp_dir + '/' + fname_dest2src, path_copy_warp + '/')
    if rm_tmp:
        # remove tmp dir
        shutil.rmtree(tmp_dir)
    # return res image
    return im_src_reg, fname_src2dest, fname_dest2src
Exemple #28
0
def apply_transfo(im_src, im_dest, warp, interp='spline', rm_tmp=True):
    # create tmp dir and go in it
    tmp_dir = tmp_create()
    # copy warping field to tmp dir
    shutil.copy(warp, tmp_dir)
    warp = ''.join(extract_fname(warp)[1:])
    # go to tmp dir
    os.chdir(tmp_dir)
    # save image and seg
    fname_src = 'src.nii.gz'
    im_src.setFileName(fname_src)
    im_src.save()
    fname_dest = 'dest.nii.gz'
    im_dest.setFileName(fname_dest)
    im_dest.save()
    # apply warping field
    fname_src_reg = add_suffix(fname_src, '_reg')
    sct_apply_transfo.main(args=['-i', fname_src,
                                  '-d', fname_dest,
                                  '-w', warp,
                                  '-x', interp])

    im_src_reg = Image(fname_src_reg)
    # get out of tmp dir
    os.chdir('..')
    if rm_tmp:
        # remove tmp dir
        shutil.rmtree(tmp_dir)
    # return res image
    return im_src_reg
Exemple #29
0
def resample_file(fname_data, fname_out, new_size, new_size_type, interpolation, verbose, fname_ref=None):
    """This function will resample the specified input
    image file to the target size.
    Can deal with 2d, 3d or 4d image objects.
    :param fname_data: The input image filename.
    :param fname_out: The output image filename.
    :param new_size: The target size, i.e. 0.25x0.25
    :param new_size_type: Unit of resample (mm, vox, factor)
    :param interpolation: The interpolation type
    :param verbose: verbosity level
    :param fname_ref: Reference image to resample input image to
    """
    # Load data
    logger.info('load data...')
    nii = nib.load(fname_data)
    if fname_ref is not None:
        nii_ref = nib.load(fname_ref)
    else:
        nii_ref = None

    nii_r = resample_nib(nii, new_size.split('x'), new_size_type, img_dest=nii_ref, interpolation=interpolation)

    # build output file name
    if fname_out == '':
        fname_out = sct.add_suffix(fname_data, '_r')
    else:
        fname_out = fname_out

    # save data
    nib.save(nii_r, fname_out)

    # to view results
    sct.display_viewer_syntax([fname_out], verbose=verbose)

    return nii_r
Exemple #30
0
def main(fname_anat, fname_centerline, degree_poly, centerline_fitting, interp,
         remove_temp_files, verbose):

    # load input image
    im_anat = Image(fname_anat)
    nx, ny, nz, nt, px, py, pz, pt = im_anat.dim
    # re-oriente to RPI
    orientation_native = im_anat.orientation
    im_anat.change_orientation("RPI")

    # load centerline
    im_centerline = Image(fname_centerline).change_orientation("RPI")

    # smooth centerline and return fitted coordinates in voxel space
    x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(
        im_centerline,
        algo_fitting=centerline_fitting,
        type_window='hanning',
        window_length=50,
        nurbs_pts_number=3000,
        phys_coordinates=False,
        verbose=verbose,
        all_slices=True)

    # compute translation for each slice, such that the flattened centerline is centered in the medial plane (R-L) and
    # avoid discontinuity in slices where there is no centerline (in which case, simply copy the translation of the
    # closest Z).
    # first, get zmin and zmax spanned by the centerline (i.e. with non-zero values)
    indz_centerline = np.where(
        [np.sum(im_centerline.data[:, :, iz]) for iz in range(nz)])[0]
    zmin, zmax = indz_centerline[0], indz_centerline[-1]
    # then, extend the centerline by copying values below zmin and above zmax
    x_centerline_extended = np.concatenate([
        np.ones(zmin) * x_centerline_fit[0], x_centerline_fit,
        np.ones(nz - zmax) * x_centerline_fit[-1]
    ])

    # loop across slices and apply translation
    im_anat_flattened = msct_image.change_type(im_anat, np.float32)
    # change type to float32 because of subsequent conversion (img_as_float). See #1790

    for iz in range(nz):
        # compute translation along x (R-L)
        translation_x = x_centerline_extended[iz] - np.round(nx / 2.0)
        # apply transformation to 2D image with linear interpolation
        # tform = tf.SimilarityTransform(scale=1, rotation=0, translation=(translation_x, 0))
        tform = transform.SimilarityTransform(translation=(0, translation_x))
        # important to force input in float to skikit image, because it will output float values
        img = img_as_float(im_anat.data[:, :, iz])
        img_reg = transform.warp(img, tform)
        im_anat_flattened.data[:, :, iz] = img_reg  # img_as_uint(img_reg)

    # change back to native orientation
    im_anat_flattened.change_orientation(orientation_native)
    # save output
    fname_out = sct.add_suffix(fname_anat, '_flatten')
    im_anat_flattened.save(fname_out)

    sct.display_viewer_syntax([fname_anat, fname_out])
Exemple #31
0
def savePredictions(predictions, path_output, list_images, segmentation_image_size):
    number_of_images = len(list_images)
    predictions = numpy.reshape(predictions, [number_of_images, segmentation_image_size, segmentation_image_size, NUM_LABELS])
    predictions = predictions[:, :, :, 1]
    for i, pref in enumerate(predictions):
        im_pred = Image(pref)
        im_pred.setFileName(path_output+sct.add_suffix(list_images[i], '_pred'))
        im_pred.save()
Exemple #32
0
def prepare(list_images):
    fname_images, orientation_images = [], []
    for fname_im in list_images:
        from sct_image import orientation
        orientation_images.append(orientation(Image(fname_im), get=True, verbose=False))
        path_fname, file_fname, ext_fname = sct.extract_fname(fname_im)
        reoriented_image_filename = 'tmp.' + sct.add_suffix(file_fname + ext_fname, "_SAL")
        sct.run('sct_image -i ' + fname_im + ' -o ' + reoriented_image_filename + ' -setorient SAL -v 0', verbose=False)
        fname_images.append(reoriented_image_filename)
    return fname_images, orientation_images
    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
Exemple #34
0
def label_segmentation(fname_seg, list_disc_z, list_disc_value, verbose=1):
    """
    Label segmentation image

    :param fname_seg: fname of the segmentation, no orientation expected
    :param list_disc_z: list of z that correspond to a disc
    :param list_disc_value: list of associated disc values
    :param verbose:
    :return:
    """

    # open segmentation
    seg = Image(fname_seg)
    init_orientation = seg.orientation
    seg.change_orientation("RPI")

    dim = seg.dim
    ny = dim[1]
    nz = dim[2]
    # loop across z
    for iz in range(nz):
        # get index of the disc right above iz
        try:
            ind_above_iz = max(
                [i for i in range(len(list_disc_z)) if list_disc_z[i] > iz])
        except ValueError:
            # if ind_above_iz is empty, attribute value 0
            vertebral_level = 0
        else:
            # assign vertebral level (add one because iz is BELOW the disk)
            vertebral_level = list_disc_value[ind_above_iz] + 1
            # sct.printv(vertebral_level)
        # get voxels in mask
        ind_nonzero = np.nonzero(seg.data[:, :, iz])
        seg.data[ind_nonzero[0], ind_nonzero[1], iz] = vertebral_level
        # if verbose == 2:
        #     # move to OO. No time to finish... (JCA)
        #     from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
        #     from matplotlib.figure import Figure
        #     fig = Figure()
        #     FigureCanvas(fig)
        #     ax = fig.add_subplot(111)
        #     ax.scatter(int(np.round(ny / 2)), iz, c=vertebral_level, vmin=min(list_disc_value),
        #                vmax=max(list_disc_value), cmap='prism', marker='_', s=200)
        #
        #     # TODO: the thing below crashes with the py3k move. Fix it when i have time...
        #     import matplotlib
        #     matplotlib.use('Agg')
        #     import matplotlib.pyplot as plt
        #     plt.figure(50)
        #     plt.scatter(int(np.round(ny / 2)), iz, c=vertebral_level, vmin=min(list_disc_value), vmax=max(list_disc_value), cmap='prism', marker='_', s=200)

    # write file
    seg.change_orientation(init_orientation).save(
        sct.add_suffix(fname_seg, '_labeled'))
def project_labels_on_spinalcord(fname_label, fname_seg):
    """
    Project labels orthogonally on the spinal cord centerline. The algorithm works by finding the smallest distance
    between each label and the spinal cord center of mass.
    :param fname_label: file name of labels
    :param fname_seg: file name of cord segmentation (could also be of centerline)
    :return: file name of projected labels
    """
    # build output name
    fname_label_projected = sct.add_suffix(fname_label, "_projected")
    # open labels and segmentation
    im_label = Image(fname_label).change_orientation("RPI")
    im_seg = Image(fname_seg)
    native_orient = im_seg.orientation
    im_seg.change_orientation("RPI")

    # smooth centerline and return fitted coordinates in voxel space
    _, arr_ctl, _ = get_centerline(im_seg, algo_fitting='bspline')
    x_centerline_fit, y_centerline_fit, z_centerline = arr_ctl
    # convert pixel into physical coordinates
    centerline_xyz_transposed = \
        [im_seg.transfo_pix2phys([[x_centerline_fit[i], y_centerline_fit[i], z_centerline[i]]])[0]
                                 for i in range(len(x_centerline_fit))]
    # transpose list
    centerline_phys_x = [i[0] for i in centerline_xyz_transposed]
    centerline_phys_y = [i[1] for i in centerline_xyz_transposed]
    centerline_phys_z = [i[2] for i in centerline_xyz_transposed]
    # get center of mass of label
    labels = im_label.getCoordinatesAveragedByValue()
    # initialize image of projected labels. Note that we use the space of the seg (not label).
    im_label_projected = msct_image.zeros_like(im_seg, dtype=np.uint8)

    # loop across label values
    for label in labels:
        # convert pixel into physical coordinates for the label
        label_phys_x, label_phys_y, label_phys_z = im_label.transfo_pix2phys([[label.x, label.y, label.z]])[0]
        # calculate distance between label and each point of the centerline
        distance_centerline = [np.linalg.norm([centerline_phys_x[i] - label_phys_x,
                                               centerline_phys_y[i] - label_phys_y,
                                               centerline_phys_z[i] - label_phys_z])
                               for i in range(len(x_centerline_fit))]
        # get the index corresponding to the min distance
        ind_min_distance = np.argmin(distance_centerline)
        # get centerline coordinate (in physical space)
        [min_phy_x, min_phy_y, min_phy_z] = [centerline_phys_x[ind_min_distance],
                                             centerline_phys_y[ind_min_distance],
                                             centerline_phys_z[ind_min_distance]]
        # convert coordinate to voxel space
        minx, miny, minz = im_seg.transfo_phys2pix([[min_phy_x, min_phy_y, min_phy_z]])[0]
        # use that index to assign projected label in the centerline
        im_label_projected.data[minx, miny, minz] = label.value
    # re-orient projected labels to native orientation and save
    im_label_projected.change_orientation(native_orient).save(fname_label_projected)
    return fname_label_projected
Exemple #36
0
def pad_image(im,
              pad_x_i=0,
              pad_x_f=0,
              pad_y_i=0,
              pad_y_f=0,
              pad_z_i=0,
              pad_z_f=0):

    nx, ny, nz, nt, px, py, pz, pt = im.dim
    pad_x_i, pad_x_f, pad_y_i, pad_y_f, pad_z_i, pad_z_f = int(pad_x_i), int(
        pad_x_f), int(pad_y_i), int(pad_y_f), int(pad_z_i), int(pad_z_f)

    if len(im.data.shape) == 2:
        new_shape = list(im.data.shape)
        new_shape.append(1)
        im.data = im.data.reshape(new_shape)

    # initialize padded_data, with same type as im.data
    padded_data = np.zeros((nx + pad_x_i + pad_x_f, ny + pad_y_i + pad_y_f,
                            nz + pad_z_i + pad_z_f),
                           dtype=im.data.dtype)

    if pad_x_f == 0:
        pad_x_f = None
    elif pad_x_f > 0:
        pad_x_f *= -1
    if pad_y_f == 0:
        pad_y_f = None
    elif pad_y_f > 0:
        pad_y_f *= -1
    if pad_z_f == 0:
        pad_z_f = None
    elif pad_z_f > 0:
        pad_z_f *= -1

    padded_data[pad_x_i:pad_x_f, pad_y_i:pad_y_f, pad_z_i:pad_z_f] = im.data
    im_out = im.copy()
    # TODO: Do not copy the Image(), because the dim field and hdr.get_data_shape() will not be updated properly.
    #   better to just create a new Image() from scratch.
    im_out.data = padded_data  # done after the call of the function
    im_out.absolutepath = sct.add_suffix(im_out.absolutepath, "_pad")

    # adapt the origin in the sform and qform matrix
    new_origin = np.dot(im_out.hdr.get_qform(),
                        [-pad_x_i, -pad_y_i, -pad_z_i, 1])

    im_out.hdr.structarr['qoffset_x'] = new_origin[0]
    im_out.hdr.structarr['qoffset_y'] = new_origin[1]
    im_out.hdr.structarr['qoffset_z'] = new_origin[2]
    im_out.hdr.structarr['srow_x'][-1] = new_origin[0]
    im_out.hdr.structarr['srow_y'][-1] = new_origin[1]
    im_out.hdr.structarr['srow_z'][-1] = new_origin[2]

    return im_out
Exemple #37
0
def project_labels_on_spinalcord(fname_label, fname_seg, param_centerline):
    """
    Project labels orthogonally on the spinal cord centerline. The algorithm works by finding the smallest distance
    between each label and the spinal cord center of mass.
    :param fname_label: file name of labels
    :param fname_seg: file name of cord segmentation (could also be of centerline)
    :return: file name of projected labels
    """
    # build output name
    fname_label_projected = sct.add_suffix(fname_label, "_projected")
    # open labels and segmentation
    im_label = Image(fname_label).change_orientation("RPI")
    im_seg = Image(fname_seg)
    native_orient = im_seg.orientation
    im_seg.change_orientation("RPI")

    # smooth centerline and return fitted coordinates in voxel space
    _, arr_ctl, _, _ = get_centerline(im_seg, param_centerline)
    x_centerline_fit, y_centerline_fit, z_centerline = arr_ctl
    # convert pixel into physical coordinates
    centerline_xyz_transposed = \
        [im_seg.transfo_pix2phys([[x_centerline_fit[i], y_centerline_fit[i], z_centerline[i]]])[0]
                                 for i in range(len(x_centerline_fit))]
    # transpose list
    centerline_phys_x = [i[0] for i in centerline_xyz_transposed]
    centerline_phys_y = [i[1] for i in centerline_xyz_transposed]
    centerline_phys_z = [i[2] for i in centerline_xyz_transposed]
    # get center of mass of label
    labels = im_label.getCoordinatesAveragedByValue()
    # initialize image of projected labels. Note that we use the space of the seg (not label).
    im_label_projected = msct_image.zeros_like(im_seg, dtype=np.uint8)

    # loop across label values
    for label in labels:
        # convert pixel into physical coordinates for the label
        label_phys_x, label_phys_y, label_phys_z = im_label.transfo_pix2phys([[label.x, label.y, label.z]])[0]
        # calculate distance between label and each point of the centerline
        distance_centerline = [np.linalg.norm([centerline_phys_x[i] - label_phys_x,
                                               centerline_phys_y[i] - label_phys_y,
                                               centerline_phys_z[i] - label_phys_z])
                               for i in range(len(x_centerline_fit))]
        # get the index corresponding to the min distance
        ind_min_distance = np.argmin(distance_centerline)
        # get centerline coordinate (in physical space)
        [min_phy_x, min_phy_y, min_phy_z] = [centerline_phys_x[ind_min_distance],
                                             centerline_phys_y[ind_min_distance],
                                             centerline_phys_z[ind_min_distance]]
        # convert coordinate to voxel space
        minx, miny, minz = im_seg.transfo_phys2pix([[min_phy_x, min_phy_y, min_phy_z]])[0]
        # use that index to assign projected label in the centerline
        im_label_projected.data[minx, miny, minz] = label.value
    # re-orient projected labels to native orientation and save
    im_label_projected.change_orientation(native_orient).save(fname_label_projected)
    return fname_label_projected
    def __init__(self, im, v=1):
        sct.printv('Thinning ... ', v, 'normal')
        self.image = im
        self.image.data = bin_data(self.image.data)
        self.dim_im = len(self.image.data.shape)

        if self.dim_im == 2:
            self.thinned_image = msct_image.empty_like(self.image)
            self.thinned_image.data = self.zhang_suen(self.image.data)
            self.thinned_image.absolutepath = sct.add_suffix(self.image.absolutepath, "_thinned")

        elif self.dim_im == 3:
            if not self.image.orientation == 'IRP':
                sct.printv('-- changing orientation ...')
                self.image.change_orientation('IRP')

            thinned_data = np.asarray([self.zhang_suen(im_slice) for im_slice in self.image.data])

            self.thinned_image = msct_image.empty_like(self.image)
            self.thinned_image.data = thinned_data
            self.thinned_image.absolutepath = sct.add_suffix(self.image.absolutepath, "_thinned")
    def __init__(self, im, v=1):
        sct.printv('Thinning ... ', v, 'normal')
        self.image = im
        self.image.data = bin_data(self.image.data)
        self.dim_im = len(self.image.data.shape)

        if self.dim_im == 2:
            self.thinned_image = msct_image.empty_like(self.image)
            self.thinned_image.data = self.zhang_suen(self.image.data)
            self.thinned_image.absolutepath = sct.add_suffix(self.image.absolutepath, "_thinned")

        elif self.dim_im == 3:
            if not self.image.orientation == 'IRP':
                sct.printv('-- changing orientation ...')
                self.image.change_orientation('IRP')

            thinned_data = np.asarray([self.zhang_suen(im_slice) for im_slice in self.image.data])

            self.thinned_image = msct_image.empty_like(self.image)
            self.thinned_image.data = thinned_data
            self.thinned_image.absolutepath = sct.add_suffix(self.image.absolutepath, "_thinned")
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 = im_in.orientation
    if orientation != 'RPI':
        fname = im_in.change_orientation(im_in, 'RPI', generate_path=True).save().absolutepath

    nx, ny, nz, nt, px, py, pz, pt = im_in.dim

    if np.round(px, 2) != np.round(npx, 2) or np.round(py, 2) != np.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 conversion problem with 2d data
            # TODO: check if this above problem is still present (now that we are using nibabel instead of nipy)
            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.save(name_resample)

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

        if orientation != 'RPI':
            name_resample = Image(name_resample) \
             .change_orientation(orientation, generate_path=True) \
             .save() \
             .absolutepath

        return name_resample
    else:
        if orientation != 'RPI':
            fname = sct.add_suffix(fname, "_RPI")
            im_in = msct_image.change_orientation(im_in, orientation).save(fname)

        sct.printv('Image resolution already ' + str(npx) + 'x' + str(npy) + 'xpz')
        return fname
def main(args=None):

    parser = get_parser()
    param = Param()

    arguments = parser.parse(sys.argv[1:])
    fname_src = arguments['-i']
    fname_dst = arguments.get("-o", sct.add_suffix(fname_src, "_tsnr"))
    verbose = int(arguments['-v'])

    # call main function
    tsnr = Tsnr(param=param, fmri=fname_src, out=fname_dst)
    tsnr.compute()
def crop_im(fname_im, fname_mask):
    fname_im_crop = sct.add_suffix(fname_im, "_crop")
    status, output_crop = sct.run("sct_crop_image -i " + fname_im + " -m " + fname_mask + " -o " + fname_im_crop)
    output_list = output_crop.split("\n")
    xi, xf, yi, yf, zi, zf = 0, 0, 0, 0, 0, 0
    for line in output_list:
        if "Dimension 0" in line:
            dim, i, xi, xf = line.split(" ")
        if "Dimension 1" in line:
            dim, i, yi, yf = line.split(" ")
        if "Dimension 2" in line:
            dim, i, zi, zf = line.split(" ")
    return fname_im_crop, int(xi), int(xf), int(yi), int(yf), int(zi), int(zf)
Exemple #43
0
def crop_im(fname_im, fname_mask):
    fname_im_crop = sct.add_suffix(fname_im, '_crop')
    status, output_crop = sct.run(['sct_crop_image', '-i', fname_im, '-m', fname_mask, '-o', fname_im_crop])
    output_list = output_crop.split('\n')
    xi, xf, yi, yf, zi, zf = 0, 0, 0, 0, 0, 0
    for line in output_list:
        if 'Dimension 0' in line:
            dim, i, xi, xf = line.split(' ')
        if 'Dimension 1' in line:
            dim, i, yi, yf = line.split(' ')
        if 'Dimension 2' in line:
            dim, i, zi, zf = line.split(' ')
    return fname_im_crop, int(xi), int(xf), int(yi), int(yf), int(zi), int(zf)
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 = im_in.orientation
    if orientation != 'RPI':
        fname = im_in.change_orientation(im_in, 'RPI', generate_path=True).save().absolutepath

    nx, ny, nz, nt, px, py, pz, pt = im_in.dim

    if np.round(px, 2) != np.round(npx, 2) or np.round(py, 2) != np.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.save(name_resample)

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

        if orientation != 'RPI':
            name_resample = Image(name_resample) \
             .change_orientation(orientation, generate_path=True) \
             .save() \
             .absolutepath

        return name_resample
    else:
        if orientation != 'RPI':
            fname = sct.add_suffix(fname, "_RPI")
            im_in = msct_image.change_orientation(im_in, orientation).save(fname)

        sct.printv('Image resolution already ' + str(npx) + 'x' + str(npy) + 'xpz')
        return fname
Exemple #45
0
    def change_type(self, dtype, generate_path=False):
        """
        Change data type on image.

        Note: the image path is voided.
        """
        if dtype is not None:
            change_type(self, dtype, self)
        if generate_path and self._path is not None:
            self._path = sct.add_suffix(self._path, "_{}".format(dtype.name))
        else:
            # safe option: remove path to avoid overwrites
            self._path = None
        return self
    def compute_texture(self):

        offset = int(self.param_glcm.distance)
        sct.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.change_orientation(self.orientation_extraction)

        dct_metric = {}
        for m in self.metric_lst:
            im_2save = msct_image.zeros_like(im_tmp, dtype='float64')
            dct_metric[m] = im_2save
            # dct_metric[m] = Image(self.fname_metric_lst[m])

        with tqdm.tqdm() as pbar:
            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], [np.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]

                        pbar.set_postfix(pos="{}/{}".format(zz, len(self.dct_im_seg["im"])))
                        pbar.update(1)

        for m in self.metric_lst:
            fname_out = sct.add_suffix(''.join(sct.extract_fname(self.param.fname_im)[1:]), '_' + m)
            dct_metric[m].save(fname_out)
            self.fname_metric_lst[m] = fname_out
def load_manual_gmseg(list_slices_target, list_fname_manual_gmseg, tmp_dir, im_sc_seg_rpi, new_res, square_size_size_mm, for_model=False, fname_mask=None):
    if isinstance(list_fname_manual_gmseg, str):
        # consider fname_manual_gmseg as a list of file names to allow multiple manual GM segmentation
        list_fname_manual_gmseg = [list_fname_manual_gmseg]

    curdir = os.getcwd()

    for fname_manual_gmseg in list_fname_manual_gmseg:
        sct.copy(fname_manual_gmseg, tmp_dir)
        # change fname level to only file name (path = tmp dir now)
        path_gm, file_gm, ext_gm = extract_fname(fname_manual_gmseg)
        fname_manual_gmseg = file_gm + ext_gm
        os.chdir(tmp_dir)

        im_manual_gmseg = Image(fname_manual_gmseg).change_orientation("RPI")

        if fname_mask is not None:
            fname_gmseg_crop = add_suffix(im_manual_gmseg.absolutepath, '_pre_crop')
            crop_im = ImageCropper(input_file=im_manual_gmseg.absolutepath, output_file=fname_gmseg_crop,
                                   mask=fname_mask)
            im_manual_gmseg_crop = crop_im.crop()
            im_manual_gmseg = im_manual_gmseg_crop

        # assert gmseg has the right number of slices
        assert im_manual_gmseg.data.shape[2] == len(list_slices_target), 'ERROR: the manual GM segmentation has not the same number of slices than the image.'

        # interpolate gm to reference image
        nz_gmseg, nx_gmseg, ny_gmseg, nt_gmseg, pz_gmseg, px_gmseg, py_gmseg, pt_gmseg = im_manual_gmseg.dim

        list_im_gm = interpolate_im_to_ref(im_manual_gmseg, im_sc_seg_rpi, new_res=new_res, sq_size_size_mm=square_size_size_mm, interpolation_mode=0)

        # load gm seg in list of slices
        n_poped = 0
        for im_gm, slice_im in zip(list_im_gm, list_slices_target):
            if im_gm.data.max() == 0 and for_model:
                list_slices_target.pop(slice_im.id - n_poped)
                n_poped += 1
            else:
                slice_im.gm_seg.append(im_gm.data)
                wm_slice = (slice_im.im > 0) - im_gm.data
                slice_im.wm_seg.append(wm_slice)

        os.chdir(curdir)

    return list_slices_target
def pad_image(im, pad_x_i=0, pad_x_f=0, pad_y_i=0, pad_y_f=0, pad_z_i=0, pad_z_f=0):

    nx, ny, nz, nt, px, py, pz, pt = im.dim
    pad_x_i, pad_x_f, pad_y_i, pad_y_f, pad_z_i, pad_z_f = int(pad_x_i), int(pad_x_f), int(pad_y_i), int(pad_y_f), int(pad_z_i), int(pad_z_f)

    if len(im.data.shape) == 2:
        new_shape = list(im.data.shape)
        new_shape.append(1)
        im.data = im.data.reshape(new_shape)

    # initialize padded_data, with same type as im.data
    padded_data = np.zeros((nx + pad_x_i + pad_x_f, ny + pad_y_i + pad_y_f, nz + pad_z_i + pad_z_f), dtype=im.data.dtype)

    if pad_x_f == 0:
        pad_x_f = None
    elif pad_x_f > 0:
        pad_x_f *= -1
    if pad_y_f == 0:
        pad_y_f = None
    elif pad_y_f > 0:
        pad_y_f *= -1
    if pad_z_f == 0:
        pad_z_f = None
    elif pad_z_f > 0:
        pad_z_f *= -1

    padded_data[pad_x_i:pad_x_f, pad_y_i:pad_y_f, pad_z_i:pad_z_f] = im.data
    im_out = im.copy()
    # TODO: Do not copy the Image(), because the dim field and hdr.get_data_shape() will not be updated properly.
    #   better to just create a new Image() from scratch.
    im_out.data = padded_data  # done after the call of the function
    im_out.absolutepath = sct.add_suffix(im_out.absolutepath, "_pad")

    # adapt the origin in the sform and qform matrix
    new_origin = np.dot(im_out.hdr.get_qform(), [-pad_x_i, -pad_y_i, -pad_z_i, 1])

    im_out.hdr.structarr['qoffset_x'] = new_origin[0]
    im_out.hdr.structarr['qoffset_y'] = new_origin[1]
    im_out.hdr.structarr['qoffset_z'] = new_origin[2]
    im_out.hdr.structarr['srow_x'][-1] = new_origin[0]
    im_out.hdr.structarr['srow_y'][-1] = new_origin[1]
    im_out.hdr.structarr['srow_z'][-1] = new_origin[2]

    return im_out
def main(fname_anat, fname_centerline, verbose):
    """
    Main function
    :param fname_anat:
    :param fname_centerline:
    :param verbose:
    :return:
    """
    # load input images
    im_anat = Image(fname_anat)
    im_centerline = Image(fname_centerline)

    # flatten sagittal
    im_anat_flattened = flatten_sagittal(im_anat, im_centerline, verbose)

    # save output
    fname_out = sct.add_suffix(fname_anat, '_flatten')
    im_anat_flattened.save(fname_out)

    sct.display_viewer_syntax([fname_anat, fname_out])
def run_main():
    parser = get_parser()
    arguments = parser.parse(sys.argv[1:])
    input_filename = arguments["-i"]

    try:
        output_filename = arguments["-o"]
    except KeyError:
        output_filename = sct.add_suffix(input_filename, '_gmseg')

    use_tta = "-t" in arguments
    model_name = arguments["-m"]
    threshold = arguments['-thr']
    verbose = int(arguments.get('-v'))
    sct.init_sct(log_level=verbose, update=True)  # Update log level

    if threshold > 1.0 or threshold < 0.0:
        raise RuntimeError("Threshold should be between 0.0 and 1.0.")

    # Threshold zero means no thresholding
    if threshold == 0.0:
        threshold = None

    from spinalcordtoolbox.deepseg_gm import deepseg_gm
    deepseg_gm.check_backend()

    out_fname = deepseg_gm.segment_file(input_filename, output_filename,
                                        model_name, threshold, int(verbose),
                                        use_tta)

    path_qc = arguments.get("-qc", None)
    qc_dataset = arguments.get("-qc-dataset", None)
    qc_subject = arguments.get("-qc-subject", None)
    if path_qc is not None:
        generate_qc(fname_in1=input_filename, fname_seg=out_fname, args=sys.argv[1:], path_qc=os.path.abspath(path_qc),
                    dataset=qc_dataset, subject=qc_subject, process='sct_deepseg_gm')

    sct.display_viewer_syntax([input_filename, format(out_fname)],
                              colormaps=['gray', 'red'],
                              opacities=['1', '0.7'],
                              verbose=verbose)
def func_rescale_header(fname_data, rescale_factor, verbose=0):
    """
    Rescale the voxel dimension by modifying the NIFTI header qform. Write the output file in a temp folder.
    :param fname_data:
    :param rescale_factor:
    :return: fname_data_rescaled
    """
    import nibabel as nib
    img = nib.load(fname_data)
    # get qform
    qform = img.header.get_qform()
    # multiply by scaling factor
    qform[0:3, 0:3] *= rescale_factor
    # generate a new nifti file
    header_rescaled = img.header.copy()
    header_rescaled.set_qform(qform)
    # the data are the same-- only the header changes
    img_rescaled = nib.nifti1.Nifti1Image(img.get_data(), None, header=header_rescaled)
    path_tmp = sct.tmp_create(basename="propseg", verbose=verbose)
    fname_data_rescaled = os.path.join(path_tmp, os.path.basename(sct.add_suffix(fname_data, "_rescaled")))
    nib.save(img_rescaled, fname_data_rescaled)
    return fname_data_rescaled
def visualize_warp(fname_warp, fname_grid=None, step=3, rm_tmp=True):
    if fname_grid is None:
        from numpy import zeros

        tmp_dir = sct.tmp_create()
        im_warp = Image(fname_warp)
        os.chdir(tmp_dir)

        assert len(im_warp.data.shape) == 5, "ERROR: Warping field does bot have 5 dimensions..."
        nx, ny, nz, nt, ndimwarp = im_warp.data.shape

        # nx, ny, nz, nt, px, py, pz, pt = im_warp.dim
        # This does not work because dimensions of a warping field are not correctly read : it would be 1,1,1,1,1,1,1,1

        sq = zeros((step, step))
        sq[step - 1] = 1
        sq[:, step - 1] = 1
        dat = zeros((nx, ny, nz))
        for i in range(0, dat.shape[0], step):
            for j in range(0, dat.shape[1], step):
                for k in range(dat.shape[2]):
                    if dat[i : i + step, j : j + step, k].shape == (step, step):
                        dat[i : i + step, j : j + step, k] = sq
        fname_grid = "grid_" + str(step) + ".nii.gz"
        im_grid = Image(param=dat)
        grid_hdr = im_warp.hdr
        im_grid.hdr = grid_hdr
        im_grid.setFileName(fname_grid)
        im_grid.save()
        fname_grid_resample = sct.add_suffix(fname_grid, "_resample")
        sct.run("sct_resample -i " + fname_grid + " -f 3x3x1 -x nn -o " + fname_grid_resample)
        fname_grid = tmp_dir + fname_grid_resample
        os.chdir("..")
    path_warp, file_warp, ext_warp = sct.extract_fname(fname_warp)
    grid_warped = path_warp + "grid_warped_gm" + ext_warp
    sct.run("sct_apply_transfo -i " + fname_grid + " -d " + fname_grid + " -w " + fname_warp + " -o " + grid_warped)
    if rm_tmp:
        sct.run("rm -rf " + tmp_dir, error_exit="warning")
    return grid_warped
Exemple #53
0
def visualize_warp(fname_warp, fname_grid=None, step=3, rm_tmp=True):
    if fname_grid is None:
        from numpy import zeros
        tmp_dir = tmp_create()
        im_warp = Image(fname_warp)
        status, out = run('fslhd '+fname_warp)
        from os import chdir
        chdir(tmp_dir)
        dim1 = 'dim1           '
        dim2 = 'dim2           '
        dim3 = 'dim3           '
        nx = int(out[out.find(dim1):][len(dim1):out[out.find(dim1):].find('\n')])
        ny = int(out[out.find(dim2):][len(dim2):out[out.find(dim2):].find('\n')])
        nz = int(out[out.find(dim3):][len(dim3):out[out.find(dim3):].find('\n')])
        sq = zeros((step, step))
        sq[step-1] = 1
        sq[:, step-1] = 1
        dat = zeros((nx, ny, nz))
        for i in range(0, dat.shape[0], step):
            for j in range(0, dat.shape[1], step):
                for k in range(dat.shape[2]):
                    if dat[i:i+step, j:j+step, k].shape == (step, step):
                        dat[i:i+step, j:j+step, k] = sq
        fname_grid = 'grid_'+str(step)+'.nii.gz'
        im_grid = Image(param=dat)
        grid_hdr = im_warp.hdr
        im_grid.hdr = grid_hdr
        im_grid.setFileName(fname_grid)
        im_grid.save()
        fname_grid_resample = add_suffix(fname_grid, '_resample')
        run('sct_resample -i '+fname_grid+' -f 3x3x1 -x nn -o '+fname_grid_resample)
        fname_grid = tmp_dir+fname_grid_resample
        chdir('..')
    path_warp, file_warp, ext_warp = extract_fname(fname_warp)
    grid_warped = path_warp+extract_fname(fname_grid)[1]+'_'+file_warp+ext_warp
    run('sct_apply_transfo -i '+fname_grid+' -d '+fname_grid+' -w '+fname_warp+' -o '+grid_warped)
    if rm_tmp:
        run('rm -rf '+tmp_dir, error_exit='warning')
def visualize_warp(fname_warp, fname_grid=None, step=3, rm_tmp=True):
    if fname_grid is None:
        from numpy import zeros
        tmp_dir = sct.tmp_create()
        im_warp = Image(fname_warp)
        status, out = sct.run(['fslhd', fname_warp])
        curdir = os.getcwd()
        os.chdir(tmp_dir)
        dim1 = 'dim1           '
        dim2 = 'dim2           '
        dim3 = 'dim3           '
        nx = int(out[out.find(dim1):][len(dim1):out[out.find(dim1):].find('\n')])
        ny = int(out[out.find(dim2):][len(dim2):out[out.find(dim2):].find('\n')])
        nz = int(out[out.find(dim3):][len(dim3):out[out.find(dim3):].find('\n')])
        sq = zeros((step, step))
        sq[step - 1] = 1
        sq[:, step - 1] = 1
        dat = zeros((nx, ny, nz))
        for i in range(0, dat.shape[0], step):
            for j in range(0, dat.shape[1], step):
                for k in range(dat.shape[2]):
                    if dat[i:i + step, j:j + step, k].shape == (step, step):
                        dat[i:i + step, j:j + step, k] = sq
        fname_grid = 'grid_' + str(step) + '.nii.gz'
        im_grid = Image(param=dat)
        grid_hdr = im_warp.hdr
        im_grid.hdr = grid_hdr
        im_grid.absolutepath = fname_grid
        im_grid.save()
        fname_grid_resample = sct.add_suffix(fname_grid, '_resample')
        sct.run(['sct_resample', '-i', fname_grid, '-f', '3x3x1', '-x', 'nn', '-o', fname_grid_resample])
        fname_grid = os.path.join(tmp_dir, fname_grid_resample)
        os.chdir(curdir)
    path_warp, file_warp, ext_warp = sct.extract_fname(fname_warp)
    grid_warped = os.path.join(path_warp, sct.extract_fname(fname_grid)[1] + '_' + file_warp + ext_warp)
    sct.run(['sct_apply_transfo', '-i', fname_grid, '-d', fname_grid, '-w', fname_warp, '-o', grid_warped])
    if rm_tmp:
        sct.rmtree(tmp_dir)
def test_integrity(param_test):
    """
    Test integrity of function
    """
    # initializations
    distance_detection = float('nan')

    # extract name of output centerline: data_centerline_optic.nii.gz
    file_pmj = os.path.join(param_test.path_output, sct.add_suffix(param_test.file_input, '_pmj'))

    # open output segmentation
    im_pmj = Image(file_pmj)

    # open ground truth
    im_pmj_manual = Image(param_test.fname_gt)

    # compute Euclidean distance between predicted and GT PMJ label
    x_true, y_true, z_true = np.where(im_pmj_manual.data == 50)
    x_pred, y_pred, z_pred = np.where(im_pmj.data == 50)

    x_true, y_true, z_true = im_pmj_manual.transfo_pix2phys([[x_true[0], y_true[0], z_true[0]]])[0]
    x_pred, y_pred, z_pred = im_pmj.transfo_pix2phys([[x_pred[0], y_pred[0], z_pred[0]]])[0]

    distance_detection = math.sqrt(((x_true - x_pred))**2 + ((y_true - y_pred))**2 + ((z_true - z_pred))**2)

    param_test.output += 'Computed distance: ' + str(distance_detection)
    param_test.output += 'Distance threshold (if computed Distance higher: fail): ' + str(param_test.dist_threshold)

    if distance_detection > param_test.dist_threshold:
        param_test.status = 99
        param_test.output += '--> FAILED'
    else:
        param_test.output += '--> PASSED'

    # update Panda structure
    param_test.results['distance_detection'] = distance_detection

    return param_test
def test_integrity(param_test):
    """
    Test integrity of function
    """

    # open ground truth
    im_seg_manual = Image(param_test.fname_gt).change_orientation("RPI")

    # Compute center of mass of the SC seg on each axial slice.
    center_of_mass_x_y_z_lst = [[int(center_of_mass(im_seg_manual.data[:, :, zz])[0]),
                                 int(center_of_mass(im_seg_manual.data[:, :, zz])[1]),
                                 zz] for zz in range(im_seg_manual.dim[2])]

    im_ctr_manual = msct_image.zeros_like(im_seg_manual)
    for x_y_z in center_of_mass_x_y_z_lst:
        im_ctr_manual.data[x_y_z[0], x_y_z[1], x_y_z[2]] = 1

    # open output segmentation
    path_in, file_in, _ = sct.extract_fname(param_test.file_input)
    file_ctr = os.path.join(param_test.path_data, 't2s', sct.add_suffix(param_test.file_input, '_centerline'))
    im_ctr = Image(file_ctr).change_orientation("RPI")

    # compute MSE between generated ctr and ctr from database
    mse_detection = compute_mse(im_ctr, im_ctr_manual)

    param_test.output += 'Computed MSE: ' + str(mse_detection)
    param_test.output += 'MSE threshold (if computed MSE higher: fail): ' + str(param_test.mse_threshold)

    if mse_detection > param_test.mse_threshold:
        param_test.status = 99
        param_test.output += '--> FAILED'
    else:
        param_test.output += '--> PASSED'

    # update Panda structure
    param_test.results['mse_detection'] = mse_detection

    return param_test
Exemple #57
0
    def change_shape(self, shape, generate_path=False):
        """
        Change data shape (in-place)

        :param generate_path: whether to create a derived path name from the
                              original absolutepath (note: while it will generate
                              a file suffix, don't expect the suffix but rather
                              use the Image's absolutepath.
                              If not set, the absolutepath is voided.

        This is mostly useful for adding/removing a fourth dimension,
        you probably don't want to use this function.

        """
        if shape is not None:
            change_shape(self, shape, self)

        if generate_path and self._path is not None:
            self._path = sct.add_suffix(self._path, "_shape-{}".format("-".join([str(x) for x in shape])))
        else:
            # safe option: remove path to avoid overwrites
            self._path = None
        return self
def multicomponent_split(im):
    """
    Convert composite image (e.g., ITK warping field, 5dim) into several 3d volumes.
    Replaces "c3d -mcs warp_comp.nii -oo warp_vecx.nii warp_vecy.nii warp_vecz.nii"
    :param im:
    :return:
    """
    data = im.data
    assert len(data.shape) == 5
    data_out = []
    for i in range(data.shape[-1]):
        dat_out = data[:, :, :, :, i]
        '''
        while dat_out.shape[-1] == 1:
            dat_out = reshape(dat_out, dat_out.shape[:-1])
        '''
        data_out.append(dat_out)  # .astype('float32'))
    im_out = [im.copy() for j in range(len(data_out))]
    for i, im in enumerate(im_out):
        im.data = data_out[i]
        im.hdr.set_intent('vector', (), '')
        im.absolutepath = sct.add_suffix(im.absolutepath, "_{}".format(i))
    return im_out
def split_data(im_in, dim, squeeze_data=True):
    """
    Split data
    :param im_in: input image.
    :param dim: dimension: 0, 1, 2, 3.
    :return: list of split images
    """

    dim_list = ['x', 'y', 'z', 't']
    # Parse file name
    # Open first file.
    data = im_in.data
    # in case input volume is 3d and dim=t, create new axis
    if dim + 1 > len(np.shape(data)):
        data = data[..., np.newaxis]
    # in case splitting along the last dim, make sure to remove the last dim to avoid singleton
    if dim + 1 == len(np.shape(data)):
        if squeeze_data:
            do_reshape = True
        else:
            do_reshape = False
    else:
        do_reshape = False
    # Split data into list
    data_split = np.array_split(data, data.shape[dim], dim)
    # Write each file
    im_out_list = []
    for idx_img, dat in enumerate(data_split):
        im_out = msct_image.empty_like(im_in)
        if do_reshape:
            im_out.data = dat.reshape(tuple([ x for (idx_shape, x) in enumerate(data.shape) if idx_shape != dim]))
        else:
            im_out.data = dat
        im_out.absolutepath = sct.add_suffix(im_in.absolutepath, "_{}{}".format(dim_list[dim].upper(), str(idx_img).zfill(4)))
        im_out_list.append(im_out)

    return im_out_list