OHIF-135: providing all data required by cornerstoneWADOImageLoader to wadors instances

This commit is contained in:
Leonardo Campos 2017-03-03 09:34:56 -03:00
parent 3d99821117
commit 9ad0b670b3
7 changed files with 194 additions and 106 deletions

View File

@ -59,6 +59,9 @@ getStudyMetadata = function(studyInstanceUid, doneCallback, failCallback) {
// and instance number in ascending order
OHIF.viewerbase.sortStudy(study);
// Updates WADO-RS metaDataManager
OHIF.viewerbase.updateMetaDataManager(study);
// Add additional metadata to our study from the studylist
var studylistStudy = StudyListStudies.findOne({
studyInstanceUid: study.studyInstanceUid

View File

@ -169,6 +169,26 @@ function getFrameIncrementPointer(element) {
return frameIncrementPointerNames[value];
}
function getRadiopharmaceuticalInfo(instance) {
const modality = DICOMWeb.getString(instance['00080060']);
if (modality !== 'PT') {
return;
}
const radiopharmaceuticalInfo = instance['00540016'];
if ((radiopharmaceuticalInfo === undefined) || !radiopharmaceuticalInfo.Value || !radiopharmaceuticalInfo.Value.length) {
return;
}
const firstPetRadiopharmaceuticalInfo = radiopharmaceuticalInfo.Value[0];
return {
radiopharmaceuticalStartTime: DICOMWeb.getString(firstPetRadiopharmaceuticalInfo['00181072']),
radionuclideTotalDose: DICOMWeb.getNumber(firstPetRadiopharmaceuticalInfo['00181074']),
radionuclideHalfLife: DICOMWeb.getNumber(firstPetRadiopharmaceuticalInfo['00181075'])
};
}
/**
* Parses result data from a WADO search into Study MetaData
* Returns an object populated with study metadata, including the
@ -196,6 +216,9 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
seriesList: seriesList,
patientName: DICOMWeb.getName(anInstance['00100010']),
patientId: DICOMWeb.getString(anInstance['00100020']),
patientAge: DICOMWeb.getNumber(anInstance['00101010']),
patientSize: DICOMWeb.getNumber(anInstance['00101020']),
patientWeight: DICOMWeb.getNumber(anInstance['00101030']),
accessionNumber: DICOMWeb.getString(anInstance['00080050']),
studyDate: DICOMWeb.getString(anInstance['00080020']),
modalities: DICOMWeb.getString(anInstance['00080061']),
@ -214,6 +237,8 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
modality: DICOMWeb.getString(instance['00080060']),
seriesInstanceUid: seriesInstanceUid,
seriesNumber: DICOMWeb.getNumber(instance['00200011']),
seriesDate: DICOMWeb.getString(instance['00080021']),
seriesTime: DICOMWeb.getString(instance['00080031']),
instances: []
};
seriesMap[seriesInstanceUid] = series;
@ -269,11 +294,12 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
lossyImageCompressionMethod: DICOMWeb.getString(instance['00282114']),
echoNumber: DICOMWeb.getString(instance['00180086']),
contrastBolusAgent: DICOMWeb.getString(instance['00180010']),
radiopharmaceuticalInfo: getRadiopharmaceuticalInfo(instance),
baseWadoRsUri: baseWadoRsUri,
wadouri: WADOProxy.convertURL(wadouri, server.requestOptions),
wadorsuri: WADOProxy.convertURL(wadorsuri),
imageRendering: server.imageRendering,
thumbnailRendering: server.thumbnailRendering,
thumbnailRendering: server.thumbnailRendering
};
// Get additional information if the instance uses "PALETTE COLOR" photometric interpretation

View File

@ -59,6 +59,10 @@ Viewerbase.updateAllViewports = updateAllViewports;
import { sortStudy } from './lib/sortStudy';
Viewerbase.sortStudy = sortStudy;
// updateMetaDataManager
import { updateMetaDataManager } from './lib/updateMetaDataManager';
Viewerbase.updateMetaDataManager = updateMetaDataManager;
// updateOrientationMarkers
import { updateOrientationMarkers } from './lib/updateOrientationMarkers';
Viewerbase.updateOrientationMarkers = updateOrientationMarkers;

View File

@ -0,0 +1,48 @@
export class WadoRsMetaDataBuilder {
constructor() {
this.tags = {};
}
addTag(tag, value, multi) {
this.tags[tag] = {
tag,
value,
multi
};
return this;
}
toJSON() {
const json = {};
const keys = Object.keys(this.tags);
keys.forEach(key => {
if (!this.tags.hasOwnProperty(key)) {
return;
}
const tag = this.tags[key];
const multi = !!tag.multi;
let value = tag.value;
if ((value == null) || ((value.length === 1) && (value[0] == null))) {
return;
}
if ((typeof value === 'string') && multi) {
value = value.split('\\');
}
if (!_.isArray(value)) {
value = [value];
}
json[key] = {
Value: value
};
});
return json;
}
}

View File

@ -1,66 +1,6 @@
import { OHIF } from 'meteor/ohif:core';
import { _ } from 'meteor/underscore';
class ImageMetadataBuilder {
constructor() {
this.tags = {};
}
addTag(tag, value, multi) {
this.tags[tag] = {
tag,
value,
multi
}
return this;
}
toJSON() {
const json = {};
const keys = Object.keys(this.tags);
keys.forEach(key => {
if(!this.tags.hasOwnProperty(key)) {
return;
}
const tag = this.tags[key];
const multi = !!tag.multi;
let value = tag.value;
if((value == null) || ((value.length === 1) && (value[0] == null))) {
return;
}
if((typeof value === 'string') && multi) {
value = value.split('\\');
}
if(!_.isArray(value)) {
value = [value];
}
json[key] = {
Value: value
};
});
return json;
}
}
function formatWADORSImageUrl(wadorsuri, frame) {
// We need to sum 1 because WADO-RS frame number is 1-based
frame = (frame || 0) + 1;
// Replaces /frame/1 by /frame/{frame}
// TODO: Maybe should be better to export the WADOProxy to be able to use it on client
// Example: WADOProxy.convertURL(baseWadoRsUri + '/frame/' + frame)
wadorsuri = wadorsuri.replace(/(%2Fframes%2F)(\d+)/, `$1${frame}`);
return Meteor.absoluteUrl(wadorsuri);
}
import { getWADORSImageUrl } from './getWADORSImageUrl';
/**
* Obtain an imageId for Cornerstone based on the WADO-RS scheme
@ -69,51 +9,14 @@ function formatWADORSImageUrl(wadorsuri, frame) {
* @returns {string} The imageId to be used by Cornerstone
*/
export function getWADORSImageId(instance, frame) {
const uri = formatWADORSImageUrl(instance.wadorsuri, frame);
const uri = getWADORSImageUrl(instance, frame);
if (!uri) {
return;
}
const imageId = `wadors:${uri}`;
const imageMetadata = new ImageMetadataBuilder()
.addTag('00080016', instance.sopClassUid)
.addTag('00080018', instance.sopInstanceUid)
.addTag('00180050', instance.sliceThickness)
.addTag('00200013', instance.instanceNumber)
.addTag('00200032', instance.imagePositionPatient, true)
.addTag('00200037', instance.imageOrientationPatient, true)
.addTag('00200052', instance.frameOfReferenceUID)
.addTag('00201041', instance.sliceLocation)
.addTag('00280002', instance.samplesPerPixel)
.addTag('00280004', instance.photometricInterpretation)
.addTag('00280006', instance.planarConfiguration)
.addTag('00280010', instance.rows)
.addTag('00280011', instance.columns)
.addTag('00280030', instance.pixelSpacing, true)
.addTag('00280034', instance.pixelAspectRatio, true)
.addTag('00280100', instance.bitsAllocated)
.addTag('00280101', instance.bitsStored)
.addTag('00280102', instance.highBit)
.addTag('00280103', instance.pixelRepresentation)
.addTag('00280106', instance.smallestPixelValue)
.addTag('00280107', instance.largestPixelValue)
.addTag('00281050', instance.windowCenter, true)
.addTag('00281051', instance.windowWidth, true)
.addTag('00281052', instance.rescaleIntercept)
.addTag('00281053', instance.rescaleSlope)
.addTag('00281054', instance.rescaleType)
.addTag('00281101', instance.redPaletteColorLookupTableDescriptor)
.addTag('00281102', instance.greenPaletteColorLookupTableDescriptor)
.addTag('00281103', instance.bluePaletteColorLookupTableDescriptor)
.addTag('00281201', instance.redPaletteColorLookupTableData)
.addTag('00281202', instance.greenPaletteColorLookupTableData)
.addTag('00281203', instance.bluePaletteColorLookupTableData)
.toJSON();
_.extend(imageMetadata, {
uri: uri,
instance: instance
});
cornerstoneWADOImageLoader.wadors.metaDataManager.add(imageId, imageMetadata);
OHIF.log.info('WADO-RS ImageID: ' + imageId);
return imageId;
};

View File

@ -0,0 +1,17 @@
export function getWADORSImageUrl(instance, frame) {
let wadorsuri = instance.wadorsuri;
if (!wadorsuri) {
return;
}
// We need to sum 1 because WADO-RS frame number is 1-based
frame = (frame || 0) + 1;
// Replaces /frame/1 by /frame/{frame}
// TODO: Maybe should be better to export the WADOProxy to be able to use it on client
// Example: WADOProxy.convertURL(baseWadoRsUri + '/frame/' + frame)
wadorsuri = wadorsuri.replace(/(%2Fframes%2F)(\d+)/, `$1${frame}`);
return Meteor.absoluteUrl(wadorsuri);
}

View File

@ -0,0 +1,87 @@
import { _ } from 'meteor/underscore';
import { getWADORSImageId } from './getWADORSImageId';
import { WadoRsMetaDataBuilder } from './classes/metadata/WadoRsMetaDataBuilder';
function getRadiopharmaceuticalInfoMetaData(instance) {
const radiopharmaceuticalInfo = instance.radiopharmaceuticalInfo;
if ((instance.modality !== 'PT') || !radiopharmaceuticalInfo) {
return;
}
return new WadoRsMetaDataBuilder()
.addTag('00181072', radiopharmaceuticalInfo.radiopharmaceuticalStartTime)
.addTag('00181074', radiopharmaceuticalInfo.radionuclideTotalDose)
.addTag('00181075', radiopharmaceuticalInfo.radionuclideHalfLife)
.toJSON();
}
const getWadoRsInstanceMetaData = (study, series, instance) => {
return new WadoRsMetaDataBuilder()
.addTag('00080016', instance.sopClassUid)
.addTag('00080018', instance.sopInstanceUid)
.addTag('00080021', series.seriesDate)
.addTag('00080031', series.seriesTime)
.addTag('00080060', instance.modality)
.addTag('00101010', study.patientAge)
.addTag('00101020', study.patientSize)
.addTag('00101030', study.patientWeight)
.addTag('00180050', instance.sliceThickness)
.addTag('0020000e', series.seriesInstanceUid)
.addTag('00200011', series.seriesNumber)
.addTag('0020000d', study.studyInstanceUid)
.addTag('00200013', instance.instanceNumber)
.addTag('00200032', instance.imagePositionPatient, true)
.addTag('00200037', instance.imageOrientationPatient, true)
.addTag('00200052', instance.frameOfReferenceUID)
.addTag('00201041', instance.sliceLocation)
.addTag('00280002', instance.samplesPerPixel)
.addTag('00280004', instance.photometricInterpretation)
.addTag('00280006', instance.planarConfiguration)
.addTag('00280010', instance.rows)
.addTag('00280011', instance.columns)
.addTag('00280030', instance.pixelSpacing, true)
.addTag('00280034', instance.pixelAspectRatio, true)
.addTag('00280100', instance.bitsAllocated)
.addTag('00280101', instance.bitsStored)
.addTag('00280102', instance.highBit)
.addTag('00280103', instance.pixelRepresentation)
.addTag('00280106', instance.smallestPixelValue)
.addTag('00280107', instance.largestPixelValue)
.addTag('00281050', instance.windowCenter, true)
.addTag('00281051', instance.windowWidth, true)
.addTag('00281052', instance.rescaleIntercept)
.addTag('00281053', instance.rescaleSlope)
.addTag('00281054', instance.rescaleType)
.addTag('00281101', instance.redPaletteColorLookupTableDescriptor)
.addTag('00281102', instance.greenPaletteColorLookupTableDescriptor)
.addTag('00281103', instance.bluePaletteColorLookupTableDescriptor)
.addTag('00281201', instance.redPaletteColorLookupTableData)
.addTag('00281202', instance.greenPaletteColorLookupTableData)
.addTag('00281203', instance.bluePaletteColorLookupTableData)
.addTag('00540016', getRadiopharmaceuticalInfoMetaData(instance))
.toJSON();
};
export function updateMetaDataManager(study) {
study.seriesList.forEach(series => {
series.instances.forEach(instance => {
// Cache just images that are going to be loaded via WADO-RS
if ((instance.imageRendering !== 'wadors') && (instance.thumbnailRendering !== 'wadors')) {
OHIF.log.info(`Skiping cornerstone metaDataManager update (${imageId})`);
return;
}
const metaData = getWadoRsInstanceMetaData(study, series, instance);
const numberOfFrames = instance.numberOfFrames || 1;
// We can share the same metaData with all frames because it doesn't have
// any frame specific data, such as frameNumber, pixelData, offset, etc.
// WADO-RS frame number is 1-based
for (let frameNumber = 0; frameNumber < numberOfFrames; frameNumber++) {
const imageId = getWADORSImageId(instance, frameNumber);
cornerstoneWADOImageLoader.wadors.metaDataManager.add(imageId, metaData);
}
});
});
}