From 4b77ad000ae1b7c9c81f463a00ffb38e6e01924e Mon Sep 17 00:00:00 2001 From: EliseCos Date: Thu, 27 Jul 2023 13:31:39 -0400 Subject: [PATCH 01/10] add subdivide sphere argument --- scripts/scil_compute_local_tracking.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/scil_compute_local_tracking.py b/scripts/scil_compute_local_tracking.py index ccba3afde..0bd77bf39 100755 --- a/scripts/scil_compute_local_tracking.py +++ b/scripts/scil_compute_local_tracking.py @@ -63,7 +63,10 @@ def _build_arg_parser(): choices=['det', 'prob', 'eudx'], help='Algorithm to use. [%(default)s]') add_sphere_arg(track_g, symmetric_only=True) - + track_g.add_argument('--sub_sphere', metavar='SPHERE_DIVISION', + type=int, default=1, + help='Multiply the number of directions in the sphere. ' + '[%(default)s]') add_seeding_options(p) out_g = add_out_options(p) @@ -78,7 +81,7 @@ def _build_arg_parser(): def _get_direction_getter(args): odf_data = nib.load(args.in_odf).get_fdata(dtype=np.float32) - sphere = HemiSphere.from_sphere(get_sphere(args.sphere)) + sphere = HemiSphere.from_sphere(get_sphere(args.sphere)).subdivide(args.sub_sphere) theta = get_theta(args.theta, args.algo) non_zeros_count = np.count_nonzero(np.sum(odf_data, axis=-1)) From cbf8e87e85bc3d7c3975643e5567e8c9783a56bf Mon Sep 17 00:00:00 2001 From: EliseCos Date: Thu, 27 Jul 2023 14:00:45 -0400 Subject: [PATCH 02/10] add test --- scripts/tests/test_compute_local_tracking.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/tests/test_compute_local_tracking.py b/scripts/tests/test_compute_local_tracking.py index 9d0c40770..c5f24f14c 100644 --- a/scripts/tests/test_compute_local_tracking.py +++ b/scripts/tests/test_compute_local_tracking.py @@ -32,6 +32,21 @@ def test_execution_tracking_fodf(script_runner): assert ret.success +def test_execution_sphere_subdivide(script_runner): + os.chdir(os.path.expanduser(tmp_dir.name)) + in_fodf = os.path.join(get_home(), 'tracking', + 'fodf.nii.gz') + in_mask = os.path.join(get_home(), 'tracking', + 'seeding_mask.nii.gz') + + ret = script_runner.run('scil_compute_local_tracking.py', in_fodf, + in_mask, in_mask, 'local_sphere.trk', '--nt', '1000', + '--compress', '0.1', '--sh_basis', 'descoteaux07', + '--min_length', '20', '--max_length', '200', + '--sub_sphere', '2') + assert ret.success + + def test_execution_tracking_fodf_no_compression(script_runner): os.chdir(os.path.expanduser(tmp_dir.name)) in_fodf = os.path.join(get_home(), 'tracking', From df0b378066f0be9aafb8ff0daf4a701ce2a10c77 Mon Sep 17 00:00:00 2001 From: EliseCos Date: Thu, 27 Jul 2023 14:30:38 -0400 Subject: [PATCH 03/10] Change default sphere_subdivide --- scripts/scil_compute_local_tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_compute_local_tracking.py b/scripts/scil_compute_local_tracking.py index 0bd77bf39..d82d09573 100755 --- a/scripts/scil_compute_local_tracking.py +++ b/scripts/scil_compute_local_tracking.py @@ -64,7 +64,7 @@ def _build_arg_parser(): help='Algorithm to use. [%(default)s]') add_sphere_arg(track_g, symmetric_only=True) track_g.add_argument('--sub_sphere', metavar='SPHERE_DIVISION', - type=int, default=1, + type=int, default=0, help='Multiply the number of directions in the sphere. ' '[%(default)s]') add_seeding_options(p) From a1aa22b9957a98ded9ce9c0e4bb096d7e19401e0 Mon Sep 17 00:00:00 2001 From: EliseCos Date: Thu, 27 Jul 2023 14:55:10 -0400 Subject: [PATCH 04/10] Change argmument default --- scripts/scil_compute_local_tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_compute_local_tracking.py b/scripts/scil_compute_local_tracking.py index d82d09573..4e39d3d11 100755 --- a/scripts/scil_compute_local_tracking.py +++ b/scripts/scil_compute_local_tracking.py @@ -64,7 +64,7 @@ def _build_arg_parser(): help='Algorithm to use. [%(default)s]') add_sphere_arg(track_g, symmetric_only=True) track_g.add_argument('--sub_sphere', metavar='SPHERE_DIVISION', - type=int, default=0, + type=int, default=1, help='Multiply the number of directions in the sphere. ' '[%(default)s]') add_seeding_options(p) From 74857258ed7b4a28c7c25d5cfca61e3a949d5f49 Mon Sep 17 00:00:00 2001 From: EliseCos Date: Thu, 27 Jul 2023 14:55:49 -0400 Subject: [PATCH 05/10] Change default argument --- .DS_Store | Bin 0 -> 10244 bytes data/.DS_Store | Bin 0 -> 6148 bytes scripts/.DS_Store | Bin 0 -> 6148 bytes scripts/scil_compute_local_tracking.py | 2 +- scripts/scil_compute_local_tracking_mouse.py | 262 +++++++++++++++++++ 5 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 .DS_Store create mode 100644 data/.DS_Store create mode 100644 scripts/.DS_Store create mode 100755 scripts/scil_compute_local_tracking_mouse.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b49a362b752ae81095fad2b14af1c39c6d5e54d9 GIT binary patch literal 10244 zcmeHMZ)_Ar6rZ;(bk;6(Te?#I^$x2P^_2eOXcfb?SFk{_&}(Ta$gy|3!iMecvAcH# zDyE{5L?nJQ2!1g}jfwwa5b%?U9}LkCCeWBbq5=J8G%+Shq9*!gXRo2x@`V^7x|8g@ znK$#^-uun(&E3oqLZB`Ee}2a7 zP!S>!A`l`FA`l`FB5)@lfZy4y&`K`DIz%8uAVgpa0k%Ix@nJF%$O$g}tph9n2!OI2 z)qcUY%o-@8flLH)f=e910^AfOH-+Gc0o)w*(O_O8kP}>Ta{|HP1A;e0a6$q9?dU)1 zPbZMzGOR-cLIh?az|y9iXhbC*QExoIXL6?DdQDAVgHTpJXKn?ppq2E=)INJG<*8oY z?NXhctT$lWW~SIyGusV)EG^e2ZOc;)OLu$&L(_4}t|7zH?6EF8Z)vV?o8kjhq+(jG z8y|0tuZ~6AI$DmzqT}tYZP;#aJ90#%O2ev0`_uc)QOkajhXBDgK<1T%bo|D63Mt1j zZEG*;*!;P~C0Sw+ljO*u+Z}65TYD@TkH=Z89W6~5Yy4JXofcC`ycK@D4n~~A)pc)s z#4WhG@p!8radXG5u5L+GrdvqzJEyW0Mb2I+a#p;nQktg>3~nD9meO)f0m<2y^9=^d+gB}~3F*H2l+K!j>oedl4pU;x>uHLVsQ=_1Fqia_N@%{M=moC5WfmLlCk9BR> z+&5VzSJy14RiqJ256d&2GIVEf%+S1jJ5)ETTbg0*9V!^EkumiFOC8m#Ax1^ts&0{@ z4Cgb(fxO`zk{c+UtdXm$q64C*HCIcG%Kf6O z(g7DE<1S*-!=mhp1N$+DxoNZ1N@YzPG}Vl5a#dVvr}AcTsKCMH%35hH6^FC-=qLu` za@{(mlgbz9Zua6{)%E&vx`pp%fhX$~We3xDYMQPE5hy*%CMsW~Bkn%c(fh`5W8sc^ zlqV?l7ZLT$(|XPD?5V+iHYgib!N5HW*Nbmmv>|cqXMf*lNUZcFY2bnoAJB$G6Yq=o zt7I8zA>E{x>>&;rCnv~B@;W&~&XRNFbMh6rLave@$S>qN`JMbh{)9O&A7rS88dw5L zp&lX-gVhj+HIRf}*aCg96$W89q(OxY?1da002e$s49~&y@B$ozm*FJ53a8)=co*J- z58y-i6fVF;xCE2%4SWk%;Trr1zrt^DT@ZyDVS!L9Gzu$)X5kSbDf9^2_(vCtJLE_) zv_RjFa%K(%_qM|6*>fne;qji0o9^Hox;#I~n!6W9St_kro0#Gpr)ZItH?rL)__Va} z3GS1il$>>o7B5-4Oo|L*2IvQGmXLA#uZE?Km=PFfaOCsLXC(>lA*2}>pVPm%fy za*13f*T_#u>c5~IM5u%1&)2E-~_yals*Ng;Wc;@-h#K`9ry^&z*#s4=iw9h48BBaUxx2Wh}%1zxbXc< z;+A~jO*aU8Ap#)+Ap#)+Ap#)+vmj8$by0Tzzy9X`|IcC>szL-p1pX@sKzVnny9=W! z9vMpmV|VRQeD>hO3Y#~POKf5J*Z&L% Y&;RTubn0dh@6f{YKff0H-<<#d23AQNy8r+H literal 0 HcmV?d00001 diff --git a/data/.DS_Store b/data/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..af988df30fd930f1ed1f81593f8983464eefbf4c GIT binary patch literal 6148 zcmeHKPfNov6i?iA9Yg3rVaI^ifzwTycqw(>JlUxSmD$pv#oCOuvxhP0S-+5<#Lwe< zNeT{o7IE)E@_T=i<_FCm#u#_!;Q?bdW6Xkv$Wf^fbXSHpOfn+JG16%e%K)s8U}|E2 z9q`+0?1EjfQILQC{y0jrZugUK)asjC4Xa_btb6ZC=3eG!^VIccw`h%|jDu45gX?IL zkL{f^nPh&HOlGPe3MY_qcM~O{%w0K8!c^6II$$-e=Gbm87QN%6j_98pE<0i|==DJ# z^q0$~wY#@}dO3cMUlRGI>Eyt+l5K+}yn|v^^Xko#SSF9)DYMHgLSldzAO?tm^=81F z3s!5rX`s~;1H?cD1Gqm3Xo!x%LZjL`pu_7k#_NbEpyOKtQ5bX#78)S}!gVR2F6HKl z!F4(Kg~@Xa78-Rq<7#FY$IM(lUbvba{6eKO?r5Z*7$62#8K`N~#`FIiewoTg{%Q$X z!~iky&luqKp*M74QRZy@u{=C$1+)ifD418E0s{KVB>)WEN7^c=;{tWaa|{+5aTN5c QazMHWC_<i_@% literal 0 HcmV?d00001 diff --git a/scripts/.DS_Store b/scripts/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 0.5: + logging.warning('Input detected as peaks. Input should be' + 'fodf for det/prob, verify input just in case.') + if args.algo == 'det': + dg_class = DeterministicMaximumDirectionGetter + else: + dg_class = ProbabilisticDirectionGetter + return dg_class.from_shcoeff( + shcoeff=odf_data, max_angle=theta, sphere=sphere, + basis_type=args.sh_basis, + relative_peak_threshold=args.sf_threshold) + elif args.algo == 'eudx': + # Code for type EUDX. We don't use peaks_from_model + # because we want the peaks from the provided sh. + odf_shape_3d = odf_data.shape[:-1] + dg = PeaksAndMetrics() + dg.sphere = sphere + dg.ang_thr = theta + dg.qa_thr = args.sf_threshold + + # Heuristic to find out if the input are peaks or fodf + # fodf are always around 0.15 and peaks around 0.75 + if non_first_val_count / non_zeros_count > 0.5: + logging.info('Input detected as peaks.') + nb_peaks = odf_data.shape[-1] // 3 + slices = np.arange(0, 15+1, 3) + peak_values = np.zeros(odf_shape_3d+(nb_peaks,)) + peak_indices = np.zeros(odf_shape_3d+(nb_peaks,)) + + for idx in np.argwhere(np.sum(odf_data, axis=-1)): + idx = tuple(idx) + for i in range(nb_peaks): + peak_values[idx][i] = np.linalg.norm( + odf_data[idx][slices[i]:slices[i+1]], axis=-1) + peak_indices[idx][i] = sphere.find_closest( + odf_data[idx][slices[i]:slices[i+1]]) + + dg.peak_dirs = odf_data + else: + logging.info('Input detected as fodf.') + npeaks = 5 + peak_dirs = np.zeros((odf_shape_3d + (npeaks, 3))) + peak_values = np.zeros((odf_shape_3d + (npeaks, ))) + peak_indices = np.full((odf_shape_3d + (npeaks, )), -1, + dtype='int') + b_matrix = get_b_matrix( + find_order_from_nb_coeff(odf_data), sphere, args.sh_basis) + + for idx in np.argwhere(np.sum(odf_data, axis=-1)): + idx = tuple(idx) + directions, values, indices = get_maximas(odf_data[idx], + sphere, b_matrix, + args.sf_threshold, 0) + if values.shape[0] != 0: + n = min(npeaks, values.shape[0]) + peak_dirs[idx][:n] = directions[:n] + peak_values[idx][:n] = values[:n] + peak_indices[idx][:n] = indices[:n] + + dg.peak_dirs = peak_dirs + + dg.peak_values = peak_values + dg.peak_indices = peak_indices + + return dg + + +def main(): + parser = _build_arg_parser() + args = parser.parse_args() + + if args.verbose: + logging.getLogger().setLevel(logging.DEBUG) + + assert_inputs_exist(parser, [args.in_odf, args.in_seed, args.in_mask]) + assert_outputs_exist(parser, args, args.out_tractogram) + + if not nib.streamlines.is_supported(args.out_tractogram): + parser.error('Invalid output streamline file format (must be trk or ' + + 'tck): {0}'.format(args.out_tractogram)) + + verify_streamline_length_options(parser, args) + verify_compression_th(args.compress) + verify_seed_options(parser, args) + + mask_img = nib.load(args.in_mask) + mask_data = get_data_as_mask(mask_img, dtype=bool) + + # Make sure the data is isotropic. Else, the strategy used + # when providing information to dipy (i.e. working as if in voxel space) + # will not yield correct results. + odf_sh_img = nib.load(args.in_odf) + if not np.allclose(np.mean(odf_sh_img.header.get_zooms()[:3]), + odf_sh_img.header.get_zooms()[0], atol=1e-03): + parser.error( + 'ODF SH file is not isotropic. Tracking cannot be ran robustly.') + + if args.npv: + nb_seeds = args.npv + seed_per_vox = True + elif args.nt: + nb_seeds = args.nt + seed_per_vox = False + else: + nb_seeds = 1 + seed_per_vox = True + + voxel_size = odf_sh_img.header.get_zooms()[0] + vox_step_size = args.step_size / voxel_size + seed_img = nib.load(args.in_seed) + + if np.count_nonzero(seed_img.get_fdata(dtype=np.float32)) == 0: + raise IOError('The image {} is empty. ' + 'It can\'t be loaded as ' + 'seeding mask.'.format(args.in_seed)) + + # Note. Seeds are in voxel world, center origin. + # (See the examples in random_seeds_from_mask). + seeds = track_utils.random_seeds_from_mask( + seed_img.get_fdata(dtype=np.float32), + np.eye(4), + seeds_count=nb_seeds, + seed_count_per_voxel=seed_per_vox, + random_seed=args.seed) + + # Tracking is performed in voxel space + max_steps = int(args.max_length / args.step_size) + 1 + streamlines_generator = LocalTracking( + _get_direction_getter(args), + BinaryStoppingCriterion(mask_data), + seeds, np.eye(4), + step_size=vox_step_size, max_cross=1, + maxlen=max_steps, + fixedstep=True, return_all=True, + random_seed=args.seed, + save_seeds=args.save_seeds) + + scaled_min_length = args.min_length / voxel_size + scaled_max_length = args.max_length / voxel_size + + if args.save_seeds: + filtered_streamlines, seeds = \ + zip(*((s, p) for s, p in streamlines_generator + if scaled_min_length <= length(s) <= scaled_max_length)) + data_per_streamlines = {'seeds': lambda: seeds} + else: + filtered_streamlines = \ + (s for s in streamlines_generator + if scaled_min_length <= length(s) <= scaled_max_length) + data_per_streamlines = {} + + if args.compress: + # Compressing. Threshold is in mm, but we are working in voxel space. + # Equivalent of sft.to_voxmm: streamline *= voxres + # Equivalent of sft.to_vox: streamline /= voxres + voxres = np.asarray(odf_sh_img.header.get_zooms()[0:3]) + filtered_streamlines = ( + compress_streamlines(s * voxres, + args.compress) / voxres + for s in filtered_streamlines) + + tractogram = LazyTractogram(lambda: filtered_streamlines, + data_per_streamlines, + affine_to_rasmm=seed_img.affine) + + filetype = nib.streamlines.detect_format(args.out_tractogram) + reference = get_reference_info(seed_img) + header = create_tractogram_header(filetype, *reference) + + # Use generator to save the streamlines on-the-fly + nib.streamlines.save(tractogram, args.out_tractogram, header=header) + + +if __name__ == '__main__': + main() From d1445a631f21497a2f742e1adb65005dfb44b043 Mon Sep 17 00:00:00 2001 From: EliseCos <140726377+EliseCos@users.noreply.github.com> Date: Thu, 27 Jul 2023 14:57:41 -0400 Subject: [PATCH 06/10] Delete scil_compute_local_tracking_mouse.py Error --- scripts/scil_compute_local_tracking_mouse.py | 262 ------------------- 1 file changed, 262 deletions(-) delete mode 100755 scripts/scil_compute_local_tracking_mouse.py diff --git a/scripts/scil_compute_local_tracking_mouse.py b/scripts/scil_compute_local_tracking_mouse.py deleted file mode 100755 index 7b14fa158..000000000 --- a/scripts/scil_compute_local_tracking_mouse.py +++ /dev/null @@ -1,262 +0,0 @@ -#! /usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Local streamline HARDI tractography. -The tracking direction is chosen in the aperture cone defined by the -previous tracking direction and the angular constraint. - -Algo 'eudx': the peak from the spherical function (SF) most closely aligned -to the previous direction. -Algo 'det': the maxima of the spherical function (SF) the most closely aligned -to the previous direction. -Algo 'prob': a direction drawn from the empirical distribution function defined -from the SF. - -NOTE: eudx can be used with pre-computed peaks from fodf as well as -evecs_v1.nii.gz from scil_compute_dti_metrics.py (experimental). - -All the input nifti files must be in isotropic resolution. -""" - -import argparse -import logging - -from dipy.core.sphere import HemiSphere -from dipy.data import get_sphere -from dipy.direction import (DeterministicMaximumDirectionGetter, - ProbabilisticDirectionGetter) -from dipy.direction.peaks import PeaksAndMetrics -from dipy.io.utils import (get_reference_info, - create_tractogram_header) -from dipy.tracking.local_tracking import LocalTracking -from dipy.tracking.stopping_criterion import BinaryStoppingCriterion -from dipy.tracking.streamlinespeed import length, compress_streamlines -from dipy.tracking import utils as track_utils -import nibabel as nib -from nibabel.streamlines.tractogram import LazyTractogram -import numpy as np - -from scilpy.reconst.utils import (find_order_from_nb_coeff, - get_b_matrix, get_maximas) -from scilpy.io.image import get_data_as_mask -from scilpy.io.utils import (add_sphere_arg, add_verbose_arg, - assert_inputs_exist, assert_outputs_exist, - verify_compression_th) -from scilpy.tracking.tools import get_theta -from scilpy.tracking.utils import (add_mandatory_options_tracking, - add_out_options, add_seeding_options, - add_tracking_options, - verify_streamline_length_options, - verify_seed_options) - - -def _build_arg_parser(): - p = argparse.ArgumentParser( - description=__doc__, - formatter_class=argparse.RawTextHelpFormatter) - - add_mandatory_options_tracking(p) - - track_g = add_tracking_options(p) - track_g.add_argument('--algo', default='prob', - choices=['det', 'prob', 'eudx'], - help='Algorithm to use. [%(default)s]') - add_sphere_arg(track_g, symmetric_only=True) - - add_seeding_options(p) - out_g = add_out_options(p) - - out_g.add_argument('--seed', type=int, - help='Random number generator seed.') - - log_g = p.add_argument_group('Logging options') - add_verbose_arg(log_g) - - return p - - -def _get_direction_getter(args): - odf_data = nib.load(args.in_odf).get_fdata(dtype=np.float32) - sphere = HemiSphere.from_sphere(get_sphere("repulsion724").subdivide(2)) - theta = get_theta(args.theta, args.algo) - - non_zeros_count = np.count_nonzero(np.sum(odf_data, axis=-1)) - non_first_val_count = np.count_nonzero(np.argmax(odf_data, axis=-1)) - - if args.algo in ['det', 'prob']: - if non_first_val_count / non_zeros_count > 0.5: - logging.warning('Input detected as peaks. Input should be' - 'fodf for det/prob, verify input just in case.') - if args.algo == 'det': - dg_class = DeterministicMaximumDirectionGetter - else: - dg_class = ProbabilisticDirectionGetter - return dg_class.from_shcoeff( - shcoeff=odf_data, max_angle=theta, sphere=sphere, - basis_type=args.sh_basis, - relative_peak_threshold=args.sf_threshold) - elif args.algo == 'eudx': - # Code for type EUDX. We don't use peaks_from_model - # because we want the peaks from the provided sh. - odf_shape_3d = odf_data.shape[:-1] - dg = PeaksAndMetrics() - dg.sphere = sphere - dg.ang_thr = theta - dg.qa_thr = args.sf_threshold - - # Heuristic to find out if the input are peaks or fodf - # fodf are always around 0.15 and peaks around 0.75 - if non_first_val_count / non_zeros_count > 0.5: - logging.info('Input detected as peaks.') - nb_peaks = odf_data.shape[-1] // 3 - slices = np.arange(0, 15+1, 3) - peak_values = np.zeros(odf_shape_3d+(nb_peaks,)) - peak_indices = np.zeros(odf_shape_3d+(nb_peaks,)) - - for idx in np.argwhere(np.sum(odf_data, axis=-1)): - idx = tuple(idx) - for i in range(nb_peaks): - peak_values[idx][i] = np.linalg.norm( - odf_data[idx][slices[i]:slices[i+1]], axis=-1) - peak_indices[idx][i] = sphere.find_closest( - odf_data[idx][slices[i]:slices[i+1]]) - - dg.peak_dirs = odf_data - else: - logging.info('Input detected as fodf.') - npeaks = 5 - peak_dirs = np.zeros((odf_shape_3d + (npeaks, 3))) - peak_values = np.zeros((odf_shape_3d + (npeaks, ))) - peak_indices = np.full((odf_shape_3d + (npeaks, )), -1, - dtype='int') - b_matrix = get_b_matrix( - find_order_from_nb_coeff(odf_data), sphere, args.sh_basis) - - for idx in np.argwhere(np.sum(odf_data, axis=-1)): - idx = tuple(idx) - directions, values, indices = get_maximas(odf_data[idx], - sphere, b_matrix, - args.sf_threshold, 0) - if values.shape[0] != 0: - n = min(npeaks, values.shape[0]) - peak_dirs[idx][:n] = directions[:n] - peak_values[idx][:n] = values[:n] - peak_indices[idx][:n] = indices[:n] - - dg.peak_dirs = peak_dirs - - dg.peak_values = peak_values - dg.peak_indices = peak_indices - - return dg - - -def main(): - parser = _build_arg_parser() - args = parser.parse_args() - - if args.verbose: - logging.getLogger().setLevel(logging.DEBUG) - - assert_inputs_exist(parser, [args.in_odf, args.in_seed, args.in_mask]) - assert_outputs_exist(parser, args, args.out_tractogram) - - if not nib.streamlines.is_supported(args.out_tractogram): - parser.error('Invalid output streamline file format (must be trk or ' + - 'tck): {0}'.format(args.out_tractogram)) - - verify_streamline_length_options(parser, args) - verify_compression_th(args.compress) - verify_seed_options(parser, args) - - mask_img = nib.load(args.in_mask) - mask_data = get_data_as_mask(mask_img, dtype=bool) - - # Make sure the data is isotropic. Else, the strategy used - # when providing information to dipy (i.e. working as if in voxel space) - # will not yield correct results. - odf_sh_img = nib.load(args.in_odf) - if not np.allclose(np.mean(odf_sh_img.header.get_zooms()[:3]), - odf_sh_img.header.get_zooms()[0], atol=1e-03): - parser.error( - 'ODF SH file is not isotropic. Tracking cannot be ran robustly.') - - if args.npv: - nb_seeds = args.npv - seed_per_vox = True - elif args.nt: - nb_seeds = args.nt - seed_per_vox = False - else: - nb_seeds = 1 - seed_per_vox = True - - voxel_size = odf_sh_img.header.get_zooms()[0] - vox_step_size = args.step_size / voxel_size - seed_img = nib.load(args.in_seed) - - if np.count_nonzero(seed_img.get_fdata(dtype=np.float32)) == 0: - raise IOError('The image {} is empty. ' - 'It can\'t be loaded as ' - 'seeding mask.'.format(args.in_seed)) - - # Note. Seeds are in voxel world, center origin. - # (See the examples in random_seeds_from_mask). - seeds = track_utils.random_seeds_from_mask( - seed_img.get_fdata(dtype=np.float32), - np.eye(4), - seeds_count=nb_seeds, - seed_count_per_voxel=seed_per_vox, - random_seed=args.seed) - - # Tracking is performed in voxel space - max_steps = int(args.max_length / args.step_size) + 1 - streamlines_generator = LocalTracking( - _get_direction_getter(args), - BinaryStoppingCriterion(mask_data), - seeds, np.eye(4), - step_size=vox_step_size, max_cross=1, - maxlen=max_steps, - fixedstep=True, return_all=True, - random_seed=args.seed, - save_seeds=args.save_seeds) - - scaled_min_length = args.min_length / voxel_size - scaled_max_length = args.max_length / voxel_size - - if args.save_seeds: - filtered_streamlines, seeds = \ - zip(*((s, p) for s, p in streamlines_generator - if scaled_min_length <= length(s) <= scaled_max_length)) - data_per_streamlines = {'seeds': lambda: seeds} - else: - filtered_streamlines = \ - (s for s in streamlines_generator - if scaled_min_length <= length(s) <= scaled_max_length) - data_per_streamlines = {} - - if args.compress: - # Compressing. Threshold is in mm, but we are working in voxel space. - # Equivalent of sft.to_voxmm: streamline *= voxres - # Equivalent of sft.to_vox: streamline /= voxres - voxres = np.asarray(odf_sh_img.header.get_zooms()[0:3]) - filtered_streamlines = ( - compress_streamlines(s * voxres, - args.compress) / voxres - for s in filtered_streamlines) - - tractogram = LazyTractogram(lambda: filtered_streamlines, - data_per_streamlines, - affine_to_rasmm=seed_img.affine) - - filetype = nib.streamlines.detect_format(args.out_tractogram) - reference = get_reference_info(seed_img) - header = create_tractogram_header(filetype, *reference) - - # Use generator to save the streamlines on-the-fly - nib.streamlines.save(tractogram, args.out_tractogram, header=header) - - -if __name__ == '__main__': - main() From d275991196fe5fc23a3ac8d7a4a7b8b83622b467 Mon Sep 17 00:00:00 2001 From: EliseCos Date: Thu, 27 Jul 2023 15:25:18 -0400 Subject: [PATCH 07/10] rm DS_Store --- .DS_Store | Bin 10244 -> 0 bytes data/.DS_Store | Bin 6148 -> 0 bytes scripts/.DS_Store | Bin 6148 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 data/.DS_Store delete mode 100644 scripts/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index b49a362b752ae81095fad2b14af1c39c6d5e54d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMZ)_Ar6rZ;(bk;6(Te?#I^$x2P^_2eOXcfb?SFk{_&}(Ta$gy|3!iMecvAcH# zDyE{5L?nJQ2!1g}jfwwa5b%?U9}LkCCeWBbq5=J8G%+Shq9*!gXRo2x@`V^7x|8g@ znK$#^-uun(&E3oqLZB`Ee}2a7 zP!S>!A`l`FA`l`FB5)@lfZy4y&`K`DIz%8uAVgpa0k%Ix@nJF%$O$g}tph9n2!OI2 z)qcUY%o-@8flLH)f=e910^AfOH-+Gc0o)w*(O_O8kP}>Ta{|HP1A;e0a6$q9?dU)1 zPbZMzGOR-cLIh?az|y9iXhbC*QExoIXL6?DdQDAVgHTpJXKn?ppq2E=)INJG<*8oY z?NXhctT$lWW~SIyGusV)EG^e2ZOc;)OLu$&L(_4}t|7zH?6EF8Z)vV?o8kjhq+(jG z8y|0tuZ~6AI$DmzqT}tYZP;#aJ90#%O2ev0`_uc)QOkajhXBDgK<1T%bo|D63Mt1j zZEG*;*!;P~C0Sw+ljO*u+Z}65TYD@TkH=Z89W6~5Yy4JXofcC`ycK@D4n~~A)pc)s z#4WhG@p!8radXG5u5L+GrdvqzJEyW0Mb2I+a#p;nQktg>3~nD9meO)f0m<2y^9=^d+gB}~3F*H2l+K!j>oedl4pU;x>uHLVsQ=_1Fqia_N@%{M=moC5WfmLlCk9BR> z+&5VzSJy14RiqJ256d&2GIVEf%+S1jJ5)ETTbg0*9V!^EkumiFOC8m#Ax1^ts&0{@ z4Cgb(fxO`zk{c+UtdXm$q64C*HCIcG%Kf6O z(g7DE<1S*-!=mhp1N$+DxoNZ1N@YzPG}Vl5a#dVvr}AcTsKCMH%35hH6^FC-=qLu` za@{(mlgbz9Zua6{)%E&vx`pp%fhX$~We3xDYMQPE5hy*%CMsW~Bkn%c(fh`5W8sc^ zlqV?l7ZLT$(|XPD?5V+iHYgib!N5HW*Nbmmv>|cqXMf*lNUZcFY2bnoAJB$G6Yq=o zt7I8zA>E{x>>&;rCnv~B@;W&~&XRNFbMh6rLave@$S>qN`JMbh{)9O&A7rS88dw5L zp&lX-gVhj+HIRf}*aCg96$W89q(OxY?1da002e$s49~&y@B$ozm*FJ53a8)=co*J- z58y-i6fVF;xCE2%4SWk%;Trr1zrt^DT@ZyDVS!L9Gzu$)X5kSbDf9^2_(vCtJLE_) zv_RjFa%K(%_qM|6*>fne;qji0o9^Hox;#I~n!6W9St_kro0#Gpr)ZItH?rL)__Va} z3GS1il$>>o7B5-4Oo|L*2IvQGmXLA#uZE?Km=PFfaOCsLXC(>lA*2}>pVPm%fy za*13f*T_#u>c5~IM5u%1&)2E-~_yals*Ng;Wc;@-h#K`9ry^&z*#s4=iw9h48BBaUxx2Wh}%1zxbXc< z;+A~jO*aU8Ap#)+Ap#)+Ap#)+vmj8$by0Tzzy9X`|IcC>szL-p1pX@sKzVnny9=W! z9vMpmV|VRQeD>hO3Y#~POKf5J*Z&L% Y&;RTubn0dh@6f{YKff0H-<<#d23AQNy8r+H diff --git a/data/.DS_Store b/data/.DS_Store deleted file mode 100644 index af988df30fd930f1ed1f81593f8983464eefbf4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKPfNov6i?iA9Yg3rVaI^ifzwTycqw(>JlUxSmD$pv#oCOuvxhP0S-+5<#Lwe< zNeT{o7IE)E@_T=i<_FCm#u#_!;Q?bdW6Xkv$Wf^fbXSHpOfn+JG16%e%K)s8U}|E2 z9q`+0?1EjfQILQC{y0jrZugUK)asjC4Xa_btb6ZC=3eG!^VIccw`h%|jDu45gX?IL zkL{f^nPh&HOlGPe3MY_qcM~O{%w0K8!c^6II$$-e=Gbm87QN%6j_98pE<0i|==DJ# z^q0$~wY#@}dO3cMUlRGI>Eyt+l5K+}yn|v^^Xko#SSF9)DYMHgLSldzAO?tm^=81F z3s!5rX`s~;1H?cD1Gqm3Xo!x%LZjL`pu_7k#_NbEpyOKtQ5bX#78)S}!gVR2F6HKl z!F4(Kg~@Xa78-Rq<7#FY$IM(lUbvba{6eKO?r5Z*7$62#8K`N~#`FIiewoTg{%Q$X z!~iky&luqKp*M74QRZy@u{=C$1+)ifD418E0s{KVB>)WEN7^c=;{tWaa|{+5aTN5c QazMHWC_<i_@% diff --git a/scripts/.DS_Store b/scripts/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Fri, 28 Jul 2023 10:29:31 -0400 Subject: [PATCH 08/10] Change the subdivide sphere definition --- scripts/scil_compute_local_tracking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/scil_compute_local_tracking.py b/scripts/scil_compute_local_tracking.py index d82d09573..fa281d7a0 100755 --- a/scripts/scil_compute_local_tracking.py +++ b/scripts/scil_compute_local_tracking.py @@ -63,9 +63,9 @@ def _build_arg_parser(): choices=['det', 'prob', 'eudx'], help='Algorithm to use. [%(default)s]') add_sphere_arg(track_g, symmetric_only=True) - track_g.add_argument('--sub_sphere', metavar='SPHERE_DIVISION', + track_g.add_argument('--sub_sphere', metavar='s', type=int, default=0, - help='Multiply the number of directions in the sphere. ' + help='Subdivides each face of the sphere into 4^s new faces.' '[%(default)s]') add_seeding_options(p) out_g = add_out_options(p) From 0639811c754b57878047562042ff423b50e39d95 Mon Sep 17 00:00:00 2001 From: EliseCos Date: Fri, 28 Jul 2023 10:36:30 -0400 Subject: [PATCH 09/10] Add space subdivide sphere argument --- scripts/scil_compute_local_tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_compute_local_tracking.py b/scripts/scil_compute_local_tracking.py index fa281d7a0..2d8d5215d 100755 --- a/scripts/scil_compute_local_tracking.py +++ b/scripts/scil_compute_local_tracking.py @@ -65,7 +65,7 @@ def _build_arg_parser(): add_sphere_arg(track_g, symmetric_only=True) track_g.add_argument('--sub_sphere', metavar='s', type=int, default=0, - help='Subdivides each face of the sphere into 4^s new faces.' + help='Subdivides each face of the sphere into 4^s new faces. ' '[%(default)s]') add_seeding_options(p) out_g = add_out_options(p) From be3577972b2bea91ca65c45b97229fdcd45898e0 Mon Sep 17 00:00:00 2001 From: EliseCos <140726377+EliseCos@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:11:05 +0200 Subject: [PATCH 10/10] Update scil_compute_local_tracking.py rm metavar --- scripts/scil_compute_local_tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_compute_local_tracking.py b/scripts/scil_compute_local_tracking.py index 2d8d5215d..1c1ee65cc 100755 --- a/scripts/scil_compute_local_tracking.py +++ b/scripts/scil_compute_local_tracking.py @@ -63,7 +63,7 @@ def _build_arg_parser(): choices=['det', 'prob', 'eudx'], help='Algorithm to use. [%(default)s]') add_sphere_arg(track_g, symmetric_only=True) - track_g.add_argument('--sub_sphere', metavar='s', + track_g.add_argument('--sub_sphere', type=int, default=0, help='Subdivides each face of the sphere into 4^s new faces. ' '[%(default)s]')