Hello,
Taking the CST fibre bundle as an example: mrthreshold tract_stats/fd/CST/fwe_1mpvalue.mif -abs 0.95 tract_stats/fd/CST/sig_fixels_05.mif. I have already obtained the significant-result .mif file, but when I try to use this significant result as a mask on the .tck file, it cannot be applied. How can I visualise the significant results as shown in the figure?
When I overlay two fibre bundles, the overlapping regions appear white. Do I need to adjust any parameters for this?
Many thanks in advance for your help
Yuhang Yang
rsmith
September 23, 2025, 8:43am
2
Welcome Yuhang!
When you provide a fixel data file as an inclusion region to tckedit, it is not interpreting that image as representing a binary mask selecting a subset of fixels. It is interpreting that file literally as an image that possesses a spatial embedding, where that embedding is as a ~500,000 x 1 x 1 stack of voxels.
Ideally tckedit would detect the fact that the image you are providing is a fixel data file, ascribing each streamline to the set of fixels it intersects and then checking to see if any of those fixels are present in your mask. I had made some progress toward centralising the handling of fixel datasets deeper in the MRtrix3 code base, thereby facilitating handling of fixel data across a wider suite of commands:
fixel_dataset_handling ← fixel_dataset_class_sift
opened 08:17AM - 18 Jun 23 UTC
This PR is part of what the set of changes aggregated in #2644 have been working… towards.
At time of initial posting the changes apply only to `tcksift` and `tcksift2`, but that list will increase over time.
Rather than receiving as input an FOD image and performing FOD segmentation at commencement of the command, they will instead take as input a fixel data file encoding fibre density, and automatically load all other information relevant to the fixel dataset.
-----
It has taken quite some time since the fixel directory format superseded the initial sparse fixel file format for me to get around to addressing how it conflicts with both pre-existing handling of, and intentions for future developments involving, fixel data.
- In FBA, one needs full user flexibility over the number and names of files stored as well as how to interpret them, whereas in quantitative fixel-wise models there is a known set of parameters and corresponding interpretations.
- If a given command loops over the data for each fixel just once, the overhead of image indexing / invoking get-set functions from function pointers / data being spread across multiple images is fine; but for complex computations, one wants native access & RAM contiguity for all data in each fixel.
Previously, these preferable attributes were achieved using the `DWI::Fixel_map<>` class and derivatives.
This predated the fixel directory format, the legacy fixel file format, and even the term "fixel".
But it:
- Was populated using the results of FOD segmentation, such that one pipeline could involve segmenting one FOD image multiple times.
- Presented an unnecessary clash in terms of fixel data handling.
- Precluded certain desired future features.
The primary goal of this PR is to supersede the `DWI::Fixel_map<>` class with new `MR::Fixel::Dataset`.
This class is more consistent with the philosophy behind the fixel directory format.
However it also provides the relevant quantitative information per fixel in a native, memory-contiguous manner.
Further, it maintains utilisation of the dixel mask information in assigning streamlines to fixels; this was a key advantage of keeping the relevant commands utilising FOD segmentation rather than the reduced resolution of fixel mean direction information only.
-----
PR is in a highly preliminary state; intend to branch other developments off of here onto a private repository.
Below is list of items that should largely be addressed before merging to base branch of #2644.
- [ ] `afdconnectivity`: Take fixel FD file as input
- [ ] `fixelconnectivity`: Make use of `TrackMapperBase`'s new `FixelMappingPlugin`
- [ ] `tckgen`: Have dynamic seeding take fixel FD file as input
- [ ] `tckmap`: Integrate fixel dataset target destination
- Correspondingly remove `tck2fixel` entirely
- [ ] Finish reworking of SIFT model weights
- [x] Rename "processing mask" to "model weights" throughout code / interface / documentation
- [x] Permit user to provide either voxel-wise or fixel-wise image data
- [x] No longer store voxel-wise image as member variable
- [ ] Add output function(s) (fixel-wise and voxel-wise)
- [ ] Rename "total variation" variance, as it is in fact not "total variation" at all
- [ ] Change MR::Fixel helper functions to no longer be `FORCE_INLINE`
- [ ] Modify constructor for `SIFT::ModelBase::FixelBase` class and derivatives to grab `ConstRowXpr`s for fixel direction and dixelmask
- [ ] Implement looping constructs for `SIFT::Model` class and derivatives
- [ ] Just as `MR::Fixel::IndexImage` provides a looping construct that yields an iterable list of integer indices, this class should be able to do the same for an iterable list of the relevant Fixel class
- [ ] In addition to looping over the set of fixels within a voxel, it should also be possible to loop over all fixels in the model
(possibly automatically skipping over any fixels for which the model weight is zero)
- [ ] Define separate mutable and immutable Fixel classes, enabling looping over fixels within member functions declared const
(I spent ages trying to get this working without success...)
- [x] Implement iterator construct for SIFT::TrackIndexRange
- [ ] Decide whether to essentially remove all manual utilisations of `Image<index_type>` as a fixel index image in favour of `MR::Fixel::IndexImage`
In many circumstances it will not be desirable to construct a full `MR::Fixel::Dataset` instance.
However rather than MR::Fixel::Loop in its current form, it may be preferable to instead modify that class to be initialised exclusively from an MR::Fixel::IndexImage.
- [x] Move the functor responsible for resampling the ACT 5TT image out of the SIFT namespace and into the ACT namespace.
- [ ] Regarding the exclusion of fixels:
- [ ] Change default behaviour to exclude untracked fixels rather than retain them, even for SIFT1 (this includes renaming the command-line option)
- [ ] Add paragraph to Description explaining impact of fixel exclusion being done on a per-tractogram basis
- [ ] For SIFT2, better explain (and disambiguate in code) distinction between fixel being excluded from model and being excluded from optimisation
- [ ] Speed up implementation mapping streamlines to fixels
Currently involves boolean check for presence of dixel masks on a per-streamline-voxel-intersection basis; would prefer to reduce the number of unnecessary branch executions
Optionals:
- [ ] For `afdconnectivity`, `tcksift` and `tcksift2`: Allow user-specified input to be either an FOD image or a fixel FD file.
This would require the ability to populate `Fixel::Dataset` from the contents of `DWI::FMLS::FOD_lobes`. This is conceptually not too difficult, and indeed the existing population of `DWI::Fixel_map<>` does something very similar. The catch is that the total number of fixels is not known a priori, and `Eigen::Array<>` is very expensive to do repeated `.conservativeResize()` calls (as we found previously with `amp2response`: #1406). So what would be necessary is either:
- A buffer class that would store the incoming fixel-wise data in something more friendly like `std::vector<>`'s and populate the `Eigen::Array<>`'s upon competion of segmentation; or:
- A wrapper class that would do a more intelligent dynamic allocation of `Fixel::Dataset` members, with a `.resize()` to fit just the populated data at completion of segmentation.
- In addition, would likely need to change the mechanism for construction of the IndexImage class. Currently the constructor receives a std::string, meaning the class is constructed from image only. If permitting creation of an image from scratch, would likely want to have static IndexImage::open() and IndexImage::scratch() functions (maybe an IndexImage::create() if wanting to homologate fod2fixel & others).
- [ ] Re-introduce capacity for "null lobes"
This is a capability that exists within the current SIFT(2) implementation, is disabled by default, but I don't quite know what I want to do about it going forward.
In its pre-existing form, this creates one additional "fixel" per voxel, that "claims" all directions not ascribed to any segmented fixel, and has an FD of zero. In this way, streamlines for which the tangent does not lie within the subset of the sphere corresponding to any fixel are assigned to this "extra" fixel, and always contribute to an excess in reconstructed density there. It may be possible to do something a bit more clever, for instance by comparing the total AFD of all retained fixels to the FOD l=0 term and attributing the difference between them to all directions not attributed to any fixel. But there's still uncertainty around how such data should be used in a downstream optimisation, rather than just assigning all streamlines to the nearest fixel (which is the current default behaviour).
There's also the question of whether this should be handled at processing time, or whether fod2fixel could include such data in the fixel output directory, with the corresponding dixel mask but with a non-finite direction. All downstream applications would need to be tested for robustness against the latter case.
- [ ] Improve handling of non-WM tissue content
A known issue with SIFT compared to COMMIT is the model fitting in areas of partial volume between GM and WM.
With COMMIT, a separate forward model component can be provided for GM, and in partial volume voxels the optimiser can choose how much of the DWI signal to attribute to streamlines vs. GM.
With SIFT, there is a kind of baked-in presumption of correspondence between the proportion of the voxel traversed by streamlines (which itself is likely influenced by ACT), and the proportion of the DWI signal attributed to WM vs. GM by MSMT (and that's not further accounting for which fixels may vs. may not have been successfully tracked).
This can introduce large model errors at partial volume voxels, which can undesirably drive the weights of individual streamlines very high.
While I have various tricks such as downregulation of such fixels in the model and regularisation of streamline weights, it remains a weakness.
What I would prefer is something that better takes into account the presence of non-WM tissue, whether from MSMT or from a 5TT image. While I haven't figured out yet *exactly* how I would want this to work, I think it should be possible to do something to stabilise the fit.
dev ← fixel_dataset_handling
opened 06:13AM - 31 May 23 UTC
This PR is intended to show the current state of a particular branch of developm… ent regarding the handling of fixel datasets. I have taken some previously existing PRs in this domain, modified the PRs to target new branch `fixel_dataset_handling`, and merged them. This will allow me to properly resolve the conflicts arising from those different developments and continue with what I'm working on. Also the integration of tests and test data will need to happen in one go due to the aforementioned conflicts.
Previous PRs:
- #2621 (superseded)
- #2625
- #2626
- #2639
Longer term the goal here is to have a more centralised handling of fixel datasets, particularly in cases where one is dealing with single-subject rather than FBA cohort data.
TODO list (outside of the developments I'm working on):
- [ ] Address slowdown reported in #2626 [here](https://github.com/MRtrix3/mrtrix3/pull/2626#issuecomment-1564716852)
- [ ] Confirm that people are happy with code placement & class names
- [ ] Add tests and test data
This is however the sort of thing that has become increasingly difficult to commit resources to, as it’s not a publishable capability and not tied to a specific research collaboration. The moment I have a minimum working example of one software enhancement, I have some other obligation that requires my attention; hence why the software has around 100 Pull Requests listed. I hope to write more on this at some point in the future.
In terms of what you can achieve with the existing software capabilities, there’s a range of possibilities. Most involve deriving a mask of those voxels with at least one significant fixel, and selecting streamlines based on their intersection with that. It may well involve manual placement of exclusion ROIs in order to remove those streamlines that pass though one of the non-significant fixels in those voxels.
Regards
Rob
Hi Robert
Thank you for such a detailed answer, it cleared up a lot of my questions. I will carefully review the code you shared. Thank you very much again for your reply!
Regards
Yuhang Yang