def test_mesh_to_image(): # Import succeeds from hasi.align import mesh_to_image # Mesh-to-image executes without error images = mesh_to_image([template_mesh, target_mesh]) # Images were generated assert (all([ type(image) == itk.Image[mesh_pixel_type, dimension] for image in images ])) # Images occupy the same physical space assert (all( [itk.spacing(image) == itk.spacing(images[0]) for image in images])) assert (all([itk.size(image) == itk.size(images[0]) for image in images])) assert (all( [itk.origin(image) == itk.origin(images[0]) for image in images])) # Mesh-to-image can run with reference image image_from_reference = mesh_to_image(target_mesh, reference_image=images[0]) # Type and image attributes match previous output assert (type(image_from_reference) == type(images[0])) assert (itk.spacing(image_from_reference) == itk.spacing(images[0])) assert (itk.size(image_from_reference) == itk.size(images[0])) assert (itk.origin(image_from_reference) == itk.origin(images[0]))
def enclosing_geometry(img1, img2): """ Does img1 enclose img2? This function could be used to test whether img2 can be used as a reference image for resampling img1. """ if equal_geometry(img1, img2): return True o1 = np.array(itk.origin(img1)) o2 = np.array(itk.origin(img2)) s1 = np.array(itk.spacing(img1)) s2 = np.array(itk.spacing(img2)) n1 = np.array(itk.size(img1)) n2 = np.array(itk.size(img2)) # compute corners lower1 = o1 - 0.5 * s1 lower2 = o2 - 0.5 * s2 upper1 = o1 + (n1 - 0.5) * s1 upper2 = o2 + (n2 - 0.5) * s2 ####################################################################### # for debugging: percentages of img2 that are inside/outside of img1. # ####################################################################### bb1 = bounding_box(img=img1) vol1 = bb1.volume bb2 = bounding_box(img=img2) vol2 = bb2.volume assert (vol2 > 0) bb2.intersect(bb1) overlap = bb2.volume outside = vol2 - bb2.volume overlap_percent = overlap * 100. / vol2 outside_percent = outside * 100. / vol2 logger.debug(f"vol img2={vol1} vol img2={vol2}") logger.debug( f"part of img2 that overlaps with img1: {overlap} or {overlap_percent} percent" ) logger.debug( f"part of img2 that is outside img1: {outside} or {outside_percent} percent" ) ####################################################################### # end debugging section # ####################################################################### # now check the lower corner if (np.logical_not(np.isclose(lower1, lower2)) * (lower1 > lower2)).any(): return False # now check the upper corner if (np.logical_not(np.isclose(upper1, upper2)) * (upper1 < upper2)).any(): return False return True
def interpolate_secondaries(input_folder, output_folder, factor, target_numprojs): sec_numprojs = len(glob.glob(f'./{input_folder}/secondary????.mha')) img0 = itk.imread(f'./{input_folder}/secondary0000.mha') img_origin = itk.origin(img0) img_spacing = itk.spacing(img0) image_ind = 0 for projnum in range(sec_numprojs - 1): # get image1 = f'./{input_folder}/secondary{projnum:04d}.mha' image2 = f'./{input_folder}/secondary{projnum+1:04d}.mha' img1_array = itk.GetArrayFromImage(itk.imread(image1)) img2_array = itk.GetArrayFromImage(itk.imread(image2)) # save the first image itk.imwrite(itk.imread(image1), f'./{output_folder}/secondary{image_ind:04d}.mha') # interpolate xfactor images between those 2 images image_interpolate_recurrence(img1_array, img2_array, image_ind, image_ind + factor, output_folder, img_origin, img_spacing) image_ind = image_ind + factor # read the last image and save it until the target_numprojs is reached lastimage = itk.imread( f'./{input_folder}/secondary{sec_numprojs-1:04d}.mha') while image_ind < target_numprojs: itk.imwrite(lastimage, f'./{output_folder}/secondary{image_ind:04d}.mha') image_ind = image_ind + 1
def compareImageHeaders(img1, img2, tolerance=0.00001): print("Comparing headers") sp1 = itk.GetArrayFromVnlVector(itk.spacing(img1).GetVnlVector()) sp2 = itk.GetArrayFromVnlVector(itk.spacing(img2).GetVnlVector()) spVar = np.sum(np.abs(sp2 - sp1)) if (spVar > tolerance): return (False) or1 = itk.GetArrayFromVnlVector(itk.origin(img1).GetVnlVector()) or2 = itk.GetArrayFromVnlVector(itk.origin(img2).GetVnlVector()) orVar = np.sum(np.abs(or2 - or1)) if (orVar > tolerance): return (False) return (True)
def attenuation_local(prim_per_proj, proj_path): if not os.path.exists(proj_path): os.makedirs(proj_path) interp_secfolder = 'interpolated_secondaries' if not os.path.exists(interp_secfolder): os.makedirs(interp_secfolder) #IMC=PMC×#primaries_per_projection×(512/128)^2+SMC size_primary = 512 size_scatter = 64 factor = prim_per_proj * pow(size_primary / size_scatter, 2) # get all the primary projections primary_files = sorted(glob.glob('./output/primary*.mha')) interpolate_secondaries(secondary_folder, interp_secfolder, 4, len(primary_files)) for projnum, primary_filename in enumerate(primary_files): # load the primary, secondary, and flatfield primary = itk.imread(primary_filename) flatfield = itk.imread(primary_filename.replace( "primary", "flatfield")) #not needed anymore - secondaries only have half the projections, so the secondary projection number = projnum/2 #second_projnum = projnum // 4 #secondary = itk.imread(f'./output/secondary{second_projnum:04d}.mha') secondary = itk.imread( f'{interp_secfolder}/secondary{projnum:04d}.mha') resizedsecondary = gt.applyTransformation( input=secondary, newsize=itk.size(primary), neworigin=itk.origin(primary), adaptive=True, force_resample=True) flatfield = itk.MultiplyImageFilter(flatfield, factor) prim_second = itk.AddImageFilter( itk.MultiplyImageFilter(primary, factor), resizedsecondary) #flatfield_sq = itk.MultiplyImageFilter(flatfield,flatfield) S = itk.DivideImageFilter(prim_second, flatfield) S = itk.MultiplyImageFilter(S, itk.MedianImageFilter(flatfield)) attenuation = itk.LogImageFilter(S) #attenuation = itk.LogImageFilter(itk.DivideImageFilter(prim_second,flatfield)) attenuation = itk.MultiplyImageFilter(attenuation, -1) itk.imwrite( attenuation, primary_filename.replace('./output/primary', f'{proj_path}/attenuation_sec'))
def downsample_images(images:list, ratio:float) -> list: assert(ratio > 1.0) downsampled_image_list = list() for image in images: new_spacing = [spacing * ratio for spacing in itk.spacing(image)] new_size = [int(size / ratio) for size in itk.size(image)] downsampled_image = itk.resample_image_filter(image, size=new_size, output_origin=itk.origin(image), output_spacing=new_spacing) downsampled_image_list.append(downsampled_image) return downsampled_image_list
def xarray_from_image(l_image): """Convert an itk.Image to an xarray.DataArray. Origin and spacing metadata is preserved in the xarray's coords. The Direction is set in the `direction` attribute. Dims are labeled as `x`, `y`, `z`, and `c`. This interface is and behavior is experimental and is subject to possible future changes.""" import xarray as xr import itk import numpy as np array_view = itk.array_view_from_image(l_image) l_spacing = itk.spacing(l_image) l_origin = itk.origin(l_image) l_size = itk.size(l_image) direction = np.flip(itk.array_from_matrix(l_image.GetDirection())) spatial_dimension = l_image.GetImageDimension() spatial_dims = ("x", "y", "z") coords = {} for l_index, dim in enumerate(spatial_dims[:spatial_dimension]): coords[dim] = np.linspace( l_origin[l_index], l_origin[l_index] + (l_size[l_index] - 1) * l_spacing[l_index], l_size[l_index], dtype=np.float64, ) dims = list(reversed(spatial_dims[:spatial_dimension])) components = l_image.GetNumberOfComponentsPerPixel() if components > 1: dims.append("c") coords["c"] = np.arange(components, dtype=np.uint64) data_array = xr.DataArray(array_view, dims=dims, coords=coords, attrs={"direction": direction}) return data_array
assert s[0] == s[1] == 256 # test physical size s = itk.physical_size(reader) assert s[0] == s[1] == 256.0 s = itk.physical_size(reader.GetOutput()) assert s[0] == s[1] == 256.0 # test spacing s = itk.spacing(reader) assert s[0] == s[1] == 1.0 s = itk.spacing(reader.GetOutput()) assert s[0] == s[1] == 1.0 # test origin s = itk.origin(reader) assert s[0] == s[1] == 0.0 s = itk.origin(reader.GetOutput()) assert s[0] == s[1] == 0.0 # test index s = itk.index(reader) assert s[0] == s[1] == 0 s = itk.index(reader.GetOutput()) assert s[0] == s[1] == 0 # test region s = itk.region(reader) assert s.GetIndex()[0] == s.GetIndex()[1] == 0 assert s.GetSize()[0] == s.GetSize()[1] == 256 s = itk.region(reader.GetOutput())
parser = argparse.ArgumentParser(description="Resample A Scalar Image.") parser.add_argument("input_image") parser.add_argument("output_image") parser.add_argument("size_x", type=int) parser.add_argument("size_y", type=int) args = parser.parse_args() output_size = [args.size_x, args.size_y] input_image = itk.imread(args.input_image) input_spacing = itk.spacing(input_image) input_size = itk.size(input_image) dimension = input_image.GetImageDimension() output_spacing = [ input_spacing[dim] * input_size[dim] / output_size[dim] for dim in range(dimension) ] transform = itk.IdentityTransform[itk.D, dimension].New() output_image = itk.resample_image_filter( input_image, size=output_size, output_spacing=output_spacing, output_origin=itk.origin(input_image), transform=transform, ) itk.imwrite(output_image, args.output_image)
def attenuation(prim_per_proj, proj_path, num_jobs): if not os.path.exists(proj_path): os.makedirs(proj_path) interp_secfolder = 'interpolated_secondaries' if not os.path.exists(interp_secfolder): os.makedirs(interp_secfolder) for results_dir in glob.glob('./results.*'): if os.path.isfile(f'{results_dir}/primary0000.mha'): primary_folder = results_dir elif os.path.isfile(f'{results_dir}/secondary0000.mha'): secondary_folder = results_dir #IMC=PMC×#primaries_per_projection×(512/128)^2+SMC size_primary = 512 size_scatter = 64 # get the number of jobs actually completed from the run folder of the scatter simulation #secondary_runfolder = secondary_folder.replace('results','run') #job_completed = len(glob.glob(f"{secondary_runfolder}/output.*")) with open(f"num_completed_jobs.txt", "r") as f: job_completed = int(f.readline()) factor = (prim_per_proj * job_completed / num_jobs) * pow( size_primary / size_scatter, 2) # get all the primary projections primary_files = sorted(glob.glob(f'{primary_folder}/primary*.mha')) interpolate_secondaries(secondary_folder, interp_secfolder, 4, len(primary_files)) for projnum, primary_filename in enumerate(primary_files): # load the primary, secondary, and flatfield primary = itk.imread(primary_filename) flatfield = itk.imread(primary_filename.replace( "primary", "flatfield")) #not needed anymore - secondaries only have half the projections, so the secondary projection number = projnum/2 #second_projnum = projnum // 4 #secondary = itk.imread(f'{secondary_folder}/secondary{second_projnum:04d}.mha') secondary = itk.imread( f'{interp_secfolder}/secondary{projnum:04d}.mha') resizedsecondary = gt.applyTransformation( input=secondary, newsize=itk.size(primary), neworigin=itk.origin(primary), adaptive=True, force_resample=True) flatfield = itk.MultiplyImageFilter(flatfield, factor) prim_second = itk.AddImageFilter( itk.MultiplyImageFilter(primary, factor), resizedsecondary) #flatfield_sq = itk.MultiplyImageFilter(flatfield,flatfield) S = itk.DivideImageFilter(prim_second, flatfield) S = itk.MultiplyImageFilter(S, itk.MedianImageFilter(flatfield)) attenuation = itk.LogImageFilter(S) #attenuation = itk.LogImageFilter(itk.DivideImageFilter(prim_second,flatfield)) attenuation = itk.MultiplyImageFilter(attenuation, -1) attenuation_path = primary_filename.replace( f'{os.path.dirname(primary_filename)}/primary', f'{proj_path}/attenuation_sec') itk.imwrite(attenuation, attenuation_path)
def conv_3Dto2D(img_3D_filename, label_3D_filename, outputimages_foldername_x, outputimages_foldername_y, outputimages_foldername_z, outputlabels_foldername_x, outputlabels_foldername_y, outputlabels_foldername_z, image_identifier_x, image_identifier_y, image_identifier_z, patient_names_x, patient_names_y, patient_names_z, casenumber_x, casenumber_y, casenumber_z, slice_info_filename_x, slice_info_filename_y, slice_info_filename_z, localtaskfolder_x, localtaskfolder_y, localtaskfolder_z, patient_folder): if outputlabels_foldername_x == '': test_dataset = True images2D_foldername_x = f'{localtaskfolder_x}/2D_testimages_x/' labels2D_foldername_x = f'{localtaskfolder_x}/2D_testlabels_x' labels_nifti_foldername_x = f'{localtaskfolder_x}/2D_testlabels_nii_x' images2D_foldername_y = f'{localtaskfolder_y}/2D_testimages_y/' labels2D_foldername_y = f'{localtaskfolder_y}/2D_testlabels_y' labels_nifti_foldername_y = f'{localtaskfolder_y}/2D_testlabels_nii_y' images2D_foldername_z = f'{localtaskfolder_z}/2D_testimages_z/' labels2D_foldername_z = f'{localtaskfolder_z}/2D_testlabels_z' labels_nifti_foldername_z = f'{localtaskfolder_z}/2D_testlabels_nii_z' outputlabels_foldername_x = labels_nifti_foldername_x outputlabels_foldername_y = labels_nifti_foldername_y outputlabels_foldername_z = labels_nifti_foldername_z else: test_dataset = False images2D_foldername_x = f'{localtaskfolder_x}/2D_trainingimages_x/' labels2D_foldername_x = f'{localtaskfolder_x}/2D_traininglabels_x' labels_nifti_foldername_x = f'{localtaskfolder_x}/2D_traininglabels_nii_x' images2D_foldername_y = f'{localtaskfolder_y}/2D_trainingimages_y/' labels2D_foldername_y = f'{localtaskfolder_y}/2D_traininglabels_y' labels_nifti_foldername_y = f'{localtaskfolder_y}/2D_traininglabels_nii_y' images2D_foldername_z = f'{localtaskfolder_z}/2D_trainingimages_z/' labels2D_foldername_z = f'{localtaskfolder_z}/2D_traininglabels_z' labels_nifti_foldername_z = f'{localtaskfolder_z}/2D_traininglabels_nii_z' maybe_mkdir_p(images2D_foldername_x) maybe_mkdir_p(labels2D_foldername_x) maybe_mkdir_p(labels_nifti_foldername_x) maybe_mkdir_p(images2D_foldername_y) maybe_mkdir_p(labels2D_foldername_y) maybe_mkdir_p(labels_nifti_foldername_y) maybe_mkdir_p(images2D_foldername_z) maybe_mkdir_p(labels2D_foldername_z) maybe_mkdir_p(labels_nifti_foldername_z) img = itk.imread(img_3D_filename) img_spacing = itk.spacing(img) img_origin = itk.origin(img) img_array = itk.GetArrayFromImage(img) if label_3D_filename != '': labelimg = itk.imread(label_3D_filename) label_spacing = itk.spacing(labelimg) label_origin = itk.origin(labelimg) label_array = itk.GetArrayFromImage(labelimg) # x direction # save for each patient the 3d_imagename, the image_identifier, the first slice, last slice, origin, and spacing of the 3d image num_slices = itk.size(img)[0] with open(slice_info_filename_x, "a") as f: f.write( f"{os.path.basename(img_3D_filename)}\t{image_identifier_x}\t{casenumber_x}\t{casenumber_x+num_slices-1}\t{np.array(img_origin)}\t{np.array(img_spacing)}\t{patient_folder}\n" ) for i in range(num_slices): casename = f'{image_identifier_x}_{casenumber_x:04d}' img_2D = itk.GetImageFromArray(img_array[:, :, i]) img_2D.SetSpacing([img_spacing[1], img_spacing[2]]) img_2D.SetOrigin([img_origin[1], img_origin[2]]) # save the 2d image in the 2D folder image2D_filename = f'{images2D_foldername_x}/{casename}.mha' #image2D_filename= (img_3D_filename.replace('3D','2D')).replace('.mha',f'_{i:04d}.mha') itk.imwrite(img_2D, image2D_filename) label_array2D = label_array[:, :, i] label_2D = itk.GetImageFromArray(label_array2D) label_2D.SetSpacing([label_spacing[1], label_spacing[2]]) label_2D.SetOrigin([label_origin[1], label_origin[2]]) #itk.imwrite(label_2D,outputlabel_filename) #print(label_array2D) # save the 2d label in the 2D folder label2D_filename = f'{labels2D_foldername_x}/{casename}.mha' #(label_3D_filename.replace('3D','2D')).replace('.mha',f'_{i:04d}.mha') itk.imwrite(label_2D, label2D_filename) # if the label is empty, don't include the image in the training dataset if np.any(img_2D) & ((test_dataset == True) | np.any(label_array2D)): patient_names_x.append(casename) # save the 2d image as a 3D nifti in the nnunet folder outputimage_filename = f'{outputimages_foldername_x}/{casename}' convert_2d_image_to_nifti(image2D_filename, outputimage_filename, is_seg=False) # save the 2d label as a 3D nifti in the nnunet folder outputlabel_filename = f'{outputlabels_foldername_x}/{casename}' convert_2d_image_to_nifti(label2D_filename, outputlabel_filename, is_seg=True) casenumber_x = casenumber_x + 1 # y direction num_slices = itk.size(img)[1] with open(slice_info_filename_y, "a") as f: f.write( f"{os.path.basename(img_3D_filename)}\t{image_identifier_y}\t{casenumber_y}\t{casenumber_y+num_slices-1}\t{np.array(img_origin)}\t{np.array(img_spacing)}\t{patient_folder}\n" ) for i in range(num_slices): casename = f'{image_identifier_y}_{casenumber_y:04d}' #outputimage_filename= f'{outputimages_foldername}/{casename}_0000.nii.gz' #outputlabel_filename= f'{outputlabels_foldername}/{casename}.nii.gz' img_2D = itk.GetImageFromArray(img_array[:, i, :]) img_2D.SetSpacing([img_spacing[0], img_spacing[2]]) img_2D.SetOrigin([img_origin[0], img_origin[2]]) # save the 2d image in the 2D folder image2D_filename = f'{images2D_foldername_y}/{casename}.mha' #image2D_filename= (img_3D_filename.replace('3D','2D')).replace('.mha',f'_{i:04d}.mha') itk.imwrite(img_2D, image2D_filename) label_array2D = label_array[:, i, :] label_2D = itk.GetImageFromArray(label_array2D) label_2D.SetSpacing([label_spacing[0], label_spacing[2]]) label_2D.SetOrigin([label_origin[0], label_origin[2]]) #itk.imwrite(label_2D,outputlabel_filename) # save the 2d label in the 2D folder label2D_filename = f'{labels2D_foldername_y}/{casename}.mha' #label2D_filename= (label_3D_filename.replace('3D','2D')).replace('.mha',f'_{i:04d}.mha') itk.imwrite(label_2D, label2D_filename) # if the label is empty, don't include the image in the training dataset if np.any(img_2D) & ((test_dataset == True) | np.any(label_array2D)): patient_names_y.append(casename) # save the 2d image as a 3D nifti in the nnunet folder outputimage_filename = f'{outputimages_foldername_y}/{casename}' convert_2d_image_to_nifti(image2D_filename, outputimage_filename, is_seg=False) # save the 2d label as a 3D nifti in the nnunet folder outputlabel_filename = f'{outputlabels_foldername_y}/{casename}' convert_2d_image_to_nifti(label2D_filename, outputlabel_filename, is_seg=True) casenumber_y = casenumber_y + 1 # z direction num_slices = itk.size(img)[2] with open(slice_info_filename_z, "a") as f: f.write( f"{os.path.basename(img_3D_filename)}\t{image_identifier_z}\t{casenumber_z}\t{casenumber_z+num_slices-1}\t{np.array(img_origin)}\t{np.array(img_spacing)}\t{patient_folder}\n" ) for i in range(num_slices): casename = f'{image_identifier_z}_{casenumber_z:04d}' #outputimage_filename= f'{outputimages_foldername}/{casename}_0000.nii.gz' #outputlabel_filename= f'{outputlabels_foldername}/{casename}.nii.gz' img_2D = itk.GetImageFromArray(img_array[i, :, :]) img_2D.SetSpacing([img_spacing[0], img_spacing[1]]) img_2D.SetOrigin([img_origin[0], img_origin[1]]) # save the 2d image in the 2D folder image2D_filename = f'{images2D_foldername_z}/{casename}.mha' #image2D_filename= (img_3D_filename.replace('3D','2D')).replace('.',f'_{i:04d}.') itk.imwrite(img_2D, image2D_filename) label_array2D = label_array[i, :, :] label_2D = itk.GetImageFromArray(label_array2D) label_2D.SetSpacing([label_spacing[0], label_spacing[1]]) label_2D.SetOrigin([label_origin[0], label_origin[1]]) #itk.imwrite(label_2D,outputlabel_filename) # save the 2d label in the 2D folder label2D_filename = f'{labels2D_foldername_z}/{casename}.mha' #label2D_filename= (label_3D_filename.replace('3D','2D')).replace('.mha',f'_{i:04d}.mha') itk.imwrite(label_2D, label2D_filename) # if the image or the label is empty, don't include the image in the training dataset if np.any(img_2D) & ((test_dataset == True) | np.any(label_array2D)): patient_names_z.append(casename) # save the 2d image as a 3D nifti in the nnunet folder outputimage_filename = f'{outputimages_foldername_z}/{casename}' convert_2d_image_to_nifti(image2D_filename, outputimage_filename, is_seg=False) # save the 2d label as a 3D nifti in the nnunet folder outputlabel_filename = f'{outputlabels_foldername_z}/{casename}' convert_2d_image_to_nifti(label2D_filename, outputlabel_filename, is_seg=True) casenumber_z = casenumber_z + 1 return casenumber_x, casenumber_y, casenumber_z, patient_names_x, patient_names_y, patient_names_z