1.复习MRML类型
MRML,Medical Reality Markup Langguage,数据类型可以独立于系统可视化和算法部分执行。
MRML Scene数据对象包含了Slicer应用程序的状态、原始数据、可视化参数等诸多数据。每一个数据类型由特定的MRML Node来表示。MRML Scene实际上就是MRML Nodes的集合。
对于MRML数据类型,Slicer附带了相应的方法进行操作。例如对其中的MRML Node进行Add、Delete、Select、Undo、Redo等。这些方法统称为Slicer的MRML库,其API函数就是用来对MRML Scene数据进行操作的。其他的组件,如Logic和GUI,一直在见识MRML Scene的变化,一旦MRML Scene发生了任何形式的操作,那么Logic、GUI就会产生相应的操作。
2.工作目录
开发前熟悉源码以及算法库的分布是很有必要的。在使用CMake配置Slicer工程前,需要指定三个目录:
- Slicer源代码文件夹
- 目标生成文件夹
- Qt库文件夹
2.1 工程目标目录结构
3Dslicer是在大量开源库(ITK、VTK、CTK、DCMTK)的基础之上开发的,所以编译3Dslicer的时候我们一定会和这些算法库打交道。庆幸的是,我们并不需要逐个一一下载!3Dslicer在编译的过程中,会通过网络自行下载各个库的源代码,并临时进行编译,所以Slicer工程目标目录就会包含这些开源算法库的源代码文件夹和编译后的文件夹。
以经典算法库BRAINSTools工程为例,其编译后对应各个文件夹,如下:
- BRAINSTools:存放Git/SVN获取的源代码
- BRAINSTools.dir:存放编译日志
- BRAINSTools-build:存放编译后的目标文件
- BRAINSTools-prefix:存放下载源代码的配置文件
像BRAINSTools这样的工具包还有cmcurl、CTK、DCMTK、EMSegment、ITKV4、jqplot、LibArchive、MultiVolumeExplorer/MultiVolumeImporter、NUMPY、OpenIGTLink/OpenIGTLinkIF、python、qRestAPI、SlicerExecutionModel、tcl、teem、VTK、zlib等19个,没事多翻翻源码总是有好处的。
Slicer-build文件夹是真正存放Slicer软件编译后的二进制代码目录,也是最关键的。使用Visual Studio打开Slicer.sln就可以清楚整个工程的子工程(>500)。
2.2 应用程序源码目录结构
Slicer的源码存放很有规律,方便浏览。在源代码目录.../Slicer下有众多子目录,每一个子目录代表一个特点的功能子集。
- Applications:该目录下包含一个子目录SlicerApp,该子目录中的源码用于Slicer软件平台的框架,包括Main.cxx和主界面创建的源代码。
- Base:实现Slicer的基础功能,包括CLI、Logic、Python、QTApp、QTCLI、QTCore、QTGUI等子目录。其中,CLI实现命令行模块功能;Logic实现数据处理的逻辑顺序、Python实现ITK、VTK算法的Python功能;QTApp帮助创建主界面;QTCLI创建命令行模块界面;QTCore实现程序的文件管理等基础功能;QTGUI实现绝大多数的工具栏、程序设置界面。
- CMake & SurperBuild: 存放程序编译过程中需要使用到的*.cmake文件。
- Libs:Slicer不仅仅使用了其他文件包中的库文件,还定义了很多函数库,都存放在该目录下。
- Modules:所有类型模块的源代码。
- Resource:存放资源文件,如HTML、icon、audio等。
2.3 CMakelist.txt分析
CMake可以根据不同平台、不同编译器生成相应的Makefile或者vcproj(Windows)项目。通过编写CMakeLists.txt可以控制生成的Makefile,从而控制编译过程。
CMake自动生成的Makefile不仅可以通过make命令构建项目生成文件,还支持make install安装、make test测试安装程序、make package生成当前平台的安装包、make package source生成源码包、产生Dashboard显示数据并上传等高级功能。所以说只要在CMakeList.txt中简单配置,就可以完成很多复杂功能。
Slicer源代码中,每一个目录以及其子目录中,都会存在一个CMakeList.txt文件,该文件就是CMake程序配置Slicer工程的关键。CMake通过读取CMakeList.txt中的代码从而得知编译该目录中的代码需要什么编译器进行编译,需要什么库进行链接。