OHIF-135: providing all data required by cornerstoneWADOImageLoader to wadors instances
This commit is contained in:
parent
3d99821117
commit
9ad0b670b3
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
|
||||
17
Packages/ohif-viewerbase/client/lib/getWADORSImageUrl.js
Normal file
17
Packages/ohif-viewerbase/client/lib/getWADORSImageUrl.js
Normal 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);
|
||||
}
|
||||
87
Packages/ohif-viewerbase/client/lib/updateMetaDataManager.js
Normal file
87
Packages/ohif-viewerbase/client/lib/updateMetaDataManager.js
Normal 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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user