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

news/2024/9/19 5:36:35/ 标签: python, 信息可视化, 笔记, 学习, numpy

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

python">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的新文件夹来保存它们。

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

python">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一定要先备份原来的表面,以防出错!

python"># 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的原始和修改版本。

python"># 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提高速度。

python"># 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后,你可以尝试:

python">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.ppmy.cn/news/1518932.html

相关文章

网络安全售前入门05安全服务——渗透测试服务方案

目录 1.服务概述 2.测试内容 2.1网络层安全 ​​​​​​​2.2系统层安全 ​​​​​​​2.3应用层安全 3.测试范围 4.漏洞分级 5.渗透用例 6.测试风险 6.1风险说明 ​​​​​​​6.2风险规避 ​​​​​​​​​​​​​6.3数据备份 7.服务输出 1.服务概述 渗透…

从0到DevOps(1)-初步了解DevOps和容器

DevOps从提出以来陆续成为行业普遍实践,目前是数字化生产普遍不可或缺的信息底座。本系列文章旨在系统性的阐述与认识DevOps, 了解企业实践里DevOps的实际面貌。 什么是DevOps? DevOps 是一套实践、工具和文化理念,为实现用户不断的软件功能和可用性要…

使用Python写贪吃蛇游戏

贪吃蛇游戏是一款经典的小游戏,玩家通过控制蛇的移动来吃食物,蛇的身体会随着吃到的食物越来越多而变长。本文将介绍如何使用Python来创建一个简单的贪吃蛇游戏。 代码解析 1. 设置窗口 首先,我们需要设置游戏窗口。使用 turtle.Screen() 创…

streamlit+wordcloud使用pyinstaller打包遇到的一些坑

说明 相比常规的python程序打包,streamlit应用打包需要额外加一层壳,常规app.py应用运行直接使用 python app.py就可以运行程序了,但streamlit应用是需要通过streamlit命令来运行 streamlit app.py所以使用常规的pyinstaller app.py打包是…

(备份)常用ASCII 8*8 点阵 以及查询显示字符的点阵

图片 #include "driver/spi_master.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "string.h" #include "driver/i2c.h" #include "esp_rom_sys.h"…

Java分布式架构知识体系及知识体系图

Java分布式架构整体知识体系是一个庞大而复杂的领域,它涵盖了多个方面,旨在帮助开发者构建高性能、高可用、可扩展的分布式系统。以下是对Java分布式架构整体知识体系的概述: 一、分布式理论基础 CAP理论: 一致性(Con…

Java算法之Gnome 排序

简介 Gnome 排序,又称为双向插入排序或鸡尾酒排序,是一种改进的插入排序算法。它在每次迭代中不仅将最小的元素移动到前面,同时也将最大的元素移动到后面。这种排序算法在每次迭代中同时向两个方向进行移动,因此得名。 算法步骤…

如何开发针对不平衡分类的成本敏感神经网络 python

如何开发针对不平衡分类的成本敏感神经网络 深度学习神经网络是一类灵活的机器学习算法,可以在各种问题上表现良好。 神经网络使用误差反向传播算法进行训练,该算法涉及计算模型在训练数据集上产生的误差,并根据这些误差的比例更新模型权重…

240831-Qwen2-VL-7B/2B部署测试

A. 运行效果 B. 配置部署 如果可以执行下面就执行下面: pip install githttps://github.com/huggingface/transformers accelerate否则分开执行 git clone https://github.com/huggingface/transformers cd transformers pip install . accelerate随后&#xff0…

k8s-pod 实战一 (创建pod,启动命令,参数,pod故障排除,拉取命令)

1. 创建一个Pod Pod 是 Kubernetes 中最小的部署单元。它可以包含一个或多个容器。下面是一个简单的 YAML 文件,用于创建一个包含 Nginx 容器的 Pod。 示例 YAML 文件 (nginx-pod.yaml) apiVersion: v1 kind: Pod metadata:name: nginx-pod spec:containers:- name: nginx-…

STM32(八):定时器——输入捕获实验

目录 输入捕获模式测频率: 结构图: 步骤: 部分函数详解: 源码: PWMI模式测频率占空比: 结构图: ​编辑 举例说明 源码: 输入捕获模式测频率: 结构图&#xf…

C#中List集合使用Remove方法详解——List使用Remove方法需要注意的坑?

目录 一、基本使用 1、简单类型的例子 2、复杂类型的例子 二、思考 三、深度解析 四、正确的使用方式 1、重写 Equals 和 GetHashCode 2、使用 LINQ 的 FirstOrDefault 方法 五、性能考虑 六、注意事项 总结 在C#中&#xff0c;List<T> 是一个常用的数据结构&…

第四章 Java核心类库 第三节 集合框架

1. 集合框架概述与结构 首先&#xff0c;我们来简单了解一下Java集合框架的概述和结构。 集合框架的定义&#xff1a;Java集合框架是一组用来存储和操作数据集合的接口和类。它提供了一种统一的标准方法来操作不同的数据集合&#xff0c;极大简化了编程任务。 集合框架的结构…

我的电脑/资源管理器里无法显示新硬盘?

前情提要 我新&#xff01;买了一个京东京造的SATA3硬盘&#xff0c;一个绿联的SATA3转USB读取 现在我的电脑里只能显示我本地的C盘和D盘&#xff0c;不能显示这个接入的SATA盘。 系统环境&#xff1a;windows11 问题描述 在我的电脑里&#xff0c;只能看到我原本的C和D&…

互联网平台大模型网络架构设计

字节跳动&#xff1a;大模型网络实践分享 自2019年起&#xff0c;字节跳动公司便开始着手白盒项目。2020年&#xff0c;推出了首款接入交换机——25G型号&#xff0c;随后逐步实现软硬件的自主研发。在当前一代产品中&#xff0c;已经实现了100G接入、25.6T400G互联&#xff0c…

扩展——双向搜索

1. 基本概念 单向搜索&#xff1a;传统的搜索算法&#xff08;如广度优先搜索 BFS、深度优先搜索 DFS&#xff09;通常从起点开始&#xff0c;逐步扩展搜索到目标节点。搜索的时间复杂度与图的大小和结构有关。 双向搜索&#xff1a;双向搜索则同时从起点和终点进行搜索&#…

分享8个Python自动化实战脚本!

1. Python自动化实战脚本 1.1 网络自动化 网络上有丰富的信息资源&#xff0c;Python可以帮我们自动化获取这些信息。 爬虫简介&#xff1a;爬虫是一种自动提取网页信息的程序。Python有许多优秀的爬虫库&#xff0c;如requests和BeautifulSoup。 案例&#xff1a;使用Pytho…

软件测试学习笔记丨静态测试与代码审计 SonarQube

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32049 一&#xff0c;SonarQube 平台搭建 1.1&#xff0c; 介绍 Sonar 是一个用于代码质量管理的开放平台。通过插件机制&#xff0c;Sonar 可以集成不同的测试工具、代码分析工具&#xff…

Having trouble using OpenAI API

题意&#xff1a;"使用OpenAI API遇到困难" 问题背景&#xff1a; I am having trouble with this code. I want to implement AI using OpenAI API in my React.js project but I cannot seem to get what the issue is. I ask it a question in the search bar in…

大语言模型数据增强与模型蒸馏解决方案

背景 在人工智能和自然语言处理领域&#xff0c;大语言模型通过训练数百亿甚至上千亿参数&#xff0c;实现了出色的文本生成、翻译、总结等任务。然而&#xff0c;这些模型的训练和推理过程需要大量的计算资源&#xff0c;使得它们的实际开发应用成本非常高&#xff1b;其次&a…