@cornerstonejs/adapters 5.4.10 → 5.4.12
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/esm/adapters/Cornerstone/Segmentation_4X.d.ts +2 -2
- package/dist/esm/adapters/Cornerstone/Segmentation_4X.js +215 -69
- package/dist/esm/adapters/Cornerstone3D/Segmentation/generateSegmentation.d.ts +10 -1
- package/dist/esm/adapters/Cornerstone3D/Segmentation/generateSegmentation.js +286 -5
- package/dist/esm/adapters/Cornerstone3D/Segmentation/generateToolState.d.ts +20 -1
- package/dist/esm/adapters/Cornerstone3D/Segmentation/generateToolState.js +37 -7
- package/dist/esm/adapters/Cornerstone3D/Segmentation/index.d.ts +2 -2
- package/dist/esm/adapters/Cornerstone3D/Segmentation/index.js +2 -1
- package/dist/esm/adapters/Cornerstone3D/Segmentation/labelmapImagesFromBuffer.d.ts +45 -3
- package/dist/esm/adapters/Cornerstone3D/Segmentation/labelmapImagesFromBuffer.js +577 -145
- package/dist/esm/adapters/Cornerstone3D/Segmentation/perFrameFunctionalGroups.d.ts +17 -0
- package/dist/esm/adapters/Cornerstone3D/Segmentation/perFrameFunctionalGroups.js +116 -0
- package/dist/esm/adapters/Cornerstone3D/encodePixelData.d.ts +46 -0
- package/dist/esm/adapters/Cornerstone3D/encodePixelData.js +440 -0
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +7 -7
|
@@ -1,30 +1,362 @@
|
|
|
1
|
+
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
1
2
|
import { triggerEvent, eventTarget, imageLoader } from '@cornerstonejs/core';
|
|
2
|
-
import { utilities
|
|
3
|
-
import { data, normalizers
|
|
3
|
+
import { utilities } from '@cornerstonejs/tools';
|
|
4
|
+
import { data, normalizers } from 'dcmjs';
|
|
4
5
|
import ndarray from 'ndarray';
|
|
5
6
|
import checkOrientation from '../../helpers/checkOrientation.js';
|
|
6
|
-
import {
|
|
7
|
+
import { unpackBinaryFrameFromPacked, getSegNumberOfFramesFromDataset, createDecodeImageDataFromMultiframe } from '../encodePixelData.js';
|
|
8
|
+
import { getValidOrientations, getSegmentMetadata, calculateCentroid, readFromUnpackedChunks, alignPixelDataWithSourceData, getSegmentIndex, findReferenceSourceImageId, getImageIdOfSourceImageBySourceImageSequence } from '../../Cornerstone/Segmentation_4X.js';
|
|
7
9
|
import { compactMergeSegmentDataWithoutInformationLoss } from './compactMergeSegData.js';
|
|
10
|
+
import { normalizeSharedFunctionalGroupsSequence } from './perFrameFunctionalGroups.js';
|
|
8
11
|
import { Events } from '../../enums/Events.js';
|
|
9
12
|
|
|
13
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
10
15
|
const DicomMessage = data.DicomMessage,
|
|
11
16
|
DicomMetaDictionary = data.DicomMetaDictionary;
|
|
12
17
|
const Normalizer = normalizers.Normalizer;
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
const LABELMAP_SEG_SOP_CLASS_UID = '1.2.840.10008.5.1.4.1.1.66.7';
|
|
19
|
+
const BUFFER_SEG_IMAGE_ID = 'cornerstone-adapters-buffer-seg:0';
|
|
20
|
+
function stripFrameQualifiersFromImageId(imageId) {
|
|
21
|
+
if (!imageId) {
|
|
22
|
+
return imageId;
|
|
23
|
+
}
|
|
24
|
+
if (imageId.includes('/frames/')) {
|
|
25
|
+
return imageId.replace(/\/frames\/\d+.*$/, '');
|
|
26
|
+
}
|
|
27
|
+
return imageId.split('&frame=')[0].split('?frame=')[0];
|
|
28
|
+
}
|
|
29
|
+
function prepareSegMultiframeMetadata(multiframe) {
|
|
30
|
+
normalizeSharedFunctionalGroupsSequence(multiframe);
|
|
31
|
+
const perFrame = multiframe.PerFrameFunctionalGroupsSequence;
|
|
32
|
+
if (perFrame && !Array.isArray(perFrame)) {
|
|
33
|
+
multiframe.PerFrameFunctionalGroupsSequence = [perFrame];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function getFrameNumberFromImageId(imageId) {
|
|
37
|
+
const frameQueryMatch = imageId.match(/(?:&|\?)frame=(\d+)/);
|
|
38
|
+
if (frameQueryMatch) {
|
|
39
|
+
return Number(frameQueryMatch[1]);
|
|
40
|
+
}
|
|
41
|
+
const wadorsFrameMatch = imageId.match(/\/frames\/(\d+)/);
|
|
42
|
+
if (wadorsFrameMatch) {
|
|
43
|
+
return Number(wadorsFrameMatch[1]);
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
function isPseudoBinaryFractional(pixelData, maximumFractionalValue) {
|
|
48
|
+
const max = Number(maximumFractionalValue);
|
|
49
|
+
if (!Number.isFinite(max)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
for (let i = 0; i < pixelData.length; i++) {
|
|
53
|
+
const value = pixelData[i];
|
|
54
|
+
if (value !== 0 && value !== max) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
function isPseudoBinaryFractionalFromChunks(chunks, maximumFractionalValue) {
|
|
61
|
+
for (const chunk of chunks) {
|
|
62
|
+
if (!isPseudoBinaryFractional(chunk, maximumFractionalValue)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
function buildSopUIDImageIdIndexMap(referencedImageIds, metadataProvider) {
|
|
69
|
+
return referencedImageIds.reduce((acc, imageId) => {
|
|
70
|
+
var _metadataProvider$get;
|
|
71
|
+
const _ref = (_metadataProvider$get = metadataProvider.get('generalImageModule', imageId)) !== null && _metadataProvider$get !== void 0 ? _metadataProvider$get : {},
|
|
72
|
+
sopInstanceUID = _ref.sopInstanceUID;
|
|
73
|
+
if (!sopInstanceUID) {
|
|
74
|
+
return acc;
|
|
75
|
+
}
|
|
76
|
+
if (!acc[sopInstanceUID]) {
|
|
77
|
+
acc[sopInstanceUID] = imageId;
|
|
78
|
+
}
|
|
79
|
+
return acc;
|
|
80
|
+
}, {});
|
|
81
|
+
}
|
|
82
|
+
function resolveStackImageId(imageId, referencedImageIds, metadataProvider) {
|
|
83
|
+
if (!imageId) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
if (referencedImageIds.includes(imageId)) {
|
|
87
|
+
return imageId;
|
|
88
|
+
}
|
|
89
|
+
const strippedTarget = stripFrameQualifiersFromImageId(imageId);
|
|
90
|
+
const targetFrame = getFrameNumberFromImageId(imageId);
|
|
91
|
+
for (const refId of referencedImageIds) {
|
|
92
|
+
var _getFrameNumberFromIm;
|
|
93
|
+
if (stripFrameQualifiersFromImageId(refId) !== strippedTarget) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (targetFrame === undefined) {
|
|
97
|
+
return refId;
|
|
98
|
+
}
|
|
99
|
+
const refFrame = (_getFrameNumberFromIm = getFrameNumberFromImageId(refId)) !== null && _getFrameNumberFromIm !== void 0 ? _getFrameNumberFromIm : 1;
|
|
100
|
+
if (refFrame === targetFrame) {
|
|
101
|
+
return refId;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (metadataProvider !== null && metadataProvider !== void 0 && metadataProvider.get) {
|
|
105
|
+
const _ref2 = metadataProvider.get('generalImageModule', imageId) || {},
|
|
106
|
+
sopInstanceUID = _ref2.sopInstanceUID;
|
|
107
|
+
if (sopInstanceUID) {
|
|
108
|
+
for (const refId of referencedImageIds) {
|
|
109
|
+
var _metadataProvider$get2, _getFrameNumberFromIm2;
|
|
110
|
+
const refSop = (_metadataProvider$get2 = metadataProvider.get('generalImageModule', refId)) === null || _metadataProvider$get2 === void 0 ? void 0 : _metadataProvider$get2.sopInstanceUID;
|
|
111
|
+
if (refSop !== sopInstanceUID) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (targetFrame === undefined) {
|
|
115
|
+
return refId;
|
|
116
|
+
}
|
|
117
|
+
const refFrame = (_getFrameNumberFromIm2 = getFrameNumberFromImageId(refId)) !== null && _getFrameNumberFromIm2 !== void 0 ? _getFrameNumberFromIm2 : 1;
|
|
118
|
+
if (refFrame === targetFrame) {
|
|
119
|
+
return refId;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
function ensureImageIdMapsEntry(imageId, referencedImageIds, imageIdMaps, metadataProvider) {
|
|
127
|
+
const stackImageId = resolveStackImageId(imageId, referencedImageIds, metadataProvider);
|
|
128
|
+
if (!stackImageId) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
if (imageIdMaps.indices[stackImageId] === undefined) {
|
|
132
|
+
const index = referencedImageIds.indexOf(stackImageId);
|
|
133
|
+
if (index === -1) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
imageIdMaps.indices[stackImageId] = index;
|
|
137
|
+
imageIdMaps.metadata[stackImageId] = imageIdMaps.metadata[stackImageId] || metadataProvider.get('instance', stackImageId);
|
|
138
|
+
}
|
|
139
|
+
return stackImageId;
|
|
140
|
+
}
|
|
141
|
+
function chunkPixelData(pixelData) {
|
|
142
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
143
|
+
const _options$maxBytesPerC = options.maxBytesPerChunk,
|
|
144
|
+
maxBytesPerChunk = _options$maxBytesPerC === void 0 ? Number.POSITIVE_INFINITY : _options$maxBytesPerC;
|
|
145
|
+
if (pixelData.length <= maxBytesPerChunk) {
|
|
146
|
+
return [pixelData];
|
|
147
|
+
}
|
|
148
|
+
const chunks = [];
|
|
149
|
+
for (let offset = 0; offset < pixelData.length; offset += maxBytesPerChunk) {
|
|
150
|
+
chunks.push(pixelData.subarray(offset, offset + maxBytesPerChunk));
|
|
151
|
+
}
|
|
152
|
+
return chunks;
|
|
153
|
+
}
|
|
154
|
+
function normalizeDecodedPixelData(pixelData) {
|
|
155
|
+
if (Array.isArray(pixelData)) {
|
|
156
|
+
if (pixelData.length === 1) {
|
|
157
|
+
return normalizeDecodedPixelData(pixelData[0]);
|
|
158
|
+
}
|
|
159
|
+
const hasUint16Frame = pixelData.some(frame => frame instanceof Uint16Array);
|
|
160
|
+
if (hasUint16Frame) {
|
|
161
|
+
const normalizedFrames = pixelData.map(frame => frame instanceof Uint16Array ? frame : new Uint16Array(frame));
|
|
162
|
+
const totalLength = normalizedFrames.reduce((acc, frame) => acc + frame.length, 0);
|
|
163
|
+
const combined = new Uint16Array(totalLength);
|
|
164
|
+
let offset = 0;
|
|
165
|
+
for (const frame of normalizedFrames) {
|
|
166
|
+
combined.set(frame, offset);
|
|
167
|
+
offset += frame.length;
|
|
168
|
+
}
|
|
169
|
+
return combined;
|
|
170
|
+
}
|
|
171
|
+
const normalizedFrames = pixelData.map(frame => frame instanceof Uint8Array ? frame : new Uint8Array(frame));
|
|
172
|
+
const totalLength = normalizedFrames.reduce((acc, frame) => acc + frame.length, 0);
|
|
173
|
+
const combined = new Uint8Array(totalLength);
|
|
174
|
+
let offset = 0;
|
|
175
|
+
for (const frame of normalizedFrames) {
|
|
176
|
+
combined.set(frame, offset);
|
|
177
|
+
offset += frame.length;
|
|
178
|
+
}
|
|
179
|
+
return combined;
|
|
180
|
+
}
|
|
181
|
+
if (pixelData instanceof Uint8Array || pixelData instanceof Uint16Array) {
|
|
182
|
+
return pixelData;
|
|
183
|
+
}
|
|
184
|
+
return new Uint8Array(pixelData);
|
|
185
|
+
}
|
|
186
|
+
function getExpectedVoxelCount(multiframe) {
|
|
187
|
+
var _multiframe$PerFrameF;
|
|
188
|
+
const numberOfFrames = Number(multiframe.NumberOfFrames) || ((_multiframe$PerFrameF = multiframe.PerFrameFunctionalGroupsSequence) === null || _multiframe$PerFrameF === void 0 ? void 0 : _multiframe$PerFrameF.length) || 1;
|
|
189
|
+
return multiframe.Rows * multiframe.Columns * numberOfFrames;
|
|
190
|
+
}
|
|
191
|
+
const DEFAULT_SEG_FRAME_DECODE_CONCURRENCY = 16;
|
|
192
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
193
|
+
const results = new Array(items.length);
|
|
194
|
+
let nextIndex = 0;
|
|
195
|
+
const worker = async () => {
|
|
196
|
+
while (nextIndex < items.length) {
|
|
197
|
+
const index = nextIndex++;
|
|
198
|
+
results[index] = await fn(items[index], index);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const poolSize = Math.max(1, Math.min(limit, items.length));
|
|
202
|
+
await Promise.all(Array.from({
|
|
203
|
+
length: poolSize
|
|
204
|
+
}, worker));
|
|
205
|
+
return results;
|
|
206
|
+
}
|
|
207
|
+
function getSegNumberOfFrames(multiframe) {
|
|
208
|
+
const fromTag = Number(multiframe.NumberOfFrames);
|
|
209
|
+
if (fromTag > 0) {
|
|
210
|
+
return fromTag;
|
|
211
|
+
}
|
|
212
|
+
const perFrame = multiframe.PerFrameFunctionalGroupsSequence;
|
|
213
|
+
if (Array.isArray(perFrame) && perFrame.length > 0) {
|
|
214
|
+
return perFrame.length;
|
|
215
|
+
}
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
function expandWadorsFrameImageIds(segImageId, numberOfFrames) {
|
|
219
|
+
const frameMatch = segImageId.match(/(.*\/frames\/)(\d+)(.*)$/);
|
|
220
|
+
if (!frameMatch || numberOfFrames <= 1) {
|
|
221
|
+
return [segImageId];
|
|
222
|
+
}
|
|
223
|
+
const prefix = frameMatch[1];
|
|
224
|
+
const suffix = frameMatch[3] || '';
|
|
225
|
+
const frameImageIds = [];
|
|
226
|
+
for (let frameNumber = 1; frameNumber <= numberOfFrames; frameNumber++) {
|
|
227
|
+
frameImageIds.push("".concat(prefix).concat(frameNumber).concat(suffix));
|
|
228
|
+
}
|
|
229
|
+
return frameImageIds;
|
|
230
|
+
}
|
|
231
|
+
const WADO_URI_FRAME_SCHEME = /^(wadouri:|dicomfile:)/;
|
|
232
|
+
function expandWadoUriFrameImageIds(segImageId, numberOfFrames) {
|
|
233
|
+
if (numberOfFrames <= 1 || !WADO_URI_FRAME_SCHEME.test(segImageId)) {
|
|
234
|
+
return [segImageId];
|
|
235
|
+
}
|
|
236
|
+
const base = segImageId.split('&frame=')[0].split('?frame=')[0];
|
|
237
|
+
const separator = base.includes('?') ? '&' : '?';
|
|
238
|
+
const frameImageIds = [];
|
|
239
|
+
for (let frameNumber = 1; frameNumber <= numberOfFrames; frameNumber++) {
|
|
240
|
+
frameImageIds.push("".concat(base).concat(separator, "frame=").concat(frameNumber));
|
|
241
|
+
}
|
|
242
|
+
return frameImageIds;
|
|
243
|
+
}
|
|
244
|
+
function resolveFrameImageIds(_ref3) {
|
|
245
|
+
let segImageId = _ref3.segImageId,
|
|
246
|
+
numberOfFrames = _ref3.numberOfFrames,
|
|
247
|
+
frameImageIds = _ref3.frameImageIds,
|
|
248
|
+
getFrameImageId = _ref3.getFrameImageId;
|
|
249
|
+
if (frameImageIds !== null && frameImageIds !== void 0 && frameImageIds.length) {
|
|
250
|
+
return frameImageIds;
|
|
251
|
+
}
|
|
252
|
+
if (getFrameImageId) {
|
|
253
|
+
return Array.from({
|
|
254
|
+
length: numberOfFrames
|
|
255
|
+
}, (_, index) => getFrameImageId(segImageId, index + 1));
|
|
256
|
+
}
|
|
257
|
+
const wadorsFrameIds = expandWadorsFrameImageIds(segImageId, numberOfFrames);
|
|
258
|
+
if (wadorsFrameIds.length > 1) {
|
|
259
|
+
return wadorsFrameIds;
|
|
260
|
+
}
|
|
261
|
+
const wadoUriFrameIds = expandWadoUriFrameImageIds(segImageId, numberOfFrames);
|
|
262
|
+
if (wadoUriFrameIds.length > 1) {
|
|
263
|
+
return wadoUriFrameIds;
|
|
264
|
+
}
|
|
265
|
+
if (numberOfFrames > 1) {
|
|
266
|
+
throw new Error("Cannot derive per-frame imageIds for multiframe SEG \"".concat(segImageId, "\" ") + "(".concat(numberOfFrames, " frames): its imageId scheme is not WADO-RS ") + "(\".../frames/N\") or WADO-URI (\"?frame=N\"/\"&frame=N\"). Supply " + "options.frameImageIds or options.getFrameImageId for this data source.");
|
|
267
|
+
}
|
|
268
|
+
return [segImageId];
|
|
269
|
+
}
|
|
270
|
+
function unpackFramePixelDataIfNeeded(framePixelData, multiframe, sliceLength) {
|
|
271
|
+
const bitsStored = Number(multiframe.BitsStored);
|
|
272
|
+
if (bitsStored === 1 && framePixelData.length < sliceLength) {
|
|
273
|
+
const packed = framePixelData instanceof Uint8Array ? framePixelData : new Uint8Array(framePixelData);
|
|
274
|
+
return unpackBinaryFrameFromPacked(packed, sliceLength);
|
|
275
|
+
}
|
|
276
|
+
return framePixelData;
|
|
277
|
+
}
|
|
278
|
+
function ensureInstanceOnMetadataProvider(metadataProvider, segImageId, multiframe) {
|
|
279
|
+
if (metadataProvider.get('instance', segImageId)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (metadataProvider.addCustomMetadata) {
|
|
283
|
+
metadataProvider.addCustomMetadata(segImageId, 'instance', multiframe);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (metadataProvider.add) {
|
|
287
|
+
metadataProvider.add(segImageId, 'instance', multiframe);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async function defaultDecodeFrameImageData(frameImageId, _frameNumber) {
|
|
291
|
+
var _segImage$getPixelDat;
|
|
292
|
+
const segImage = await imageLoader.loadImage(frameImageId);
|
|
293
|
+
return segImage === null || segImage === void 0 || (_segImage$getPixelDat = segImage.getPixelData) === null || _segImage$getPixelDat === void 0 ? void 0 : _segImage$getPixelDat.call(segImage);
|
|
294
|
+
}
|
|
295
|
+
async function decodeSegPixelDataFromFrameIds(_ref4) {
|
|
296
|
+
let segImageId = _ref4.segImageId,
|
|
297
|
+
multiframe = _ref4.multiframe,
|
|
298
|
+
frameImageIds = _ref4.frameImageIds,
|
|
299
|
+
getFrameImageId = _ref4.getFrameImageId,
|
|
300
|
+
_ref4$decodeImageData = _ref4.decodeImageData,
|
|
301
|
+
decodeImageData = _ref4$decodeImageData === void 0 ? defaultDecodeFrameImageData : _ref4$decodeImageData,
|
|
302
|
+
_ref4$concurrency = _ref4.concurrency,
|
|
303
|
+
concurrency = _ref4$concurrency === void 0 ? DEFAULT_SEG_FRAME_DECODE_CONCURRENCY : _ref4$concurrency;
|
|
304
|
+
const rows = Number(multiframe.Rows);
|
|
305
|
+
const columns = Number(multiframe.Columns);
|
|
306
|
+
const sliceLength = rows * columns;
|
|
307
|
+
const numberOfFrames = getSegNumberOfFrames(multiframe);
|
|
308
|
+
const expectedVoxelCount = getExpectedVoxelCount(multiframe);
|
|
309
|
+
const resolvedFrameImageIds = resolveFrameImageIds({
|
|
310
|
+
segImageId,
|
|
311
|
+
numberOfFrames,
|
|
312
|
+
frameImageIds,
|
|
313
|
+
getFrameImageId
|
|
314
|
+
});
|
|
315
|
+
if (numberOfFrames <= 1) {
|
|
316
|
+
const frameImageId = resolvedFrameImageIds[0] || segImageId;
|
|
317
|
+
const framePixelData = await decodeImageData(frameImageId, 1);
|
|
318
|
+
if (!framePixelData) {
|
|
319
|
+
throw new Error("No decoded pixel data found for SEG imageId: ".concat(frameImageId));
|
|
320
|
+
}
|
|
321
|
+
const normalized = normalizeDecodedPixelData(framePixelData);
|
|
322
|
+
const decodedPixelData = unpackFramePixelDataIfNeeded(normalized, multiframe, sliceLength);
|
|
323
|
+
return {
|
|
324
|
+
pixelDataChunks: [decodedPixelData],
|
|
325
|
+
expectedVoxelCount
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
const perFramePixelData = await mapWithConcurrency(resolvedFrameImageIds.slice(0, numberOfFrames), concurrency, async (frameImageId, frameIndex) => {
|
|
329
|
+
const frameNumber = frameIndex + 1;
|
|
330
|
+
if (!frameImageId) {
|
|
331
|
+
throw new Error("Missing SEG frame imageId at frame ".concat(frameNumber, " (expected ").concat(numberOfFrames, " frame imageIds)"));
|
|
332
|
+
}
|
|
333
|
+
const framePixelData = await decodeImageData(frameImageId, frameNumber);
|
|
334
|
+
if (!framePixelData) {
|
|
335
|
+
throw new Error("No decoded pixel data found for SEG frame imageId: ".concat(frameImageId));
|
|
336
|
+
}
|
|
337
|
+
let normalizedFrame = normalizeDecodedPixelData(framePixelData);
|
|
338
|
+
normalizedFrame = unpackFramePixelDataIfNeeded(normalizedFrame, multiframe, sliceLength);
|
|
339
|
+
return normalizedFrame.subarray(0, sliceLength);
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
pixelDataChunks: perFramePixelData,
|
|
343
|
+
expectedVoxelCount
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const updateSegmentsOnFrame = _ref5 => {
|
|
347
|
+
let segmentsOnFrame = _ref5.segmentsOnFrame,
|
|
348
|
+
imageIdIndex = _ref5.imageIdIndex,
|
|
349
|
+
segmentIndex = _ref5.segmentIndex;
|
|
18
350
|
if (!segmentsOnFrame[imageIdIndex]) {
|
|
19
351
|
segmentsOnFrame[imageIdIndex] = [];
|
|
20
352
|
}
|
|
21
353
|
segmentsOnFrame[imageIdIndex].push(segmentIndex);
|
|
22
354
|
};
|
|
23
|
-
const updateSegmentsPixelIndices =
|
|
24
|
-
let segmentsPixelIndices =
|
|
25
|
-
segmentIndex =
|
|
26
|
-
imageIdIndex =
|
|
27
|
-
indexCache =
|
|
355
|
+
const updateSegmentsPixelIndices = _ref6 => {
|
|
356
|
+
let segmentsPixelIndices = _ref6.segmentsPixelIndices,
|
|
357
|
+
segmentIndex = _ref6.segmentIndex,
|
|
358
|
+
imageIdIndex = _ref6.imageIdIndex,
|
|
359
|
+
indexCache = _ref6.indexCache;
|
|
28
360
|
if (!segmentsPixelIndices.has(segmentIndex)) {
|
|
29
361
|
segmentsPixelIndices.set(segmentIndex, {});
|
|
30
362
|
}
|
|
@@ -32,13 +364,17 @@ const updateSegmentsPixelIndices = _ref2 => {
|
|
|
32
364
|
segmentIndexObject[imageIdIndex] = indexCache;
|
|
33
365
|
segmentsPixelIndices.set(segmentIndex, segmentIndexObject);
|
|
34
366
|
};
|
|
35
|
-
const extractInfoFromPerFrameFunctionalGroups =
|
|
36
|
-
let PerFrameFunctionalGroups =
|
|
37
|
-
sequenceIndex =
|
|
38
|
-
sopUIDImageIdIndexMap =
|
|
39
|
-
multiframe =
|
|
40
|
-
const
|
|
41
|
-
const
|
|
367
|
+
const extractInfoFromPerFrameFunctionalGroups = _ref7 => {
|
|
368
|
+
let PerFrameFunctionalGroups = _ref7.PerFrameFunctionalGroups,
|
|
369
|
+
sequenceIndex = _ref7.sequenceIndex,
|
|
370
|
+
sopUIDImageIdIndexMap = _ref7.sopUIDImageIdIndexMap,
|
|
371
|
+
multiframe = _ref7.multiframe;
|
|
372
|
+
const derivationImageSequence = PerFrameFunctionalGroups === null || PerFrameFunctionalGroups === void 0 ? void 0 : PerFrameFunctionalGroups.DerivationImageSequence;
|
|
373
|
+
const normalizedDerivationImageSequence = Array.isArray(derivationImageSequence) ? derivationImageSequence[0] : derivationImageSequence;
|
|
374
|
+
const sourceImageSequence = normalizedDerivationImageSequence === null || normalizedDerivationImageSequence === void 0 ? void 0 : normalizedDerivationImageSequence.SourceImageSequence;
|
|
375
|
+
const normalizedSourceImageSequence = Array.isArray(sourceImageSequence) ? sourceImageSequence[0] : sourceImageSequence;
|
|
376
|
+
const referencedSOPInstanceUid = normalizedSourceImageSequence === null || normalizedSourceImageSequence === void 0 ? void 0 : normalizedSourceImageSequence.ReferencedSOPInstanceUID;
|
|
377
|
+
const referencedImageId = referencedSOPInstanceUid && normalizedSourceImageSequence ? getImageIdOfSourceImageBySourceImageSequence(normalizedSourceImageSequence, sopUIDImageIdIndexMap) : undefined;
|
|
42
378
|
const segmentIndex = getSegmentIndex(multiframe, sequenceIndex);
|
|
43
379
|
return {
|
|
44
380
|
referencedSOPInstanceUid,
|
|
@@ -46,17 +382,46 @@ const extractInfoFromPerFrameFunctionalGroups = _ref3 => {
|
|
|
46
382
|
segmentIndex
|
|
47
383
|
};
|
|
48
384
|
};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
385
|
+
const getReferencedImageIdFromPerFrameGroup = _ref8 => {
|
|
386
|
+
let perFrameFunctionalGroup = _ref8.perFrameFunctionalGroup,
|
|
387
|
+
sopUIDImageIdIndexMap = _ref8.sopUIDImageIdIndexMap;
|
|
388
|
+
const derivationImageSequence = perFrameFunctionalGroup === null || perFrameFunctionalGroup === void 0 ? void 0 : perFrameFunctionalGroup.DerivationImageSequence;
|
|
389
|
+
const normalizedDerivationImageSequence = Array.isArray(derivationImageSequence) ? derivationImageSequence[0] : derivationImageSequence;
|
|
390
|
+
const sourceImageSequence = normalizedDerivationImageSequence === null || normalizedDerivationImageSequence === void 0 ? void 0 : normalizedDerivationImageSequence.SourceImageSequence;
|
|
391
|
+
const normalizedSourceImageSequence = Array.isArray(sourceImageSequence) ? sourceImageSequence[0] : sourceImageSequence;
|
|
392
|
+
const referencedSOPInstanceUID = normalizedSourceImageSequence === null || normalizedSourceImageSequence === void 0 ? void 0 : normalizedSourceImageSequence.ReferencedSOPInstanceUID;
|
|
393
|
+
if (!referencedSOPInstanceUID || !normalizedSourceImageSequence) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
return getImageIdOfSourceImageBySourceImageSequence(normalizedSourceImageSequence, sopUIDImageIdIndexMap);
|
|
397
|
+
};
|
|
398
|
+
async function createLabelmapsFromSegImageIds(referencedImageIds, segImageId, metadataProvider, options) {
|
|
399
|
+
const _ref9 = options !== null && options !== void 0 ? options : {},
|
|
400
|
+
_ref9$tolerance = _ref9.tolerance,
|
|
401
|
+
tolerance = _ref9$tolerance === void 0 ? 1e-3 : _ref9$tolerance,
|
|
402
|
+
_ref9$TypedArrayConst = _ref9.TypedArrayConstructor,
|
|
403
|
+
TypedArrayConstructor = _ref9$TypedArrayConst === void 0 ? Uint8Array : _ref9$TypedArrayConst,
|
|
404
|
+
maxBytesPerChunk = _ref9.maxBytesPerChunk,
|
|
405
|
+
_ref9$parserType = _ref9.parserType,
|
|
406
|
+
parserType = _ref9$parserType === void 0 ? 'bitmap' : _ref9$parserType,
|
|
407
|
+
frameImageIds = _ref9.frameImageIds,
|
|
408
|
+
getFrameImageId = _ref9.getFrameImageId,
|
|
409
|
+
_ref9$decodeImageData = _ref9.decodeImageData,
|
|
410
|
+
decodeImageData = _ref9$decodeImageData === void 0 ? defaultDecodeFrameImageData : _ref9$decodeImageData,
|
|
411
|
+
_ref9$concurrency = _ref9.concurrency,
|
|
412
|
+
concurrency = _ref9$concurrency === void 0 ? DEFAULT_SEG_FRAME_DECODE_CONCURRENCY : _ref9$concurrency,
|
|
413
|
+
_ref9$multiframe = _ref9.multiframe,
|
|
414
|
+
providedMultiframe = _ref9$multiframe === void 0 ? undefined : _ref9$multiframe;
|
|
415
|
+
let multiframe = providedMultiframe;
|
|
416
|
+
if (!multiframe) {
|
|
417
|
+
var _instanceMeta$dataset;
|
|
418
|
+
const instanceMeta = metadataProvider.get('instance', segImageId);
|
|
419
|
+
if (!instanceMeta) {
|
|
420
|
+
throw new Error("No instance metadata found for SEG imageId: ".concat(segImageId, ". Ensure the SEG instance is registered in the metadata provider (e.g. after loading the image)."));
|
|
421
|
+
}
|
|
422
|
+
multiframe = (_instanceMeta$dataset = instanceMeta.dataset) !== null && _instanceMeta$dataset !== void 0 ? _instanceMeta$dataset : instanceMeta;
|
|
423
|
+
}
|
|
424
|
+
prepareSegMultiframeMetadata(multiframe);
|
|
60
425
|
const imagePlaneModule = metadataProvider.get('imagePlaneModule', referencedImageIds[0]);
|
|
61
426
|
const generalSeriesModule = metadataProvider.get('generalSeriesModule', referencedImageIds[0]);
|
|
62
427
|
const SeriesInstanceUID = generalSeriesModule.seriesInstanceUID;
|
|
@@ -66,32 +431,38 @@ async function createLabelmapsFromBufferInternal(referencedImageIds, arrayBuffer
|
|
|
66
431
|
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];
|
|
67
432
|
const validOrientations = getValidOrientations(ImageOrientationPatient);
|
|
68
433
|
const segMetadata = getSegmentMetadata(multiframe, SeriesInstanceUID);
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
434
|
+
const _await$decodeSegPixel = await decodeSegPixelDataFromFrameIds({
|
|
435
|
+
segImageId,
|
|
436
|
+
multiframe,
|
|
437
|
+
frameImageIds,
|
|
438
|
+
getFrameImageId,
|
|
439
|
+
decodeImageData,
|
|
440
|
+
concurrency
|
|
441
|
+
}),
|
|
442
|
+
pixelDataChunks = _await$decodeSegPixel.pixelDataChunks,
|
|
443
|
+
expectedVoxelCount = _await$decodeSegPixel.expectedVoxelCount;
|
|
444
|
+
const sliceLength = multiframe.Rows * multiframe.Columns;
|
|
445
|
+
let resolvedPixelDataChunks = pixelDataChunks;
|
|
446
|
+
if (Number(multiframe.BitsStored) === 1 && pixelDataChunks.length === 1 && pixelDataChunks[0].length < expectedVoxelCount) {
|
|
447
|
+
const packed = pixelDataChunks[0];
|
|
448
|
+
const unpacked = unpackBinaryFrameFromPacked(packed instanceof Uint8Array ? packed : new Uint8Array(packed), sliceLength);
|
|
449
|
+
resolvedPixelDataChunks = chunkPixelData(unpacked, {
|
|
82
450
|
maxBytesPerChunk
|
|
83
451
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
452
|
+
}
|
|
453
|
+
const totalSamples = resolvedPixelDataChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
454
|
+
const decodedFrameCount = Math.max(1, Math.floor(totalSamples / sliceLength));
|
|
455
|
+
if (multiframe.SegmentationType === 'FRACTIONAL' && !isPseudoBinaryFractionalFromChunks(resolvedPixelDataChunks, multiframe.MaximumFractionalValue)) {
|
|
456
|
+
throw new Error('Fractional segmentations are not yet supported');
|
|
457
|
+
}
|
|
458
|
+
let finalPixelDataChunks = resolvedPixelDataChunks;
|
|
459
|
+
if (maxBytesPerChunk && maxBytesPerChunk < Number.POSITIVE_INFINITY) {
|
|
460
|
+
finalPixelDataChunks = resolvedPixelDataChunks.flatMap(chunk => chunkPixelData(chunk, {
|
|
461
|
+
maxBytesPerChunk
|
|
462
|
+
}));
|
|
87
463
|
}
|
|
88
464
|
const orientation = checkOrientation(multiframe, validOrientations, [imagePlaneModule.rows, imagePlaneModule.columns, referencedImageIds.length], tolerance);
|
|
89
|
-
const sopUIDImageIdIndexMap = referencedImageIds
|
|
90
|
-
const _metadataProvider$get = metadataProvider.get('generalImageModule', imageId),
|
|
91
|
-
sopInstanceUID = _metadataProvider$get.sopInstanceUID;
|
|
92
|
-
acc[sopInstanceUID] = imageId;
|
|
93
|
-
return acc;
|
|
94
|
-
}, {});
|
|
465
|
+
const sopUIDImageIdIndexMap = buildSopUIDImageIdIndexMap(referencedImageIds, metadataProvider);
|
|
95
466
|
let insertFunction;
|
|
96
467
|
switch (orientation) {
|
|
97
468
|
case 'Planar':
|
|
@@ -119,7 +490,7 @@ async function createLabelmapsFromBufferInternal(referencedImageIds, arrayBuffer
|
|
|
119
490
|
const _await$insertFunction = await insertFunction({
|
|
120
491
|
segmentsOnFrame,
|
|
121
492
|
labelMapImages,
|
|
122
|
-
pixelDataChunks,
|
|
493
|
+
pixelDataChunks: finalPixelDataChunks,
|
|
123
494
|
multiframe,
|
|
124
495
|
referencedImageIds,
|
|
125
496
|
validOrientations,
|
|
@@ -128,7 +499,9 @@ async function createLabelmapsFromBufferInternal(referencedImageIds, arrayBuffer
|
|
|
128
499
|
segmentsPixelIndices,
|
|
129
500
|
sopUIDImageIdIndexMap,
|
|
130
501
|
imageIdMaps,
|
|
131
|
-
TypedArrayConstructor
|
|
502
|
+
TypedArrayConstructor,
|
|
503
|
+
parserType,
|
|
504
|
+
decodedFrameCount
|
|
132
505
|
}),
|
|
133
506
|
hasOverlappingSegments = _await$insertFunction.hasOverlappingSegments,
|
|
134
507
|
arrayOfLabelMapImages = _await$insertFunction.arrayOfLabelMapImages;
|
|
@@ -145,38 +518,46 @@ async function createLabelmapsFromBufferInternal(referencedImageIds, arrayBuffer
|
|
|
145
518
|
overlappingSegments: hasOverlappingSegments
|
|
146
519
|
};
|
|
147
520
|
}
|
|
148
|
-
const throttledTriggerLoadProgressEvent = utilities
|
|
521
|
+
const throttledTriggerLoadProgressEvent = utilities.throttle(percentComplete => {
|
|
149
522
|
triggerEvent(eventTarget, Events.SEGMENTATION_LOAD_PROGRESS, {
|
|
150
523
|
percentComplete
|
|
151
524
|
});
|
|
152
525
|
}, 200);
|
|
153
|
-
function insertPixelDataPlanar(
|
|
154
|
-
let segmentsOnFrame =
|
|
155
|
-
labelMapImages =
|
|
156
|
-
pixelDataChunks =
|
|
157
|
-
multiframe =
|
|
158
|
-
referencedImageIds =
|
|
159
|
-
validOrientations =
|
|
160
|
-
metadataProvider =
|
|
161
|
-
tolerance =
|
|
162
|
-
segmentsPixelIndices =
|
|
163
|
-
sopUIDImageIdIndexMap =
|
|
164
|
-
imageIdMaps =
|
|
526
|
+
function insertPixelDataPlanar(_ref0) {
|
|
527
|
+
let segmentsOnFrame = _ref0.segmentsOnFrame,
|
|
528
|
+
labelMapImages = _ref0.labelMapImages,
|
|
529
|
+
pixelDataChunks = _ref0.pixelDataChunks,
|
|
530
|
+
multiframe = _ref0.multiframe,
|
|
531
|
+
referencedImageIds = _ref0.referencedImageIds,
|
|
532
|
+
validOrientations = _ref0.validOrientations,
|
|
533
|
+
metadataProvider = _ref0.metadataProvider,
|
|
534
|
+
tolerance = _ref0.tolerance,
|
|
535
|
+
segmentsPixelIndices = _ref0.segmentsPixelIndices,
|
|
536
|
+
sopUIDImageIdIndexMap = _ref0.sopUIDImageIdIndexMap,
|
|
537
|
+
imageIdMaps = _ref0.imageIdMaps,
|
|
538
|
+
parserType = _ref0.parserType,
|
|
539
|
+
decodedFrameCount = _ref0.decodedFrameCount;
|
|
165
540
|
const SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
|
|
166
541
|
PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
|
|
167
542
|
Rows = multiframe.Rows,
|
|
168
543
|
Columns = multiframe.Columns;
|
|
169
544
|
const sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence ? SharedFunctionalGroupsSequence.PlaneOrientationSequence.ImageOrientationPatient : undefined;
|
|
170
545
|
const sliceLength = Columns * Rows;
|
|
171
|
-
const
|
|
546
|
+
const metadataFrameCount = Number(multiframe.NumberOfFrames) || PerFrameFunctionalGroupsSequence.length;
|
|
547
|
+
const groupsLenFromMetadata = PerFrameFunctionalGroupsSequence.length || metadataFrameCount;
|
|
548
|
+
const groupsLen = typeof decodedFrameCount === 'number' ? Math.min(groupsLenFromMetadata, decodedFrameCount) : groupsLenFromMetadata;
|
|
172
549
|
let overlapping = false;
|
|
173
550
|
return new Promise(resolve => {
|
|
174
551
|
const percentImagesPerChunk = 0.1;
|
|
175
552
|
const imagesPerChunk = Math.ceil(groupsLen * percentImagesPerChunk);
|
|
176
553
|
const processChunk = firstIndex => {
|
|
177
554
|
for (let i = firstIndex; i < firstIndex + imagesPerChunk && i < groupsLen; i++) {
|
|
555
|
+
var _PerFrameFunctionalGr;
|
|
178
556
|
const PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[i];
|
|
179
|
-
const ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
|
|
557
|
+
const ImageOrientationPatientI = sharedImageOrientationPatient || (PerFrameFunctionalGroups === null || PerFrameFunctionalGroups === void 0 || (_PerFrameFunctionalGr = PerFrameFunctionalGroups.PlaneOrientationSequence) === null || _PerFrameFunctionalGr === void 0 ? void 0 : _PerFrameFunctionalGr.ImageOrientationPatient);
|
|
558
|
+
if (!ImageOrientationPatientI) {
|
|
559
|
+
throw new Error("SEG frame ".concat(i + 1, " is missing ImageOrientationPatient in per-frame and shared functional groups."));
|
|
560
|
+
}
|
|
180
561
|
const view = readFromUnpackedChunks(pixelDataChunks, i * sliceLength, sliceLength);
|
|
181
562
|
const pixelDataI2D = ndarray(view, [Rows, Columns]);
|
|
182
563
|
const alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
@@ -190,16 +571,25 @@ function insertPixelDataPlanar(_ref4) {
|
|
|
190
571
|
if (!segmentsPixelIndices.has(segmentIndex)) {
|
|
191
572
|
segmentsPixelIndices.set(segmentIndex, {});
|
|
192
573
|
}
|
|
193
|
-
|
|
574
|
+
let imageId = findReferenceSourceImageId(multiframe, i, referencedImageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
194
575
|
if (!imageId) {
|
|
195
576
|
console.warn("Image not present in stack, can't import frame : " + i + '.');
|
|
196
|
-
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
const stackImageId = ensureImageIdMapsEntry(imageId, referencedImageIds, imageIdMaps, metadataProvider);
|
|
580
|
+
if (!stackImageId) {
|
|
581
|
+
console.warn("Image not present in stack, can't import frame : ".concat(i, "."));
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
const sourceImageMetadata = imageIdMaps.metadata[stackImageId];
|
|
585
|
+
if (!sourceImageMetadata) {
|
|
586
|
+
console.warn("No instance metadata for referenced image at frame : ".concat(i, "."));
|
|
587
|
+
continue;
|
|
197
588
|
}
|
|
198
|
-
const sourceImageMetadata = imageIdMaps.metadata[imageId];
|
|
199
589
|
if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
|
|
200
590
|
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. ');
|
|
201
591
|
}
|
|
202
|
-
const imageIdIndex = imageIdMaps.indices[
|
|
592
|
+
const imageIdIndex = imageIdMaps.indices[stackImageId];
|
|
203
593
|
const labelmapImage = labelMapImages[imageIdIndex];
|
|
204
594
|
const labelmap2DView = labelmapImage.getPixelData();
|
|
205
595
|
const imageVoxelManager = labelmapImage.voxelManager;
|
|
@@ -260,26 +650,43 @@ function insertPixelDataPlanar(_ref4) {
|
|
|
260
650
|
const pfSeq = multiframe.PerFrameFunctionalGroupsSequence;
|
|
261
651
|
const sharedPlaneOrientation = (_multiframe$SharedFun = multiframe.SharedFunctionalGroupsSequence.PlaneOrientationSequence) === null || _multiframe$SharedFun === void 0 ? void 0 : _multiframe$SharedFun.ImageOrientationPatient;
|
|
262
652
|
for (let i = firstIndex; i < firstIndex + imagesPerChunk && i < groupsLen; i++) {
|
|
653
|
+
var _PerFrameFunctionalGr2;
|
|
263
654
|
const PerFrameFunctionalGroups = pfSeq[i];
|
|
264
|
-
const ImageOrientationPatientI = sharedPlaneOrientation || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
|
|
265
|
-
const view = pixelDataChunks
|
|
655
|
+
const ImageOrientationPatientI = sharedPlaneOrientation || (PerFrameFunctionalGroups === null || PerFrameFunctionalGroups === void 0 || (_PerFrameFunctionalGr2 = PerFrameFunctionalGroups.PlaneOrientationSequence) === null || _PerFrameFunctionalGr2 === void 0 ? void 0 : _PerFrameFunctionalGr2.ImageOrientationPatient) || validOrientations[0];
|
|
656
|
+
const view = readFromUnpackedChunks(pixelDataChunks, i * sliceLength, sliceLength);
|
|
266
657
|
const pixelDataI2D = ndarray(view, [Rows, Columns]);
|
|
267
658
|
const alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
268
659
|
if (!alignedPixelDataI) {
|
|
269
660
|
throw new Error('Individual Labelmap SEG frames are out of plane with respect to the first SEG frame. ' + 'This is not yet supported. Aborting segmentation loading.');
|
|
270
661
|
}
|
|
271
|
-
|
|
662
|
+
let imageId = findReferenceSourceImageId(multiframe, i, referencedImageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
272
663
|
if (!imageId) {
|
|
664
|
+
imageId = getReferencedImageIdFromPerFrameGroup({
|
|
665
|
+
perFrameFunctionalGroup: PerFrameFunctionalGroups,
|
|
666
|
+
sopUIDImageIdIndexMap
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
if (!imageId) {
|
|
670
|
+
console.warn("Image not present in stack, can't import frame : ".concat(i, "."));
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
const stackImageId = ensureImageIdMapsEntry(imageId, referencedImageIds, imageIdMaps, metadataProvider);
|
|
674
|
+
if (!stackImageId) {
|
|
273
675
|
console.warn("Image not present in stack, can't import frame : ".concat(i, "."));
|
|
274
676
|
continue;
|
|
275
677
|
}
|
|
276
|
-
const sourceImageMetadata = imageIdMaps.metadata[
|
|
678
|
+
const sourceImageMetadata = imageIdMaps.metadata[stackImageId];
|
|
679
|
+
if (!sourceImageMetadata) {
|
|
680
|
+
console.warn("No instance metadata for referenced image at frame : ".concat(i, "."));
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
277
683
|
if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
|
|
278
684
|
throw new Error('Individual Labelmap SEG frames have different geometry dimensions (Rows and Columns) ' + 'respect to the source image reference frame. This is not yet supported. ' + 'Aborting segmentation loading. ');
|
|
279
685
|
}
|
|
280
|
-
const imageIdIndex = imageIdMaps.indices[
|
|
686
|
+
const imageIdIndex = imageIdMaps.indices[stackImageId];
|
|
281
687
|
const labelmapImage = labelMapImages[imageIdIndex];
|
|
282
688
|
const labelmap2DView = labelmapImage.getPixelData();
|
|
689
|
+
const imageVoxelManager = labelmapImage.voxelManager;
|
|
283
690
|
const data = alignedPixelDataI.data;
|
|
284
691
|
let segmentsOnFrameArr = segmentsOnFrame[imageIdIndex];
|
|
285
692
|
if (!segmentsOnFrameArr) {
|
|
@@ -290,7 +697,11 @@ function insertPixelDataPlanar(_ref4) {
|
|
|
290
697
|
for (let k = 0, len = data.length; k < len; ++k) {
|
|
291
698
|
const segIdx = data[k];
|
|
292
699
|
if (segIdx !== 0) {
|
|
293
|
-
|
|
700
|
+
if (imageVoxelManager) {
|
|
701
|
+
imageVoxelManager.setAtIndex(k, segIdx);
|
|
702
|
+
} else {
|
|
703
|
+
labelmap2DView[k] = segIdx;
|
|
704
|
+
}
|
|
294
705
|
if (!segSet.has(segIdx)) {
|
|
295
706
|
segmentsOnFrameArr.push(segIdx);
|
|
296
707
|
segSet.add(segIdx);
|
|
@@ -317,23 +728,24 @@ function insertPixelDataPlanar(_ref4) {
|
|
|
317
728
|
});
|
|
318
729
|
}
|
|
319
730
|
};
|
|
320
|
-
|
|
731
|
+
const isLabelmapSegmentation = parserType === 'labelmap' || multiframe.SOPClassUID === LABELMAP_SEG_SOP_CLASS_UID || multiframe.SegmentationType === 'LABELMAP';
|
|
732
|
+
if (isLabelmapSegmentation) {
|
|
321
733
|
processLabelmapChunk(0);
|
|
322
734
|
} else {
|
|
323
735
|
processChunk(0);
|
|
324
736
|
}
|
|
325
737
|
});
|
|
326
738
|
}
|
|
327
|
-
const getAlignedPixelData =
|
|
328
|
-
let sharedImageOrientationPatient =
|
|
329
|
-
PerFrameFunctionalGroups =
|
|
330
|
-
pixelDataChunks =
|
|
331
|
-
sequenceIndex =
|
|
332
|
-
sliceLength =
|
|
333
|
-
Rows =
|
|
334
|
-
Columns =
|
|
335
|
-
validOrientations =
|
|
336
|
-
tolerance =
|
|
739
|
+
const getAlignedPixelData = _ref1 => {
|
|
740
|
+
let sharedImageOrientationPatient = _ref1.sharedImageOrientationPatient,
|
|
741
|
+
PerFrameFunctionalGroups = _ref1.PerFrameFunctionalGroups,
|
|
742
|
+
pixelDataChunks = _ref1.pixelDataChunks,
|
|
743
|
+
sequenceIndex = _ref1.sequenceIndex,
|
|
744
|
+
sliceLength = _ref1.sliceLength,
|
|
745
|
+
Rows = _ref1.Rows,
|
|
746
|
+
Columns = _ref1.Columns,
|
|
747
|
+
validOrientations = _ref1.validOrientations,
|
|
748
|
+
tolerance = _ref1.tolerance;
|
|
337
749
|
const ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
|
|
338
750
|
const view = readFromUnpackedChunks(pixelDataChunks, sequenceIndex * sliceLength, sliceLength);
|
|
339
751
|
const pixelDataI2D = ndarray(view, [Rows, Columns]);
|
|
@@ -343,19 +755,19 @@ const getAlignedPixelData = _ref5 => {
|
|
|
343
755
|
}
|
|
344
756
|
return alignedPixelDataI;
|
|
345
757
|
};
|
|
346
|
-
const checkImageDimensions =
|
|
347
|
-
let metadataProvider =
|
|
348
|
-
imageId =
|
|
349
|
-
Rows =
|
|
350
|
-
Columns =
|
|
758
|
+
const checkImageDimensions = _ref10 => {
|
|
759
|
+
let metadataProvider = _ref10.metadataProvider,
|
|
760
|
+
imageId = _ref10.imageId,
|
|
761
|
+
Rows = _ref10.Rows,
|
|
762
|
+
Columns = _ref10.Columns;
|
|
351
763
|
const sourceImageMetadata = metadataProvider.get('instance', imageId);
|
|
352
764
|
if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
|
|
353
765
|
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. ');
|
|
354
766
|
}
|
|
355
767
|
};
|
|
356
|
-
const getArrayOfLabelMapImagesWithSegmentData =
|
|
357
|
-
let arrayOfSegmentData =
|
|
358
|
-
referencedImageIds =
|
|
768
|
+
const getArrayOfLabelMapImagesWithSegmentData = _ref11 => {
|
|
769
|
+
let arrayOfSegmentData = _ref11.arrayOfSegmentData,
|
|
770
|
+
referencedImageIds = _ref11.referencedImageIds;
|
|
359
771
|
let largestArray = [];
|
|
360
772
|
for (let i = 0; i < arrayOfSegmentData.length; i++) {
|
|
361
773
|
const segmentData = arrayOfSegmentData[i];
|
|
@@ -378,18 +790,18 @@ const getArrayOfLabelMapImagesWithSegmentData = _ref7 => {
|
|
|
378
790
|
return labelMapImages;
|
|
379
791
|
});
|
|
380
792
|
};
|
|
381
|
-
function insertOverlappingPixelDataPlanar(
|
|
382
|
-
let segmentsOnFrame =
|
|
383
|
-
labelMapImages =
|
|
384
|
-
pixelDataChunks =
|
|
385
|
-
multiframe =
|
|
386
|
-
referencedImageIds =
|
|
387
|
-
validOrientations =
|
|
388
|
-
metadataProvider =
|
|
389
|
-
tolerance =
|
|
390
|
-
segmentsPixelIndices =
|
|
391
|
-
sopUIDImageIdIndexMap =
|
|
392
|
-
imageIdMaps =
|
|
793
|
+
function insertOverlappingPixelDataPlanar(_ref12) {
|
|
794
|
+
let segmentsOnFrame = _ref12.segmentsOnFrame,
|
|
795
|
+
labelMapImages = _ref12.labelMapImages,
|
|
796
|
+
pixelDataChunks = _ref12.pixelDataChunks,
|
|
797
|
+
multiframe = _ref12.multiframe,
|
|
798
|
+
referencedImageIds = _ref12.referencedImageIds,
|
|
799
|
+
validOrientations = _ref12.validOrientations,
|
|
800
|
+
metadataProvider = _ref12.metadataProvider,
|
|
801
|
+
tolerance = _ref12.tolerance,
|
|
802
|
+
segmentsPixelIndices = _ref12.segmentsPixelIndices,
|
|
803
|
+
sopUIDImageIdIndexMap = _ref12.sopUIDImageIdIndexMap,
|
|
804
|
+
imageIdMaps = _ref12.imageIdMaps;
|
|
393
805
|
const SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
|
|
394
806
|
PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
|
|
395
807
|
Rows = multiframe.Rows,
|
|
@@ -422,22 +834,22 @@ function insertOverlappingPixelDataPlanar(_ref8) {
|
|
|
422
834
|
hasOverlappingSegments: true
|
|
423
835
|
};
|
|
424
836
|
}
|
|
425
|
-
const getArrayOfSegmentData =
|
|
426
|
-
let sliceLength =
|
|
427
|
-
Rows =
|
|
428
|
-
Columns =
|
|
429
|
-
validOrientations =
|
|
430
|
-
metadataProvider =
|
|
431
|
-
imageIdMaps =
|
|
432
|
-
segmentsOnFrame =
|
|
433
|
-
tolerance =
|
|
434
|
-
pixelDataChunks =
|
|
435
|
-
PerFrameFunctionalGroupsSequence =
|
|
436
|
-
labelMapImages =
|
|
437
|
-
sopUIDImageIdIndexMap =
|
|
438
|
-
multiframe =
|
|
439
|
-
sharedImageOrientationPatient =
|
|
440
|
-
segmentsPixelIndices =
|
|
837
|
+
const getArrayOfSegmentData = _ref13 => {
|
|
838
|
+
let sliceLength = _ref13.sliceLength,
|
|
839
|
+
Rows = _ref13.Rows,
|
|
840
|
+
Columns = _ref13.Columns,
|
|
841
|
+
validOrientations = _ref13.validOrientations,
|
|
842
|
+
metadataProvider = _ref13.metadataProvider,
|
|
843
|
+
imageIdMaps = _ref13.imageIdMaps,
|
|
844
|
+
segmentsOnFrame = _ref13.segmentsOnFrame,
|
|
845
|
+
tolerance = _ref13.tolerance,
|
|
846
|
+
pixelDataChunks = _ref13.pixelDataChunks,
|
|
847
|
+
PerFrameFunctionalGroupsSequence = _ref13.PerFrameFunctionalGroupsSequence,
|
|
848
|
+
labelMapImages = _ref13.labelMapImages,
|
|
849
|
+
sopUIDImageIdIndexMap = _ref13.sopUIDImageIdIndexMap,
|
|
850
|
+
multiframe = _ref13.multiframe,
|
|
851
|
+
sharedImageOrientationPatient = _ref13.sharedImageOrientationPatient,
|
|
852
|
+
segmentsPixelIndices = _ref13.segmentsPixelIndices;
|
|
441
853
|
const arrayOfSegmentData = [];
|
|
442
854
|
const numberOfSegments = multiframe.SegmentSequence.length;
|
|
443
855
|
for (let currentSegmentIndex = 1; currentSegmentIndex <= numberOfSegments; ++currentSegmentIndex) {
|
|
@@ -466,23 +878,23 @@ const getArrayOfSegmentData = _ref9 => {
|
|
|
466
878
|
}
|
|
467
879
|
return arrayOfSegmentData;
|
|
468
880
|
};
|
|
469
|
-
const getSegmentData =
|
|
470
|
-
let PerFrameFunctionalGroupsSequence =
|
|
471
|
-
labelMapImages =
|
|
472
|
-
sopUIDImageIdIndexMap =
|
|
473
|
-
multiframe =
|
|
474
|
-
segmentIndex =
|
|
475
|
-
sliceLength =
|
|
476
|
-
Rows =
|
|
477
|
-
Columns =
|
|
478
|
-
validOrientations =
|
|
479
|
-
tolerance =
|
|
480
|
-
pixelDataChunks =
|
|
481
|
-
sharedImageOrientationPatient =
|
|
482
|
-
metadataProvider =
|
|
483
|
-
imageIdMaps =
|
|
484
|
-
segmentsOnFrame =
|
|
485
|
-
segmentsPixelIndices =
|
|
881
|
+
const getSegmentData = _ref14 => {
|
|
882
|
+
let PerFrameFunctionalGroupsSequence = _ref14.PerFrameFunctionalGroupsSequence,
|
|
883
|
+
labelMapImages = _ref14.labelMapImages,
|
|
884
|
+
sopUIDImageIdIndexMap = _ref14.sopUIDImageIdIndexMap,
|
|
885
|
+
multiframe = _ref14.multiframe,
|
|
886
|
+
segmentIndex = _ref14.segmentIndex,
|
|
887
|
+
sliceLength = _ref14.sliceLength,
|
|
888
|
+
Rows = _ref14.Rows,
|
|
889
|
+
Columns = _ref14.Columns,
|
|
890
|
+
validOrientations = _ref14.validOrientations,
|
|
891
|
+
tolerance = _ref14.tolerance,
|
|
892
|
+
pixelDataChunks = _ref14.pixelDataChunks,
|
|
893
|
+
sharedImageOrientationPatient = _ref14.sharedImageOrientationPatient,
|
|
894
|
+
metadataProvider = _ref14.metadataProvider,
|
|
895
|
+
imageIdMaps = _ref14.imageIdMaps,
|
|
896
|
+
segmentsOnFrame = _ref14.segmentsOnFrame,
|
|
897
|
+
segmentsPixelIndices = _ref14.segmentsPixelIndices;
|
|
486
898
|
const segmentData = [];
|
|
487
899
|
for (let currentLabelMapImageIndex = 0; currentLabelMapImageIndex < labelMapImages.length; currentLabelMapImageIndex++) {
|
|
488
900
|
const currentLabelMapImage = labelMapImages[currentLabelMapImageIndex];
|
|
@@ -547,5 +959,25 @@ const getSegmentData = _ref0 => {
|
|
|
547
959
|
}
|
|
548
960
|
return segmentData;
|
|
549
961
|
};
|
|
962
|
+
async function createLabelmapsFromDICOMBuffer(referencedImageIds, arrayBuffer, metadataProvider) {
|
|
963
|
+
var _options$segImageId;
|
|
964
|
+
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
965
|
+
const dicomData = DicomMessage.readFile(arrayBuffer);
|
|
966
|
+
const dataset = DicomMetaDictionary.naturalizeDataset(dicomData.dict);
|
|
967
|
+
dataset._meta = DicomMetaDictionary.namifyDataset(dicomData.meta);
|
|
968
|
+
const multiframe = Normalizer.normalizeToDataset([dataset]);
|
|
969
|
+
const segImageId = (_options$segImageId = options.segImageId) !== null && _options$segImageId !== void 0 ? _options$segImageId : BUFFER_SEG_IMAGE_ID;
|
|
970
|
+
ensureInstanceOnMetadataProvider(metadataProvider, segImageId, multiframe);
|
|
971
|
+
const numberOfFrames = getSegNumberOfFramesFromDataset(multiframe);
|
|
972
|
+
const frameImageIds = Array.from({
|
|
973
|
+
length: numberOfFrames
|
|
974
|
+
}, (_, index) => "".concat(segImageId, "#frame=").concat(index + 1));
|
|
975
|
+
const decodeImageData = createDecodeImageDataFromMultiframe(multiframe);
|
|
976
|
+
return createLabelmapsFromSegImageIds(referencedImageIds, segImageId, metadataProvider, _objectSpread(_objectSpread({}, options), {}, {
|
|
977
|
+
frameImageIds,
|
|
978
|
+
decodeImageData,
|
|
979
|
+
multiframe
|
|
980
|
+
}));
|
|
981
|
+
}
|
|
550
982
|
|
|
551
|
-
export {
|
|
983
|
+
export { buildSopUIDImageIdIndexMap, createLabelmapsFromDICOMBuffer, createLabelmapsFromSegImageIds, decodeSegPixelDataFromFrameIds, insertOverlappingPixelDataPlanar, insertPixelDataPlanar, isPseudoBinaryFractional, resolveFrameImageIds };
|