feat: Annotation and Measurements support on multi-frame DICOM (#2973)
* added utilities to get frameNumber from imageId and add frameNumber to per-frame instance copy * Fix measurements' display texts on the Measurements Panel to have the correct instance number and frame number * fixed minor React bugs (errors on console) * fixed React's console bugs that are logged for some series that doesn't have "description" * bug fix - multi-frame files was not loading frames correctly. It was loading Frame 1 twice, and not loading the last frame. Due to wrong frame number indexing (frame number begins with 1, not 0) * metadata parser fix - providing default values of imagePlaneModule * measurement SR support on multi-frame DICOM * bug fix - jumping to the selected measurment on multi-frame DICOM * upgrade dcmjs dependency to 2.8.1 * StudySummary component - allow "description" to be null * make getUIDsFromImageID() method public from MetadataProvider * imageId usage fixes to be more stable * change the variable name to be more meaningful * fix metaProvider importing * for(...of) instead of for(i=0;i<length;..) as that doesn't assume anything about the layout/design and just gets next until done. * use Array.findIndex instead of plain for loop * use ReferencedSOPSequence[0] - because the ReferencedSOPSequence is an array that happens to have attributes of child zero when of length 1, but you shouldn't count on that. * DisplaySetService.getDisplaySetForSOPInstanceUID() - added optional frameNumber parameter for future usage : now they are just ignored as we are not supporting multiframe splits * simple code refactoring * refactoring for checking undefined values - mappedAnnotations * remove unreachable code * code refactoring - prefer conditional chaining * fix how we access imageIds of viewport (StackViewport)
This commit is contained in:
1 parent
af09578544
commit
b93067b6a2
30 files changed
+276
-132
No files matched your search
@@ -52,7 +52,7 @@ class MetadataProvider {
|
||||
}
|
||||
|
||||
_getInstance(imageId) {
|
||||
const uids = this._getUIDsFromImageID(imageId);
|
||||
const uids = this.getUIDsFromImageID(imageId);
|
||||
|
||||
if (!uids) {
|
||||
return;
|
||||
@@ -191,14 +191,16 @@ class MetadataProvider {
|
||||
rows: toNumber(instance.Rows),
|
||||
columns: toNumber(instance.Columns),
|
||||
imageOrientationPatient: toNumber(ImageOrientationPatient),
|
||||
rowCosines: toNumber(rowCosines),
|
||||
columnCosines: toNumber(columnCosines),
|
||||
imagePositionPatient: toNumber(instance.ImagePositionPatient),
|
||||
rowCosines: toNumber(rowCosines || [0, 1, 0]),
|
||||
columnCosines: toNumber(columnCosines || [0, 0, -1]),
|
||||
imagePositionPatient: toNumber(
|
||||
instance.ImagePositionPatient || [0, 0, 0]
|
||||
),
|
||||
sliceThickness: toNumber(instance.SliceThickness),
|
||||
sliceLocation: toNumber(instance.SliceLocation),
|
||||
pixelSpacing: toNumber(PixelSpacing),
|
||||
rowPixelSpacing: toNumber(rowPixelSpacing),
|
||||
columnPixelSpacing: toNumber(columnPixelSpacing),
|
||||
pixelSpacing: toNumber(PixelSpacing || 1),
|
||||
rowPixelSpacing: toNumber(rowPixelSpacing || 1),
|
||||
columnPixelSpacing: toNumber(columnPixelSpacing || 1),
|
||||
};
|
||||
break;
|
||||
case WADO_IMAGE_LOADER_TAGS.IMAGE_PIXEL_MODULE:
|
||||
@@ -409,7 +411,7 @@ class MetadataProvider {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
_getUIDsFromImageID(imageId) {
|
||||
getUIDsFromImageID(imageId) {
|
||||
// TODO: adding csiv here is not really correct. Probably need to use
|
||||
// metadataProvider.addImageIdToUIDs(imageId, {
|
||||
// StudyInstanceUID,
|
||||
|
||||
@@ -75,7 +75,11 @@ export default class DisplaySetService {
|
||||
);
|
||||
};
|
||||
|
||||
getDisplaySetForSOPInstanceUID(SOPInstanceUID, SeriesInstanceUID) {
|
||||
getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
frameNumber
|
||||
) {
|
||||
const displaySets = SeriesInstanceUID
|
||||
? this.getDisplaySetsForSeries(SeriesInstanceUID)
|
||||
: this.getDisplaySetCache();
|
||||
|
||||
@@ -38,6 +38,7 @@ const MEASUREMENT_SCHEMA_KEYS = [
|
||||
'FrameOfReferenceUID',
|
||||
'referenceStudyUID',
|
||||
'referenceSeriesUID',
|
||||
'frameNumber',
|
||||
'displaySetInstanceUID',
|
||||
'label',
|
||||
'description',
|
||||
|
||||
@@ -12,22 +12,33 @@ const combineFrameInstance = (frame, instance) => {
|
||||
const {
|
||||
PerFrameFunctionalGroupsSequence,
|
||||
SharedFunctionalGroupsSequence,
|
||||
NumberOfFrames,
|
||||
} = instance;
|
||||
if (!PerFrameFunctionalGroupsSequence) return instance;
|
||||
const shared = Object.values(SharedFunctionalGroupsSequence[0])
|
||||
.map(it => it[0])
|
||||
.filter(it => it !== undefined && typeof it === 'object');
|
||||
const perFrame = Object.values(
|
||||
PerFrameFunctionalGroupsSequence[(frame || 1) - 1]
|
||||
)
|
||||
.map(it => it[0])
|
||||
.filter(it => it !== undefined && typeof it === 'object');
|
||||
return Object.assign(
|
||||
{},
|
||||
instance,
|
||||
...Object.values(shared),
|
||||
...Object.values(perFrame)
|
||||
);
|
||||
|
||||
if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
|
||||
const frameNumber = Number.parseInt(frame || 1);
|
||||
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[0])
|
||||
.filter(it => it !== undefined && typeof it === 'object');
|
||||
|
||||
return Object.assign(
|
||||
{ frameNumber: frameNumber },
|
||||
instance,
|
||||
...Object.values(shared),
|
||||
...Object.values(perFrame)
|
||||
);
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
export default combineFrameInstance;
|
||||
Reference in new issue
Block a user