Skip to content

Commit

Permalink
feat: first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DESKTOP-HD3BEBF\user authored and DESKTOP-HD3BEBF\user committed Sep 5, 2024
0 parents commit 36ac631
Show file tree
Hide file tree
Showing 5 changed files with 499 additions and 0 deletions.
75 changes: 75 additions & 0 deletions ImagingStudy-ImagingStudyBase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"resourceType" : "ImagingStudy",
"id" : "ImagingStudyBase",
"meta" : {
"profile" : ["https://twcore.mohw.gov.tw/ig/emr/StructureDefinition/ImagingStudyBase"]
},
"text" : {
"status" : "generated",
"div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p class=\"res-header-id\"><b>Generated Narrative: ImagingStudy ImagingStudyBase</b></p><a name=\"ImagingStudyBase\"> </a><a name=\"hcImagingStudyBase\"> </a><a name=\"ImagingStudyBase-en-US\"> </a><p><b>identifier</b>: Study instancce UID/urn:oid:2.25.284733062255854756631429402605810248731\u00a0(use:\u00a0official,\u00a0), Accession ID/2ffe0c20-50d8-49df-85f6-6452d1d201b9\u00a0(use:\u00a0official,\u00a0)</p><p><b>status</b>: Available</p><p><b>subject</b>: <a href=\"Patient-TWCorePatient.html\">胖吉 綠 (official) Male, DoB: 1987-01-01 ( National Person Identifier where the xxx is the ISO table 3166 3-character (alphabetic) country code\u00a0(use:\u00a0official,\u00a0))</a></p><p><b>started</b>: 2024-01-01 11:01:20+0300</p><p><b>endpoint</b>: <a href=\"Endpoint-MitwEndpoint.html\">Endpoint: status = active; connectionType = DICOM WADO-RS (Endpoint Connection Type#dicom-wado-rs); payloadType = ; payloadMimeType = application/dicom; address = http://localhost:8081/dicom-web</a></p><p><b>numberOfSeries</b>: 1</p><p><b>numberOfInstances</b>: 1</p><p><b>procedureReference</b>: <a href=\"Procedure-TWCoreProcedure.html\">Procedure 胸部及腹部電腦斷層掃描</a></p><p><b>procedureCode</b>: <span title=\"Codes:{https://twcore.mohw.gov.tw/ig/emr/CodeSystem/ICD-10-procedurecode BW24ZZZ}\">Computerized Tomography (CT Scan) of Chest and Abdomen</span></p><blockquote><p><b>series</b></p><p><b>uid</b>: 2.25.88017001449189502323411118737039844242</p><p><b>modality</b>: <a href=\"CodeSystem-AcquisitionModality.html#AcquisitionModality-CT\">Acquisition Modality</a> CT: Computed Tomography</p><p><b>numberOfInstances</b>: 1</p><p><b>bodySite</b>: <a href=\"http://snomed.info/id/251007\">SNOMED CT (all versions)</a> 251007: Pectoral region</p><h3>Instances</h3><table class=\"grid\"><tr><td style=\"display: none\">-</td><td><b>Uid</b></td><td><b>SopClass</b></td></tr><tr><td style=\"display: none\">*</td><td>2.25.284548087604447302186649612333159050027</td><td><a href=\"CodeSystem-DicomsopClass.html#DicomsopClass-urn.58oid.581.462.46840.4610008.465.461.464.461.461.461\">DICOM sopClass</a> urn:oid:1.2.840.10008.5.1.4.1.1.1: Computed Radiography Image Storage</td></tr></table></blockquote></div>"
},
"identifier" : [{
"use" : "official",
"type" : {
"coding" : [{
"system" : "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/ImageIdentifierType",
"code" : "SIUID",
"display" : "Study instancce UID"
}]
},
"system" : "urn:dicom:uid",
"value" : "urn:oid:2.25.284733062255854756631429402605810248731"
},
{
"use" : "official",
"type" : {
"coding" : [{
"system" : "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/ImageIdentifierType",
"code" : "ACSN",
"display" : "Accession ID"
}]
},
"system" : "http://www.moi.gov.tw/",
"value" : "2ffe0c20-50d8-49df-85f6-6452d1d201b9"
}],
"status" : "available",
"subject" : {
"reference" : "Patient/TWCorePatient"
},
"started" : "2024-01-01T11:01:20+03:00",
"endpoint" : [{
"reference" : "Endpoint/MitwEndpoint"
}],
"numberOfSeries" : 1,
"numberOfInstances" : 1,
"procedureReference" : {
"reference" : "Procedure/TWCoreProcedure"
},
"procedureCode" : [{
"coding" : [{
"system" : "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/ICD-10-procedurecode",
"code" : "BW24ZZZ",
"display" : "Computerized Tomography (CT Scan) of Chest and Abdomen"
}]
}],
"series" : [{
"uid" : "2.25.88017001449189502323411118737039844242",
"modality" : {
"system" : "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/AcquisitionModality",
"code" : "CT"
},
"numberOfInstances" : 1,
"bodySite" : {
"system" : "http://snomed.info/sct",
"code" : "251007",
"display" : "Pectoral region"
},
"instance" : [{
"uid" : "2.25.284548087604447302186649612333159050027",
"sopClass" : {
"system" : "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/DicomsopClass",
"code" : "urn:oid:1.2.840.10008.5.1.4.1.1.1"
}
}]
}]
}
16 changes: 16 additions & 0 deletions configOAuth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"enabled":true,
"hostname":"172.18.0.58",
"port":"8080",
"http":"http",
"client_id":"dcm4chee",
"client_secret":"v6uYKjl6UDXFhe7ebPBGwOILQ01GYRQg",
"endpoints":
{
"auth":"realms/mitw/protocol/openid-connect/auth",
"validation":"realms/mitw/protocol/openid-connect/userinfo",
"token":"realms/mitw/protocol/openid-connect/token"
},
"tokenInRequest":true
}

43 changes: 43 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DICOM Web Query</title>
<!-- 引入 Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="./oauth.js"></script>
<script src="./main.js"></script>
</head>
<body class="bg-light">

<div class="container mt-5">
<h1 class="text-center mb-4">DICOM Web Query to FHIR ImagingStudy</h1>
<div class="card p-4 shadow-sm">
<div class="mb-3">
<label for="dicom-url" class="form-label">DICOM Web URL:</label>
<input type="text" class="form-control" id="dicom-url" placeholder="Enter DICOM Web URL"
value="http://172.18.0.53:10000/dcm4chee-arc/aets/DCM4CHEE/rs">
</div>

<div class="mb-3">
<label for="study-uid" class="form-label">Study Instance UID:</label>
<input type="text" class="form-control" id="study-uid" placeholder="Enter Study Instance UID"
value="1.3.46.670589.45.1.1.4993912214784.1.5436.1538560373543">
</div>

<button class="btn btn-primary w-100" onclick="main()">產生結果</button>

<div class="mt-4">
<label for="result" class="form-label">結果:</label>
<textarea class="form-control" id="result" rows="6" readonly></textarea>
</div>
</div>
</div>

<!-- 引入 Bootstrap JS 和 Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>


</body>
</html>
184 changes: 184 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
async function main() {

let imagingStudy = await loadJson("./ImagingStudy-ImagingStudyBase.json");
console.log(imagingStudy);
// 1. Query DICOM by StudyInstanceUID 查詢dicom
let studyData = await queryStudy();
let seriesData = await querySeries(studyData[0]['0020000D']['Value'][0]);
let instanceData = {};
for(let i = 0; i < seriesData.length; i++) {
instanceData[seriesData[i]['0020000E']['Value'][0]] = await queryInstances(studyData[0]['0020000D']['Value'][0], seriesData[i]['0020000E']['Value'][0]);
}
console.log(studyData);
console.log(seriesData);
console.log(instanceData);
// 2. Fill in the FHIR JSON using the DICOM Query Result 將dicom查詢結果填入fhir ImagingStudy
let resultImagingStudy = fillImagingStudy(imagingStudy,studyData,seriesData,instanceData);
// 3. Put the FHIR JSON Result in Textarea. 顯示結果
console.log(resultImagingStudy);
document.getElementById('result').innerText = JSON.stringify(resultImagingStudy);
}

/**
* DICOM to FHIR Imaging Study
* @param {*} imagingStudy base json
* @param {*} studyData
* @param {*} seriesData
* @param {*} instanceData
* @returns imaging study result
*/
function fillImagingStudy(imagingStudy, studyData, seriesData, instanceData) {
// Fill in the study instance uid
imagingStudy.identifier[0].value = `urn:oid:${studyData[0]['0020000D']['Value'][0]}`;
// Fill in the Accession Number
imagingStudy.identifier[1].value = `${studyData[0]['00080050']['Value'][0]}`;
// Fill in the Number Of Instances
imagingStudy.numberOfInstances = 0;
for(let i = 0; i < Object.keys(instanceData).length; i++){
imagingStudy.numberOfInstances += instanceData[Object.keys(instanceData)[i]].length;
}
// Fill in the Number Of Series
imagingStudy.numberOfSeries = seriesData.length;

// Fill in the procedure code
imagingStudy.procedureCode = [{
"coding" : [{
"system" : "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/ICD-10-procedurecode",
"code" : "BW24ZZZ",
"display" : "Computerized Tomography (CT Scan) of Chest and Abdomen"
}]
}];
if(studyData[0]['00081032'] != undefined){
for(let i = 0; i < studyData[0]['00081032']['Value'].length; i++){
let thisCode = [{"coding":[]}];
let thisCodeData = studyData[0]['00081032']['Value'][i];
thisCode["coding"].push({
"system": "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/ICD-10-procedurecode",
"code": thisCodeData['00080100']['Value'][0],
"display": thisCodeData['00080104']['Value'][0]
});
}
}

// Fill in the series
imagingStudy.series = [];
for(let i = 0; i < seriesData.length; i++){
let thisSeries = {};
thisSeries.uid = seriesData[i]['0020000E']['Value'][0];
thisSeries.modality = {
"system": "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/AcquisitionModality",
"code": seriesData[i]['00080060']['Value'][0]
};
thisSeries.numberOfInstances = instanceData[thisSeries.uid].length;
thisSeries.instance = [];
for(let j = 0; j < instanceData[thisSeries.uid].length; j++){
thisSeries.bodySite = {
"system": "http://snomed.info./sct",
"code": "251007", // should be instance's tag 00082218.00080100
"display": "Pectoral region" // should be instance's tag 00082218.00080104
};

let thisInstance = {
"uid": instanceData[thisSeries.uid][j]["00080018"]['Value'][0],
"sopClass": {
"system": "https://twcore.mohw.gov.tw/ig/emr/CodeSystem/DicomsopClass",
"code": `urn:oid:${instanceData[thisSeries.uid][j]["00080016"]['Value'][0]}`
}
};

thisSeries.instance.push(thisInstance);

}
imagingStudy.series.push(thisSeries);
}
return imagingStudy;

}

/**
* Load OAuth config file.
*/
function loadJson(url) {
return new Promise((resolve, reject) => {
let config = {};
let requestURL = url;
let request = new XMLHttpRequest();
request.open('GET', requestURL);
request.responseType = 'json';
request.send();
request.onload = function () {
config = request.response;
return resolve(config);
}
});
}

// Function to query Study by StudyInstanceUID using XMLHttpRequest
function queryStudy() {
return new Promise((resolve, reject) => {
const studyUID = document.getElementById('study-uid').value;
const baseUrl = document.getElementById('dicom-url').value;
const url = `${baseUrl}/studies?StudyInstanceUID=${studyUID}`;

const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
resolve(response);
} else {
reject(`Error querying study: ${xhr.status} ${xhr.statusText}`);
}
}
};
xhr.send();
});
}

// Function to query Series by StudyInstanceUID using XMLHttpRequest
function querySeries(studyUID) {
return new Promise((resolve, reject) => {
const baseUrl = document.getElementById('dicom-url').value;
const url = `${baseUrl}/studies/${studyUID}/series`;

const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
resolve(response);
} else {
reject(`Error querying series: ${xhr.status} ${xhr.statusText}`);
}
}
};
xhr.send();
});
}

// Function to query Instances by SeriesInstanceUID using XMLHttpRequest
function queryInstances(studyUID, seriesUID) {
return new Promise((resolve, reject) => {
const baseUrl = document.getElementById('dicom-url').value;
const url = `${baseUrl}/studies/${studyUID}/series/${seriesUID}/instances`;

const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
resolve(response);
} else {
reject(`Error querying instances: ${xhr.status} ${xhr.statusText}`);
}
}
};
xhr.send();
});
}
Loading

0 comments on commit 36ac631

Please sign in to comment.