Python-MNE-源空间和正模型07:修复BEM和头表面

有时在创建BEM模型时,由于可能出现的一系列问题(例如,表面之间的交叉),表面需要手动校正。在这里,我们将看到如何通过将表面导出到3D建模程序blender,编辑它们,并重新导入它们来实现这一点。我们还将给出一个简单的例子,说明如何使用pymeshfix来修复拓扑问题。
本教程的大部分内容都是基于Ezequiel Mikulan的ezemikulan/blender_freesurfer。

import os
import shutilimport mnedata_path = mne.datasets.sample.data_path()
subjects_dir = data_path / "subjects"
bem_dir = subjects_dir / "sample" / "bem" / "flash"
surf_dir = subjects_dir / "sample" / "surf"

导出表面到blender

在本教程中,我们使用MNE-Sample集,其表面没有问题。为了演示如何修复有问题的表面,我们将手动放置一个内颅骨顶点在外颅骨顶点的外部的网格。

然后我们将表面转换为.obj文件,并在FreeSurfer subject文件夹中创建一个名为conv的新文件夹来保存它们。

# Put the converted surfaces in a separate 'conv' folder
conv_dir = subjects_dir / "sample" / "conv"
os.makedirs(conv_dir, exist_ok=True)# Load the inner skull surface and create a problem
# The metadata is empty in this example. In real study, we want to write the
# original metadata to the fixed surface file. Set read_metadata=True to do so.
coords, faces = mne.read_surface(bem_dir / "inner_skull.surf")
coords[0] *= 1.1  # Move the first vertex outside the skull# Write the inner skull surface as an .obj file that can be imported by
# Blender.
mne.write_surface(conv_dir / "inner_skull.obj", coords, faces, overwrite=True)# Also convert the outer skull surface.
coords, faces = mne.read_surface(bem_dir / "outer_skull.surf")
mne.write_surface(conv_dir / "outer_skull.obj", coords, faces, overwrite=True)

(以上代码中的文件连接在新版本中更改)

在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中手动进行的编辑:

coords, faces = mne.read_surface(conv_dir / "inner_skull.obj")
coords[0] /= 1.1  # Move the first vertex back inside the skull
mne.write_surface(conv_dir / "inner_skull_fixed.obj", coords, faces, overwrite=True)

现在回到Python,你可以读取修复后的.obj文件,并将它们保存为FreeSurfer的 .surf文件。为了mne.make_bem_model()函数找到它们,需要使用它们的原始名称保存在surf文件夹中,例如bem/inner_skull.surf一定要先备份原来的表面,以防出错!

# Read the fixed surface
coords, faces = mne.read_surface(conv_dir / "inner_skull_fixed.obj")# Backup the original surface
shutil.copy(bem_dir / "inner_skull.surf", bem_dir / "inner_skull_orig.surf")# Overwrite the original surface with the fixed version
# In real study you should provide the correct metadata using ``volume_info=``
# This could be accomplished for example with:
#
# _, _, vol_info = mne.read_surface(bem_dir / 'inner_skull.surf',
#                                   read_metadata=True)
# mne.write_surface(bem_dir / 'inner_skull.surf', coords, faces,
#                   volume_info=vol_info, overwrite=True)

编辑头表面

有时头部表面有缺陷,需要手动编辑。我们使用mne.write_head_bem()将修改的表面转换为.fif文件。

低分辨率的头

对于EEG正向建模,outer_skin.surf可能是手动编辑的。在这种情况下,记得保存从编辑表面文件或配准得到的-head.fif的原始和修改版本。

# Load the fixed surface
coords, faces = mne.read_surface(bem_dir / "outer_skin.surf")# Make sure we are in the correct directory
head_dir = bem_dir.parent# Remember to backup the original head file in advance!
# Overwrite the original head file
#
# mne.write_head_bem(head_dir / 'sample-head.fif', coords, faces,
#                    overwrite=True)

高分辨率的头

我们使用mne.read_bem_surfaces()来读取head surface文件。编辑完成后,我们再次使用mne.write_head_bem()输出头文件。这里我们用-head.fif提高速度。

# If ``-head-dense.fif`` does not exist, you need to run
# ``mne make_scalp_surfaces`` first.
# [0] because a list of surfaces is returned
surf = mne.read_bem_surfaces(head_dir / "sample-head.fif")[0]# For consistency only
coords = surf["rr"]
faces = surf["tris"]# Write the head as an .obj file for editing
mne.write_surface(conv_dir / "sample-head.obj", coords, faces, overwrite=True)# Usually here you would go and edit your meshes.
#
# Here we just use the same surface as if it were fixed
# Read in the .obj file
coords, faces = mne.read_surface(conv_dir / "sample-head.obj")# Remember to backup the original head file in advance!
# Overwrite the original head file
#
# mne.write_head_bem(head_dir / 'sample-head.fif', coords, faces,
#                    overwrite=True)
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目录中使用如下内容:

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中使用网格时可能遇到的一些错误示例,以及这些错误的可能原因。

  1. Cannot decimate to requested ico grade
    错误是由于顶点太少或太多造成的。完整的错误类似于:
RuntimeError: Cannot decimate to requested ico grade 4. The provided
BEM surface has 20516 triangles, which cannot be isomorphic with a
subdivided icosahedron. Consider manually decimating the surface to a
suitable density and then use ico=None in make_bem_model.
  1. Surface inner skull has topological defects
    在试图通过删除顶点来匹配原始三角形数量时,可能会发生此错误。完整的错误信息如下所示:
RuntimeError: Surface inner skull has topological defects: 12 / 20484
vertices have fewer than three neighboring triangles [733, 1014,2068, 7732, 8435, 8489, 10181, 11120, 11121, 11122, 11304, 11788]
  1. Surface inner skull is not complete
    这个错误,和前面的错误一样,反映了表面拓扑结构的一个问题,即预期的顶点/边/面模式被打乱了。
RuntimeError: Surface inner skull is not complete (sum of solid
angles yielded 0.999668, should be 1.)
  1. Triangle ordering is wrong
    这个错误反映了内存中表示曲面的方式(顶点/面定义的顺序)与MNE-Python所期望的不匹配。完整的错误是:
RuntimeError: The source surface has a matching number of triangles
but ordering is wrong
在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后,你可以尝试:

import pymeshfix
rr, tris = mne.read_surface('lh.seghead')
rr, tris = pymeshfix.clean_from_arrays(rr, tris)
mne.write_surface('lh.seghead', rr, tris)

在某些情况下,这可以修复拓扑结构,以便后续对mne make_scalp_surfaces的调用可以成功,而不需要使用--force参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/51685.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙(API 12 Beta3版)【通过字节数组生成码图】

基本概念 码图生成能力支持将字节数组转换为自定义格式的码图。 场景介绍 码图生成能力支持将字节数组转换为自定义格式的码图。 例如:调用码图生成能力, 将字节数组转换成交通一卡通二维码使用。 约束与限制 只支持QR Code生成,根据纠错水平不同对…

【已解决】win11笔记本电脑突然无法检测到其他显示器 / 无法使用扩展屏(2024.8.29 / 驱动更新问题)

我们点击 winx ,找到设备管理器,查看显示适配器: 主要问题就出现在 NVIDIA GeForce RTX 3060 Laptop GPU 上(虽然我把所有驱动都重新更新了一遍😭)。 常用驱动更新: dell 驱动更新&#xff08…

HTML <template> 标签的基本技巧

前言 HTML中的<template>标记是 Web 开发中一个功能强大但经常未得到充分利用的元素。它允许你定义可重复使用的内容&#xff0c;这些内容可以克隆并插入 DOM 中而无需最初渲染。 此功能对于创建动态、交互式 Web 应用程序特别有用。 在本文中&#xff0c;我们将探讨有…

STM32G474采用“多个单通道ADC转换”读取3个ADC引脚的电压

STM32G474采用“多个单通道ADC转换”读取3个ADC引脚的电压&#xff1a;PC0、PA1和PA2。本测试将ADC1_IN6映射到PC0引脚&#xff0c;ADC12_IN2映射到PA1引脚&#xff0c;ADC1_IN3映射到PA2引脚。 1、ADC输入 ADC输入电压范围&#xff1a;Vref– ≤ VIN ≤ Vref ADC支持“单端输入…

顺序表和链表知识点

1 顺序表 顺序表是指用一段物理地址连续的空间去存储数据的线性结构。 顺序表有两种&#xff1a;静态顺序表&#xff0c;动态顺序表。 1.1 静态顺序表结构体定义 typedef int ElemDataSL;typedef struct SequeList {ElemDataSL arr[100];int size; }SL; 静态顺序表在创建结构体…

【 html+css 绚丽Loading 】000026 五行吞灵盘

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽Loading&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495…

网络安全领域含金量最高的5大赛事,每个网安人的梦!

做网络安全一定要知道的5大赛事&#xff0c;含金量贼高&#xff0c;如果你能拿奖&#xff0c;国内大厂随你挑&#xff0c;几乎是每个有志网安人的梦&#xff01; 一、 DEF CON CTF&#xff08;DEF CON Capture the Flag&#xff09; DEF CON CTF是DEF CON黑帽大会上的一项著名…

江协科技STM32学习- P7 GPIO输入

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

数据结构(树、平衡树、红黑树)

目录 树 树的遍历方式 平衡二叉树 旋转机制 左旋 右旋 旋转实例 左左 左右 右右 右左 总结 红黑树 树 相关概念 节点的内部结构如下 二叉树与二叉查找树的定义如下 树的遍历方式 前序遍历&#xff1a;当前节点&#xff0c;左子节点&#xff0c;右子结点 中序遍…

string的模拟实现与深浅拷贝

在上一章中可以看见&#xff0c;string类函数的基本实现和用法&#xff0c;在本文。来用基础的语言来模拟实现string类&#xff0c;来了解一下他们的基础底层&#xff1b; 在VS中string&#xff0c;我们可以看见&#xff0c;实现VS的类成员很多&#xff0c;很麻烦&#xff1b; …

【STM32】电容触摸按键

电容按键就是酷&#xff0c;但据我使用过电容按键版的洗澡计费机子后&#xff0c;一生黑&#xff08;湿手优化没做好的电容按键简直稀碎&#xff09;。 大部分图片来源&#xff1a;正点原子HAL库课程 专栏目录&#xff1a;记录自己的嵌入式学习之路-CSDN博客 目录 1 触摸按…

Zookeeper官网Java示例代码解读(一)

2024-08-22 1. 基本信息 官网地址&#xff1a; https://zookeeper.apache.org/doc/r3.8.4/javaExample.html 示例设计思路 Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection, and the other which monitors data. I…

【C++ Primer Plus习题】7.5

问题: 解答: #include <iostream> using namespace std;int function(int n) {if (n 0)return 1;if (n 1)return 1;return n* function(n - 1); }int main() {int value 0;while (true){cout << "请输入数字:";cin >> value;cout << val…

华为Huawei路由器交换机SSH配置

华为设备的SSH登录配置需要5个步骤&#xff0c;示例如下&#xff1a; 一、配置命令 使能SSH功能 stelnet server enable生成公钥 rsa local-key-pair create 1024配置AAA用户密码及相应授权 aaalocal-user xxx password cipher xxxyyy1234local-user xxx privilege level …

ADB 获取屏幕坐标,并模拟滑动和点击屏幕

本文声明:本文是参考https://blog.csdn.net/beyond702/article/details/69258932编制。同时,补充了在windows系统模式下,详细的获取屏幕坐标的步骤。 1.判断设备与windows电脑USB连接是否正常 在CMD窗口输入命令:ADB devices,按ENTER键,输出如下结果,则表示连接正常。 …

Prometheus+Grafana监控数据可视化

上一篇文章讲了prometheus的简单使用&#xff0c;这一篇就先跳过中间略显枯燥的内容&#xff0c;来到监控数据可视化。 一方面&#xff0c;可视化的界面看着更带劲&#xff0c;另一方面&#xff0c;也更方便我们直观的查看监控数据&#xff0c;方便后面的学习。 Grafana安装与…

DIFFUSION 系列笔记| Latent Diffusion Model、Stable Diffusion基础概念、数学原理、代码分析、案例展示

目录 Latent Diffusion Model LDM 主要思想 LDM使用示例 LDM Pipeline LDM 中的 UNET 准备时间步 time steps 预处理阶段 pre-process 下采样过程 down sampling 中间处理 mid processing 上采样 upsampling 后处理 post-process LDM Super Resolution Pipeline…

Redis基本全局命令

文章目录 get和setkeysexistsdelexpirettltype redis全局命令&#xff1a; redis支持很多种数据结构&#xff0c;整体上来说。redis是键值对结构&#xff0c;key固定就是字符串&#xff0c;value实际上就会有很多种&#xff0c;比如说&#xff1a; 字符串哈希表列表有序集合 …

住宅物业满意度计算方式中满意率和满意度指数的区别

满意率和满意度指数是用于计算住宅物业满意度的两种不同方式&#xff0c;它们的区别如下&#xff1a; 1、满意率&#xff1a;满意率是通过计算满意的居民人数与总参与调查的居民人数之间的比例来衡量满意度。它以百分比形式表示&#xff0c;可以直观地了解居民对物业管理的整体…

集运系统如何多维度展现企业业务情况?

在集运行业&#xff0c;数据是企业决策的重要依据。为了在竞争中保持优势&#xff0c;企业需要一套高效、灵活且可靠的管理工具来应对市场的快速变化。易境通集运系统以其全面而精细的统计报表功能&#xff0c;成为企业决策优化和业务增长的重要助手。 易境通集运系统https://…