Registration of SEEG to freesurfer brains

  • MNE version: 1.60
  • operating system: Manjaro Linux i3

Hi, I’m working with SEEG data and am trying to coregister digitized montages to my freesurfer subject brains. I don’t have the post op CTs on hand as they are with a collaborator, but I’m led to believe that the electrode locations were digitized in MRI RAS (not freesurfer RAS) space. I’m hoping to check my process with those who have more experience with this.

The electrode locations (x,y,z) are in mm, and I used:

montage = mne.channels.read_custom_montage('xxx.csv')
raw.set_montage(montage, match_case=True)

Then I made a trans matrix to translate electrode locations to voxel then to FS RAS space:

t1 = nibabel.load('T1.mgz')
mm_to_m = np.eyes(4)
inv_affine = np.linalg.inv(t1.affine)
Torig = t1.header.get_vox2ras_tkr()
trans =, inv.affine),Torig)
trans = mne.transforms.Transform('head','mri',trans=trans)

mne.viz.plot_alignment(, trans=trans, subject='xxx', surfaces=dict(white=0.25))

In the figure that results, it appears that the electrode locations are close to correct in x and z dimensions but not in y, they are too anterior by about half a brain’s length and sit outside the brain. Am I missing something here?

Best regards

I wrote mne_bids.convert_montage_to_mri to avoid having to write how to do the transforms correctly every time, maybe try that first. You might have to scale the montage positions to m first.

Thank you for your answer.
I’ve tried to use mne_bids.convert_montage_to_mri, but it returns an AttributeError: No mne attribute bids. I did install mne-bids, and imported mne_bids, but I still get this. I was hoping it would return a transformation matrix.
I feel like there should be a simple solution to this…

It doesn"t return anything, it just modifies the montage in place.

Not sure about that error sounds like maybe a version conflict. You can do pip install -U mne mne-bids to get the latest stable versions of both.

I’ve tried to use the above solution - it seemed to work for one subject but not for another… I’m not sure I’m using it correctly.

What I have so far:

import numpy as np
import mne, mne_bids

raw ='xxxx.fif')

mm2m = np.eye(4)
mm2m[:3,:3] *= 0.001
mm2m = mne.transforms.Transform('head','head',trans=mm2m)

montage = raw.get_montage()

trans = mne.coreg.estimate_head_mri('sub-x')
mne_bids.convert_montage_to_ras(montage, 'sub-x')
mne_bids.convert_montage_to_mri(montage, 'sub-x')

mne.viz.plot_alignment(, trans=trans, subject='sub-x', surfaces=dict(pial=0.5, sensor_colors='cyan')


I figured out the solution after a while.
From the opening post, the matrix multiplications produce a transformation matrix, but the signs and order of axes were mixed up in the translocation matrix (first 3 rows of the last column). To correct this:
Multiplied [0,3] by -1
[1,3] should be [2,3]
[2,3] should be [1,3] * (-1)
After these modifications, I used mne.transforms.Transform to turn this into a transformation matrix (head to mri), then used this in plot_alignment.
Hope this helps somebody.

I’m glad you found a solution that works but you really shouldn’t have to modify the transformation matrix directly something like this should work:

import numpy as np
import mne, mne_bids

raw ='xxxx.fif')

mm2m = np.eye(4)
mm2m[:3,:3] *= 0.001
mm2m = mne.transforms.Transform('ras', 'ras', trans=mm2m)

montage = raw.get_montage()
montage.apply_trans(mm2m)  # to m in RAS
mne_bids.convert_montage_to_mri(montage, 'sub-x')  # to mri surface RAS
trans = mne.coreg.estimate_head_mri('sub-x')  # estimate surface RAS to head
# (between left and right auricular points is 0)
montage.apply_trans(mne.transforms.invert_transform(trans))  # to head

mne.viz.plot_alignment(, trans=trans, subject='sub-x', surfaces=dict(pial=0.5, sensor_colors='cyan')

here the trans can be estimated by a transformation from fsaverage which already has the fiducials marked or faked as the identity even, it is going round trip (applied and then inverse applied inside plot_alignment) so it doesn’t matter what it is in practice.

Oh also, it looks like your montage may have already started in head coordinates. If fiducials were present in the montage, this transformation takes place automatically. You might want to just hold out those fiducials in order to suppress that transformation. You could use those fiducials to transform directly to mri (surface RAS) but I’m not sure there’s a nice way within the existing MNE API currently, it would probably require a pull request.

1 Like