---
# System prepended metadata

title: DICOM To FHIR ImagingStudy - Node.js
tags: [DICOM]

---

###### tags: `DICOM`

# DICOM To FHIR ImagingStudy - Node.js
# 所需知識
- FHIR Resource文件查看以及組成能力
- 基本的程式能力
- JSON資料格式
# 使用工具
- [Weasis](https://nroduit.github.io/en/getting-started/#try-weasis-now)或[RadiAnt DICOM Viewer](https://www.radiantviewer.com/download/?src=mbst&f=setup) (查看DICOM用)
- [Visual Studio Code](https://code.visualstudio.com/Download) (撰寫程式用)

# 程式語言
- [Node.js](https://nodejs.org/en/download/)

# DICOM 架構
這邊使用TCIA，編號`0522c0001`的部分檔案做範例，[點我下載](https://yrouka-my.sharepoint.com/:u:/g/personal/a5566qq123_my365_com_tw/Eejy-0hUEOtPoL7IJ7l-rtwB-0xUOKPOfMJRPQBi9xKXCA?e=SVzR8f)

首先快速了解DICOM檔案的架構。

1個病人有多個Study(報告)，Study內有多個Series(部位)，Series當中有多個Instance(影像實例)。
![image alt](https://dicom.nema.org/medical/dicom/current/output/chtml/part04/figures/PS3.4_C.6-1.svg)

以JSON來看大概會長這樣
```json=
{
    "study": {
        "series" : [
            {
                "instance": [

                ]
            }
        ]
    }
}

```

如果太過抽象，可以透過DICOM Viewer開啟提供的範例檔。

這裡使用Weasis開啟其中一個資料中所有的檔案。
![](https://i.imgur.com/KiPe8FZ.png)
- 藍色，以日期為標題框住的範圍為Study
- 綠色，單一個正方形預覽圖為Series
- 紅色，於正方形左下角之數字為此Series含有的Instance的數量

# DICOM欄位資訊
我們可以透過Weasis上的按鈕，來查看DICOM的欄位資訊，打開後請記得切換到`All DICOM attributes`。
![](https://i.imgur.com/hpOmqZu.png)

圖中可以看到我們常用的`病人名稱`欄位，由以下幾項組成:
- (0010,0010) -> 欄位標籤，解析DICOM時會用到
> 補充: [DICOM PS3.6 2021e - Data Dictionary 5 Conventions](https://dicom.nema.org/medical/dicom/current/output/chtml/part06/chapter_5.html)
A 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 -> 數值
![](https://i.imgur.com/1CXW4N0.png)

如果想要快速查詢`欄位標籤`可以使用以下網站輔助:
- [DICOM Library](https://www.dicomlibrary.com/dicom/dicom-tags/)
- [DICOM Standard Browser](https://dicom.innolitics.com/ciods)

## 如何知道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
```
- 開寫程式碼
```javascript=
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官方文件](https://www.hl7.org/fhir/imagingstudy.html)以及下圖來看，ImagingStudy採用與DICOM一樣的架構來儲存資料(Study->Series->Instance)。
![](https://i.imgur.com/UV6VrYx.png)

## Mappings
官方文件也提供了DICOM轉換成FHIR ImagingStudy的Mappings，可以說是非常地友善。
[ImagingStudy Mappings](https://www.hl7.org/fhir/imagingstudy-mappings.html)
使用此表格，我們就可以輕易地將DICOM轉成FHIR的格式。
![](https://i.imgur.com/8Fri4q5.png)

# DICOM轉成ImagingStudy
## 撰寫Data Types的Class
為方便使用及管理程式碼，首先要做的是幫 ImagingStudy 使用到的 Data Types 寫成 Class 以利組成 ImagingStudy。
- 創建`FHIRDataTypes.js`檔案並把 Class 都寫在此檔案
- 以`Identifier` type為例
![](https://i.imgur.com/NQNtLoW.png)
:::warning
注意 Identifier 底下還包含了幾種需要建成 Class 的 Type:
- CodeableConcept
- Period
- Reference
:::
```javascript=
//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: [Github 點我看程式碼](https://github.com/chinlin-example/dicom-to-fhir/blob/62df074ccc7bfe1702d0069ffebc4d6393dad744/nodejs/src/FHIRDataTypes.js)

# 轉換主程式

上面已經把會用到的Data Types轉成 Class了，現在開始撰寫轉換的程式。
思路如下
- 讀取 DICOM 檔案
- 搭配[ImagingStudy Mappings](https://www.hl7.org/fhir/imagingstudy-mappings.html)對照 DICOM Tags 轉換到FHIR的欄位
- 使用dicom-parser讀取數值
- 利用剛剛寫的 Class 把數值填入對應的 Class
- 把 ImagingStudy 組合起來

## 套件
- dicom-parser (解析dicom用)
- flat
- lodash
- moment
```bash=
npm install dicom-parser flat lodash moment
```
完整程式碼: [Github 點我看程式碼](https://github.com/chinlin-example/dicom-to-fhir/blob/62df074ccc7bfe1702d0069ffebc4d6393dad744/nodejs/src/DICOM2FHIRImagingStudy.js)



## 轉換結果
```json=
{
    "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"
                }
            ]
        }
    ]
}
```

# Support Me

文件創作花費了很多心血製作，如果你覺得很有幫助
不妨贊助我一下喝杯咖啡唄，[Support Me](https://portaly.cc/Li070/support)