目录
8.创建完成之后你的moudle已经加载到了Slicer中,其中的机制是什么?
一、3Dslicer中的Extension Wizard
3D Slicer 中的 Extension Wizard 用于创建 3D Slicer 的扩展项目,并提供了一些初始的项目结构。以下是 Extension Wizard 新建的拓展项目中包含的主要内容:
CMake 文件:包含了用于构建和配置项目的 CMakeLists.txt 文件。CMake 是用于管理跨平台项目的工具,用于生成项目的构建文件。
模块代码:包含了扩展的源代码文件。这些文件可能使用 C++ 或 Python 编写,具体取决于你选择的扩展类型。
模块类和接口定义:包含了定义扩展模块类和接口的头文件。
图标和资源文件:包含了扩展可能使用的图标和其他资源文件。
CMake 扩展宏:包含了一些用于配置和构建 3D Slicer 扩展的 CMake 宏,这些宏简化了构建和安装过程。
测试数据文件:包含了一些测试数据文件,用于在测试期间验证扩展的功能。
文档文件:包含了一些用于描述和文档化扩展的文档文件。
模块描述文件:包含了描述模块的信息,如名称、版本、作者等的模块描述文件。
构建目录和输出目录:包含了构建时生成的中间文件和最终输出文件的目录。
二、了解Extensions
官方文档:
https://slicer.readthedocs.io/en/latest/developer_guide/extensions.html
官方其实介绍的很少,我们先跟着官方文档的顺序来:
Step-by-step: How to create, publish, distribute and maintain an extension ?(一步一步来实现)
a. Scan through the user and developer extension FAQs(即开发者扩展的常见问题解答 (FAQs)就是你要先去了解整个软件和Extension一些常见问题,逛逛社区啥的,那些网址都 有官方维护,在我另一篇介绍3DSlicer的文章中。)
b. Inform a community about your plans on the Slicer forum to get information about potential parallel efforts (other developers may already work on a similar idea and you could join or build on each other's work), past efforts (related tools might have been available in earlier Slicer versions or in other software that you may reuse), and get early feedback from prospective users. You may also seek advice on the name of your extension and how to organize features into modules. All these can save you a lot of time in the long term.(先在Slicer forum上发表你关于自己extension的想法,看看有没有跟你做类似工作的人,或者你的extension的思想别人已经做过,你可以用别人开发好的工具,另外你也可以获取到很多关于你extension设计的建议)
c. If you have not done already, use the Extension Wizard module in Slicer to create an extension that will contain your module(s).(官方建议直接使用Extension Wizard来创建Extension,这样可以省去很多搭建项目上的麻烦)
d. If developing C++ loadable or CLI modules (not needed if developing in Python):
build Slicer application.
build your extension
To build extensions that contain modules implemented in C++, you need to build Slicer from source on your machine; they cannot be built against a binary download. If developing modules in Python only, then it is not necessary to build the extension.(如果你想要开发loadable或者CLI类型的模块的话,你需要自行对slicer从源码进行编译,{并且编译版本得是Release版,因为你开发的模块需要用到很多Release版的库}这个说法有待验证,官方现在只说了要Build没有强调必须编译Release版本;对于Python 类型的模块,直接在slicer的二进制形式的发行版上开发就行了,这里理解为Python作为一种脚本语言的强大性,后面会说到这些不同的Extension项目的区别)
也就是你要看你要实现的功能是不是别人已经实现了,或者正在做,然后如果真的没有的话,就开始自己创建一个基于3DSlicer的新Extension来实现要实现的功能。
三、环境准备和注意事项
1. 环境
3DSlicer5.6.0
Pycharm22.03
win11
2. 3DSlicer中的数据结构(MRML)
“MRML node”内存中的3DSlicer管理的某些数据元素
“MRMLscene”3DSlicer的MRML节点的所有实例的集合
MRML = Medical Reality Markup Language(医学现实标记语言)
用于在磁盘上序列化MRML场景的基于XML的格式(.MRML文件)
这里突然开始介绍MRML这个东西,解释为一种3DSlicer管理的数据结构,在3DSlicer中选择data->勾选show mrml,然后可以通过Python Console来获取这些数据,这应该就是在逻辑类中怎么通过接口获取到MRML数据并且处理它的方法。
下图是通过Python Console来获取这些数据,然后输出,这就是我们在代码中能从3DSlicer拿到的数据,非常重要,因为我们几乎实现的功能都是围绕它作为数据起点。
3.python的一些规则
由于3DSlicer创建的项目要么是C++要么是Python来开发,而且更加偏向于Python,所以这里先介绍提醒一些python的注意事项,也是再告诉大家,需要有Python的基础。
缩进非常重要!似乎Python没有分号,是根据缩进来判断代码执行逻辑的 |
所以使用空格,而不是TAB! |
类方法总是包含self作为第一个参数 |
注释单行用# |
3级以及之上的的多行注释用”(“”“注释”“”) |
四、创建Extension
1.创建扩展教程参考:
https://www.slicer.org/wiki/Documentation/4.10/Training#Tutorials_for_software_developers
上面的链接是维基百科上的有人做的一些参考资料,看完了文档,我们跟着这些教程和资料,来创建Extension吧。
2.勾选开发者模式
3.点击Create Extension
这里可以看到很多个选项,创建的项目中,这是针对不同的开发需求选择的种类,为了方便大家理解,我全部试了一遍,可以一起看看区别
简要解释一下:
-
命令行界面(CLI) 1.有限的交互性
2.无法直接访问切片器核心
3.不直接操作用户界面
4.通过预定义接口(切片器执行模型或SEM)进行通信*
已编写脚本(Scripted) 1.Python(开发起来容易多了!)
2.可以访问Slicer的大部分内部 3.只能访问Python中封装的内容(没有DCMTK、ITK)
可装载(loadable) 1.对所有切片器API的完全访问
2.C++,但可以包括Python代码
4.填写一些你项目信息,路径,然后ok,自动生成了文件
5.创建完成之后,可以看看扩展包的文件分别包含了些什么文件
CMakeList.txt文件之中不能随意修改,否则就无法连接上slicer服务,暂时认为是和slicer读取moudles有关。
6.创建之后的Extension展示
我们可以对比一下这个UI,然后已经嵌入到了3DSlicer的左边的界面之中,上下分别都有父类窗口的一些控件,中间是自己可以控制的UI界面
7.脚本文件(.py)
可以看到我们都是操作MRML节点,再次印证了3DSlicer接口传出我们获取的数据结构就是这个
.py文件中一共有这么几个类,每个类的作用依次解释一下
class LineIntensityProfile(ScriptedLoadableModule):
"""
基础信息初始化
"""
class LineIntensityProfileParameterNode:
"""
模块所需的参数。
inputVolume-要设置阈值的音量。
imageThreshold—设置输入音量阈值的值。
inverteThreshold-如果为true,将反转阈值。
thresholdedVolume-将包含阈值音量的输出音量。
invertedVolume—将包含反转阈值体积的输出体积。
"""
class LineIntensityProfileWidget(ScriptedLoadableModuleWidget, VTKObservationMixin):
"""
主要的窗口界面显示。
可以完成各种界面设置和设计以及连接LineIntensityProfileLogic
可在https://github.com/Slicer/Slicer/blob/
main/Base/Python/slicer/ScriptedLoadableModule.py
"""
class LineIntensityProfileLogic(ScriptedLoadableModuleLogic):
"""
此类应实现所有实际逻辑处理和模块完成的计算。
接口应该使得其他python代码可以导入这个类并使用该功能,
而不需要Widget的实例,就是没有界面的纯逻辑代码,
继承自ScriptedLoadableModuleLogic基类,
"""
class LineIntensityProfileTest(ScriptedLoadableModuleTest):
"""
用于测试module。
这是脚本化模块的测试用例Uses ScriptedLoadableModuleTest基类
"""
8.创建完成之后你的moudle已经加载到了Slicer中,其中的机制是什么?
待补充。暂时认为是LineIntensityProfile这个基类做了初始化,而且信息是存在一些文件中的。
9.修改及开发Extension,实现功能
我们就简单的修改一下这个文件吧,加一个button之后给它一张图片作为Icon
更改之后,重新打开3DSlicer,重新加载你的module,然后就可以看到变化。
修改之前:
修改之后:
五、总结
总体就是创建了一个项目之后,功能实现的话还是去学习一些python用法,以及调用的3DSlicer的接口的使用,才能帮助我们开发出我们自己想要的Extension,可以多上上社区,毕竟开源项目大家一起讨论才是出路。
我现在才明白3DSlicer支持Python的notebook一样的功能是什么意思,它的python console能输出你的module中py代码的结果,也就是出错它会给你抛出,就相当于在3DSlicer中可以调试你的代码,但是现在不太清楚修改好了代码,怎么样才能重新在3DSlicer中加载module呢,现在的方法是关了3DSlicer之后重新打开(待补充)
这篇文章就写到这里,主要的重点就是后续的利用python开发你需要的功能,在之后的时间我会补充后续的Test以及打包发布等步骤,我有机会也会分享一些实际开发中的问题和实现,敬请期待!