Brainstorm Generate Head Surface Fails

Hello!

I have a few subjects for whom Brainstorm fails to Generate a Head Surface in the following way:
image

I have tried adjusting the available parameters including # of vertices, Erode Factor, and Fill Holes Factor to no avail. If anyone has any suggestions for troubleshooting this, it would be very much appreciated!

Thanks,
Brendan

Hi Brendan,

That looks very strange,

What happens if you calculate the BEM surfaces and then plot the scalp surface? Maybe there is something wrong with your input data.

Kind regards,
Steven

Steven,

If I calculate the BEM surfaces using Brainstorm (uses the above result) it fails obviously. But if I calculate the BEM surfaces using Fieldtrip (creates a new scalp surface) it fails for this participant due to intersecting surfaces. If I use spm12 to create the BEM surfaces that works. But I'm not sure that I want to use spm. I'd rather figure out a way to fix the root of the problem here or use Freesurfer to generate a scalp surface. I find it a bit weird that recon-all doesn't do that automatically. I'm currently looking into how I could add this to our freesurfer pipeline. Apparently mri_watershed has the ability to output the BEM surfaces but they are not registered (not sure how to get them in the same space and why it's different from how the other surfaces are generated) and the documentation says " The -surf tool is intended as an added convenience and not as a high quality estimation of these tissue boundaries (one would not use an MPRAGE type volume for defining these tissue boundaries). For a tool designed to do that please see mri_make_bem_surfaces."

So I checked out that tool and it won't work because I'm missing files but I don't know where to find those files.

Dear Brendan,

My apologies, I misunderstood the question. Using the freesurfer scripts is not something i do often and thus it is a bit too advanced for me. I hope someone else can help you better :slight_smile:

Kind regards,
Steven

Steven,

Thanks anyway! :smiley:

Okay so after doing a lot of research, here's where I'm at. I looked into using Freesurfer to generate the scalp surface and it's way more trouble than it's worth because Freesurfer just has very little support for it. So I went back to Brainstorm to try to find the root of the problem. Finally I found the actual function that generates the head surface and after doing some debugging and comparing with other subject's that didn't have this issue, I found the underlying problem is the histogram computed for the MRI. The exact function where this failure is occuring is mri_histogram.m. It is failing to estimate the bg intensity from the histogram. That is why it was unable to generate a head surface. If I hard code it to use a reasonable background intensity, it works, but still isn't super accurate (because the bg intensity isn't precise for that subject). So I'm still trying to figure out where and why this function is failing and if there's something I can do to fix it. See example below where the top right histogram is that of the subject who failed head surface generation and the other three worked correctly.

So apparently brainstorm is making an unsafe assumption when picking peaks in the histogram. See lines below from lines 240-250 in mri_histogram.m:

    % If the highest maxima is > (3*second highest maxima) : 
    % it is a background maxima : use the first minima after the
    % background maxima as background threshold
    % (and if this minima exist)
    [orderedMaxVal, orderedMaxInd] = sort(cat(1,Histogram.max.y), 'descend');
    if ((orderedMaxVal(1) > 3*orderedMaxVal(2)) && (length(Histogram.min) >= orderedMaxInd(1)))
         Histogram.bgLevel = Histogram.min(orderedMaxInd(1)).x;
    % Else, use the default background threshold
    else
        Histogram.bgLevel = defaultBg;
    end

If I hardcode it to use the first minimum instead of the 4th like it's trying to, everything works correctly and I get a beautiful head surface. I'm not sure how the Brainstorm devs would want to handle this, but I'll see what I can figure out and then put in a request on github. Worst case, I could add a manual peak picking option for the histogram to use when people fail.

So apparently the root of the problem was that our images had the background removed and brainstorm failed to identify that. So the bgLevel should have been 1.

On line 231 of mri_histogram, I changed the conditional statement to the following so that it would recognize that most voxels were zero value:

( ((nzero(1)>2) && ~isempty(nnonzero) && (nnonzero(1) > nzero(1))) || (Histogram.fncY(1) == max(Histogram.fncY)) )

Moved equivalent github issue for avoid duplicating sources of discussion.
Post from @balken:

For detailed report see:
Brainstorm Generate Head Surface Fails - #4 by SBeumer

The root of the problem turned out to be in mri_histogram on line 231 where the function is attempting to determine if the background has been removed in the MRI. In our case, we DO remove the background during a cleaning step. It was failing to recognize this. I changed the conditional statement on line 231 to the following (and now everything is working for us):

( ((nzero(1)>2) && ~isempty(nnonzero) && (nnonzero(1) > nzero(1))) || (Histogram.fncY(1) == max(Histogram.fncY)) )

because there are more zero value voxels in our MRIs than nonzero. This is a fairly safe assumption for our data because our zero voxels are over 3x as numerous as nonzero. However, brainstorm devs might want to take a closer look at the mri_histogram function in general. I also noticed an unsafe assumption on lines 240-250 where it assumes "if the highest maxima is > (3*second highest maxima) : it is a background maxima : use the first minima after the background maxima as background threshold". This is where our histogram was failing (see detailed report for visualization). It didn't recognize that the background was removed so it continued on to attempt to use this assumption to determine the bgLevel but that wasn't accurate for our data.

We are using MP2Rage images that have had their static removed. See example below.

image

Before static is removed:

image

Sounds good!

(Histogram.fncY(1) == max(Histogram.fncY))

Checking if the first bin is the biggest bin does not always indicate if the background was removed. In many cases the volume is re-oriented/resized and padded with zeros for the missing values, possibly causing 0 to become the most prevalent value.

What about we consider that if 50% of the volume are zeros, then the background was removed? It is quite conservative, but I don't want to mess too much with this function that has been quite stable over the past 10 years.
Anatomy: Use custom background threshold for head surface generation · brainstorm-tools/brainstorm3@5522c90 · GitHub

If this doesn't work for you, I also added an extra parameter Background intensity threshold to the options for generating the head surface. It allows you to redefine manually a badly identified background threshold:
https://neuroimage.usc.edu/brainstorm/Tutorials/LabelFreeSurfer#Handling_errors

Please let us know what you think of these solutions.

image

Francois,

Those both sound like excellent solutions to me!

Thanks,
Brendan

Unfortunately, > 50% is not enough as evidenced by failures in our own tutorials where MRIs were defaced, leading to many 0 voxels, but the background is still present.

I did a PR to remove this condition. It can still be done manually with the new option.

Problem fixed in this commit:
https://github.com/brainstorm-tools/brainstorm3/commit/25732db0073a343411ea2c88bebb5686873e41f9

The background removal detection added recently was removed. Only the manual definition of the threshold in the head surface computation was kept.
To recompute the histogram for the MRI already in the database and get a fixed "guessed background theshold" when generating the head surface, simply display the histogram (right-click on the MRI > Display > Histogram)