所需知識
- FHIR Resource文件查看以及組成能力
- 基本的程式能力
- JSON資料格式
使用工具
- Weasis或RadiAnt DICOM Viewer (查看DICOM用)
- Visual Studio Code (撰寫程式用)
程式語言
DICOM 架構
這邊使用TCIA,編號0522c0001
的部分檔案做範例,點我下載
首先快速了解DICOM檔案的架構。
1個病人有多個Study(報告),Study內有多個Series(部位),Series當中有多個Instance(影像實例)。
以JSON來看大概會長這樣
{
"study": {
"series" : [
{
"instance": [
]
}
]
}
}
如果太過抽象,可以透過DICOM Viewer開啟提供的範例檔。
這裡使用Weasis開啟其中一個資料中所有的檔案。
- 藍色,以日期為標題框住的範圍為Study
- 綠色,單一個正方形預覽圖為Series
- 紅色,於正方形左下角之數字為此Series含有的Instance的數量
DICOM欄位資訊
我們可以透過Weasis上的按鈕,來查看DICOM的欄位資訊,打開後請記得切換到All DICOM attributes
。
圖中可以看到我們常用的病人名稱
欄位,由以下幾項組成:
- (0010,0010) -> 欄位標籤,解析DICOM時會用到
補充: DICOM PS3.6 2021e - Data Dictionary 5 ConventionsA Data Element Tag is represented as (gggg,eeee), where gggg equates to the Group Number and eeee equates to the Element Number within that Group.
- [PN] -> 欄位資料型態
- PatientName -> 欄位名稱
- 0552c0001 -> 數值
如果想要快速查詢欄位標籤
可以使用以下網站輔助:
如何知道DICOM檔是同個Study
- DICOM欄位有三個UID,分別是
StudyInstanceUID
、SeriesInstanceUID
、SOPInstanceUID (InstanceUID)
。 - 只要是相同
StudyInstanceUID
的檔案,就代表是同個Study。
使用程式讀取DICOM
此範例將示範如何取出DICOM檔案某個欄位標籤的數值。
- 創建資料夾
- 用Visual Studio Code開啟資料夾
- 新增一個新的
Terminal
- 初始化專案
npm init -y
- 安裝dicom-parser
npm i dicom-parser
- 開寫程式碼
const fs = require('fs');
const dicomParser = require('dicom-parser');
//讀取檔案
let fileBuffer = fs.readFileSync("./1.3.6.1.4.1.14519.5.2.1.5099.8010.199920086920823171706454903251/1.3.6.1.4.1.14519.5.2.1.5099.8010.260151978148957514594497217760/000001.dcm");
//將讀取後的Buffer轉成Uint8Array
let uint8FileBuffer = new Uint8Array(fileBuffer);
//使用DICOM Parser讀取DICOM檔
let dataSet = dicomParser.parseDicom(uint8FileBuffer);
//取出 Patient Name 0010,0010的數值
let patientName = dataSet.string("x00100010");
//印出取得的數值
console.log("Patient Name: " + patientName);
FHIR ImagingStudy
以上大致了解了如何讀取DICOM後,現在來了解FHIR ImagingStudy。
從FHIR ImagingStudy官方文件以及下圖來看,ImagingStudy採用與DICOM一樣的架構來儲存資料(Study->Series->Instance)。
Mappings
官方文件也提供了DICOM轉換成FHIR ImagingStudy的Mappings,可以說是非常地友善。ImagingStudy Mappings使用此表格,我們就可以輕易地將DICOM轉成FHIR的格式。
DICOM轉成ImagingStudy
撰寫Data Types的Class
為方便使用及管理程式碼,首先要做的是幫 ImagingStudy 使用到的 Data Types 寫成 Class 以利組成 ImagingStudy。
- 創建
FHIRDataTypes.js
檔案並把 Class 都寫在此檔案 - 以
Identifier
type為例
注意 Identifier 底下還包含了幾種需要建成 Class 的 Type: - CodeableConcept - Period - Reference
//Coding
class Coding {
constructor() {
this.system = undefined;
this.version = undefined;
this.code = undefined;
this.display = undefined;
this.userSelected = undefined;
}
}
//CodeableConcept
class CodeableConcept {
constructor() {
this.Coding = undefined;
this.text = undefined;
}
}
//Period
class Period {
constructor() {
this.start = undefined;
this.end = undefined;
}
}
//Reference
class Reference {
constructor() {
this.reference = undefined; //(Literal reference, Relative, internal or absolute URL)(string)
this.type = undefined; //string
this.identifier = undefined;
this.display = undefined;
}
}
//Identifier
class Identifier {
constructor() {
this.use = undefined;
this.type = new CodeableConcept();
this.system = undefined;
this.value = undefined;
this.period = new Period();
}
}
最後在一步一步把 ImagingStudy 的 Class 都寫完。
完整的FHIR Data Types Class:
轉換主程式
上面已經把會用到的Data Types轉成 Class了,現在開始撰寫轉換的程式。思路如下
- 讀取 DICOM 檔案
- 搭配ImagingStudy Mappings對照 DICOM Tags 轉換到FHIR的欄位
- 使用dicom-parser讀取數值
- 利用剛剛寫的 Class 把數值填入對應的 Class
- 把 ImagingStudy 組合起來
套件
- dicom-parser (解析dicom用)
- flat
- lodash
- moment
npm install dicom-parser flat lodash moment
整體專案完整程式碼
到專案主頁面會有 C#
、Python
版本的範例,以下為 node.js
範例
單檔案程式碼
如果覺得上面的專案比較複雜,可以看看這支程式碼都寫在一個檔案的範例
轉換結果
{
"resourceType": "ImagingStudy",
"id": "1.2.826.0.1.3680043.8.1055.1.20111102150758591.92402465.76095170",
"identifier": [
{
"use": "official",
"system": "urn:dicom:uid",
"value": "urn:oid:1.2.826.0.1.3680043.8.1055.1.20111102150758591.92402465.76095170"
}
],
"status": "unknown",
"subject": {
"reference": "Patient/0",
"type": "Patient",
"identifier": {
"use": "usual",
"value": "0"
}
},
"started": "2006-10-12T01:02:58.000Z",
"description": "CT1 abdomen",
"series": [
{
"uid": "1.2.826.0.1.3680043.8.1055.1.20111102150758591.96842950.07877442",
"number": 6168,
"modality": {
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "CT"
},
"description": "ARTERIELLE",
"instance": [
{
"uid": "1.2.826.0.1.3680043.8.1055.1.20111102150758591.03296050.69180943",
"sopClass": {
"system": "urn:ietf:rfc:3986",
"code": "urn:oid:1.2.840.10008.5.1.4.1.1.2"
},
"number": 1,
"title": "ORIGINAL\\PRIMARY\\AXIAL\\HELIX"
}
]
}
]
}