RayStation治疗计划系统脚本的初步应用
2013-11-12张建英孙菁王芸
张建英,孙菁,王芸
1 复旦大学附属中山医院放疗科,上海市,200032
2 上海市杨浦区市东医院放疗科,上海市,200438
0 前言
RayStation(RaySearch Laboratories AB)系统是刚进入我国的肿瘤放射治疗计划系统。该系统同时具备其他计划系统中的多种亮点功能,脚本就是其中的典型功能之一。
Pinnacle计划系统(Philips Nederland B.v.)在国内放疗界的应用十分广泛。该系统的基本性能可以在其内含的脚本功能帮助下获得很大的拓展。但是,Pinnacle对基层的单位只提供了脚本的记录和回放功能[1],限制了脚本功能的发挥。
RayStation系统的脚本功能与Pinnacle相比有较大的性能区别。严格意义上而言,RayStation提供的不是一个“脚本”,而是一种方法,通过与Ironpython编程语言结合,利用.NET控件实现对自身系统的控制。
本研究主要通过解决计划射野设计和计划输出两方面的典型问题来探讨在RayStation系统中实现脚本功能的基本方法及需要注意的主要问题。
1 材料和方法
1.1 材料
本研究使用RayStation3.0计划系统,该系统具备常规调强、MCO调强优化功能、形变图象融合配准功能,自适应治疗计划设计、旋转调强计划设计等功能。RayStation在系统安装时,也同步安装了Ironpython2.7编程语言和.NET Framework4.0框架结构。
在RayStation中可以把一系列计划系统操作记录为一个Ironpyhton文件;可以在计划系统中编辑和调试脚本,可以观察脚本执行的细节,可以在脚本管理中将一个Ironpython程序文件导入计划系统;可以将脚本按功能进行分类;可以在脚本使用前进行确认授权;可以将现有的脚本导出系统;在控制台脚本的帮助下,还可以实现脚本和计划系统的数据交互[2]。
RayStation计划系统虽然提供了脚本的记录和回放功能,但使用Ironpython语言编写的脚本,其性能比记录的脚本要强,所以在RayStation中,使用Ironpython直接编写脚本更为常见[3-4]。
RayStation目前并未提供有关脚本的专门手册,可安装目录下ScriptClient文件夹中提供了数个实用工具脚本,其中console.py可以在RayStation系统中调用Ironpython控制台;statetree.py提供了查看当前计划患者的全部对象及其属性和可操作函数(如图1)的方法,也提供了查看当前计划系统用户操作界面的组织关系和操作函数(如图2)的方法;ui-utils.py还提供了在脚本中建立交互界面所需的一些类和函数。在这些工具脚本的帮助下,RayStation计划系统编程的脉络结构就比较清晰地暴露出来。
图1 当前患者全部对象的结构树Fig.2 Structural tree of current patients’ all objects
图2 当前用户界面的结构树Fig.2 Structural tree of current user’s interface
从图1 可以看到,Ray Satation 计划系统中Patient(患者)是一个基本的对象。在这个对象的TreatmentPlans数组(或集合)中有多个TreatmentPlan对象,这些对象可以通过名称调用。TreatmentPlans还有一个AddNewPlan(...)的函数,在面向对象的编程语言中,这实际就是TreatmentPlans对象的一个方法。在图1中的右半部分给出了AddNewPlan(...)函数所需使用的三个参数,分别是PlanName、Comment、ExaminationName,图中还给出了三个参数的具体解释。
从图2中可以看出,计划设计界面有治疗设置控件,其中处方区域有一个DoseVolume的文本框,该文本框的Text属性可以用于输入剂量-体积处方中的体积参数。
RayStation的脚本可以通过调用Patient对象的各函数和改变Patient对象的属性两种方法来达到控制治疗计划的目的。
1.2 方法
本研究将以射野设计和计划输出两方面的典型问题为例进行讨论。
1.2.1 射野设计
射野设计中,经常会使用一些经典的布野方案,如均匀间隔五野或九野方案以及三野加楔形板的方案。以五野为例,计划实践中有时需要五个射野的机架围绕等中心做小幅度旋转,最简单的办法如下:先设计标准射野方案里的第一个射野,然后由记录的脚本完成其他射野的复制,再将各射野的机架角改为所需的数值。其中改机架角的步骤可用Iromnpython脚本(这里假定旋转的角度为15o)完成。
根据图1类似的方法可以查到Pateint对象下具有TreatmentPlans集合,其下又有BeamSets对象,再次一级的对象为Beams集合,每一个Beam对象都具有GantryAngle属性,修改每个射野的机架角实际上就是修改Beam对象的GantryAngle属性的操作。
编写脚本过程中,主要修改语句为“zjy_c=zjy_i.GantryAngle+15”和“zjy_i.GantryAngle=zjy_c”。本研究使用了Ironpython的for循环语句和if条件判别语句,而且继承Ironpython的语法规则区分大小写,在循环内部还需要进行行首的缩进、对齐。脚本第一行通常为“from connect import *”,它建立了脚本内函数和对象与RayStation本身之间的联系。从Ironpython本身的性质来看,RayStation脚本的变量生命周期和作用范围应该局限在脚本内部,这可以在新脚本中查看原来脚本中的变量是否存在来验证,建议尽量以编写者姓名作为变量名前缀,以期望脚本能安全运行。
因为将旋转角度写入了脚本,有必要建立一个交互的输入界面。ui_utlis.py工具中提供了使用脚本建立输入窗体的方法,本研究利用该工具,使用类似“zjy_a1=button('OK')”的方法在窗体中添加了两个按键和一个输入框,使用像“def okClick(sender,args):”这样的语句建立“OK”按键的触发事件,并把改变机架角度的语句直接写入这个事件中,在ui_utlis.py的末尾添加create_window和ShowDialog()函数实现窗体的显示和运行,再直接执行ui_utlis.py就可以实现交互的输入界面,更改机架角。需要特别指出的是,原ui_utlis.py文件在函数window_content中可能存在错误,只有将原函数第5行的([[main_group],[btn_grid]])改为([main_group],btn_grid),本研究中的脚本方法才能实现。
因输入界面的内容写入了改变机架角的脚本,使整个脚本显得比较长,难以阅读,而且输入界面无法用于其他目的的参数输入。在Ironpython中可以把一个函数或类作为一个完整的模块使用,因此可以在一个公用的模块中编写一个提供参数输入的函数,然后在其他脚本中调用这个函数实现参数的输入。在本研究中,“clr.AddReference('System.Windows.Forms')”和“from System.Windows.Forms import *”将Windows窗体的控件引入脚本;使用“def frm_input (frm_title,input_in):”定义输入函数,使用“text=TextBox()”和“frm.Controls.Add (text)”语句在窗体中添加输入控件;使用“input_out=text.Text”结合“return input_out”将窗体控件属性传输给公共输入函数的函数值。
在公共输入函数中,提示输入参数性质的内容可以在整个窗体的标题栏中填写,输入参数的初始值可以在input_in输入变量中给出。在输入过程中,如需放弃输入的内容,通过使用Reset键可以返回初始值,程序退出时,通过input_out变量传回输入值。
为了在Raystation中调用这样的函数,需要把这个脚本放在与statetree.py相同的目录中。事实上这种的函数还可以进一步扩展,比如增加输入内容合法性的检查,使用枚举类型的数据作为输入选项等等。在其他脚本中调用上面的公共输入函数十分简单,如“import input_frm”和“zjy_shift_angle=frm_input("Please input the shift angle for all the beams","0")”即可,其中“import input_frm”用于引用frm_input函数所在的脚本文件input_frm。
在RayStation中,GantryAngle是float类型,而frm_input函数返回的是str类型,需要通过float函数进行转换,具体方法为“float(decimal.Decimal(zjy_shift_angle))”。同样,函数转换时没有提供输入合法性检查,如果frm_input返回的是纯字符,脚本将会报错。
上面的研究工作中使用了两种不同的窗体编程方式。首先使用的是WPF(PresentationFramework),随后使用的是Windows Forms。在实际的脚本编写中,WPF模式窗体的优势是可以在微软公司的Visual Studio Shell中使用 Ironpython Tools可视化编辑窗体各控件,缺点是控件的属性事件和方法的开发还不够完善,但目前微软的开发方向是使用WPF。
1.2.2 计划输出
在放射治疗临床和研究中常常需要对DVH曲线进行评估。尽管每种治疗计划系统几乎都提供了DVH分析工具,但是几乎没有哪种计划系统能满足全部的用户要求。RayStation系统可以用DVH Export curves菜单将DVH曲线输出到文本文件中,但它是把整个DVH以很高的分辨率输出,实际使用起来并不方便。在临床实践中,如研究肝放射性损伤过程,需要获取的是一个计划中受到5 Gy、10 Gy、20 Gy的正常肝的体积。在RayStation中实现这个目标可以有两种基本方法:一是在计划评估中使用Clinical Goals(临床目标)进行设置,二是在 DVH曲线上使用光标逐点测量。无论那种方法,记录结果都是一个比较费时、费力的工作。
在RayStation系统中存在一个Clinical Goals表格。这个表格原来的用途是检查计划是否符合临床处方要求,现可以辅助获取DVH曲线上的数据点。
因此,本研究使用“zjy_ui=connect.get_current("ui")”获得RayStation的运行界面;并使用类似“for i in zjy_Goals_list:”和“zjy_temp1=zjy_GoalTextBlock_ClinicalGoal.Text”获得在RayStation中计划评估界面中ClinicalGoals中一项ClinicalGoal的文本;本研究中还需要使用类似“file_object=open('thefile.txt','w')”和“file_object.write(zjy_temp4.dose+","+zjy_temp4.volume+" ")”语句将获得的结果输入到一个文本文件中。
在RayStation中,为了使用界面的友好,已经把ClinicalGoal的逻辑表达式转换为叙述性的语句如“At most 10.00% volume at 50 cGy dose”,为了把这个语句中对应的剂量提取出来,本研究的脚本中大量使用了字符串处理函数,如split、len、find等,目的都是为了从文本中提取必要的数值。前提是,需要提取的剂量体积关系必须事先以模板的形式在Clinical Goal中设置,且只能存在一个器官的剂量体积关系,如果需要提取不同器官的参数,则要设置判断器官名称的相应语句。这样的方法需要在特定的窗体界面下使用,否则会出现部分用户界面对象不存在的错误。
尽管上述方法已经可以实现临床目的,但使用起来界面并不够友好,并没有充分使用Ironpython语言结合.NET框架结构的性能,同时作为Patient对象的函数功能还没有得到应用。为充分显示RayStation的性能,本研究编写了RayStation的一个插件功能的综合脚本,这个脚本部分使用了微软公司的可视化开发工具和Python Tools。
综合脚本的运行界面如图3所示。
图3 综合运行界面Fig.3 Integrated running interface
综合脚本中定义了脚本自己的对象(point,指向DVH曲线上的一个点);脚本调用了可视化编辑的窗体布局,这个布局存放于planoutput.xaml文件中;脚本使用了标准的窗体对话框来输入保存输出结果的文件名称;脚本运用了窗体控件的数据绑定;还使用Patient对象中的感兴趣区域对可选列表进行数据填充;最后脚本还调用TotalDose的GetDoseAtRelativeVolumes()函数计算出了相对体积所对应的剂量。本研究只计算出了对应相对体积的剂量而没有计算出对应剂量的相对体积,但这解决起来相对较易。
2 结果
本研究中,对RayStation脚本的使用主要体现在两个方面。一是利用系统中Patient对象和ui对象的属性和函数(方法),直接干预计划本身的数据和计划操作,达到修改和控制计划的目的;二是充分运用Ironpython语言的特性,结合.NET的支撑,在脚本中实现计划系统与操作系统的数据交换。
本研究并没有盲目使用工具脚本。工作中也曾发现工具脚本中存在语法错误,也需要进行调试,象statetree.py这样的工具脚本,在Ironpython中尚是一个module(模块),还需在其他脚本中进行引用,再调用CreateStateTreeWindow函数建立窗体,ShowDialog显示窗体才能最终获得当前Patient对象的结构树。
由于工具脚本仅能提供当前对象的信息,如果当前对象没有相关的属性,工具脚本并不能充分发挥作用。在本研究中,设置了一个范例计划,在这个范例计划上尽可能多地使用了RayStation系统的各种功能,然后用工具脚本获取了范例脚本的Patient对象和ui对象尽可能详细的资料来辅助脚本编写。
在典型解决问题的过程中,与Pinnacle计划系统脚本不同,在Ironpython环境中运用变量、数组、集合,使用条件判别、类型转换,使用循环等等都不再是技术问题,而作为面向对象编程常使用的诸如类、对象、属性、数据绑定等等方法在本研究中的脚本中也可以顺利实现。因此,脚本的编写实际上也是Ironpython语言编程过程。
3 结论
结果提示,在工具脚本的帮助下,通过Ironpython的脚本编程,完全可以在RayStation中开发并使用脚本扩展RayStation系统,实现原系统不具备的一些功能。
从根本上而言,本研究只是在RayStation中应用脚本的初步研究,所涉及到的问题和方法比较简单,利用工具脚本所获得的RayStation中的对象和函数也比较局限,目前的研究结果也部分揭示了RayStation脚本运用的前景。
Ironpython作为一种编程语言,和现在很多工具软件具有良好的接口,这些软件包括微软办公软件Office、数学工具Matlab、文档工具Adobe Reader等等。这些软件在使用脚本扩展RaySatation性能方面发挥重要的作用。比如,通过Office的帮助,RayStation系统可以直接读取Word或Excel格式的计划处方文件,并将其导入系统作为计划评估的参数;可以在脚本中使用Matlab进行计划的再优化,甚至自行开发优化算法而将RayStation作为剂量计算引擎;可以使用脚本将以PDF格式保存的计划报告通过FTP直接向网络系统推送等等。从这个角度上看,RayStation脚本可以扩展的广度是很大的。今后RayStation脚本的应用也应该向这几个方向拓展。
尽管如此,RayStation的脚本也并不能解决所有的问题。由于RayStation没有提供脚本操作手册,有些对象也不能控制自如,像控制图像显示的控件Corevtkcontrol就是如此,该控件在计划系统中作用很大,多数图象处理需要使用这个控件,关于这个控件详细信息从工具脚本中不能得到,因此也就不能通过脚本实施相关图象处理的操作了。
在本研究中可以看到,脚本功能虽然强大,但是脚本的使用中会出现合法性检查和容错性能的问题,也会出现单线程和多线程的问题,而且脚本功能越强大,这样的问题就越突出。在临床实际使用脚本的时候,需要认真检查脚本对计划系统的每个操作,确保脚本的使用对RayStation本身不会产生安全影响。
限于本文篇幅,涉及的完整脚本未在文中列出,可通过邮件向作者索取。
[1]Pinnacle3 Planning reference guide[M].Fitchburg USA:Philips Medical System,2008.
[2]RayStation 3.0 Reference Manual[M].Stockholm,Sweden:RaySearch Laboratories AB,2012.
[3]Mueller JP.Professional IronPython design and develop IronPython techniques[M].Indiana,USA:Wiley Publishing Inc,2010.
[4]Foord MJ,Muirhead C.IronPython in action[M].Greenwich,CT,USA:Manning Publications Co,2010.