许自强,王丽嘉
(上海理工大学健康科学与工程学院,上海 200093)
医学成像技术已经成为越来越重要的诊断手段。随着数据量的爆炸式增长,人们对医学图像处理技术有了更高的要求。以医学图像分割为例,它是计算机辅助诊断的关键步骤,也是整个处理任务耗时较多的一步,现有的分割模型精度并不能满足所有的应用场景[1]。如何让这些不够精确但能够起到一定辅助作用的模型尽快投入使用呢?在医学图像领域,已经出现了一些符合医学数字成像和传输协议(Digital Imaging and Communications in Medicine,DICOM)标准的优秀开源软件,如Sébastien Jodogne等开发的图像归档与传输系统[2-3](Picture Archiving and Communication System,PACS)Orthanc[4],Open Health Imaging Foundation(OHIF)开发的OHIF Viewer[5]等,这些都为解决该问题提供了技术支持。文中提出一种对非全自动化流程可特别支持的,基于Web 的医学图像处理系统。
医学图像处理系统的主要数据对象是DICOM文件,系统除了提供图像归档、图像查看、数据在线访问这些基础功能之外,还应提供一种表示图像处理任务的方法,以便在各子系统之间传递处理任务的信息。考虑到一个完整的图像处理任务可能涉及到人工介入,例如对图像分割质量进行人工确认和对手术方案进行规划,系统还需要提供相应的应用编程接口(Application Programming Interface,API)。通常开发这样的系统至少需要配备软件工程师和算法工程师这两类岗位的人员,软件工程师擅长软件开发,熟悉整个系统的运行机制,能够快速定位系统故障;算法工程师专注于图像处理模块,通常对该模块以外的部分不如软件工程师熟悉。为了设计出易于开发、扩展和维护的系统,需要充分考虑各岗位人员的技术特点。基于上述分析,该系统的功能结构图如图1 所示。
图1 系统功能结构图
各模块具体功能如下:
1)基础功能模块,该模块提供用户登录验证、用户基本信息管理、用户角色管理和数据分组管理等基础功能。
2)图像归档模块,该模块提供DICOM 文件的存储、检索和在线访问功能,为了易与Web 系统和一些现成的工具包集成,该模块需要支持DICOM 标准定义的DICOM Standard for Web-based medical imaging(DICOMWeb)[6-7]接口。
3)图像处理模块,该模块提供医学图像处理功能,由于算法的实现往往依赖复杂的软件环境,且不同算法可能依赖不同版本的软件,大部分软件不支持同时安装多个版本,所以该模块需要支持不同类别的算法使用独立的运行环境。
4)人机交互模块,该模块提供易于用户使用的可视化操作界面,方便用户进行如用户登录、图像查看、图像分割和处理任务提交等操作。
5)任务管理模块:一个处理任务至少包含一个步骤,文中也将处理任务的步骤称为“计算作业”。该模块用于创建、查询和控制用户提交的处理任务和维护计算作业的执行情况。
6)作业调度模块:该模块用于异步和同步执行计算作业;支持按照各个节点的负载情况和作业优先级分配作业;支持启动、查询、中断和结束计算作业的运行;支持对计算节点的管理。考虑到高并发情况,还应支持对计算节点进行横向扩展。
7)文件管理模块:该模块提供文件的在线存取和管理的功能,通常医学图像处理的结果以文件的形式进行表示,对外暴露的结果文件使用该模块进行管理。
在实际的医学图像处理任务中,总是会涉及到人工介入的操作。文中以肝脏手术规划中的图像分割任务为例,肝脏手术规划需要精确分割大部分腹部脏器和肝内管道系统。特别地对于肝内管道系统这类小目标来说,目前开发的全自动分割模型精度常常无法满足实际要求。但是这些分割任务完全依靠人工操作,又非常繁琐和耗时。在这样的背景下,文中将这样的图像分割任务分解为“自动分割”和“手动分割”两部分,“自动分割”表示使用计算机程序对图像进行初步分割,“手动分割”表示人工对自动分割的结果进行二次确认,如果分割结果有错误或者缺少,则人工手动对其进行修正,分割流程如图2 所示。对于任何需要人工介入的操作,都可以使用类似的流程。
图2 有人工介入的图像分割流程
根据功能设计的逻辑结构,将系统划分为前端App、API 网关、Web 后端、PACS、算法后端和调度中心共计六个子系统,系统架构图如图3 所示。
图3 系统架构图
对各子系统的说明如下:
1)前端App:实现系统的人机交互模块,是基于该系统对外开放的API 开发的一组应用。
2)API 网关:是前端和后端通信的桥梁,用于统一管理对外暴露的API。
3)Web 后端:实现系统的基础功能模块、任务管理模块和文件管理模块。
4)PACS:实现系统的图像归档模块。
5)算法后端:实现系统的图像处理模块。
6)调度中心:实现系统的作业调度模块。
这里的前端是广义上的前端,它们通过使用超文本传输协议(Hyper Text Transfer Protocol,HTTP)的API 经过网关与后端通信,既包含了基于浏览器开发的Web App,又包含了原生App和命令行App。该系统目前设计开发两个Web App 和一个命令行App,为了保持界面逻辑的清晰,用两个Web App 分别承担DICOM 图像相关交互和一些其他的图形化交互,它们的代号分别为DICOM Viewer和DICOM Explorer。其中DICOM Viewer 使用TypeScript 语言基于OHIF Viewer 开发,是专门用于处理DICOM 文件的应用,支持DICOMWeb 接口,用于实现DICOM 图像的查看和手动分割功能;DICOM Explorer 使用TypeScript 语言基于Vue3 和Element-Plus[8]开发,实现用户管理、数据集管理、DICOM 文件上传、处理任务提交和数据预览等常规的交互操作。命令行App 的代号为DICOM Uploader,使 用Python 语言开 发,用于解 决DICOM Explorer 上传大批量数据时容易出现的性能问题和实现一些在Web 浏览器中难以实现的功能。
该系统后端有多个子系统,互相通信均使用HTTP 协议,系统将会定义大量HTTP API,一部分API 如作业调度接口,出于安全和性能方面的考虑,应仅供后端内部使用,不对外部开放。除此之外系统还需要路由配置、登录状态检查等功能,该系统使用API 网关来实现。常用的方案有使用NGINX、OpenResty、Kong 和Apache APISIX[9]作为网关,通过性能、易用性、插件支持情况和功能等方面的比较,最终选用APISIX。APISIX 是云原生架构的开源API网关,相较于传统的API 网关,它提供了动态路由、插件热加载等诸多能力,可以为海量API 和微服务提供安全可靠的动态、高性能、可扩展的管理平台。
该子系统基于Kotlin[11]语言和Spring Boot框架[11-12]开发,实现基础功能模块、任务管理模块和文件管理模块这三个模块功能。基础功能模块实现了用户管理和认证功能,并引入数据集概念,将DICOM 图像分配到不同的数据集下,即实现了数据分组管理的功能。文件管理模块实现为所有管理的文件夹和文件分配唯一id的功能,并提供增删改查操作的API。
2.3.1 处理任务类型的表示
系统要能够集成多种类型的处理任务,需要对处理任务的类型进行表示,因此设计了名为PipelineDescriptor 的数据结构,其具体结构如图4 所示。该数据结构的属性及其说明如表1 所示,序号为1-7、8-13、14-17 的分别 是PipelineDescriptor、StageDescriptor、ParameterDescriptor 结构的说明。
表1 PipelineDescriptor属性
图4 表示处理任务类型的数据结构
该系统集成“肝内血管分割”和“肺结节良恶性分析”这两种类型的处理任务作为示例。现给出“肺结节良恶性分析”类型的JSON 格式表示,如下所示:
除了高精度图像分割之外,目前进行如手术规划之类的复杂操作也难以实现完全自动化,均可以通过类似的方式来定义流程。
2.3.2 计算作业所需图像序列的指定
医学图像的采集通常是多模态的,即每个检查(Study)下会采集多个序列(Series)的图像,以“肝内血管分割”类型的处理任务为例,需要对肝静脉、门静脉和肝动脉进行精确的分割,肝静脉通常在静脉期或者延迟期有清晰成像,肝动脉通常在动脉期有清晰成像,所以要完成各类血管的分割,需要在多个序列图像上分别运行相应的分割模型。DICOM标准没有规定如何表示此类期相信息,各影像机构通常利用DICOM 文件的SeriesDescription 标签来记录,由于各机构都使用自己约定的表述方式或者在扫描时由技师随意指定,这种宽松的做法导致在开发图像序列选择程序时可能出现找不到所需序列图像的情况。所以在表示计算作业类型的数据结构StageDescriptor 中,设计了parameters 属性,用于表示该类计算作业需要的参数,用户可以通过这个参数来手动指定所需图像序列。
2.3.3 处理任务与计算作业的存储
在数据库中创建一张名为task 的数据表,用于存储处理任务和计算作业的执行状况,数据表的关键字段及其说明如表2 所示。
表2 task数据表的关键字段及说明
该子系统为所有处理任务及其计算作业都创建一条数据库记录,且非自动计算作业的状态变化必须通过显式调用API 来进行,以此表示用户手动结束非自动计算作业。
PACS 子系统直接选用现成软件,为了便于后期对该子系统进行替换,PACS 子系统与其他子系统通过DICOMWeb接口通信。经比较,开源版本的Orthanc是一个合适的选择,使用PostgreSQL 替换Orthanc 默认的数据库,Orthanc 的性能达到较优的状态[4]。
为了和其他软硬件保持兼容性,该系统充分利用DICOM 标 准,使用Modality 为SEG 的DICOM 文件存储分割结果。并做如下约定,为每种分割类型指定一个id,每个分割实例使用一个DICOM 序列存储,且该序列下仅包含一个实例文件(Instance),并用SeriesDescription 标签记录分割类型id,使用ContentCreateDate 标签和ContentCreateTime 标签记录该分割结果的创建时间。将这个文件导入Orthanc 后,可通过DICOMWeb 接口查询使用。为了以示区分,模型预测的分割类型id 以model_为前缀,目前规定的分割类型id 及其说明如表3 所示。
算法后端子系统专注于数据处理工作,且图像处理程序多用Python 和C/C++开发。由于Python 相对于C/C++,可以很容易地集成其他编程语言的代码,也有成熟易用的异步框架,所以算法后端选择了Python 语言和Celery 框架[13-14]作为主要技术,并以RabbitMQ 作为broker 和backend。算法后端集成的处理作业均以函数的形式对外开放,一个函数即实现一个计算作业。根据不同依赖环境的计算作业必须在不同的组别、同一任务的计算作业必须在同一组别的原则对其分组。如将“肝内血管分割”的两个计算作业编入liver-worker 组,将“肺结节的良恶性分析”的计算作业编入lung-worker 组。上述的liver-worker 和lung-worker 将作 为Celery 框架的两类worker 实例运行,按照配置的优先级,在独立的软件环境中对计算作业进行处理。
使用Celery 的Flower[15]插件对Celery 进行扩展,Flower 是一个基于Web 的监控和管理Celery 集群的开源工具,适合作为该系统的调度中心。Flower 支持HTTP 协议的API,可以方便地与Web 后端子系统进行集成。
该系统通过HTTP API 与外界通信,应当进行全面的测试以保证功能的完整性和系统的安全性,并为每个对外开放的API 编写易理解的文档,该系统选用Apifox 作为API 文档管理工具和API 测试工具。
该系统所有的代码均使用Git 进行版本管理,为了加快开发效率和方便测试,使用Jenkins 进行持续集成,每当有代码提交Jenkins 将自动将其构建为Docker 镜像[16]。由于各组件均构建为Docker 镜像,该系统既可以使用Docker Compose 部署到单机,又可使用Kubernetes 部署到计算机集群,部署工作非常方便。
系统通过将处理任务分解为计算作业的方式,对各种自动化程度的图像处理任务都进行了支持,这可以加速科研成果到产业的转化,具备高度的灵活性和通用性。在实际应用中发现,系统仍有不足之处,即使对Orthanc 的配置进行了优化,部分DICOMWeb 接口还是存在性能问题,这个问题可以尝试使用多个Orthanc 实例负载均衡,或者使用高性能的商用PACS 软件来改善。