Updates for Timepoint assocation (LT-60) and Conformance Checks (LT-92, LT-93, LT-94)

This commit is contained in:
Erik Ziegler committed 2016-02-08 19:59:39 +01:00
1 parent 6c4eae3699
commit beaa56c0b3
144 files changed
+5050 -2416

No files matched your search

@@ -10,7 +10,7 @@ function getElementIfNotEmpty(viewportIndex) {
element = imageViewerViewports.get(viewportIndex),
canvases = imageViewerViewports.eq(viewportIndex).find('canvas');
if (!element || $(element).hasClass("empty") || canvases.length === 0) {
if (!element || $(element).hasClass('empty') || canvases.length === 0) {
return;
}
@@ -20,6 +20,7 @@ function getElementIfNotEmpty(viewportIndex) {
} catch(error) {
return;
}
return element;
}
@@ -28,10 +29,12 @@ function getPatient(property) {
if (!this.imageId) {
return false;
}
var patient = cornerstoneTools.metaData.get('patient', this.imageId);
if (!patient) {
return '';
}
return patient[property];
}
@@ -40,10 +43,12 @@ function getStudy(property) {
if (!this.imageId) {
return false;
}
var study = cornerstoneTools.metaData.get('study', this.imageId);
if (!study) {
return '';
}
return study[property];
}
@@ -52,10 +57,12 @@ function getSeries(property) {
if (!this.imageId) {
return false;
}
var series = cornerstoneTools.metaData.get('series', this.imageId);
if (!series) {
return '';
}
return series[property];
}
@@ -64,10 +71,12 @@ function getInstance(property) {
if (!this.imageId) {
return false;
}
var instance = cornerstoneTools.metaData.get('instance', this.imageId);
if (!instance) {
return '';
}
return instance[property];
}
@@ -76,15 +85,18 @@ function getImage(viewportIndex) {
if (!element) {
return false;
}
var enabledElement;
try {
enabledElement = cornerstone.getEnabledElement(element);
} catch(error) {
return false;
}
if (!enabledElement || !enabledElement.image) {
return false;
}
return enabledElement.image;
}
@@ -95,10 +107,12 @@ Template.viewportOverlay.helpers({
if (!element) {
return '';
}
var viewport = cornerstone.getViewport(element);
if (!viewport) {
return '';
}
return 'W ' + viewport.voi.windowWidth.toFixed(0) + ' L ' + viewport.voi.windowCenter.toFixed(0);
},
zoom: function() {
@@ -107,10 +121,12 @@ Template.viewportOverlay.helpers({
if (!element) {
return '';
}
var viewport = cornerstone.getViewport(element);
if (!viewport) {
return '';
}
return (viewport.scale * 100.0);
},
imageDimensions: function() {
@@ -118,41 +134,42 @@ Template.viewportOverlay.helpers({
var image = getImage(this.viewportIndex);
if (!image) {
return '';
return '';
}
return image.width + ' x ' + image.height;
},
patientName : function() {
patientName: function() {
return getPatient.call(this, 'name');
},
patientId : function() {
patientId: function() {
return getPatient.call(this, 'id');
},
studyDate : function() {
studyDate: function() {
return getStudy.call(this, 'studyDate');
},
studyTime : function() {
studyTime: function() {
return getStudy.call(this, 'studyTime');
},
studyDescription : function() {
studyDescription: function() {
return getStudy.call(this, 'studyDescription');
},
seriesDescription : function() {
seriesDescription: function() {
return getSeries.call(this, 'seriesDescription');
},
seriesNumber : function() {
seriesNumber: function() {
return getSeries.call(this, 'seriesNumber');
},
imageNumber : function() {
imageNumber: function() {
return getInstance.call(this, 'instanceNumber');
},
imageIndex : function() {
imageIndex: function() {
return getInstance.call(this, 'index');
},
numImages : function() {
numImages: function() {
return getSeries.call(this, 'numImages');
},
prior : function() {
prior: function() {
// This helper is updated whenever a new image is displayed in the viewport
Session.get('CornerstoneNewImage' + this.viewportIndex);
if (!this.imageId) {
@@ -165,15 +182,19 @@ Template.viewportOverlay.helpers({
// that we can obtain the oldest study as the first element of the array
//
// TODO= Find out if we should encode studyDate as a Date in the ViewerStudies Collection
var viewportStudies = ViewerStudies.find({}, {sort: {studyDate: 1}});
var viewportStudies = ViewerStudies.find({}, {
sort: {
studyDate: 1
}
});
if (viewportStudies.count() < 2) {
return;
}
// Get study data
var study = cornerstoneTools.metaData.get('study', this.imageId);
if (study.studyInstanceUid === viewportStudies.fetch()[0].studyInstanceUid) {
if (study.studyDate === viewportStudies.fetch()[0].studyDate) {
return 'Prior';
}
}
});
});
@@ -1,6 +1,7 @@
.imageViewerViewportOverlay
font-family: Helvetica, OpenSans
font-size: 13px
color: #e4ad00
color: #979797
line-height: 18px
display: none // Shown when an image is loaded
+72 -56
View File
@@ -7,40 +7,55 @@ Meteor.startup(function() {
}
OHIF.viewer.defaultHotkeys = {
defaultTool: "ESC",
angle: "A",
stackScroll: "S",
pan: "P",
magnify: "M",
scrollDown: ["DOWN", "PAGEDOWN"],
scrollUp: ["UP", "PAGEUP"],
nextPanel: "RIGHT",
previousPanel: "LEFT",
invert: "I",
flipV: "V",
flipH: "H",
wwwc: "W",
zoom: "Z",
cinePlay: "SPACE",
rotateR: "R",
rotateL: "L",
defaultTool: 'ESC',
angle: 'A',
stackScroll: 'S',
pan: 'P',
magnify: 'M',
scrollDown: ['DOWN', 'PAGEDOWN'],
scrollUp: ['UP', 'PAGEUP'],
nextPanel: 'RIGHT',
previousPanel: 'LEFT',
invert: 'I',
flipV: 'V',
flipH: 'H',
wwwc: 'W',
zoom: 'Z',
cinePlay: 'SPACE',
rotateR: 'R',
rotateL: 'L',
toggleOverlayTags: 'SHIFT',
WLPresetSoftTissue: ["NUMPAD1", "1"],
WLPresetLung: ["NUMPAD2", "2"],
WLPresetLiver: ["NUMPAD3", "3"],
WLPresetBone: ["NUMPAD4", "4"],
WLPresetBrain: ["NUMPAD5", "5"]
WLPresetSoftTissue: ['NUMPAD1', '1'],
WLPresetLung: ['NUMPAD2', '2'],
WLPresetLiver: ['NUMPAD3', '3'],
WLPresetBone: ['NUMPAD4', '4'],
WLPresetBrain: ['NUMPAD5', '5']
};
// For now
OHIF.viewer.hotkeys = OHIF.viewer.defaultHotkeys;
OHIF.viewer.defaultWLPresets = {
'SoftTissue' : {wc : 40, ww : 400},
'Lung' : {wc : -600, ww : 1500},
'Liver' : {wc : 90, ww : 150},
'Bone' : {wc: 480, ww : 2500},
'Brain' : {wc : 40, ww : 80}
SoftTissue: {
wc: 40,
ww: 400
},
Lung: {
wc: -600,
ww: 1500
},
Liver: {
wc: 90,
ww: 150
},
Bone: {
wc: 480,
ww: 2500
},
Brain: {
wc: 40,
ww: 80
}
};
// For now
@@ -48,53 +63,53 @@ Meteor.startup(function() {
OHIF.viewer.hotkeyFunctions = {
wwwc: function() {
toolManager.setActiveTool("wwwc");
toolManager.setActiveTool('wwwc');
},
zoom: function() {
toolManager.setActiveTool("zoom");
toolManager.setActiveTool('zoom');
},
angle: function() {
toolManager.setActiveTool("angle");
toolManager.setActiveTool('angle');
},
dragProbe: function() {
toolManager.setActiveTool("dragProbe");
toolManager.setActiveTool('dragProbe');
},
ellipticalRoi: function() {
toolManager.setActiveTool("ellipticalRoi");
toolManager.setActiveTool('ellipticalRoi');
},
magnify: function() {
toolManager.setActiveTool("magnify");
toolManager.setActiveTool('magnify');
},
annotate: function() {
toolManager.setActiveTool("annotate");
toolManager.setActiveTool('annotate');
},
stackScroll: function() {
toolManager.setActiveTool("stackScroll");
toolManager.setActiveTool('stackScroll');
},
pan: function() {
toolManager.setActiveTool("pan");
toolManager.setActiveTool('pan');
},
length: function() {
toolManager.setActiveTool("length");
toolManager.setActiveTool('length');
},
spine: function() {
toolManager.setActiveTool("spine");
toolManager.setActiveTool('spine');
},
wwwcRegion: function() {
toolManager.setActiveTool("wwwcRegion");
toolManager.setActiveTool('wwwcRegion');
},
zoomIn: function () {
var button = document.getElementById("zoomIn");
zoomIn: function() {
var button = document.getElementById('zoomIn');
flashButton(button);
zoomIn();
},
zoomOut: function () {
var button = document.getElementById("zoomOut");
zoomOut: function() {
var button = document.getElementById('zoomOut');
flashButton(button);
zoomOut();
},
zoomToFit: function () {
var button = document.getElementById("zoomToFit");
zoomToFit: function() {
var button = document.getElementById('zoomToFit');
flashButton(button);
zoomToFit();
},
@@ -134,27 +149,27 @@ Meteor.startup(function() {
previousActivePanel();
},
invert: function() {
var button = document.getElementById("invert");
var button = document.getElementById('invert');
flashButton(button);
invert();
},
flipV: function() {
var button = document.getElementById("flipV");
var button = document.getElementById('flipV');
flashButton(button);
flipV();
},
flipH: function() {
var button = document.getElementById("flipH");
var button = document.getElementById('flipH');
flashButton(button);
flipH();
},
rotateR: function() {
var button = document.getElementById("rotateR");
var button = document.getElementById('rotateR');
flashButton(button);
rotateR();
},
rotateL: function() {
var button = document.getElementById("rotateL");
var button = document.getElementById('rotateL');
flashButton(button);
rotateL();
},
@@ -174,6 +189,8 @@ Meteor.startup(function() {
}
}
};
OHIF.viewer.loadedSeriesData = {};
});
// Define a jQuery reverse function
@@ -198,7 +215,6 @@ function previousActivePanel() {
setActiveViewport(element);
}
function nextActivePanel() {
log.info('nextActivePanel');
var currentIndex = Session.get('activeViewport');
@@ -224,7 +240,7 @@ function flashButton(button) {
}
button.classList.add('active');
setTimeout(function () {
setTimeout(function() {
button.classList.remove('active');
}, 100);
}
@@ -233,13 +249,13 @@ function bindHotkey(hotkey, task) {
var hotkeyFunctions = OHIF.viewer.hotkeyFunctions;
// Only bind defined, non-empty HotKeys
if (!hotkey || hotkey === "") {
if (!hotkey || hotkey === '') {
return;
}
var fn;
if (task.indexOf("WLPreset") > -1) {
var presetName = task.replace("WLPreset", "");
if (task.indexOf('WLPreset') > -1) {
var presetName = task.replace('WLPreset', '');
fn = function() {
applyWLPresetToActiveElement(presetName);
};
@@ -282,4 +298,4 @@ enableHotkeys = function() {
bindHotkey(taskHotkeys, task);
}
});
};
};
+12 -4
View File
@@ -29,8 +29,14 @@ getWADORSImageId = function(instance) {
//maxPixelValue : 255,
slope: instance.rescaleSlope,
intercept: instance.rescaleIntercept,
windowCenter : windowCenter,
windowWidth : windowWidth,
samplesPerPixel: instance.samplesPerPixel,
imageOrientationPatient: instance.imageOrientationPatient,
imagePositionPatient: instance.imagePositionPatient,
sopClassUid: instance.sopClassUid,
instanceNumber: instance.instanceNumber,
frameOfReferenceUID: instance.frameOfReferenceUID,
windowCenter: windowCenter,
windowWidth: windowWidth,
//render: cornerstone.renderColorImage,
//getPixelData: getPixelData,
//getImageData: getImageData,
@@ -47,6 +53,8 @@ getWADORSImageId = function(instance) {
instance: instance
};
var imageId = cornerstoneWADORSImageLoader.addImage(image);
var imageId = cornerstoneWADOImageLoader.imageManager.add(image);
console.log('WADO-RS ImageID: ' + imageId);
return imageId;
};
};
+11 -6
View File
@@ -1,9 +1,14 @@
/**
* Formats a patient name for display purposes
*/
formatPN = function(context) {
if (!context) {
return;
}
return context.replace('^', ', ');
};
/**
* A global Blaze UI helper to format a patient name for display purposes
*/
UI.registerHelper('formatPN', function (context) {
if (!context) {
return undefined;
}
return context.replace('^', ', ');
});
UI.registerHelper('formatPN', formatPN);
+1 -1
View File
@@ -7,4 +7,4 @@ UI.registerHelper("inlineIf", function (value, match, attributeName) {
return attributeName;
}
return '';
});
});
@@ -0,0 +1,20 @@
/**
* Helper function to determine if the current client devices
* is touch-capable. This can be used to modify certain aspects of the UI.
*
* The check may not work on all devices!
*
* @returns {boolean} true if the client device is touch-capable, false otherwise
*/
isTouchDevice = function() {
return (('ontouchstart' in window) ||
(navigator.MaxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));
};
/**
* Blaze helper for checking if the current device is touch capable
*
* @returns {boolean} true if the client device is touch-capable, false otherwise
*/
UI.registerHelper('isTouchDevice', isTouchDevice);
-13
View File
@@ -1,13 +0,0 @@
/**
* Helper function to determine if the current client devices
* is touch-capable. This can be used to modify certain aspects of the UI.
*
* The check may not work on all devices!
*
* @returns {boolean} true if the client device is touch-capable, false otherwise
*/
isTouchDevice = function() {
return (('ontouchstart' in window) ||
(navigator.MaxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));
};
@@ -46,6 +46,7 @@ addMetaData = function(imageId, data) {
instanceNumber: instanceMetaData.instanceNumber,
laterality: instanceMetaData.laterality,
viewPosition: instanceMetaData.viewPosition,
sliceThickness: instanceMetaData.sliceThickness,
index: imageIndex
};
@@ -1 +0,0 @@
+18 -4
View File
@@ -16,7 +16,9 @@ Package.onUse(function (api) {
api.use('practicalmeteor:loglevel');
api.use('momentjs:moment');
// Our custom package
// Our custom packages
api.use('dicomweb');
api.use('dimseservice');
api.use('cornerstone');
api.use('hangingprotocols');
@@ -107,7 +109,6 @@ Package.onUse(function (api) {
api.addFiles('lib/createStacks.js', 'client');
api.addFiles('lib/getImageId.js', 'client');
api.addFiles('lib/getWADORSImageId.js', 'client');
api.addFiles('lib/isTouchDevice.js', 'client');
api.addFiles('lib/metaDataProvider.js', 'client');
api.addFiles('lib/rerenderViewportWithNewSeries.js', 'client');
api.addFiles('lib/sortStudy.js', 'client');
@@ -125,6 +126,7 @@ Package.onUse(function (api) {
api.addFiles('lib/setFocusToActiveViewport.js', 'client');
api.addFiles('lib/encodeQueryData.js', 'server');
//api.export('accountsConfig', 'client');
api.export('resizeViewportElements','client');
api.export('handleResize','client');
@@ -135,7 +137,6 @@ Package.onUse(function (api) {
api.export('createStacks', 'client');
api.export('getImageId', 'client');
api.export('getWADORSImageId', 'client');
api.export('isTouchDevice', 'client');
api.export('metaDataProvider', 'client');
api.export('rerenderViewportWithNewSeries', 'client');
api.export('sortStudy', 'client');
@@ -153,18 +154,31 @@ Package.onUse(function (api) {
// UI Helpers
api.addFiles('lib/helpers/formatDA.js', 'client');
api.addFiles('lib/helpers/formatNumberPrecision.js', 'client');
api.addFiles('lib/helpers/formatPN.js', 'client');
api.addFiles('lib/helpers/formatTM.js', 'client');
api.addFiles('lib/helpers/inlineIf.js', 'client');
api.addFiles('lib/helpers/formatPN.js', 'client');
api.export('formatPN', 'client');
api.addFiles('lib/helpers/isTouchDevice.js', 'client');
api.export('isTouchDevice', 'client');
// Server-side functions
api.addFiles('server/seed.js', 'server');
api.addFiles('server/lib/namespace.js', 'server');
api.addFiles('server/methods/getStudyMetadata.js', 'server');
api.addFiles('server/methods/worklistSearch.js', 'server');
// DICOMWeb instance, study, and metadata retrieval
api.addFiles('server/services/qido/instances.js', 'server');
api.addFiles('server/services/qido/studies.js', 'server');
api.addFiles('server/services/wado/retrieveMetadata.js', 'server');
// DIMSE instance, study, and metadata retrieval
api.addFiles('server/services/dimse/instances.js', 'server');
api.addFiles('server/services/dimse/studies.js', 'server');
api.addFiles('server/services/dimse/retrieveMetadata.js', 'server');
api.export('Services', 'server');
});
+2 -1
View File
@@ -1,3 +1,4 @@
Services = {};
Services.QIDO = {};
Services.WADO = {};
Services.WADO = {};
Services.DIMSE = {};
@@ -3,13 +3,17 @@ Meteor.methods({
* Retrieves Study metadata given a Study Instance UID
* This Meteor method is available from both the client and the server
*/
'GetStudyMetadata' : function(studyInstanceUid) {
GetStudyMetadata: function(studyInstanceUid) {
log.info('GetStudyMetadata(%s)', studyInstanceUid);
if (!Meteor.settings.dicomWeb) {
throw 'No properly configured server was available over DICOMWeb';
}
// Get the server data. This is user-defined in the
// config.json files used to run the Meteor server
var server = Meteor.settings.dicomWeb.endpoints[0];
return Services.WADO.RetrieveMetadata(server, studyInstanceUid);
}
});
});
@@ -3,16 +3,17 @@ Meteor.methods({
* Use the specified filter to conduct a search from the DICOM server
* @param filter
*/
'WorklistSearch': function(filter) {
if (!Meteor.settings.dicomWeb) {
console.warn('No dicomWeb settings provided! Worklist search is not possible!')
return;
}
// Get the server data. This is user-defined in the
// config.json files used to run the Meteor server
var server = Meteor.settings.dicomWeb.endpoints[0];
WorklistSearch: function(filter) {
if (Meteor.settings.dicomWeb && Meteor.settings.defaultServiceType === 'dicomWeb') {
// Get the server data. This is user-defined in the
// config.json files used to run the Meteor server
var server = Meteor.settings.dicomWeb.endpoints[0];
return Services.QIDO.Studies(server, filter);
return Services.QIDO.Studies(server, filter);
} else if (Meteor.settings.dimse && Meteor.settings.defaultServiceType === 'dimse') {
return Services.DIMSE.Studies(filter);
} else {
throw 'No properly configured server was available over DICOMWeb or DIMSE.';
}
}
});
});
+70
View File
@@ -0,0 +1,70 @@
/**
* Parses data returned from a study search and transforms it into
* an array of series that are present in the study
*
* @param resultData
* @returns {Array} Series List
*/
function resultDataToStudyMetadata(resultData) {
var seriesMap = {};
var seriesList = [];
resultData.forEach(function(instanceRaw) {
var instance = instanceRaw.toObject();
// Use seriesMap to cache series data
// If the series instance UID has already been used to
// process series data, continue using that series
var seriesInstanceUid = instance[0x0020000E];
var series = seriesMap[seriesInstanceUid];
// If no series data exists in the seriesMap cache variable,
// process any available series data
if (!series) {
series = {
seriesInstanceUid: seriesInstanceUid,
seriesNumber: instance[0x00200011],
instances: []
};
// Save this data in the seriesMap cache variable
seriesMap[seriesInstanceUid] = series;
seriesList.push(series);
}
var host = Meteor.settings.dimse.host,
port = Meteor.settings.dimse.port;
var serverRoot = host + ':' + port;
log.info('INSTANCE');
log.info(instance);
var sopInstanceUid = instance[0x00080018];
var uri = serverRoot + '/studies/' + studyInstanceUid + '/series/' + seriesInstanceUid + '/instances/' + sopInstanceUid + '/frames/1';
// Add this instance to the current series
series.instances.push({
sopClassUid: instance[0x00080016],
sopInstanceUid: sopInstanceUid,
uri: uri,
instanceNumber: instance[0x00200013]
});
});
return seriesList;
}
/**
* Retrieve a set of instances using a DIMSE call
* @param studyInstanceUid
* @returns {{wadoUriRoot: String, studyInstanceUid: String, seriesList: Array}}
*/
Services.DIMSE.Instances = function(studyInstanceUid) {
//var url = buildUrl(server, studyInstanceUid);
var result = DIMSE.retrieveInstances(studyInstanceUid);
console.log("DIMSE Instance retrieval");
console.log(result);
return {
studyInstanceUid: studyInstanceUid,
seriesList: resultDataToStudyMetadata(result)
};
};
@@ -0,0 +1,162 @@
/**
* Parses the SourceImageSequence, if it exists, in order
* to return a ReferenceSOPInstanceUID. The ReferenceSOPInstanceUID
* is used to refer to this image in any accompanying DICOM-SR documents.
*
* @param instance
* @returns {String} The ReferenceSOPInstanceUID
*/
function getSourceImageInstanceUid(instance) {
// TODO= Parse the whole Source Image Sequence
// This is a really poor workaround for now.
// Later we should probably parse the whole sequence.
var SourceImageSequence = instance[0x00082112];
log.info('SourceImageSequence ' + SourceImageSequence);
if (SourceImageSequence && SourceImageSequence.length) {
return SourceImageSequence[0][0x00081155];
}
}
/**
* Parses result data from a DIMSE search into Study MetaData
* Returns an object populated with study metadata, including the
* series list.
*
* @param resultData
* @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}}
*/
function resultDataToStudyMetadata(studyInstanceUid, resultData) {
var seriesMap = {};
var seriesList = [];
if (!resultData.length) {
return;
}
var anInstance = resultData[0].toObject();
if (!anInstance) {
return;
}
var studyData = {
seriesList: seriesList,
patientName: anInstance[0x00100010],
patientId: anInstance[0x00100020],
accessionNumber: anInstance[0x00080050],
studyDate: anInstance[0x00080020],
modalities: anInstance[0x00080061],
studyDescription: anInstance[0x00081030],
imageCount: anInstance[0x00201208],
studyInstanceUid: anInstance[0x0020000D]
};
resultData.forEach(function(instanceRaw) {
var instance = instanceRaw.toObject();
var seriesInstanceUid = instance[0x0020000E];
var series = seriesMap[seriesInstanceUid];
if (!series) {
series = {
seriesDescription: instance[0x0008103E],
modality: instance[0x00080060],
seriesInstanceUid: seriesInstanceUid,
seriesNumber: parseFloat(instance[0x00200011]),
instances: []
};
seriesMap[seriesInstanceUid] = series;
seriesList.push(series);
}
var sopInstanceUid = instance[0x00080018];
log.info('instance');
log.info(instance);
var instanceSummary = {
imageType: instance[0x00080008],
sopClassUid: instance[0x00080016],
sopInstanceUid: sopInstanceUid,
instanceNumber: parseFloat(instance[0x00200013]),
imagePositionPatient: instance[0x00200032],
imageOrientationPatient: instance[0x00200037],
frameOfReferenceUID: instance[0x00200052],
sliceLocation: parseFloat(instance[0x00201041]),
samplesPerPixel: parseFloat(instance[0x00280002]),
photometricInterpretation: instance[0x00280004],
rows: parseFloat(instance[0x00280010]),
columns: parseFloat(instance[0x00280011]),
pixelSpacing: instance[0x00280030],
bitsAllocated: parseFloat(instance[0x00280100]),
bitsStored: parseFloat(instance[0x00280101]),
highBit: parseFloat(instance[0x00280102]),
pixelRepresentation: parseFloat(instance[0x00280103]),
windowCenter: instance[0x00281050],
windowWidth: instance[0x00281051],
rescaleIntercept: parseFloat(instance[0x00281052]),
rescaleSlope: parseFloat(instance[0x00281053]),
sourceImageInstanceUid: getSourceImageInstanceUid(instance),
laterality: instance[0x00200062],
viewPosition: instance[0x00185101],
numFrames: parseFloat(instance[0x00280008]),
frameRate: parseFloat(instance[0x00181063])
};
var host = Meteor.settings.dimse.host,
port = Meteor.settings.dimse.port;
var serverRoot = host + ':' + port;
instanceSummary.wadorsuri = serverRoot + '/studies/' + studyInstanceUid + '/series/' + seriesInstanceUid + '/instances/' + sopInstanceUid + '/frames/1';
series.instances.push(instanceSummary);
});
return studyData;
}
/**
* Retrieved Study MetaData from a DICOM server using DIMSE
* @param studyInstanceUid
* @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}}
*/
Services.DIMSE.RetrieveMetadata = function(studyInstanceUid) {
console.log('DIMSE RetrieveMetadata');
var result = DIMSE.retrieveInstances(studyInstanceUid, null, {
0x00080050: '',
0x00080061: '',
0x00081030: '',
0x00201208: '',
0x00080060: '',
0x00080008: '',
0x00200032: '',
0x00200037: '',
0x00200052: '',
0x00201041: '',
0x00280002: '',
0x00280004: '',
0x00280030: '',
0x00280100: '',
0x00280101: '',
0x00280102: '',
0x00280103: '',
0x00281050: '',
0x00281051: '',
0x00281052: '',
0x00281053: '',
0x00200062: '',
0x00185101: '',
0x00280008: '',
0x00181063: '',
0x00082112: ''
});
var study = resultDataToStudyMetadata(studyInstanceUid, result);
if (!study) {
study = {};
}
study.studyInstanceUid = studyInstanceUid;
console.log(study);
console.log(study.seriesList[0].instances[0]);
return study;
};
+48
View File
@@ -0,0 +1,48 @@
/**
* Parses resulting data from a QIDO call into a set of Study MetaData
*
* @param resultData
* @returns {Array} An array of Study MetaData objects
*/
function resultDataToStudies(resultData) {
var studies = [];
resultData.forEach(function(studyRaw) {
var study = studyRaw.toObject();
studies.push({
studyInstanceUid: study[0x0020000D],
// 00080005 = SpecificCharacterSet
studyDate: study[0x00080020],
studyTime: study[0x00080030],
accessionNumber: study[0x00080050],
referringPhysicianName: study[0x00080090],
// 00081190 = URL
patientName: study[0x00100010],
patientId: study[0x00100020],
patientBirthdate: study[0x00100030],
patientSex: study[0x00100040],
imageCount: study[0x00201208],
studyId: study[0x00200010],
studyDescription: study[0x00081030],
modalities: study[0x00080061]
});
});
return studies;
}
Services.DIMSE.Studies = function(filter) {
console.log('Services.DIMSE.Studies');
var parameters = {
0x00100010: filter.patientName,
0x00100020: filter.patientId,
0x00080050: filter.accessionNumber,
0x00081030: filter.studyDescription,
0x00100040: "",
0x00201208: "",
0x00080061: ""
};
var results = DIMSE.retrieveStudies(parameters);
return resultDataToStudies(results);
};
@@ -30,10 +30,10 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
// If no series data exists in the seriesMap cache variable,
// process any available series data
if(!series) {
if (!series) {
series = {
seriesInstanceUid : seriesInstanceUid,
seriesNumber : DICOMWeb.getString(instance['00200011']),
seriesInstanceUid: seriesInstanceUid,
seriesNumber: DICOMWeb.getString(instance['00200011']),
instances: []
};
@@ -52,7 +52,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
// manually create a WADO-URI from the UIDs
// NOTE: Haven't been able to get Orthanc's WADO-URI to work yet - maybe its not configured?
var sopInstanceUid = DICOMWeb.getString(instance['00080018']);
var uri = server.wadoUriRoot + '?requestType=WADO&studyUID=' + studyInstanceUid + '&seriesUID=' + seriesInstanceUid + '&objectUID=' + sopInstanceUid + "&contentType=application%2Fdicom";
var uri = server.wadoUriRoot + '?requestType=WADO&studyUID=' + studyInstanceUid + '&seriesUID=' + seriesInstanceUid + '&objectUID=' + sopInstanceUid + '&contentType=application%2Fdicom';
// Add this instance to the current series
series.instances.push({
@@ -61,8 +61,8 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
uri: uri,
instanceNumber: DICOMWeb.getString(instance['00200013'])
});
});
return seriesList;
});
return seriesList;
}
/**
@@ -80,4 +80,4 @@ Services.QIDO.Instances = function(server, studyInstanceUid) {
studyInstanceUid: studyInstanceUid,
seriesList: resultDataToStudyMetadata(server, studyInstanceUid, result.data)
};
};
};
@@ -16,6 +16,7 @@ function filterToQIDOURL(server, filter) {
PatientName: filter.patientName,
PatientID: filter.patientId,
AccessionNumber: filter.accessionNumber,
StudyDescription: filter.studyDescription,
limit: filter.limit || 20,
includefield: server.qidoSupportsIncludeField ? 'all' : commaSeparatedFields
};
@@ -105,7 +105,8 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
laterality: DICOMWeb.getString(instance['00200062']),
viewPosition: DICOMWeb.getString(instance['00185101']),
numFrames: DICOMWeb.getNumber(instance['00280008']),
frameRate: DICOMWeb.getNumber(instance['00181063'])
frameRate: DICOMWeb.getNumber(instance['00181063']),
sliceThickness: DICOMWeb.getNumber(instance['00180050'])
};
if (server.imageRendering === 'wadouri') {