1.循序渐进的脚本模块
脚本模块是采用Python编写的。
1.1 使用ModuleWizard的模板创建Scripted Module
参考:
https://na-mic.org/wiki/2013_Project_Week_Breakout_Session:Slicer4Python
https://www.slicer.org/wiki/Documentation/Nightly/Developers/ModuleWizard
声明:
在Slicer4.4以及之后的版本,ModuleWizard被弃用了,官方建议使用ExtensionWizard。
以Mac平台为例进行讨论,这些步骤对于所有平台都是通用的。
Slicer在不同平台上构建说明与指令参考如下:
https://www.slicer.org/wiki/Documentation/Nightly/Developers/Build_Instructions
我们以一个简单的脚本模块作为示例做一个拓展。可以在Slicer源目录中运行下面命令:
1 ./Utilities/Scripts/ModuleWizard.py \
2 --template ./Extensions/Testing/ScriptedLoadableExtensionTemplate \
3 --target ../VolumeTools VolumeTools
我们把这个拓展起的名是VolumeTools,因为我们用它实现脚本模块的功能:在当前场景中滚动立体。
现在,我们想把脚本模块嵌入到这个扩展中,需要执行以下命令(仍然在Slicer源目录):
1 ./Utilities/Scripts/ModuleWizard.py \
2 --template ./Extensions/Testing/ScriptedLoadableExtensionTemplate/ScriptedLoadableModuleTemplate \
3 --target ../VolumeTools/VolumeScroller VolumeScroller
注意:我们使用了Module模板,module模板位于Extension模板中。
因为这个模板包括了一个stand-in脚本模块(替身脚本模块?),我们希望删除这个stand-in模块,然后告诉CMakeLists.txt使用我们新创建的VolumScroller模块。我们也需要去清理dummy模块(虚拟模块?)。在unix平台上执行以下命令:
1 rm -rf ../VolumeTools/ScriptedLoadableModuleTemplate
2 perl -pi -e 's/ScriptedLoadableModuleTemplate/VolumeScroller/g' ../VolumeTools/CMakeLists.txt
注意:我们将来要手动编辑CMakeListsy.txt,因为它包括了扩展的所有元数据,如作者、类别、文档URL等。
我们现在需要测试我们的模块,最简单的方法就是利用命令行指定路径,如:
./Slicer-build/Slicer --additional-module-paths ../VolumeTools/VolumeScroller
上面的路径是假设你处在当地构建目录——Slicer-superbuild目录中,但是,我们用启动Slicer替换这个路径。
利用模板创建的初始化模块
接下来,我们就可以开启脚本模块的编程之路。
1.2 理解脚本模块的结构
再编程之前,花一点时间浏览模板还是值得的。模板代码就300多行,其中大多数是引用,所以实际应用过程中只需要进行小小的改动就好了。其他部分需要彻底的更改,因为我们要实现从模板到实际功能的转变。
模板中类定义如下:
注意:使用ModuleWizard/ExtensionWizard之后,字符串“ScriptedLoadableModuleTemplate”会替换成“VolumeScroller”。
- https://github.com/Slicer/Slicer/blob/master/Extensions/Testing/ScriptedLoadableExtensionTemplate/ScriptedLoadableModuleTemplate/ScriptedLoadableModuleTemplate.py#L9-34 ScriptedLoadableModuleTemplate是我们定制模块元数据的地方。注意:我们的测试代码在这里初始化。传递parent给构造函数,而parent是SlicerScriptedLoadableModule的实例。
- ScriptedLoadableModuleTemplateWidget定义了模型的GUI。通过传递qSlicerScriptedLoadableModuleWidget的实例给构造函数(C++的钩子)
- ScriptedLoadableModuleTemplateLogic就是一个辅助类,定义算法的应用和我们需要的其他辅助函数。按照惯例,这个类不应该引用任何GUI元素。
- ScriptedLoadableModuleTemplateTest is a subclass ofa standard python unittest TestCase. Note that this class responds specially to methods whose names start with the string "test", so follow the pattern of the template when adding test functionality.
1.3 基本的开发周期
作为一个学习的例子,让我们在运行时的环境中操纵我们的窗口部件。这是Slicer中Python脚本模块非常强大的特征。
首先,打开Python控制台:View->Python Interactor
在控制台中,我们访问下面对象:slicer.modules.VolumeScrollerWidget
这是我们窗口模块部件的实例。注意:控制台我们已经配置好,使用它我们可以访问接口的任何字段,甚至操纵这些字段。看着接口时,可以尝试下面代码:
1 b = slicer.modules.VolumeScrollerWidget.applyButton
2 b.enabled = True
3 b.down = True
4 b.down = False
5 b.clicked()
注意:“clicked()”如何触发“Run the Algorithm”消息?这是因为对于按钮而言,点击相当于一个信号signal,它连接着Python的一个调用,这是脚本模块的一部分。
1.重载和测试可折叠盒子
注意两个大按钮“Reload”和“Reload and Test"按键,在开发的过程中还是很有用的:
Reload:
- 移除当前模块GUI的实例
- 重载Python源代码
- 在先前的位置在创建一个GUI
- 更新slicer.modules.<moduleName>Widget,指向新的实例
Reload and Test:
默认情况下,测试将会下载一个示例数据集并确认该数据集已经被加载。后面仍然会讨论测试的内容。
2.Reloading
https://na-mic.org/wiki/2013_Project_Week_Breakout_Session:Slicer4Python
1.4 完善的功能
此时,写代码实现我们想要的功能是一个简单的事。我们不需要一行一行地浏览代码,只需要在每一步更换block-by-block来测试功能。
2.Python脚本模块设计:超越基础
包括Widget的应用、Logic、MRML 类,使用MRML节点存储模型参数
3.Module Factory
加载模块分成许多步骤:
- module factories 必须注册到 factorymanager中
- 下载模块后的目录必须传递给factory manager
- 将模块与场景和应用连接
4.MRML节点与模块之间的联系
模块可以与MRML节点进行关联,例如,这种关联关系允许模块编辑确定的MRML节点。模块既可以通过重写 qSlicerAbstractCoreModule::associatedNodeTypes()方法指定节点类型列表,也可以通过调用qSlicerCoreApplication::addModuleAssociatedNodeTypes()关联任何模块的任何节点。
多个模块可以与同一个MRML节点类型相关联。