Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Michiel Cottaar
gyral_structure
Commits
9b606f3b
Commit
9b606f3b
authored
May 02, 2020
by
Michiel Cottaar
Browse files
DOC: update tutorial
parent
2aa5e6ae
Changes
2
Hide whitespace changes
Inline
Side-by-side
doc/tutorial.rst
View file @
9b606f3b
...
...
@@ -71,7 +71,7 @@ or to do streamline tractography (:ref:`gs_track <gs_track>`).
Deconstructing gs_fit
---------------------
To become more familiar with the gyral_structure python API we will here take us
step-by-step through the :ref:`gs_fit <gs_fit>` code.
step-by-step through
(a somewhat simplified version of)
the :ref:`gs_fit <gs_fit>` code.
After defining the command line interface we start by importing the libraries:
...
...
@@ -139,43 +139,42 @@ we have to provide those observed dyads as well:
mm_dyads_arr /= np.sqrt((mm_dyads_arr ** 2).sum(-1))[:, None]
aligned = cost.orient.Watson(vol_request, field=mm_dyads_arr)
Note that we fit the field in mm rather than voxel space, so we need to convert the
bvec
s from radiological
Note that we fit the field in mm rather than
scaled
voxel space, so we need to convert the
dyad
s from radiological
voxel space to mm space.
Before defining the cost function on the surface, we need to load the target density distribution.
For each face in the surface, the target
density is the average of its vertices (or a uniform target density of on
e
if no target density is provided).
For each
triangular
face in the surface, the target
number of streamlines is proportional to th
e
size of the wedge covered by that triangle:
.. code-block:: python
surf_mask = nib.load(args.surf_mask).darrays[0].data != 0
white_surf = CorticalMesh.read(args.white)[surf_mask]
target_density = 1.
if args.target_density is not None:
target_density_vertex = nib.load(args.target_density).darrays[0].data[surf_mask]
target_density = white_surf.graph_connection_point().T.dot(target_density_vertex) / 3.
target_density = Cortex([white_surf, CorticalMesh.read(args.pial)[surf_mask]]).wedge_volume()
This
finally
allows us to define the cost function at the surface:
This allows us to define the cost function at the surface:
.. code-block:: python
white_normal = white_surf.normal().T
white_radial = cost.orient.VonMises(white_request, field=white_normal)
white_uniform = cost.dens.TargetInner(white_request, field=white_normal, target_inner=target_density)
white_radial = cost.orient.VonMises(white_request, field=white_normal) / white_request.npos
white_density = cost.dens.TargetInner(white_request, field=white_normal,
target_inner=target_density / white_surf.size_faces()) / white_request.npos
if args.mid_thickness is not None:
mid_normal = CorticalMesh.read(args.mid_thickness)[surf_mask].normal().T
mid_radial = cost.orient.VonMises(mid_request, field=mid_normal)
mid_uniform = cost.dens.TargetInner(mid_request, field=mid_normal, target_inner=target_density)
mid_surf = CorticalMesh.read(args.mid_thickness)[surf_mask]
mid_normal = mid_surf.normal().T
mid_radial = cost.orient.VonMises(mid_request, field=mid_normal) / mid_request.npos
mid_uniform = cost.dens.TargetInner(mid_request, field=mid_normal,
target_inner=target_density / mid_surf.size_faces()) / mid_request.npos
radial = 0.5 * (white_radial + mid_radial)
uniform
= 0.5 * (white_
uniform
+ mid_uniform)
density
= 0.5 * (white_
density
+ mid_uniform)
else:
radial = white_radial
uniform
= white_
uniform
density
= white_
density
If no mid-thickness surface was provided (i.e., args.mid_thickness is None), than
the resulting cost functions are simply instances of :class:`cost.orient.VonMises <gyral_structure.cost.orient.VonMises>`
(to encourage radiality) and :class:`cost.dens.TargetInner <gyral_structure.cost.dens.TargetInner>` (to encourage a
mean
streamline
density crossing the surface of 1
).
(to encourage radiality) and :class:`cost.dens.TargetInner <gyral_structure.cost.dens.TargetInner>` (to encourage a
mean
streamline
termination density of 1 per mm$^3$
).
If a mid-thickness is provided we define the same cost functions for the request
of the mid-thickness surface. These are then combined into a single cost-function
...
...
@@ -192,7 +191,7 @@ the user-provided weights:
.. code-block:: python
no_dyads = args.w
uniform * uniform
+ args.wradial * radial + args.wL2 * L2
no_dyads = args.w
density * density
+ args.wradial * radial + args.wL2 * L2
with_dyads = no_dyads + args.wdyad * aligned
Note that this adding of cost-functions is done before any evaluation of the
...
...
@@ -215,7 +214,7 @@ Now that we have a cost function, we still have to define our basis functions:
masked_pial = CorticalMesh.read(args.pial)[surf_mask]
points_pial = masked_pial.vertices[:, masked_pial.faces].mean(1).T
charge_pial = -
white_request.size() *
target_density
charge_pial = -target_density
charge_max = -np.atleast_1d(charge_pial.sum())
...
...
@@ -223,14 +222,12 @@ Now that we have a cost function, we still have to define our basis functions:
basis.ChargeDistribution(points_pial, 0.1),
basis.ChargeDistribution(mm_max[None, :], 0.1)
])
charge_basis.fix(0, charge_pial)
charge_basis.fix(1, charge_max)
This code block defines the initial vector field estimate. As our cost function expects
a `target_density` streamlines crossing the surface, we can create a rough approximation
of this by distributing uniform charges of -`target_density`
* the surface size
along the pial surface.
of this by distributing uniform charges of -`target_density` along the pial surface.
This basis function is defined by the line `basis.ChargeDistribution(points_pial, 0.1)`
which defines where the charges are (i.e., `points_pial`) and the s
ize
of the charges (i.e., 0.1 mm).
which defines where the charges are (i.e., `points_pial`) and the s
patial extent
of the charges (i.e., 0.1 mm).
Our final basis function `charge_basis` combines this basis function with one
defined by a single charge at the centre of the brain (i.e., the point furthest away from
...
...
gyral_structure/scripts/gs_deform_surface
View file @
9b606f3b
...
...
@@ -10,7 +10,7 @@ parser.add_argument('-n', '--negative', action='store_true',
parser
.
add_argument
(
'--steplength'
,
type
=
float
,
default
=
0.2
,
help
=
'tractography step length (default: 0.2 mm)'
)
parser
.
add_argument
(
'-S'
,
'--nsteps'
,
type
=
int
,
default
=
2000
,
help
=
'maximum number of steps to take per streamline (default:
1
000)'
)
help
=
'maximum number of steps to take per streamline (default:
2
000)'
)
parser
.
add_argument
(
'-ol'
,
'--output_length'
,
help
=
'Outputs streamline lengths to given directory in GIFTI file'
)
parser
.
add_argument
(
'-ot'
,
'--output_tracts'
,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment