def main(): parser = _build_arg_parser() args = parser.parse_args() if args.verbose: logging.basicConfig(level=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) 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: filtered_streamlines = ( compress_streamlines(s, args.compress) 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)
def main(): t_init = perf_counter() parser = _build_arg_parser() args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.INFO) assert_inputs_exist(parser, [args.in_odf, args.in_mask, args.in_seed]) assert_outputs_exist(parser, args, args.out_tractogram) if args.compress is not None: verify_compression_th(args.compress) odf_sh_img = nib.load(args.in_odf) mask = get_data_as_mask(nib.load(args.in_mask)) seed_mask = get_data_as_mask(nib.load(args.in_seed)) odf_sh = odf_sh_img.get_fdata(dtype=np.float32) t0 = perf_counter() 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 # Seeds are returned with origin `center`. # However, GPUTracker expects origin to be `corner`. # Therefore, we need to shift the seed positions by half voxel. seeds = random_seeds_from_mask(seed_mask, np.eye(4), seeds_count=nb_seeds, seed_count_per_voxel=seed_per_vox, random_seed=args.rng_seed) + 0.5 logging.info('Generated {0} seed positions in {1:.2f}s.'.format( len(seeds), perf_counter() - t0)) voxel_size = odf_sh_img.header.get_zooms()[0] vox_step_size = args.step_size / voxel_size vox_max_length = args.max_length / voxel_size vox_min_length = args.min_length / voxel_size min_strl_len = int(vox_min_length / vox_step_size) + 1 max_strl_len = int(vox_max_length / vox_step_size) + 1 # initialize tracking tracker = GPUTacker(odf_sh, mask, seeds, vox_step_size, min_strl_len, max_strl_len, args.theta, args.sh_basis, args.batch_size, args.forward_only, args.rng_seed) # wrapper for tracker.track() yielding one TractogramItem per # streamline for use with the LazyTractogram. def tracks_generator_wrapper(): for strl, seed in tracker.track(): # seed must be saved in voxel space, with origin `center`. dps = {'seeds': seed - 0.5} if args.save_seeds else {} # TODO: Investigate why the streamline must NOT be shifted to # origin `corner` for LazyTractogram. strl *= voxel_size # in mm. if args.compress: strl = compress_streamlines(strl, args.compress) yield TractogramItem(strl, dps, {}) # instantiate tractogram tractogram = LazyTractogram.from_data_func(tracks_generator_wrapper) tractogram.affine_to_rasmm = odf_sh_img.affine filetype = nib.streamlines.detect_format(args.out_tractogram) reference = get_reference_info(odf_sh_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) logging.info('Saved tractogram to {0}.'.format(args.out_tractogram)) # Total runtime logging.info('Total runtime of {0:.2f}s.'.format(perf_counter() - t_init))
def main(): parser = _build_arg_parser() args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) 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)) inputs = [args.in_odf, args.in_seed, args.in_mask] assert_inputs_exist(parser, inputs) assert_outputs_exist(parser, args, args.out_tractogram) verify_streamline_length_options(parser, args) verify_compression_th(args.compress) verify_seed_options(parser, args) theta = gm.math.radians(get_theta(args.theta, args.algo)) max_nbr_pts = int(args.max_length / args.step_size) min_nbr_pts = int(args.min_length / args.step_size) + 1 max_invalid_dirs = int(math.ceil(args.max_invalid_length / args.step_size)) logging.debug("Loading seeding mask.") seed_img = nib.load(args.in_seed) seed_data = seed_img.get_fdata(caching='unchanged', dtype=float) seed_res = seed_img.header.get_zooms()[:3] seed_generator = SeedGenerator(seed_data, seed_res) if args.npv: # toDo. This will not really produce n seeds per voxel, only true # in average. nbr_seeds = len(seed_generator.seeds) * args.npv elif args.nt: nbr_seeds = args.nt else: # Setting npv = 1. nbr_seeds = len(seed_generator.seeds) if len(seed_generator.seeds) == 0: parser.error( 'Seed mask "{}" does not have any voxel with value > 0.'.format( args.in_seed)) logging.debug("Loading tracking mask.") mask_img = nib.load(args.in_mask) mask_data = mask_img.get_fdata(caching='unchanged', dtype=float) mask_res = mask_img.header.get_zooms()[:3] mask = DataVolume(mask_data, mask_res, args.mask_interp) logging.debug("Loading ODF SH data.") odf_sh_img = nib.load(args.in_odf) odf_sh_data = odf_sh_img.get_fdata(caching='unchanged', dtype=float) odf_sh_res = odf_sh_img.header.get_zooms()[:3] dataset = DataVolume(odf_sh_data, odf_sh_res, args.sh_interp) logging.debug("Instantiating propagator.") propagator = ODFPropagator(dataset, args.step_size, args.rk_order, args.algo, args.sh_basis, args.sf_threshold, args.sf_threshold_init, theta, args.sphere) logging.debug("Instantiating tracker.") tracker = Tracker(propagator, mask, seed_generator, nbr_seeds, min_nbr_pts, max_nbr_pts, max_invalid_dirs, compression_th=args.compress, nbr_processes=args.nbr_processes, save_seeds=args.save_seeds, mmap_mode='r+', rng_seed=args.rng_seed, track_forward_only=args.forward_only, skip=args.skip) start = time.time() logging.debug("Tracking...") streamlines, seeds = tracker.track() str_time = "%.2f" % (time.time() - start) logging.debug("Tracked {} streamlines (out of {} seeds), in {} seconds.\n" "Now saving...".format(len(streamlines), nbr_seeds, str_time)) # save seeds if args.save_seeds is given data_per_streamline = {'seeds': seeds} if args.save_seeds else {} # Silencing SFT's logger if our logging is in DEBUG mode, because it # typically produces a lot of outputs! set_sft_logger_level('WARNING') # Compared with scil_compute_local_tracking, using sft rather than # LazyTractogram to deal with space. # Contrary to scilpy or dipy, where space after tracking is vox, here # space after tracking is voxmm. # Smallest possible streamline coordinate is (0,0,0), equivalent of # corner origin (TrackVis) sft = StatefulTractogram(streamlines, mask_img, Space.VOXMM, Origin.TRACKVIS, data_per_streamline=data_per_streamline) save_tractogram(sft, args.out_tractogram)
def main(): parser = build_argparser() args = parser.parse_args() logging.basicConfig(level=args.logging.upper()) # ----- Checks 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)) assert_inputs_exist(parser, args.hdf5_file) assert_outputs_exist(parser, args, args.out_tractogram) verify_streamline_length_options(parser, args) verify_compression_th(args.compress) verify_seed_options(parser, args) # ----- Prepare values max_nbr_pts = int(args.max_length / args.step_size) min_nbr_pts = int(args.min_length / args.step_size) + 1 max_invalid_dirs = int(math.ceil(args.max_invalid_len / args.step_size)) # r+ is necessary for interpolation function in cython who need read/write # rights mmap_mode = None if args.set_mmap_to_none else 'r+' device = torch.device('cpu') if args.use_gpu: if args.nbr_processes > 1: logging.warning("Number of processes was set to {} but you " "are using GPU. Parameter ignored.".format( args.nbr_processes)) if torch.cuda.is_available(): device = torch.device('cuda') hdf_handle = h5py.File(args.hdf5_file, 'r') tracker, ref = prepare_tracker(parser, args, hdf_handle, device, min_nbr_pts, max_nbr_pts, max_invalid_dirs, mmap_mode) # ----- Track with Timer("\nTracking...", newline=True, color='blue'): streamlines, seeds = tracker.track() logging.debug( "Tracked {} streamlines (out of {} seeds). Now saving...".format( len(streamlines), tracker.nbr_seeds)) # save seeds if args.save_seeds is given data_per_streamline = {'seed': lambda: seeds} if args.save_seeds else {} # Silencing SFT's logger if our logging is in DEBUG mode, because it # typically produces a lot of outputs! set_sft_logger_level('WARNING') sft = StatefulTractogram(streamlines, ref, Space.VOXMM, data_per_streamline=data_per_streamline) save_tractogram(sft, args.out_tractogram, bbox_valid_check=False)