def dmri_ail_cropped(tmp_path): """Reorient image to sagittal for testing another orientation (and crop to save time).""" path_out = str(tmp_path / 'dmri_AIL_crop.nii') sct_image.main(argv=['-i', 'dmri/dmri.nii.gz', '-setorient', 'AIL', '-o', 'dmri/dmri_AIL.nii']) sct_crop_image.main(argv=['-i', 'dmri/dmri_AIL.nii', '-zmin', '19', '-zmax', '21', '-o', path_out]) return path_out
def test_sct_image_concat_dmri(tmp_path, dmri_t_slices, dmri_in): """Run the CLI script and verify concatenated image matches reference image.""" path_out = str(tmp_path / 'dmri_concat.nii.gz') sct_image.main(argv=['-i'] + dmri_t_slices + ['-concat', 't', '-o', path_out]) ref = Image(dmri_in) new = Image(path_out) assert np.linalg.norm(ref.data - new.data) == 0
def dmri_t_slices(tmp_path, dmri_in): """Filepaths for 4D dMRI image split across t axis.""" fname_out = str(tmp_path / 'dmri.nii.gz') sct_image.main(argv=['-i', dmri_in, '-split', 't', '-o', fname_out]) parent, filename, ext = extract_fname(fname_out) fname_slices = [ os.path.join(parent, filename + '_T' + str(i).zfill(4) + ext) for i in range(7) ] return fname_slices
def test_sct_image_pad(): """Run the CLI script and test the '-pad' option.""" pad = 2 path_in = 'mt/mtr.nii.gz' # 3D path_out = 'sct_image_out.nii.gz' sct_image.main(argv=[ '-i', path_in, '-o', 'sct_image_out.nii.gz', '-pad', f'0,0,{pad}' ]) # z axis (dim[2]) should be padded, but all other values should be unchanged expected_dim = Image(path_in).dim[:2] + ( Image(path_in).dim[2] + (2 * pad), ) + Image(path_in).dim[3:] assert Image(path_out).dim == expected_dim
def check_and_correct_segmentation(fname_segmentation, fname_centerline, folder_output='', threshold_distance=5.0, remove_temp_files=1, verbose=0): """ This function takes the outputs of isct_propseg (centerline and segmentation) and check if the centerline of the segmentation is coherent with the centerline provided by the isct_propseg, especially on the edges (related to issue #1074). Args: fname_segmentation: filename of binary segmentation fname_centerline: filename of binary centerline threshold_distance: threshold, in mm, beyond which centerlines are not coherent verbose: Returns: None """ printv('\nCheck consistency of segmentation...', verbose) # creating a temporary folder in which all temporary files will be placed and deleted afterwards path_tmp = tmp_create(basename="propseg") convert(fname_segmentation, os.path.join(path_tmp, "tmp.segmentation.nii.gz"), verbose=0) convert(fname_centerline, os.path.join(path_tmp, "tmp.centerline.nii.gz"), verbose=0) fname_seg_absolute = os.path.abspath(fname_segmentation) # go to tmp folder curdir = os.getcwd() os.chdir(path_tmp) # convert segmentation image to RPI im_input = Image('tmp.segmentation.nii.gz') image_input_orientation = im_input.orientation sct_image.main( "-i tmp.segmentation.nii.gz -setorient RPI -o tmp.segmentation_RPI.nii.gz -v 0" .split()) sct_image.main( "-i tmp.centerline.nii.gz -setorient RPI -o tmp.centerline_RPI.nii.gz -v 0" .split()) # go through segmentation image, and compare with centerline from propseg im_seg = Image('tmp.segmentation_RPI.nii.gz') im_centerline = Image('tmp.centerline_RPI.nii.gz') # Get size of data printv('\nGet data dimensions...', verbose) nx, ny, nz, nt, px, py, pz, pt = im_seg.dim # extraction of centerline provided by isct_propseg and computation of center of mass for each slice # the centerline is defined as the center of the tubular mesh outputed by propseg. centerline, key_centerline = {}, [] for i in range(nz): slice = im_centerline.data[:, :, i] if np.any(slice): x_centerline, y_centerline = ndi.measurements.center_of_mass(slice) centerline[str(i)] = [x_centerline, y_centerline] key_centerline.append(i) minz_centerline = np.min(key_centerline) maxz_centerline = np.max(key_centerline) mid_slice = int((maxz_centerline - minz_centerline) / 2) # for each slice of the segmentation, check if only one object is present. If not, remove the slice from segmentation. # If only one object (the spinal cord) is present in the slice, check if its center of mass is close to the centerline of isct_propseg. slices_to_remove = [ False ] * nz # flag that decides if the slice must be removed for i in range(minz_centerline, maxz_centerline + 1): # extraction of slice slice = im_seg.data[:, :, i] distance = -1 label_objects, nb_labels = ndi.label( slice) # count binary objects in the slice if nb_labels > 1: # if there is more that one object in the slice, the slice is removed from the segmentation slices_to_remove[i] = True elif nb_labels == 1: # check if the centerline is coherent with the one from isct_propseg x_centerline, y_centerline = ndi.measurements.center_of_mass(slice) slice_nearest_coord = min(key_centerline, key=lambda x: abs(x - i)) coord_nearest_coord = centerline[str(slice_nearest_coord)] distance = np.sqrt(( (x_centerline - coord_nearest_coord[0]) * px)**2 + ( (y_centerline - coord_nearest_coord[1]) * py)**2 + ((i - slice_nearest_coord) * pz)**2) if distance >= threshold_distance: # threshold must be adjusted, default is 5 mm slices_to_remove[i] = True # Check list of removal and keep one continuous centerline (improve this comment) # Method: # starting from mid-centerline (in both directions), the first True encountered is applied to all following slices slice_to_change = False for i in range(mid_slice, nz): if slice_to_change: slices_to_remove[i] = True elif slices_to_remove[i]: slice_to_change = True slice_to_change = False for i in range(mid_slice, 0, -1): if slice_to_change: slices_to_remove[i] = True elif slices_to_remove[i]: slice_to_change = True for i in range(0, nz): # remove the slice if slices_to_remove[i]: im_seg.data[:, :, i] *= 0 # saving the image im_seg.save('tmp.segmentation_RPI_c.nii.gz') # replacing old segmentation with the corrected one sct_image.main( '-i tmp.segmentation_RPI_c.nii.gz -setorient {} -o {} -v 0'.format( image_input_orientation, fname_seg_absolute).split()) os.chdir(curdir) # display information about how much of the segmentation has been corrected # remove temporary files if remove_temp_files: # printv("\nRemove temporary files...", verbose) rmtree(path_tmp)
def test_sct_image_display_warp_check_output_exists(): """Run the CLI script and check that the warp image file was created.""" fname_in = 'warp_template2anat.nii.gz' fname_out = 'grid_3_resample_' + fname_in sct_image.main(argv=['-i', sct_test_path('t2', fname_in), '-display-warp']) assert os.path.exists(sct_test_path('t2', fname_out))
def test_sct_image_show_header_no_checks(output_format): """Run the CLI script without checking results. The rationale for not checking results is provided here: https://github.com/spinalcordtoolbox/spinalcordtoolbox/pull/3317#issuecomment-811429547""" sct_image.main(argv=[ '-i', sct_test_path('t2', 't2.nii.gz'), '-header', output_format ])
def test_sct_image_getorient(path_in): """Run the CLI script and .""" sct_image.main(argv=['-i', path_in, '-getorient'])