coregistration and trans.fif

I have a problem with coregistration. I have a matrix which transforms sensor coordinates (in ITAB / device coordinate frame) to mni/acpc coordinate frame of standard 4x4 form (in a shorthand notation):

T = [[rotation matrix 3x3] [translation vector 3x1]

Then I create a transform using

trans = mne.transforms.Transform('head', 'mri', trans=T)

Coordinates of sensors in both coordinate systems (ITAB/device and mri/acpc) are given in mm.

Problem is that when I plot alignment

f = mne.viz.plot_alignment(info=info, bem=bem, trans=trans, subject=subject, subjects_dir=subjects_dir,
                           surfaces='auto', meg=('helmet', 'sensors'), show_axes=True, coord_frame='mri',
                           src=src, fig=fig, verbose='info')

origins of head and MRI systems are shifted by distance of 42112.2 mm.

That probably implies there is a problem with scaling/units. In order to fix it I used a rescaling matrix:

a = 1000

R = [[a, 0, 0, 0],
        [0, a, 0, 0],
        [0, 0, a, 0],
        [0, 0, 0, 1]]

T = np.matmul(T, R)

T = np.matmul(np.linalg.inv(R), T)

The distance between the systems is now decreased to 42.1 mm, but when I plot alignment it’s wrong: helmet surface cuts through a head surface.

How to construct transformation, and what are exactly units used by trans?

PS: using identity matrix as T the outcome looks like this, so the problem is the form of the T:

From your description it seems that your sensors are in device coordinates, not head. So the transform is deviceMRI. You need a transform from device coordinates to head coordinates as well to make this work. This is typically done through localizing the HPI coils. With MEGIN equipment, this transform is stored in the FIFF file when you are recording.


Hi Marijn,
thank you for your help!
This is what I get from header of MEG recording for channels (first entry):

[{'scanno': 1, 'logno': 1, 'kind': 1 (FIFFV_MEG_CH), 'range': 1.0, 'cal': 1.0, 'coil_type': 3024 (FIFFV_COIL_VV_MAG_T3), 'loc': array([-10.06000042,  52.91999817, 157.05000305,   1.        ,
         0.        ,   0.        ,   0.        ,   1.        ,
         0.        ,   0.        ,   0.        ,   1.        ]), 'unit': 112 (FIFF_UNIT_T), 'unit_mul': 0 (FIFF_UNITM_NONE), 'ch_name': 'MAG_000', 'coord_frame': 1 (FIFFV_COORD_DEVICE)}, {'scanno': 2, 'logno': 2, 'kind': 1 (FIFFV_MEG_CH), 'range': 1.0, 'cal': 1.0, 'coil_type': 3024 (FIFFV_COIL_VV_MAG_T3), 'loc': array([ -9.05000019,  25.57999992, 165.38000488,   1.        ,

I’m not sure if transform DEVICE → HEAD is here. If not, where to have a look?

Also transform used in mne.viz.plot_alignment(info=info, bem=bem, trans=trans... is from head to mri.
So how to multiply them or where to put T(DEVICE>HEAD)?

does['dev_head_t'] exist?

Yes it exists, however it is an identity matrix:

<Transform | MEG device->head>
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

that’s not very helpful then

Did you try defining your existing trans as meg -> mri instead of head -> mri in the call to mne.Transform()? As @wmvanvliet said it seems like what you have are device coords, not head coords.

If that doesn’t help you could consider stepping through (parts of) this tutorial with your own data to see if it clarifies things: Source alignment and coordinate frames — MNE 1.5.1 documentation

Thank you Dan,
changing head to meg

trans = mne.transforms.Transform('meg', 'mri', trans=trans_itab_acpc)

raises an error

  File "/home/white/APPS/anaconda3/envs/mega/lib/python3.11/site-packages/mne/", line 487, in _ensure_trans
    raise ValueError(f"{err_str} " + ", ".join(misses))
ValueError: trans must be a Transform between head<->mri, got meg->mri

I’m still thinking that there can be also problem with units considering large distance between the origins of coordinate systems.

Small update: It occurred that for this data device coordinates are in fact already head coordinates. Hence[‘dev_head_t’] equals identity matrix is correct.

Seems something else is not right…

If device coords == head coords, then it makes sense that plot_alignment puts the helmet straight through the head. Because that’s how things would look if you put the MEG helmet at the center of the head :slight_smile:

Hi Marijn,
thank you! I think it’s not what really happens. The coordinates of head surface and coordinates of sensors are different. They should be different whatever coordinate system you choose.

Also notice that without rescaling there is a huge distance between the origins of head and mri coordinate systems and of course helmet does not cut through head surface.

PS. I can share more code if necessary to solve this problem.