Added a basic implementation of hanging protocols with one hardcoded mammogram protocol.

This commit is contained in:
Erik Ziegler committed 2015-11-18 16:56:37 +01:00
1 parent dac91857f0
commit 292edc11d3
17 files changed
+5706 -133

No files matched your search

+10 -10
View File
@@ -1,17 +1,17 @@
Package.describe({
name: "weiwei:hangingprotocols",
summary: "DICOM Haning Protocols",
version: '0.0.1'
name: "hangingprotocols",
summary: "Support functions for using DICOM Hanging Protocols",
version: '0.0.1'
});
Package.onUse(function (api) {
api.use("weiwei:dicomservices");
api.use('cornerstone');;
api.addFiles('server/namespace.js', 'server');
api.addFiles('server/namespace.js', 'server');
api.addFiles('server/dataDictionary.js', 'server');
api.addFiles('server/instanceDataToJsObject.js', 'server');
api.export("DICOMHP", 'server');
});
Package.onTest(function (api){
api.use(["weiwei:hangingprotocols"]);
api.export('instanceDataToJsObject', 'server');
api.export('TAG_DICT', 'server');
api.export("DICOMHP", ['client', 'server']);
});
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,78 @@
/**
* converts an implicit dataSet to a javascript object with the help of a data dictionary
*
* @param dataSet
* @param options
*/
dataSetToJsWithDictionary = function (dataSet, dictionary, options) {
if (!dataSet) {
throw 'dataSetToJsWithDictionary: missing required parameter dataSet';
}
options = options || {
omitPrivateAttibutes: true, // true if private elements should be omitted
maxElementLength : 128 // maximum element length to try and convert to string format
};
// For the purpose of inserting a comma into the tag in order
// to search the dictionary, store a position value
var position = 3;
var result = {};
for(var tag in dataSet.elements) {
var element = dataSet.elements[tag];
// Reformat the tag from x00020010 to "0002,0010" to suit the dictionary
var tagFormatted = tagFormatted.substr(1, position) + ',' + tagFormatted.substr(position);
// Retrieve the tag dictionary entry
var tagDictionaryEntry = dictionary[tagFormatted];
// If there is no tag dictionary entry, or no name
// for this tag, just use the original tag instead
var tagName;
if (!tagDictionaryEntry || !tagDictionaryEntry.name) {
tagName = tag;
} else {
tagName = tagDictionaryEntry.name;
}
// Set the element VR from the dictionary, if necessary and possible
if (!element.vr && tagDictionaryEntry && tagDictionaryEntry.vr) {
element.vr = tagDictionaryEntry.vr;
}
// skip this element if it a private element and our options specify that we should
if(options.omitPrivateAttibutes === true && dicomParser.isPrivateTag(tag)) {
continue;
}
if(element.items) {
// handle sequences
var sequenceItems = [];
for(var i=0; i < element.items.length; i++) {
sequenceItems.push(dicomParser.dataSetToJsWithDictionary(element.items[i].dataSet, dictionary, options));
}
result[tagName] = sequenceItems;
} else {
var asString;
if (element.length < options.maxElementLength) {
asString = dicomParser.explicitElementToString(dataSet, element);
}
if(asString !== undefined) {
result[tagName] = asString;
} else {
result[tagName] = {
dataOffset: element.dataOffset,
length : element.length
};
}
}
}
return result;
};
@@ -0,0 +1,73 @@
var valueRepresentationTypes = {
number: [
'SH',
'LO'
]
};
/**
* converts an WADO instance to a javascript object with the help of a data dictionary
*
* @param instance
* @param options
*/
instanceDataToJsObject = function (instance, dictionary) {
if (!instance) {
throw 'instanceDataToJsObject: missing required parameter dataSet';
}
var result = {};
// The comma is always inserted after the first four digits
var position = 4;
Object.keys(instance).forEach(function(tag) {
var item = instance[tag];
// Reformat the tag from 00020010 to "(0002,0010)" to suit the dictionary
var tagFormatted = '(' + tag.substr(0, position) + ',' + tag.substr(position) + ')';
// Retrieve the tag dictionary entry
var tagDictionaryEntry = dictionary[tagFormatted];
console.log(tagDictionaryEntry);
// If there is no tag dictionary entry, or no name
// for this tag, just use the original tag instead
var tagName;
if (!tagDictionaryEntry || !tagDictionaryEntry.name) {
tagName = tag;
} else {
tagName = tagDictionaryEntry.name;
}
if (item.Value && item.Value.length > 1) {
// handle sequences
var sequenceItems = [];
item.Value.forEach(function(instance) {
sequenceItems.push(instanceDataToJsObject(instance, dictionary));
});
result[tagName] = sequenceItems;
} else if (!item.Value || !item.Value.length) {
// Handle empty arrays
result[tagName] = undefined;
} else {
// Handle single valued cases
if (item.vr === 'PN') {
// Patient Name
result[tagName] = DICOMWeb.getName(item);
} else if (valueRepresentationTypes.number.indexOf(item.vr) > 0) {
// Number type
result[tagName] = DICOMWeb.getNumber(item);
} else {
// Everything else
result[tagName] = DICOMWeb.getString(item);
}
}
});
console.log(result);
return result;
};
+83 -42
View File
@@ -1,46 +1,87 @@
var tags = {
sopClassUid: '00080016'
};
var tagValues = {
HangingProtocolStorage: '1.2.840.10008.5.1.4.38.1'
};
/**
* Finds appropriate hanging protocols given a studyInstanceUid
*
* This function retrieves all hanging protocols in storage
* in order to find those that match the parameters of the given study
*
* @param studyInstanceUID
* @returns {Array} An array of matching hanging protocols
*/
DICOMHP.match = function(studyInstanceUID) {
var metadata = DICOMService.retrieveMetadata(studyInstanceUID);
if (!metadata) {
return [];
}
var params = {"00080016" : "1.2.840.10008.5.1.4.38.1"}, modalities = metadata["00080061"].Value[0],
modalityMatch = null;
if (modalities) {
modalityMatch = [];
modalities.split('\\').forEach(function(modality){
if (modality && modality != 'SC') {
modalityMatch.push(modality);
}
});
}
var firstInstance = DICOMService.retrieveMetadata(studyInstanceUID, null, null, {limit : 1}),
lateralityMatch = null;
if (firstInstance.length > 0) {
lateralityMatch = firstInstance[0]["00200060"].Value[0];
}
// since orthanc doesn't support sequence matching
var allProtocols = DICOMService.searchForInstances(null, null, params);
if (allProtocols.length < 1) {
return [];
}
var matchedPrtocols = [];
allProtocols.forEach(function(protocol) {
var definitionSequence = protocol["0072000C"].Value;
definitionSequence.forEach(function(definition){
var defModality = definition["00080060"].Value[0];
if (defModality && modalityMatch && modalityMatch.indexOf(defModality) != -1) {
matchedPrtocols.push(protocol);
// First, retrieve the metaData from the given study
var studyInstance = Services.WADO.retrieveMetadata(studyInstanceUID);
if (!studyInstance) {
return;
}
var defLaterality = definition["00200060"].Value[0];
if (defLaterality && (defLaterality == lateralityMatch)) {
matchedPrtocols.push(protocol);
return;
}
}
// Note: It turns out Orthanc doesn't support hanging protocol storage yet,
// so I will just stop here.
var studyData = instanceDataToJsObject(studyInstance, TAG_DICT);
/*var searchParameters = {
tags['sopClassUid']: tagValues['HangingProtocolStorage']
};
var modalities = studyData.ModalitiesInStudy;
var modalityMatch;
if (modalities) {
modalityMatch = [];
modalities.split('\\').forEach(function(modality){
if (modality && modality != 'SC') {
modalityMatch.push(modality);
}
});
}
var firstInstance = Services.WADO..retrieveMetadata(studyInstanceUID, null, null, {limit : 1}),
lateralityMatch;
if (firstInstance.length > 0) {
lateralityMatch = firstInstance[0]["00200060"].Value[0];
}
// since orthanc doesn't support sequence matching
var allProtocols = Services.WADO..searchForInstances(null, null, params);
if (allProtocols.length < 1) {
return [];
}
var matchedProtocols = [];
allProtocols.forEach(function(protocol) {
var definitionSequence = protocol["0072000C"].Value;
definitionSequence.forEach(function(definition){
var defModality = definition["00080060"].Value[0];
if (defModality && modalityMatch && modalityMatch.indexOf(defModality) != -1) {
matchedProtocols.push(protocol);
return;
}
var defLaterality = definition["00200060"].Value[0];
if (defLaterality && (defLaterality == lateralityMatch)) {
matchedProtocols.push(protocol);
}
});
});
});
return matchedPrtocols;
return matchedProtocols;*/
};
Binary file not shown.
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<dicom>
<attr tag="00080008" vr="CS" len="22">ORIGINAL\PRIMARY\AXIAL</attr>
<attr tag="00430010" vr="LO" len="12">GEMS_PARM_01</attr>
<attr tag="00431012" vr="SS" len="6">14\2\3</attr>
<attr tag="00431018" vr="DS" len="26">0.085000\1.102000\0.095000</attr>
<attr tag="0043101A" vr="SL" len="4">7</attr>
<attr tag="00431026" vr="US" len="12">0\1\1\0\0\0</attr>
<attr tag="00431027" vr="SH" len="6">/1.0:1</attr>
<attr tag="00431040" vr="FL" len="4">178.07993</attr>
</dicom>
File diff suppressed because it is too large. Load diff