def test_back_project_with_slor_weights(self): image_shape = (324, 128, 68) voxel_size_mm = 0.5 sigma = voxel_size_mm model = miil.recon.BreastPETSystemMatrix(image_shape, voxel_size_mm=voxel_size_mm, sigma=sigma, tor_width=1) weight_val = 2.0 slor_weights = weight_val * np.ones(miil.no_slors()) lors = np.array((855655487, ), dtype=np.int64) # LOR straight across FOV val = model._back_project(lors, slor_weights=slor_weights) x_mm = voxel_size_mm * (np.arange(0, image_shape[0]) - image_shape[0] / 2 + 0.5) z_mm = voxel_size_mm * (np.arange(0, image_shape[2]) - image_shape[2] / 2 + 0.5) pos0, pos1 = miil.get_lor_positions(lors) ref = np.ones(image_shape, dtype=np.float32) d2 = ((pos0[0,0] - x_mm[:, None, None]) / voxel_size_mm) ** 2 + \ ((pos0[0,2] - z_mm[None, None, :]) / voxel_size_mm) ** 2 d2_exp = np.exp(-d2 * sigma) d2_exp[d2 > 1.0] = 0 ref *= d2_exp ref *= weight_val assert (((val == 0) == (ref == 0)).all()) assert ((np.abs(val - ref) < 1e-5).all()) val = model.back_project(lors, slor_weights=slor_weights) assert (((val == 0) == (ref == 0)).all()) assert ((np.abs(val - ref) < 1e-5).all())
def back_project(self, lors=None, value=None, crystal_weights=None, slor_weights=None, subset_size=40000000): if lors is None: no_lors = miil.no_lors(self.system_shape) else: lors = np.ascontiguousarray(lors, dtype=np.int64) no_lors = lors.size if value is not None: value = np.asarray(value) if value.size != no_lors: raise RuntimeError('''Number of values is not equal to the number of LORs''') if crystal_weights is not None: crystal_weights = np.ascontiguousarray(crystal_weights, dtype=np.float64) if crystal_weights.size != miil.no_crystals(self.system_shape): raise RuntimeError('''Number of crystal weights is not equal to the number of crystals''') if slor_weights is not None: slor_weights = np.ascontiguousarray(slor_weights, dtype=np.float64) if slor_weights.size != miil.no_slors(self.system_shape): raise RuntimeError('''Number of slor weights is not equal to the number of slors''') image = np.zeros(self.image_size, dtype=np.float32) start_idxs = np.arange(0, no_lors, subset_size) end_idxs = np.minimum( np.arange(0, no_lors, subset_size) + subset_size, no_lors) for start_idx, end_idx in zip(start_idxs, end_idxs): if lors is None: local_lors = np.arange(start_idx, end_idx) else: local_lors = lors[start_idx:end_idx] if value is None: local_value = None else: local_value = value[start_idx:end_idx] local_image = self._back_project( local_lors, value=local_value, crystal_weights=crystal_weights, slor_weights=slor_weights) image += local_image return image
def test_forward_project_to_slors(self): image_shape = (324, 128, 68) model = miil.recon.BreastPETSystemMatrix(image_shape, voxel_size_mm=0.5, tor_width=-1) lors = np.array((855655487, ), dtype=np.int64) # LOR straight across FOV ref = 2.0 slor_weights = ref * np.ones(miil.no_slors()) val = model.forward_project(np.ones(image_shape, np.float32), lors, slor_weights=slor_weights, return_val=False, return_slors=True) expected = miil.lor_to_slor_bins(lors, model.system_shape) * \ ref * image_shape[1] assert ((val == expected).all())
def test_forward_project_with_slor_weights(self): image_shape = (324, 128, 68) model = miil.recon.BreastPETSystemMatrix(image_shape, voxel_size_mm=0.5, tor_width=-1) lors = np.array((855655487, ), dtype=np.int64) # LOR straight across FOV ref = 2.0 slor_weights = ref * np.ones(miil.no_slors()) val = model._forward_project(np.ones(image_shape, np.float32), lors, slor_weights=slor_weights) assert ((val == ref * image_shape[1]).all()) val = model.forward_project(np.ones(image_shape, np.float32), lors, slor_weights=slor_weights) assert ((val == ref * image_shape[1]).all())
def forward_project(self, image, lors=None, weight=None, crystal_weights=None, slor_weights=None, subset_size=40000000, return_val=True, return_slors=False, return_crystals=False): image = np.ascontiguousarray(image, dtype=np.float32) if not return_val and not return_crystals and not return_slors: raise ValueError('No output selected') if lors is None: no_lors = miil.no_lors(self.system_shape) else: lors = np.ascontiguousarray(lors, dtype=np.int64) no_lors = lors.size no_crystals = miil.no_crystals(self.system_shape) no_slors = miil.no_slors(self.system_shape) if return_val: lor_val = np.zeros(no_lors, dtype=np.float32) if return_crystals: crystal_val = np.zeros(no_crystals) if return_slors: slor_val = np.zeros(no_slors) if weight is not None: weight = np.asarray(weight) if weight.size != no_lors: raise RuntimeError('''Number of weights is not equal to the number of LORs''') start_idxs = np.arange(0, no_lors, subset_size) end_idxs = np.minimum((start_idxs + subset_size), no_lors) for start_idx, end_idx in zip(start_idxs, end_idxs): if lors is None: local_lors = np.arange(start_idx, end_idx) else: local_lors = lors[start_idx:end_idx] if weight is None: local_weight = None else: local_weight = weight[start_idx:end_idx] val = self._forward_project(image, local_lors, weight=local_weight, crystal_weights=crystal_weights, slor_weights=slor_weights) if return_val: lor_val[start_idx:end_idx] = val.copy() if return_slors: slor_idx = miil.lor_to_slor(local_lors, self.system_shape) slor_val += np.bincount(slor_idx, weights=val, minlength=no_slors) if return_crystals: c0, c1 = miil.lor_to_crystals(local_lors, self.system_shape) crystal_val += np.bincount(c0, weights=val, minlength=no_crystals) crystal_val += np.bincount(c1, weights=val, minlength=no_crystals) out = [] if return_val: out.append(lor_val) if return_slors: out.append(slor_val) if return_crystals: out.append(crystal_val) if len(out) > 1: return out else: return out[0]