一、基本介紹:
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、插件源碼下載:
- 下載地址:http://www.dicoogle.com/downloads/
- 下載位置:
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;
}
}
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復制或移動到DicoolgeDir\Plugins下;
-
將編譯好的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/