3dDepthMap¶
Overview¶
This program calculates the depth of ROIs, masks and 'background', using
the fun Euclidean Distance Transform (EDT).
Basically, this means calculating the Euclidean distance of each
voxel's centroid to the nearest boundary with a separate ROI (well, to be
brutally technical, to centroid of the nearest voxel in a neighboring ROI.
The input dataset should be a map of ROIs (so, integer-valued). The
EDT values are calculated throughout the entire FOV by default,
even in the zero/background regions (there is an option to control this).
written by: PA Taylor and P Lauren (SSCC, NIMH, NIH)
Description¶
This code calculates the Euclidean Distance Transform (EDT) for 3D
volumes following this nice, efficient algorithm, by Felzenszwalb
and Huttenlocher (2012; FH2012):
Felzenszwalb PF, Huttenlocher DP (2012). Distance Transforms of
Sampled Functions. Theory of Computing 8:415-428.
https://cs.brown.edu/people/pfelzens/papers/dt-final.pdf
Thanks to C. Rorden for pointing this paper out and discussing it.
The current code here extends/tweaks the FH2012 algorithm to a more
general case of having several different ROIs present, for running
in 3D (trivial extension), and for having voxels of non-unity and
non-isotropic lengths. It does this by utilizing the fact that at
its very heart, the FH2012 algorithm works line by line and can even
be thought of as working boundary-by-boundary.
Here, the zero-valued 'background' is also just treated like an ROI,
with one difference. At a FOV boundary, the zero-valued
ROI/background is treated as open, so that the EDT value at each
'zero' voxel is always to one of the shapes within the FOV. For
nonzero ROIs, one can treat the FOV boundary *either* as an ROI edge
(EDT value there will be 1 edge length) *or* as being open.
Command usage and option list¶
3dDepthMap [options] -prefix PREF -input DSET
where:
-input DSET :(req) input dataset
-prefix PREF :(req) output prefix name
-mask MASK :mask dataset. NB: this mask is only applied *after*
the EDT has been calculated. Therefore, the boundaries
of this mask have no affect on the calculated distance
values, except for potentially zeroing some out at the
end.
-dist_sq :by default, the output EDT volume contains distance
values. By using this option, the output values are
distance**2.
-ignore_voxdims :this EDT algorithm works in terms of physical distance
and uses the voxel dimension info in each direction, by
default. However, using this option will ignore voxel
size, producing outputs as if each voxel dimension was
unity.
-rimify RIM :instead of outputting a depthmap for each ROI, output
a map of each ROI's 'rim' voxels---that is, the boundary
layer or periphery up to thickness RIM---if RIM>0.
+ Note that RIM is applied to whatever kind of depth
information you are calculating: if you use '-dist_sq'
then the voxel's distance-squared value to the ROI edge
is compared with RIM; if using '-ignore_voxdims', then
the number-of-voxels to the edge is compared with RIM.
The depthmap thresholding is applied as:
abs(DEPTH)<=RIM.
+ When using this opt, any labeltable/atlastable
from the original should be passed along, as well.
+ A negative RIM value inverts the check, and the
output is kept if the depth info is:
abs(DEPTH)>=abs(RIM).
NB: with a negative RIM value, it is possible an ROI
could disappear!
-zeros_are_zero :by default, EDT values are output for the full FOV,
even zero-valued regions. If this option is used, EDT
values are only reported within the nonzero locations
of the input dataset.
-zeros_are_neg :if this option is used, EDT in the zero/background
of the input will be negative (def: they are positive).
This opt cannot be used if '-zeros_are_zero' is.
-nz_are_neg :if this option is used, EDT in the nonzero ROI regions
of the input will be negative (def: they are positive).
-bounds_are_not_zero :this flag affects how FOV boundaries are treated for
nonzero ROIs: by default, they are viewed as ROI
boundaries (so the FOV is a closed boundary for an ROI,
as if the FOV were padded by an extra layer of zeros);
but when this option is used, the ROI behaves as if it
continued 'infinitely' at the FOV boundary (so it is
an open boundary). Zero-valued ROIs (= background)
are not affected by this option.
-only2D SLI :instead of running full 3D EDT, run just in 2D, per.
plane. Provide the slice plane you want to run along
as the single argument SLI:
"axi" -> for axial slice
"cor" -> for coronal slice
"sag" -> for sagittal slice
-binary_only :if the input is a binary mask or should be treated as
one (all nonzero voxels -> 1; all zeros stay 0), then
using this option will speed up the calculation. See
Notes below for more explanation of this. NOT ON YET!
-verb V :manage verbosity when running code (def: 1).
Providing a V of 0 means to run quietly.
Notes¶
Depth and the Euclidean Distance Transform¶
The original EDT algorithm of FH2012 was developed for a simple binary
mask input (and actually for homogeneous data grids of spacing=1). This
program, however, was built to handle more generalized cases of inputs,
namely ROI maps (and arbitrary voxel dimensions).
The tradeoff of the expansion to handling ROI maps is an increase in
processing time---the original binary-mask algorithm is *very* efficient,
and the generalized one is still pretty quick but less so.
So, if you know that your input should be treated as a binary mask, then
you can use the '-binary_only' option to utilize the more efficient
(and less generalized) algorithm. The output dataset should be the same
in either case---this option flag is purely about speed of computation.
All other options about outputting dist**2 or negative values/etc. can be
used in conjunction with the '-binary_only', too.
Examples¶
1) Basic case:
3dDepthMap \
-input roi_map.nii.gz \
-prefix roi_map_EDT.nii.gz
2) Same as above, but only output distances within nonzero regions/ROIs:
3dDepthMap \
-zeros_are_zero \
-input roi_map.nii.gz \
-prefix roi_map_EDT_ZZ.nii.gz
3) Output distance-squared at each voxel:
3dDepthMap \
-dist_sq \
-input mask.nii.gz \
-prefix mask_EDT_SQ.nii.gz
4) Distinguish ROIs from nonzero background by making the former have
negative distance values in output:
3dDepthMap \
-nz_are_neg \
-input roi_map.nii.gz \
-prefix roi_map_EDT_NZNEG.nii.gz
5) Have output voxel values represent (number of vox)**2 from a boundary;
voxel dimensions are ignored here:
3dDepthMap \
-ignore_voxdims \
-dist_sq \
-input roi_map.nii.gz \
-prefix roi_map_EDT_SQ_VOX.nii.gz
6) Basic case, with option for speed-up because the input is a binary mask
(i.e., only ones and zeros); any of the other above options can
be combined with this, too:
3dDepthMap \
-binary_only \
-input roi_mask.nii.gz \
-prefix roi_mask_EDT.nii.gz
7) Instead of outputting ROI depth, output a map of the ROI rims, keeping:
the part of the ROI up to where depth is >=1.6mm
3dDepthMap \
-input roi_map.nii.gz \
-rimify 1.6 \
-prefix roi_map_rim.nii.gz