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
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 pre_processing(fname_target, fname_sc_seg, fname_level=None, fname_manual_gmseg=None, new_res=0.3, square_size_size_mm=22.5, denoising=True, verbose=1, rm_tmp=True, for_model=False): printv('\nPre-process data...', verbose, 'normal') tmp_dir = sct.tmp_create() sct.copy(fname_target, tmp_dir) fname_target = ''.join(extract_fname(fname_target)[1:]) sct.copy(fname_sc_seg, tmp_dir) fname_sc_seg = ''.join(extract_fname(fname_sc_seg)[1:]) curdir = os.getcwd() os.chdir(tmp_dir) original_info = { 'orientation': None, 'im_sc_seg_rpi': None, 'interpolated_images': [] } im_target = Image(fname_target).copy() im_sc_seg = Image(fname_sc_seg).copy() # get original orientation printv(' Reorient...', verbose, 'normal') original_info['orientation'] = im_target.orientation # assert images are in the same orientation assert im_target.orientation == im_sc_seg.orientation, "ERROR: the image to segment and it's SC segmentation are not in the same orientation" im_target_rpi = set_orientation(im_target, 'RPI') im_sc_seg_rpi = set_orientation(im_sc_seg, 'RPI') original_info['im_sc_seg_rpi'] = im_sc_seg_rpi.copy( ) # target image in RPI will be used to post-process segmentations # denoise using P. Coupe non local means algorithm (see [Manjon et al. JMRI 2010]) implemented in dipy if denoising: printv(' Denoise...', verbose, 'normal') # crop image before denoising to fasten denoising nx, ny, nz, nt, px, py, pz, pt = im_target_rpi.dim size_x, size_y = (square_size_size_mm + 1) / px, (square_size_size_mm + 1) / py size = int(math.ceil(max(size_x, size_y))) # create mask fname_mask = 'mask_pre_crop.nii.gz' sct_create_mask.main([ '-i', im_target_rpi.absolutepath, '-p', 'centerline,' + im_sc_seg_rpi.absolutepath, '-f', 'box', '-size', str(size), '-o', fname_mask ]) # crop image fname_target_crop = add_suffix(im_target_rpi.absolutepath, '_pre_crop') crop_im = ImageCropper(input_file=im_target_rpi.absolutepath, output_file=fname_target_crop, mask=fname_mask) im_target_rpi_crop = crop_im.crop() # crop segmentation fname_sc_seg_crop = add_suffix(im_sc_seg_rpi.absolutepath, '_pre_crop') crop_sc_seg = ImageCropper(input_file=im_sc_seg_rpi.absolutepath, output_file=fname_sc_seg_crop, mask=fname_mask) im_sc_seg_rpi_crop = crop_sc_seg.crop() # denoising from sct_maths import denoise_nlmeans block_radius = 3 block_radius = int( im_target_rpi_crop.data.shape[2] / 2) if im_target_rpi_crop.data.shape[2] < (block_radius * 2) else block_radius patch_radius = block_radius - 1 data_denoised = denoise_nlmeans(im_target_rpi_crop.data, block_radius=block_radius, patch_radius=patch_radius) im_target_rpi_crop.data = data_denoised im_target_rpi = im_target_rpi_crop im_sc_seg_rpi = im_sc_seg_rpi_crop else: fname_mask = None # interpolate image to reference square image (resample and square crop centered on SC) printv(' Interpolate data to the model space...', verbose, 'normal') list_im_slices = interpolate_im_to_ref(im_target_rpi, im_sc_seg_rpi, new_res=new_res, sq_size_size_mm=square_size_size_mm) original_info[ 'interpolated_images'] = list_im_slices # list of images (not Slice() objects) printv(' Mask data using the spinal cord segmentation...', verbose, 'normal') list_sc_seg_slices = interpolate_im_to_ref( im_sc_seg_rpi, im_sc_seg_rpi, new_res=new_res, sq_size_size_mm=square_size_size_mm, interpolation_mode=1) for i in range(len(list_im_slices)): # list_im_slices[i].data[list_sc_seg_slices[i].data == 0] = 0 list_sc_seg_slices[i] = binarize(list_sc_seg_slices[i], thr_min=0.5, thr_max=1) list_im_slices[ i].data = list_im_slices[i].data * list_sc_seg_slices[i].data printv(' Split along rostro-caudal direction...', verbose, 'normal') list_slices_target = [ Slice(slice_id=i, im=im_slice.data, gm_seg=[], wm_seg=[]) for i, im_slice in enumerate(list_im_slices) ] # load vertebral levels if fname_level is not None: printv(' Load vertebral levels...', verbose, 'normal') # copy level file to tmp dir os.chdir(curdir) sct.copy(fname_level, tmp_dir) os.chdir(tmp_dir) # change fname level to only file name (path = tmp dir now) fname_level = ''.join(extract_fname(fname_level)[1:]) # load levels list_slices_target = load_level(list_slices_target, fname_level) os.chdir(curdir) # load manual gmseg if there is one (model data) if fname_manual_gmseg is not None: printv('\n\tLoad manual GM segmentation(s) ...', verbose, 'normal') list_slices_target = load_manual_gmseg(list_slices_target, fname_manual_gmseg, tmp_dir, im_sc_seg_rpi, new_res, square_size_size_mm, for_model=for_model, fname_mask=fname_mask) if rm_tmp: # remove tmp folder sct.rmtree(tmp_dir) return list_slices_target, original_info
def pre_processing(fname_target, fname_sc_seg, fname_level=None, fname_manual_gmseg=None, new_res=0.3, square_size_size_mm=22.5, denoising=True, verbose=1, rm_tmp=True, for_model=False): printv('\nPre-process data...', verbose, 'normal') tmp_dir = sct.tmp_create() sct.copy(fname_target, tmp_dir) fname_target = ''.join(extract_fname(fname_target)[1:]) sct.copy(fname_sc_seg, tmp_dir) fname_sc_seg = ''.join(extract_fname(fname_sc_seg)[1:]) curdir = os.getcwd() os.chdir(tmp_dir) original_info = {'orientation': None, 'im_sc_seg_rpi': None, 'interpolated_images': []} im_target = Image(fname_target).copy() im_sc_seg = Image(fname_sc_seg).copy() # get original orientation printv(' Reorient...', verbose, 'normal') original_info['orientation'] = im_target.orientation # assert images are in the same orientation assert im_target.orientation == im_sc_seg.orientation, "ERROR: the image to segment and it's SC segmentation are not in the same orientation" im_target_rpi = im_target.copy().change_orientation('RPI', generate_path=True).save() im_sc_seg_rpi = im_sc_seg.copy().change_orientation('RPI', generate_path=True).save() original_info['im_sc_seg_rpi'] = im_sc_seg_rpi.copy() # target image in RPI will be used to post-process segmentations # denoise using P. Coupe non local means algorithm (see [Manjon et al. JMRI 2010]) implemented in dipy if denoising: printv(' Denoise...', verbose, 'normal') # crop image before denoising to fasten denoising nx, ny, nz, nt, px, py, pz, pt = im_target_rpi.dim size_x, size_y = (square_size_size_mm + 1) / px, (square_size_size_mm + 1) / py size = int(np.ceil(max(size_x, size_y))) # create mask fname_mask = 'mask_pre_crop.nii.gz' sct_create_mask.main(['-i', im_target_rpi.absolutepath, '-p', 'centerline,' + im_sc_seg_rpi.absolutepath, '-f', 'box', '-size', str(size), '-o', fname_mask]) # crop image fname_target_crop = add_suffix(im_target_rpi.absolutepath, '_pre_crop') crop_im = ImageCropper(input_file=im_target_rpi.absolutepath, output_file=fname_target_crop, mask=fname_mask) im_target_rpi_crop = crop_im.crop() # crop segmentation fname_sc_seg_crop = add_suffix(im_sc_seg_rpi.absolutepath, '_pre_crop') crop_sc_seg = ImageCropper(input_file=im_sc_seg_rpi.absolutepath, output_file=fname_sc_seg_crop, mask=fname_mask) im_sc_seg_rpi_crop = crop_sc_seg.crop() # denoising from sct_maths import denoise_nlmeans block_radius = 3 block_radius = int(im_target_rpi_crop.data.shape[2] / 2) if im_target_rpi_crop.data.shape[2] < (block_radius*2) else block_radius patch_radius = block_radius -1 data_denoised = denoise_nlmeans(im_target_rpi_crop.data, block_radius=block_radius, patch_radius=patch_radius) im_target_rpi_crop.data = data_denoised im_target_rpi = im_target_rpi_crop im_sc_seg_rpi = im_sc_seg_rpi_crop else: fname_mask = None # interpolate image to reference square image (resample and square crop centered on SC) printv(' Interpolate data to the model space...', verbose, 'normal') list_im_slices = interpolate_im_to_ref(im_target_rpi, im_sc_seg_rpi, new_res=new_res, sq_size_size_mm=square_size_size_mm) original_info['interpolated_images'] = list_im_slices # list of images (not Slice() objects) printv(' Mask data using the spinal cord segmentation...', verbose, 'normal') list_sc_seg_slices = interpolate_im_to_ref(im_sc_seg_rpi, im_sc_seg_rpi, new_res=new_res, sq_size_size_mm=square_size_size_mm, interpolation_mode=1) for i in range(len(list_im_slices)): # list_im_slices[i].data[list_sc_seg_slices[i].data == 0] = 0 list_sc_seg_slices[i] = binarize(list_sc_seg_slices[i], thr_min=0.5, thr_max=1) list_im_slices[i].data = list_im_slices[i].data * list_sc_seg_slices[i].data printv(' Split along rostro-caudal direction...', verbose, 'normal') list_slices_target = [Slice(slice_id=i, im=im_slice.data, gm_seg=[], wm_seg=[]) for i, im_slice in enumerate(list_im_slices)] # load vertebral levels if fname_level is not None: printv(' Load vertebral levels...', verbose, 'normal') # copy level file to tmp dir os.chdir(curdir) sct.copy(fname_level, tmp_dir) os.chdir(tmp_dir) # change fname level to only file name (path = tmp dir now) fname_level = ''.join(extract_fname(fname_level)[1:]) # load levels list_slices_target = load_level(list_slices_target, fname_level) os.chdir(curdir) # load manual gmseg if there is one (model data) if fname_manual_gmseg is not None: printv('\n\tLoad manual GM segmentation(s) ...', verbose, 'normal') list_slices_target = load_manual_gmseg(list_slices_target, fname_manual_gmseg, tmp_dir, im_sc_seg_rpi, new_res, square_size_size_mm, for_model=for_model, fname_mask=fname_mask) if rm_tmp: # remove tmp folder sct.rmtree(tmp_dir) return list_slices_target, original_info