Precise quantification of streamlines lengths#1507
Conversation
|
Some more musings on the forum, with potentially more to change in the code. |
|
Looking at this, I'm reminded that we might want to change the default setting for the max length. Currently, it's set to 100× voxel size, which is really a bit useless. Might be best reserved for a separate pull request - but how do people feel about setting it to the largest image dimension instead (i.e. max FoV)? |
|
Agreed the default is a bit useless. I don't think max FoV will be enough though: if you cropped your FoV to just the brain mask (which many people often do, to deal with large datasets / high resolutions), this doesn't allow a streamline to run "back and forth" through the brain anymore. The default should, in my opinion, just be something that is realistically not reached, but is there anyway to avoid streamlines looping infinitely. So going by my earlier reasoning/argument ... what about 2x max FoV...? |
Actually seems fair enough to me... 👍 |
|
...and just to be safe: max(FoV) could be defined here as the maximal length that fits (as a straight line) in the FoV; i.e. the length of the diagonal connecting opposite corners. |
I think I might have proposed this last time around? Was still concerned about the influence of FoV cropping though. We've never figured out a better heuristic so it really needs its own issue listing. |
Conflicts: src/dwi/tractography/streamline.h
|
Exposing my inner monologue for a moment: What I'm working on as I write this is, for a given step size / angle / downsampling ratio, what is the maximum number of vertices that a post-downsampling streamline could plausibly have and still be shorter than the minimum length; that way, if a streamline has more vertices than this, the expense of computing the precise length can be skipped. (While iFOD2 is only 1% slower with these changes, the proportional computational hit is likely to be greater for those algorithms that generate streamlines faster) This made me realise that this kind of complexity occurs the other way also: if a streamline is terminated due to reaching the maximum number of vertices (calculated based on the step size), then it's possible that after downsampling, that streamline would then be shorter than the maximum length, in which case it could potentially have propagated further. Therefore: should streamlines be permitted to propagate beyond the maximum number of vertices calculated based on step size alone, and only have their length compared against the maximum length criterion after downsampling has taken place? |
- Change the default step size for first-order methods from (0.1 x voxel) to (0.5 x voxel) when RK4 is activated. - All streamlines must conform to the minimum and maximum length restrictions AFTER down-sampling; likewise, it's not omputationally efficient to compute precisely the length of every generated streamline. Therefore, introduce two sets of vertex count limits: One pair that is utilised before downsampling to detect outright rejection of short tracks and cessation of propagation of long tracks, and another to detect when it is necessary to calculate a precise streamline length in order to compare against the floating-point length criteria. These are calculated based on the minimum radius of curvature and downsampling ratio (among other things), as downsampling reduces the lengths of streamlines. Additionally, if a streamline is longer than the maximum length after downsampling (which is possible given the precise length of the streamline is not known during streamlines propagation, and hence tracking is permitted to extend beyond the maximum length), and ACT is not being used, truncate the streamline to be precisely the maximum length. Also note that even if downsampling is not being used, the precise streamline length may nevertheless need to be verified if ACT cropping at the GM-WM interface is enabled. - Default angle per step for first-order methods changed to be that which yields a minimum radius of curvature of one voxel, rather than (90deg x step_size / voxel_size).
|
Turns out I opened up a can of worms with this one... I'll explain as best I can, and we'll see then what you think might need independent verification / discussion.
😥 |
Revert changes that were made in #1507 with respect to determination of the default maximum angle for the various tracking algorithms. There, this decision was changed from being based on (90deg * step_size / vox()) to being a minimum radius of curvature of one voxel. Additionally, the default step size in the presence of RK4 was changed from 0.1*vox() to 0.5*vox(). This commit reverts these changes, but retains the calculation of minimum radius of curvature necessary for streamline length calculation optimisations.
Resolve divergence between #1630 and #1507. Use a single function Tractography::Shared::set_step_and_angle() that is responsible for setting up both the step size and maximum deviation angle per step. Remove calculation of maximum angle based on radius of curvature, in favour of a fixed angle for each algorithm. Use separate member variables for maximum angles and related quantities between first-order and higher-order integration as was introduced in #1507. Conflicts: src/dwi/tractography/algorithms/fact.h src/dwi/tractography/algorithms/iFOD1.h src/dwi/tractography/algorithms/iFOD2.h src/dwi/tractography/algorithms/nulldist.h src/dwi/tractography/algorithms/sd_stream.h src/dwi/tractography/algorithms/seedtest.h src/dwi/tractography/algorithms/tensor_det.h src/dwi/tractography/tracking/shared.cpp src/dwi/tractography/tracking/shared.h src/dwi/tractography/tracking/tractography.cpp
- Reduces redundancy of code surrounding calculation of streamline tengents. - Moves to using single-precision floating-points to represent streamline tengents based on vertices that are only stored at single-precision. - Remove function templates for Tractography::Streamline::calc_length(), for which the implementations were removed in #1507.
- Reduces redundancy of code surrounding calculation of streamline tengents. - Moves to using single-precision floating-points to represent streamline tengents based on vertices that are only stored at single-precision. - Remove function templates for Tractography::Streamline::calc_length(), for which the implementations were removed in #1507.
As discussed in #1501.
The only time at which it is safe to perform a multiplication between number of vertices and step size in order to derive the streamline length is within the tractography propagation algorithm itself, when a fixed step size is guaranteed. As soon as there is the possibility of an inconsistent step size (input data from a file, various resampling strategies, truncation), this is no longer safe, and so the sum of inter-vertex distances must be calculated.
Couple of points to note:
Whenever
tckgen -act -crop_at_gmwmiis specified, streamline lengths are always re-quantified, based on a fixed step size for all but the first and last segments (those are measured explicitly) and compared against the floating-point minimum length (previously thetckgentest for minimum length was purely based on number of vertices).Downsampling that can occur in
tckgen(and is on by default for iFOD2) affects length quantification. As such I've thrown in an additional test against the tracking minimum length after downsampling has occurred. I measured the performance penalty of this at about 1%.Conceptually this isn't required for iFOD2 under default usage, since in that algorithm it's actually the post-downsampling inter-vertex distance that is controlled, not the "internal" step size within each arc trajectory. But trying to catch this case in order to skip it would be kinda clumsy.
I intentionally designed the histogram feature in
tckstatsto centre the bins at multiples of the step size; therefore floating-point variations in quantified lengths shouldn't be a major issue here.I also tweaked
tckstatsto be a little more explicit about the presence of empty streamlines (0 vertices) vs. zero-length streamlines (1 vertex).I looked briefly into quantification of spline length rather than piecewise length (in the hope it'd be less sensitive to variations in vertex density), but it went straight into the too-hard basket.
Closes #1501.
Closes #1153.