@ohif/app 3.12.0-beta.104 → 3.12.0-beta.106
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{1403.bundle.ea5eb28d7e1c937ccbbf.js → 1403.bundle.b45c67c19dabf9c62ead.js} +2 -0
- package/dist/{1608.bundle.a25c80a3971ed6361b51.js → 1608.bundle.0687c661f1c9edfb3b8a.js} +2 -2
- package/dist/{1730.bundle.d1acf1f07ca5b3892f15.js → 1730.bundle.c9e0d9f751d8b24cfbe2.js} +4 -2
- package/dist/{1927.bundle.019331c266d306772371.js → 1927.bundle.3050588e95f43cf57cdd.js} +1 -1
- package/dist/{2701.bundle.e01a06411f68459ac955.js → 2701.bundle.12bd01a80a9f8ea4cd94.js} +2 -2
- package/dist/{2842.bundle.7852a204d3510fca8b27.js → 2842.bundle.72b8e407027b26a34584.js} +68 -101
- package/dist/{1903.bundle.27b8f13121796caad7a2.js → 3081.bundle.71a2f4b2706114346d67.js} +56 -9
- package/dist/{3343.bundle.f8fe9316b0ff68d087f7.js → 3343.bundle.d7578ce8f75d158c0bab.js} +2 -0
- package/dist/{3353.bundle.a0f1654c642395bbbbbc.js → 3353.bundle.7d5f628fe7eb8fe738ce.js} +146 -144
- package/dist/{3461.bundle.93c1d3ecf976a746f785.js → 3461.bundle.84ff305e012481a9ded5.js} +2 -2
- package/dist/{4019.bundle.01f63d5dd5b96ded0c00.js → 4019.bundle.cdb81fb4777792f6175d.js} +132 -10
- package/dist/{4202.bundle.fa6f6adfd3d08a1cdcd7.js → 4202.bundle.5a0f8e4004c5d8a68548.js} +1 -1
- package/dist/{4775.bundle.f463033dbb9c8da57d52.js → 4775.bundle.cc7c126b04c9c6214d9f.js} +2 -0
- package/dist/{4819.bundle.58e054b5b00d756e2d14.js → 4819.bundle.ce13d222206c192b78f8.js} +2 -2
- package/dist/{5028.bundle.862ac206a79ac2818f64.js → 5028.bundle.d011dac918b575c5472a.js} +2 -2
- package/dist/{5400.bundle.de97508611da1c00d58a.js → 5400.bundle.be4bdac337da734fdcd3.js} +1 -0
- package/dist/{5448.bundle.9a36e001169ea3bfeb6c.js → 5448.bundle.2a82fcfac24d62355154.js} +22 -6
- package/dist/{5462.bundle.a81a691eeef782ab95b9.js → 5462.bundle.21beddaca145b7465c72.js} +2 -0
- package/dist/{5549.bundle.d5def6a3124a3a481b7c.js → 5549.bundle.4d086f8682a317140e65.js} +159 -155
- package/dist/{6163.bundle.f327d1e8aea322893404.js → 6163.bundle.e0d7dbf2a795589d1ba0.js} +4 -2
- package/dist/{7412.bundle.aec4834a71fc27c4ce06.js → 7412.bundle.7b062eda3b01de135817.js} +119 -151
- package/dist/{7639.bundle.6444531fac0b110595e5.js → 7639.bundle.096a5aaabaff706ab769.js} +9 -5
- package/dist/{8305.bundle.b1fb25aa020e0d0faec8.js → 8305.bundle.b4a98270e518f46feaa0.js} +2 -2
- package/dist/{8558.bundle.6b45234a8d6365bff3b9.js → 8558.bundle.0fd075bf5ebda9511e73.js} +3 -1
- package/dist/{8583.bundle.246b35769cd393843c6e.js → 8583.bundle.7534fbaf03a232fd85c5.js} +2 -2
- package/dist/{9195.bundle.5f9be23bc1e8857cc478.js → 9195.bundle.6663852fdc83058f3686.js} +2 -2
- package/dist/{9845.bundle.155759f5e8d8070ee16f.js → 9845.bundle.255e7c7f7a88193b4e47.js} +2 -2
- package/dist/{9862.bundle.bb6b5cab9e8eda1cc675.js → 9862.bundle.2992313d0e19d394e6a5.js} +1 -1
- package/dist/app.bundle.css +1 -1
- package/dist/{app.bundle.41cd81f26da8a340185f.js → app.bundle.faddb2bd6978a85105c6.js} +75 -24
- package/dist/{compute.bundle.fdee4a0f193ee2e1b6da.js → compute.bundle.6f1bd84d7c7116ff82a4.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/{polySeg.bundle.11f9746cd60c9811a412.js → polySeg.bundle.d4bcf15986821b88dec9.js} +1 -1
- package/dist/sw.js +1 -1
- package/package.json +21 -21
- /package/dist/{1459.bundle.5dc3647b918b624cead1.js → 1459.bundle.93b2412d40d25b566a2c.js} +0 -0
- /package/dist/{1933.bundle.d9f39020c89b72d593cc.js → 1933.bundle.a5eb66b39be97a7c6e1e.js} +0 -0
- /package/dist/{2018.bundle.3790d08e5f93c334eb29.js → 2018.bundle.17a0d310b03d6dbab3e4.js} +0 -0
- /package/dist/{213.bundle.4cdd711da5e5f19a6c76.js → 213.bundle.8e5031f961dbbf058e5d.js} +0 -0
- /package/dist/{2424.bundle.9bb3300eaecd20077a37.js → 2424.bundle.55a38e540e3ac2db94d5.js} +0 -0
- /package/dist/{5457.bundle.105e15da7973e5b61959.js → 5457.bundle.5357429ada1334292c6a.js} +0 -0
- /package/dist/{5485.bundle.07103c4b490382c0ee77.js → 5485.bundle.52d28268e556576dd215.js} +0 -0
- /package/dist/{5858.bundle.d5f4bf849aaeebf5025c.js → 5858.bundle.ff6b340cf7457db76a1a.js} +0 -0
- /package/dist/{6027.bundle.83186e7c3d210cd30320.js → 6027.bundle.4cb3d089c1bec23076d7.js} +0 -0
- /package/dist/{85.bundle.3cb557e3015e5c652610.js → 85.bundle.9855c5d5c7602012d954.js} +0 -0
- /package/dist/{9927.bundle.ca2f72f62468744559e4.js → 9927.bundle.d89e796c1107971d4277.js} +0 -0
|
@@ -112,16 +112,16 @@ const {
|
|
|
112
112
|
DicomMetaDictionary
|
|
113
113
|
} = dcmjs_es/* data */.p;
|
|
114
114
|
const FINDING = {
|
|
115
|
-
CodingSchemeDesignator:
|
|
116
|
-
CodeValue:
|
|
115
|
+
CodingSchemeDesignator: 'DCM',
|
|
116
|
+
CodeValue: '121071'
|
|
117
117
|
};
|
|
118
118
|
const FINDING_SITE = {
|
|
119
|
-
CodingSchemeDesignator:
|
|
120
|
-
CodeValue:
|
|
119
|
+
CodingSchemeDesignator: 'SCT',
|
|
120
|
+
CodeValue: '363698007'
|
|
121
121
|
};
|
|
122
122
|
const FINDING_SITE_OLD = {
|
|
123
|
-
CodingSchemeDesignator:
|
|
124
|
-
CodeValue:
|
|
123
|
+
CodingSchemeDesignator: 'SRT',
|
|
124
|
+
CodeValue: 'G-C0E3'
|
|
125
125
|
};
|
|
126
126
|
const codeValueMatch = (group, code, oldCode) => {
|
|
127
127
|
const {
|
|
@@ -165,8 +165,8 @@ class MeasurementReport {
|
|
|
165
165
|
const contentSequenceArr = toArray(ContentSequence);
|
|
166
166
|
const findingGroup = contentSequenceArr.find(group => codeValueMatch(group, FINDING));
|
|
167
167
|
const findingSiteGroups = contentSequenceArr.filter(group => codeValueMatch(group, FINDING_SITE, FINDING_SITE_OLD)) || [];
|
|
168
|
-
const NUMGroup = contentSequenceArr.find(group => group.ValueType ===
|
|
169
|
-
const SCOORDGroup = toArray(NUMGroup.ContentSequence).find(group => group.ValueType ===
|
|
168
|
+
const NUMGroup = contentSequenceArr.find(group => group.ValueType === 'NUM');
|
|
169
|
+
const SCOORDGroup = toArray(NUMGroup.ContentSequence).find(group => group.ValueType === 'SCOORD');
|
|
170
170
|
const {
|
|
171
171
|
ReferencedSOPSequence
|
|
172
172
|
} = SCOORDGroup.ContentSequence;
|
|
@@ -208,16 +208,16 @@ class MeasurementReport {
|
|
|
208
208
|
let allMeasurementGroups = [];
|
|
209
209
|
const firstImageId = Object.keys(toolState)[0];
|
|
210
210
|
if (!firstImageId) {
|
|
211
|
-
throw new Error(
|
|
211
|
+
throw new Error('No measurements provided.');
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
/* Patient ID
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const generalSeriesModule = metadataProvider.get(
|
|
215
|
+
Warning - Missing attribute or value that would be needed to build DICOMDIR - Patient ID
|
|
216
|
+
Warning - Missing attribute or value that would be needed to build DICOMDIR - Study Date
|
|
217
|
+
Warning - Missing attribute or value that would be needed to build DICOMDIR - Study Time
|
|
218
|
+
Warning - Missing attribute or value that would be needed to build DICOMDIR - Study ID
|
|
219
|
+
*/
|
|
220
|
+
const generalSeriesModule = metadataProvider.get('generalSeriesModule', firstImageId);
|
|
221
221
|
|
|
222
222
|
//const sopCommonModule = metadataProvider.get('sopCommonModule', firstImageId);
|
|
223
223
|
|
|
@@ -231,8 +231,8 @@ class MeasurementReport {
|
|
|
231
231
|
|
|
232
232
|
// Loop through each image in the toolData
|
|
233
233
|
Object.keys(toolState).forEach(imageId => {
|
|
234
|
-
const sopCommonModule = metadataProvider.get(
|
|
235
|
-
const frameNumber = metadataProvider.get(
|
|
234
|
+
const sopCommonModule = metadataProvider.get('sopCommonModule', imageId);
|
|
235
|
+
const frameNumber = metadataProvider.get('frameNumber', imageId);
|
|
236
236
|
const toolData = toolState[imageId];
|
|
237
237
|
const toolTypes = Object.keys(toolData);
|
|
238
238
|
const ReferencedSOPSequence = {
|
|
@@ -271,26 +271,26 @@ class MeasurementReport {
|
|
|
271
271
|
const _meta = {
|
|
272
272
|
FileMetaInformationVersion: {
|
|
273
273
|
Value: [fileMetaInformationVersionArray.buffer],
|
|
274
|
-
vr:
|
|
274
|
+
vr: 'OB'
|
|
275
275
|
},
|
|
276
276
|
//MediaStorageSOPClassUID
|
|
277
277
|
//MediaStorageSOPInstanceUID: sopCommonModule.sopInstanceUID,
|
|
278
278
|
TransferSyntaxUID: {
|
|
279
|
-
Value: [
|
|
280
|
-
vr:
|
|
279
|
+
Value: ['1.2.840.10008.1.2.1'],
|
|
280
|
+
vr: 'UI'
|
|
281
281
|
},
|
|
282
282
|
ImplementationClassUID: {
|
|
283
283
|
Value: [DicomMetaDictionary.uid()],
|
|
284
284
|
// TODO: could be git hash or other valid id
|
|
285
|
-
vr:
|
|
285
|
+
vr: 'UI'
|
|
286
286
|
},
|
|
287
287
|
ImplementationVersionName: {
|
|
288
|
-
Value: [
|
|
289
|
-
vr:
|
|
288
|
+
Value: ['dcmjs'],
|
|
289
|
+
vr: 'SH'
|
|
290
290
|
}
|
|
291
291
|
};
|
|
292
292
|
const _vrMap = {
|
|
293
|
-
PixelData:
|
|
293
|
+
PixelData: 'OW'
|
|
294
294
|
};
|
|
295
295
|
derivationSourceDataset._meta = _meta;
|
|
296
296
|
derivationSourceDataset._vrMap = _vrMap;
|
|
@@ -300,7 +300,7 @@ class MeasurementReport {
|
|
|
300
300
|
// Merge the derived dataset with the content from the Measurement Report
|
|
301
301
|
report.dataset = Object.assign(report.dataset, contentItem);
|
|
302
302
|
report.dataset._meta = _meta;
|
|
303
|
-
report.dataset.SpecificCharacterSet =
|
|
303
|
+
report.dataset.SpecificCharacterSet = 'ISO_IR 192';
|
|
304
304
|
return report;
|
|
305
305
|
}
|
|
306
306
|
|
|
@@ -314,12 +314,12 @@ class MeasurementReport {
|
|
|
314
314
|
static generateToolState(dataset) {
|
|
315
315
|
let hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
316
316
|
// For now, bail out if the dataset is not a TID1500 SR with length measurements
|
|
317
|
-
if (dataset.ContentTemplateSequence.TemplateIdentifier !==
|
|
318
|
-
throw new Error(
|
|
317
|
+
if (dataset.ContentTemplateSequence.TemplateIdentifier !== '1500') {
|
|
318
|
+
throw new Error('This package can currently only interpret DICOM SR TID 1500');
|
|
319
319
|
}
|
|
320
|
-
const REPORT =
|
|
321
|
-
const GROUP =
|
|
322
|
-
const TRACKING_IDENTIFIER =
|
|
320
|
+
const REPORT = 'Imaging Measurements';
|
|
321
|
+
const GROUP = 'Measurement Group';
|
|
322
|
+
const TRACKING_IDENTIFIER = 'Tracking Identifier';
|
|
323
323
|
|
|
324
324
|
// Identify the Imaging Measurements
|
|
325
325
|
const imagingMeasurementContent = toArray(dataset.ContentSequence).find(codeMeaningEquals(REPORT));
|
|
@@ -365,7 +365,7 @@ MeasurementReport.CORNERSTONE_TOOL_CLASSES_BY_TOOL_TYPE = {};
|
|
|
365
365
|
|
|
366
366
|
|
|
367
367
|
;// ../../../node_modules/@cornerstonejs/adapters/dist/esm/adapters/Cornerstone/cornerstone4Tag.js
|
|
368
|
-
var CORNERSTONE_4_TAG =
|
|
368
|
+
var CORNERSTONE_4_TAG = 'cornerstoneTools@^4.0.0';
|
|
369
369
|
|
|
370
370
|
|
|
371
371
|
|
|
@@ -377,7 +377,7 @@ var CORNERSTONE_4_TAG = "cornerstoneTools@^4.0.0";
|
|
|
377
377
|
const {
|
|
378
378
|
Length: TID300Length
|
|
379
379
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
380
|
-
const LENGTH =
|
|
380
|
+
const LENGTH = 'Length';
|
|
381
381
|
class Length {
|
|
382
382
|
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
|
|
383
383
|
static getMeasurementData(MeasurementGroup) {
|
|
@@ -414,7 +414,7 @@ class Length {
|
|
|
414
414
|
const point1 = handles.start;
|
|
415
415
|
const point2 = handles.end;
|
|
416
416
|
const distance = tool.length;
|
|
417
|
-
const trackingIdentifierTextValue =
|
|
417
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:Length';
|
|
418
418
|
return {
|
|
419
419
|
point1,
|
|
420
420
|
point2,
|
|
@@ -429,10 +429,10 @@ Length.toolType = LENGTH;
|
|
|
429
429
|
Length.utilityToolType = LENGTH;
|
|
430
430
|
Length.TID300Representation = TID300Length;
|
|
431
431
|
Length.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
432
|
-
if (!TrackingIdentifier.includes(
|
|
432
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
433
433
|
return false;
|
|
434
434
|
}
|
|
435
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
435
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
436
436
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
437
437
|
return false;
|
|
438
438
|
}
|
|
@@ -502,7 +502,7 @@ class FreehandRoi {
|
|
|
502
502
|
area = 0,
|
|
503
503
|
perimeter = 0
|
|
504
504
|
} = cachedStats;
|
|
505
|
-
const trackingIdentifierTextValue =
|
|
505
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:FreehandRoi';
|
|
506
506
|
return {
|
|
507
507
|
points,
|
|
508
508
|
area,
|
|
@@ -513,14 +513,14 @@ class FreehandRoi {
|
|
|
513
513
|
};
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
|
-
FreehandRoi.toolType =
|
|
517
|
-
FreehandRoi.utilityToolType =
|
|
516
|
+
FreehandRoi.toolType = 'FreehandRoi';
|
|
517
|
+
FreehandRoi.utilityToolType = 'FreehandRoi';
|
|
518
518
|
FreehandRoi.TID300Representation = TID300Polyline;
|
|
519
519
|
FreehandRoi.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
520
|
-
if (!TrackingIdentifier.includes(
|
|
520
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
521
521
|
return false;
|
|
522
522
|
}
|
|
523
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
523
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
524
524
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
525
525
|
return false;
|
|
526
526
|
}
|
|
@@ -540,11 +540,11 @@ MeasurementReport.registerTool(FreehandRoi);
|
|
|
540
540
|
const {
|
|
541
541
|
Bidirectional: TID300Bidirectional
|
|
542
542
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
543
|
-
const BIDIRECTIONAL =
|
|
544
|
-
const LONG_AXIS =
|
|
545
|
-
const SHORT_AXIS =
|
|
546
|
-
const Bidirectional_FINDING =
|
|
547
|
-
const Bidirectional_FINDING_SITE =
|
|
543
|
+
const BIDIRECTIONAL = 'Bidirectional';
|
|
544
|
+
const LONG_AXIS = 'Long Axis';
|
|
545
|
+
const SHORT_AXIS = 'Short Axis';
|
|
546
|
+
const Bidirectional_FINDING = '121071';
|
|
547
|
+
const Bidirectional_FINDING_SITE = 'G-C0E3';
|
|
548
548
|
class Bidirectional {
|
|
549
549
|
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
|
|
550
550
|
static getMeasurementData(MeasurementGroup) {
|
|
@@ -554,9 +554,9 @@ class Bidirectional {
|
|
|
554
554
|
const findingGroup = toArray(ContentSequence).find(group => group.ConceptNameCodeSequence.CodeValue === Bidirectional_FINDING);
|
|
555
555
|
const findingSiteGroups = toArray(ContentSequence).filter(group => group.ConceptNameCodeSequence.CodeValue === Bidirectional_FINDING_SITE);
|
|
556
556
|
const longAxisNUMGroup = toArray(ContentSequence).find(group => group.ConceptNameCodeSequence.CodeMeaning === LONG_AXIS);
|
|
557
|
-
const longAxisSCOORDGroup = toArray(longAxisNUMGroup.ContentSequence).find(group => group.ValueType ===
|
|
557
|
+
const longAxisSCOORDGroup = toArray(longAxisNUMGroup.ContentSequence).find(group => group.ValueType === 'SCOORD');
|
|
558
558
|
const shortAxisNUMGroup = toArray(ContentSequence).find(group => group.ConceptNameCodeSequence.CodeMeaning === SHORT_AXIS);
|
|
559
|
-
const shortAxisSCOORDGroup = toArray(shortAxisNUMGroup.ContentSequence).find(group => group.ValueType ===
|
|
559
|
+
const shortAxisSCOORDGroup = toArray(shortAxisNUMGroup.ContentSequence).find(group => group.ValueType === 'SCOORD');
|
|
560
560
|
const {
|
|
561
561
|
ReferencedSOPSequence
|
|
562
562
|
} = longAxisSCOORDGroup.ContentSequence;
|
|
@@ -631,7 +631,7 @@ class Bidirectional {
|
|
|
631
631
|
isCreating: false,
|
|
632
632
|
longestDiameter,
|
|
633
633
|
shortestDiameter,
|
|
634
|
-
toolName:
|
|
634
|
+
toolName: 'Bidirectional',
|
|
635
635
|
visible: true,
|
|
636
636
|
finding: findingGroup ? findingGroup.ConceptCodeSequence : undefined,
|
|
637
637
|
findingSites: findingSiteGroups.map(fsg => fsg.ConceptCodeSequence)
|
|
@@ -651,7 +651,7 @@ class Bidirectional {
|
|
|
651
651
|
finding,
|
|
652
652
|
findingSites
|
|
653
653
|
} = tool;
|
|
654
|
-
const trackingIdentifierTextValue =
|
|
654
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:Bidirectional';
|
|
655
655
|
return {
|
|
656
656
|
longAxis: {
|
|
657
657
|
point1: start,
|
|
@@ -673,10 +673,10 @@ Bidirectional.toolType = BIDIRECTIONAL;
|
|
|
673
673
|
Bidirectional.utilityToolType = BIDIRECTIONAL;
|
|
674
674
|
Bidirectional.TID300Representation = TID300Bidirectional;
|
|
675
675
|
Bidirectional.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
676
|
-
if (!TrackingIdentifier.includes(
|
|
676
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
677
677
|
return false;
|
|
678
678
|
}
|
|
679
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
679
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
680
680
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
681
681
|
return false;
|
|
682
682
|
}
|
|
@@ -694,7 +694,7 @@ MeasurementReport.registerTool(Bidirectional);
|
|
|
694
694
|
const {
|
|
695
695
|
Ellipse: TID300Ellipse
|
|
696
696
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
697
|
-
const ELLIPTICALROI =
|
|
697
|
+
const ELLIPTICALROI = 'EllipticalRoi';
|
|
698
698
|
class EllipticalRoi {
|
|
699
699
|
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
|
|
700
700
|
static getMeasurementData(MeasurementGroup) {
|
|
@@ -837,7 +837,7 @@ class EllipticalRoi {
|
|
|
837
837
|
y: center.y
|
|
838
838
|
});
|
|
839
839
|
}
|
|
840
|
-
const trackingIdentifierTextValue =
|
|
840
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:EllipticalRoi';
|
|
841
841
|
return {
|
|
842
842
|
area,
|
|
843
843
|
points,
|
|
@@ -851,10 +851,10 @@ EllipticalRoi.toolType = ELLIPTICALROI;
|
|
|
851
851
|
EllipticalRoi.utilityToolType = ELLIPTICALROI;
|
|
852
852
|
EllipticalRoi.TID300Representation = TID300Ellipse;
|
|
853
853
|
EllipticalRoi.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
854
|
-
if (!TrackingIdentifier.includes(
|
|
854
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
855
855
|
return false;
|
|
856
856
|
}
|
|
857
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
857
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
858
858
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
859
859
|
return false;
|
|
860
860
|
}
|
|
@@ -872,7 +872,7 @@ MeasurementReport.registerTool(EllipticalRoi);
|
|
|
872
872
|
const {
|
|
873
873
|
Circle: TID300Circle
|
|
874
874
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
875
|
-
const CIRCLEROI =
|
|
875
|
+
const CIRCLEROI = 'CircleRoi';
|
|
876
876
|
class CircleRoi {
|
|
877
877
|
/** Gets the measurement data for cornerstone, given DICOM SR measurement data. */
|
|
878
878
|
static getMeasurementData(MeasurementGroup) {
|
|
@@ -953,7 +953,7 @@ class CircleRoi {
|
|
|
953
953
|
const points = [];
|
|
954
954
|
points.push(center);
|
|
955
955
|
points.push(end);
|
|
956
|
-
const trackingIdentifierTextValue =
|
|
956
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:CircleRoi';
|
|
957
957
|
return {
|
|
958
958
|
area,
|
|
959
959
|
perimeter,
|
|
@@ -969,10 +969,10 @@ CircleRoi.toolType = CIRCLEROI;
|
|
|
969
969
|
CircleRoi.utilityToolType = CIRCLEROI;
|
|
970
970
|
CircleRoi.TID300Representation = TID300Circle;
|
|
971
971
|
CircleRoi.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
972
|
-
if (!TrackingIdentifier.includes(
|
|
972
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
973
973
|
return false;
|
|
974
974
|
}
|
|
975
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
975
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
976
976
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
977
977
|
return false;
|
|
978
978
|
}
|
|
@@ -990,8 +990,8 @@ MeasurementReport.registerTool(CircleRoi);
|
|
|
990
990
|
const {
|
|
991
991
|
Point: TID300Point
|
|
992
992
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
993
|
-
const ARROW_ANNOTATE =
|
|
994
|
-
const CORNERSTONEFREETEXT =
|
|
993
|
+
const ARROW_ANNOTATE = 'ArrowAnnotate';
|
|
994
|
+
const CORNERSTONEFREETEXT = 'CORNERSTONEFREETEXT';
|
|
995
995
|
class ArrowAnnotate {
|
|
996
996
|
static getMeasurementData(MeasurementGroup) {
|
|
997
997
|
const {
|
|
@@ -1052,7 +1052,7 @@ class ArrowAnnotate {
|
|
|
1052
1052
|
if (!finding || finding.CodeValue !== CORNERSTONEFREETEXT) {
|
|
1053
1053
|
finding = {
|
|
1054
1054
|
CodeValue: CORNERSTONEFREETEXT,
|
|
1055
|
-
CodingSchemeDesignator:
|
|
1055
|
+
CodingSchemeDesignator: 'CST4',
|
|
1056
1056
|
CodeMeaning: tool.label
|
|
1057
1057
|
};
|
|
1058
1058
|
}
|
|
@@ -1064,10 +1064,10 @@ ArrowAnnotate.toolType = ARROW_ANNOTATE;
|
|
|
1064
1064
|
ArrowAnnotate.utilityToolType = ARROW_ANNOTATE;
|
|
1065
1065
|
ArrowAnnotate.TID300Representation = TID300Point;
|
|
1066
1066
|
ArrowAnnotate.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
1067
|
-
if (!TrackingIdentifier.includes(
|
|
1067
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
1068
1068
|
return false;
|
|
1069
1069
|
}
|
|
1070
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
1070
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
1071
1071
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1072
1072
|
return false;
|
|
1073
1073
|
}
|
|
@@ -1085,7 +1085,7 @@ MeasurementReport.registerTool(ArrowAnnotate);
|
|
|
1085
1085
|
const {
|
|
1086
1086
|
CobbAngle: TID300CobbAngle
|
|
1087
1087
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
1088
|
-
const COBB_ANGLE =
|
|
1088
|
+
const COBB_ANGLE = 'CobbAngle';
|
|
1089
1089
|
class CobbAngle {
|
|
1090
1090
|
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
|
|
1091
1091
|
static getMeasurementData(MeasurementGroup) {
|
|
@@ -1132,7 +1132,7 @@ class CobbAngle {
|
|
|
1132
1132
|
const point3 = handles.start2;
|
|
1133
1133
|
const point4 = handles.end2;
|
|
1134
1134
|
const rAngle = tool.rAngle;
|
|
1135
|
-
const trackingIdentifierTextValue =
|
|
1135
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:CobbAngle';
|
|
1136
1136
|
return {
|
|
1137
1137
|
point1,
|
|
1138
1138
|
point2,
|
|
@@ -1149,10 +1149,10 @@ CobbAngle.toolType = COBB_ANGLE;
|
|
|
1149
1149
|
CobbAngle.utilityToolType = COBB_ANGLE;
|
|
1150
1150
|
CobbAngle.TID300Representation = TID300CobbAngle;
|
|
1151
1151
|
CobbAngle.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
1152
|
-
if (!TrackingIdentifier.includes(
|
|
1152
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
1153
1153
|
return false;
|
|
1154
1154
|
}
|
|
1155
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
1155
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
1156
1156
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1157
1157
|
return false;
|
|
1158
1158
|
}
|
|
@@ -1170,7 +1170,7 @@ MeasurementReport.registerTool(CobbAngle);
|
|
|
1170
1170
|
const {
|
|
1171
1171
|
Angle: TID300Angle
|
|
1172
1172
|
} = dcmjs_es/* utilities */.BF.TID300;
|
|
1173
|
-
const ANGLE =
|
|
1173
|
+
const ANGLE = 'Angle';
|
|
1174
1174
|
class Angle {
|
|
1175
1175
|
/**
|
|
1176
1176
|
* Generate TID300 measurement data for a plane angle measurement - use a Angle, but label it as Angle
|
|
@@ -1212,7 +1212,7 @@ class Angle {
|
|
|
1212
1212
|
const point3 = handles.middle;
|
|
1213
1213
|
const point4 = handles.end;
|
|
1214
1214
|
const rAngle = tool.rAngle;
|
|
1215
|
-
const trackingIdentifierTextValue =
|
|
1215
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:Angle';
|
|
1216
1216
|
return {
|
|
1217
1217
|
point1,
|
|
1218
1218
|
point2,
|
|
@@ -1229,10 +1229,10 @@ Angle.toolType = ANGLE;
|
|
|
1229
1229
|
Angle.utilityToolType = ANGLE;
|
|
1230
1230
|
Angle.TID300Representation = TID300Angle;
|
|
1231
1231
|
Angle.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
1232
|
-
if (!TrackingIdentifier.includes(
|
|
1232
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
1233
1233
|
return false;
|
|
1234
1234
|
}
|
|
1235
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
1235
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
1236
1236
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1237
1237
|
return false;
|
|
1238
1238
|
}
|
|
@@ -1305,7 +1305,7 @@ class RectangleRoi {
|
|
|
1305
1305
|
area,
|
|
1306
1306
|
perimeter
|
|
1307
1307
|
} = cachedStats;
|
|
1308
|
-
const trackingIdentifierTextValue =
|
|
1308
|
+
const trackingIdentifierTextValue = 'cornerstoneTools@^4.0.0:RectangleRoi';
|
|
1309
1309
|
return {
|
|
1310
1310
|
points,
|
|
1311
1311
|
area,
|
|
@@ -1316,14 +1316,14 @@ class RectangleRoi {
|
|
|
1316
1316
|
};
|
|
1317
1317
|
}
|
|
1318
1318
|
}
|
|
1319
|
-
RectangleRoi.toolType =
|
|
1320
|
-
RectangleRoi.utilityToolType =
|
|
1319
|
+
RectangleRoi.toolType = 'RectangleRoi';
|
|
1320
|
+
RectangleRoi.utilityToolType = 'RectangleRoi';
|
|
1321
1321
|
RectangleRoi.TID300Representation = RectangleRoi_TID300Polyline;
|
|
1322
1322
|
RectangleRoi.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
|
|
1323
|
-
if (!TrackingIdentifier.includes(
|
|
1323
|
+
if (!TrackingIdentifier.includes(':')) {
|
|
1324
1324
|
return false;
|
|
1325
1325
|
}
|
|
1326
|
-
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(
|
|
1326
|
+
const [cornerstone4Tag, toolType] = TrackingIdentifier.split(':');
|
|
1327
1327
|
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1328
1328
|
return false;
|
|
1329
1329
|
}
|
|
@@ -1436,9 +1436,9 @@ function generateSegmentation(images, brushData) {
|
|
|
1436
1436
|
dims.xy = dims.x * dims.y;
|
|
1437
1437
|
const numSegments = _getSegCount(seg, segments);
|
|
1438
1438
|
if (!numSegments) {
|
|
1439
|
-
throw new Error(
|
|
1439
|
+
throw new Error('No segments to export!');
|
|
1440
1440
|
}
|
|
1441
|
-
const isMultiframe = image0.imageId.includes(
|
|
1441
|
+
const isMultiframe = image0.imageId.includes('?frame');
|
|
1442
1442
|
const seg = _createSegFromImages(images, isMultiframe, options);
|
|
1443
1443
|
const {
|
|
1444
1444
|
referencedFramesPerSegment,
|
|
@@ -1540,9 +1540,9 @@ function generateToolState(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1540
1540
|
const dataset = Segmentation_3X_DicomMetaDictionary.naturalizeDataset(dicomData.dict);
|
|
1541
1541
|
dataset._meta = Segmentation_3X_DicomMetaDictionary.namifyDataset(dicomData.meta);
|
|
1542
1542
|
const multiframe = Segmentation_3X_Normalizer.normalizeToDataset([dataset]);
|
|
1543
|
-
const imagePlaneModule = metadataProvider.get(
|
|
1543
|
+
const imagePlaneModule = metadataProvider.get('imagePlaneModule', imageIds[0]);
|
|
1544
1544
|
if (!imagePlaneModule) {
|
|
1545
|
-
console.warn(
|
|
1545
|
+
console.warn('Insufficient metadata, imagePlaneModule missing.');
|
|
1546
1546
|
}
|
|
1547
1547
|
const ImageOrientationPatient = Array.isArray(imagePlaneModule.rowCosines) ? [...imagePlaneModule.rowCosines, ...imagePlaneModule.columnCosines] : [imagePlaneModule.rowCosines.x, imagePlaneModule.rowCosines.y, imagePlaneModule.rowCosines.z, imagePlaneModule.columnCosines.x, imagePlaneModule.columnCosines.y, imagePlaneModule.columnCosines.z];
|
|
1548
1548
|
|
|
@@ -1593,17 +1593,17 @@ function generateToolState(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1593
1593
|
*/
|
|
1594
1594
|
function unpackPixelData(multiframe) {
|
|
1595
1595
|
const segType = multiframe.SegmentationType;
|
|
1596
|
-
if (segType ===
|
|
1596
|
+
if (segType === 'BINARY') {
|
|
1597
1597
|
return BitArray.unpack(multiframe.PixelData);
|
|
1598
1598
|
}
|
|
1599
1599
|
const pixelData = new Uint8Array(multiframe.PixelData);
|
|
1600
1600
|
const max = multiframe.MaximumFractionalValue;
|
|
1601
1601
|
const onlyMaxAndZero = pixelData.find(element => element !== 0 && element !== max) === undefined;
|
|
1602
1602
|
if (!onlyMaxAndZero) {
|
|
1603
|
-
dcmjs_es/* log */.Rm.warn(
|
|
1603
|
+
dcmjs_es/* log */.Rm.warn('This is a fractional segmentation, which is not currently supported.');
|
|
1604
1604
|
return;
|
|
1605
1605
|
}
|
|
1606
|
-
dcmjs_es/* log */.Rm.warn(
|
|
1606
|
+
dcmjs_es/* log */.Rm.warn('This segmentation object is actually binary... processing as such.');
|
|
1607
1607
|
return pixelData;
|
|
1608
1608
|
}
|
|
1609
1609
|
|
|
@@ -1669,7 +1669,7 @@ function getImageIdOfSourceImage(SourceImageSequence, imageIds, metadataProvider
|
|
|
1669
1669
|
*/
|
|
1670
1670
|
function getImageIdOfReferencedSingleFramedSOPInstance(sopInstanceUid, imageIds, metadataProvider) {
|
|
1671
1671
|
return imageIds.find(imageId => {
|
|
1672
|
-
const sopCommonModule = metadataProvider.get(
|
|
1672
|
+
const sopCommonModule = metadataProvider.get('sopCommonModule', imageId);
|
|
1673
1673
|
if (!sopCommonModule) {
|
|
1674
1674
|
return;
|
|
1675
1675
|
}
|
|
@@ -1690,11 +1690,11 @@ function getImageIdOfReferencedSingleFramedSOPInstance(sopInstanceUid, imageIds,
|
|
|
1690
1690
|
*/
|
|
1691
1691
|
function getImageIdOfReferencedFrame(sopInstanceUid, frameNumber, imageIds, metadataProvider) {
|
|
1692
1692
|
const imageId = imageIds.find(imageId => {
|
|
1693
|
-
const sopCommonModule = metadataProvider.get(
|
|
1693
|
+
const sopCommonModule = metadataProvider.get('sopCommonModule', imageId);
|
|
1694
1694
|
if (!sopCommonModule) {
|
|
1695
1695
|
return;
|
|
1696
1696
|
}
|
|
1697
|
-
const imageIdFrameNumber = Number(imageId.split(
|
|
1697
|
+
const imageIdFrameNumber = Number(imageId.split('frame=')[1]);
|
|
1698
1698
|
return (
|
|
1699
1699
|
//frameNumber is zero indexed for cornerstoneDICOMImageLoader image Ids.
|
|
1700
1700
|
sopCommonModule.sopInstanceUID === sopInstanceUid && imageIdFrameNumber === frameNumber - 1
|
|
@@ -1967,19 +1967,19 @@ function fillSegmentation(segmentation, inputLabelmaps3D) {
|
|
|
1967
1967
|
// to be 1 for BINARY. This is not ideal and there should be a better format for compression in this manner
|
|
1968
1968
|
// added to the standard.
|
|
1969
1969
|
segmentation.assignToDataset({
|
|
1970
|
-
BitsAllocated:
|
|
1971
|
-
BitsStored:
|
|
1972
|
-
HighBit:
|
|
1973
|
-
SegmentationType:
|
|
1974
|
-
SegmentationFractionalType:
|
|
1975
|
-
MaximumFractionalValue:
|
|
1970
|
+
BitsAllocated: '8',
|
|
1971
|
+
BitsStored: '8',
|
|
1972
|
+
HighBit: '7',
|
|
1973
|
+
SegmentationType: 'FRACTIONAL',
|
|
1974
|
+
SegmentationFractionalType: 'PROBABILITY',
|
|
1975
|
+
MaximumFractionalValue: '255'
|
|
1976
1976
|
});
|
|
1977
1977
|
segmentation.dataset._meta.TransferSyntaxUID = {
|
|
1978
|
-
Value: [
|
|
1979
|
-
vr:
|
|
1978
|
+
Value: ['1.2.840.10008.1.2.5'],
|
|
1979
|
+
vr: 'UI'
|
|
1980
1980
|
};
|
|
1981
|
-
segmentation.dataset.SpecificCharacterSet =
|
|
1982
|
-
segmentation.dataset._vrMap.PixelData =
|
|
1981
|
+
segmentation.dataset.SpecificCharacterSet = 'ISO_IR 192';
|
|
1982
|
+
segmentation.dataset._vrMap.PixelData = 'OB';
|
|
1983
1983
|
segmentation.dataset.PixelData = rleEncodedFrames;
|
|
1984
1984
|
} else {
|
|
1985
1985
|
// If no rleEncoding, at least bitpack the data.
|
|
@@ -2039,11 +2039,11 @@ async function Segmentation_4X_generateToolState(referencedImageIds, arrayBuffer
|
|
|
2039
2039
|
const dataset = Segmentation_4X_DicomMetaDictionary.naturalizeDataset(dicomData.dict);
|
|
2040
2040
|
dataset._meta = Segmentation_4X_DicomMetaDictionary.namifyDataset(dicomData.meta);
|
|
2041
2041
|
const multiframe = Segmentation_4X_Normalizer.normalizeToDataset([dataset]);
|
|
2042
|
-
const imagePlaneModule = metadataProvider.get(
|
|
2043
|
-
const generalSeriesModule = metadataProvider.get(
|
|
2042
|
+
const imagePlaneModule = metadataProvider.get('imagePlaneModule', referencedImageIds[0]);
|
|
2043
|
+
const generalSeriesModule = metadataProvider.get('generalSeriesModule', referencedImageIds[0]);
|
|
2044
2044
|
const SeriesInstanceUID = generalSeriesModule.seriesInstanceUID;
|
|
2045
2045
|
if (!imagePlaneModule) {
|
|
2046
|
-
console.warn(
|
|
2046
|
+
console.warn('Insufficient metadata, imagePlaneModule missing.');
|
|
2047
2047
|
}
|
|
2048
2048
|
const ImageOrientationPatient = Array.isArray(imagePlaneModule.rowCosines) ? [...imagePlaneModule.rowCosines, ...imagePlaneModule.columnCosines] : [imagePlaneModule.rowCosines.x, imagePlaneModule.rowCosines.y, imagePlaneModule.rowCosines.z, imagePlaneModule.columnCosines.x, imagePlaneModule.columnCosines.y, imagePlaneModule.columnCosines.z];
|
|
2049
2049
|
|
|
@@ -2054,11 +2054,11 @@ async function Segmentation_4X_generateToolState(referencedImageIds, arrayBuffer
|
|
|
2054
2054
|
const TransferSyntaxUID = multiframe._meta.TransferSyntaxUID.Value[0];
|
|
2055
2055
|
let pixelData;
|
|
2056
2056
|
let pixelDataChunks;
|
|
2057
|
-
if (TransferSyntaxUID ===
|
|
2057
|
+
if (TransferSyntaxUID === '1.2.840.10008.1.2.5') {
|
|
2058
2058
|
const rleEncodedFrames = Array.isArray(multiframe.PixelData) ? multiframe.PixelData : [multiframe.PixelData];
|
|
2059
2059
|
pixelData = decode(rleEncodedFrames, multiframe.Rows, multiframe.Columns);
|
|
2060
2060
|
if (multiframe.BitsStored === 1) {
|
|
2061
|
-
console.warn(
|
|
2061
|
+
console.warn('No implementation for rle + bitbacking.');
|
|
2062
2062
|
return;
|
|
2063
2063
|
}
|
|
2064
2064
|
|
|
@@ -2069,7 +2069,7 @@ async function Segmentation_4X_generateToolState(referencedImageIds, arrayBuffer
|
|
|
2069
2069
|
maxBytesPerChunk
|
|
2070
2070
|
});
|
|
2071
2071
|
if (!pixelDataChunks) {
|
|
2072
|
-
throw new Error(
|
|
2072
|
+
throw new Error('Fractional segmentations are not yet supported');
|
|
2073
2073
|
}
|
|
2074
2074
|
}
|
|
2075
2075
|
const orientation = checkOrientation(multiframe, validOrientations, [imagePlaneModule.rows, imagePlaneModule.columns, referencedImageIds.length], tolerance);
|
|
@@ -2080,7 +2080,7 @@ async function Segmentation_4X_generateToolState(referencedImageIds, arrayBuffer
|
|
|
2080
2080
|
const sopUIDImageIdIndexMap = referencedImageIds.reduce((acc, imageId) => {
|
|
2081
2081
|
const {
|
|
2082
2082
|
sopInstanceUID
|
|
2083
|
-
} = metadataProvider.get(
|
|
2083
|
+
} = metadataProvider.get('generalImageModule', imageId);
|
|
2084
2084
|
acc[sopInstanceUID] = imageId;
|
|
2085
2085
|
return acc;
|
|
2086
2086
|
}, {});
|
|
@@ -2090,25 +2090,25 @@ async function Segmentation_4X_generateToolState(referencedImageIds, arrayBuffer
|
|
|
2090
2090
|
}
|
|
2091
2091
|
let insertFunction;
|
|
2092
2092
|
switch (orientation) {
|
|
2093
|
-
case
|
|
2093
|
+
case 'Planar':
|
|
2094
2094
|
if (overlapping) {
|
|
2095
2095
|
insertFunction = insertOverlappingPixelDataPlanar;
|
|
2096
2096
|
} else {
|
|
2097
2097
|
insertFunction = insertPixelDataPlanar;
|
|
2098
2098
|
}
|
|
2099
2099
|
break;
|
|
2100
|
-
case
|
|
2100
|
+
case 'Perpendicular':
|
|
2101
2101
|
//insertFunction = insertPixelDataPerpendicular;
|
|
2102
|
-
throw new Error(
|
|
2103
|
-
case
|
|
2104
|
-
throw new Error(
|
|
2102
|
+
throw new Error('Segmentations orthogonal to the acquisition plane of the source data are not yet supported.');
|
|
2103
|
+
case 'Oblique':
|
|
2104
|
+
throw new Error('Segmentations oblique to the acquisition plane of the source data are not yet supported.');
|
|
2105
2105
|
}
|
|
2106
2106
|
|
|
2107
2107
|
/* if SEGs are overlapping:
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2108
|
+
1) the labelmapBuffer will contain M volumes which have non-overlapping segments;
|
|
2109
|
+
2) segmentsOnFrame will have M * numberOfFrames values to track in which labelMap are the segments;
|
|
2110
|
+
3) insertFunction will return the number of LabelMaps
|
|
2111
|
+
4) generateToolState return is an array*/
|
|
2112
2112
|
|
|
2113
2113
|
const segmentsOnFrameArray = [];
|
|
2114
2114
|
segmentsOnFrameArray[0] = [];
|
|
@@ -2121,7 +2121,7 @@ async function Segmentation_4X_generateToolState(referencedImageIds, arrayBuffer
|
|
|
2121
2121
|
// a function for each imageId in the for loop.
|
|
2122
2122
|
const imageIdMaps = referencedImageIds.reduce((acc, curr, index) => {
|
|
2123
2123
|
acc.indices[curr] = index;
|
|
2124
|
-
acc.metadata[curr] = metadataProvider.get(
|
|
2124
|
+
acc.metadata[curr] = metadataProvider.get('instance', curr);
|
|
2125
2125
|
return acc;
|
|
2126
2126
|
}, {
|
|
2127
2127
|
indices: {},
|
|
@@ -2372,7 +2372,7 @@ function findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadata
|
|
|
2372
2372
|
}
|
|
2373
2373
|
}
|
|
2374
2374
|
} else if (SourceImageSequence && SourceImageSequence.length !== 0) {
|
|
2375
|
-
console.warn(
|
|
2375
|
+
console.warn('DerivationImageSequence not present, using SourceImageSequence assuming SEG has the same geometry as the source image.');
|
|
2376
2376
|
frameSourceImageSequence = SourceImageSequence[frameSegment];
|
|
2377
2377
|
}
|
|
2378
2378
|
if (frameSourceImageSequence) {
|
|
@@ -2417,12 +2417,12 @@ function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations
|
|
|
2417
2417
|
for (let frameSegment = 0; frameSegment < groupsLen; ++frameSegment) {
|
|
2418
2418
|
const segmentIndex = getSegmentIndex(multiframe, frameSegment);
|
|
2419
2419
|
if (segmentIndex === undefined) {
|
|
2420
|
-
console.warn(
|
|
2420
|
+
console.warn('Could not retrieve the segment index for frame segment ' + frameSegment + ', skipping this frame.');
|
|
2421
2421
|
continue;
|
|
2422
2422
|
}
|
|
2423
2423
|
const imageId = findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
2424
2424
|
if (!imageId) {
|
|
2425
|
-
console.warn("Image not present in stack, can't import frame : " + frameSegment +
|
|
2425
|
+
console.warn("Image not present in stack, can't import frame : " + frameSegment + '.');
|
|
2426
2426
|
continue;
|
|
2427
2427
|
}
|
|
2428
2428
|
const imageIdIndex = imageIds.findIndex(element => element === imageId);
|
|
@@ -2446,7 +2446,7 @@ function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations
|
|
|
2446
2446
|
const pixelDataI2D = ndarray_default()(view, [Rows, Columns]);
|
|
2447
2447
|
const alignedPixelDataI = Segmentation_4X_alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
2448
2448
|
if (!alignedPixelDataI) {
|
|
2449
|
-
console.warn(
|
|
2449
|
+
console.warn('Individual SEG frames are out of plane with respect to the first SEG frame, this is not yet supported, skipping this frame.');
|
|
2450
2450
|
continue;
|
|
2451
2451
|
}
|
|
2452
2452
|
const data = alignedPixelDataI.data;
|
|
@@ -2497,7 +2497,7 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
|
|
|
2497
2497
|
const PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[i];
|
|
2498
2498
|
const segmentIndex = getSegmentIndex(multiframe, i);
|
|
2499
2499
|
if (segmentIndex === undefined) {
|
|
2500
|
-
throw new Error(
|
|
2500
|
+
throw new Error('Could not retrieve the segment index. Aborting segmentation loading.');
|
|
2501
2501
|
}
|
|
2502
2502
|
if (segmentIndex !== segmentIndexToProcess) {
|
|
2503
2503
|
continue;
|
|
@@ -2511,16 +2511,16 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
|
|
|
2511
2511
|
const pixelDataI2D = ndarray_default()(view, [Rows, Columns]);
|
|
2512
2512
|
const alignedPixelDataI = Segmentation_4X_alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
2513
2513
|
if (!alignedPixelDataI) {
|
|
2514
|
-
throw new Error(
|
|
2514
|
+
throw new Error('Individual SEG frames are out of plane with respect to the first SEG frame. ' + 'This is not yet supported. Aborting segmentation loading.');
|
|
2515
2515
|
}
|
|
2516
2516
|
const imageId = findReferenceSourceImageId(multiframe, i, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
2517
2517
|
if (!imageId) {
|
|
2518
|
-
console.warn("Image not present in stack, can't import frame : " + i +
|
|
2518
|
+
console.warn("Image not present in stack, can't import frame : " + i + '.');
|
|
2519
2519
|
continue;
|
|
2520
2520
|
}
|
|
2521
|
-
const sourceImageMetadata = metadataProvider.get(
|
|
2521
|
+
const sourceImageMetadata = metadataProvider.get('instance', imageId);
|
|
2522
2522
|
if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
|
|
2523
|
-
throw new Error(
|
|
2523
|
+
throw new Error('Individual SEG frames have different geometry dimensions (Rows and Columns) ' + 'respect to the source image reference frame. This is not yet supported. ' + 'Aborting segmentation loading. ');
|
|
2524
2524
|
}
|
|
2525
2525
|
const imageIdIndex = imageIds.findIndex(element => element === imageId);
|
|
2526
2526
|
const byteOffset = sliceLength * imageIdIndex * TypedArrayConstructor.BYTES_PER_ELEMENT;
|
|
@@ -2602,23 +2602,23 @@ function insertPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBu
|
|
|
2602
2602
|
const pixelDataI2D = ndarray_default()(view, [Rows, Columns]);
|
|
2603
2603
|
const alignedPixelDataI = Segmentation_4X_alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
2604
2604
|
if (!alignedPixelDataI) {
|
|
2605
|
-
throw new Error(
|
|
2605
|
+
throw new Error('Individual SEG frames are out of plane with respect to the first SEG frame. ' + 'This is not yet supported. Aborting segmentation loading.');
|
|
2606
2606
|
}
|
|
2607
2607
|
const segmentIndex = getSegmentIndex(multiframe, i);
|
|
2608
2608
|
if (segmentIndex === undefined) {
|
|
2609
|
-
throw new Error(
|
|
2609
|
+
throw new Error('Could not retrieve the segment index. Aborting segmentation loading.');
|
|
2610
2610
|
}
|
|
2611
2611
|
if (!segmentsPixelIndices.has(segmentIndex)) {
|
|
2612
2612
|
segmentsPixelIndices.set(segmentIndex, {});
|
|
2613
2613
|
}
|
|
2614
2614
|
const imageId = findReferenceSourceImageId(multiframe, i, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
2615
2615
|
if (!imageId) {
|
|
2616
|
-
console.warn("Image not present in stack, can't import frame : " + i +
|
|
2616
|
+
console.warn("Image not present in stack, can't import frame : " + i + '.');
|
|
2617
2617
|
continue;
|
|
2618
2618
|
}
|
|
2619
2619
|
const sourceImageMetadata = imageIdMaps.metadata[imageId];
|
|
2620
2620
|
if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
|
|
2621
|
-
throw new Error(
|
|
2621
|
+
throw new Error('Individual SEG frames have different geometry dimensions (Rows and Columns) ' + 'respect to the source image reference frame. This is not yet supported. ' + 'Aborting segmentation loading. ');
|
|
2622
2622
|
}
|
|
2623
2623
|
const imageIdIndex = imageIdMaps.indices[imageId];
|
|
2624
2624
|
const byteOffset = sliceLength * imageIdIndex * TypedArrayConstructor.BYTES_PER_ELEMENT;
|
|
@@ -2684,15 +2684,15 @@ function Segmentation_4X_unpackPixelData(multiframe, options) {
|
|
|
2684
2684
|
data = multiframe.PixelData;
|
|
2685
2685
|
}
|
|
2686
2686
|
if (data === undefined) {
|
|
2687
|
-
dcmjs_es/* log */.Rm.error(
|
|
2687
|
+
dcmjs_es/* log */.Rm.error('This segmentation pixelData is undefined.');
|
|
2688
2688
|
}
|
|
2689
|
-
if (segType ===
|
|
2689
|
+
if (segType === 'BINARY') {
|
|
2690
2690
|
// For extreme big data, we can't unpack the data at once and we need to
|
|
2691
2691
|
// chunk it and unpack each chunk separately.
|
|
2692
2692
|
// MAX 2GB is the limit right now to allocate a buffer
|
|
2693
2693
|
return getUnpackedChunks(data, options.maxBytesPerChunk);
|
|
2694
2694
|
}
|
|
2695
|
-
if (segType ===
|
|
2695
|
+
if (segType === 'LABELMAP') {
|
|
2696
2696
|
// For LABELMAP, we can return the data as is, since it is already in a
|
|
2697
2697
|
// format that Cornerstone can handle. Also here we are returning the
|
|
2698
2698
|
// whole data at once, since the storage is more efficent than BINARY mode
|
|
@@ -2711,7 +2711,7 @@ function Segmentation_4X_unpackPixelData(multiframe, options) {
|
|
|
2711
2711
|
// This is a fractional segmentation, which is not currently supported.
|
|
2712
2712
|
return;
|
|
2713
2713
|
}
|
|
2714
|
-
dcmjs_es/* log */.Rm.warn(
|
|
2714
|
+
dcmjs_es/* log */.Rm.warn('This segmentation object is actually binary... processing as such.');
|
|
2715
2715
|
return pixelData;
|
|
2716
2716
|
}
|
|
2717
2717
|
function getUnpackedChunks(data, maxBytesPerChunk) {
|
|
@@ -2750,15 +2750,15 @@ function getImageIdOfSourceImageBySourceImageSequence(SourceImageSequence, sopUI
|
|
|
2750
2750
|
return undefined;
|
|
2751
2751
|
}
|
|
2752
2752
|
if (ReferencedFrameNumber !== undefined) {
|
|
2753
|
-
if (baseImageId.includes(
|
|
2753
|
+
if (baseImageId.includes('frames/')) {
|
|
2754
2754
|
return baseImageId.replace(/frames\/\d+/, `frames/${ReferencedFrameNumber}`);
|
|
2755
|
-
} else if (baseImageId.includes(
|
|
2755
|
+
} else if (baseImageId.includes('dicomfile:')) {
|
|
2756
2756
|
// dicomfile base 1, despite having frame=
|
|
2757
2757
|
return baseImageId.replace(/frame=\d+/, `frame=${ReferencedFrameNumber}`);
|
|
2758
|
-
} else if (baseImageId.includes(
|
|
2758
|
+
} else if (baseImageId.includes('frame=')) {
|
|
2759
2759
|
return baseImageId.replace(/frame=\d+/, `frame=${ReferencedFrameNumber - 1}`);
|
|
2760
2760
|
} else {
|
|
2761
|
-
if (baseImageId.includes(
|
|
2761
|
+
if (baseImageId.includes('wadors:')) {
|
|
2762
2762
|
return `${baseImageId}/frames/${ReferencedFrameNumber}`;
|
|
2763
2763
|
} else {
|
|
2764
2764
|
return `${baseImageId}?frame=${ReferencedFrameNumber - 1}`;
|
|
@@ -2797,7 +2797,7 @@ function getImageIdOfSourceImagebyGeometry(ReferencedSeriesInstanceUID, FrameOfR
|
|
|
2797
2797
|
}
|
|
2798
2798
|
const segFramePosition = PerFrameFunctionalGroup.PlanePositionSequence[0].ImagePositionPatient;
|
|
2799
2799
|
for (let imageId of imageIds) {
|
|
2800
|
-
const sourceImageMetadata = metadataProvider.get(
|
|
2800
|
+
const sourceImageMetadata = metadataProvider.get('instance', imageId);
|
|
2801
2801
|
if (!sourceImageMetadata) {
|
|
2802
2802
|
continue;
|
|
2803
2803
|
}
|
|
@@ -2808,7 +2808,7 @@ function getImageIdOfSourceImagebyGeometry(ReferencedSeriesInstanceUID, FrameOfR
|
|
|
2808
2808
|
|
|
2809
2809
|
// For multiframe images, check each frame's position
|
|
2810
2810
|
if (isMultiframe) {
|
|
2811
|
-
const framePosition = metadataProvider.get(
|
|
2811
|
+
const framePosition = metadataProvider.get('imagePlaneModule', imageId)?.imagePositionPatient;
|
|
2812
2812
|
if (framePosition && esm.utilities.isEqual(segFramePosition, framePosition, tolerance)) {
|
|
2813
2813
|
return imageId;
|
|
2814
2814
|
}
|
|
@@ -2938,7 +2938,7 @@ function readFromUnpackedChunks(chunks, offset, length) {
|
|
|
2938
2938
|
function getUnpackedOffsetAndLength(chunks, offset, length) {
|
|
2939
2939
|
var totalBytes = chunks.reduce((total, chunk) => total + chunk.length, 0);
|
|
2940
2940
|
if (offset < 0 || offset + length > totalBytes) {
|
|
2941
|
-
throw new Error(
|
|
2941
|
+
throw new Error('Offset and length out of bounds');
|
|
2942
2942
|
}
|
|
2943
2943
|
var startChunkIndex = 0;
|
|
2944
2944
|
var startOffsetInChunk = offset;
|
|
@@ -2979,9 +2979,9 @@ function calculateCentroid(imageIdIndexBufferIndex, multiframe, metadataProvider
|
|
|
2979
2979
|
|
|
2980
2980
|
// Get metadata for this slice
|
|
2981
2981
|
const imageId = imageIds[z];
|
|
2982
|
-
const imagePlaneModule = metadataProvider.get(
|
|
2982
|
+
const imagePlaneModule = metadataProvider.get('imagePlaneModule', imageId);
|
|
2983
2983
|
if (!imagePlaneModule) {
|
|
2984
|
-
console.debug(
|
|
2984
|
+
console.debug('Missing imagePlaneModule metadata for centroid calculation');
|
|
2985
2985
|
continue;
|
|
2986
2986
|
}
|
|
2987
2987
|
const {
|
|
@@ -3333,7 +3333,7 @@ const CornerstonePMAP = {
|
|
|
3333
3333
|
|
|
3334
3334
|
|
|
3335
3335
|
;// ../../../node_modules/@cornerstonejs/adapters/dist/esm/adapters/Cornerstone3D/cornerstone3DTag.js
|
|
3336
|
-
var CORNERSTONE_3D_TAG =
|
|
3336
|
+
var CORNERSTONE_3D_TAG = 'Cornerstone3DTools@^0.1.0';
|
|
3337
3337
|
|
|
3338
3338
|
|
|
3339
3339
|
|
|
@@ -3432,10 +3432,10 @@ function toPoint3(flatPoints) {
|
|
|
3432
3432
|
// This is a custom coding scheme defined to store some annotations from Cornerstone.
|
|
3433
3433
|
// Note: CodeMeaning is VR type LO, which means we only actually support 64 characters
|
|
3434
3434
|
// here this is fine for most labels, but may be problematic at some point.
|
|
3435
|
-
const CodingScheme_CORNERSTONEFREETEXT =
|
|
3435
|
+
const CodingScheme_CORNERSTONEFREETEXT = 'CORNERSTONEFREETEXT';
|
|
3436
3436
|
|
|
3437
3437
|
// Cornerstone specified coding scheme for storing findings
|
|
3438
|
-
const CodingSchemeDesignator =
|
|
3438
|
+
const CodingSchemeDesignator = 'CORNERSTONEJS';
|
|
3439
3439
|
const CodingScheme = {
|
|
3440
3440
|
CodingSchemeDesignator,
|
|
3441
3441
|
codeValues: {
|
|
@@ -6783,7 +6783,7 @@ class Segmentation_Segmentation {
|
|
|
6783
6783
|
* @return {{}}
|
|
6784
6784
|
*/
|
|
6785
6785
|
static generateSegments(dataset) {
|
|
6786
|
-
if (dataset.SegmentSequence.constructor.name !==
|
|
6786
|
+
if (dataset.SegmentSequence.constructor.name !== 'Array') {
|
|
6787
6787
|
dataset.SegmentSequence = [dataset.SegmentSequence];
|
|
6788
6788
|
}
|
|
6789
6789
|
dataset.SegmentSequence.forEach(segment => {
|
|
@@ -7045,6 +7045,8 @@ var SegmentationRepresentations;
|
|
|
7045
7045
|
/* harmony export */ });
|
|
7046
7046
|
var StrategyCallbacks;
|
|
7047
7047
|
(function (StrategyCallbacks) {
|
|
7048
|
+
StrategyCallbacks["CalculateCursorGeometry"] = "calculateCursorGeometry";
|
|
7049
|
+
StrategyCallbacks["RenderCursor"] = "renderCursor";
|
|
7048
7050
|
StrategyCallbacks["OnInteractionStart"] = "onInteractionStart";
|
|
7049
7051
|
StrategyCallbacks["OnInteractionEnd"] = "onInteractionEnd";
|
|
7050
7052
|
StrategyCallbacks["Preview"] = "preview";
|