Skip to content

Commit 95b886f

Browse files
feat: adding support for multiframe metadata in wadors and wadouri (#494)
* 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
1 parent 16e0130 commit 95b886f

File tree

11 files changed

+464
-8
lines changed

11 files changed

+464
-8
lines changed

.prettierrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"proseWrap": "always",
55
"tabWidth": 2,
66
"semi": true,
7-
"singleQuote": true
7+
"singleQuote": true,
8+
"endOfLine":"auto"
89
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import getTagValue from './getTagValue.js';
2+
3+
function getFrameInformation(
4+
PerFrameFunctionalGroupsSequence,
5+
SharedFunctionalGroupsSequence,
6+
frameNumber
7+
) {
8+
const shared = (
9+
SharedFunctionalGroupsSequence
10+
? Object.values(SharedFunctionalGroupsSequence[0])
11+
: []
12+
)
13+
.map((it) => it[0])
14+
.filter((it) => it !== undefined && typeof it === 'object');
15+
const perFrame = (
16+
PerFrameFunctionalGroupsSequence
17+
? Object.values(PerFrameFunctionalGroupsSequence[frameNumber - 1])
18+
: []
19+
)
20+
.map((it) => it.Value[0])
21+
.filter((it) => it !== undefined && typeof it === 'object');
22+
23+
return {
24+
shared,
25+
perFrame,
26+
};
27+
}
28+
29+
function getMultiframeInformation(metaData) {
30+
let {
31+
52009230: PerFrameFunctionalGroupsSequence,
32+
52009229: SharedFunctionalGroupsSequence,
33+
'00280008': NumberOfFrames,
34+
// eslint-disable-next-line prefer-const
35+
...rest
36+
} = metaData;
37+
38+
PerFrameFunctionalGroupsSequence = getTagValue(
39+
PerFrameFunctionalGroupsSequence,
40+
false
41+
);
42+
SharedFunctionalGroupsSequence = getTagValue(
43+
SharedFunctionalGroupsSequence,
44+
false
45+
);
46+
NumberOfFrames = getTagValue(NumberOfFrames);
47+
48+
return {
49+
PerFrameFunctionalGroupsSequence,
50+
SharedFunctionalGroupsSequence,
51+
NumberOfFrames,
52+
rest,
53+
};
54+
}
55+
// function that retrieves specific frame metadata information from multiframe
56+
// metadata
57+
function combineFrameInstance(frameNumber, instance) {
58+
const {
59+
PerFrameFunctionalGroupsSequence,
60+
SharedFunctionalGroupsSequence,
61+
NumberOfFrames,
62+
rest,
63+
} = getMultiframeInformation(instance);
64+
65+
if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
66+
const { shared, perFrame } = getFrameInformation(
67+
PerFrameFunctionalGroupsSequence,
68+
SharedFunctionalGroupsSequence,
69+
frameNumber
70+
);
71+
72+
return Object.assign(
73+
rest,
74+
{ '00280008': NumberOfFrames },
75+
...Object.values(shared),
76+
...Object.values(perFrame)
77+
);
78+
}
79+
80+
return instance;
81+
}
82+
83+
export { combineFrameInstance, getMultiframeInformation, getFrameInformation };
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default function getTagValue(tag, justElement = true) {
2+
if (tag && tag.Value) {
3+
if (tag.Value[0] && justElement) {
4+
return tag.Value[0];
5+
}
6+
7+
return tag.Value;
8+
}
9+
10+
return tag;
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import getTagValue from '../getTagValue.js';
2+
3+
export default function fixNMMetadata(metaData) {
4+
if (!metaData['00200032'] || metaData['00200037']) {
5+
// adjust metadata in case of multiframe NM data, as the dicom tags
6+
// 00200032 and 00200037 could be found only in the dicom tag 00540022
7+
const detectorInformationSequence = getTagValue(metaData['00540022']);
8+
9+
if (detectorInformationSequence) {
10+
metaData['00200032'] = detectorInformationSequence['00200032'];
11+
metaData['00200037'] = detectorInformationSequence['00200037'];
12+
}
13+
}
14+
15+
return metaData;
16+
}

src/imageLoader/wadors/metaData/metaDataProvider.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,53 @@
11
import external from '../../../externalModules.js';
22
import getNumberValues from './getNumberValues.js';
3-
import getValue from './getValue.js';
43
import getNumberValue from './getNumberValue.js';
54
import getOverlayPlaneModule from './getOverlayPlaneModule.js';
65
import metaDataManager from '../metaDataManager.js';
6+
import getValue from './getValue.js';
7+
//import fixNMMetadata from './fixNMMetadata.js';
8+
import {
9+
getMultiframeInformation,
10+
getFrameInformation,
11+
} from '../combineFrameInstance.js';
12+
import multiframeMetadata from '../retrieveMultiframeMetadata.js';
713

814
function metaDataProvider(type, imageId) {
15+
if (type === 'multiframeModule') {
16+
// the get function removes the PerFrameFunctionalGroupsSequence
17+
const { metadata, frame } =
18+
multiframeMetadata.retrieveMultiframeMetadata(imageId);
19+
20+
if (!metadata) {
21+
return;
22+
}
23+
const {
24+
PerFrameFunctionalGroupsSequence,
25+
SharedFunctionalGroupsSequence,
26+
NumberOfFrames,
27+
} = getMultiframeInformation(metadata);
28+
29+
if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
30+
const { shared, perFrame } = getFrameInformation(
31+
PerFrameFunctionalGroupsSequence,
32+
SharedFunctionalGroupsSequence,
33+
frame
34+
);
35+
36+
return {
37+
NumberOfFrames,
38+
//PerFrameFunctionalGroupsSequence,
39+
PerFrameFunctionalInformation: perFrame,
40+
SharedFunctionalInformation: shared,
41+
};
42+
}
43+
44+
return {
45+
NumberOfFrames,
46+
//PerFrameFunctionalGroupsSequence,
47+
};
48+
}
949
const { dicomParser } = external;
50+
1051
const metaData = metaDataManager.get(imageId);
1152

1253
if (!metaData) {
@@ -38,6 +79,7 @@ function metaDataProvider(type, imageId) {
3879
}
3980

4081
if (type === 'imagePlaneModule') {
82+
//metaData = fixNMMetadata(metaData);
4183
const imageOrientationPatient = getNumberValues(metaData['00200037'], 6);
4284
const imagePositionPatient = getNumberValues(metaData['00200032'], 3);
4385
const pixelSpacing = getNumberValues(metaData['00280030'], 2);

src/imageLoader/wadors/metaDataManager.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,50 @@
11
import imageIdToURI from '../imageIdToURI.js';
2+
import { combineFrameInstance } from './combineFrameInstance.js';
3+
import multiframeMetadata from './retrieveMultiframeMetadata.js';
24

35
let metadataByImageURI = [];
46

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

10+
metadata.isMultiframe = multiframeMetadata.isMultiframe(metadata);
11+
812
metadataByImageURI[imageURI] = metadata;
913
}
1014

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

14-
return metadataByImageURI[imageURI];
22+
// dealing first with the non multiframe information
23+
let metadata = metadataByImageURI[imageURI];
24+
25+
if (metadata) {
26+
if (!metadata.isMultiframe) {
27+
return metadata;
28+
}
29+
}
30+
31+
let frame = 1;
32+
33+
if (!metadata) {
34+
// in this case it could indicate a multiframe imageid
35+
// Try to get the first frame metadata, where is stored the multiframe info
36+
const firstFrameInfo =
37+
multiframeMetadata._retrieveMultiframeMetadata(imageURI);
38+
39+
metadata = firstFrameInfo.metadata;
40+
frame = firstFrameInfo.frame;
41+
}
42+
43+
if (metadata) {
44+
metadata = combineFrameInstance(frame, metadata);
45+
}
46+
47+
return metadata;
1548
}
1649

1750
function remove(imageId) {
@@ -24,6 +57,8 @@ function purge() {
2457
metadataByImageURI = [];
2558
}
2659

60+
export { metadataByImageURI };
61+
2762
export default {
2863
add,
2964
get,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import getValue from './metaData/getValue.js';
2+
import imageIdToURI from '../imageIdToURI.js';
3+
import { metadataByImageURI } from './metaDataManager.js';
4+
5+
// get metadata information for the first frame
6+
function _retrieveMultiframeMetadata(imageURI) {
7+
const lastSlashIdx = imageURI.indexOf('/frames/') + 8;
8+
// imageid string without frame number
9+
const imageIdFrameless = imageURI.slice(0, lastSlashIdx);
10+
// calculating frame number
11+
const frame = parseInt(imageURI.slice(lastSlashIdx), 10);
12+
// retrieving the frame 1 that contains multiframe information
13+
14+
const metadata = metadataByImageURI[`${imageIdFrameless}1`];
15+
16+
return {
17+
metadata,
18+
frame,
19+
};
20+
}
21+
22+
function retrieveMultiframeMetadata(imageId) {
23+
const imageURI = imageIdToURI(imageId);
24+
25+
return _retrieveMultiframeMetadata(imageURI);
26+
}
27+
28+
function isMultiframe(metadata) {
29+
// Checks if dicomTag NumberOf Frames exists and it is greater than one
30+
const numberOfFrames = getValue(metadata['00280008']);
31+
32+
return numberOfFrames && numberOfFrames > 1;
33+
}
34+
35+
export default {
36+
_retrieveMultiframeMetadata,
37+
retrieveMultiframeMetadata,
38+
isMultiframe,
39+
};

0 commit comments

Comments
 (0)