Skip to content

Commit 8ac2a66

Browse files
author
Alexis Girault
committed
WIP Dicom parsing example
1 parent d2916f4 commit 8ac2a66

File tree

7 files changed

+395
-0
lines changed

7 files changed

+395
-0
lines changed

examples/Dicom/.babelrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
presets: [
3+
['@babel/preset-env', {
4+
targets: {
5+
browsers: ['last 2 versions'],
6+
},
7+
}],
8+
],
9+
}

examples/Dicom/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
itk-webpack-example
2+
===================
3+
4+
This example demonstrates how to load DICOM files using [itk.js](https://insightsoftwareconsortium.github.io/itk-js/).
5+
More information can be found in the [example
6+
documentation](https://insightsoftwareconsortium.github.io/itk-js/examples/dicom.html).
7+
8+
## Run Locally
9+
10+
```
11+
npm install
12+
npm run start
13+
```
14+
15+
And visit [http://localhost:8080/](http://localhost:8080/).
16+
17+
## Development
18+
19+
```
20+
npm install
21+
npm run build
22+
npm test
23+
```

examples/Dicom/dist/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>itk.js Webpack Example</title>
5+
<meta charset="UTF-8" />
6+
<link rel="stylesheet" href="styles.css">
7+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
8+
</head>
9+
10+
<body>
11+
<!-- Input selector -->
12+
<div>
13+
<label>Select dicom file(s):</label>
14+
<input name="inputFile" type="file" multiple>
15+
</div>
16+
17+
<!-- File information -->
18+
<textarea readonly name="fileInformation">File information...</textarea>
19+
20+
<!-- Javascript -->
21+
<script src="index.js"></script>
22+
<script>
23+
var outputTextArea = document.querySelector('textarea')
24+
var handleFile = index.outputFileInformation(outputTextArea)
25+
var fileInput = document.querySelector('input')
26+
fileInput.addEventListener('change', handleFile);
27+
</script>
28+
</body>
29+
</html>

examples/Dicom/dist/styles.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
html, body {
2+
height: 90%;
3+
}
4+
5+
textarea {
6+
resize: none;
7+
overflow-y: scroll;
8+
position: absolute;
9+
box-sizing: border-box;
10+
width: 100%;
11+
height: 80%;
12+
bottom: 0px;
13+
left: 0px;
14+
top: 50px;
15+
}

examples/Dicom/package.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "itk-dicom-example",
3+
"version": "1.0.1",
4+
"description": "This example demonstrates how to load DICOM files using itk.js.",
5+
"main": "index.js",
6+
"scripts": {
7+
"build": "webpack --progress --colors -p",
8+
"start": "webpack-dev-server --mode development --content-base ./dist/ --watch-content-base"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/InsightSoftwareConsortium/itk-js.git"
13+
},
14+
"keywords": [
15+
"itk",
16+
"webpack"
17+
],
18+
"author": "Matt McCormick <[email protected]>",
19+
"license": "Apache-2.0",
20+
"bugs": {
21+
"url": "https://github.com/InsightSoftwareConsortium/itk-js/issues"
22+
},
23+
"homepage": "https://github.com/InsightSoftwareConsortium/itk-js#readme",
24+
"dependencies": {
25+
"curry": "^1.2.0",
26+
"expose-loader": "^0.7.5",
27+
"itk": "^9.5.0",
28+
"dicom-parser": "^1.8.3"
29+
},
30+
"devDependencies": {
31+
"@babel/core": "^7.2.0",
32+
"@babel/preset-env": "^7.2.0",
33+
"babel-loader": "^8.0.4",
34+
"copy-webpack-plugin": "^4.5.1",
35+
"tap-spec": "^4.1.1",
36+
"tape": "^4.9.0",
37+
"webpack": "^4.27.1",
38+
"webpack-cli": "^3.1.2",
39+
"webpack-dev-server": "^3.1.10"
40+
}
41+
}

examples/Dicom/src/index.js

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
import curry from 'curry'
2+
import dicomParser from 'dicom-parser'
3+
4+
class DICOMStore {
5+
constructor() {
6+
this.patientDict = new Map()
7+
this.fileLoaded = this.fileLoaded.bind(this)
8+
}
9+
10+
fileLoaded(event) {
11+
var arrayBuffer = event.target.result
12+
var byteArray = new Uint8Array(arrayBuffer)
13+
var dicomMetaData = dicomParser.parseDicom(byteArray)
14+
var patientId = dicomMetaData.string('x00100020')
15+
var patient = this.patientDict.get(patientId)
16+
if (patient === undefined) {
17+
console.log(`New patient ${patientId}`)
18+
patient = new DICOMPatient()
19+
this.patientDict.set(patientId, patient)
20+
}
21+
patient.parseMetaData(dicomMetaData)
22+
}
23+
24+
readFile(file) {
25+
var reader = new FileReader()
26+
reader.onload = this.fileLoaded
27+
reader.readAsArrayBuffer(file)
28+
}
29+
}
30+
31+
class DICOMPatient {
32+
constructor() {
33+
this.id = undefined // x00100020
34+
this.name = undefined // x00100010
35+
this.dateOfBirth = undefined // x00100030
36+
this.sex = undefined // x00100040
37+
this.studyDict = new Map()
38+
}
39+
40+
parseMetaData(dicomMetaData) {
41+
const id = dicomMetaData.string('x00100020')
42+
if (this.id === undefined) {
43+
this.id = id
44+
} else {
45+
console.assert(this.id === id, "Inconsistent id")
46+
}
47+
48+
const name = dicomMetaData.string('x00100010')
49+
if (this.name === undefined) {
50+
this.name = name
51+
} else {
52+
console.assert(this.name === name, "Inconsistent name")
53+
}
54+
55+
const dob = dicomMetaData.string('x00100030')
56+
if (this.dateOfBirth === undefined) {
57+
this.dateOfBirth = dob
58+
} else {
59+
console.assert(this.dateOfBirth === dob, "Inconsistent date of birth")
60+
}
61+
62+
const sex = dicomMetaData.string('x00100040')
63+
if (this.sex === undefined) {
64+
this.sex = sex
65+
} else {
66+
console.assert(this.sex === sex, "Inconsistent sex")
67+
}
68+
69+
const studyId = dicomMetaData.string('x00200010')
70+
var study = this.studyDict.get(studyId)
71+
if (study === undefined) {
72+
console.log(`new study ${studyId}`)
73+
study = new DICOMStudy()
74+
this.studyDict.set(studyId, study)
75+
}
76+
study.parseMetaData(dicomMetaData)
77+
}
78+
}
79+
80+
class DICOMStudy {
81+
constructor() {
82+
this.id = undefined // x00200010
83+
this.uid = undefined // x0020000d
84+
this.date = undefined // x00080020
85+
this.time = undefined // x00080030
86+
this.accessionNumber = undefined // x00080050
87+
this.description = undefined // x00081030
88+
this.serieDict = new Map()
89+
}
90+
91+
parseMetaData(dicomMetaData) {
92+
const id = dicomMetaData.string('x00200010')
93+
if (this.id === undefined) {
94+
this.id = id
95+
} else {
96+
console.assert(this.id === id, "Inconsistent id")
97+
}
98+
99+
const uid = dicomMetaData.string('x0020000d')
100+
if (this.uid === undefined) {
101+
this.uid = uid
102+
} else {
103+
console.assert(this.uid === uid, "Inconsistent uid")
104+
}
105+
106+
const date = dicomMetaData.string('x00080020')
107+
if (this.date === undefined) {
108+
this.date = date
109+
} else {
110+
console.assert(this.date === date, "Inconsistent date")
111+
}
112+
113+
const time = dicomMetaData.string('x00080030')
114+
if (this.time === undefined) {
115+
this.time = time
116+
} else {
117+
console.assert(this.time === time, "Inconsistent time")
118+
}
119+
120+
const nbr = dicomMetaData.string('x00080050')
121+
if (this.accessionNumber === undefined) {
122+
this.accessionNumber = nbr
123+
} else {
124+
console.assert(this.accessionNumber === nbr, "Inconsistent accession number")
125+
}
126+
127+
const description = dicomMetaData.string('x00081030')
128+
if (this.description === undefined) {
129+
this.description = description
130+
} else {
131+
console.assert(this.description === description, "Inconsistent description")
132+
}
133+
134+
const serieNumber = dicomMetaData.string('x00200011')
135+
var serie = this.serieDict.get(serieNumber)
136+
if (serie === undefined) {
137+
console.log(`new serie ${serieNumber}`)
138+
serie = new DICOMSerie()
139+
this.serieDict.set(serieNumber, serie)
140+
}
141+
serie.parseMetaData(dicomMetaData)
142+
}
143+
}
144+
145+
class DICOMSerie {
146+
constructor() {
147+
this.number = undefined // x00200011
148+
this.uid = undefined // x0020000e
149+
this.date = undefined // x00080021
150+
this.time = undefined // x00080031
151+
this.modality = undefined // x00080060
152+
this.description = undefined // x0008103e
153+
this.protocolName = undefined // x00181030
154+
this.bodyPart = undefined // x00180015
155+
this.imageDict = new Map()
156+
}
157+
158+
parseMetaData(dicomMetaData) {
159+
const number = dicomMetaData.string('x00200011')
160+
if (this.number === undefined) {
161+
this.number = number
162+
} else {
163+
console.assert(this.number === number, "Inconsistent number")
164+
}
165+
166+
const uid = dicomMetaData.string('x0020000e')
167+
if (this.uid === undefined) {
168+
this.uid = uid
169+
} else {
170+
console.assert(this.uid === uid, "Inconsistent number")
171+
}
172+
173+
const date = dicomMetaData.string('x00080021')
174+
if (this.date === undefined) {
175+
this.date = date
176+
} else {
177+
console.assert(this.date === date, "Inconsistent date")
178+
}
179+
180+
const time = dicomMetaData.string('x00080031')
181+
if (this.time === undefined) {
182+
this.time = time
183+
} else {
184+
console.assert(this.time === time, "Inconsistent time")
185+
}
186+
187+
const modality = dicomMetaData.string('x00080060')
188+
if (this.modality === undefined) {
189+
this.modality = modality
190+
} else {
191+
console.assert(this.modality === modality, "Inconsistent modality")
192+
}
193+
194+
const description = dicomMetaData.string('x0008103e')
195+
if (this.description === undefined) {
196+
this.description = description
197+
} else {
198+
console.assert(this.description === description, "Inconsistent description")
199+
}
200+
201+
const bodyPart = dicomMetaData.string('x00180015')
202+
if (this.bodyPart === undefined) {
203+
this.bodyPart = bodyPart
204+
} else {
205+
console.assert(this.bodyPart === bodyPart, "Inconsistent body part")
206+
}
207+
208+
const protocolName = dicomMetaData.string('x00181030')
209+
if (this.protocolName === undefined) {
210+
this.protocolName = protocolName
211+
} else {
212+
console.assert(this.protocolName === protocolName, "Inconsistent protocol name")
213+
}
214+
215+
var imageNumber = dicomMetaData.string('x00200013')
216+
if (this.imageDict.has(imageNumber)) {
217+
console.warn(`Instance #${imageNumber} was already added to the serie`)
218+
} else {
219+
// TODO
220+
}
221+
}
222+
}
223+
224+
225+
var store = new DICOMStore()
226+
227+
const outputFileInformation = curry(function outputFileInformation (outputTextArea, event) {
228+
outputTextArea.textContent = "Loading..."
229+
230+
const dataTransfer = event.dataTransfer
231+
const files = event.target.files || dataTransfer.files
232+
233+
Array.from(files).forEach( file => {
234+
store.readFile(file)
235+
})
236+
console.log(store)
237+
})
238+
239+
export { outputFileInformation }

0 commit comments

Comments
 (0)