🚀 Get started with with Tractography.jl

This tutorial will introduce you to the functionalities for computing streamlines.

Basic use

In this example, we will sample Nmc streamlines from a Tractography Markov Chain (TMC).

using Tractography
const TG = Tractography

model = TMC(Δt = 0.125f0,
            odfdata = ODFData((@__DIR__) * "/../../examples/fod-FC.nii.gz"),
            )
Nmc = 10
seeds = rand(Float32, 6, Nmc)
alg = Probabilistic()
streamlines, tract_length = sample(model, alg, seeds);
size(streamlines)
(3, 1000, 10)

Step 1: Define a TMC

We define a Tractography Markov Chain (TMC) model as follows:

model = TMC(Δt = 0.125f0,
            odfdata = ODFData((@__DIR__) * "/../../examples/fod-FC.nii.gz"),
            )
TMC with elype Float32
 ├─ Δt = 0.125
 ├─ minimal probability = 0.0
 ├─ cone                = Cone{Float32}(90.0f0)
 ├─ mollifier           = default_mollifier
 ├─ evaluation of SH    = Tractography.PreComputeAllODF()
 └─ data : ⋯

Step 2: Define the seeds

Nmc = 10 # Monte Carlo sample
seeds = rand(Float32, 6, Nmc)
6×10 Matrix{Float32}:
 0.699676   0.897379    0.354413    …  0.799349  0.7909    0.135136
 0.109339   0.0626113   0.00133878     0.226532  0.864209  0.845987
 0.0925213  0.205087    0.0902188      0.611725  0.890164  0.0928188
 0.68239    0.655883    0.746452       0.161025  0.812333  0.747428
 0.0804574  0.166266    0.877734       0.572459  0.971108  0.625676
 0.0150239  0.00817198  0.390573    …  0.896385  0.515138  0.379825

Step 3: Chose a sample algorithm

alg = Probabilistic()
Probabilistic()

Step 4: Sample the streamlines

streamlines, tract_length = sample(model, alg, seeds);
(Float32[0.6996757 0.744685 … 1.3607349 1.3607349; 0.10933852 0.020569026 … -1.5032667 -1.5032667; 0.09252125 0.16814625 … 0.3643962 0.3643962;;; 0.897379 0.9978078 … 0.4683959 0.4683959; 0.06261134 -0.011718966 … -1.5101061 -1.5101061; 0.20508665 0.20883664 … 0.8844618 0.8844618;;; 0.3544129 0.26243073 … -0.15772633 -0.15772633; 0.0013387799 0.08358399 … -1.5767674 -1.5767674; 0.09021878 0.07021877 … 1.931469 1.931469;;; 0.8991796 0.9157228 … -1.5125067 -1.5125067; 0.3875895 0.42294145 … -0.3598523 -0.3598523; 0.9110481 1.0297982 … 3.6485493 3.6485493;;; 0.16493052 0.26410875 … -0.43646148 -0.43646148; 0.55720156 0.4913596 … -1.5459987 -1.5459987; 0.7578414 0.7959664 … 1.5428407 1.5428407;;; 0.840282 0.8445866 … 1.4200428 1.4200428; 0.07813364 0.17611435 … 1.6132761 1.6132761; 0.32908052 0.2515805 … -1.5365449 -1.5365449;;; 0.6707732 0.69420904 … -0.2277061 -0.2277061; 0.70351064 0.7184186 … 1.2233584 1.2233584; 0.5126335 0.6345085 … -1.5086166 -1.5086166;;; 0.7993491 0.84934914 … -1.5522764 -1.5522764; 0.22653162 0.32334813 … 4.195594 4.195594; 0.61172456 0.5504746 … -0.102025315 -0.102025315;;; 0.7909003 0.82665145 … -1.5531696 -1.5531696; 0.8642086 0.9831951 … 8.828414 8.828414; 0.89016426 0.87641424 … 2.740788 2.740788;;; 0.13513577 0.15034999 … -0.71147585 -0.71147585; 0.84598744 0.93072605 … -1.5829475 -1.5829475; 0.0928188 0.002193801 … 1.2828178 1.2828178], UInt32[0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000])

Optimal use

It is often better to cache some data when computing batches of streamlines. This would be done as follows

model = TMC(Δt = 0.125f0,
            odfdata = ODFData((@__DIR__) * "/../../examples/fod-FC.nii.gz"),
            )
Nmc = 10
seeds = rand(Float32, 6, Nmc)
streamlines = zeros(Float32, 6, 20, Nmc)
tract_length = zeros(UInt32, Nmc)
alg = Probabilistic()
cache = TG.init(model, alg)
# this can be called repeatedly after updating seeds for example
TG.sample!(streamlines, tract_length, model, cache, alg, seeds);
size(streamlines)
(6, 20, 10)