Updates for Timepoint assocation (LT-60) and Conformance Checks (LT-92, LT-93, LT-94)
This commit is contained in:
1 parent
6c4eae3699
commit
beaa56c0b3
144 files changed
+5050
-2416
No files matched your search
@@ -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
@@ -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
@@ -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') {
|
||||
|
||||
Reference in new issue
Block a user