def test_piesno(): # Values taken from hispeed.OptimalPIESNO with the test data # in the package computed in matlab test_piesno_data = nib.load(dipy.data.get_data("test_piesno")).get_data() sigma = piesno(test_piesno_data, N=8, alpha=0.01, l=1, eps=1e-10, return_mask=False) assert_almost_equal(sigma, 0.010749458025559) noise1 = (np.random.randn(100, 100, 100) * 50) + 10 noise2 = (np.random.randn(100, 100, 100) * 50) + 10 rician_noise = np.sqrt(noise1**2 + noise2**2) sigma, mask = piesno(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True) # less than 3% of error? assert_(np.abs(sigma - 50) / sigma < 0.03) # Test using the median as the initial estimation initial_estimation = (np.median(sigma) / np.sqrt(2 * _inv_nchi_cdf(1, 1, 0.5))) sigma, mask = _piesno_3D(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True, initial_estimation=initial_estimation) assert_(np.abs(sigma - 50) / sigma < 0.03) sigma = _piesno_3D(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=False, initial_estimation=initial_estimation) assert_(np.abs(sigma - 50) / sigma < 0.03) sigma = _piesno_3D(np.zeros_like(rician_noise), N=1, alpha=0.01, l=1, eps=1e-10, return_mask=False, initial_estimation=initial_estimation) assert_(np.all(sigma == 0)) sigma, mask = _piesno_3D(np.zeros_like(rician_noise), N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True, initial_estimation=initial_estimation) assert_(np.all(sigma == 0)) assert_(np.all(mask == 0)) # Check if no noise points found in array it exits sigma = _piesno_3D(1000*np.ones_like(rician_noise), N=1, alpha=0.01, l=1, eps=1e-10, return_mask=False, initial_estimation=10) assert_(np.all(sigma == 10))
def test_piesno(): # Values taken from hispeed.OptimalPIESNO with the test data # in the package computed in matlab test_piesno_data = nib.load(dpd.get_fnames("test_piesno")).get_data() sigma = piesno(test_piesno_data, N=8, alpha=0.01, l=1, eps=1e-10, return_mask=False) assert_almost_equal(sigma, 0.010749458025559) noise1 = (np.random.randn(100, 100, 100) * 50) + 10 noise2 = (np.random.randn(100, 100, 100) * 50) + 10 rician_noise = np.sqrt(noise1**2 + noise2**2) sigma, mask = piesno(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True) # less than 3% of error? assert_(np.abs(sigma - 50) / sigma < 0.03) # Test using the median as the initial estimation initial_estimation = (np.median(sigma) / np.sqrt(2 * _inv_nchi_cdf(1, 1, 0.5))) sigma, mask = _piesno_3D(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True, initial_estimation=initial_estimation) assert_(np.abs(sigma - 50) / sigma < 0.03) sigma = _piesno_3D(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=False, initial_estimation=initial_estimation) assert_(np.abs(sigma - 50) / sigma < 0.03) sigma = _piesno_3D(np.zeros_like(rician_noise), N=1, alpha=0.01, l=1, eps=1e-10, return_mask=False, initial_estimation=initial_estimation) assert_(np.all(sigma == 0)) sigma, mask = _piesno_3D(np.zeros_like(rician_noise), N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True, initial_estimation=initial_estimation) assert_(np.all(sigma == 0)) assert_(np.all(mask == 0)) # Check if no noise points found in array it exits sigma = _piesno_3D(1000*np.ones_like(rician_noise), N=1, alpha=0.01, l=1, eps=1e-10, return_mask=False, initial_estimation=10) assert_(np.all(sigma == 10))
def _get_piesno_sigma(vol, log, args): data = vol.get_data() sigma = np.zeros(data.shape[:3], dtype=np.float32) mask_noise = np.zeros(data.shape[:3], dtype=np.int16) for idx in range(data.shape[-2]): log.info('Now processing slice %s out of %s', idx + 1, data.shape[-2]) sigma[..., idx], mask_noise[..., idx] = \ piesno(data[..., idx, :], N=args.N, return_mask=True) if args.save_piesno_mask is not None: nib.save(nib.Nifti1Image(mask_noise, vol.affine, vol.header), args.save_piesno_mask) # If the noise mask has few voxels, the detected noise standard # deviation can be very low and maybe something went wrong. We # check here that at least 1% of noisy voxels were found and warn # the user otherwise. frac_noisy_voxels = np.sum(mask_noise) / np.size(mask_noise) * 100 if frac_noisy_voxels < 1.: log.warning( 'PIESNO was used with N={}, but it found only {:.3f}% of voxels ' 'as pure noise with a mean standard deviation of {:.5f}. This is ' 'suspicious, so please check the resulting sigma volume if ' 'something went wrong. In cases where PIESNO is not working, ' 'you might want to try --noise_est basic'.format( args.N, frac_noisy_voxels, np.mean(sigma))) else: log.info('The noise standard deviation from piesno is %s', np.array_str(sigma[0, 0, :])) return sigma
def local_piesno(data, N, size=5, return_mask=True): m_out = np.zeros(data.shape[:-1], dtype=np.bool) reshaped_maps = sliding_window(data, (size, size, size, data.shape[-1])) sigma = np.zeros(reshaped_maps.shape[0], dtype=np.float32) mask = np.zeros((reshaped_maps.shape[0], size**3), dtype=np.bool) for i in range(reshaped_maps.shape[0]): cur_map = reshaped_maps[i].reshape(size**3, 1, -1) sigma[i], m = piesno(cur_map, N=N, return_mask=True) mask[i] = np.squeeze(m) s_out = sigma.reshape(data.shape[0] // size, data.shape[1] // size, data.shape[2] // size) for n, i in enumerate(np.ndindex(s_out.shape)): i = np.array(i) * size j = i + size m_out[i[0]:j[0], i[1]:j[1], i[2]:j[2]] = mask[n].reshape(size, size, size) interpolated = np.zeros_like(data[..., 0], dtype=np.float32) x, y, z = np.array(s_out.shape) * size interpolated[:x, :y, :z] = zoom(s_out, size, order=1) if return_mask: return interpolated, m_out return interpolated
def test_piesno_type(): # This is testing if the `sum_m2` cast is overflowing data = np.ones((10, 10, 10), dtype=np.int16) for i in range(10): data[:, i, :] = i * 26 sigma = piesno(data, N=2, alpha=0.01, l=1, eps=1e-10, return_mask=False) assert_almost_equal(sigma, 79.970003117424739)
def execution(self, context): data_vol = aims.read(self.dwi_data.fullPath()) header = data_vol.header() data = vol_to_array(data_vol) sigma = piesno(data, self.coil_number, alpha=self.alpha, l=self.trials, itermax=ITERMAX, eps=EPS, return_mask=False) sigma_arr = sigma*np.ones(data.shape[:-1], dtype=np.float32) sigma_vol = array_to_vol(sigma_arr, header=header) aims.write(sigma_vol, self.sigma.fullPath())
def test_piesno(): # Values taken from hispeed.OptimalPIESNO with the test data # in the package computed in matlab test_piesno_data = nib.load(dipy.data.get_data("test_piesno")).get_data() sigma = piesno(test_piesno_data, N=8, alpha=0.01, l=1, eps=1e-10, return_mask=False) assert_almost_equal(sigma, 0.010749458025559)
def main(fname_in, freedom_degree,file_output): img = nib.load(fname_in) data = img.get_data() sigma, mask = piesno(data, N=freedom_degree, return_mask=True) sct.printv('\nWrite NIFTI volumes...') output_name = file_output nib.save(nib.Nifti1Image(mask, img.get_affine(), img.get_header()), output_name) sct.printv('\n.. The noise standard deviation is sigma = ' + str(sigma))
def main(fname_in, freedom_degree, file_output): img = nib.load(fname_in) data = img.get_data() sigma, mask = piesno(data, N=freedom_degree, return_mask=True) sct.printv('\nWrite NIFTI volumes...') output_name = file_output nib.save(nib.Nifti1Image(mask, img.get_affine(), img.get_header()), output_name) sct.printv('\n.. The noise standard deviation is sigma = ' + str(sigma))
def test_piesno(): # Values taken from hispeed.OptimalPIESNO with the test data # in the package computed in matlab test_piesno_data = nib.load(dipy.data.get_data("test_piesno")).get_data() sigma = piesno(test_piesno_data, N=8, alpha=0.01, l=1, eps=1e-10, return_mask=False) assert_almost_equal(sigma, 0.010749458025559) noise1 = (np.random.randn(100, 100, 100) * 50) + 10 noise2 = (np.random.randn(100, 100, 100) * 50) + 10 rician_noise = np.sqrt(noise1**2 + noise2**2) sigma, mask = piesno(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True) # less than 3% of error? assert_almost_equal(np.abs(sigma - 50) / sigma < 0.03, True) # Test using the median as the initial estimation initial_estimation = np.median(sigma) / np.sqrt(2 * _inv_nchi_cdf(1, 1, 0.5)) sigma, mask = _piesno_3D(rician_noise, N=1, alpha=0.01, l=1, eps=1e-10, return_mask=True, initial_estimation=initial_estimation) assert_almost_equal(np.abs(sigma - 50) / sigma < 0.03, True)
def main(): parser = buildArgsParser() args = parser.parse_args() if args.savename is None: temp, ext = str.split(os.path.basename(args.input), '.', 1) filename = os.path.dirname(os.path.realpath(args.input)) + '/' + temp else: filename = args.savename # If the file already exists, check if the user want to overwrite it. If not, simply exit. filename += '_denoised.nii.gz' print("Now denoising", os.path.realpath(args.input)) vol = nib.load(args.input) affine = vol.get_affine() data = vol.get_data() if args.std is 0: print("Compute sigma with piesno") sigma = piesno(data, N=1, return_mask=False) print("sigma is: ", sigma) sigma = np.mean(sigma) print("sigma is: ", sigma) else: print("Sigma is: ", args.std) sigma = args.std if args.mask is None: print("No mask.. you should") else: print("Mask is: ", args.mask) img_mask = nib.load(args.mask) mask_t1 = img_mask.get_data() img_denoised = nlmeans(data, sigma, mask=mask_t1) nib.save(nib.Nifti1Image(img_denoised, affine), filename) print("Denoised file was saved as", filename)
fetch_sherbrooke_3shell() img, gtab = read_sherbrooke_3shell() data = img.get_data() """ Now that we have fetched a dataset, we must call PIESNO with the right number of coils used to acquire this dataset. It is also important to know what was the parallel reconstruction algorithm used. Here, the data comes from a GRAPPA reconstruction, was acquired with a 12-elements head coil available on the Tim Trio Siemens, for which the 12 coil elements are combined into 4 groups of 3 coil elements each. The signal is therefore received through 4 distinct groups of receiver channels, yielding N = 4. Had we used a GE acquisition, we would have used N=1 even if multiple channel coils are used because GE uses a SENSE reconstruction, which has a Rician noise nature and thus N is always 1. """ sigma, mask = piesno(data, N=4, return_mask=True) axial = data[:, :, data.shape[2] // 2, 0].T axial_piesno = mask[:, :, data.shape[2] // 2].T import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 2) ax[0].imshow(axial, cmap='gray', origin='lower') ax[0].set_title('Axial slice of the b=0 data') ax[1].imshow(axial_piesno, cmap='gray', origin='lower') ax[1].set_title('Background voxels from the data') for a in ax: a.set_axis_off() plt.savefig('piesno.png', bbox_inches='tight') """
def main(): parser = buildArgsParser() args = parser.parse_args() vol = nib.load(args.input) data = vol.get_data() affine = vol.get_affine() if args.mask is None: mask = np.ones(data.shape[:-1], dtype=np.bool) else: mask = nib.load(args.mask).get_data().astype(np.bool) N = args.N if args.n_cores is None: n_cores = cpu_count() else: if args.n_cores > cpu_count(): n_cores = cpu_count() else: n_cores = args.n_cores noise_method = args.noise_method smooth_method = args.smooth_method filename = args.output if noise_method == 'noise_map': if args.noise_maps is None: raise ValueError( 'You need to supply --noise_map path_to_file to use --noise_est noise_map' ) noise_maps = nib.load(args.noise_maps).get_data() # Since negatives are allowed, convert uint to int if data.dtype.kind == 'u': dtype = data.dtype.name[1:] else: dtype = data.dtype logging.info("Estimating m_hat with method " + smooth_method) if smooth_method == 'local_mean': m_hat = np.zeros_like(data, dtype=np.float32) size = (3, 3, 3) k = np.ones(size) / np.sum(size) conv_out = np.zeros_like(data[..., 0], dtype=np.float64) for idx in range(data.shape[-1]): convolve(data[..., idx], k, mode='reflect', output=conv_out) m_hat[..., idx] = conv_out elif smooth_method == 'nlmeans': nlmeans_sigma = estimate_sigma(data) m_hat = nlmeans(data, nlmeans_sigma, rician=False, mask=mask) elif smooth_method == 'no_smoothing': m_hat = np.array(data, copy=True, dtype=np.float32) elif smooth_method == 'sh_smooth': bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) gtab = gradient_table(bvals, bvecs) m_hat = sh_smooth(data, gtab, sh_order=4) logging.info("Estimating noise with method " + noise_method) if noise_method == 'piesno': sigma = np.zeros_like(data, dtype=np.float32) mask_noise = np.zeros(data.shape[:-1], dtype=np.int16) for idx in range(data.shape[-2]): logging.info("Now processing slice", idx + 1, "out of", data.shape[-2]) sigma[..., idx, :], mask_noise[..., idx] = piesno(data[..., idx, :], N=N, return_mask=True) if args.save_piesno_mask is not None: nib.save(nib.Nifti1Image(mask_noise.astype(np.int16), affine), args.save_piesno_mask) elif noise_method == 'local_std': sigma_3D = local_standard_deviation(data, n_cores=n_cores) # Compute the corrected value for each 3D volume sigma = corrected_sigma(m_hat, np.repeat(sigma_3D[..., None], data.shape[-1], axis=-1), np.repeat(mask[..., None], data.shape[-1], axis=-1), N, n_cores=n_cores) elif noise_method == 'noise_map': # Local piesno works on 4D, so we need to broadcast before if noise_maps.ndim == 3: noise_maps = noise_maps[..., None] sigma, mask_noise = local_piesno(noise_maps, N=N, return_mask=True) sigma = np.repeat(sigma[..., None], data.shape[-1], axis=-1) if args.save_piesno_mask is not None: nib.save(nib.Nifti1Image(mask_noise.astype(np.int16), affine), args.save_piesno_mask) nib.save(nib.Nifti1Image(sigma, affine), args.sigma) logging.info("Now performing stabilisation") pool = Pool(processes=n_cores) arglist = [(data[..., idx, :], m_hat[..., idx, :], np.repeat(mask[..., idx, None], data.shape[-1], axis=-1), sigma[..., idx, :], N_vox) for idx, N_vox in zip(range(data.shape[-2]), repeat(N))] data_out = pool.map(multiprocess_stabilisation, arglist) pool.close() pool.join() data_stabilized = np.empty(data.shape, dtype=dtype) for idx in range(len(data_out)): data_stabilized[..., idx, :] = data_out[idx] nib.save(nib.Nifti1Image(data_stabilized, affine), filename)
img, gtab = read_sherbrooke_3shell() data = img.get_data() """ Now that we have fetched a dataset, we must call PIESNO with the right number of coils used to acquire this dataset. It is also important to know what was the parallel reconstruction algorithm used. Here, the data comes from a GRAPPA reconstruction, was acquired with a 12-elements head coil available on the Tim Trio Siemens, for which the 12 coil elements are combined into 4 groups of 3 coil elements each. The signal is therefore received through 4 distinct groups of receiver channels, yielding N = 4. Had we used a GE acquisition, we would have used N=1 even if multiple channel coils are used because GE uses a SENSE reconstruction, which has a Rician noise nature and thus N is always 1. """ sigma, mask = piesno(data, N=4, return_mask=True) axial = data[:, :, data.shape[2] // 2, 0].T axial_piesno = mask[:, :, data.shape[2] // 2].T import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 2) ax[0].imshow(axial, cmap='gray', origin='lower') ax[0].set_title('Axial slice of the b=0 data') ax[1].imshow(axial_piesno, cmap='gray', origin='lower') ax[1].set_title('Background voxels from the data') for a in ax: a.set_axis_off() plt.savefig('piesno.png', bbox_inches='tight')
def getBackgroundIdxUsingPIESNO(data): _, mask = piesno(data, N=1, return_mask=True) return np.nonzero(mask)