Closed noreun closed 4 years ago
you can call:
raw.plot_sensors()
to see if it makes sense.
I just found out they do not
https://drive.google.com/open?id=0B0p7WZ2wlTFSSUh4OFQySzYwYzQ
here is the EGI electrodes for reference
https://drive.google.com/open?id=0B0p7WZ2wlTFSTDZ2bzI1NWc3VVk
Which is weird since they were not that far from the MRI...
https://drive.google.com/open?id=0B0p7WZ2wlTFSNklmcTlPakJERXc
How can I fix this? Apparently the loaded electrode positions used in raw.set_montage with the Montage object (called before the snippet posted above) where very far from the MNE reference. Is it projecting into the (X,Y) plane?
just to make it clear, they were also not that far before aligning to MRI, specially not upside-down like in the raw.plot_sensors()
@noreun want to try plot_trans
with #3707 with your data?
I did, and it looks really bad: it is like the translation is not applied to the electrodes positions. I feel like I'm missing some important step here
https://drive.google.com/open?id=0B0p7WZ2wlTFSN2JrSXh5Tkhrd1U
However, if I show the digitization points, than I can see they are in the correct position as shown during mne.gui.coregistration!
https://drive.google.com/open?id=0B0p7WZ2wlTFSN0JkVEJyOWxZOTA
Just a reminder, I first use
raw.set_montage()
with a normal Montage object, built from the electrodes positions/labels saved during the digitization process
Next, I create a DigMontage object using the same information + fiducials, call
raw.set_montage()
again passing this new object to set the digitization information. Then finally I save the Raw object and run
mne coreg
to align the fiducials using the file with the Raw object, and save the -trans.fif file.
The plot above was generated with the raw.info and the -trans.fif file resulting from this process...
btw, here is the call to the plot_trans file
plot_trans(raw.info, trans, subject=subject_name, dig=True,
eeg_sensors=['original', 'projected'],
meg_sensors=[], coord_frame='head', subjects_dir=subjects_dir)
ok, I figured out the problem. The plot now looks like this:
https://drive.google.com/open?id=0B0p7WZ2wlTFSQ0VfNWwwTkJpOFE
The problem is that read_dig_montage
has a default parameter Transform
that project the hsp
and elp
points into neuromag space
On the other hand, this is not the default during read_montage
Therefore, the translation matrix created with mne.gui.coregistration
do not make sense for the electrodes positions inside raw.info
, creating a non-sense projection.
For me the correct solution would be to run read_dig_montage
with Transform=False
(and have this more explicit in the Tutorial, since I guess not everybody uses Polhemus or Neuromag).
However, it turns out that in this case, the fiducials are just ignored in montage.py!
Lines 597 to 602:
neuromag_trans = get_ras_to_neuromag_trans(nasion, lpa, rpa)
fids = apply_trans(neuromag_trans, [nasion, lpa, rpa])
elp = apply_trans(neuromag_trans, elp)
hsp = apply_trans(neuromag_trans, hsp)
else:
fids = [None] * 3
My current solution is to also project the eletrodes into neuromag space dugin read_montage
using Transform=True
.
Another weird thing is that read_montage
expects the fiducials to be ('nz', 'lpa', 'rpa') while read_dig_montage
expects ('nasion', 'lpa', 'rpa').
Summing-up:
read_dig_montage
even when not projecting into neuromag space (Transform=False), or if it is crucial for MNE that electrodes exist in the neuromag space, the projection should be enforced during read_montage
(I think this is why my plots with raw.plot_sensors()
did not make sense in the figures above)@noreun thanks a lot for looking into this.
could you send us a WIP pull request with the changes you had to do to make it work for you?
if you PR contains test it will guarantee that we won't break your workflow in the long term.
I created a PR for the change in fiducials name so that they are the same in both read_montage
and read_dig_montage
However I don't know if I should I use Tranform=True
during read_montage (my current solution, no changes in mne required) or Tranform=False
in read_dig_montage (did not try yet, should change read_dig_montage)?
I figure that the reason the fiducials are set to [None] * 3
in read_dig_montage
is because they have to be in Neuromag space, otherwise something would break. Is that correct? Otherwise, I'd be willing to fix that and update the fiducials in read_dig_montage
.
Once this is decided, I'd also be willing to write a tutorial about co-registration with locations from generic input (e.g., text files), that could be referenced in the Head Model and Forward Computation Tutorial (there is not much info about this important step)
I guess I should just create a tutorial/plot_coregistration.py following these guidelines?
http://mne-tools.github.io/stable/contributing.html#checking-and-building-documentation
@teonbrooks do you have a moment to comment on these issues? I'm not sure what the purpose of these arguments was/is.
Once this is decided, I'd also be willing to write a tutorial
Yes please reference in the head model tutorial that you need properly provided dig points. Your new tutorial could have nice sanity check plots like plot_sensors, plot_trans, etc. Whatever you used to make sure things weren't broken can help here. Even things like the histogram of distances thing we talked about might be a cool thing to add (manual matplotlib/numpy stuff like that is great if it's only a few lines to do something useful).
I guess I should just create a tutorial/plot_coregistration.py following these guidelines?
Yes. And I recommend copy-pasting an existing tutorial to get you started, and adapt from there. Things like the title need to be formatted properly or it will break, so don't start from absolute scratch. (Please also add this tidbit to the contrib instructions while you're in there if you have time.)
the DigMontage wasn't intentionally meant for electrode placements but for head shape, ELP (indicator points in headshape-space) and HPI (indicator points in MEG space). Maybe the name wasn't the best choice...maybe this needs more documentation and/or a name change.
One standard way to deal with digitized electrode positions is to make a hpts file and use the read_montage
. Sorry @noreun, I only had a chance to skim through the past notes so you might have mentioned this but how are you reading the digitized electrode points now to get through to properly work.
I figure that the reason the fiducials are set to [None] * 3 in read_dig_montage is because they have to be in Neuromag space, otherwise something would break. Is that correct? Otherwise, I'd be willing to fix that and update the fiducials in read_dig_montage.
if you use the transform=True
, it would put all the points into Neuromag space
just fyi, the keyword transform
, and the Transform
object serve different roles.
@teonbrooks so Montage
is for electrode points, whether from a standard (non-individualized) set or digitized set? And DigMontage
is meant for all other things? I thought you had said before that Montage
was really meant for standard things and DigMontage
was for anything that was manually digitized... but I could be wrong.
yeah, this is confusing. so DigMontage
was purposed to take care of digitized head points, and digitized reference points. we should probably add an argument to handle digitized electrodes, it seems like the most fitting place.
hpts
has been historically used as a placeholder for electrode/sensor points that aren't a standard format. it could be modified to handle digitized points but the standard practice of Montages is that they are preset points.
My proposal is that we could add the arguments sensor positions
, which should be a numpy array and sensor_types
, which should be a list of str and we could have the set_montage
take care of the appropriate transformation when set to True.
@Eric89GXL, what are your thoughts on this? this would essentially make the DigMontage
do what a number of people desire it to do.
I don't use these functions so it's hard to know if this would make sense to people. @jona-sassenhagen do you use these functions? @choldgraf I saw you used them in some code?
@teonbrooks now I use read_montage with transform=True, and then read_dig_montage also with transform=True. This way the electrodes positions defined in read_montage and the fiducials positions defined in read_dig_montage are in the same space, so I can finally use mne coreg
to create the Transformation matrix that put both into MRI space.
More than the fact that Montage object sets the electrodes positions and DigMontage sets only the fiducials (and elp, hpi, etc), the most confusing part to debug was the fact that transform is defaulted to False in read_montage and defaulted to True in read_dig_montage.
But it is true that if read_dig_montage is fixed to also set the electrodes positions, which will also be transformed into Neuromag space by default, it settles the problem.
@Eric89GXL which functions? DigMontage
? I've never used them before (I'm a spoiled ecog brat so I haven't used much of the EEG/MEG API)
I am in the process of changing DigMontage
to support channel dig. It already does to some extent. @choldgraf that's what you'll want to use instead of Montage
@Eric89GXL so after the changes, there will be only one call to read_dig_montage
, and the info
will have the channel locations and fiducials/head points all in the same space? This will be really good.
I think that this has been taken care of in the refactoring plus examples like:
Feel free to reopen if things are still not clear
A coregistration between electrodes and scalp surface is necessary in order to create a forward model.
The tutorial about Head Model and forward computation does not have much information about how it is done, except that a "-trans.fif" containing the alignment between electrodes and scalp surface is necessary:
http://martinos.org/mne/stable/auto_tutorials/plot_forward.html
And that it can be generated using mne.gui.coregistration, mne_analyse or mrilab.
If mne.gui.coregistration is used, it is necessary to have the digitization information in another ".fif" file. However it is not very clear how this information should be inserted into the mne.Raw() object, or even which information is necessary desired (fiducials, head points, etc)
I created a simple procedure that loads the digitization of electrodes positions and fiducials information from a text file using cvs.read, creates a DigMontage object using mne.channels.read_dig_montage, and update the infor['dig'] using raw.set_montage()
However I don't know if this is the correct was to do it. For example raw.set_montage do not set the electrodes positions when called with a DigMontage object, so it has to be called twice, the frist time with a normal Montage object
Here is the code, I can improve it a help to write a tutorial / update documentation if it is the case