@cornerstonejs/adapters 2.0.0-beta.1 → 2.0.0-beta.3
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/adapters.es.js +784 -36
- package/dist/adapters.es.js.map +1 -1
- package/dist/types/adapters/Cornerstone3D/RTStruct/RTSS.d.ts +27 -0
- package/dist/types/adapters/Cornerstone3D/RTStruct/index.d.ts +3 -0
- package/dist/types/adapters/Cornerstone3D/Segmentation/generateSegmentation.d.ts +1 -1
- package/dist/types/adapters/Cornerstone3D/index.d.ts +5 -1
- package/dist/types/adapters/helpers/downloadDICOMData.d.ts +10 -0
- package/dist/types/adapters/helpers/index.d.ts +2 -1
- package/dist/types/adapters/index.d.ts +7 -11
- package/dist/types/index.d.ts +2 -2
- package/package.json +5 -5
package/dist/adapters.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { utilities, derivations, normalizers,
|
|
1
|
+
import dcmjs, { data, utilities, derivations, normalizers, log } from 'dcmjs';
|
|
2
|
+
import { Buffer } from 'buffer';
|
|
2
3
|
import ndarray from 'ndarray';
|
|
3
4
|
import cloneDeep from 'lodash.clonedeep';
|
|
4
|
-
import { Buffer } from 'buffer';
|
|
5
5
|
import { vec3 } from 'gl-matrix';
|
|
6
6
|
|
|
7
7
|
function _iterableToArrayLimit(arr, i) {
|
|
@@ -545,9 +545,34 @@ var graphicTypeEquals = function (graphicType) {
|
|
|
545
545
|
};
|
|
546
546
|
};
|
|
547
547
|
|
|
548
|
+
var datasetToDict = data.datasetToDict;
|
|
549
|
+
/**
|
|
550
|
+
* Trigger file download from an array buffer
|
|
551
|
+
* @param bufferOrDataset - ArrayBuffer or DicomDataset
|
|
552
|
+
* @param filename - name of the file to download
|
|
553
|
+
*/
|
|
554
|
+
function downloadDICOMData(bufferOrDataset, filename) {
|
|
555
|
+
var blob;
|
|
556
|
+
if (bufferOrDataset instanceof ArrayBuffer) {
|
|
557
|
+
blob = new Blob([bufferOrDataset], { type: "application/dicom" });
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
if (!bufferOrDataset._meta) {
|
|
561
|
+
throw new Error("Dataset must have a _meta property");
|
|
562
|
+
}
|
|
563
|
+
var buffer = Buffer.from(datasetToDict(bufferOrDataset).write());
|
|
564
|
+
blob = new Blob([buffer], { type: "application/dicom" });
|
|
565
|
+
}
|
|
566
|
+
var link = document.createElement("a");
|
|
567
|
+
link.href = window.URL.createObjectURL(blob);
|
|
568
|
+
link.download = filename;
|
|
569
|
+
link.click();
|
|
570
|
+
}
|
|
571
|
+
|
|
548
572
|
var index$1 = /*#__PURE__*/Object.freeze({
|
|
549
573
|
__proto__: null,
|
|
550
574
|
codeMeaningEquals: codeMeaningEquals,
|
|
575
|
+
downloadDICOMData: downloadDICOMData,
|
|
551
576
|
graphicTypeEquals: graphicTypeEquals,
|
|
552
577
|
toArray: toArray
|
|
553
578
|
});
|
|
@@ -558,7 +583,7 @@ var StructuredReport$1 = derivations.StructuredReport;
|
|
|
558
583
|
var Normalizer$4 = normalizers.Normalizer;
|
|
559
584
|
var TID1500MeasurementReport$1 = TID1500$1.TID1500MeasurementReport,
|
|
560
585
|
TID1501MeasurementGroup$1 = TID1500$1.TID1501MeasurementGroup;
|
|
561
|
-
var DicomMetaDictionary$
|
|
586
|
+
var DicomMetaDictionary$4 = data.DicomMetaDictionary;
|
|
562
587
|
var FINDING$2 = {
|
|
563
588
|
CodingSchemeDesignator: "DCM",
|
|
564
589
|
CodeValue: "121071"
|
|
@@ -729,7 +754,7 @@ var MeasurementReport$1 = /*#__PURE__*/function () {
|
|
|
729
754
|
vr: "UI"
|
|
730
755
|
},
|
|
731
756
|
ImplementationClassUID: {
|
|
732
|
-
Value: [DicomMetaDictionary$
|
|
757
|
+
Value: [DicomMetaDictionary$4.uid()],
|
|
733
758
|
// TODO: could be git hash or other valid id
|
|
734
759
|
vr: "UI"
|
|
735
760
|
},
|
|
@@ -1802,7 +1827,7 @@ var _utilities$orientatio$1 = utilities.orientation,
|
|
|
1802
1827
|
var datasetToBlob = utilities.datasetToBlob,
|
|
1803
1828
|
BitArray$2 = utilities.BitArray,
|
|
1804
1829
|
DicomMessage$1 = utilities.DicomMessage,
|
|
1805
|
-
DicomMetaDictionary$
|
|
1830
|
+
DicomMetaDictionary$3 = utilities.DicomMetaDictionary;
|
|
1806
1831
|
var Normalizer$3 = normalizers.Normalizer;
|
|
1807
1832
|
var SegmentationDerivation$2 = derivations.Segmentation;
|
|
1808
1833
|
var Segmentation$5 = {
|
|
@@ -1932,16 +1957,16 @@ function _createSegFromImages$1(images, isMultiframe, options) {
|
|
|
1932
1957
|
var image = images[0];
|
|
1933
1958
|
var arrayBuffer = image.data.byteArray.buffer;
|
|
1934
1959
|
var dicomData = DicomMessage$1.readFile(arrayBuffer);
|
|
1935
|
-
var dataset = DicomMetaDictionary$
|
|
1936
|
-
dataset._meta = DicomMetaDictionary$
|
|
1960
|
+
var dataset = DicomMetaDictionary$3.naturalizeDataset(dicomData.dict);
|
|
1961
|
+
dataset._meta = DicomMetaDictionary$3.namifyDataset(dicomData.meta);
|
|
1937
1962
|
datasets.push(dataset);
|
|
1938
1963
|
} else {
|
|
1939
1964
|
for (var i = 0; i < images.length; i++) {
|
|
1940
1965
|
var _image = images[i];
|
|
1941
1966
|
var _arrayBuffer = _image.data.byteArray.buffer;
|
|
1942
1967
|
var _dicomData = DicomMessage$1.readFile(_arrayBuffer);
|
|
1943
|
-
var _dataset = DicomMetaDictionary$
|
|
1944
|
-
_dataset._meta = DicomMetaDictionary$
|
|
1968
|
+
var _dataset = DicomMetaDictionary$3.naturalizeDataset(_dicomData.dict);
|
|
1969
|
+
_dataset._meta = DicomMetaDictionary$3.namifyDataset(_dicomData.meta);
|
|
1945
1970
|
datasets.push(_dataset);
|
|
1946
1971
|
}
|
|
1947
1972
|
}
|
|
@@ -1961,8 +1986,8 @@ function _createSegFromImages$1(images, isMultiframe, options) {
|
|
|
1961
1986
|
*/
|
|
1962
1987
|
function generateToolState$3(imageIds, arrayBuffer, metadataProvider) {
|
|
1963
1988
|
var dicomData = DicomMessage$1.readFile(arrayBuffer);
|
|
1964
|
-
var dataset = DicomMetaDictionary$
|
|
1965
|
-
dataset._meta = DicomMetaDictionary$
|
|
1989
|
+
var dataset = DicomMetaDictionary$3.naturalizeDataset(dicomData.dict);
|
|
1990
|
+
dataset._meta = DicomMetaDictionary$3.namifyDataset(dicomData.meta);
|
|
1966
1991
|
var multiframe = Normalizer$3.normalizeToDataset([dataset]);
|
|
1967
1992
|
var imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
|
|
1968
1993
|
if (!imagePlaneModule) {
|
|
@@ -2240,10 +2265,9 @@ var _utilities$orientatio = utilities.orientation,
|
|
|
2240
2265
|
flipMatrix2D = _utilities$orientatio.flipMatrix2D,
|
|
2241
2266
|
rotateMatrix902D = _utilities$orientatio.rotateMatrix902D,
|
|
2242
2267
|
nearlyEqual = _utilities$orientatio.nearlyEqual;
|
|
2243
|
-
var
|
|
2244
|
-
BitArray$1 = data.BitArray,
|
|
2268
|
+
var BitArray$1 = data.BitArray,
|
|
2245
2269
|
DicomMessage = data.DicomMessage,
|
|
2246
|
-
DicomMetaDictionary$
|
|
2270
|
+
DicomMetaDictionary$2 = data.DicomMetaDictionary;
|
|
2247
2271
|
var Normalizer$2 = normalizers.Normalizer;
|
|
2248
2272
|
var SegmentationDerivation$1 = derivations.Segmentation;
|
|
2249
2273
|
var _utilities$compressio = utilities.compression,
|
|
@@ -2280,12 +2304,13 @@ function generateSegmentation$2(images, inputLabelmaps3D) {
|
|
|
2280
2304
|
}
|
|
2281
2305
|
|
|
2282
2306
|
/**
|
|
2283
|
-
*
|
|
2307
|
+
* Fills a given segmentation object with data from the input labelmaps3D
|
|
2284
2308
|
*
|
|
2285
|
-
* @param
|
|
2286
|
-
* @param
|
|
2287
|
-
* @param
|
|
2288
|
-
*
|
|
2309
|
+
* @param segmentation - The segmentation object to be filled.
|
|
2310
|
+
* @param inputLabelmaps3D - An array of 3D labelmaps, or a single 3D labelmap.
|
|
2311
|
+
* @param userOptions - Optional configuration settings. Will override the default options.
|
|
2312
|
+
*
|
|
2313
|
+
* @returns {object} The filled segmentation object.
|
|
2289
2314
|
*/
|
|
2290
2315
|
function fillSegmentation$1(segmentation, inputLabelmaps3D) {
|
|
2291
2316
|
var userOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -2367,11 +2392,7 @@ function fillSegmentation$1(segmentation, inputLabelmaps3D) {
|
|
|
2367
2392
|
// If no rleEncoding, at least bitpack the data.
|
|
2368
2393
|
segmentation.bitPackPixelData();
|
|
2369
2394
|
}
|
|
2370
|
-
|
|
2371
|
-
var segBlob = new Blob([buffer], {
|
|
2372
|
-
type: "application/dicom"
|
|
2373
|
-
});
|
|
2374
|
-
return segBlob;
|
|
2395
|
+
return segmentation;
|
|
2375
2396
|
}
|
|
2376
2397
|
function _getLabelmapsFromReferencedFrameIndicies(labelmap3D, referencedFrameIndicies) {
|
|
2377
2398
|
var labelmaps2D = labelmap3D.labelmaps2D;
|
|
@@ -2396,16 +2417,16 @@ function _createSegFromImages(images, isMultiframe, options) {
|
|
|
2396
2417
|
var image = images[0];
|
|
2397
2418
|
var arrayBuffer = image.data.byteArray.buffer;
|
|
2398
2419
|
var dicomData = DicomMessage.readFile(arrayBuffer);
|
|
2399
|
-
var dataset = DicomMetaDictionary$
|
|
2400
|
-
dataset._meta = DicomMetaDictionary$
|
|
2420
|
+
var dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
|
|
2421
|
+
dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
|
|
2401
2422
|
datasets.push(dataset);
|
|
2402
2423
|
} else {
|
|
2403
2424
|
for (var i = 0; i < images.length; i++) {
|
|
2404
2425
|
var _image = images[i];
|
|
2405
2426
|
var _arrayBuffer = _image.data.byteArray.buffer;
|
|
2406
2427
|
var _dicomData = DicomMessage.readFile(_arrayBuffer);
|
|
2407
|
-
var _dataset = DicomMetaDictionary$
|
|
2408
|
-
_dataset._meta = DicomMetaDictionary$
|
|
2428
|
+
var _dataset = DicomMetaDictionary$2.naturalizeDataset(_dicomData.dict);
|
|
2429
|
+
_dataset._meta = DicomMetaDictionary$2.namifyDataset(_dicomData.meta);
|
|
2409
2430
|
datasets.push(_dataset);
|
|
2410
2431
|
}
|
|
2411
2432
|
}
|
|
@@ -2589,8 +2610,8 @@ function _generateToolState() {
|
|
|
2589
2610
|
case 0:
|
|
2590
2611
|
_options$skipOverlapp = options.skipOverlapping, skipOverlapping = _options$skipOverlapp === void 0 ? false : _options$skipOverlapp, _options$tolerance = options.tolerance, tolerance = _options$tolerance === void 0 ? 1e-3 : _options$tolerance, _options$TypedArrayCo = options.TypedArrayConstructor, TypedArrayConstructor = _options$TypedArrayCo === void 0 ? Uint8Array : _options$TypedArrayCo, _options$maxBytesPerC = options.maxBytesPerChunk, maxBytesPerChunk = _options$maxBytesPerC === void 0 ? 199000000 : _options$maxBytesPerC, eventTarget = options.eventTarget, triggerEvent = options.triggerEvent;
|
|
2591
2612
|
dicomData = DicomMessage.readFile(arrayBuffer);
|
|
2592
|
-
dataset = DicomMetaDictionary$
|
|
2593
|
-
dataset._meta = DicomMetaDictionary$
|
|
2613
|
+
dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
|
|
2614
|
+
dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
|
|
2594
2615
|
multiframe = Normalizer$2.normalizeToDataset([dataset]);
|
|
2595
2616
|
imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
|
|
2596
2617
|
generalSeriesModule = metadataProvider.get("generalSeriesModule", imageIds[0]);
|
|
@@ -3566,7 +3587,7 @@ var TID1500 = utilities.TID1500, addAccessors = utilities.addAccessors;
|
|
|
3566
3587
|
var StructuredReport = derivations.StructuredReport;
|
|
3567
3588
|
var Normalizer$1 = normalizers.Normalizer;
|
|
3568
3589
|
var TID1500MeasurementReport = TID1500.TID1500MeasurementReport, TID1501MeasurementGroup = TID1500.TID1501MeasurementGroup;
|
|
3569
|
-
var DicomMetaDictionary = data.DicomMetaDictionary;
|
|
3590
|
+
var DicomMetaDictionary$1 = data.DicomMetaDictionary;
|
|
3570
3591
|
var FINDING = { CodingSchemeDesignator: "DCM", CodeValue: "121071" };
|
|
3571
3592
|
var FINDING_SITE = { CodingSchemeDesignator: "SCT", CodeValue: "363698007" };
|
|
3572
3593
|
var FINDING_SITE_OLD = { CodingSchemeDesignator: "SRT", CodeValue: "G-C0E3" };
|
|
@@ -3635,7 +3656,7 @@ var MeasurementReport = /** @class */ (function () {
|
|
|
3635
3656
|
vr: "UI"
|
|
3636
3657
|
},
|
|
3637
3658
|
ImplementationClassUID: {
|
|
3638
|
-
Value: [DicomMetaDictionary.uid()],
|
|
3659
|
+
Value: [DicomMetaDictionary$1.uid()],
|
|
3639
3660
|
vr: "UI"
|
|
3640
3661
|
},
|
|
3641
3662
|
ImplementationVersionName: {
|
|
@@ -3670,7 +3691,7 @@ var MeasurementReport = /** @class */ (function () {
|
|
|
3670
3691
|
description: undefined,
|
|
3671
3692
|
sopInstanceUid: ReferencedSOPInstanceUID,
|
|
3672
3693
|
annotation: {
|
|
3673
|
-
annotationUID: DicomMetaDictionary.uid(),
|
|
3694
|
+
annotationUID: DicomMetaDictionary$1.uid(),
|
|
3674
3695
|
metadata: {
|
|
3675
3696
|
toolName: toolType,
|
|
3676
3697
|
referencedImageId: referencedImageId,
|
|
@@ -4853,6 +4874,7 @@ var SegmentationDerivation = derivations.Segmentation;
|
|
|
4853
4874
|
* @param labelmaps - An array of the 3D Volumes that contain the segmentation data.
|
|
4854
4875
|
*/
|
|
4855
4876
|
function generateSegmentation(images, labelmaps, metadata, options) {
|
|
4877
|
+
if (options === void 0) { options = {}; }
|
|
4856
4878
|
var segmentation = _createMultiframeSegmentationFromReferencedImages(images, metadata, options);
|
|
4857
4879
|
return fillSegmentation$1(segmentation, labelmaps, options);
|
|
4858
4880
|
}
|
|
@@ -4872,7 +4894,7 @@ function _createMultiframeSegmentationFromReferencedImages(images, metadata, opt
|
|
|
4872
4894
|
var instance = metadata.get("instance", image.imageId);
|
|
4873
4895
|
return __assign(__assign(__assign({}, image), instance), {
|
|
4874
4896
|
// Todo: move to dcmjs tag style
|
|
4875
|
-
SOPClassUID: instance.SopClassUID, SOPInstanceUID: instance.SopInstanceUID, PixelData: image.getPixelData(), _vrMap: {
|
|
4897
|
+
SOPClassUID: instance.SopClassUID || instance.SOPClassUID, SOPInstanceUID: instance.SopInstanceUID || instance.SOPInstanceUID, PixelData: image.getPixelData(), _vrMap: {
|
|
4876
4898
|
PixelData: "OW"
|
|
4877
4899
|
}, _meta: {} });
|
|
4878
4900
|
});
|
|
@@ -4952,6 +4974,726 @@ var Segmentation$1 = /*#__PURE__*/Object.freeze({
|
|
|
4952
4974
|
generateToolState: generateToolState
|
|
4953
4975
|
});
|
|
4954
4976
|
|
|
4977
|
+
/**
|
|
4978
|
+
* Checks if point is within array
|
|
4979
|
+
* @param {*} array
|
|
4980
|
+
* @param {*} pt
|
|
4981
|
+
* @returns
|
|
4982
|
+
*/
|
|
4983
|
+
function ptInArray(array, pt) {
|
|
4984
|
+
var index = -1;
|
|
4985
|
+
for (var i = 0; i < array.length; i++) {
|
|
4986
|
+
if (isSamePoint(pt, array[i])) {
|
|
4987
|
+
index = i;
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
return index;
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
/**
|
|
4994
|
+
* Checks if point A and point B contain same values
|
|
4995
|
+
* @param {*} ptA
|
|
4996
|
+
* @param {*} ptB
|
|
4997
|
+
* @returns
|
|
4998
|
+
*/
|
|
4999
|
+
function isSamePoint(ptA, ptB) {
|
|
5000
|
+
if (ptA[0] == ptB[0] && ptA[1] == ptB[1] && ptA[2] == ptB[2]) {
|
|
5001
|
+
return true;
|
|
5002
|
+
} else {
|
|
5003
|
+
return false;
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
|
|
5007
|
+
/**
|
|
5008
|
+
* Goes through linesArray and replaces all references of old index with new index
|
|
5009
|
+
* @param {*} linesArray
|
|
5010
|
+
* @param {*} oldIndex
|
|
5011
|
+
* @param {*} newIndex
|
|
5012
|
+
*/
|
|
5013
|
+
function replacePointIndexReferences(linesArray, oldIndex, newIndex) {
|
|
5014
|
+
for (var i = 0; i < linesArray.length; i++) {
|
|
5015
|
+
var line = linesArray[i];
|
|
5016
|
+
if (line.a == oldIndex) {
|
|
5017
|
+
line.a = newIndex;
|
|
5018
|
+
} else if (line.b == oldIndex) {
|
|
5019
|
+
line.b = newIndex;
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
}
|
|
5023
|
+
|
|
5024
|
+
/**
|
|
5025
|
+
* Iterate through polyData from vtkjs and merge any points that are the same
|
|
5026
|
+
* then update merged point references within lines array
|
|
5027
|
+
* @param {*} polyData
|
|
5028
|
+
* @param {*} bypass
|
|
5029
|
+
* @returns
|
|
5030
|
+
*/
|
|
5031
|
+
function removeDuplicatePoints(polyData, bypass) {
|
|
5032
|
+
var points = polyData.getPoints();
|
|
5033
|
+
var lines = polyData.getLines();
|
|
5034
|
+
var pointsArray = [];
|
|
5035
|
+
for (var i = 0; i < points.getNumberOfPoints(); i++) {
|
|
5036
|
+
var pt = points.getPoint(i).slice();
|
|
5037
|
+
pointsArray.push(pt);
|
|
5038
|
+
}
|
|
5039
|
+
var linesArray = [];
|
|
5040
|
+
for (var _i = 0; _i < lines.getNumberOfCells(); _i++) {
|
|
5041
|
+
var cell = lines.getCell(_i * 3).slice();
|
|
5042
|
+
//console.log(JSON.stringify(cell));
|
|
5043
|
+
var a = cell[0];
|
|
5044
|
+
var b = cell[1];
|
|
5045
|
+
var line = {
|
|
5046
|
+
a: a,
|
|
5047
|
+
b: b
|
|
5048
|
+
};
|
|
5049
|
+
linesArray.push(line);
|
|
5050
|
+
}
|
|
5051
|
+
if (bypass) {
|
|
5052
|
+
return {
|
|
5053
|
+
points: pointsArray,
|
|
5054
|
+
lines: linesArray
|
|
5055
|
+
};
|
|
5056
|
+
}
|
|
5057
|
+
|
|
5058
|
+
// Iterate through points and replace any duplicates
|
|
5059
|
+
var newPoints = [];
|
|
5060
|
+
for (var _i2 = 0; _i2 < pointsArray.length; _i2++) {
|
|
5061
|
+
var _pt = pointsArray[_i2];
|
|
5062
|
+
var index = ptInArray(newPoints, _pt);
|
|
5063
|
+
if (index >= 0) {
|
|
5064
|
+
// Duplicate Point -> replace references in lines
|
|
5065
|
+
replacePointIndexReferences(linesArray, _i2, index);
|
|
5066
|
+
} else {
|
|
5067
|
+
index = newPoints.length;
|
|
5068
|
+
newPoints.push(_pt);
|
|
5069
|
+
replacePointIndexReferences(linesArray, _i2, index);
|
|
5070
|
+
}
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5073
|
+
// Final pass through lines, remove any that refer to exact same point
|
|
5074
|
+
var newLines = [];
|
|
5075
|
+
linesArray.forEach(function (line) {
|
|
5076
|
+
if (line.a != line.b) {
|
|
5077
|
+
newLines.push(line);
|
|
5078
|
+
}
|
|
5079
|
+
});
|
|
5080
|
+
return {
|
|
5081
|
+
points: newPoints,
|
|
5082
|
+
lines: newLines
|
|
5083
|
+
};
|
|
5084
|
+
}
|
|
5085
|
+
|
|
5086
|
+
function findNextLink(line, lines, contourPoints) {
|
|
5087
|
+
var index = -1;
|
|
5088
|
+
lines.forEach(function (cell, i) {
|
|
5089
|
+
if (index >= 0) {
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
if (cell.a == line.b) {
|
|
5093
|
+
index = i;
|
|
5094
|
+
}
|
|
5095
|
+
});
|
|
5096
|
+
if (index >= 0) {
|
|
5097
|
+
var nextLine = lines[index];
|
|
5098
|
+
lines.splice(index, 1);
|
|
5099
|
+
contourPoints.push(nextLine.b);
|
|
5100
|
+
if (contourPoints[0] == nextLine.b) {
|
|
5101
|
+
return {
|
|
5102
|
+
remainingLines: lines,
|
|
5103
|
+
contourPoints: contourPoints,
|
|
5104
|
+
type: "CLOSED_PLANAR"
|
|
5105
|
+
//type: 'CLOSEDPLANAR_XOR',
|
|
5106
|
+
};
|
|
5107
|
+
}
|
|
5108
|
+
|
|
5109
|
+
return findNextLink(nextLine, lines, contourPoints);
|
|
5110
|
+
}
|
|
5111
|
+
return {
|
|
5112
|
+
remainingLines: lines,
|
|
5113
|
+
contourPoints: contourPoints,
|
|
5114
|
+
type: "OPEN_PLANAR"
|
|
5115
|
+
};
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
/**
|
|
5119
|
+
*
|
|
5120
|
+
* @param {*} lines
|
|
5121
|
+
*/
|
|
5122
|
+
function findContours(lines) {
|
|
5123
|
+
if (lines.length == 0) {
|
|
5124
|
+
return [];
|
|
5125
|
+
}
|
|
5126
|
+
var contourPoints = [];
|
|
5127
|
+
var firstCell = lines.shift();
|
|
5128
|
+
contourPoints.push(firstCell.a);
|
|
5129
|
+
contourPoints.push(firstCell.b);
|
|
5130
|
+
var result = findNextLink(firstCell, lines, contourPoints);
|
|
5131
|
+
if (result.remainingLines.length == 0) {
|
|
5132
|
+
return [{
|
|
5133
|
+
type: result.type,
|
|
5134
|
+
contourPoints: result.contourPoints
|
|
5135
|
+
}];
|
|
5136
|
+
} else {
|
|
5137
|
+
var extraContours = findContours(result.remainingLines);
|
|
5138
|
+
extraContours.push({
|
|
5139
|
+
type: result.type,
|
|
5140
|
+
contourPoints: result.contourPoints
|
|
5141
|
+
});
|
|
5142
|
+
return extraContours;
|
|
5143
|
+
}
|
|
5144
|
+
}
|
|
5145
|
+
function findContoursFromReducedSet(lines, points) {
|
|
5146
|
+
return findContours(lines);
|
|
5147
|
+
}
|
|
5148
|
+
|
|
5149
|
+
function generateContourSetsFromLabelmap(_ref) {
|
|
5150
|
+
var segmentations = _ref.segmentations,
|
|
5151
|
+
cornerstoneCache = _ref.cornerstoneCache,
|
|
5152
|
+
cornerstoneToolsEnums = _ref.cornerstoneToolsEnums,
|
|
5153
|
+
vtkUtils = _ref.vtkUtils;
|
|
5154
|
+
var LABELMAP = cornerstoneToolsEnums.SegmentationRepresentations.Labelmap;
|
|
5155
|
+
var representationData = segmentations.representationData,
|
|
5156
|
+
segments = segmentations.segments;
|
|
5157
|
+
var segVolumeId = representationData[LABELMAP].volumeId;
|
|
5158
|
+
|
|
5159
|
+
// Get segmentation volume
|
|
5160
|
+
var vol = cornerstoneCache.getVolume(segVolumeId);
|
|
5161
|
+
if (!vol) {
|
|
5162
|
+
console.warn("No volume found for ".concat(segVolumeId));
|
|
5163
|
+
return;
|
|
5164
|
+
}
|
|
5165
|
+
var numSlices = vol.dimensions[2];
|
|
5166
|
+
|
|
5167
|
+
// Get image volume segmentation references
|
|
5168
|
+
var imageVol = cornerstoneCache.getVolume(vol.referencedVolumeId);
|
|
5169
|
+
if (!imageVol) {
|
|
5170
|
+
console.warn("No volume found for ".concat(vol.referencedVolumeId));
|
|
5171
|
+
return;
|
|
5172
|
+
}
|
|
5173
|
+
|
|
5174
|
+
// NOTE: Workaround for marching squares not finding closed contours at
|
|
5175
|
+
// boundary of image volume, clear pixels along x-y border of volume
|
|
5176
|
+
var segData = vol.imageData.getPointData().getScalars().getData();
|
|
5177
|
+
var pixelsPerSlice = vol.dimensions[0] * vol.dimensions[1];
|
|
5178
|
+
for (var z = 0; z < numSlices; z++) {
|
|
5179
|
+
for (var y = 0; y < vol.dimensions[1]; y++) {
|
|
5180
|
+
for (var x = 0; x < vol.dimensions[0]; x++) {
|
|
5181
|
+
var index = x + y * vol.dimensions[0] + z * pixelsPerSlice;
|
|
5182
|
+
if (x === 0 || y === 0 || x === vol.dimensions[0] - 1 || y === vol.dimensions[1] - 1) {
|
|
5183
|
+
segData[index] = 0;
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
}
|
|
5188
|
+
|
|
5189
|
+
// end workaround
|
|
5190
|
+
//
|
|
5191
|
+
//
|
|
5192
|
+
var ContourSets = [];
|
|
5193
|
+
|
|
5194
|
+
// Iterate through all segments in current segmentation set
|
|
5195
|
+
var numSegments = segments.length;
|
|
5196
|
+
for (var segIndex = 0; segIndex < numSegments; segIndex++) {
|
|
5197
|
+
var segment = segments[segIndex];
|
|
5198
|
+
|
|
5199
|
+
// Skip empty segments
|
|
5200
|
+
if (!segment) {
|
|
5201
|
+
continue;
|
|
5202
|
+
}
|
|
5203
|
+
var contourSequence = [];
|
|
5204
|
+
for (var sliceIndex = 0; sliceIndex < numSlices; sliceIndex++) {
|
|
5205
|
+
// Check if the slice is empty before running marching cube
|
|
5206
|
+
if (isSliceEmptyForSegment(sliceIndex, segData, pixelsPerSlice, segIndex)) {
|
|
5207
|
+
continue;
|
|
5208
|
+
}
|
|
5209
|
+
try {
|
|
5210
|
+
var _reducedSet$points;
|
|
5211
|
+
var scalars = vtkUtils.vtkDataArray.newInstance({
|
|
5212
|
+
name: "Scalars",
|
|
5213
|
+
values: Array.from(segData),
|
|
5214
|
+
numberOfComponents: 1
|
|
5215
|
+
});
|
|
5216
|
+
|
|
5217
|
+
// Modify segData for this specific segment directly
|
|
5218
|
+
var segmentIndexFound = false;
|
|
5219
|
+
for (var i = 0; i < segData.length; i++) {
|
|
5220
|
+
var value = segData[i];
|
|
5221
|
+
if (value === segIndex) {
|
|
5222
|
+
segmentIndexFound = true;
|
|
5223
|
+
scalars.setValue(i, 1);
|
|
5224
|
+
} else {
|
|
5225
|
+
scalars.setValue(i, 0);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
if (!segmentIndexFound) {
|
|
5229
|
+
continue;
|
|
5230
|
+
}
|
|
5231
|
+
var mSquares = vtkUtils.vtkImageMarchingSquares.newInstance({
|
|
5232
|
+
slice: sliceIndex
|
|
5233
|
+
});
|
|
5234
|
+
|
|
5235
|
+
// filter out the scalar data so that only it has background and
|
|
5236
|
+
// the current segment index
|
|
5237
|
+
var imageDataCopy = vtkUtils.vtkImageData.newInstance();
|
|
5238
|
+
imageDataCopy.shallowCopy(vol.imageData);
|
|
5239
|
+
imageDataCopy.getPointData().setScalars(scalars);
|
|
5240
|
+
|
|
5241
|
+
// Connect pipeline
|
|
5242
|
+
mSquares.setInputData(imageDataCopy);
|
|
5243
|
+
var cValues = [];
|
|
5244
|
+
cValues[0] = 1;
|
|
5245
|
+
mSquares.setContourValues(cValues);
|
|
5246
|
+
mSquares.setMergePoints(false);
|
|
5247
|
+
|
|
5248
|
+
// Perform marching squares
|
|
5249
|
+
var msOutput = mSquares.getOutputData();
|
|
5250
|
+
|
|
5251
|
+
// Clean up output from marching squares
|
|
5252
|
+
var reducedSet = removeDuplicatePoints(msOutput);
|
|
5253
|
+
if ((_reducedSet$points = reducedSet.points) !== null && _reducedSet$points !== void 0 && _reducedSet$points.length) {
|
|
5254
|
+
var contours = findContoursFromReducedSet(reducedSet.lines, reducedSet.points);
|
|
5255
|
+
contourSequence.push({
|
|
5256
|
+
referencedImageId: imageVol.imageIds[sliceIndex],
|
|
5257
|
+
contours: contours,
|
|
5258
|
+
polyData: reducedSet
|
|
5259
|
+
});
|
|
5260
|
+
}
|
|
5261
|
+
} catch (e) {
|
|
5262
|
+
console.warn(sliceIndex);
|
|
5263
|
+
console.warn(e);
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
var metadata = {
|
|
5267
|
+
referencedImageId: imageVol.imageIds[0],
|
|
5268
|
+
// just use 0
|
|
5269
|
+
FrameOfReferenceUID: imageVol.metadata.FrameOfReferenceUID
|
|
5270
|
+
};
|
|
5271
|
+
var ContourSet = {
|
|
5272
|
+
label: segment.label,
|
|
5273
|
+
color: segment.color,
|
|
5274
|
+
metadata: metadata,
|
|
5275
|
+
sliceContours: contourSequence
|
|
5276
|
+
};
|
|
5277
|
+
ContourSets.push(ContourSet);
|
|
5278
|
+
}
|
|
5279
|
+
return ContourSets;
|
|
5280
|
+
}
|
|
5281
|
+
function isSliceEmptyForSegment(sliceIndex, segData, pixelsPerSlice, segIndex) {
|
|
5282
|
+
var startIdx = sliceIndex * pixelsPerSlice;
|
|
5283
|
+
var endIdx = startIdx + pixelsPerSlice;
|
|
5284
|
+
for (var i = startIdx; i < endIdx; i++) {
|
|
5285
|
+
if (segData[i] === segIndex) {
|
|
5286
|
+
return false;
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
return true;
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
// comment
|
|
5293
|
+
var RectangleROIStartEndThreshold = /*#__PURE__*/function () {
|
|
5294
|
+
function RectangleROIStartEndThreshold() {
|
|
5295
|
+
_classCallCheck(this, RectangleROIStartEndThreshold);
|
|
5296
|
+
} // empty
|
|
5297
|
+
_createClass(RectangleROIStartEndThreshold, null, [{
|
|
5298
|
+
key: "getContourSequence",
|
|
5299
|
+
value: function getContourSequence(toolData, metadataProvider) {
|
|
5300
|
+
var data = toolData.data;
|
|
5301
|
+
var _data$cachedStats = data.cachedStats,
|
|
5302
|
+
projectionPoints = _data$cachedStats.projectionPoints,
|
|
5303
|
+
projectionPointsImageIds = _data$cachedStats.projectionPointsImageIds;
|
|
5304
|
+
return projectionPoints.map(function (point, index) {
|
|
5305
|
+
var ContourData = getPointData(point);
|
|
5306
|
+
var ContourImageSequence = getContourImageSequence(projectionPointsImageIds[index], metadataProvider);
|
|
5307
|
+
return {
|
|
5308
|
+
NumberOfContourPoints: ContourData.length / 3,
|
|
5309
|
+
ContourImageSequence: ContourImageSequence,
|
|
5310
|
+
ContourGeometricType: "CLOSED_PLANAR",
|
|
5311
|
+
ContourData: ContourData
|
|
5312
|
+
};
|
|
5313
|
+
});
|
|
5314
|
+
}
|
|
5315
|
+
}]);
|
|
5316
|
+
return RectangleROIStartEndThreshold;
|
|
5317
|
+
}();
|
|
5318
|
+
RectangleROIStartEndThreshold.toolName = "RectangleROIStartEndThreshold";
|
|
5319
|
+
function getPointData(points) {
|
|
5320
|
+
// Since this is a closed contour, the order of the points is important.
|
|
5321
|
+
// re-order the points to be in the correct order clockwise
|
|
5322
|
+
// Spread to make sure Float32Arrays are converted to arrays
|
|
5323
|
+
var orderedPoints = [].concat(_toConsumableArray(points[0]), _toConsumableArray(points[1]), _toConsumableArray(points[3]), _toConsumableArray(points[2]));
|
|
5324
|
+
var pointsArray = orderedPoints.flat();
|
|
5325
|
+
|
|
5326
|
+
// reduce the precision of the points to 2 decimal places
|
|
5327
|
+
var pointsArrayWithPrecision = pointsArray.map(function (point) {
|
|
5328
|
+
return point.toFixed(2);
|
|
5329
|
+
});
|
|
5330
|
+
return pointsArrayWithPrecision;
|
|
5331
|
+
}
|
|
5332
|
+
function getContourImageSequence(imageId, metadataProvider) {
|
|
5333
|
+
var sopCommon = metadataProvider.get("sopCommonModule", imageId);
|
|
5334
|
+
return {
|
|
5335
|
+
ReferencedSOPClassUID: sopCommon.sopClassUID,
|
|
5336
|
+
ReferencedSOPInstanceUID: sopCommon.sopInstanceUID
|
|
5337
|
+
};
|
|
5338
|
+
}
|
|
5339
|
+
|
|
5340
|
+
function validateAnnotation(annotation) {
|
|
5341
|
+
if (!(annotation !== null && annotation !== void 0 && annotation.data)) {
|
|
5342
|
+
throw new Error("Tool data is empty");
|
|
5343
|
+
}
|
|
5344
|
+
if (!annotation.metadata || annotation.metadata.referenceImageId) {
|
|
5345
|
+
throw new Error("Tool data is not associated with any imageId");
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
var AnnotationToPointData = /*#__PURE__*/function () {
|
|
5349
|
+
function AnnotationToPointData() {
|
|
5350
|
+
_classCallCheck(this, AnnotationToPointData);
|
|
5351
|
+
} // empty
|
|
5352
|
+
_createClass(AnnotationToPointData, null, [{
|
|
5353
|
+
key: "convert",
|
|
5354
|
+
value: function convert(annotation, index, metadataProvider) {
|
|
5355
|
+
validateAnnotation(annotation);
|
|
5356
|
+
var toolName = annotation.metadata.toolName;
|
|
5357
|
+
var toolClass = AnnotationToPointData.TOOL_NAMES[toolName];
|
|
5358
|
+
if (!toolClass) {
|
|
5359
|
+
throw new Error("Unknown tool type: ".concat(toolName, ", cannot convert to RTSSReport"));
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5362
|
+
// Each toolData should become a list of contours, ContourSequence
|
|
5363
|
+
// contains a list of contours with their pointData, their geometry
|
|
5364
|
+
// type and their length.
|
|
5365
|
+
var ContourSequence = toolClass.getContourSequence(annotation, metadataProvider);
|
|
5366
|
+
|
|
5367
|
+
// Todo: random rgb color for now, options should be passed in
|
|
5368
|
+
var color = [Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)];
|
|
5369
|
+
return {
|
|
5370
|
+
ReferencedROINumber: index + 1,
|
|
5371
|
+
ROIDisplayColor: color,
|
|
5372
|
+
ContourSequence: ContourSequence
|
|
5373
|
+
};
|
|
5374
|
+
}
|
|
5375
|
+
}, {
|
|
5376
|
+
key: "register",
|
|
5377
|
+
value: function register(toolClass) {
|
|
5378
|
+
AnnotationToPointData.TOOL_NAMES[toolClass.toolName] = toolClass;
|
|
5379
|
+
}
|
|
5380
|
+
}]);
|
|
5381
|
+
return AnnotationToPointData;
|
|
5382
|
+
}();
|
|
5383
|
+
AnnotationToPointData.TOOL_NAMES = {};
|
|
5384
|
+
AnnotationToPointData.register(RectangleROIStartEndThreshold);
|
|
5385
|
+
|
|
5386
|
+
function getPatientModule(imageId, metadataProvider) {
|
|
5387
|
+
var generalSeriesModule = metadataProvider.get("generalSeriesModule", imageId);
|
|
5388
|
+
var generalStudyModule = metadataProvider.get("generalStudyModule", imageId);
|
|
5389
|
+
var patientStudyModule = metadataProvider.get("patientStudyModule", imageId);
|
|
5390
|
+
var patientModule = metadataProvider.get("patientModule", imageId);
|
|
5391
|
+
var patientDemographicModule = metadataProvider.get("patientDemographicModule", imageId);
|
|
5392
|
+
return {
|
|
5393
|
+
Modality: generalSeriesModule.modality,
|
|
5394
|
+
PatientID: patientModule.patientId,
|
|
5395
|
+
PatientName: patientModule.patientName,
|
|
5396
|
+
PatientBirthDate: "",
|
|
5397
|
+
PatientAge: patientStudyModule.patientAge,
|
|
5398
|
+
PatientSex: patientDemographicModule.patientSex,
|
|
5399
|
+
PatientWeight: patientStudyModule.patientWeight,
|
|
5400
|
+
StudyDate: generalStudyModule.studyDate,
|
|
5401
|
+
StudyTime: generalStudyModule.studyTime,
|
|
5402
|
+
StudyID: "ToDo",
|
|
5403
|
+
AccessionNumber: generalStudyModule.accessionNumber
|
|
5404
|
+
};
|
|
5405
|
+
}
|
|
5406
|
+
|
|
5407
|
+
function getReferencedFrameOfReferenceSequence(metadata, metadataProvider, dataset) {
|
|
5408
|
+
var imageId = metadata.referencedImageId,
|
|
5409
|
+
FrameOfReferenceUID = metadata.FrameOfReferenceUID;
|
|
5410
|
+
var instance = metadataProvider.get("instance", imageId);
|
|
5411
|
+
var SeriesInstanceUID = instance.SeriesInstanceUID;
|
|
5412
|
+
var ReferencedSeriesSequence = dataset.ReferencedSeriesSequence;
|
|
5413
|
+
return [{
|
|
5414
|
+
FrameOfReferenceUID: FrameOfReferenceUID,
|
|
5415
|
+
RTReferencedStudySequence: [{
|
|
5416
|
+
ReferencedSOPClassUID: dataset.SOPClassUID,
|
|
5417
|
+
ReferencedSOPInstanceUID: dataset.SOPInstanceUID,
|
|
5418
|
+
RTReferencedSeriesSequence: [{
|
|
5419
|
+
SeriesInstanceUID: SeriesInstanceUID,
|
|
5420
|
+
ContourImageSequence: _toConsumableArray(ReferencedSeriesSequence[0].ReferencedInstanceSequence)
|
|
5421
|
+
}]
|
|
5422
|
+
}]
|
|
5423
|
+
}];
|
|
5424
|
+
}
|
|
5425
|
+
|
|
5426
|
+
function getReferencedSeriesSequence(metadata, _index, metadataProvider, DicomMetadataStore) {
|
|
5427
|
+
// grab imageId from toolData
|
|
5428
|
+
var imageId = metadata.referencedImageId;
|
|
5429
|
+
var instance = metadataProvider.get("instance", imageId);
|
|
5430
|
+
var SeriesInstanceUID = instance.SeriesInstanceUID,
|
|
5431
|
+
StudyInstanceUID = instance.StudyInstanceUID;
|
|
5432
|
+
var ReferencedSeriesSequence = [];
|
|
5433
|
+
if (SeriesInstanceUID) {
|
|
5434
|
+
var series = DicomMetadataStore.getSeries(StudyInstanceUID, SeriesInstanceUID);
|
|
5435
|
+
var ReferencedSeries = {
|
|
5436
|
+
SeriesInstanceUID: SeriesInstanceUID,
|
|
5437
|
+
ReferencedInstanceSequence: []
|
|
5438
|
+
};
|
|
5439
|
+
series.instances.forEach(function (instance) {
|
|
5440
|
+
var SOPInstanceUID = instance.SOPInstanceUID,
|
|
5441
|
+
SOPClassUID = instance.SOPClassUID;
|
|
5442
|
+
ReferencedSeries.ReferencedInstanceSequence.push({
|
|
5443
|
+
ReferencedSOPClassUID: SOPClassUID,
|
|
5444
|
+
ReferencedSOPInstanceUID: SOPInstanceUID
|
|
5445
|
+
});
|
|
5446
|
+
});
|
|
5447
|
+
ReferencedSeriesSequence.push(ReferencedSeries);
|
|
5448
|
+
}
|
|
5449
|
+
return ReferencedSeriesSequence;
|
|
5450
|
+
}
|
|
5451
|
+
|
|
5452
|
+
function getRTROIObservationsSequence(toolData, index) {
|
|
5453
|
+
return {
|
|
5454
|
+
ObservationNumber: index + 1,
|
|
5455
|
+
ReferencedROINumber: index + 1,
|
|
5456
|
+
RTROIInterpretedType: "Todo: type",
|
|
5457
|
+
ROIInterpreter: "Todo: interpreter"
|
|
5458
|
+
};
|
|
5459
|
+
}
|
|
5460
|
+
|
|
5461
|
+
function getRTSeriesModule(DicomMetaDictionary) {
|
|
5462
|
+
return {
|
|
5463
|
+
SeriesInstanceUID: DicomMetaDictionary.uid(),
|
|
5464
|
+
// generate a new series instance uid
|
|
5465
|
+
SeriesNumber: "99" // Todo:: what should be the series number?
|
|
5466
|
+
};
|
|
5467
|
+
}
|
|
5468
|
+
|
|
5469
|
+
function getStructureSetModule(contour, index) {
|
|
5470
|
+
var FrameOfReferenceUID = contour.metadata.FrameOfReferenceUID;
|
|
5471
|
+
return {
|
|
5472
|
+
ROINumber: index + 1,
|
|
5473
|
+
ROIName: contour.name || "Todo: name ".concat(index + 1),
|
|
5474
|
+
ROIDescription: "Todo: description ".concat(index + 1),
|
|
5475
|
+
ROIGenerationAlgorithm: "Todo: algorithm",
|
|
5476
|
+
ReferencedFrameOfReferenceUID: FrameOfReferenceUID
|
|
5477
|
+
};
|
|
5478
|
+
}
|
|
5479
|
+
|
|
5480
|
+
var DicomMetaDictionary = dcmjs.data.DicomMetaDictionary;
|
|
5481
|
+
/**
|
|
5482
|
+
* Convert handles to RTSS report containing the dcmjs dicom dataset.
|
|
5483
|
+
*
|
|
5484
|
+
* Note: current WIP and using segmentation to contour conversion,
|
|
5485
|
+
* routine that is not fully tested
|
|
5486
|
+
*
|
|
5487
|
+
* @param segmentations - Cornerstone tool segmentations data
|
|
5488
|
+
* @param metadataProvider - Metadata provider
|
|
5489
|
+
* @param DicomMetadataStore - metadata store instance
|
|
5490
|
+
* @param cs - cornerstone instance
|
|
5491
|
+
* @param csTools - cornerstone tool instance
|
|
5492
|
+
* @returns Report object containing the dataset
|
|
5493
|
+
*/
|
|
5494
|
+
function generateRTSSFromSegmentations(segmentations, metadataProvider, DicomMetadataStore, cornerstoneCache, cornerstoneToolsEnums, vtkUtils) {
|
|
5495
|
+
// Convert segmentations to ROIContours
|
|
5496
|
+
var roiContours = [];
|
|
5497
|
+
var contourSets = generateContourSetsFromLabelmap({
|
|
5498
|
+
segmentations: segmentations,
|
|
5499
|
+
cornerstoneCache: cornerstoneCache,
|
|
5500
|
+
cornerstoneToolsEnums: cornerstoneToolsEnums,
|
|
5501
|
+
vtkUtils: vtkUtils
|
|
5502
|
+
});
|
|
5503
|
+
contourSets.forEach(function (contourSet, segIndex) {
|
|
5504
|
+
// Check contour set isn't undefined
|
|
5505
|
+
if (contourSet) {
|
|
5506
|
+
var contourSequence_1 = [];
|
|
5507
|
+
contourSet.sliceContours.forEach(function (sliceContour) {
|
|
5508
|
+
/**
|
|
5509
|
+
* addContour - Adds a new ROI with related contours to ROIContourSequence
|
|
5510
|
+
*
|
|
5511
|
+
* @param newContour - cornerstoneTools `ROIContour` object
|
|
5512
|
+
*
|
|
5513
|
+
* newContour = {
|
|
5514
|
+
* name: string,
|
|
5515
|
+
* description: string,
|
|
5516
|
+
* contourSequence: array[contour]
|
|
5517
|
+
* color: array[number],
|
|
5518
|
+
* metadata: {
|
|
5519
|
+
* referencedImageId: string,
|
|
5520
|
+
* FrameOfReferenceUID: string
|
|
5521
|
+
* }
|
|
5522
|
+
* }
|
|
5523
|
+
*
|
|
5524
|
+
* contour = {
|
|
5525
|
+
* ContourImageSequence: array[
|
|
5526
|
+
* { ReferencedSOPClassUID: string, ReferencedSOPInstanceUID: string}
|
|
5527
|
+
* ]
|
|
5528
|
+
* ContourGeometricType: string,
|
|
5529
|
+
* NumberOfContourPoints: number,
|
|
5530
|
+
* ContourData: array[number]
|
|
5531
|
+
* }
|
|
5532
|
+
*/
|
|
5533
|
+
// Note: change needed if support non-planar contour representation is needed
|
|
5534
|
+
var sopCommon = metadataProvider.get("sopCommonModule", sliceContour.referencedImageId);
|
|
5535
|
+
var ReferencedSOPClassUID = sopCommon.sopClassUID;
|
|
5536
|
+
var ReferencedSOPInstanceUID = sopCommon.sopInstanceUID;
|
|
5537
|
+
var ContourImageSequence = [
|
|
5538
|
+
{ ReferencedSOPClassUID: ReferencedSOPClassUID, ReferencedSOPInstanceUID: ReferencedSOPInstanceUID } // NOTE: replace in dcmjs?
|
|
5539
|
+
];
|
|
5540
|
+
var sliceContourPolyData = sliceContour.polyData;
|
|
5541
|
+
sliceContour.contours.forEach(function (contour, index) {
|
|
5542
|
+
var ContourGeometricType = contour.type;
|
|
5543
|
+
var NumberOfContourPoints = contour.contourPoints.length;
|
|
5544
|
+
var ContourData = [];
|
|
5545
|
+
contour.contourPoints.forEach(function (point) {
|
|
5546
|
+
var pointData = sliceContourPolyData.points[point];
|
|
5547
|
+
pointData[0] = +pointData[0].toFixed(2);
|
|
5548
|
+
pointData[1] = +pointData[1].toFixed(2);
|
|
5549
|
+
pointData[2] = +pointData[2].toFixed(2);
|
|
5550
|
+
ContourData.push(pointData[0]);
|
|
5551
|
+
ContourData.push(pointData[1]);
|
|
5552
|
+
ContourData.push(pointData[2]);
|
|
5553
|
+
});
|
|
5554
|
+
contourSequence_1.push({
|
|
5555
|
+
ContourImageSequence: ContourImageSequence,
|
|
5556
|
+
ContourGeometricType: ContourGeometricType,
|
|
5557
|
+
NumberOfContourPoints: NumberOfContourPoints,
|
|
5558
|
+
ContourNumber: index + 1,
|
|
5559
|
+
ContourData: ContourData
|
|
5560
|
+
});
|
|
5561
|
+
});
|
|
5562
|
+
});
|
|
5563
|
+
var segLabel = contourSet.label || "Segment ".concat(segIndex + 1);
|
|
5564
|
+
var ROIContour = {
|
|
5565
|
+
name: segLabel,
|
|
5566
|
+
description: segLabel,
|
|
5567
|
+
contourSequence: contourSequence_1,
|
|
5568
|
+
color: contourSet.color,
|
|
5569
|
+
metadata: contourSet.metadata
|
|
5570
|
+
};
|
|
5571
|
+
roiContours.push(ROIContour);
|
|
5572
|
+
}
|
|
5573
|
+
});
|
|
5574
|
+
var rtMetadata = {
|
|
5575
|
+
name: segmentations.label,
|
|
5576
|
+
label: segmentations.label
|
|
5577
|
+
};
|
|
5578
|
+
var dataset = _initializeDataset(rtMetadata, roiContours[0].metadata, metadataProvider);
|
|
5579
|
+
roiContours.forEach(function (contour, index) {
|
|
5580
|
+
var roiContour = {
|
|
5581
|
+
ROIDisplayColor: contour.color || [255, 0, 0],
|
|
5582
|
+
ContourSequence: contour.contourSequence,
|
|
5583
|
+
ReferencedROINumber: index + 1
|
|
5584
|
+
};
|
|
5585
|
+
dataset.StructureSetROISequence.push(getStructureSetModule(contour, index));
|
|
5586
|
+
dataset.ROIContourSequence.push(roiContour);
|
|
5587
|
+
// ReferencedSeriesSequence
|
|
5588
|
+
dataset.ReferencedSeriesSequence = getReferencedSeriesSequence(contour.metadata, index, metadataProvider, DicomMetadataStore);
|
|
5589
|
+
// ReferencedFrameOfReferenceSequence
|
|
5590
|
+
dataset.ReferencedFrameOfReferenceSequence =
|
|
5591
|
+
getReferencedFrameOfReferenceSequence(contour.metadata, metadataProvider, dataset);
|
|
5592
|
+
});
|
|
5593
|
+
var fileMetaInformationVersionArray = new Uint8Array(2);
|
|
5594
|
+
fileMetaInformationVersionArray[1] = 1;
|
|
5595
|
+
var _meta = {
|
|
5596
|
+
FileMetaInformationVersion: {
|
|
5597
|
+
Value: [fileMetaInformationVersionArray.buffer],
|
|
5598
|
+
vr: "OB"
|
|
5599
|
+
},
|
|
5600
|
+
TransferSyntaxUID: {
|
|
5601
|
+
Value: ["1.2.840.10008.1.2.1"],
|
|
5602
|
+
vr: "UI"
|
|
5603
|
+
},
|
|
5604
|
+
ImplementationClassUID: {
|
|
5605
|
+
Value: [DicomMetaDictionary.uid()],
|
|
5606
|
+
vr: "UI"
|
|
5607
|
+
},
|
|
5608
|
+
ImplementationVersionName: {
|
|
5609
|
+
Value: ["dcmjs"],
|
|
5610
|
+
vr: "SH"
|
|
5611
|
+
}
|
|
5612
|
+
};
|
|
5613
|
+
dataset._meta = _meta;
|
|
5614
|
+
return dataset;
|
|
5615
|
+
}
|
|
5616
|
+
/**
|
|
5617
|
+
* Convert handles to RTSSReport report object containing the dcmjs dicom dataset.
|
|
5618
|
+
*
|
|
5619
|
+
* Note: The tool data needs to be formatted in a specific way, and currently
|
|
5620
|
+
* it is limited to the RectangleROIStartEndTool in the Cornerstone.
|
|
5621
|
+
*
|
|
5622
|
+
* @param annotations Array of Cornerstone tool annotation data
|
|
5623
|
+
* @param metadataProvider Metadata provider
|
|
5624
|
+
* @param options report generation options
|
|
5625
|
+
* @returns Report object containing the dataset
|
|
5626
|
+
*/
|
|
5627
|
+
function generateRTSSFromAnnotations(annotations, metadataProvider, DicomMetadataStore, options) {
|
|
5628
|
+
var rtMetadata = {
|
|
5629
|
+
name: "RTSS from Annotations",
|
|
5630
|
+
label: "RTSS from Annotations"
|
|
5631
|
+
};
|
|
5632
|
+
var dataset = _initializeDataset(rtMetadata, annotations[0].metadata, metadataProvider);
|
|
5633
|
+
annotations.forEach(function (annotation, index) {
|
|
5634
|
+
var ContourSequence = AnnotationToPointData.convert(annotation, index, metadataProvider, options);
|
|
5635
|
+
dataset.StructureSetROISequence.push(getStructureSetModule(annotation, index));
|
|
5636
|
+
dataset.ROIContourSequence.push(ContourSequence);
|
|
5637
|
+
dataset.RTROIObservationsSequence.push(getRTROIObservationsSequence(annotation, index));
|
|
5638
|
+
// ReferencedSeriesSequence
|
|
5639
|
+
// Todo: handle more than one series
|
|
5640
|
+
dataset.ReferencedSeriesSequence = getReferencedSeriesSequence(annotation.metadata, index, metadataProvider, DicomMetadataStore);
|
|
5641
|
+
// ReferencedFrameOfReferenceSequence
|
|
5642
|
+
dataset.ReferencedFrameOfReferenceSequence =
|
|
5643
|
+
getReferencedFrameOfReferenceSequence(annotation.metadata, metadataProvider, dataset);
|
|
5644
|
+
});
|
|
5645
|
+
var fileMetaInformationVersionArray = new Uint8Array(2);
|
|
5646
|
+
fileMetaInformationVersionArray[1] = 1;
|
|
5647
|
+
var _meta = {
|
|
5648
|
+
FileMetaInformationVersion: {
|
|
5649
|
+
Value: [fileMetaInformationVersionArray.buffer],
|
|
5650
|
+
vr: "OB"
|
|
5651
|
+
},
|
|
5652
|
+
TransferSyntaxUID: {
|
|
5653
|
+
Value: ["1.2.840.10008.1.2.1"],
|
|
5654
|
+
vr: "UI"
|
|
5655
|
+
},
|
|
5656
|
+
ImplementationClassUID: {
|
|
5657
|
+
Value: [DicomMetaDictionary.uid()],
|
|
5658
|
+
vr: "UI"
|
|
5659
|
+
},
|
|
5660
|
+
ImplementationVersionName: {
|
|
5661
|
+
Value: ["dcmjs"],
|
|
5662
|
+
vr: "SH"
|
|
5663
|
+
}
|
|
5664
|
+
};
|
|
5665
|
+
dataset._meta = _meta;
|
|
5666
|
+
return dataset;
|
|
5667
|
+
}
|
|
5668
|
+
// /**
|
|
5669
|
+
// * Generate Cornerstone tool state from dataset
|
|
5670
|
+
// * @param {object} dataset dataset
|
|
5671
|
+
// * @param {object} hooks
|
|
5672
|
+
// * @param {function} hooks.getToolClass Function to map dataset to a tool class
|
|
5673
|
+
// * @returns
|
|
5674
|
+
// */
|
|
5675
|
+
// //static generateToolState(_dataset, _hooks = {}) {
|
|
5676
|
+
// function generateToolState() {
|
|
5677
|
+
// // Todo
|
|
5678
|
+
// console.warn("RTSS.generateToolState not implemented");
|
|
5679
|
+
// }
|
|
5680
|
+
function _initializeDataset(rtMetadata, imgMetadata, metadataProvider) {
|
|
5681
|
+
var rtSOPInstanceUID = DicomMetaDictionary.uid();
|
|
5682
|
+
// get the first annotation data
|
|
5683
|
+
var imageId = imgMetadata.referencedImageId, FrameOfReferenceUID = imgMetadata.FrameOfReferenceUID;
|
|
5684
|
+
var studyInstanceUID = metadataProvider.get("generalSeriesModule", imageId).studyInstanceUID;
|
|
5685
|
+
var patientModule = getPatientModule(imageId, metadataProvider);
|
|
5686
|
+
var rtSeriesModule = getRTSeriesModule(DicomMetaDictionary);
|
|
5687
|
+
return __assign(__assign(__assign({ StructureSetROISequence: [], ROIContourSequence: [], RTROIObservationsSequence: [], ReferencedSeriesSequence: [], ReferencedFrameOfReferenceSequence: [] }, patientModule), rtSeriesModule), { StudyInstanceUID: studyInstanceUID, SOPClassUID: "1.2.840.10008.5.1.4.1.1.481.3", SOPInstanceUID: rtSOPInstanceUID, Manufacturer: "dcmjs", Modality: "RTSTRUCT", FrameOfReferenceUID: FrameOfReferenceUID, PositionReferenceIndicator: "", StructureSetLabel: rtMetadata.label || "", StructureSetName: rtMetadata.name || "", ReferringPhysicianName: "", OperatorsName: "", StructureSetDate: DicomMetaDictionary.date(), StructureSetTime: DicomMetaDictionary.time() });
|
|
5688
|
+
}
|
|
5689
|
+
|
|
5690
|
+
var RTSS = /*#__PURE__*/Object.freeze({
|
|
5691
|
+
__proto__: null,
|
|
5692
|
+
generateContourSetsFromLabelmap: generateContourSetsFromLabelmap,
|
|
5693
|
+
generateRTSSFromAnnotations: generateRTSSFromAnnotations,
|
|
5694
|
+
generateRTSSFromSegmentations: generateRTSSFromSegmentations
|
|
5695
|
+
});
|
|
5696
|
+
|
|
4955
5697
|
var Cornerstone3DSR = {
|
|
4956
5698
|
Bidirectional: Bidirectional,
|
|
4957
5699
|
CobbAngle: CobbAngle,
|
|
@@ -4970,6 +5712,9 @@ var Cornerstone3DSR = {
|
|
|
4970
5712
|
var Cornerstone3DSEG = {
|
|
4971
5713
|
Segmentation: Segmentation$1
|
|
4972
5714
|
};
|
|
5715
|
+
var Cornerstone3DRT = {
|
|
5716
|
+
RTSS: RTSS
|
|
5717
|
+
};
|
|
4973
5718
|
|
|
4974
5719
|
var Colors = data.Colors,
|
|
4975
5720
|
BitArray = data.BitArray;
|
|
@@ -5163,10 +5908,13 @@ var adaptersSR = {
|
|
|
5163
5908
|
Cornerstone3D: Cornerstone3DSR
|
|
5164
5909
|
};
|
|
5165
5910
|
var adaptersSEG = {
|
|
5166
|
-
Cornerstone:
|
|
5911
|
+
Cornerstone: CornerstoneSEG,
|
|
5167
5912
|
Cornerstone3D: Cornerstone3DSEG,
|
|
5168
5913
|
VTKjs: VTKjsSEG
|
|
5169
5914
|
};
|
|
5915
|
+
var adaptersRT = {
|
|
5916
|
+
Cornerstone3D: Cornerstone3DRT
|
|
5917
|
+
};
|
|
5170
5918
|
|
|
5171
|
-
export { index as Enums, adaptersSEG, adaptersSR, index$1 as helpers };
|
|
5919
|
+
export { index as Enums, adaptersRT, adaptersSEG, adaptersSR, index$1 as helpers };
|
|
5172
5920
|
//# sourceMappingURL=adapters.es.js.map
|