def ctvi_stats(ctvi, mask, histo): ''' Doc todo ''' ctvi = itk.imread(ctvi) mask = itk.imread(mask) check_same_geometry(ctvi, mask) data = itk.array_view_from_image(ctvi) mask = itk.array_view_from_image(mask) mask[mask != 0] = 1 s = basics_stats(data, mask) print( f'Min/Max {s.min:.2f} {s.max:.2f} Mean/Std {s.mean:.2f} {s.std:.2f} ' f' {s.pixels_count} pixels Q10/Q90 {s.q10:.2f} {s.q90:.2f} ') if histo == 0: exit(0) fig = plt.figure() m = mask.ravel() d = data.ravel()[m != 0] d = d[d != 0] # there are a lot of almost zeros values q1 = np.quantile(d, 0.9) plt.hist(d, bins=histo, range=(0, q1)) plt.show()
def set_external_dose_zero(image, structure_file, structure): """Set all dose outside of patient's contour to zero """ img = None if type(image) == str: #Assume we have file path img = itk.imread(image) else: #Assume we have itk image object img = image ds = pydicom.dcmread(structure_file) aroi = roiutils.region_of_interest(ds, structure) mask = aroi.get_mask(img, corrected=False) pix_mask = itk.array_view_from_image(mask) pix_img = itk.array_view_from_image(img) if (pix_mask.shape != pix_img.shape): print("Inconsistent shapes of mask and image") pix_img_flat = pix_img.flatten() for i, val in enumerate(pix_mask.flatten()): if val == 0: pix_img_flat[i] = 0 pix_img = pix_img_flat.reshape(pix_img.shape) img_modified = itk.image_view_from_array(pix_img) img_modified.CopyInformation(img) return img_modified
def _get_array_data(self, img) -> np.ndarray: """ Get the raw array data of the image, converted to Numpy array. Following PyTorch conventions, the returned array data has contiguous channels, e.g. for an RGB image, all red channel image pixels are contiguous in memory. The first axis of the returned array is the channel axis. Args: img: a ITK image object loaded from a image file. """ channels = img.GetNumberOfComponentsPerPixel() if channels == 1: return itk.array_view_from_image(img, keep_axes=False) else: # The memory layout of itk.Image has all pixel's channels adjacent # in memory, i.e. R1G1B1R2G2B2R3G3B3. For PyTorch/MONAI, we need # channels to be contiguous, i.e. R1R2R3G1G2G3B1B2B3. arr = itk.array_view_from_image(img, keep_axes=False) dest = list(range(img.ndim)) source = dest.copy() end = source.pop() source.insert(0, end) arr_contiguous_channels = np.moveaxis(arr, source, dest) return arr_contiguous_channels
def override_hu(img_file, structure_file, output_img, structure, hu): #MAYBE JUST PASS THE IMAGE OBJECT AND DICOM OBJECT?? """Override all HUs inside of specified structure""" img = itk.imread(img_file) ds = pydicom.dcmread(structure_file) # TESTING GATETOOLS aroi = roiutils.region_of_interest(ds, structure) mask = aroi.get_mask(img, corrected=False) ##aroi = rt.region_of_interest( ds, structure ) ##mask = aroi.get_mask(img, corrected=False) pix_mask = itk.array_view_from_image(mask) pix_img = itk.array_view_from_image(img) if (pix_mask.shape != pix_img.shape): print("Inconsistent shapes of mask and image") pix_img_flat = pix_img.flatten() for i, val in enumerate(pix_mask.flatten()): if val == 1: pix_img_flat[i] = hu pix_img = pix_img_flat.reshape(pix_img.shape) img_modified = itk.image_view_from_array(pix_img) img_modified.CopyInformation(img) ##img_modified.SetSpacing( img.GetSpacing() ) # "ElementSpacing" in .mhd ##img_modified.SetOrigin( img.GetOrigin() ) # "Offset" in .mhd itk.imwrite(img_modified, output_img)
def test_image_projection(self): image = createImageExample() output = image_projection(image, 0, False) outputArray = itk.array_view_from_image(output) self.assertTrue(outputArray[13, 14] == 14 * 15) self.assertTrue(output.GetSpacing()[0] == 2) self.assertTrue(output.GetSpacing()[1] == 3.1) self.assertTrue(output.GetOrigin()[0] == 12.4) self.assertTrue(output.GetOrigin()[1] == -0.7) self.assertTrue(output.GetLargestPossibleRegion().GetSize()[0] == 23) self.assertTrue(output.GetLargestPossibleRegion().GetSize()[1] == 21) output = image_projection(image, 1, False) outputArray = itk.array_view_from_image(output) self.assertTrue(outputArray[8, 5] == 253) self.assertTrue(output.GetSpacing()[0] == 1.1) self.assertTrue(output.GetSpacing()[1] == 3.1) self.assertTrue(output.GetOrigin()[0] == 10) self.assertTrue(output.GetOrigin()[1] == -0.7) self.assertTrue(output.GetLargestPossibleRegion().GetSize()[0] == 15) self.assertTrue(output.GetLargestPossibleRegion().GetSize()[1] == 21) output = image_projection(image, 2) outputArray = itk.array_view_from_image(output) self.assertTrue(outputArray[6, 10] == 6 * 21) self.assertTrue(output.GetSpacing()[0] == 1.1) self.assertTrue(output.GetSpacing()[1] == 2) self.assertTrue(output.GetOrigin()[0] == 10) self.assertTrue(output.GetOrigin()[1] == 12.4) self.assertTrue(output.GetLargestPossibleRegion().GetSize()[0] == 15) self.assertTrue(output.GetLargestPossibleRegion().GetSize()[1] == 23) output = image_projection(image, 2, True) outputArray = itk.array_view_from_image(output) self.assertTrue(outputArray[6, 10] == 6)
def lung_mass_and_volume(img, img_mask): ''' Mass in g Volume in L # HU = 1000 x (mu-mu_w) / (mu_w - mu_air) # mu = HU/1000 * (mu_w-mu_a) + mu_w # This is WRONG for H > 0 ! # See for ex Schneider2000 ''' data = itk.array_view_from_image(img) mask = itk.array_view_from_image(img_mask) check_same_geometry(img, img_mask) # lung volume (be sure to consider all labels != 0 in the mask) pixel_vol = pix_vol(img) # in mm3 mask[mask != 0] = 1 n = mask.sum() lung_vol = n * pixel_vol * 1e-6 # vol in L # lung mass mu_w = 1 mu_a = 0.0 d = data / 1000.0 * (mu_w - mu_a) + mu_w d[mask == 0] = 0.0 lung_mass = d.sum() * pixel_vol * 1e-3 # mass in grams stat = Box() stat.mass_g = lung_mass stat.volume_L = lung_vol stat.pixels_count = n stat.pixel_volume_mm3 = pixel_vol return stat
def GetSegmentationMask(self, region): seg = itk.array_view_from_image(self.segmentation) inmask = np.full(seg.shape, 1, dtype=np.int16) if not self.mask is None: inmask[itk.array_view_from_image(self.mask) == 0] = 0 if region in self.segmentationRules.keys(): rule = self.segmentationRules[region] # Limit to segmentation inclusion regions if not rule[0] is None: inmask = np.full(seg.shape, 0) for i in rule[0]: inmask[seg == i] = 1 # Eliminate exclusion regions if not rule[1] is None: for i in rule[1]: inmask[seg == i] = 0 else: inmask[seg != region] = 0 # Apply global masking if not self.mask is None: inmask[itk.array_view_from_image(self.mask) == 0] = 0 segMask = itk.image_from_array(inmask) segMask.SetSpacing(self.segmentation.GetSpacing()) segMask.SetOrigin(self.segmentation.GetOrigin()) segMask.SetDirection(self.segmentation.GetDirection()) return (segMask)
def __init__(self, cfg): self.out_dose_nxyz = cfg.out_dose_nxyz.astype(np.int) self.sim_dose_nxyz = cfg.sim_dose_nxyz.astype(np.int) if bool(cfg.mask_mhd): self.mask = itk.imread(os.path.join(cfg.workdir, cfg.mask_mhd)) self.amask = itk.array_view_from_image(self.mask) if not (self.out_dose_nxyz[::-1] == self.amask.shape).all(): msg = "mask resolution {} inconsistent with expected output dose resolution {}".format( self.out_dose_nxyz[::-1], self.amask.shape) logger.error(msg) raise RuntimeError(msg) else: self.mask = None if bool(cfg.mass_mhd): #self.mass = itk.imread(cfg.mass_mhd) self.mass = itk.imread(os.path.join(cfg.workdir, cfg.mass_mhd)) self.amass = itk.array_view_from_image(self.mass) if not (self.sim_dose_nxyz[::-1] == self.amass.shape).all(): raise RuntimeError( "mass resolution {} inconsistent with expected simulation dose resolution {}" .format(self.sim_dose_nxyz[::-1], self.amass.shape)) else: self.mass = None if bool(cfg.mass_mhd) != bool(cfg.mask_mhd): msg = "got mass_mhd={} and mask_mhd={}".format( cfg.mass_mhd, cfg.mask_mhd) msg += "you should provide EITHER both the mass and the mask file, OR neither of them." logger.error(msg) raise RuntimeError(msg) self.cfg = cfg syscfg = system_configuration.getInstance() self.ntop = syscfg["n top voxels for mean dose max"] self.toppct = syscfg[ "dose threshold as fraction in percent of mean dose max"] self.reset()
def override_hu(image, structure_file, structure, hu): #MAYBE JUST PASS THE IMAGE OBJECT AND DICOM OBJECT?? """Override all HUs inside of specified structure""" ds = pydicom.dcmread(structure_file) img = None if type(image) == str: #Assume we have file path img = itk.imread(image) else: #Assume we have itk image object img = image aroi = roiutils.region_of_interest(ds, structure) mask = aroi.get_mask(img, corrected=False) pix_mask = itk.array_view_from_image(mask) pix_img = itk.array_view_from_image(img) if (pix_mask.shape != pix_img.shape): print("Inconsistent shapes of mask and image") pix_img_flat = pix_img.flatten() for i, val in enumerate(pix_mask.flatten()): if val == 1: pix_img_flat[i] = hu pix_img = pix_img_flat.reshape(pix_img.shape) img_modified = itk.image_view_from_array(pix_img) img_modified.CopyInformation(img) #itk.imwrite(img_modified, output_img ) return img_modified
def test_checkerboards(self): logger.debug( "test 3D checkerboards: have D=0.25 in even voxels and D=0.75 in odd voxels for ref image, vice versa for test image." ) #for every voxel in the target image, the neighboring voxels in the ref image has the same dose #therefore the gamma index should be equal to spacing/dta for all voxels. #logger.debug('Test_GammaIndex3dIdenticalMesh test_checkerboards') nx, ny, nz = 4, 5, 6 ix, iy, iz = np.meshgrid(np.arange(nx, dtype=int), np.arange(ny, dtype=int), np.arange(nz, dtype=int), indexing='ij') a_odd = 0.5 * (((ix + iy + iz) % 2) == 1).astype(float) + 0.25 a_even = 0.5 * (((ix + iy + iz) % 2) == 0).astype(float) + 0.25 img_odd = itk.image_from_array(a_odd) img_even = itk.image_from_array(a_even) img_gamma_even_odd = gamma_index_3d_equal_geometry(img_even, img_odd, dd=10., dta=2.) img_gamma_odd_even = gamma_index_3d_equal_geometry(img_odd, img_even, dd=10., dta=2.) self.assertTrue( np.allclose(itk.array_view_from_image(img_gamma_odd_even), itk.array_view_from_image(img_gamma_even_odd))) self.assertTrue( np.allclose(itk.array_view_from_image(img_gamma_odd_even), 0.5)) logger.debug("DONE test checkerboards")
def image_filter_wrapper(*args, **kwargs): have_array_input = False have_xarray_input = False args_list = list(args) for index, arg in enumerate(args): if _HAVE_XARRAY and isinstance(arg, xr.DataArray): have_xarray_input = True image = itk.image_from_xarray(arg) args_list[index] = image elif not isinstance(arg, itk.Object) and is_arraylike(arg): have_array_input = True array = np.asarray(arg) image = itk.image_view_from_array(array) args_list[index] = image potential_image_input_kwargs = ('input', 'input1', 'input2', 'input3') for key, value in kwargs.items(): if (key.lower() in potential_image_input_kwargs or "image" in key.lower()): if _HAVE_XARRAY and isinstance(value, xr.DataArray): have_xarray_input = True image = itk.image_from_xarray(value) kwargs[key] = image elif not isinstance(value, itk.Object) and is_arraylike(value): have_array_input = True array = np.asarray(value) image = itk.image_view_from_array(array) kwargs[key] = image if have_xarray_input or have_array_input: # Convert output itk.Image's to numpy.ndarray's output = image_filter(*tuple(args_list), **kwargs) if isinstance(output, tuple): output_list = list(output) for index, value in output_list: if isinstance(value, itk.Image): if have_xarray_input: data_array = itk.xarray_from_image(value) output_list[index] = data_array else: array = itk.array_view_from_image(value) output_list[index] = array return tuple(output_list) else: if isinstance(output, itk.Image): if have_xarray_input: output = itk.xarray_from_image(output) else: output = itk.array_view_from_image(output) return output else: return image_filter(*args, **kwargs)
def test_EqualMesh(self): # For equal meshes, the "unequalmesh" implementation should give the # same results as "equal mesh" implementation. logger.debug('Test_GammaIndex3dUnequalMesh test_EqualMesh') np.random.seed(71234567) for i in range(5): logger.debug( "{}. comparing implementations with 'equal' and 'unequal' geometry assumptions" .format(i)) nxyz = np.random.randint(25, 35, 3) oxyz = np.random.uniform(-100., 100., 3) sxyz = np.random.uniform(0.5, 2.5, 3) img_ref = itk.image_from_array( np.ones(nxyz, dtype=float).swapaxes(0, 2).copy()) img_ref.SetOrigin(oxyz) img_ref.SetSpacing(sxyz) img_target = itk.image_from_array( np.random.normal(1., 0.05, nxyz).swapaxes(0, 2).copy()) img_target.SetOrigin(oxyz) img_target.SetSpacing(sxyz) t0 = datetime.now() img_gamma_equal = gamma_index_3d_equal_geometry(img_ref, img_target, dd=3., dta=2.0) t1 = datetime.now() logger.debug( "{}. equal implementation with {} voxels took {}".format( i, np.prod(nxyz), t1 - t0)) img_gamma_unequal = gamma_index_3d_unequal_geometry(img_ref, img_target, dd=3., dta=2.0) t2 = datetime.now() logger.debug( "{}. unequal implementation with {} voxels took {}".format( i, np.prod(nxyz), t2 - t1)) aeq = itk.array_view_from_image(img_gamma_equal) auneq = itk.array_view_from_image(img_gamma_unequal) logger.debug("eq min/median/mean/max={}/{}/{}/{}".format( np.min(aeq), np.median(aeq), np.mean(aeq), np.max(aeq))) logger.debug("uneq min/median/mean/max={}/{}/{}/{}".format( np.min(auneq), np.median(auneq), np.mean(auneq), np.max(auneq))) logger.debug("{} out of {} are close".format( np.sum(np.isclose(aeq, auneq)), np.prod(aeq.shape))) logger.debug("eq first 2x2x2: {}".format(aeq[:2, :2, :2])) logger.debug("uneq first 2x2x2: {}".format(auneq[:2, :2, :2])) logger.debug("eq last 2x2x2: {}".format(aeq[-2:, -2:, -2:])) logger.debug("uneq last 2x2x2: {}".format(auneq[-2:, -2:, -2:])) self.assertTrue(np.allclose(aeq, auneq)) logger.debug("Yay!")
def ctvi(exhale, inhale, lung_mask, output, radius_erode_mask, sigma_gauss, radius_median, rho_normalize): ''' Doc todo ''' exhale = itk.imread(exhale) inhale = itk.imread(inhale) lung_mask = itk.imread(lung_mask) # options options = Box() options.ventil_type = 'Kipritidis2015' options.rho_normalize = rho_normalize options.sigma_gauss = sigma_gauss options.radius_median = radius_median options.remove_10pc = False options.mass_corrected_inhale = True if radius_erode_mask != 0: mask = itk.array_view_from_image(lung_mask) mask[mask != 0] = 1 lung_mask = erode_mask(lung_mask, radius_erode_mask) # go ctvi = compute_ctvi(exhale, inhale, lung_mask, options) itk.imwrite(ctvi, output)
def itkimage_to_json(itkimage, manager=None): """Serialize a Python itk.Image object. Attributes of this dictionary are to be passed to the JavaScript itkimage constructor. """ if itkimage is None: return None else: direction = itkimage.GetDirection() directionMatrix = direction.GetVnlMatrix() directionList = [] dimension = itkimage.GetImageDimension() pixelArr = itk.array_view_from_image(itkimage) compressor = zstd.ZstdCompressor(level=3) compressed = compressor.compress(pixelArr.data) pixelArrCompressed = memoryview(compressed) for col in range(dimension): for row in range(dimension): directionList.append(directionMatrix.get(row, col)) componentType, pixelType = _image_to_type(itkimage) imageType = dict(dimension=dimension, componentType=componentType, pixelType=pixelType, components=itkimage.GetNumberOfComponentsPerPixel()) return dict(imageType=imageType, origin=tuple(itkimage.GetOrigin()), spacing=tuple(itkimage.GetSpacing()), size=tuple(itkimage.GetBufferedRegion().GetSize()), direction={ 'data': directionList, 'rows': dimension, 'columns': dimension }, compressedData=pixelArrCompressed)
def test_Shift(self): # two images identical up to a translation less than half the spacing should yield a gamma index # equal to the ratio of the length of the translation vector and the DTA. logger.debug('Test_GammaIndex3dUnequalMesh test_Shift') np.random.seed(1234568) for i in range(5): logger.debug("shift image no. {}".format(i)) nxyz = np.random.randint(5, 15, 3) oxyz = np.random.uniform(-100., 100., 3) sxyz = np.random.uniform(0.5, 2.5, 3) txyz = np.random.uniform(-0.5, 0.5, 3) * sxyz data = np.random.normal(1., 0.1, nxyz) img_ref = itk.image_from_array(data.swapaxes(0, 2).copy()) img_ref.SetSpacing(sxyz) img_ref.SetOrigin(oxyz) img_target = itk.image_from_array(data.swapaxes( 0, 2).copy()) # same as ref img_target.SetSpacing(sxyz) # same as ref img_target.SetOrigin(oxyz + txyz) # translated! ddp = 3.0 # % dta = 2.0 # mm img_gamma = gamma_index_3d_unequal_geometry(img_ref, img_target, dd=ddp, dta=dta) agamma = itk.array_view_from_image(img_gamma).swapaxes(0, 2) gval_expected = np.sqrt(np.sum((txyz / dta)**2)) self.assertTrue(np.allclose(agamma, gval_expected)) logger.debug("ok #voxels={} gval_exp={}".format( np.prod(nxyz), gval_expected))
def get_profile(image_or_array): image_from_array = to_itk_image(image_or_array) if image_from_array: image_ = image_from_array else: image_ = image_or_array image_array = itk.array_view_from_image(image_) dimension = image_.GetImageDimension() distance = np.sqrt( sum([(profiler.point1[ii] - profiler.point2[ii])**2 for ii in range(dimension)])) index1 = tuple( image_.TransformPhysicalPointToIndex( tuple(profiler.point1[:dimension]))) index2 = tuple( image_.TransformPhysicalPointToIndex( tuple(profiler.point2[:dimension]))) num_points = int( np.round( np.sqrt( sum([(index1[ii] - index2[ii])**2 for ii in range(dimension)])) * 2.1)) coords = [ np.linspace(index1[ii], index2[ii], num_points) for ii in range(dimension) ] mapped = scipy.ndimage.map_coordinates(image_array, np.vstack(coords[::-1]), order=order, mode='nearest') return np.linspace(0.0, distance, num_points), mapped
def get_stats_struct(uncertpath, dicom_struct, struct_name): """Generate stats from a dose image and uncertainty image; but only for pixels inside specified structure """ uncertimg = itk.imread(uncertpath) uncert_flat = itk.array_from_image(uncertimg).flatten() ds = pydicom.dcmread(dicom_struct) aroi = roiutils.region_of_interest(ds, struct_name) mask = aroi.get_mask(uncertimg, corrected=False) mask_voxels_flat = itk.array_view_from_image(mask).flatten() relevant_uncerts = [] for i, val in enumerate(mask_voxels_flat): if val == 1: relevant_uncerts.append(uncert_flat[i]) relevant_uncerts = np.array(relevant_uncerts) print() print("Number of voxels in {} = {}".format(struct_name, len(relevant_uncerts))) print("Mean uncertainty = {}".format(relevant_uncerts.mean())) print("Median = {}".format(np.median(relevant_uncerts))) print("Max = {}".format(relevant_uncerts.max())) print("Min = {}".format(relevant_uncerts.min())) print("Std dev = {}".format(relevant_uncerts.std())) # Make histogram ymax = int(relevant_uncerts.max() * 100 + 2) binsize = 0.01 bins = [i * binsize for i in range(int(ymax / binsize))] plt.hist(100 * relevant_uncerts, bins=bins) plt.xlabel("Dose uncertainty (%)") plt.show()
def test_image_from_image_layer_metadata(): data = np.random.randint(256, size=(10, 10, 3), dtype=np.uint8) metadata = {"wookies": 7, "units": "mm"} image_layer = napari.layers.Image(data, metadata=metadata) image = itk_napari_conversion.image_from_image_layer(image_layer) assert np.array_equal(data, itk.array_view_from_image(image)) assert image["wookies"] == 7 assert image["units"] == "mm"
def test_image_from_image_layer_scale(): data = np.random.randint(256, size=(10, 10), dtype=np.uint8) metadata = {"wookies": 7, "units": "mm"} scale = [1.1, 2.2] image_layer = napari.layers.Image(data, scale=scale) image = itk_napari_conversion.image_from_image_layer(image_layer) assert np.array_equal(data, itk.array_view_from_image(image)) assert np.allclose(scale, np.array(image["spacing"]))
def test_image_from_image_layer_translate(): data = np.random.randint(256, size=(10, 10), dtype=np.uint8) metadata = {"wookies": 7, "units": "mm"} translate = [1.1, 2.2] image_layer = napari.layers.Image(data, translate=translate) image = itk_napari_conversion.image_from_image_layer(image_layer) assert np.array_equal(data, itk.array_view_from_image(image)) assert np.allclose(translate, np.array(image["origin"]))
def estimate_uncertainty(self): if self.n < 2: return if self.mask: amask = itk.array_view_from_image(self.mask) logger.info( "applying mask with {} voxels enabled out of {}".format( np.sum(amask > 0), np.prod(amask.shape))) self.dosesum *= amask self.dose2sum *= amask logger.info("dose sum is nonzero in {} voxels".format( np.sum(self.dosesum > 0))) logger.info("dose**2 sum is nonzero in {} voxels".format( np.sum(self.dose2sum > 0))) logger.info("sum of weights is {}, wmin={}, wmax={}".format( self.weightsum, self.wmin, self.wmax)) amean = self.dosesum / self.weightsum amean2 = self.dose2sum / self.weightsum avariance = amean2 - amean**2 m0 = avariance < 0 logger.info("negative variance in {} voxels".format(np.sum(m0))) avariance[m0] = 0. m0 = amean < 0 logger.info("negative mean in {} voxels".format(np.sum(m0))) amean[m0] = 0. m0 = amean > 0 m00 = amean2 > 0 logger.info("positive mean in {} voxels".format(np.sum(m0))) logger.info("positive mean of squares in {} voxels".format( np.sum(m00))) logger.info( "positive mean and mean of squares masks are different in {} voxels" .format(np.sum(m0 != m00))) logger.info("average/median of nonzero variance in is {}/{}".format( np.mean(avariance[m0]), np.median(avariance[m0]))) logger.info("average/median of nonzero mean in is {}/{}".format( np.mean(amean[m0]), np.median(amean[m0]))) logger.info( "average/median of nonzero mean of squares in is {}/{}".format( np.mean(amean2[m0]), np.median(amean2[m0]))) logger.info( "average/median of nonzero square of the mean in is {}/{}".format( np.mean(amean[m0]**2), np.median(amean[m0]**2))) std_pct = np.full_like(avariance, 100.) std_pct[m0] = np.sqrt(avariance[m0] / self.n) * 100. / amean[m0] dmax = np.mean(np.partition(amean.flat, -self.ntop)[-self.ntop:]) dthr = dmax * self.toppct / 100.0 mask = (amean > dthr) logger.info( "{} voxels have more than {} percent of the 'max dose'".format( np.sum(mask), self.toppct)) self.mean_unc_pct = np.mean(std_pct[mask]) # if no goal is specified, this will never converge converged = self.mean_unc_pct < self.cfg.unc_goal_pct logger.info( "'mean uncertainty' = {0:.2f} pct, goal = {1} pct, => {2}".format( self.mean_unc_pct, self.cfg.unc_goal_pct, "CONVERGED" if converged else "CONTINUE"))
def test_five_2D_images(self): logger.info('Test_Sum test_five_2D_images') nx,ny = 4,5 hundred = 100 thousand = 1000 spacing = (42.,24.) origin = (4242.,2424.) # float images imglistF = [ itk.image_from_array(np.arange(nx*ny,dtype=np.float32).reshape(nx,ny).copy()), itk.image_from_array(np.arange(nx*ny,dtype=np.float32)[::-1].reshape(nx,ny).copy()), itk.image_from_array(np.arange(0,nx*ny*hundred,hundred,dtype=np.float32).reshape(nx,ny).copy()), itk.image_from_array(np.arange(0,nx*ny*hundred,hundred,dtype=np.float32)[::-1].reshape(4,5).copy()), itk.image_from_array(thousand*np.ones((nx,ny),dtype=np.float32)) ] for imgF in imglistF: imgF.SetSpacing( spacing ) imgF.SetOrigin( origin ) imgsumF = image_sum(input_list=imglistF) logger.debug("got image with spacing {}".format(imgsumF.GetSpacing())) index = imgsumF.GetLargestPossibleRegion().GetSize() -1 logger.debug("get sum value {} while expecting {}".format(imgsumF.GetPixel(index),4.*5. -1.)) self.assertTrue( np.allclose(itk.array_view_from_image(imgsumF),nx*ny-1.+(nx*ny-1.)*hundred +thousand) ) # floats: approximate equality self.assertTrue( itk.array_from_image(imgsumF).shape == (nx,ny)) self.assertTrue( np.allclose(imgsumF.GetSpacing(),spacing)) self.assertTrue( np.allclose(imgsumF.GetOrigin(),origin)) # unsigned short int images ("US" in itk lingo) nx,ny = 40,50 ten = 10 thirteen = 13 spacing = (32.,23.) origin = (3232.,2323.) imglistUS = [ itk.image_from_array(np.arange(nx*ny,dtype=np.uint16).reshape(nx,ny).copy()), itk.image_from_array(np.arange(nx*ny,dtype=np.uint16)[::-1].reshape(nx,ny).copy()), itk.image_from_array(np.arange(0,ten*nx*ny,ten,dtype=np.uint16).reshape(nx,ny).copy()), itk.image_from_array(np.arange(0,ten*nx*ny,ten,dtype=np.uint16)[::-1].reshape(nx,ny).copy()), itk.image_from_array(thirteen*np.ones((nx,ny),dtype=np.uint16)) ] for imgUS in imglistUS: imgUS.SetSpacing( spacing ) imgUS.SetOrigin( origin ) imgsumUS = image_sum(input_list=imglistUS) logger.debug("got image with spacing {}".format(imgsumUS.GetSpacing())) logger.debug("get sum value {} while expecting {}".format(imgsumUS.GetPixel(index),40*50-1+10*40*50-10+13)) self.assertTrue( (itk.array_view_from_image(imgsumUS)==nx*ny-1+ten*nx*ny-ten+thirteen).all() ) # ints: exact equality self.assertTrue( itk.array_from_image(imgsumUS).shape == (nx,ny)) self.assertTrue( np.allclose(imgsumUS.GetSpacing(),spacing)) self.assertTrue( np.allclose(imgsumUS.GetOrigin(),origin))
def _validate_label_image_weights(self, proposal): """Check the number of weights equals the number of labels.""" value = proposal['value'] value = np.array(value, dtype=np.float32) if self.rendered_label_image: labels = len(np.unique(itk.array_view_from_image(self.rendered_label_image))) if labels != len(value): raise TraitError('Number of labels, {0}, does not equal number of label weights, {1}'.format(labels, len(value))) return value
def _get_array_data(self, img: Image) -> np.ndarray: """ Get the raw array data of the image, converted to Numpy array. Args: img: a ITK image object loaded from a image file. """ return itk.array_view_from_image(img, keep_axes=not self.c_order_axis_indexing)
def _apply_operation_to_image_list(op, input_list, output_file=None): img_list = _image_list(input_list) if len(img_list) == 1: return _image_output(img_list[0], output_file) np_list = [ itk.array_view_from_image(img) for img in img_list] np_result = reduce(op, np_list) img = itk.image_from_array(np_result) img.CopyInformation(img_list[0]) return _image_output(img, output_file)
def _get_array_data(self, img) -> np.ndarray: """ Get the raw array data of the image, converted to Numpy array. Args: img: a ITK image object loaded from a image file. """ return itk.array_view_from_image(img, keep_axes=False)
def get_profile(self, image_or_array=None, point1=None, point2=None, order=None): """Calculate the line profile. Calculate the pixel intensity values along the line that connects the given two points. The image can be 2D or 3D. If any/all of the parameters are None, default vales are assigned. Parameters ---------- image_or_array : array_like, itk.Image, or vtk.vtkImageData The 2D or 3D image to visualize. point1 : list of float List elements represent the 2D/3D coordinate of the point1. point2 : list of float List elements represent the 2D/3D coordinate of the point2. order : int, optional Spline order for line profile interpolation. The order has to be in the range 0-5. """ if not have_scipy: raise RuntimeError('The scipy package in necessary for the line_profiler widget.') if not have_itk: raise RuntimeError('The itk package in necessary for the line_profiler widget.') if image_or_array is None: image_or_array = self.image if point1 is None: point1 = self.point1 if point2 is None: point2 = self.point2 if order is None: order = self.order image = to_itk_image(image_or_array) image_array = itk.array_view_from_image(image) dimension = image.GetImageDimension() distance = np.sqrt( sum([(point1[ii] - point2[ii])**2 for ii in range(dimension)])) index1 = tuple(image.TransformPhysicalPointToIndex( tuple(point1[:dimension]))) index2 = tuple(image.TransformPhysicalPointToIndex( tuple(point2[:dimension]))) num_points = int(np.round( np.sqrt(sum([(index1[ii] - index2[ii])**2 for ii in range(dimension)])) * 2.1)) coords = [np.linspace(index1[ii], index2[ii], num_points) for ii in range(dimension)] mapped = scipy.ndimage.map_coordinates(image_array, np.vstack(coords[::-1]), order=order, mode='nearest') return np.linspace(0.0, distance, num_points), mapped
def test_scaling(self): logger.debug("test scaling small") # two images identical up to a scaling factor 1.03 should give gamma(3%)<=1.0 in all voxels logger.debug('Test_GammaIndex3dIdenticalMesh test_scaling') np.random.seed(1234567) a_rnd = np.random.uniform(0., 10., (4, 5, 6)) img1 = itk.image_from_array(a_rnd) img2 = itk.image_from_array(1.03 * a_rnd) img_gamma = gamma_index_3d_equal_geometry(img1, img2, dd=3., dta=2.0) self.assertTrue((itk.array_view_from_image(img_gamma) < 1.0001).all()) logger.debug("DONE test scaling")
def test_identity(self): # two identical images should give gamma=0.0 in all voxels logger.debug("test identity") logger.debug('Test_GammaIndex3dIdenticalMesh test_identity') np.random.seed(1234567) a_rnd = np.random.uniform(0., 10., (4, 5, 6)) img1 = itk.image_from_array(a_rnd) img2 = itk.image_from_array(a_rnd) img_gamma = gamma_index_3d_equal_geometry(img1, img2, dd=3., dta=2.0) self.assertTrue((itk.array_view_from_image(img_gamma) == 0.).all()) logger.debug("DONE test identity")
def image_std(input_list=[],output_file=None): """ Computes element-wise standard deviation of a list of image with equal geometry. """ img_list = _image_list(input_list) if len(img_list) == 1: return _image_output(img_list[0], output_file) np_list = [ itk.array_view_from_image(img) for img in img_list] np_result = np.std(np_list, axis=0) img = itk.image_from_array(np_result) img.CopyInformation(img_list[0]) return _image_output(img, output_file)