Dicoogle——开源的PACS存档系统(1)

一、基本介绍:

1、Dicoogle介绍:

Dicoogle是一个可扩展的、跨平台的、开源的PACS存档软件,它使用可插拔的索引和检索机制代替了通常是硬编码的传统集中式数据库,后者是独立开发并在部署时安装的。

2、Dicoogle支持的传输协议:

  • 基于DICOM3.0协议的数据传输;

3、Dicoogle支持的通信协议:

  • 支持基于TCP/IP的通信协议,Dicoogle底层使用NIO实现;
  • 支持基于HTTP通信协议;

4、Dicoogle的优点:

  • 可扩展:基于插件的架构、简单的安装和部署;
  • 提供了用于存储、查询/检索的DICOM服务;
  • REST Web:提供了与现代浏览器兼容的Web应用程序;
  • 开源:平台无关(Windows、Linux、Mac),符合GPL v3开源许可;

5、Dicoogle的缺点:

  • 源码提供的存储、索引能力相对单一,需要开发插件:
  • 通信连接、数据传输不稳定,需要进行优化;
  • 社区活跃度低,相关文档较少;

6、Dicoogle提供的存储能力:

Dicoogle通过插件的方式提供可扩展的存储能力。Dicoogle默认提供了基于文件系统的存储,文件系统的存储插件是filestorage.jar,官网可下载源码。Dicoogle通过Storage API(StorageInterface)对存储技术进行接口抽象,使用者可以根据自己的业务场景定制数据存储源,无论使用哪种存储技术,都可以通过通用API实现对DICOM对象的读取和存储。出于存储的目的,默认的文件存储插件将DICOM文件依照(Patient->Study->Series->Image)层次结构存储到文件系统中。

7、Dicoogle可扩展的文件存储领域:

  • 分布式文件系统,如:IPFS;
  • 云存储,如:Amazon S3;
  • 文档数据库,如:MongoDB、CouchDB;

8、Dicoogle的查询/索引能力:

Dicoogle通过插件的方式提供查询/索引能力。Dicoogle默认提供基于Apache Lucene插件实现查询/索引,支持对DICOM元数据的索引和查询,可以对影像的所有元数据建立索引,并通过关键字和范围很方便的进行查询。也可以通过自定义插件将医学影像图像及元数据存储在云服务器上并由关系型数据库建立索引。

9、Dicoogle使用的技术栈:

  • Dicoogle使用Java SE开发,核心和SDK子项目通过Maven构建。
  • DICOM相关功能通过dcm4che2提供;
  • Web服务通过嵌入式Eclipse Netty服务器提供;
  • 用户界面是由React和Bootstrap组件提供支持的单页Web应用程序。

二、源码编译:

1、编译环境准备:

  • Java JDK,Oracle或OpenJDK(1.8及以上,包含1.8);
  • Maven 3;
  • Node.js(至少为版本10,建议使用最新的稳定版);
  • Python 2.7(Dicoogle 2.5版本需要);

2、源码下载:

  • 可以通过在GitHub网站点击下载ZIP;
  • 也可以通过git命令行下载,如下:
  git clone -b 2.5.0 https://github.com/bioinformatics-ua/dicoogle.git

3、源码编译:

(1)、前端源码编译:

  cd ../dicoogle/dicoogle/src/main/resources/webapp 
  npm install

(2)、后端源码编译:

  cd ../dicoogle目录下
  mvn install -Dskip.installnodenpm -Dskip.npm

三、插件编译:

1、官方提供的插件:

  • 存储插件:filestorage.jar,支持DICOM文件的存储;
  • 查询/索引插件:lucene.jar,支持DICOM元数据的查询/索引;

2、插件源码下载:

3、源码编译:

(1)、解压下载后插件源码,解压后的插件源码目录结构如下:

(2)、通过如下命令即可同时对文件存储插件、检索插件实现编译:

  mvn install

(3)、编译成功后的可使用插件在如下目录中:

../dicoogle-sources-2.5.0/plugins/filestorage/target/filestorage-2.5.0.jar
../dicoogle-sources-2.5.0/plugins/lucene/target/lucene-2.5.0.jar

四、插件开发:

1、五种特定类型的插件:

(1)、Storage Plugins:

负责存储和检索数据。一个基本的实现方式是将文件保留在本地文件系统中。

(2)、Indexer Plugins:

提供了索引数据的方法。查询与特定的索引器捆绑在插件集中。

(3)、Query Plugins:

提供了一种查询索引数据的方法。查询与特定的索引器捆绑在插件集中。

(4)、Jetty Service Plugins:

支持jetty servlet,方便在Dicoogle中托管新的Web服务。

(5)、Rest Web Service Plugins:

包含一个可以连接到Dicoogle的Restlet服务器资源,用于托管新的Web服务。

注:(4)与(5)都是用来开发Web服务的,算是一种插件两种解决方案。

2、注册插件:

将某些类标记为插件是通过PluginSet完成的。创建一个实现PluginSet接口的类,在该类上应用@PluginImplementation注解,该注解允许插件框架从核心平台获取Plugin集合。构造方法应为每一个预期的插件的实例,并且插件获取程序需要提供一个不变的插件列表。当插件集不提供任何特定类型的插件时,相应的getter应返回一个空列表(Collections.EMPTY_LIST)。此外,名称获取器(getName())应提供一个简单,唯一的名称,并且查询提供者与索引器可以共享相同的名称,但是两个不同的查询提供者不能共享。如下:

@PluginImplementation
public class MyPluginSet implements PluginSet {

    // 使用slf4j进行日志记录
    private static final Logger logger LoggerFactory.getLogger(MyPluginSet.class);

    private final MyQueryProvider query;

    // 可以在此处添加其他资源
    private ConfigurationHolder settings;

    public MyPluginSet() throws IOException {
        logger.info("Initializing My Plugin Set");
        // 构造所有插件
        this.query = new MyQueryProvider();        
        logger.info("My Plugin Set is ready");
    }

    @Override
    public Collection<QueryInterface> getQueryPlugins() {
        return Collections.singleton((QueryInterface) this.query);
    }

    @Override
    public String getName() {
        return "mine";
    }
}

3、调用平台API:

Dicoogle Platform Interface是Dicoogle提供的通用接口,通过该接口的方法可以实现与核心平台进行交互。首先自定义的Plugin需要引入PlatformCommunicatorInterface接口,实现setPlatformProxy()方法等待回调(当插件被加载后,平台会调用该方法)。

public class MyQueryPlugin implements QueryInterface, PlatformCommunicatorInterface {

    private DicooglePlatformInterface platform;

    @Override
    void setPlatformProxy(DicooglePlatformInterface platform) {
        this.platform = platform;
    }
}

注:平台提供的方法见 https://github.com/bioinformatics-ua/dicoogle/blob/master/sdk/src/main/java/pt/ua/dicoogle/sdk/core/DicooglePlatformInterface.java

4、对配置进行读写:

如果需要自定义配置文件,可以实现setSettings(),这也是一个回调方法。实例化后,会将自定义的配置信息生成到DicoogleDir/Plugins/settings目录中,该配置文件遵循Apache Commons1.x https://commons.apache.org/proper/commons-configuration/userguide_v1.10/user_guide.html 规范。

@Override
public void setSettings(ConfigurationHolder configurationHolder) {
    this.settings = configurationHolder;
    XmlConfiguration configuration = this.settings.getConfiguration();
    try {
        // 必填字段
        String uid = configuration.getString("service-uid");
    } catch (RuntimeException ex) {
        logger.warn("Failed to configure plugin: required fields are missing!", ex);
    }
    // 可选字段,默认值为1
    int numResources = configuration.getInt("num-resources", 1);
    configuration.setProperty("num-resources", numResources);
    try {
        configuration.save();
    } catch (ConfigurationException ex) {
        logger.warn("Failed to save configurations!", ex);
    }
    this.uid = uid;
    this.numResources = numResources;
    }

@Override
public ConfigurationHolder getSettings() {
    return this.settings;
}

注:在最新版本的Dicoogle中,如果此方法引发未经检查的异常,则将禁用该插件。这与插件特定的设置有关。为了读写全局Dicoogle设置,平台API提供了必要的方法。

5、编写查询插件DEMO:

(1)、通过引入官方提供的SDK:

<dependency>
    <groupId>pt.ua.ieeta</groupId>
    <artifactId>dicoogle-sdk</artifactId>
    <version>2.5.0</version>
</dependency>

(2)、自定义查询类并且引入QueryInterface接口实现相应的查询方法:

public class MyQuery implements QueryInterface {

    private SearchResult generateSearchResult(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("PatientID",UUID.randomUUID().toString() );
        map.put("PatientName",UUID.randomUUID().toString() );
        map.put("SOPInstanceUID",UUID.randomUUID().toString() );
        map.put("SeriesInstanceUID",UUID.randomUUID().toString() );
        map.put("StudyInstanceUID",UUID.randomUUID().toString() );
        map.put("Modality","CT");
        map.put("StudyDate","20200920");
        map.put("SeriesDate","20200920");
        SearchResult r = new SearchResult(
          URI.create("file:" + File.separatorChar + UUID.randomUUID().toString() ), 1, map);
        return r;
    }

    @Override
    public Iterable<SearchResult> query(String query, Object... parameters) {
        List<SearchResult> results =  new ArrayList<>();
        results.add(generateSearchResult());
        results.add(generateSearchResult());
        results.add(generateSearchResult());
        results.add(generateSearchResult());
        results.add(generateSearchResult());
    return results;
   }
}

(3)、将自定义插件放入到插件集中:

@PluginImplementation
public class MyPluginSet implements PluginSet {
    
    private final MyQuery query;

    public RSIPluginSet() throws IOException {
       logger.info("Initializing RSI Plugin Set");
       // 所有的plugins都放在这里
       this.query = new MyQuery();
      logger.info("RSI Plugin Set is ready");
   }

    @Override
    public Collection<QueryInterface> getQueryPlugins() {
        return Collections.singleton((QueryInterface) this.query);
    }
}

(4)、使用mvn install命令编译打包:

  mvn install

(5)、将生成的jar文件放入到DicoogleDir/Plugins目录下;

(6)、可以进行查询,并且访问到自定义的数据:

五、服务部署:

1、部署服务器需要的环境:

  • Java JDK 8;

2、设置运行环境:

  • 创建Dicoogle Server运行需要的目录结构,如下:

  • 将编译好的lucene-2.5.0.jar、filestorage-2.5.0.jar复制或移动到DicoolgeDirPlugins下;

  • 将编译好的dicoogle.jar复制或移动到DicoogleDir下;

3、启动Dicoogle Server:

  • 通过如下命令启动Dicoogle Server:
  java -jar dicoogle.jar -s

注:-s是可选参数,表示Dicoogle将自动在Web应用程序上打开默认的浏览器。

  • 设置Dicoogle Server机器标识:

  • 访问Dicoogle Server:

  http://localhost:8080/

如下:
<img src="https://img2020.cnblogs.com/blog/1872705/202101/1872705-20210125162244919-316970995.png style="zoom:70%"/>

用户名/密码:dicoogle/dicoogle

Http接口调用:

1、查询接口:

(1)、根据日期范围查询DICOM:

  http://localhost:8080/search?query=StudyDate:[20200901 TO 20200930]

(2)、根据日期范围、影像模式查询DICOM:

  http://localhost:8080/search?query=Modality:CT AND StudyDate:[20200901 TO 20200930]

(3)、根据关键字查询DICOM:

  http://localhost:8080/search?query=CT

(4)、根据SOPInstanceUID获取DICOM元数据:

  http://localhost:8080/dump?uid=1.3.12.2.1107.5.1.4.54023.30000005032914013107800000965

2、下载接口:

(1)、根据SOPInstanceUID获取DICOM文件:

  http://localhost:8080/legacy/file?uid=1.3.12.2.1107.5.1.4.54023.30000005032914013107800000965

3、索引相关接口:

(1)、强制Dicoogle为指定目录下的文件建立索引:

  http://localhost:8080/management/tasks/index?uri=file:/D:DicoogleDir/storage/
原文地址:https://www.cnblogs.com/xiaoshuzhagen/p/14324840.html