def read_sherbrooke_3shell(): """ Load Sherbrooke 3-shell HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ folder = pjoin(dipy_home, 'sherbrooke_3shell') fraw = pjoin(folder, 'HARDI193.nii.gz') fbval = pjoin(folder, 'HARDI193.bval') fbvec = pjoin(folder, 'HARDI193.bvec') md5_dict = {'data': '0b735e8f16695a37bfbd66aab136eb66', 'bval': 'e9b9bb56252503ea49d31fb30a0ac637', 'bvec': '0c83f7e8b917cd677ad58a078658ebb7'} check_md5(fraw, md5_dict['data']) check_md5(fbval, md5_dict['bval']) check_md5(fbvec, md5_dict['bvec']) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def test_multi_tensor(): sphere = get_sphere('symmetric724') vertices = sphere.vertices mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) e0 = np.array([np.sqrt(2) / 2., np.sqrt(2) / 2., 0]) e1 = np.array([0, np.sqrt(2) / 2., np.sqrt(2) / 2.]) mevecs = [all_tensor_evecs(e0), all_tensor_evecs(e1)] # odf = multi_tensor_odf(vertices, [0.5, 0.5], mevals, mevecs) # assert_(odf.shape == (len(vertices),)) # assert_(np.all(odf <= 1) & np.all(odf >= 0)) fimg, fbvals, fbvecs = get_data('small_101D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) s1 = single_tensor(gtab, 100, mevals[0], mevecs[0], snr=None) s2 = single_tensor(gtab, 100, mevals[1], mevecs[1], snr=None) Ssingle = 0.5*s1 + 0.5*s2 S, sticks = MultiTensor(gtab, mevals, S0=100, angles=[(90, 45), (45, 90)], fractions=[50, 50], snr=None) assert_array_almost_equal(S, Ssingle)
def read_stanford_hardi(): """ Load Stanford HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser("~"), ".dipy") folder = pjoin(dipy_home, "stanford_hardi") fraw = pjoin(folder, "HARDI150.nii.gz") fbval = pjoin(folder, "HARDI150.bval") fbvec = pjoin(folder, "HARDI150.bvec") md5_dict = { "data": "0b18513b46132b4d1051ed3364f2acbc", "bval": "4e08ee9e2b1d2ec3fddb68c70ae23c36", "bvec": "4c63a586f29afc6a48a5809524a76cb4", } check_md5(fraw, md5_dict["data"]) check_md5(fbval, md5_dict["bval"]) check_md5(fbvec, md5_dict["bvec"]) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_taiwan_ntu_dsi(): """ Load Taiwan NTU dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser("~"), ".dipy") folder = pjoin(dipy_home, "taiwan_ntu_dsi") fraw = pjoin(folder, "DSI203.nii.gz") fbval = pjoin(folder, "DSI203.bval") fbvec = pjoin(folder, "DSI203.bvec") md5_dict = { "data": "950408c0980a7154cb188666a885a91f", "bval": "602e5cb5fad2e7163e8025011d8a6755", "bvec": "a95eb1be44748c20214dc7aa654f9e6b", "license": "7fa1d5e272533e832cc7453eeba23f44", } check_md5(fraw, md5_dict["data"]) check_md5(fbval, md5_dict["bval"]) check_md5(fbvec, md5_dict["bvec"]) check_md5(pjoin(folder, "DSI203_license.txt"), md5_dict["license"]) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) bvecs[1:] = bvecs[1:] / np.sqrt(np.sum(bvecs[1:] * bvecs[1:], axis=1))[:, None] gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_isbi2013_2shell(): """ Load ISBI 2013 2-shell synthetic dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser("~"), ".dipy") folder = pjoin(dipy_home, "isbi2013") fraw = pjoin(folder, "phantom64.nii.gz") fbval = pjoin(folder, "phantom64.bval") fbvec = pjoin(folder, "phantom64.bvec") md5_dict = { "data": "42911a70f232321cf246315192d69c42", "bval": "90e8cf66e0f4d9737a3b3c0da24df5ea", "bvec": "4b7aa2757a1ccab140667b76e8075cb1", } check_md5(fraw, md5_dict["data"]) check_md5(fbval, md5_dict["bval"]) check_md5(fbvec, md5_dict["bvec"]) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_sherbrooke_3shell(): """ Load Sherbrooke 3-shell HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser("~"), ".dipy") folder = pjoin(dipy_home, "sherbrooke_3shell") fraw = pjoin(folder, "HARDI193.nii.gz") fbval = pjoin(folder, "HARDI193.bval") fbvec = pjoin(folder, "HARDI193.bvec") md5_dict = { "data": "0b735e8f16695a37bfbd66aab136eb66", "bval": "e9b9bb56252503ea49d31fb30a0ac637", "bvec": "0c83f7e8b917cd677ad58a078658ebb7", } check_md5(fraw, md5_dict["data"]) check_md5(fbval, md5_dict["bval"]) check_md5(fbvec, md5_dict["bvec"]) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_data(fimg, fbvals, fbvecs): bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) img = nib.load(fimg) data = img.get_data() affine = img.get_affine() return data, affine, gtab
def read_stanford_hardi(): """ Load Stanford HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ folder = pjoin(dipy_home, 'stanford_hardi') fraw = pjoin(folder, 'HARDI150.nii.gz') fbval = pjoin(folder, 'HARDI150.bval') fbvec = pjoin(folder, 'HARDI150.bvec') md5_dict = {'data': '0b18513b46132b4d1051ed3364f2acbc', 'bval': '4e08ee9e2b1d2ec3fddb68c70ae23c36', 'bvec': '4c63a586f29afc6a48a5809524a76cb4'} check_md5(fraw, md5_dict['data']) check_md5(fbval, md5_dict['bval']) check_md5(fbvec, md5_dict['bvec']) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_taiwan_ntu_dsi(): """ Load Taiwan NTU dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ folder = pjoin(dipy_home, 'taiwan_ntu_dsi') fraw = pjoin(folder, 'DSI203.nii.gz') fbval = pjoin(folder, 'DSI203.bval') fbvec = pjoin(folder, 'DSI203.bvec') md5_dict = {'data': '950408c0980a7154cb188666a885a91f', 'bval': '602e5cb5fad2e7163e8025011d8a6755', 'bvec': 'a95eb1be44748c20214dc7aa654f9e6b', 'license': '7fa1d5e272533e832cc7453eeba23f44'} check_md5(fraw, md5_dict['data']) check_md5(fbval, md5_dict['bval']) check_md5(fbvec, md5_dict['bvec']) check_md5(pjoin(folder, 'DSI203_license.txt'), md5_dict['license']) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) bvecs[1:] = bvecs[1:] / np.sqrt(np.sum(bvecs[1:] * bvecs[1:], axis=1))[:, None] gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_isbi2013_2shell(): """ Load ISBI 2013 2-shell synthetic dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ folder = pjoin(dipy_home, 'isbi2013') fraw = pjoin(folder, 'phantom64.nii.gz') fbval = pjoin(folder, 'phantom64.bval') fbvec = pjoin(folder, 'phantom64.bvec') md5_dict = {'data': '42911a70f232321cf246315192d69c42', 'bval': '90e8cf66e0f4d9737a3b3c0da24df5ea', 'bvec': '4b7aa2757a1ccab140667b76e8075cb1'} check_md5(fraw, md5_dict['data']) check_md5(fbval, md5_dict['bval']) check_md5(fbvec, md5_dict['bvec']) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def test_btable_prepare(): sq2 = np.sqrt(2) / 2. bvals = 1500 * np.ones(7) bvals[0] = 0 bvecs = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [sq2, sq2, 0], [sq2, 0, sq2], [0, sq2, sq2]]) bt = gradient_table(bvals, bvecs) npt.assert_array_equal(bt.bvecs, bvecs) # bt.info fimg, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) bvecs = np.where(np.isnan(bvecs), 0, bvecs) bt = gradient_table(bvals, bvecs) npt.assert_array_equal(bt.bvecs, bvecs) bt2 = gradient_table(bvals, bvecs.T) npt.assert_array_equal(bt2.bvecs, bvecs) btab = np.concatenate((bvals[:, None], bvecs), axis=1) bt3 = gradient_table(btab) npt.assert_array_equal(bt3.bvecs, bvecs) npt.assert_array_equal(bt3.bvals, bvals) bt4 = gradient_table(btab.T) npt.assert_array_equal(bt4.bvecs, bvecs) npt.assert_array_equal(bt4.bvals, bvals) # Test for proper inputs (expects either bvals/bvecs or 4 by n): npt.assert_raises(ValueError, gradient_table, bvecs)
def test_read_bvals_bvecs(): fimg, fbvals, fbvecs = get_data('small_101D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gt = gradient_table(bvals, bvecs) npt.assert_array_equal(bvals, gt.bvals) npt.assert_array_equal(bvecs, gt.bvecs) # None should also work as an input: bvals_none, bvecs_none = read_bvals_bvecs(None, fbvecs) npt.assert_array_equal(bvecs_none, gt.bvecs) bvals_none, bvecs_none = read_bvals_bvecs(fbvals, None) npt.assert_array_equal(bvals_none, gt.bvals) # Test for error raising with unknown file formats: nan_fbvecs = osp.splitext(fbvecs)[0] + '.nan' # Nonsense extension npt.assert_raises(ValueError, read_bvals_bvecs, fbvals, nan_fbvecs) # Test for error raising with incorrect file-contents: # These bvecs only have two rows/columns: new_bvecs1 = bvecs[:, :2] # Make a temporary file bv_file1 = tempfile.NamedTemporaryFile(mode='wt') # And fill it with these 2-columned bvecs: for x in range(new_bvecs1.shape[0]): bv_file1.file.write('%s %s\n' % (new_bvecs1[x][0], new_bvecs1[x][1])) bv_file1.close() npt.assert_raises(IOError, read_bvals_bvecs, fbvals, bv_file1.name) # These bvecs are saved as one long array: new_bvecs2 = np.ravel(bvecs) bv_file2 = tempfile.NamedTemporaryFile() np.save(bv_file2, new_bvecs2) bv_file2.close() npt.assert_raises(IOError, read_bvals_bvecs, fbvals, bv_file2.name) # There are less bvecs than bvals: new_bvecs3 = bvecs[:-1, :] bv_file3 = tempfile.NamedTemporaryFile() np.save(bv_file3, new_bvecs3) bv_file3.close() npt.assert_raises(IOError, read_bvals_bvecs, fbvals, bv_file3.name) # You entered the bvecs on both sides: npt.assert_raises(IOError, read_bvals_bvecs, fbvecs, fbvecs)
def get_fitted_tensor(self, data, mask, bval, bvec, b0_threshold=0): logging.info('Diffusion kurtosis estimation...') bvals, bvecs = read_bvals_bvecs(bval, bvec) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold) dkmodel = self.get_dki_model(gtab) dkfit = dkmodel.fit(data, mask) return dkfit, gtab
def get_fitted_tensor(self, data, mask, bval, bvec, b0_threshold=0): logging.info('Tensor estimation...') bvals, bvecs = read_bvals_bvecs(bval, bvec) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold) tenmodel = self.get_tensor_model(gtab) tenfit = tenmodel.fit(data, mask) return tenfit, gtab
def setup_module(): """Module-level setup""" global gtab, gtab_2s _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) # 2 shells for techniques that requires multishell data bvals_2s = np.concatenate((bvals, bvals * 2), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = gradient_table(bvals_2s, bvecs_2s)
def get_fitted_ivim(self, data, mask, bval, bvec, b0_threshold=50): logging.info('Intra-Voxel Incoherent Motion Estimation...') bvals, bvecs = read_bvals_bvecs(bval, bvec) if b0_threshold < bvals.min(): warn("b0_threshold (value: {0}) is too low, increase your " "b0_threshold. It should higher than the first b0 value " "({1}).".format(b0_threshold, bvals.min())) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold) ivimmodel = IvimModel(gtab) ivimfit = ivimmodel.fit(data, mask) return ivimfit, gtab
def get_fitted_tensor(self, data, mask, bval, bvec, b0_threshold=50): logging.info('Diffusion kurtosis estimation...') bvals, bvecs = read_bvals_bvecs(bval, bvec) if b0_threshold < bvals.min(): warn("b0_threshold (value: {0}) is too low, increase your " "b0_threshold. It should higher than the first b0 value " "({1}).".format(b0_threshold, bvals.min())) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold) dkmodel = self.get_dki_model(gtab) dkfit = dkmodel.fit(data, mask) return dkfit, gtab
def setup_module(): """Module-level setup""" global gtab, gtab_2s, mevals, model_params_mv global DWI, FAref, GTF, MDref, FAdti, MDdti _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) # FW model requires multishell data bvals_2s = np.concatenate((bvals, bvals * 1.5), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = gradient_table(bvals_2s, bvecs_2s) # Simulation a typical DT and DW signal for no water contamination S0 = np.array(100) dt = np.array([0.0017, 0, 0.0003, 0, 0, 0.0003]) evals, evecs = decompose_tensor(from_lower_triangular(dt)) S_tissue = single_tensor(gtab_2s, S0=100, evals=evals, evecs=evecs, snr=None) dm = dti.TensorModel(gtab_2s, 'WLS') dtifit = dm.fit(S_tissue) FAdti = dtifit.fa MDdti = dtifit.md dtiparams = dtifit.model_params # Simulation of 8 voxels tested DWI = np.zeros((2, 2, 2, len(gtab_2s.bvals))) FAref = np.zeros((2, 2, 2)) MDref = np.zeros((2, 2, 2)) # Diffusion of tissue and water compartments are constant for all voxel mevals = np.array([[0.0017, 0.0003, 0.0003], [0.003, 0.003, 0.003]]) # volume fractions GTF = np.array([[[0.06, 0.71], [0.33, 0.91]], [[0., 0.], [0., 0.]]]) # S0 multivoxel S0m = 100 * np.ones((2, 2, 2)) # model_params ground truth (to be fill) model_params_mv = np.zeros((2, 2, 2, 13)) for i in range(2): for j in range(2): gtf = GTF[0, i, j] S, p = multi_tensor(gtab_2s, mevals, S0=100, angles=[(90, 0), (90, 0)], fractions=[(1-gtf) * 100, gtf*100], snr=None) DWI[0, i, j] = S FAref[0, i, j] = FAdti MDref[0, i, j] = MDdti R = all_tensor_evecs(p[0]) R = R.reshape((9)) model_params_mv[0, i, j] = \ np.concatenate(([0.0017, 0.0003, 0.0003], R, [gtf]), axis=0)
def read_isbi2013_2shell(): """ Load ISBI 2013 2-shell synthetic dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ files, folder = fetch_isbi2013_2shell() fraw = pjoin(folder, "phantom64.nii.gz") fbval = pjoin(folder, "phantom64.bval") fbvec = pjoin(folder, "phantom64.bvec") bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_stanford_hardi(): """ Load Stanford HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ files, folder = fetch_stanford_hardi() fraw = pjoin(folder, "HARDI150.nii.gz") fbval = pjoin(folder, "HARDI150.bval") fbvec = pjoin(folder, "HARDI150.bvec") bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_ivim(): """ Load IVIM dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ files, folder = fetch_ivim() fraw = pjoin(folder, "ivim.nii.gz") fbval = pjoin(folder, "ivim.bval") fbvec = pjoin(folder, "ivim.bvec") bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_sherbrooke_3shell(): """ Load Sherbrooke 3-shell HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ files, folder = fetch_sherbrooke_3shell() fraw = pjoin(folder, "HARDI193.nii.gz") fbval = pjoin(folder, "HARDI193.bval") fbvec = pjoin(folder, "HARDI193.bvec") bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_taiwan_ntu_dsi(): """ Load Tawian NTU dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser('~'), '.dipy') folder = pjoin(dipy_home, 'taiwan_ntu_dsi') fraw = pjoin(folder, 'DSI203.nii.gz') fbval = pjoin(folder, 'DSI203.bval') fbvec = pjoin(folder, 'DSI203.bvec') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_taiwan_ntu_dsi(): """ Load Taiwan NTU dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ files, folder = fetch_taiwan_ntu_dsi() fraw = pjoin(folder, "DSI203.nii.gz") fbval = pjoin(folder, "DSI203.bval") fbvec = pjoin(folder, "DSI203.bvec") bvals, bvecs = read_bvals_bvecs(fbval, fbvec) bvecs[1:] = bvecs[1:] / np.sqrt(np.sum(bvecs[1:] * bvecs[1:], axis=1))[:, None] gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_beijing_dti(): """ Load Beijing dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser('~'), '.dipy') folder = pjoin(dipy_home, 'beijing_dti') fraw = pjoin(folder, 'DTI64.nii.gz') fbval = pjoin(folder, 'DTI64.bval') fbvec = pjoin(folder, 'DTI64.bvec') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def test_FiberModel_init(): # Get some small amount of data: data_file, bval_file, bvec_file = dpd.get_fnames('small_64D') data_ni = nib.load(data_file) bvals, bvecs = read_bvals_bvecs(bval_file, bvec_file) gtab = dpg.gradient_table(bvals, bvecs) FM = life.FiberModel(gtab) streamline = [[[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]], [[1, 2, 3], [4, 5, 3], [5, 6, 3]]] affine = np.eye(4) for sphere in [None, False, dpd.get_sphere('symmetric362')]: fiber_matrix, vox_coords = FM.setup(streamline, affine, sphere=sphere) npt.assert_array_equal(np.array(vox_coords), np.array([[1, 2, 3], [4, 5, 3], [5, 6, 3], [6, 7, 3]])) npt.assert_equal(fiber_matrix.shape, (len(vox_coords) * 64, len(streamline)))
def test_predict(): SNR = 1000 S0 = 100 _, fbvals, fbvecs = dpd.get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = sims.multi_tensor(gtab, mevals, S0, angles=angles, fractions=[10, 90], snr=SNR) sfmodel = sfm.SparseFascicleModel(gtab, response=[0.0015, 0.0003, 0.0003]) sffit = sfmodel.fit(S) pred = sffit.predict() npt.assert_(xval.coeff_of_determination(pred, S) > 97) # Should be possible to predict using a different gtab: new_gtab = grad.gradient_table(bvals[::2], bvecs[::2]) new_pred = sffit.predict(new_gtab) npt.assert_(xval.coeff_of_determination(new_pred, S[::2]) > 97)
def read_cfin_dwi(): """Load CFIN multi b-value DWI data Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ files, folder = fetch_cfin_multib() fraw = pjoin(folder, '__DTI_AX_ep2d_2_5_iso_33d_20141015095334_4.nii') fbval = pjoin(folder, '__DTI_AX_ep2d_2_5_iso_33d_20141015095334_4.bval') fbvec = pjoin(folder, '__DTI_AX_ep2d_2_5_iso_33d_20141015095334_4.bvec') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def read_stanford_hardi(): """ Load Stanford HARDI dataset Returns ------- img : obj, Nifti1Image gtab : obj, GradientTable """ dipy_home = pjoin(os.path.expanduser('~'), '.dipy') folder = pjoin(dipy_home, 'stanford_hardi') fraw = pjoin(folder, 'HARDI150.nii.gz') fbval = pjoin(folder, 'HARDI150.bval') fbvec = pjoin(folder, 'HARDI150.bvec') bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) img = nib.load(fraw) return img, gtab
def tensor_model( input_filename_data, input_filename_bvecs, input_filename_bvals, output_filename_fa=None, output_filename_evecs=None ): # print 'Tensor model ...' # print 'Loading data ...' img = nib.load(input_filename_data) data = img.get_data() affine = img.get_affine() bvals, bvecs = read_bvals_bvecs(input_filename_bvals, input_filename_bvecs) gtab = gradient_table(bvals, bvecs) mask = data[..., 0] > 50 tenmodel = TensorModel(gtab) tenfit = tenmodel.fit(data, mask) FA = fractional_anisotropy(tenfit.evals) FA[np.isnan(FA)] = 0 if output_filename_fa == None: filename_save_fa = input_filename_data.split(".")[0] + "_tensor_fa.nii.gz" else: filename_save_fa = os.path.abspath(output_filename_fa) fa_img = nib.Nifti1Image(FA, img.get_affine()) nib.save(fa_img, filename_save_fa) print "Saving fa to:", filename_save_fa if output_filename_evecs == None: filename_save_evecs = input_filename_data.split(".")[0] + "_tensor_evecs.nii.gz" else: filename_save_evecs = os.path.abspath(output_filename_evecs) evecs_img = nib.Nifti1Image(tenfit.evecs, img.get_affine()) nib.save(evecs_img, filename_save_evecs) print "Saving evecs to:", filename_save_evecs return filename_save_fa, filename_save_evecs
def test_odf_sh_to_sharp(): SNR = None S0 = 1 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) S, _ = multi_tensor(gtab, mevals, S0, angles=[(10, 0), (100, 0)], fractions=[50, 50], snr=SNR) sphere = get_sphere('symmetric724') qb = QballModel(gtab, sh_order=8, assume_normed=True) qbfit = qb.fit(S) odf_gt = qbfit.odf(sphere) Z = np.linalg.norm(odf_gt) odfs_gt = np.zeros((3, 1, 1, odf_gt.shape[0])) odfs_gt[:, :, :] = odf_gt[:] odfs_sh = sf_to_sh(odfs_gt, sphere, sh_order=8, basis_type=None) odfs_sh /= Z fodf_sh = odf_sh_to_sharp(odfs_sh, sphere, basis=None, ratio=3 / 15., sh_order=8, lambda_=1., tau=0.1) fodf = sh_to_sf(fodf_sh, sphere, sh_order=8, basis_type=None) directions2, _, _ = peak_directions(fodf[0, 0, 0], sphere) assert_equal(directions2.shape[0], 2)
def main(): parser = buildArgsParser() args = parser.parse_args() bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) ren = fvtk.ren() if args.points: points = fvtk.point(bvecs * bvals[..., None] * 0.01, fvtk.colors.red, point_radius=.5) fvtk.add(ren, points) if args.antipod: points = fvtk.point(-bvecs * bvals[..., None] * 0.01, fvtk.colors.green, point_radius=.5) fvtk.add(ren, points) else: for i in range(bvecs.shape[0]): label = fvtk.label(ren, text=str(i), pos=bvecs[i] * bvals[i] * 0.01, color=fvtk.colors.red, scale=(0.5, 0.5, 0.5)) fvtk.add(ren, label) if args.antipod: label = fvtk.label(ren, text=str(i), pos=-bvecs[i] * bvals[i] * 0.01, color=fvtk.colors.green, scale=(0.5, 0.5, 0.5)) fvtk.add(ren, label) fvtk.show(ren)
def main(): parser = _build_arg_parser() args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.INFO) required_args = [args.dwi, args.bvec, args.bval, args.table] _, extension = split_name_with_nii(args.dwi) output_filenames = [ args.baseName + extension, args.baseName + '.bval', args.baseName + '.bvec' ] assert_inputs_exist(parser, required_args) assert_outputs_exist(parser, args, output_filenames) oTable = np.loadtxt(args.table, skiprows=1) bvals, bvecs = read_bvals_bvecs(args.bval, args.bvec) dwis = nb.load(args.dwi) newIndex = valideInputs(oTable, dwis, bvals, bvecs) bvecs = bvecs[newIndex] bvals = bvals[newIndex] data = dwis.get_fdata(dtype=np.float32) data = data[:, :, :, newIndex] nb.save( nb.Nifti1Image(data.astype(dwis.get_data_dtype()), dwis.affine, header=dwis.header), output_filenames[0]) np.savetxt(args.baseName + '.bval', bvals.reshape(1, len(bvals)), '%d') np.savetxt(args.baseName + '.bvec', bvecs.T, '%0.15f')
print(data.shape) # Size of data print(img.header.get_zooms()[:3]) # Checking dimensions of each voxel ############################################################# # Plotting # ############################################################# axial_middle = data.shape[2]//2 plt.figure('Showing the datasets') plt.subplot(1, 2, 1).set_axis_off() plt.imshow(data[:, :, axial_middle, 0].T, cmap='gray', origin='lower') plt.subplot(1, 2, 2).set_axis_off() plt.imshow(data[:, :, axial_middle, 10].T, cmap='gray', origin='lower') plt.show() bvals, bvecs = read_bvals_bvecs(fbval, fbvec) # Reading bvals and bvecs gtab = gradient_table(bvals, bvecs) # Table which will hold all acquisition specific parameters print(gtab.info) # Show information about table print(gtab.bvals) # Printing bvals on console print(gtab.bvecs) # Printing bvecs on console S0s = data[:, :, :, gtab.b0s_mask] # Used to tell which part of the data contains b0s print(S0s.shape) # Verifying the dimensions of S0s to determine the number of b0s nib.save(nib.Nifti1Image(S0s, img.affine), subject+'_b0_AP.nii.gz') # Just for necessary src = join(home, '.dipy', subject + '_b0_AP.nii.gz') # Where the source file is dst = join(dname, subject + "_b0_AP.nii.gz") # The new destination for the file shutil.move(src, dst) # Moving the file to the right directory ############################################################# # Merging # #############################################################
def main(): parser = _build_arg_parser() args = parser.parse_args() assert_inputs_exist(parser, [args.in_dwi, args.in_bval, args.in_bvec], args.in_mask) assert_output_dirs_exist_and_empty(parser, args, os.path.join(args.out_dir, 'NODDI'), optional=args.save_kernels) # COMMIT has some c-level stdout and non-logging print that cannot # be easily stopped. Manual redirection of all printed output if args.verbose: logging.basicConfig(level=logging.DEBUG) redirected_stdout = redirect_stdout(sys.stdout) else: f = io.StringIO() redirected_stdout = redirect_stdout(f) redirect_stdout_c() # Generage a scheme file from the bvals and bvecs files tmp_dir = tempfile.TemporaryDirectory() tmp_scheme_filename = os.path.join(tmp_dir.name, 'gradients.scheme') tmp_bval_filename = os.path.join(tmp_dir.name, 'bval') bvals, _ = read_bvals_bvecs(args.in_bval, args.in_bvec) shells_centroids, indices_shells = identify_shells(bvals, args.b_thr, roundCentroids=True) np.savetxt(tmp_bval_filename, shells_centroids[indices_shells], newline=' ', fmt='%i') fsl2mrtrix(tmp_bval_filename, args.in_bvec, tmp_scheme_filename) logging.debug('Compute NODDI with AMICO on {} shells at found ' 'at {}.'.format(len(shells_centroids), shells_centroids)) with redirected_stdout: # Load the data amico.core.setup() ae = amico.Evaluation('.', '.') ae.load_data(args.in_dwi, tmp_scheme_filename, mask_filename=args.in_mask) # Compute the response functions ae.set_model("NODDI") intra_vol_frac = np.linspace(0.1, 0.99, 12) intra_orient_distr = np.hstack((np.array([0.03, 0.06]), np.linspace(0.09, 0.99, 10))) ae.model.set(args.para_diff, args.iso_diff, intra_vol_frac, intra_orient_distr, False) ae.set_solver(lambda1=args.lambda1, lambda2=args.lambda2) # The kernels are, by default, set to be in the current directory # Depending on the choice, manually change the saving location if args.save_kernels: kernels_dir = os.path.join(args.save_kernels) regenerate_kernels = True elif args.load_kernels: kernels_dir = os.path.join(args.load_kernels) regenerate_kernels = False else: kernels_dir = os.path.join(tmp_dir.name, 'kernels', ae.model.id) regenerate_kernels = True ae.set_config('ATOMS_path', kernels_dir) out_model_dir = os.path.join(args.out_dir, ae.model.id) ae.set_config('OUTPUT_path', out_model_dir) ae.generate_kernels(regenerate=regenerate_kernels) ae.load_kernels() # Set number of processes solver_params = ae.get_config('solver_params') solver_params['numThreads'] = args.nbr_processes ae.set_config('solver_params', solver_params) # Model fit ae.fit() # Save the results ae.save_results() tmp_dir.cleanup()
from dipy.viz import window, actor import numpy as np from weighted_tracts import * subj = all_subj_folders names = all_subj_names for s, n in zip(subj[14:15], names[14:15]): folder_name = subj_folder + s dir_name = folder_name + '\streamlines' gtab, data, affine, labels, white_matter, nii_file, bvec_file = load_dwi_files( folder_name) bval_file = bvec_file[:-4:] + 'bval' sphere = default_sphere bvals, bvecs = read_bvals_bvecs(bval_file, bvec_file) bvals = np.around(bvals, decimals=-2) gtab = gradient_table(bvals, bvecs) bvals = gtab.bvals bvecs = gtab.bvecs denoised_arr = data tissue_mask = r'F:\Hila\Ax3D_Pack\V6\after_file_prep\YA_lab_Yaniv_002334_20210107_1820\r20210107_182004T1wMPRAGERLs008a1001_brain_seg.nii' t_mask_img = load_nifti(tissue_mask)[0] wm = t_mask_img == 3 gm = t_mask_img == 2 csf = t_mask_img == 1 mask_wm = wm.astype(float)
def gradient_table(bvals, bvecs=None, big_delta=None, small_delta=None, b0_threshold=0, atol=1e-2): """A general function for creating diffusion MR gradients. It reads, loads and prepares scanner parameters like the b-values and b-vectors so that they can be useful during the reconstruction process. Parameters ---------- bvals : can be any of the four options 1. an array of shape (N,) or (1, N) or (N, 1) with the b-values. 2. a path for the file which contains an array like the above (1). 3. an array of shape (N, 4) or (4, N). Then this parameter is considered to be a b-table which contains both bvals and bvecs. In this case the next parameter is skipped. 4. a path for the file which contains an array like the one at (3). bvecs : can be any of two options 1. an array of shape (N, 3) or (3, N) with the b-vectors. 2. a path for the file which contains an array like the previous. big_delta : float acquisition pulse separation time in seconds (default None) small_delta : float acquisition pulse duration time in seconds (default None) b0_threshold : float All b-values with values less than or equal to `bo_threshold` are considered as b0s i.e. without diffusion weighting. atol : float All b-vectors need to be unit vectors up to a tolerance. Returns ------- gradients : GradientTable A GradientTable with all the gradient information. Examples -------- >>> from dipy.core.gradients import gradient_table >>> bvals = 1500 * np.ones(7) >>> bvals[0] = 0 >>> sq2 = np.sqrt(2) / 2 >>> bvecs = np.array([[0, 0, 0], ... [1, 0, 0], ... [0, 1, 0], ... [0, 0, 1], ... [sq2, sq2, 0], ... [sq2, 0, sq2], ... [0, sq2, sq2]]) >>> gt = gradient_table(bvals, bvecs) >>> gt.bvecs.shape == bvecs.shape True >>> gt = gradient_table(bvals, bvecs.T) >>> gt.bvecs.shape == bvecs.T.shape False Notes ----- 1. Often b0s (b-values which correspond to images without diffusion weighting) have 0 values however in some cases the scanner cannot provide b0s of an exact 0 value and it gives a bit higher values e.g. 6 or 12. This is the purpose of the b0_threshold in the __init__. 2. We assume that the minimum number of b-values is 7. 3. B-vectors should be unit vectors. """ # If you provided strings with full paths, we go and load those from # the files: if isinstance(bvals, string_types): bvals, _ = io.read_bvals_bvecs(bvals, None) if isinstance(bvecs, string_types): _, bvecs = io.read_bvals_bvecs(None, bvecs) bvals = np.asarray(bvals) # If bvecs is None we expect bvals to be an (N, 4) or (4, N) array. if bvecs is None: if bvals.shape[-1] == 4: bvecs = bvals[:, 1:] bvals = np.squeeze(bvals[:, 0]) elif bvals.shape[0] == 4: bvecs = bvals[1:, :].T bvals = np.squeeze(bvals[0, :]) else: raise ValueError("input should be bvals and bvecs OR an (N, 4)" " array containing both bvals and bvecs") else: bvecs = np.asarray(bvecs) if (bvecs.shape[1] > bvecs.shape[0]) and bvecs.shape[0] > 1: bvecs = bvecs.T return gradient_table_from_bvals_bvecs(bvals, bvecs, big_delta=big_delta, small_delta=small_delta, b0_threshold=b0_threshold, atol=atol)
def test_predict(): SNR = 1000 S0 = 100 _, fbvals, fbvecs = dpd.get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = grad.gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) angles = [(0, 0), (60, 0)] S, sticks = sims.multi_tensor(gtab, mevals, S0, angles=angles, fractions=[10, 90], snr=SNR) sfmodel = sfm.SparseFascicleModel(gtab, response=[0.0015, 0.0003, 0.0003]) sffit = sfmodel.fit(S) pred = sffit.predict() npt.assert_(xval.coeff_of_determination(pred, S) > 97) # Should be possible to predict using a different gtab: new_gtab = grad.gradient_table(bvals[::2], bvecs[::2]) new_pred = sffit.predict(new_gtab) npt.assert_(xval.coeff_of_determination(new_pred, S[::2]) > 97) # Should be possible to predict for a single direction: with warnings.catch_warnings(): warnings.simplefilter("ignore", category=UserWarning) new_gtab = grad.gradient_table(bvals[1][None], bvecs[1][None, :]) new_pred = sffit.predict(new_gtab) # Fitting and predicting with a volume of data: fdata, fbval, fbvec = dpd.get_fnames('small_25') gtab = grad.gradient_table(fbval, fbvec) data = load_nifti_data(fdata) sfmodel = sfm.SparseFascicleModel(gtab, response=[0.0015, 0.0003, 0.0003]) sffit = sfmodel.fit(data) pred = sffit.predict() # Should be possible to predict using a different gtab: new_gtab = grad.gradient_table(bvals[::2], bvecs[::2]) new_pred = sffit.predict(new_gtab) npt.assert_equal( new_pred.shape, data.shape[:-1] + bvals[::2].shape, ) # Should be possible to predict for a single direction: with warnings.catch_warnings(): warnings.simplefilter("ignore", category=UserWarning) new_gtab = grad.gradient_table(bvals[1][None], bvecs[1][None, :]) new_pred = sffit.predict(new_gtab) npt.assert_equal(new_pred.shape, data.shape[:-1]) # Fitting and predicting with masked data: mask = np.zeros(data.shape[:3]) mask[2:5, 2:5, :] = 1 sffit = sfmodel.fit(data, mask=mask) pred = sffit.predict() npt.assert_equal(pred.shape, data.shape) # Should be possible to predict using a different gtab: new_gtab = grad.gradient_table(bvals[::2], bvecs[::2]) new_pred = sffit.predict(new_gtab) npt.assert_equal( new_pred.shape, data.shape[:-1] + bvals[::2].shape, ) npt.assert_equal(new_pred[0, 0, 0], 0) # Should be possible to predict for a single direction: with warnings.catch_warnings(): warnings.simplefilter("ignore", category=UserWarning) new_gtab = grad.gradient_table(bvals[1][None], bvecs[1][None, :]) new_pred = sffit.predict(new_gtab) npt.assert_equal(new_pred.shape, data.shape[:-1]) npt.assert_equal(new_pred[0, 0, 0], 0)
def main(): parser = _build_arg_parser() args = parser.parse_args() try: devnull = open(os.devnull) subprocess.call(args.eddy_cmd, stderr=devnull) except: parser.error("Please download the {} command.".format(args.eddy_cmd)) if args.verbose: logging.basicConfig(level=logging.INFO) required_args = [args.input_dwi, args.bvals, args.bvecs, args.mask] assert_inputs_exist(parser, required_args) if os.path.splitext(args.output_prefix)[1] != '': parser.error('The prefix must not contain any extension.') bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) bvals_min = bvals.min() b0_threshold = args.b0_thr if bvals_min < 0 or bvals_min > b0_threshold: raise ValueError('The minimal b-value is lesser than 0 or greater ' 'than {0}. This is highly suspicious. Please check ' 'your data to ensure everything is correct. ' 'Value found: {1}'.format(b0_threshold, bvals_min)) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold) acqparams = create_acqparams(gtab, args.readout, args.encoding_direction) index = create_index(bvals) bvecs = create_non_zero_norm_bvecs(bvecs) if not os.path.exists(args.output_directory): os.makedirs(args.output_directory) acqparams_path = os.path.join(args.output_directory, 'acqparams.txt') np.savetxt(acqparams_path, acqparams, fmt='%1.4f', delimiter=' ') bvecs_path = os.path.join(args.output_directory, 'non_zero_norm.bvecs') np.savetxt(bvecs_path, bvecs.T, fmt="%.8f") index_path = os.path.join(args.output_directory, 'index.txt') np.savetxt(index_path, index, fmt='%i', newline=" ") additional_args = "" if args.topup is not None: additional_args += "--topup={} ".format(args.topup) if args.slice_drop_correction: additional_args += "--repol " if args.fix_seed: additional_args += "--initrand " output_path = os.path.join(args.output_directory, args.output_prefix) eddy = '{0} --imain={1} --mask={2} --acqp={3} --index={4}' \ ' --bvecs={5} --bvals={6} --out={7} --data_is_shelled {8}' \ .format(args.eddy_cmd, args.input_dwi, args.mask, acqparams_path, index_path, bvecs_path, args.bvals, output_path, additional_args) if args.output_script: with open("eddy.sh", 'w') as f: f.write(eddy) else: print(eddy)
def track(dname, fdwi, fbval, fbvec, fmask=None, seed_density=1, show=False): data, affine = load_nifti(fdwi) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs, b0_threshold=50) if fmask is None: from dipy.segment.mask import median_otsu b0_mask, mask = median_otsu( data) # TODO: check parameters to improve the mask else: mask, mask_affine = load_nifti(fmask) mask = np.squeeze(mask) #fix mask dimensions # compute DTI model from dipy.reconst.dti import TensorModel tenmodel = TensorModel(gtab) #, fit_method='OLS') #, min_signal=5000) # fit the dti model tenfit = tenmodel.fit(data, mask=mask) # save fa ffa = dname + 'tensor_fa.nii.gz' fa_img = nib.Nifti1Image(tenfit.fa.astype(np.float32), affine) nib.save(fa_img, ffa) sh_order = 8 #TODO: check what that does if data.shape[-1] < 15: raise ValueError('You need at least 15 unique DWI volumes to ' 'compute fiber ODFs. You currently have: {0}' ' DWI volumes.'.format(data.shape[-1])) elif data.shape[-1] < 30: sh_order = 6 # compute the response equation ? from dipy.reconst.csdeconv import auto_response response, ratio = auto_response(gtab, data) response = list(response) peaks_sphere = get_sphere('symmetric362') #TODO: check what that does peaks_csd = peaks_from_model( model=tenmodel, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, #.5 min_separation_angle=25, mask=mask, return_sh=True, sh_order=sh_order, normalize_peaks=True, parallel=False) peaks_csd.affine = affine fpeaks = dname + 'peaks.npz' save_peaks(fpeaks, peaks_csd) from dipy.io.trackvis import save_trk from dipy.tracking import utils from dipy.tracking.local import (ThresholdTissueClassifier, LocalTracking) stopping_thr = 0.25 #0.25 pam = load_peaks(fpeaks) #ffa = dname + 'tensor_fa_nomask.nii.gz' fa, fa_affine = load_nifti(ffa) classifier = ThresholdTissueClassifier(fa, stopping_thr) # seeds seed_mask = fa > 0.4 #0.4 #TODO: check this parameter seeds = utils.seeds_from_mask(seed_mask, density=seed_density, affine=affine) # tractography, if affine then in world coordinates streamlines = LocalTracking(pam, classifier, seeds, affine=affine, step_size=.5) # Compute streamlines and store as a list. streamlines = list(streamlines) ftractogram = dname + 'tractogram.trk' #save .trk save_trk_old_style(ftractogram, streamlines, affine, fa.shape) if show: #render show_results(data, streamlines, fa, fa_affine)
def run(self, input_files, bvalues_files, bvectors_files, mask_files, b0_threshold=50.0, bvecs_tol=0.01, roi_center=None, roi_radii=10, fa_thr=0.7, frf=None, extract_pam_values=False, sh_order=8, odf_to_sh_order=8, parallel=False, nbr_processes=None, out_dir='', out_pam='peaks.pam5', out_shm='shm.nii.gz', out_peaks_dir='peaks_dirs.nii.gz', out_peaks_values='peaks_values.nii.gz', out_peaks_indices='peaks_indices.nii.gz', out_gfa='gfa.nii.gz'): """ Constrained spherical deconvolution Parameters ---------- input_files : string Path to the input volumes. This path may contain wildcards to process multiple inputs at once. bvalues_files : string Path to the bvalues files. This path may contain wildcards to use multiple bvalues files at once. bvectors_files : string Path to the bvectors files. This path may contain wildcards to use multiple bvectors files at once. mask_files : string Path to the input masks. This path may contain wildcards to use multiple masks at once. (default: No mask used) b0_threshold : float, optional Threshold used to find b0 volumes. bvecs_tol : float, optional Bvecs should be unit vectors. roi_center : variable int, optional Center of ROI in data. If center is None, it is assumed that it is the center of the volume with shape `data.shape[:3]`. roi_radii : int or array-like, optional radii of cuboid ROI in voxels. fa_thr : float, optional FA threshold for calculating the response function. frf : variable float, optional Fiber response function can be for example inputed as 15 4 4 (from the command line) or [15, 4, 4] from a Python script to be converted to float and multiplied by 10**-4 . If None the fiber response function will be computed automatically. extract_pam_values : bool, optional Save or not to save pam volumes as single nifti files. sh_order : int, optional Spherical harmonics order used in the CSA fit. odf_to_sh_order : int, optional Spherical harmonics order used for peak_from_model to compress the ODF to spherical harmonics coefficients. parallel : bool, optional Whether to use parallelization in peak-finding during the calibration procedure. nbr_processes : int, optional If `parallel` is True, the number of subprocesses to use (default multiprocessing.cpu_count()). out_dir : string, optional Output directory. (default current directory) out_pam : string, optional Name of the peaks volume to be saved. out_shm : string, optional Name of the spherical harmonics volume to be saved. out_peaks_dir : string, optional Name of the peaks directions volume to be saved. out_peaks_values : string, optional Name of the peaks values volume to be saved. out_peaks_indices : string, optional Name of the peaks indices volume to be saved. out_gfa : string, optional Name of the generalized FA volume to be saved. References ---------- .. [1] Tournier, J.D., et al. NeuroImage 2007. Robust determination of the fibre orientation distribution in diffusion MRI: Non-negativity constrained super-resolved spherical deconvolution. """ io_it = self.get_io_iterator() for (dwi, bval, bvec, maskfile, opam, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa) in io_it: logging.info('Loading {0}'.format(dwi)) data, affine = load_nifti(dwi) bvals, bvecs = read_bvals_bvecs(bval, bvec) print(b0_threshold, bvals.min()) if b0_threshold < bvals.min(): warn( "b0_threshold (value: {0}) is too low, increase your " "b0_threshold. It should be higher than the first b0 value " "({1}).".format(b0_threshold, bvals.min())) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold, atol=bvecs_tol) mask_vol = load_nifti_data(maskfile).astype(bool) n_params = ((sh_order + 1) * (sh_order + 2)) / 2 if data.shape[-1] < n_params: raise ValueError('You need at least {0} unique DWI volumes to ' 'compute fiber odfs. You currently have: {1}' ' DWI volumes.'.format( n_params, data.shape[-1])) if frf is None: logging.info('Computing response function') if roi_center is not None: logging.info( 'Response ROI center:\n{0}'.format(roi_center)) logging.info('Response ROI radii:\n{0}'.format(roi_radii)) response, ratio = auto_response_ssst(gtab, data, roi_center=roi_center, roi_radii=roi_radii, fa_thr=fa_thr) response = list(response) else: logging.info('Using response function') if isinstance(frf, str): l01 = np.array(literal_eval(frf), dtype=np.float64) else: l01 = np.array(frf, dtype=np.float64) l01 *= 10**-4 response = np.array([l01[0], l01[1], l01[1]]) ratio = l01[1] / l01[0] response = (response, ratio) logging.info("Eigenvalues for the frf of the input" " data are :{0}".format(response[0])) logging.info( 'Ratio for smallest to largest eigen value is {0}'.format( ratio)) peaks_sphere = default_sphere logging.info('CSD computation started.') csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=sh_order) peaks_csd = peaks_from_model(model=csd_model, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=mask_vol, return_sh=True, sh_order=sh_order, normalize_peaks=True, parallel=parallel, nbr_processes=nbr_processes) peaks_csd.affine = affine save_peaks(opam, peaks_csd) logging.info('CSD computation completed.') if extract_pam_values: peaks_to_niftis(peaks_csd, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa, reshape_dirs=True) dname_ = os.path.dirname(opam) if dname_ == '': logging.info('Pam5 file saved in current directory') else: logging.info('Pam5 file saved in {0}'.format(dname_)) return io_it
def run(self, input_files, bvalues_files, bvectors_files, mask_files, sh_order=6, odf_to_sh_order=8, b0_threshold=50.0, bvecs_tol=0.01, extract_pam_values=False, parallel=False, nbr_processes=None, out_dir='', out_pam='peaks.pam5', out_shm='shm.nii.gz', out_peaks_dir='peaks_dirs.nii.gz', out_peaks_values='peaks_values.nii.gz', out_peaks_indices='peaks_indices.nii.gz', out_gfa='gfa.nii.gz'): """ Constant Solid Angle. Parameters ---------- input_files : string Path to the input volumes. This path may contain wildcards to process multiple inputs at once. bvalues_files : string Path to the bvalues files. This path may contain wildcards to use multiple bvalues files at once. bvectors_files : string Path to the bvectors files. This path may contain wildcards to use multiple bvectors files at once. mask_files : string Path to the input masks. This path may contain wildcards to use multiple masks at once. (default: No mask used) sh_order : int, optional Spherical harmonics order used in the CSA fit. odf_to_sh_order : int, optional Spherical harmonics order used for peak_from_model to compress the ODF to spherical harmonics coefficients. b0_threshold : float, optional Threshold used to find b0 volumes. bvecs_tol : float, optional Threshold used so that norm(bvec)=1. extract_pam_values : bool, optional Whether or not to save pam volumes as single nifti files. parallel : bool, optional Whether to use parallelization in peak-finding during the calibration procedure. nbr_processes : int, optional If `parallel` is True, the number of subprocesses to use (default multiprocessing.cpu_count()). out_dir : string, optional Output directory. (default current directory) out_pam : string, optional Name of the peaks volume to be saved. out_shm : string, optional Name of the spherical harmonics volume to be saved. out_peaks_dir : string, optional Name of the peaks directions volume to be saved. out_peaks_values : string, optional Name of the peaks values volume to be saved. out_peaks_indices : string, optional Name of the peaks indices volume to be saved. out_gfa : string, optional Name of the generalized FA volume to be saved. References ---------- .. [1] Aganj, I., et al. 2009. ODF Reconstruction in Q-Ball Imaging with Solid Angle Consideration. """ io_it = self.get_io_iterator() for (dwi, bval, bvec, maskfile, opam, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa) in io_it: logging.info('Loading {0}'.format(dwi)) data, affine = load_nifti(dwi) bvals, bvecs = read_bvals_bvecs(bval, bvec) if b0_threshold < bvals.min(): warn( "b0_threshold (value: {0}) is too low, increase your " "b0_threshold. It should be higher than the first b0 value " "({1}).".format(b0_threshold, bvals.min())) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold, atol=bvecs_tol) mask_vol = load_nifti_data(maskfile).astype(bool) peaks_sphere = default_sphere logging.info('Starting CSA computations {0}'.format(dwi)) csa_model = CsaOdfModel(gtab, sh_order) peaks_csa = peaks_from_model(model=csa_model, data=data, sphere=peaks_sphere, relative_peak_threshold=.5, min_separation_angle=25, mask=mask_vol, return_sh=True, sh_order=odf_to_sh_order, normalize_peaks=True, parallel=parallel, nbr_processes=nbr_processes) peaks_csa.affine = affine save_peaks(opam, peaks_csa) logging.info('Finished CSA {0}'.format(dwi)) if extract_pam_values: peaks_to_niftis(peaks_csa, oshm, opeaks_dir, opeaks_values, opeaks_indices, ogfa, reshape_dirs=True) dname_ = os.path.dirname(opam) if dname_ == '': logging.info('Pam5 file saved in current directory') else: logging.info('Pam5 file saved in {0}'.format(dname_)) return io_it
def run(self, data_files, bvals_files, bvecs_files, small_delta, big_delta, b0_threshold=50.0, laplacian=True, positivity=True, bval_threshold=2000, save_metrics=[], laplacian_weighting=0.05, radial_order=6, out_dir='', out_rtop='rtop.nii.gz', out_lapnorm='lapnorm.nii.gz', out_msd='msd.nii.gz', out_qiv='qiv.nii.gz', out_rtap='rtap.nii.gz', out_rtpp='rtpp.nii.gz', out_ng='ng.nii.gz', out_perng='perng.nii.gz', out_parng='parng.nii.gz'): """Workflow for fitting the MAPMRI model (with optional Laplacian regularization). Generates rtop, lapnorm, msd, qiv, rtap, rtpp, non-gaussian (ng), parallel ng, perpendicular ng saved in a nifti format in input files provided by `data_files` and saves the nifti files to an output directory specified by `out_dir`. In order for the MAPMRI workflow to work in the way intended either the Laplacian or positivity or both must be set to True. Parameters ---------- data_files : string Path to the input volume. bvals_files : string Path to the bval files. bvecs_files : string Path to the bvec files. small_delta : float Small delta value used in generation of gradient table of provided bval and bvec. big_delta : float Big delta value used in generation of gradient table of provided bval and bvec. b0_threshold : float, optional Threshold used to find b0 volumes. laplacian : bool, optional Regularize using the Laplacian of the MAP-MRI basis. positivity : bool, optional Constrain the propagator to be positive. bval_threshold : float, optional Sets the b-value threshold to be used in the scale factor estimation. In order for the estimated non-Gaussianity to have meaning this value should set to a lower value (b<2000 s/mm^2) such that the scale factors are estimated on signal points that reasonably represent the spins at Gaussian diffusion. save_metrics : variable string, optional List of metrics to save. Possible values: rtop, laplacian_signal, msd, qiv, rtap, rtpp, ng, perng, parng laplacian_weighting : float, optional Weighting value used in fitting the MAPMRI model in the Laplacian and both model types. radial_order : unsigned int, optional Even value used to set the order of the basis. out_dir : string, optional Output directory. (default: current directory) out_rtop : string, optional Name of the rtop to be saved. out_lapnorm : string, optional Name of the norm of Laplacian signal to be saved. out_msd : string, optional Name of the msd to be saved. out_qiv : string, optional Name of the qiv to be saved. out_rtap : string, optional Name of the rtap to be saved. out_rtpp : string, optional Name of the rtpp to be saved. out_ng : string, optional Name of the Non-Gaussianity to be saved. out_perng : string, optional Name of the Non-Gaussianity perpendicular to be saved. out_parng : string, optional Name of the Non-Gaussianity parallel to be saved. """ io_it = self.get_io_iterator() for (dwi, bval, bvec, out_rtop, out_lapnorm, out_msd, out_qiv, out_rtap, out_rtpp, out_ng, out_perng, out_parng) in io_it: logging.info('Computing MAPMRI metrics for {0}'.format(dwi)) data, affine = load_nifti(dwi) bvals, bvecs = read_bvals_bvecs(bval, bvec) if b0_threshold < bvals.min(): warn("b0_threshold (value: {0}) is too low, increase your " "b0_threshold. It should be higher than the first b0 " "value({1}).".format(b0_threshold, bvals.min())) gtab = gradient_table(bvals=bvals, bvecs=bvecs, small_delta=small_delta, big_delta=big_delta, b0_threshold=b0_threshold) if not save_metrics: save_metrics = [ 'rtop', 'laplacian_signal', 'msd', 'qiv', 'rtap', 'rtpp', 'ng', 'perng', 'parng' ] if laplacian and positivity: map_model_aniso = mapmri.MapmriModel( gtab, radial_order=radial_order, laplacian_regularization=True, laplacian_weighting=laplacian_weighting, positivity_constraint=True, bval_threshold=bval_threshold) mapfit_aniso = map_model_aniso.fit(data) elif positivity: map_model_aniso = mapmri.MapmriModel( gtab, radial_order=radial_order, laplacian_regularization=False, positivity_constraint=True, bval_threshold=bval_threshold) mapfit_aniso = map_model_aniso.fit(data) elif laplacian: map_model_aniso = mapmri.MapmriModel( gtab, radial_order=radial_order, laplacian_regularization=True, laplacian_weighting=laplacian_weighting, bval_threshold=bval_threshold) mapfit_aniso = map_model_aniso.fit(data) else: map_model_aniso = mapmri.MapmriModel( gtab, radial_order=radial_order, laplacian_regularization=False, positivity_constraint=False, bval_threshold=bval_threshold) mapfit_aniso = map_model_aniso.fit(data) # for name, fname, func in [('rtop', out_rtop, mapfit_aniso.rtop), # ]: # if name in save_metrics: # r = func() # save_nifti(fname, r.astype(np.float32), affine) if 'rtop' in save_metrics: r = mapfit_aniso.rtop() save_nifti(out_rtop, r.astype(np.float32), affine) if 'laplacian_signal' in save_metrics: ll = mapfit_aniso.norm_of_laplacian_signal() save_nifti(out_lapnorm, ll.astype(np.float32), affine) if 'msd' in save_metrics: m = mapfit_aniso.msd() save_nifti(out_msd, m.astype(np.float32), affine) if 'qiv' in save_metrics: q = mapfit_aniso.qiv() save_nifti(out_qiv, q.astype(np.float32), affine) if 'rtap' in save_metrics: r = mapfit_aniso.rtap() save_nifti(out_rtap, r.astype(np.float32), affine) if 'rtpp' in save_metrics: r = mapfit_aniso.rtpp() save_nifti(out_rtpp, r.astype(np.float32), affine) if 'ng' in save_metrics: n = mapfit_aniso.ng() save_nifti(out_ng, n.astype(np.float32), affine) if 'perng' in save_metrics: n = mapfit_aniso.ng_perpendicular() save_nifti(out_perng, n.astype(np.float32), affine) if 'parng' in save_metrics: n = mapfit_aniso.ng_parallel() save_nifti(out_parng, n.astype(np.float32), affine) logging.info('MAPMRI saved in {0}'.format( os.path.dirname(out_dir)))
def main(): parser = _build_args_parser() args = parser.parse_args() print('LOADING DATA') # load data img = nib.load(args.data) data = img.get_fdata() # load bval bvec bval, bvec = read_bvals_bvecs(args.bval, args.bvec) gtab = gradient_table(bval, bvec) # detect b0 b0_th = 75. b0_index = np.where(bval < b0_th)[0] # build include index if args.index is None: index = np.zeros(bval.shape[0], dtype=np.bool) # include the last args.last non-b0 N = args.last # list of non-zero index tmp = np.arange(bval.shape[0])[bval >= b0_th] index[tmp[-N:]] = True # include all b0s index[b0_index] = True else: index = np.genfromtxt(args.index).astype(np.bool) if index.shape[0] != bval.shape[0]: print('index length different from bval length') return None if args.mask is None: mask = np.ones(data.shape[:3], dtype=np.bool) else: mask = nib.load(args.mask).get_fdata().astype(np.bool) totalVoxel = np.prod(mask.shape) voxelInMask = mask.sum() print('{} voxels out of {} inside mask ({:.1f}%)'.format(voxelInMask, totalVoxel, 100*voxelInMask/totalVoxel)) print('COMPUTING TIME CURVES') # compute per-volume mean inside mask volume_mean_intensity = data[mask].mean(axis=0) viz_hack = volume_mean_intensity.copy() viz_hack[b0_index] = np.nan pl.figure() pl.plot(volume_mean_intensity, color='black', label='mean intensity in mask') pl.scatter(np.where(index), np.ones(index.sum())*(0.95*volume_mean_intensity.min()), label='Included', color='red') pl.title('Mean intensity in mask (WITH b0)') pl.legend() pl.figure() pl.plot(viz_hack, color='black', label='mean intensity in mask') pl.scatter(np.where(index), np.ones(index.sum())*(0.95*volume_mean_intensity.min()), label='Included', color='red') pl.title('Mean intensity in mask (WITHOUT b0)') pl.legend() pl.show() # fit DTI on included volume in index low_bvec = bvec[index] low_bval = bval[index] data_low = data[..., index] gtab_low = gradient_table(low_bval, low_bvec) tenmodel_low = dti.TensorModel(gtab_low) print('FITTING DTI') tenmodel_low = dti.TensorModel(gtab_low, fit_method='WLS', return_S0_hat=True) # Dipy has hard min signal cutoff of 1e-4, so we amplify # set the non-zero minimum to the threshold data_low_masked = data_low[mask] # this is gettho more and more garbage, to accomodate debias negative data # we look at the min above zero # in pratice this is terrible and we should just scale the data before multiplier = 1e-4 / data_low_masked[(data_low_masked>0)].min() tenfit_low = tenmodel_low.fit(multiplier*data_low, mask=mask) print('PREDICTING SIGNALS') # predict signal for each volume for fit predicted_S0 = tenfit_low.S0_hat predicted_signal = tenfit_low.predict(gtab) predicted_normalized_signal = predicted_signal / predicted_S0[..., None] predicted_normalized_signal[np.isnan(predicted_normalized_signal)] = 0 predicted_normalized_signal[np.isinf(predicted_normalized_signal)] = 0 predicted_adc = -np.log(predicted_normalized_signal)/bval[None, None, None, :] predicted_adc[np.isinf(predicted_adc)] = 0 predicted_adc[np.isnan(predicted_adc)] = 0 print('COMPUTING TEMPERATURE') ks = 1 - (np.log(multiplier*data/(predicted_signal)) * (bval[None, None, None, :]*predicted_adc)**-1) ks[np.isnan(ks)] = 1 ks[np.isinf(ks)] = 1 # save the diffusivity multiplier map nib.nifti1.Nifti1Image(ks, img.affine).to_filename(args.outputks) mean_directional_k = np.median(ks[mask], axis=(0,)) pl.figure() pl.plot(mean_directional_k ) pl.axhline(1, color='red', linestyle='dashed') pl.title('Estimated (median) diffusivity multiplier in mask per volume') pl.show() print('COMPUTING CORRECTION') # diffusivity to center the calibration D_calibrate = 1/bval.max() print('Calibrating for diffusivity 1/bmax = 1/{:.0f} = {:.2e}'.format(bval.max(), D_calibrate)) heat_calibrate = np.exp(-bval*mean_directional_k*D_calibrate) # pl.plot(np.exp(-bval*D_calibrate)/heat_calibrate) meank_fix_correction = np.exp(-bval*D_calibrate)/heat_calibrate data_meank_fix = data * meank_fix_correction[None,None,None,:] meandata_meank_fix = data_meank_fix[mask].mean(axis=(0,)) viz_hack2 = meandata_meank_fix.copy() viz_hack2[b0_index] = np.nan pl.figure() pl.plot(volume_mean_intensity, color='black', label='no correction') pl.plot(meandata_meank_fix, color='red', label='with correction') # pl.scatter(np.where(index), np.ones(index.sum())*(0.95*volume_mean_intensity.min()), label='Included', color='red') pl.title('Mean intensity in mask (WITH b0)') pl.legend() pl.figure() pl.plot(viz_hack, color='black', label='no correction') pl.plot(viz_hack2, color='red', label='with correction') # pl.scatter(np.where(index), np.ones(index.sum())*(0.95*volume_mean_intensity.min()), label='Included', color='red') pl.title('Mean intensity in mask (WITHOUT b0)') pl.legend() pl.show() print('SAVING CORRECTED NIFTI') nib.nifti1.Nifti1Image(data_meank_fix, img.affine).to_filename(args.output)
def main(): logger = logging.getLogger("Compute_DKI_Metrics") logger.setLevel(logging.INFO) parser = _build_args_parser() args = parser.parse_args() if not args.not_all: args.dki_fa = args.dki_fa or 'dki_fa.nii.gz' args.dki_md = args.dki_md or 'dki_md.nii.gz' args.dki_ad = args.dki_ad or 'dki_ad.nii.gz' args.dki_rd = args.dki_rd or 'dki_rd.nii.gz' args.mk = args.mk or 'mk.nii.gz' args.rk = args.rk or 'rk.nii.gz' args.ak = args.ak or 'ak.nii.gz' args.dki_residual = args.dki_residual or 'dki_residual.nii.gz' args.msk = args.msk or 'msk.nii.gz' args.msd = args.msd or 'msd.nii.gz' outputs = [args.dki_fa, args.dki_md, args.dki_ad, args.dki_rd, args.mk, args.rk, args.ak, args.dki_residual, args.msk, args.msd] if args.not_all and not any(outputs): parser.error('When using --not_all, you need to specify at least ' + 'one metric to output.') assert_inputs_exist( parser, [args.input, args.bvals, args.bvecs], args.mask) assert_outputs_exist(parser, args, outputs) img = nib.load(args.input) data = img.get_fdata() affine = img.affine if args.mask is None: mask = None else: mask = nib.load(args.mask).get_fdata().astype(np.bool) # Validate bvals and bvecs bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) if not is_normalized_bvecs(bvecs): logging.warning('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) # Find the volume indices that correspond to the shells to extract. tol = args.tolerance shells, _ = identify_shells(bvals, tol) if not len(shells) >= 3: parser.error('Data is not multi-shell. You need at least 2 non-zero' + ' b-values') if (shells > 2500).any(): logging.warning('You seem to be using b > 2500 s/mm2 DWI data. ' + 'In theory, this is beyond the optimal range for DKI') check_b0_threshold(args, bvals.min()) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) fwhm = args.smooth if fwhm > 0: # converting fwhm to Gaussian std gauss_std = fwhm / np.sqrt(8 * np.log(2)) data_smooth = np.zeros(data.shape) for v in range(data.shape[-1]): data_smooth[..., v] = gaussian_filter(data[..., v], sigma=gauss_std) data = data_smooth # Compute DKI dkimodel = dki.DiffusionKurtosisModel(gtab) dkifit = dkimodel.fit(data, mask=mask) min_k = args.min_k max_k = args.max_k if args.dki_fa: FA = dkifit.fa FA[np.isnan(FA)] = 0 FA = np.clip(FA, 0, 1) fa_img = nib.Nifti1Image(FA.astype(np.float32), affine) nib.save(fa_img, args.dki_fa) if args.dki_md: MD = dkifit.md md_img = nib.Nifti1Image(MD.astype(np.float32), affine) nib.save(md_img, args.dki_md) if args.dki_ad: AD = dkifit.ad ad_img = nib.Nifti1Image(AD.astype(np.float32), affine) nib.save(ad_img, args.dki_ad) if args.dki_rd: RD = dkifit.rd rd_img = nib.Nifti1Image(RD.astype(np.float32), affine) nib.save(rd_img, args.dki_rd) if args.mk: MK = dkifit.mk(min_k, max_k) mk_img = nib.Nifti1Image(MK.astype(np.float32), affine) nib.save(mk_img, args.mk) if args.ak: AK = dkifit.ak(min_k, max_k) ak_img = nib.Nifti1Image(AK.astype(np.float32), affine) nib.save(ak_img, args.ak) if args.rk: RK = dkifit.rk(min_k, max_k) rk_img = nib.Nifti1Image(RK.astype(np.float32), affine) nib.save(rk_img, args.rk) if args.msk or args.msd: # Compute MSDKI msdki_model = msdki.MeanDiffusionKurtosisModel(gtab) msdki_fit = msdki_model.fit(data, mask=mask) if args.msk: MSK = msdki_fit.msk MSK[np.isnan(MSK)] = 0 MSK = np.clip(MSK, min_k, max_k) msk_img = nib.Nifti1Image(MSK.astype(np.float32), affine) nib.save(msk_img, args.msk) if args.msd: MSD = msdki_fit.msd msd_img = nib.Nifti1Image(MSD.astype(np.float32), affine) nib.save(msd_img, args.msd) if args.dki_residual: S0 = np.mean(data[..., gtab.b0s_mask], axis=-1) data_p = dkifit.predict(gtab, S0) R = np.mean(np.abs(data_p[..., ~gtab.b0s_mask] - data[..., ~gtab.b0s_mask]), axis=-1) norm = np.linalg.norm(R) if norm != 0: R = R / norm if args.mask is not None: R *= mask R_img = nib.Nifti1Image(R.astype(np.float32), affine) nib.save(R_img, args.dki_residual)
def test_gtable_from_files(): fimg, fbvals, fbvecs = get_data('small_101D') gt = gradient_table(fbvals, fbvecs) bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) npt.assert_array_equal(gt.bvals, bvals) npt.assert_array_equal(gt.bvecs, bvecs)
def cart2sphA(pts): return np.array([cart2sphere(x, y, z) for x, y, z in pts]) ''' def appendSpherical(xyz): np.hstack((xyz, cart2sphA(xyz))) ''' # Load Gradient Directions and Visualize in theta and phi coordinates on a hemisphere bvec_path = r'D:\Users\Vishwesh\PycharmProjects\shore_mapmri\ms_bvecs_b0.bvec' bval_path = r'D:\Users\Vishwesh\PycharmProjects\shore_mapmri\ms_bvals_b0.bval' bvals, bvecs = read_bvals_bvecs(bval_path, bvec_path) print("Debug Here") # Calculate Spherical Coordinates b3000_bvecs = bvecs[0:100, :] b3000_bvals = bvals[0:100] test = cart2sphA(b3000_bvecs) theta = test[:, 1] phi = test[:, 2] # Gradient Table formation for the heck of it gtab_b3000 = gradient_table(b3000_bvals, b3000_bvecs) # Generate a Hemisphere figure plot hsph_initial = HemiSphere(theta=theta, phi=phi)
def main(): parser = _build_args_parser() args = parser.parse_args() if not args.not_all: args.fa = args.fa or 'fa.nii.gz' args.ga = args.ga or 'ga.nii.gz' args.rgb = args.rgb or 'rgb.nii.gz' args.md = args.md or 'md.nii.gz' args.ad = args.ad or 'ad.nii.gz' args.rd = args.rd or 'rd.nii.gz' args.mode = args.mode or 'mode.nii.gz' args.norm = args.norm or 'tensor_norm.nii.gz' args.tensor = args.tensor or 'tensor.nii.gz' args.evecs = args.evecs or 'tensor_evecs.nii.gz' args.evals = args.evals or 'tensor_evals.nii.gz' args.residual = args.residual or 'dti_residual.nii.gz' args.p_i_signal =\ args.p_i_signal or 'physically_implausible_signals_mask.nii.gz' args.pulsation = args.pulsation or 'pulsation_and_misalignment.nii.gz' outputs = [args.fa, args.ga, args.rgb, args.md, args.ad, args.rd, args.mode, args.norm, args.tensor, args.evecs, args.evals, args.residual, args.p_i_signal, args.pulsation] if args.not_all and not any(outputs): parser.error('When using --not_all, you need to specify at least ' + 'one metric to output.') assert_inputs_exist( parser, [args.input, args.bvals, args.bvecs], args.mask) assert_outputs_exist(parser, args, outputs) img = nib.load(args.input) data = img.get_data() affine = img.get_affine() if args.mask is None: mask = None else: mask = nib.load(args.mask).get_data().astype(np.bool) # Validate bvals and bvecs logging.info('Tensor estimation with the %s method...', args.method) bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) if not is_normalized_bvecs(bvecs): logging.warning('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) check_b0_threshold(args, bvals.min()) gtab = gradient_table(bvals, bvecs, b0_threshold=bvals.min()) # Get tensors if args.method == 'restore': sigma = ne.estimate_sigma(data) tenmodel = TensorModel(gtab, fit_method=args.method, sigma=sigma, min_signal=_get_min_nonzero_signal(data)) else: tenmodel = TensorModel(gtab, fit_method=args.method, min_signal=_get_min_nonzero_signal(data)) tenfit = tenmodel.fit(data, mask) FA = fractional_anisotropy(tenfit.evals) FA[np.isnan(FA)] = 0 FA = np.clip(FA, 0, 1) if args.tensor: # Get the Tensor values and format them for visualisation # in the Fibernavigator. tensor_vals = lower_triangular(tenfit.quadratic_form) correct_order = [0, 1, 3, 2, 4, 5] tensor_vals_reordered = tensor_vals[..., correct_order] fiber_tensors = nib.Nifti1Image( tensor_vals_reordered.astype(np.float32), affine) nib.save(fiber_tensors, args.tensor) if args.fa: fa_img = nib.Nifti1Image(FA.astype(np.float32), affine) nib.save(fa_img, args.fa) if args.ga: GA = geodesic_anisotropy(tenfit.evals) GA[np.isnan(GA)] = 0 ga_img = nib.Nifti1Image(GA.astype(np.float32), affine) nib.save(ga_img, args.ga) if args.rgb: RGB = color_fa(FA, tenfit.evecs) rgb_img = nib.Nifti1Image(np.array(255 * RGB, 'uint8'), affine) nib.save(rgb_img, args.rgb) if args.md: MD = mean_diffusivity(tenfit.evals) md_img = nib.Nifti1Image(MD.astype(np.float32), affine) nib.save(md_img, args.md) if args.ad: AD = axial_diffusivity(tenfit.evals) ad_img = nib.Nifti1Image(AD.astype(np.float32), affine) nib.save(ad_img, args.ad) if args.rd: RD = radial_diffusivity(tenfit.evals) rd_img = nib.Nifti1Image(RD.astype(np.float32), affine) nib.save(rd_img, args.rd) if args.mode: # Compute tensor mode inter_mode = dipy_mode(tenfit.quadratic_form) # Since the mode computation can generate NANs when not masked, # we need to remove them. non_nan_indices = np.isfinite(inter_mode) mode = np.zeros(inter_mode.shape) mode[non_nan_indices] = inter_mode[non_nan_indices] mode_img = nib.Nifti1Image(mode.astype(np.float32), affine) nib.save(mode_img, args.mode) if args.norm: NORM = norm(tenfit.quadratic_form) norm_img = nib.Nifti1Image(NORM.astype(np.float32), affine) nib.save(norm_img, args.norm) if args.evecs: evecs = tenfit.evecs.astype(np.float32) evecs_img = nib.Nifti1Image(evecs, affine) nib.save(evecs_img, args.evecs) # save individual e-vectors also e1_img = nib.Nifti1Image(evecs[..., 0], affine) e2_img = nib.Nifti1Image(evecs[..., 1], affine) e3_img = nib.Nifti1Image(evecs[..., 2], affine) nib.save(e1_img, add_filename_suffix(args.evecs, '_v1')) nib.save(e2_img, add_filename_suffix(args.evecs, '_v2')) nib.save(e3_img, add_filename_suffix(args.evecs, '_v3')) if args.evals: evals = tenfit.evals.astype(np.float32) evals_img = nib.Nifti1Image(evals, affine) nib.save(evals_img, args.evals) # save individual e-values also e1_img = nib.Nifti1Image(evals[..., 0], affine) e2_img = nib.Nifti1Image(evals[..., 1], affine) e3_img = nib.Nifti1Image(evals[..., 2], affine) nib.save(e1_img, add_filename_suffix(args.evals, '_e1')) nib.save(e2_img, add_filename_suffix(args.evals, '_e2')) nib.save(e3_img, add_filename_suffix(args.evals, '_e3')) if args.p_i_signal: S0 = np.mean(data[..., gtab.b0s_mask], axis=-1, keepdims=True) DWI = data[..., ~gtab.b0s_mask] pis_mask = np.max(S0 < DWI, axis=-1) if args.mask is not None: pis_mask *= mask pis_img = nib.Nifti1Image(pis_mask.astype(np.int16), affine) nib.save(pis_img, args.p_i_signal) if args.pulsation: STD = np.std(data[..., ~gtab.b0s_mask], axis=-1) if args.mask is not None: STD *= mask std_img = nib.Nifti1Image(STD.astype(np.float32), affine) nib.save(std_img, add_filename_suffix(args.pulsation, '_std_dwi')) if np.sum(gtab.b0s_mask) <= 1: logger.info('Not enough b=0 images to output standard ' 'deviation map') else: if len(np.where(gtab.b0s_mask)) == 2: logger.info('Only two b=0 images. Be careful with the ' 'interpretation of this std map') STD = np.std(data[..., gtab.b0s_mask], axis=-1) if args.mask is not None: STD *= mask std_img = nib.Nifti1Image(STD.astype(np.float32), affine) nib.save(std_img, add_filename_suffix(args.pulsation, '_std_b0')) if args.residual: # Mean residual image S0 = np.mean(data[..., gtab.b0s_mask], axis=-1) data_p = tenfit.predict(gtab, S0) R = np.mean(np.abs(data_p[..., ~gtab.b0s_mask] - data[..., ~gtab.b0s_mask]), axis=-1) if args.mask is not None: R *= mask R_img = nib.Nifti1Image(R.astype(np.float32), affine) nib.save(R_img, args.residual) # Each volume's residual statistics if args.mask is None: logger.info("Outlier detection will not be performed, since no " "mask was provided.") stats = [dict.fromkeys(['label', 'mean', 'iqr', 'cilo', 'cihi', 'whishi', 'whislo', 'fliers', 'q1', 'med', 'q3'], []) for i in range(data.shape[-1])] # stats with format for boxplots # Note that stats will be computed manually and plotted using bxp # but could be computed using stats = cbook.boxplot_stats # or pyplot.boxplot(x) R_k = np.zeros(data.shape[-1]) # mean residual per DWI std = np.zeros(data.shape[-1]) # std residual per DWI q1 = np.zeros(data.shape[-1]) # first quartile per DWI q3 = np.zeros(data.shape[-1]) # third quartile per DWI iqr = np.zeros(data.shape[-1]) # interquartile per DWI percent_outliers = np.zeros(data.shape[-1]) nb_voxels = np.count_nonzero(mask) for k in range(data.shape[-1]): x = np.abs(data_p[..., k] - data[..., k])[mask] R_k[k] = np.mean(x) std[k] = np.std(x) q3[k], q1[k] = np.percentile(x, [75, 25]) iqr[k] = q3[k] - q1[k] stats[k]['med'] = (q1[k] + q3[k]) / 2 stats[k]['mean'] = R_k[k] stats[k]['q1'] = q1[k] stats[k]['q3'] = q3[k] stats[k]['whislo'] = q1[k] - 1.5 * iqr[k] stats[k]['whishi'] = q3[k] + 1.5 * iqr[k] stats[k]['label'] = k # Outliers are observations that fall below Q1 - 1.5(IQR) or # above Q3 + 1.5(IQR) We check if a voxel is an outlier only if # we have a mask, else we are biased. if args.mask is not None: outliers = (x < stats[k]['whislo']) | (x > stats[k]['whishi']) percent_outliers[k] = np.sum(outliers)/nb_voxels*100 # What would be our definition of too many outliers? # Maybe mean(all_means)+-3SD? # Or we let people choose based on the figure. # if percent_outliers[k] > ???? : # logger.warning(' Careful! Diffusion-Weighted Image' # ' i=%s has %s %% outlier voxels', # k, percent_outliers[k]) # Saving all statistics as npy values residual_basename, _ = split_name_with_nii(args.residual) res_stats_basename = residual_basename + ".npy" np.save(add_filename_suffix( res_stats_basename, "_mean_residuals"), R_k) np.save(add_filename_suffix(res_stats_basename, "_q1_residuals"), q1) np.save(add_filename_suffix(res_stats_basename, "_q3_residuals"), q3) np.save(add_filename_suffix(res_stats_basename, "_iqr_residuals"), iqr) np.save(add_filename_suffix(res_stats_basename, "_std_residuals"), std) # Showing results in graph if args.mask is None: fig, axe = plt.subplots(nrows=1, ncols=1, squeeze=False) else: fig, axe = plt.subplots(nrows=1, ncols=2, squeeze=False, figsize=[10, 4.8]) # Default is [6.4, 4.8]. Increasing width to see better. medianprops = dict(linestyle='-', linewidth=2.5, color='firebrick') meanprops = dict(linestyle='-', linewidth=2.5, color='green') axe[0, 0].bxp(stats, showmeans=True, meanline=True, showfliers=False, medianprops=medianprops, meanprops=meanprops) axe[0, 0].set_xlabel('DW image') axe[0, 0].set_ylabel('Residuals per DWI volume. Red is median,\n' 'green is mean. Whiskers are 1.5*interquartile') axe[0, 0].set_title('Residuals') axe[0, 0].set_xticks(range(0, q1.shape[0], 5)) axe[0, 0].set_xticklabels(range(0, q1.shape[0], 5)) if args.mask is not None: axe[0, 1].plot(range(data.shape[-1]), percent_outliers) axe[0, 1].set_xticks(range(0, q1.shape[0], 5)) axe[0, 1].set_xticklabels(range(0, q1.shape[0], 5)) axe[0, 1].set_xlabel('DW image') axe[0, 1].set_ylabel('Percentage of outlier voxels') axe[0, 1].set_title('Outliers') plt.savefig(residual_basename + '_residuals_stats.png')
def run(self, input_files, bvalues_files, bvectors_files, sigma=0, b0_threshold=50, bvecs_tol=0.01, patch_radius=2, pca_method='eig', tau_factor=2.3, out_dir='', out_denoised='dwi_lpca.nii.gz'): r"""Workflow wrapping LPCA denoising method. Parameters ---------- input_files : string Path to the input volumes. This path may contain wildcards to process multiple inputs at once. bvalues_files : string Path to the bvalues files. This path may contain wildcards to use multiple bvalues files at once. bvectors_files : string Path to the bvectors files. This path may contain wildcards to use multiple bvectors files at once. sigma : float, optional Standard deviation of the noise estimated from the data. Default 0: it means sigma value estimation with the Manjon2013 algorithm [3]_. b0_threshold : float, optional Threshold used to find b0 volumes. bvecs_tol : float, optional Threshold used to check that norm(bvec) = 1 +/- bvecs_tol b-vectors are unit vectors. patch_radius : int, optional The radius of the local patch to be taken around each voxel (in voxels) For example, for a patch radius with value 2, and assuming the input image is a 3D image, the denoising will take place in blocks of 5x5x5 voxels. pca_method : string, optional Use either eigenvalue decomposition ('eig') or singular value decomposition ('svd') for principal component analysis. The default method is 'eig' which is faster. However, occasionally 'svd' might be more accurate. tau_factor : float, optional Thresholding of PCA eigenvalues is done by nulling out eigenvalues that are smaller than: .. math :: \tau = (\tau_{factor} \sigma)^2 \tau_{factor} can be change to adjust the relationship between the noise standard deviation and the threshold \tau. If \tau_{factor} is set to None, it will be automatically calculated using the Marcenko-Pastur distribution [2]_. out_dir : string, optional Output directory. (default current directory) out_denoised : string, optional Name of the resulting denoised volume. References ---------- .. [1] Veraart J, Novikov DS, Christiaens D, Ades-aron B, Sijbers, Fieremans E, 2016. Denoising of Diffusion MRI using random matrix theory. Neuroimage 142:394-406. doi: 10.1016/j.neuroimage.2016.08.016 .. [2] Veraart J, Fieremans E, Novikov DS. 2016. Diffusion MRI noise mapping using random matrix theory. Magnetic Resonance in Medicine. doi: 10.1002/mrm.26059. .. [3] Manjon JV, Coupe P, Concha L, Buades A, Collins DL (2013) Diffusion Weighted Image Denoising Using Overcomplete Local PCA. PLoS ONE 8(9): e73021. https://doi.org/10.1371/journal.pone.0073021 """ io_it = self.get_io_iterator() for dwi, bval, bvec, odenoised in io_it: logging.info('Denoising %s', dwi) data, affine, image = load_nifti(dwi, return_img=True) if not sigma: logging.info('Estimating sigma') bvals, bvecs = read_bvals_bvecs(bval, bvec) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_threshold, atol=bvecs_tol) sigma = pca_noise_estimate(data, gtab, correct_bias=True, smooth=3) logging.debug('Found sigma %s', sigma) denoised_data = localpca(data, sigma=sigma, patch_radius=patch_radius, pca_method=pca_method, tau_factor=tau_factor) save_nifti(odenoised, denoised_data, affine, image.header) logging.info('Denoised volume saved as %s', odenoised)
def main(): parser = _build_args_parser() args = parser.parse_args() img = nib.load(args.input) data = img.get_data() print('\ndata shape ({}, {}, {}, {})'.format(data.shape[0], data.shape[1], data.shape[2], data.shape[3])) print('total voxels {}'.format(np.prod(data.shape[:3]))) # remove negatives print('\ncliping negative ({} voxels, {:.2f} % of total)'.format((data<0).sum(),100*(data<0).sum()/float(np.prod(data.shape[:3])))) data = np.clip(data, 0, np.inf) affine = img.affine if args.mask is None: mask = None masksum = np.prod(data.shape[:3]) else: mask = nib.load(args.mask).get_data().astype(np.bool) masksum = mask.sum() print('\nMask has {} voxels, {:.2f} % of total'.format(masksum,100*masksum/float(np.prod(data.shape[:3])))) # Validate bvals and bvecs bvals, bvecs = read_bvals_bvecs(args.bvals, args.bvecs) if not is_normalized_bvecs(bvecs): print('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) # detect unique b-shell and assign shell id to each volume # sort bvals to get monotone increasing bvalue bvals_argsort = np.argsort(bvals) bvals_sorted = bvals[bvals_argsort] b_shell_threshold = 25. unique_bvalues = [] shell_idx = [] unique_bvalues.append(bvals_sorted[0]) shell_idx.append(0) for newb in bvals_sorted[1:]: # check if volume is in existing shell done = False for i,b in enumerate(unique_bvalues): if (newb - b_shell_threshold < b) and (newb + b_shell_threshold > b): shell_idx.append(i) done = True if not done: unique_bvalues.append(newb) shell_idx.append(i+1) unique_bvalues = np.array(unique_bvalues) # un-sort shells shells = np.zeros_like(bvals) shells[bvals_argsort] = shell_idx print('\nWe have {} shells'.format(len(unique_bvalues))) print('with b-values {}\n'.format(unique_bvalues)) for i in range(len(unique_bvalues)): shell_b = bvals[shells==i] print('shell {}: n = {}, min/max {} {}'.format(i, len(shell_b), shell_b.min(), shell_b.max())) # Get tensors method = 'WLS' min_signal = 1e-16 print('\nUsing fitting method {}'.format(method)) # print('Using minimum signal = {}'.format(min_signal) b0_thr = bvals.min() + 10 print('\nassuming existence of b0 (thr = {})\n'.format(b0_thr)) mds = [] for i in range(len(unique_bvalues)-1): # max_shell = i+1 print('fitting using first {} shells (bmax = {})'.format(i+2, bvals[shells==i+1].max())) # restricted gtab gtab = gradient_table(bvals[shells <= i+1], bvecs[shells <= i+1], b0_threshold=b0_thr) tenmodel = TensorModel(gtab, fit_method=method, min_signal=min_signal) tenfit = tenmodel.fit(data[..., shells <= i+1], mask) evalmax = np.max(tenfit.evals, axis=3) evalmin = np.min(tenfit.evals, axis=3) evalmax[np.isnan(evalmax)] = 0 evalmin[np.isnan(evalmin)] = 0 evalmax[np.isinf(evalmax)] = 0 evalmin[np.isinf(evalmin)] = 0 weird_contrast = np.exp(-unique_bvalues[i+1]*evalmin) - np.exp(-unique_bvalues[i+1]*evalmax) mds.append(weird_contrast[mask]) # peaks = [] oneq = [] twoq = [] threeq = [] th = 0.01 print('\nonly using values inside quantile [{}, {}] for plotting'.format(th, 1-th)) for i in range(len(unique_bvalues)-1): plt.figure() tit = 'exp(-b diff_MIN) - exp(-b diff_MAX), first {} shells (bmax = {})'.format(i+2, bvals[shells==i+1].max()) print('\nbmax = {}'.format(bvals[shells==i+1].max())) # truncate lower and upper MD to remove crazy outliers minval = 0 # maxval = np.quantile(mds[i], 1-th) tmp = mds[i] # vv1 = tmp.shape[0] tmp = tmp[tmp > minval] # vv2 = tmp.shape[0] print('removed {} zeros'.format(mds[i].shape[0] - tmp.shape[0])) # # remove high diffusivity non physical outlier # idx1 = (tmp <= 1/3.0e-3) # free water diffusivity at in-vivo brain temperature # print('{} voxels above free water diffusivity ({:.2f} % of mask)'.format(idx1.sum(), 100*idx1.sum()/float(masksum))) # # remove low diffusivity probable outlier # th_diff = 0.05 # idx2 = (tmp >= 1/(th_diff*1.0e-3)) # 1% of mean diffusivity of in-vivo WM at in-vivo brain temperature # print('{} voxels below {} of in-vivo WM diffusivity ({:.2f} % of mask)'.format(idx2.sum(),th_diff, 100*idx2.sum()/float(masksum))) # tmp = tmp[np.logical_not(np.logical_or(idx1, idx2))] # fit smoothed curve for peak extraction # gkde = gaussian_kde(tmp) # plt.hist(tmp, bins=100, density=True, color='grey') logbins = np.logspace(-2,np.log10(0.7),100) plt.hist(tmp, bins=logbins, density=True, color='grey') # bs = np.linspace(tmp.min(), tmp.max(), 1000) # bs = np.logspace(np.log10(tmp.min()), np.log10(tmp.max()), 1000) # smoothed = gkde.pdf(bs) # plt.plot(bs, smoothed, color='blue', linewidth=2) plt.semilogx([],[]) # plt.semilogx(bs, smoothed, color='blue', linewidth=2) # peak extraction # smoothed_peak = bs[smoothed.argmax()] # plt.axvline(smoothed_peak, color='red', label='peak ({:.0f})'.format(smoothed_peak)) # peaks.append(smoothed_peak) # useless extra lines onequart = np.quantile(tmp, 0.25) twoquart = np.quantile(tmp, 0.5) threequart = np.quantile(tmp, 0.75) oneq.append(onequart) twoq.append(twoquart) threeq.append(threequart) plt.axvline(onequart, color='pink', label='25% ({:.2f})'.format(onequart)) plt.axvline(twoquart, color='yellow', label='50% ({:.2f})'.format(twoquart)) plt.axvline(threequart, color='green', label='75% ({:.2f})'.format(threequart)) plt.title(tit) plt.legend(loc=1) plt.xlim([0.01,0.7]) plt.savefig('./dSEst_bmax_{:.0f}.png'.format(unique_bvalues[i])) # plt.show() # print('\nHigher-than-required bmax will artifactually decrease MD, increasing 1/MD') # print('The error on the estimation of 1/MD should be small when the peak is close to bmax') # print('This is under the assumption that we have a valid WM mask so that the tissues are somewhat uniform') bmaxs = np.array([bvals[shells==i+1].max() for i in range(len(unique_bvalues)-1)]) # plt.figure() # plt.plot(bmaxs, peaks, '-x', label = 'fit') # plt.plot(bmaxs, bmaxs, label = 'identity') # plt.xlabel('bmax') # plt.ylabel('MD^-1') # plt.legend() # plt.title('PEAK') # plt.savefig('./bvalEst_peak.png') plt.figure() plt.grid() plt.plot(bmaxs, oneq, '-x', label = 'fit') # plt.plot(bmaxs, bmaxs, label = 'identity') plt.xlabel('bmax') # plt.ylabel('MD^-1') # plt.legend() # plt.title('25% quartile') # plt.savefig('./bvalEst_50Q.png') # plt.figure() plt.plot(bmaxs, twoq, '-x', label = 'fit') # plt.plot(bmaxs, bmaxs, label = 'identity') plt.xlabel('bmax') # plt.ylabel('MD^-1') # plt.legend() # plt.title('50% quartile') # plt.savefig('./bvalEst_50Q.png') # plt.figure() plt.plot(bmaxs, threeq, '-x', label = 'fit') # plt.plot(bmaxs, bmaxs, label = 'identity') plt.xlabel('bmax') plt.ylabel('delta S') # plt.legend() # plt.title('75% quartile') plt.title('Quartile') plt.savefig('./bvalEst_Qs.png')
""" Reconstructing diffusion data using MSDKI ========================================= Now that the properties of MSDKI were illustrated, let's apply MSDKI to in-vivo diffusion-weighted data. As the example for the standard DKI (see :ref:`example_reconst_dki`), we use fetch to download a multi-shell dataset which was kindly provided by Hansen and Jespersen (more details about the data are provided in their paper [Hansen2016]_). The total size of the downloaded data is 192 MBytes, however you only need to fetch it once. """ fraw, fbval, fbvec, t1_fname = get_fnames('cfin_multib') data, affine = load_nifti(fraw) bvals, bvecs = read_bvals_bvecs(fbval, fbvec) gtab = gradient_table(bvals, bvecs) """ Before fitting the data, we preform some data pre-processing. For illustration, we only mask the data to avoid unnecessary calculations on the background of the image; however, you could also apply other pre-processing techniques. For example, some state of the art denoising algorithms are available in DIPY_ (e.g. the non-local means filter :ref:`example-denoise-nlmeans` or the local pca :ref:`example-denoise-localpca`). """ maskdata, mask = median_otsu(data, vol_idx=[0, 1], median_radius=4, numpass=2, autocrop=False,
def test_reconst_dki(): with TemporaryDirectory() as out_dir: data_path, bval_path, bvec_path = get_fnames('small_101D') volume, affine = load_nifti(data_path) mask = np.ones_like(volume[:, :, :, 0]) mask_path = pjoin(out_dir, 'tmp_mask.nii.gz') save_nifti(mask_path, mask.astype(np.uint8), affine) dki_flow = ReconstDkiFlow() args = [data_path, bval_path, bvec_path, mask_path] dki_flow.run(*args, out_dir=out_dir) fa_path = dki_flow.last_generated_outputs['out_fa'] fa_data = load_nifti_data(fa_path) assert_equal(fa_data.shape, volume.shape[:-1]) tensor_path = dki_flow.last_generated_outputs['out_dt_tensor'] tensor_data = load_nifti_data(tensor_path) assert_equal(tensor_data.shape[-1], 6) assert_equal(tensor_data.shape[:-1], volume.shape[:-1]) ga_path = dki_flow.last_generated_outputs['out_ga'] ga_data = load_nifti_data(ga_path) assert_equal(ga_data.shape, volume.shape[:-1]) rgb_path = dki_flow.last_generated_outputs['out_rgb'] rgb_data = load_nifti_data(rgb_path) assert_equal(rgb_data.shape[-1], 3) assert_equal(rgb_data.shape[:-1], volume.shape[:-1]) md_path = dki_flow.last_generated_outputs['out_md'] md_data = load_nifti_data(md_path) assert_equal(md_data.shape, volume.shape[:-1]) ad_path = dki_flow.last_generated_outputs['out_ad'] ad_data = load_nifti_data(ad_path) assert_equal(ad_data.shape, volume.shape[:-1]) rd_path = dki_flow.last_generated_outputs['out_rd'] rd_data = load_nifti_data(rd_path) assert_equal(rd_data.shape, volume.shape[:-1]) mk_path = dki_flow.last_generated_outputs['out_mk'] mk_data = load_nifti_data(mk_path) assert_equal(mk_data.shape, volume.shape[:-1]) ak_path = dki_flow.last_generated_outputs['out_ak'] ak_data = load_nifti_data(ak_path) assert_equal(ak_data.shape, volume.shape[:-1]) rk_path = dki_flow.last_generated_outputs['out_rk'] rk_data = load_nifti_data(rk_path) assert_equal(rk_data.shape, volume.shape[:-1]) kt_path = dki_flow.last_generated_outputs['out_dk_tensor'] kt_data = load_nifti_data(kt_path) assert_equal(kt_data.shape[-1], 15) assert_equal(kt_data.shape[:-1], volume.shape[:-1]) mode_path = dki_flow.last_generated_outputs['out_mode'] mode_data = load_nifti_data(mode_path) assert_equal(mode_data.shape, volume.shape[:-1]) evecs_path = dki_flow.last_generated_outputs['out_evec'] evecs_data = load_nifti_data(evecs_path) assert_equal(evecs_data.shape[-2:], tuple((3, 3))) assert_equal(evecs_data.shape[:-2], volume.shape[:-1]) evals_path = dki_flow.last_generated_outputs['out_eval'] evals_data = load_nifti_data(evals_path) assert_equal(evals_data.shape[-1], 3) assert_equal(evals_data.shape[:-1], volume.shape[:-1]) bvals, bvecs = read_bvals_bvecs(bval_path, bvec_path) bvals[0] = 5. bvecs = generate_bvecs(len(bvals)) tmp_bval_path = pjoin(out_dir, "tmp.bval") tmp_bvec_path = pjoin(out_dir, "tmp.bvec") np.savetxt(tmp_bval_path, bvals) np.savetxt(tmp_bvec_path, bvecs.T) dki_flow._force_overwrite = True npt.assert_warns(UserWarning, dki_flow.run, data_path, tmp_bval_path, tmp_bvec_path, mask_path, out_dir=out_dir, b0_threshold=0)
def test_peaksFromModelParallel(): SNR = 100 S0 = 100 _, fbvals, fbvecs = get_fnames('small_64D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gtab = gradient_table(bvals, bvecs) mevals = np.array(([0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003])) data, _ = multi_tensor(gtab, mevals, S0, angles=[(0, 0), (60, 0)], fractions=[50, 50], snr=SNR) for sphere in [_sphere, get_sphere('symmetric724')]: # test equality with/without multiprocessing model = SimpleOdfModel(gtab) pam_multi = peaks_from_model(model, data, sphere, .5, 45, normalize_peaks=True, return_odf=True, return_sh=True, parallel=True) pam_single = peaks_from_model(model, data, sphere, .5, 45, normalize_peaks=True, return_odf=True, return_sh=True, parallel=False) pam_multi_inv1 = peaks_from_model(model, data, sphere, .5, 45, normalize_peaks=True, return_odf=True, return_sh=True, parallel=True, nbr_processes=0) pam_multi_inv2 = peaks_from_model(model, data, sphere, .5, 45, normalize_peaks=True, return_odf=True, return_sh=True, parallel=True, nbr_processes=-2) for pam in [pam_multi, pam_multi_inv1, pam_multi_inv2]: assert_equal(pam.gfa.dtype, pam_single.gfa.dtype) assert_equal(pam.gfa.shape, pam_single.gfa.shape) assert_array_almost_equal(pam.gfa, pam_single.gfa) assert_equal(pam.qa.dtype, pam_single.qa.dtype) assert_equal(pam.qa.shape, pam_single.qa.shape) assert_array_almost_equal(pam.qa, pam_single.qa) assert_equal(pam.peak_values.dtype, pam_single.peak_values.dtype) assert_equal(pam.peak_values.shape, pam_single.peak_values.shape) assert_array_almost_equal(pam.peak_values, pam_single.peak_values) assert_equal(pam.peak_indices.dtype, pam_single.peak_indices.dtype) assert_equal(pam.peak_indices.shape, pam_single.peak_indices.shape) assert_array_equal(pam.peak_indices, pam_single.peak_indices) assert_equal(pam.peak_dirs.dtype, pam_single.peak_dirs.dtype) assert_equal(pam.peak_dirs.shape, pam_single.peak_dirs.shape) assert_array_almost_equal(pam.peak_dirs, pam_single.peak_dirs) assert_equal(pam.shm_coeff.dtype, pam_single.shm_coeff.dtype) assert_equal(pam.shm_coeff.shape, pam_single.shm_coeff.shape) assert_array_almost_equal(pam.shm_coeff, pam_single.shm_coeff) assert_equal(pam.odf.dtype, pam_single.odf.dtype) assert_equal(pam.odf.shape, pam_single.odf.shape) assert_array_almost_equal(pam.odf, pam_single.odf)
def main(): start = time.time() with open('config.json') as config_json: config = json.load(config_json) # Load the data dmri_image = nib.load(config['data_file']) dmri = dmri_image.get_data() affine = dmri_image.affine #aparc_im = nib.load(config['freesurfer']) aparc_im = nib.load('volume.nii.gz') aparc = aparc_im.get_data() end = time.time() print('Loaded Files: ' + str((end - start))) print(dmri.shape) print(aparc.shape) # Create the white matter and callosal masks start = time.time() wm_regions = [ 2, 41, 16, 17, 28, 60, 51, 53, 12, 52, 12, 52, 13, 18, 54, 50, 11, 251, 252, 253, 254, 255, 10, 49, 46, 7 ] wm_mask = np.zeros(aparc.shape) for l in wm_regions: wm_mask[aparc == l] = 1 #np.save('wm_mask',wm_mask) #p = os.getcwd()+'wm.json' #json.dump(wm_mask, codecs.open(p, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4) #with open('wm_mask.txt', 'wb') as wm: #np.savetxt('wm.txt', wm_mask, fmt='%5s') #print(wm_mask) # Create the gradient table from the bvals and bvecs bvals, bvecs = read_bvals_bvecs(config['data_bval'], config['data_bvec']) gtab = gradient_table(bvals, bvecs, b0_threshold=100) end = time.time() print('Created Gradient Table: ' + str((end - start))) ##The probabilistic model## """ # Use the Constant Solid Angle (CSA) to find the Orientation Dist. Function # Helps orient the wm tracts start = time.time() csa_model = CsaOdfModel(gtab, sh_order=6) csa_peaks = peaks_from_model(csa_model, dmri, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=wm_mask) print('Creating CSA Model: ' + str(time.time() - start)) """ # Use the SHORE model to find Orientation Dist. Function start = time.time() shore_model = ShoreModel(gtab) shore_peaks = peaks_from_model(shore_model, dmri, default_sphere, relative_peak_threshold=.8, min_separation_angle=45, mask=wm_mask) print('Creating Shore Model: ' + str(time.time() - start)) # Begins the seed in the wm tracts seeds = utils.seeds_from_mask(wm_mask, density=[1, 1, 1], affine=affine) print('Created White Matter seeds: ' + str(time.time() - start)) # Create a CSD model to measure Fiber Orientation Dist print('Begin the probabilistic model') response, ratio = auto_response(gtab, dmri, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data=dmri, mask=wm_mask) print('Created the CSD model: ' + str(time.time() - start)) # Set the Direction Getter to randomly choose directions prob_dg = ProbabilisticDirectionGetter.from_shcoeff(csd_fit.shm_coeff, max_angle=30., sphere=default_sphere) print('Created the Direction Getter: ' + str(time.time() - start)) # Restrict the white matter tracking classifier = ThresholdTissueClassifier(shore_peaks.gfa, .25) print('Created the Tissue Classifier: ' + str(time.time() - start)) # Create the probabilistic model streamlines = LocalTracking(prob_dg, tissue_classifier=classifier, seeds=seeds, step_size=.5, max_cross=1, affine=affine) print('Created the probabilistic model: ' + str(time.time() - start)) # Compute streamlines and store as a list. streamlines = list(streamlines) print('Computed streamlines: ' + str(time.time() - start)) #from dipy.tracking.streamline import transform_streamlines #streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) # Create a tractogram from the streamlines and save it tractogram = Tractogram(streamlines, affine_to_rasmm=affine) save(tractogram, 'track.tck') end = time.time() print("Created the tck file: " + str((end - start)))
def reconst_flow_core(flow): with TemporaryDirectory() as out_dir: data_path, bval_path, bvec_path = get_fnames('small_64D') volume, affine = load_nifti(data_path) mask = np.ones_like(volume[:, :, :, 0]) mask_path = pjoin(out_dir, 'tmp_mask.nii.gz') save_nifti(mask_path, mask.astype(np.uint8), affine) reconst_flow = flow() for sh_order in [4, 6, 8]: if flow.get_short_name() == 'csd': reconst_flow.run(data_path, bval_path, bvec_path, mask_path, sh_order=sh_order, out_dir=out_dir, extract_pam_values=True) elif flow.get_short_name() == 'csa': reconst_flow.run(data_path, bval_path, bvec_path, mask_path, sh_order=sh_order, odf_to_sh_order=sh_order, out_dir=out_dir, extract_pam_values=True) gfa_path = reconst_flow.last_generated_outputs['out_gfa'] gfa_data = load_nifti_data(gfa_path) npt.assert_equal(gfa_data.shape, volume.shape[:-1]) peaks_dir_path =\ reconst_flow.last_generated_outputs['out_peaks_dir'] peaks_dir_data = load_nifti_data(peaks_dir_path) npt.assert_equal(peaks_dir_data.shape[-1], 15) npt.assert_equal(peaks_dir_data.shape[:-1], volume.shape[:-1]) peaks_idx_path = \ reconst_flow.last_generated_outputs['out_peaks_indices'] peaks_idx_data = load_nifti_data(peaks_idx_path) npt.assert_equal(peaks_idx_data.shape[-1], 5) npt.assert_equal(peaks_idx_data.shape[:-1], volume.shape[:-1]) peaks_vals_path = \ reconst_flow.last_generated_outputs['out_peaks_values'] peaks_vals_data = load_nifti_data(peaks_vals_path) npt.assert_equal(peaks_vals_data.shape[-1], 5) npt.assert_equal(peaks_vals_data.shape[:-1], volume.shape[:-1]) shm_path = reconst_flow.last_generated_outputs['out_shm'] shm_data = load_nifti_data(shm_path) # Test that the number of coefficients is what you would expect # given the order of the sh basis: npt.assert_equal(shm_data.shape[-1], sph_harm_ind_list(sh_order)[0].shape[0]) npt.assert_equal(shm_data.shape[:-1], volume.shape[:-1]) pam = load_peaks(reconst_flow.last_generated_outputs['out_pam']) npt.assert_allclose(pam.peak_dirs.reshape(peaks_dir_data.shape), peaks_dir_data) npt.assert_allclose(pam.peak_values, peaks_vals_data) npt.assert_allclose(pam.peak_indices, peaks_idx_data) npt.assert_allclose(pam.shm_coeff, shm_data) npt.assert_allclose(pam.gfa, gfa_data) bvals, bvecs = read_bvals_bvecs(bval_path, bvec_path) bvals[0] = 5. bvecs = generate_bvecs(len(bvals)) tmp_bval_path = pjoin(out_dir, "tmp.bval") tmp_bvec_path = pjoin(out_dir, "tmp.bvec") np.savetxt(tmp_bval_path, bvals) np.savetxt(tmp_bvec_path, bvecs.T) reconst_flow._force_overwrite = True if flow.get_short_name() == 'csd': reconst_flow = flow() reconst_flow._force_overwrite = True reconst_flow.run(data_path, bval_path, bvec_path, mask_path, out_dir=out_dir, frf=[15, 5, 5]) reconst_flow = flow() reconst_flow._force_overwrite = True reconst_flow.run(data_path, bval_path, bvec_path, mask_path, out_dir=out_dir, frf='15, 5, 5') reconst_flow = flow() reconst_flow._force_overwrite = True reconst_flow.run(data_path, bval_path, bvec_path, mask_path, out_dir=out_dir, frf=None) reconst_flow2 = flow() reconst_flow2._force_overwrite = True reconst_flow2.run(data_path, bval_path, bvec_path, mask_path, out_dir=out_dir, frf=None, roi_center=[5, 5, 5]) else: with npt.assert_raises(BaseException): npt.assert_warns(UserWarning, reconst_flow.run, data_path, tmp_bval_path, tmp_bvec_path, mask_path, out_dir=out_dir, extract_pam_values=True) # test parallel implementation reconst_flow = flow() reconst_flow._force_overwrite = True reconst_flow.run(data_path, bval_path, bvec_path, mask_path, out_dir=out_dir, parallel=True, nbr_processes=None) reconst_flow = flow() reconst_flow._force_overwrite = True reconst_flow.run(data_path, bval_path, bvec_path, mask_path, out_dir=out_dir, parallel=True, nbr_processes=2)
# load other dipy's functions that will be used for auxiliar analysis from dipy.core.gradients import gradient_table from dipy.io.image import load_nifti from dipy.io.gradients import read_bvals_bvecs from dipy.segment.mask import median_otsu import dipy.reconst.dki as dki """ For this example, we use fetch to download a multi-shell dataset which was kindly provided by Hansen and Jespersen (more details about the data are provided in their paper [Hansen2016]_). The total size of the downloaded data is 192 MBytes, however you only need to fetch it once. """ dwi_fname, dwi_bval_fname, dwi_bvec_fname, _ = get_fnames('cfin_multib') data, affine = load_nifti(dwi_fname) bvals, bvecs = read_bvals_bvecs(dwi_bval_fname, dwi_bvec_fname) gtab = gradient_table(bvals, bvecs) """ For the sake of simplicity, we only select two non-zero b-values for this example. """ bvals = gtab.bvals bvecs = gtab.bvecs sel_b = np.logical_or(np.logical_or(bvals == 0, bvals == 1000), bvals == 2000) data = data[..., sel_b] gtab = gradient_table(bvals[sel_b], bvecs[sel_b])
def test_read_bvals_bvecs(): fimg, fbvals, fbvecs = get_data('small_101D') bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) gt = gradient_table(bvals, bvecs) npt.assert_array_equal(bvals, gt.bvals) npt.assert_array_equal(bvecs, gt.bvecs) # None should also work as an input: bvals_none, bvecs_none = read_bvals_bvecs(None, fbvecs) npt.assert_array_equal(bvecs_none, gt.bvecs) bvals_none, bvecs_none = read_bvals_bvecs(fbvals, None) npt.assert_array_equal(bvals_none, gt.bvals) # Test for error raising with unknown file formats: nan_fbvecs = osp.splitext(fbvecs)[0] + '.nan' # Nonsense extension npt.assert_raises(ValueError, read_bvals_bvecs, fbvals, nan_fbvecs) # Test for error raising with incorrect file-contents: with InTemporaryDirectory(): # These bvecs only have two rows/columns: new_bvecs1 = bvecs[:, :2] # Make a temporary file with open('test_bv_file1.txt', 'wt') as bv_file1: # And fill it with these 2-columned bvecs: for x in range(new_bvecs1.shape[0]): bv_file1.write('%s %s\n' % (new_bvecs1[x][0], new_bvecs1[x][1])) npt.assert_raises(IOError, read_bvals_bvecs, fbvals, 'test_bv_file1.txt') # These bvecs are saved as one long array: new_bvecs2 = np.ravel(bvecs) with open('test_bv_file2.npy', 'w') as bv_file2: print('FILENAME:', bv_file2.name) np.save(bv_file2.name, new_bvecs2) npt.assert_raises(IOError, read_bvals_bvecs, fbvals, 'test_bv_file2.npy') # There are less bvecs than bvals: new_bvecs3 = bvecs[:-1, :] with open('test_bv_file3.txt', 'w') as bv_file3: np.savetxt(bv_file3.name, new_bvecs3) npt.assert_raises(IOError, read_bvals_bvecs, fbvals, 'test_bv_file3.txt') # You entered the bvecs on both sides: npt.assert_raises(IOError, read_bvals_bvecs, fbvecs, fbvecs) # All possible delimiters should work bv_file4 = 'test_space.txt' with open(bv_file4, 'w') as f: f.write("66 55 33") bvals_1, _ = read_bvals_bvecs(bv_file4, '') bv_file5 = 'test_coma.txt' with open(bv_file5, 'w') as f: f.write("66, 55, 33") bvals_2, _ = read_bvals_bvecs(bv_file5, '') bv_file6 = 'test_tabs.txt' with open(bv_file6, 'w') as f: f.write("66 \t 55 \t 33") bvals_3, _ = read_bvals_bvecs(bv_file6, '') ans = np.array([66., 55., 33.]) npt.assert_array_equal(ans, bvals_1) npt.assert_array_equal(ans, bvals_2) npt.assert_array_equal(ans, bvals_3) bv_file7 = 'test_space_2.txt' with open(bv_file7, 'w') as f: f.write("66 55 33\n45 34 21\n55 32 65\n") _, bvecs_1 = read_bvals_bvecs('', bv_file7) bv_file8 = 'test_coma_2.txt' with open(bv_file8, 'w') as f: f.write("66, 55, 33\n45, 34, 21 \n 55, 32, 65\n") _, bvecs_2 = read_bvals_bvecs('', bv_file8) bv_file9 = 'test_tabs_2.txt' with open(bv_file9, 'w') as f: f.write("66 \t 55 \t 33\n45 \t 34 \t 21\n55 \t 32 \t 65\n") _, bvecs_3 = read_bvals_bvecs('', bv_file9) bv_file10 = 'test_multiple_space.txt' with open(bv_file10, 'w') as f: f.write("66 55 33\n45, 34, 21 \n 55, 32, 65\n") _, bvecs_4 = read_bvals_bvecs('', bv_file10) ans = np.array([[66., 55., 33.], [45., 34., 21.], [55., 32., 65.]]) npt.assert_array_equal(ans, bvecs_1) npt.assert_array_equal(ans, bvecs_2) npt.assert_array_equal(ans, bvecs_3) npt.assert_array_equal(ans, bvecs_4)
auto_response) from dipy.tracking import utils from dipy.tracking.local_tracking import LocalTracking from dipy.tracking.streamline import Streamlines from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion from dipy.viz import window, actor, colormap, has_fury # Enables/disables interactive visualization interactive = False hardi_fname, hardi_bval_fname, hardi_bvec_fname = get_fnames('stanford_hardi') label_fname = get_fnames('stanford_labels') data, affine, hardi_img = load_nifti(hardi_fname, return_img=True) labels = load_nifti_data(label_fname) bvals, bvecs = read_bvals_bvecs(hardi_bval_fname, hardi_bvec_fname) gtab = gradient_table(bvals, bvecs) seed_mask = (labels == 2) white_matter = (labels == 1) | (labels == 2) seeds = utils.seeds_from_mask(seed_mask, affine, density=1) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) """ We use the GFA of the CSA model to build a stopping criterion. """ from dipy.reconst.shm import CsaOdfModel
def main(): parser = _build_arg_parser() args = parser.parse_args() logging.basicConfig(level=logging.INFO) if not args.not_all: args.wm_out_fODF = args.wm_out_fODF or 'wm_fodf.nii.gz' args.gm_out_fODF = args.gm_out_fODF or 'gm_fodf.nii.gz' args.csf_out_fODF = args.csf_out_fODF or 'csf_fodf.nii.gz' args.vf = args.vf or 'vf.nii.gz' args.vf_rgb = args.vf_rgb or 'vf_rgb.nii.gz' arglist = [args.wm_out_fODF, args.gm_out_fODF, args.csf_out_fODF, args.vf, args.vf_rgb] if args.not_all and not any(arglist): parser.error('When using --not_all, you need to specify at least ' + 'one file to output.') assert_inputs_exist(parser, [args.in_dwi, args.in_bval, args.in_bvec, args.in_wm_frf, args.in_gm_frf, args.in_csf_frf]) assert_outputs_exist(parser, args, arglist) # Loading data wm_frf = np.loadtxt(args.in_wm_frf) gm_frf = np.loadtxt(args.in_gm_frf) csf_frf = np.loadtxt(args.in_csf_frf) vol = nib.load(args.in_dwi) data = vol.get_fdata(dtype=np.float32) bvals, bvecs = read_bvals_bvecs(args.in_bval, args.in_bvec) # Checking mask if args.mask is None: mask = None else: mask = get_data_as_mask(nib.load(args.mask), dtype=bool) if mask.shape != data.shape[:-1]: raise ValueError("Mask is not the same shape as data.") sh_order = args.sh_order # Checking data and sh_order b0_thr = check_b0_threshold( args.force_b0_threshold, bvals.min(), bvals.min()) if data.shape[-1] < (sh_order + 1) * (sh_order + 2) / 2: logging.warning( 'We recommend having at least {} unique DWIs volumes, but you ' 'currently have {} volumes. Try lowering the parameter --sh_order ' 'in case of non convergence.'.format( (sh_order + 1) * (sh_order + 2) / 2, data.shape[-1])) # Checking bvals, bvecs values and loading gtab if not is_normalized_bvecs(bvecs): logging.warning('Your b-vectors do not seem normalized...') bvecs = normalize_bvecs(bvecs) gtab = gradient_table(bvals, bvecs, b0_threshold=b0_thr) # Checking response functions and computing msmt response function if not wm_frf.shape[1] == 4: raise ValueError('WM frf file did not contain 4 elements. ' 'Invalid or deprecated FRF format') if not gm_frf.shape[1] == 4: raise ValueError('GM frf file did not contain 4 elements. ' 'Invalid or deprecated FRF format') if not csf_frf.shape[1] == 4: raise ValueError('CSF frf file did not contain 4 elements. ' 'Invalid or deprecated FRF format') ubvals = unique_bvals_tolerance(bvals, tol=20) msmt_response = multi_shell_fiber_response(sh_order, ubvals, wm_frf, gm_frf, csf_frf) # Loading spheres reg_sphere = get_sphere('symmetric362') # Computing msmt-CSD msmt_model = MultiShellDeconvModel(gtab, msmt_response, reg_sphere=reg_sphere, sh_order=sh_order) # Computing msmt-CSD fit msmt_fit = fit_from_model(msmt_model, data, mask=mask, nbr_processes=args.nbr_processes) shm_coeff = msmt_fit.all_shm_coeff nan_count = len(np.argwhere(np.isnan(shm_coeff[..., 0]))) voxel_count = np.prod(shm_coeff.shape[:-1]) if nan_count / voxel_count >= 0.05: msg = """There are {} voxels out of {} that could not be solved by the solver, reaching a critical amount of voxels. Make sure to tune the response functions properly, as the solving process is very sensitive to it. Proceeding to fill the problematic voxels by 0. """ logging.warning(msg.format(nan_count, voxel_count)) elif nan_count > 0: msg = """There are {} voxels out of {} that could not be solved by the solver. Make sure to tune the response functions properly, as the solving process is very sensitive to it. Proceeding to fill the problematic voxels by 0. """ logging.warning(msg.format(nan_count, voxel_count)) shm_coeff = np.where(np.isnan(shm_coeff), 0, shm_coeff) # Saving results if args.wm_out_fODF: wm_coeff = shm_coeff[..., 2:] if args.sh_basis == 'tournier07': wm_coeff = convert_sh_basis(wm_coeff, reg_sphere, mask=mask, nbr_processes=args.nbr_processes) nib.save(nib.Nifti1Image(wm_coeff.astype(np.float32), vol.affine), args.wm_out_fODF) if args.gm_out_fODF: gm_coeff = shm_coeff[..., 1] if args.sh_basis == 'tournier07': gm_coeff = gm_coeff.reshape(gm_coeff.shape + (1,)) gm_coeff = convert_sh_basis(gm_coeff, reg_sphere, mask=mask, nbr_processes=args.nbr_processes) nib.save(nib.Nifti1Image(gm_coeff.astype(np.float32), vol.affine), args.gm_out_fODF) if args.csf_out_fODF: csf_coeff = shm_coeff[..., 0] if args.sh_basis == 'tournier07': csf_coeff = csf_coeff.reshape(csf_coeff.shape + (1,)) csf_coeff = convert_sh_basis(csf_coeff, reg_sphere, mask=mask, nbr_processes=args.nbr_processes) nib.save(nib.Nifti1Image(csf_coeff.astype(np.float32), vol.affine), args.csf_out_fODF) if args.vf: nib.save(nib.Nifti1Image(msmt_fit.volume_fractions.astype(np.float32), vol.affine), args.vf) if args.vf_rgb: vf = msmt_fit.volume_fractions vf_rgb = vf / np.max(vf) * 255 vf_rgb = np.clip(vf_rgb, 0, 255) nib.save(nib.Nifti1Image(vf_rgb.astype(np.uint8), vol.affine), args.vf_rgb)