有时在创建BEM模型时,由于可能出现的一系列问题(例如,表面之间的交叉),表面需要手动校正。在这里,我们将看到如何通过将表面导出到3D建模程序blender,编辑它们,并重新导入它们来实现这一点。我们还将给出一个简单的例子,说明如何使用pymeshfix来修复拓扑问题。
本教程的大部分内容都是基于Ezequiel Mikulan的ezemikulan/blender_freesurfer。
1 | import os |
导出表面到blender
在本教程中,我们使用MNE-Sample集,其表面没有问题。为了演示如何修复有问题的表面,我们将手动放置一个内颅骨顶点在外颅骨顶点的外部的网格。
然后我们将表面转换为.obj文件,并在FreeSurfer subject文件夹中创建一个名为conv的新文件夹来保存它们。
1 | # Put the converted surfaces in a separate 'conv' folder |
(以上代码中的文件连接在新版本中更改)
在blender中编辑
查看下面的视频教程,了解如何在Blender中导入,编辑和导出表面(一步一步的说明也在下面):
在blender中编辑
我们现在可以打开Blender并导入表面。进入文件>导入>Wavefront(.obj)。导航到conv文件夹并选择要导入的文件。确保选择“保持垂直顺序”(Keep Vert Order)选项。你还可以选择Y Forward选项以在正确的方向(RAS)加载坐标轴:
为方便起见,您可以通过按下Operator Presets旁边的+
按钮来保存这些设置,对所有你想导入的表面重复这个过程。
你现在可以编辑任何你喜欢的表面。请参阅初学者blender系列教程来学习如何使用blender。可以看它的第2部分,教你如何使用基本的编辑工具来修复表面。
在MNE-Python中使用修复的表面
在Blender中,你可以通过选择它来导出一个表面作为.obj文件,然后进入file > export > Wavefront (.obj)。你需要再次选择Y Forwar选项,并选中Keep Vertex Order box。
每个surface都需要作为单独的文件导出。我们建议将它们保存在conv文件夹中,并以_fixed.obj为结尾,尽管不是严格必要的。
为了能够从上到下运行本教程脚本,我们在这里使用Python代码模拟您在Blender中手动进行的编辑:
1 | coords, faces = mne.read_surface(conv_dir / "inner_skull.obj") |
现在回到Python,你可以读取修复后的.obj文件,并将它们保存为FreeSurfer的 .surf文件。为了mne.make_bem_model()
函数找到它们,需要使用它们的原始名称保存在surf文件夹中,例如bem/inner_skull.surf
。一定要先备份原来的表面,以防出错!
1 | # Read the fixed surface |
编辑头表面
有时头部表面有缺陷,需要手动编辑。我们使用mne.write_head_bem()
将修改的表面转换为.fif文件。
低分辨率的头
对于EEG正向建模,outer_skin.surf
可能是手动编辑的。在这种情况下,记得保存从编辑表面文件或配准得到的-head.fif
的原始和修改版本。
1 | # Load the fixed surface |
高分辨率的头
我们使用mne.read_bem_surfaces()
来读取head surface文件。编辑完成后,我们再次使用mne.write_head_bem()
输出头文件。这里我们用-head.fif
提高速度。
1 | # If ``-head-dense.fif`` does not exist, you need to run |
1 BEM surfaces found Reading a surface... [done] 1 BEM surfaces read
blender编辑技巧
一个特别有用的操作是Shrinkwrap功能,它将一个表面限制在另一个表面内。使用方法如下:
①选择表面:选择产生问题的表面。
②选择顶点:在Edit Mode下,按C
使用圆选择工具选择外面的顶点。
③-⑤对顶点进行分组:在 Object Data Properties选项卡使用+
按钮添加一个顶点组,并单击Assign将当前选择分配到组。
⑥-⑧Shrinkwrap:在Modifiers选项卡中,在Add Modifier下添加一个Shrinkwrap,并将其设置为snap内部,外部表面为Target,之前创建的Group为Vertex Group。然后可以使用Offset参数来调整距离。
⑨应用:在Object Mode下,点击Shrinkwrap修饰符的向下箭头,然后点击应用。
如果上述操作后没有任何变化,内颅骨表面的法线可能被反转了。要解决这个问题,请选择所有的顶点或内部颅骨的所有面,并在工具栏中进行Mesh>Normals>Flip。
然后!我们就已经准备好继续分析了,例如继续运行mne.make_bem_model()
。
还有错误怎么办?
blender操作
当在Blender中编辑BEM表面/网格时,请确保使用的工具不会改变顶点的数量或顺序,或三角形面的几何形状。例如,避免使用挤压工具(extrusion tool),因为它复制了被挤压的顶点。
用smoothing的方法清理坏的、密集的头部表面
如果你在使用mne make_scalp_surfaces
时得到一个粗糙的头部表面,考虑使用FreeSurfer的高斯内核提前平滑T1,在受试者的mri目录中使用如下内容:
1 | mri_convert --fwhm 3 T1.mgz T1_smoothed_3.mgz |
这里的--fwhm
参数决定了应用多少smoothing,单位为mm。然后删除SUBJECTS_DIR/SUBJECT/surf/lh.seghead
重新运行mne make_scalp_surfaces
并添加额外的参数--mri="T1_smoothed_3.mgz" --overwrite
,你应该得到更clean的表面。
拓扑错误
MNE-Python要求网格满足一定的拓扑检查,以保证边界元求解、电极投影等后续处理能够正常工作。
下面是在MNE-Python中使用网格时可能遇到的一些错误示例,以及这些错误的可能原因。
- Cannot decimate to requested ico grade
错误是由于顶点太少或太多造成的。完整的错误类似于:
1 | RuntimeError: Cannot decimate to requested ico grade 4. The provided |
- Surface inner skull has topological defects
在试图通过删除顶点来匹配原始三角形数量时,可能会发生此错误。完整的错误信息如下所示:
1 | RuntimeError: Surface inner skull has topological defects: 12 / 20484 |
- Surface inner skull is not complete
这个错误,和前面的错误一样,反映了表面拓扑结构的一个问题,即预期的顶点/边/面模式被打乱了。
1 | RuntimeError: Surface inner skull is not complete (sum of solid |
- Triangle ordering is wrong
这个错误反映了内存中表示曲面的方式(顶点/面定义的顺序)与MNE-Python所期望的不匹配。完整的错误是:
1 | RuntimeError: The source surface has a matching number of triangles |
在blender中处理拓扑结构
对于任何这些错误,通常最简单的方法是从未编辑的BEM表面重新开始,并再次尝试,确保只移动顶点和面,而不添加或删除任何顶点和面。例如,选择一个圆的顶点,然后按G将它们拖动到想要的位置。在Blender中smoothing一组选中的顶点(右键单击并选择“smoothing”)也hen有用。
使用pymeshfix处理拓扑结构
pymeshfix
是一个GPL许可的Python模块,用于生成满足上述拓扑检查的水密网格。例如,如果你的'SUBJECTS_DIR/SUBJECT/surf/lh.seghead'
文件中有拓扑问题,通过上面的“用smoothing的方法清理坏的、密集的头部表面”行不通的,你可以尝试修复网格。在使用conda或pip从SUBJECTS_DIR/SUBJECT/surf
目录安装pymeshfix后,你可以尝试:
1 | import pymeshfix |
在某些情况下,这可以修复拓扑结构,以便后续对mne make_scalp_surfaces
的调用可以成功,而不需要使用--force
参数。