Skip to content

Commit

Permalink
feat: adding support for multiframe metadata in wadors and wadouri (#494
Browse files Browse the repository at this point in the history
)

* adding suppoort for multiframe in cswil

* Refactoring code and add comments

* Refactor and comment code

* Apply changes to wadouri side

* Refactoring multiframe functions

* Applying PR reviewer suggestions

* adding suppoort for multiframe in cswil

* Refactoring code and add comments

* Refactor and comment code

* Apply changes to wadouri side

* Refactoring multiframe functions

* Applying refactoring changes from PR review

* Resolving rebase issues

* Refactoring code for wado and wadouri code

* Minor typo fix from last commit

* Applying camel name for multiframe function names

* Adding multifrmae support for wadouri

* Minor typo changes

* rename file
  • Loading branch information
rodrigobasilio2022 authored Jan 16, 2023
1 parent 16e0130 commit 95b886f
Show file tree
Hide file tree
Showing 11 changed files with 464 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"proseWrap": "always",
"tabWidth": 2,
"semi": true,
"singleQuote": true
"singleQuote": true,
"endOfLine":"auto"
}
83 changes: 83 additions & 0 deletions src/imageLoader/wadors/combineFrameInstance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import getTagValue from './getTagValue.js';

function getFrameInformation(
PerFrameFunctionalGroupsSequence,
SharedFunctionalGroupsSequence,
frameNumber
) {
const shared = (
SharedFunctionalGroupsSequence
? Object.values(SharedFunctionalGroupsSequence[0])
: []
)
.map((it) => it[0])
.filter((it) => it !== undefined && typeof it === 'object');
const perFrame = (
PerFrameFunctionalGroupsSequence
? Object.values(PerFrameFunctionalGroupsSequence[frameNumber - 1])
: []
)
.map((it) => it.Value[0])
.filter((it) => it !== undefined && typeof it === 'object');

return {
shared,
perFrame,
};
}

function getMultiframeInformation(metaData) {
let {
52009230: PerFrameFunctionalGroupsSequence,
52009229: SharedFunctionalGroupsSequence,
'00280008': NumberOfFrames,
// eslint-disable-next-line prefer-const
...rest
} = metaData;

PerFrameFunctionalGroupsSequence = getTagValue(
PerFrameFunctionalGroupsSequence,
false
);
SharedFunctionalGroupsSequence = getTagValue(
SharedFunctionalGroupsSequence,
false
);
NumberOfFrames = getTagValue(NumberOfFrames);

return {
PerFrameFunctionalGroupsSequence,
SharedFunctionalGroupsSequence,
NumberOfFrames,
rest,
};
}
// function that retrieves specific frame metadata information from multiframe
// metadata
function combineFrameInstance(frameNumber, instance) {
const {
PerFrameFunctionalGroupsSequence,
SharedFunctionalGroupsSequence,
NumberOfFrames,
rest,
} = getMultiframeInformation(instance);

if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
const { shared, perFrame } = getFrameInformation(
PerFrameFunctionalGroupsSequence,
SharedFunctionalGroupsSequence,
frameNumber
);

return Object.assign(
rest,
{ '00280008': NumberOfFrames },
...Object.values(shared),
...Object.values(perFrame)
);
}

return instance;
}

export { combineFrameInstance, getMultiframeInformation, getFrameInformation };
11 changes: 11 additions & 0 deletions src/imageLoader/wadors/getTagValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function getTagValue(tag, justElement = true) {
if (tag && tag.Value) {
if (tag.Value[0] && justElement) {
return tag.Value[0];
}

return tag.Value;
}

return tag;
}
16 changes: 16 additions & 0 deletions src/imageLoader/wadors/metaData/fixNMMetadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import getTagValue from '../getTagValue.js';

export default function fixNMMetadata(metaData) {
if (!metaData['00200032'] || metaData['00200037']) {
// adjust metadata in case of multiframe NM data, as the dicom tags
// 00200032 and 00200037 could be found only in the dicom tag 00540022
const detectorInformationSequence = getTagValue(metaData['00540022']);

if (detectorInformationSequence) {
metaData['00200032'] = detectorInformationSequence['00200032'];
metaData['00200037'] = detectorInformationSequence['00200037'];
}
}

return metaData;
}
44 changes: 43 additions & 1 deletion src/imageLoader/wadors/metaData/metaDataProvider.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,53 @@
import external from '../../../externalModules.js';
import getNumberValues from './getNumberValues.js';
import getValue from './getValue.js';
import getNumberValue from './getNumberValue.js';
import getOverlayPlaneModule from './getOverlayPlaneModule.js';
import metaDataManager from '../metaDataManager.js';
import getValue from './getValue.js';
//import fixNMMetadata from './fixNMMetadata.js';
import {
getMultiframeInformation,
getFrameInformation,
} from '../combineFrameInstance.js';
import multiframeMetadata from '../retrieveMultiframeMetadata.js';

function metaDataProvider(type, imageId) {
if (type === 'multiframeModule') {
// the get function removes the PerFrameFunctionalGroupsSequence
const { metadata, frame } =
multiframeMetadata.retrieveMultiframeMetadata(imageId);

if (!metadata) {
return;
}
const {
PerFrameFunctionalGroupsSequence,
SharedFunctionalGroupsSequence,
NumberOfFrames,
} = getMultiframeInformation(metadata);

if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
const { shared, perFrame } = getFrameInformation(
PerFrameFunctionalGroupsSequence,
SharedFunctionalGroupsSequence,
frame
);

return {
NumberOfFrames,
//PerFrameFunctionalGroupsSequence,
PerFrameFunctionalInformation: perFrame,
SharedFunctionalInformation: shared,
};
}

return {
NumberOfFrames,
//PerFrameFunctionalGroupsSequence,
};
}
const { dicomParser } = external;

const metaData = metaDataManager.get(imageId);

if (!metaData) {
Expand Down Expand Up @@ -38,6 +79,7 @@ function metaDataProvider(type, imageId) {
}

if (type === 'imagePlaneModule') {
//metaData = fixNMMetadata(metaData);
const imageOrientationPatient = getNumberValues(metaData['00200037'], 6);
const imagePositionPatient = getNumberValues(metaData['00200032'], 3);
const pixelSpacing = getNumberValues(metaData['00280030'], 2);
Expand Down
37 changes: 36 additions & 1 deletion src/imageLoader/wadors/metaDataManager.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
import imageIdToURI from '../imageIdToURI.js';
import { combineFrameInstance } from './combineFrameInstance.js';
import multiframeMetadata from './retrieveMultiframeMetadata.js';

let metadataByImageURI = [];

function add(imageId, metadata) {
const imageURI = imageIdToURI(imageId);

metadata.isMultiframe = multiframeMetadata.isMultiframe(metadata);

metadataByImageURI[imageURI] = metadata;
}

// multiframes images will have only one imageid returned by the dicomweb
// client and registered in metadataByImageURI for all the n frames. If an
// iamgeid does not have metadata, or it does not have at all, or the imageid
// belongs to a frame, not registered in metadataByImageURI
function get(imageId) {
const imageURI = imageIdToURI(imageId);

return metadataByImageURI[imageURI];
// dealing first with the non multiframe information
let metadata = metadataByImageURI[imageURI];

if (metadata) {
if (!metadata.isMultiframe) {
return metadata;
}
}

let frame = 1;

if (!metadata) {
// in this case it could indicate a multiframe imageid
// Try to get the first frame metadata, where is stored the multiframe info
const firstFrameInfo =
multiframeMetadata._retrieveMultiframeMetadata(imageURI);

metadata = firstFrameInfo.metadata;
frame = firstFrameInfo.frame;
}

if (metadata) {
metadata = combineFrameInstance(frame, metadata);
}

return metadata;
}

function remove(imageId) {
Expand All @@ -24,6 +57,8 @@ function purge() {
metadataByImageURI = [];
}

export { metadataByImageURI };

export default {
add,
get,
Expand Down
39 changes: 39 additions & 0 deletions src/imageLoader/wadors/retrieveMultiframeMetadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import getValue from './metaData/getValue.js';
import imageIdToURI from '../imageIdToURI.js';
import { metadataByImageURI } from './metaDataManager.js';

// get metadata information for the first frame
function _retrieveMultiframeMetadata(imageURI) {
const lastSlashIdx = imageURI.indexOf('/frames/') + 8;
// imageid string without frame number
const imageIdFrameless = imageURI.slice(0, lastSlashIdx);
// calculating frame number
const frame = parseInt(imageURI.slice(lastSlashIdx), 10);
// retrieving the frame 1 that contains multiframe information

const metadata = metadataByImageURI[`${imageIdFrameless}1`];

return {
metadata,
frame,
};
}

function retrieveMultiframeMetadata(imageId) {
const imageURI = imageIdToURI(imageId);

return _retrieveMultiframeMetadata(imageURI);
}

function isMultiframe(metadata) {
// Checks if dicomTag NumberOf Frames exists and it is greater than one
const numberOfFrames = getValue(metadata['00280008']);

return numberOfFrames && numberOfFrames > 1;
}

export default {
_retrieveMultiframeMetadata,
retrieveMultiframeMetadata,
isMultiframe,
};
Loading

0 comments on commit 95b886f

Please sign in to comment.