3dBrickStat sub-range selector

Hello,

Does the sub-range selector in 3dBrickStat “override” the -mask option?
I did the following test:
3dBrickStat -min -slow -mask mymask.nii.gz mynifti.nii.gz
and I got 5, meaning that within mymask the minimal value in mynifti is 5.

Then I reran it with the sub-range selector:
3dBrickStat -min -slow -mask mymask.nii.gz ‘mynifti.nii.gz<0…20>’
and I got 0.
This made me think that the sub-range selector “overrides” the -mask option. Is this true? If it is, would it be possible to modify the program to maintain both the sub-range selector and the -mask option active at the same time?

Thank you very much,
Giuseppe

I just noted that regardless of the mask, when I use the sub-range selector the min value I got from my dataset is always 0, even when I put <10…100> as sub-range. Not sure if this is an expected behavior…

Another example:
3dBrickStat -perclist 1 1 -mask mymask.nii.gz mynifti.nii.gz
gives me 800.
So I interpret this as: the first percentile of mymask in mynifti has value 800.

Then I do 3dBrickStat -count -mask mymask.nii.gz ‘mynifti.nii.gz<0…800>’ to check how many voxels constitute that first percentile and I got the same number I would get when I run it without the sub-range selector, i.e. 3dBrickStat -count -mask mymask.nii.gz mynifti.nii.gz.
Am I misunderstanding something?

That is interesting and surprising. I will try to look more within the code, but at a quick glance I don't see why subrange selectors would turn off the masking. Hmmm.

Is it possible that the subrange selectors are putting zeros into the region within the mask? I suspect that might be happening, therefore the minimum within the mask becomes zero (and I guess in this case, the zeros won't be ignored). That is, if you had a value of 100 in mynifti.nii.gz that was also within the nonzero part of mymask.nii.gz, then it would make sense for the within-mask minimum in your subranged case to reported as 0.

You could verify this with:

3dcalc                      \
  -a mynifti.nii.gz'<0..20>’ \
  -expr 'a'                 \
  -prefix mynifti_B.nii.gz

 3dBrickStat -min -slow -mask mymask.nii.gz mynifti_B.nii.gz

or

3dcalc                      \
  -a mynifti.nii.gz'<0..20>’ \
  -b mymask.nii.gz          \
  -expr 'a*step(b)'         \
  -prefix mynifti_C.nii.gz

 3dBrickStat -min -slow mynifti_C.nii.gz

Please let us know if that seems to be the case.

--pt

In the perclist case, it is a bit more complicated to see, indeed. The distribution within the mask will be changing, because there will potentially be more zeros within it. It is surprising to see the same number pop out; when I tried a similar thing, I did get different numbers (the second time, I got a 0 output, which suggested many values got turned to zero in the mynifti.nii.gz with that subrange selector).

Also, it might just be a reproducing typo, but there should only be 2 dots in the subrange: '<0..800>', not three.

--pt

Yes, I think the message board automatically adds the third dot to the text of the post.

So I tested both your options and in both cases the subrange selectors put zeros into the region within the mask (even though there are voxels within the mask that have values within the range 0-20).
Why does this happen? I thought the subrange selector would simply work by keeping all the voxels within the input range of values.

Wow, the evil board put an extra dot into my range selector, too! I will try to edit that, and then have it not do that. Yikes.

Re. subrange selectors: I think if you have a dataset with N voxels to start, you have to have N voxels after using the subrange selector, and some of them just get mapped to 0, as if you had run that initial 3dcalc command. So, if your dataset were (simplified 1D case):
x = [0,1,2,3,4,5,6,7]
and then you selected x'<3..6>', your dataset would be interpreted as:
[0,0,0,3,4,5,6,0]
when being read in. If the spot occupied by the 2 in x were in the nonzero part of your mask, then you would have a 0 in your analysis bin when reading in x'<3..6>'.

--pt

I see... but I am quite confused though about this behavior.
Regardless of the mask, the subrange selector by definition will have N voxels afterwards that are smaller than the initial N voxels, that's the purpose of the selector: selecting a subset of voxels.

I guess I will need to do the "long way" :sweat_smile: : making a new nifti with all the values out of my range equal to 0 and then apply the mask on this new nifti.

And, we have dis-enabled some of the autocorrection features. Note that the double dot -> triple dot thing will still (unfortunately!) happen, unless you put the dots within a code formatting, which is done by surrounding text with a pair of single backticks or a codeblock surrounding by pairs of triple backticks. So:
'<A..B>' is OK, but '<A..B>' is not.

I would think of the subrange selector as pre-masking the input dataset: you still have N voxels, with values at every voxel location, but you are pre-zeroing some out.

--pt

But this is not what happens in reality. The subrange selector makes some values equal to 0, but including values within the range I input.
When I did
3dcalc
-a mynifti.nii.gz'<0..20>’
-expr 'a'
-prefix mynifti_B.nii.gz
voxels that were 5 or 10 were changed to 0.

Is there a scale factor in your dset?

3dinfo -fac DSET

or:

nifti_tool \
  -disp_hdr -field scl_slope -field scl_inter \
  -infiles DSET  

?

Output is 0.0000 with the first command and the following with the second command:

name offset nvals values


scl_slope 112 1 0.0
scl_inter 116 1 0.0

I figured the problem, there was an issue with my files.
The sub-range selector works as expected.
Sorry for all the troubles and thank you for your support, Paul!

Ah, OK, no worries. I was going to ask to check out the file next, but if you have figured out a different issue with it, that is fine. Sorry there is an issue with the file; but hopefully the subrange+masking stuff will all work well when it is fixed.

1 Like

Glad you have this all worked out. Just wanted to add that you can use "-non-zero" to limit your data in addition to the mask and the range selector dset'<min..max>'.

1 Like