3dZipperZapper - calculations

Hello AFNI gurus,

We are looking into the command 3dZipperZapper outputs and were curious on how the outputs on *param.1D and *parcorr.1D are calculated. Also, how are is the “badlist” created?


Alexandre R. Franco, PhD

Computational Neuroimaging Laboratories (CNL)
Center for Biomedical Imaging and Neuromodulation (C-BIN)
Nathan S. Kline Institute for Psychiatric Research

Hi, Alex-

DWIs are often acquired with an interleaved acquisition: that is, slices with indices 0,2,4,6,… are acquired first and then those with indices 1,3,57,… Due to this, if a subject moves during the acquisition of a volume, one hallmark of that motion (and a sign of a huge problem for the quality of data in that volume) is seeing alternating bright-dark patterns going up the inf-sup axis (e.g., horizontal stripes when looking at a sagittal or coronal image of a volume). Another problem wtih intravolume motion during DWI acquisition is that a slice might have near-total signal dropout-- so, one very severe case of a bright-dark-bright pattern.

3dZipperZapper tries to exploit these effects and determine if a DWI volume is bad by looking for these things programmatically. This is a classic case of the human eye being able to detect something veeery easily, but a program has a much more difficult time doing so. Basically, it tries to count patterns of somewhat large bright-dark patterns between slices within the brain. It has to decide how “big” a brightness change is big enough to be a sign of something problematic, and how many slices of “big enough” changes qualify as something bad. These things are important, but basically heuristic and determined by comparing with lots of data checked for badness by eye.

So, to answer your questions more directly, the following is done within a 3D volume:

Within a masked-brain region, (scaled) differences are calculated between a voxel and its upstairs neighbor. (“Upstairs” here means in the inf-sup direction.) Two things happen with this information:
A) For each slice, the fraction of voxels that are greater than their upstairs neighbor is calculated; 0.5 is subtracted from this value, because that is the expected value by random chance (and we want to see if a slice tends to be uniformly greater/less than its neighbors).
B) For each slice, these differences are flattened out into a 1D vector, and the correlation of those values is calculated between neighboring slices.

The information from A is used to find dropout slices (cases where a slice has a huuuuge fraction uniformly less than both of its neighbors) or streaks where the fraction see-saws back and forth a lot-- this is a proxy for seeing those bright/dark stripes that are the hallmark of intravoxel motion.

The information from B is also used to find streaks of see-sawing properties: if the values are strongly anti-correlated over several slices, that would likely be a sign of bright-dark due to intravolume motion.

For a given volume: if it fails any of the above criteria (i.e., it has ‘bright-dark’ streaks or dropout), then its index gets added to the “badlist”.

The parcorr.1D file contains: -1(the slicewise correlations from B). That is, where values of parcorr.1D are large, there was strong anticorrelation between neighboring slice’s difference maps (hence, see-sawing a lot between relatively bright and dark). The “-1” scaling is just to make the “worrisome” points have large, upward values in a plot.

The *param.1D files contains: abs(difference of values in A between slices). That is, where there are large differences (either positive or negative) in the fraction of voxels greater than their upstairs neighbors, then one expects there to be see-sawing brightness.


Hi Paul,
Thanks! That was a very clear explanation. And what we see in the param and parcorr outputs clearly matches what we are visually seeing in our imaging data.

Just one followup question. What is the static/threshold used to define the “Bad Slices” on A and B?


Hi, Alex–

The defaults are as follows:

For the param.1D file,

  • finding a streak of at least 4 consecutive slices with abs difference > 0.3 (so, a few slices of ~large alternating brightness patches); the minimum streak size can be adjusted with the “-min_streak_len …” opt)
  • finding a single slices shows abs param value is >0.45 (recall: the param values were ‘centered’ around 0, so this is a pretty extreme fraction of being greater/less than other slices), or any pair of slices whose abs difference is >0.7 (so, dropout-like slices);

For the parcorr file, having at least 4 consecutive slices that each have with -1*correlation > 0.3 (so, again, large alternating brightness).

Again, these values are heuristic based on looking at example data sets from different places. Happy to have any feedback/comments.