@cornerstonejs/adapters 1.7.2 → 1.8.0
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/{@cornerstonejs/adapters.es.js → adapters.es.js} +1344 -698
- package/dist/adapters.es.js.map +1 -0
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone/index.d.ts +5 -3
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/Angle.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/Bidirectional.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/CircleROI.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/CobbAngle.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/EllipticalROI.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/MeasurementReport.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/PlanarFreehandROI.d.ts +1 -1
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/RectangleROI.d.ts +1 -1
- package/dist/types/adapters/Cornerstone3D/Segmentation/generateLabelMaps2DFrom3D.d.ts +18 -0
- package/dist/types/adapters/Cornerstone3D/Segmentation/generateSegmentation.d.ts +8 -0
- package/dist/types/adapters/Cornerstone3D/Segmentation/generateToolState.d.ts +16 -0
- package/dist/types/adapters/Cornerstone3D/Segmentation/index.d.ts +4 -0
- package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/index.d.ts +6 -2
- package/dist/types/adapters/VTKjs/index.d.ts +4 -0
- package/dist/types/adapters/enums/Events.d.ts +10 -0
- package/dist/types/adapters/enums/index.d.ts +2 -0
- package/dist/types/adapters/helpers/codeMeaningEquals.d.ts +9 -0
- package/dist/types/adapters/helpers/graphicTypeEquals.d.ts +7 -0
- package/dist/types/adapters/helpers/index.d.ts +4 -0
- package/dist/types/adapters/helpers/toArray.d.ts +2 -0
- package/dist/{@cornerstonejs/dts → types}/adapters/index.d.ts +21 -3
- package/dist/types/index.d.ts +2 -0
- package/package.json +15 -8
- package/dist/@cornerstonejs/adapters.es.js.map +0 -1
- package/dist/@cornerstonejs/dts/adapters/VTKjs/index.d.ts +0 -4
- package/dist/@cornerstonejs/dts/index.d.ts +0 -3
- /package/dist/{@cornerstonejs/dts → types}/adapters/Cornerstone3D/isValidCornerstoneTrackingIdentifier.d.ts +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { utilities, derivations, normalizers, data, log } from 'dcmjs';
|
|
2
2
|
import ndarray from 'ndarray';
|
|
3
3
|
import cloneDeep from 'lodash.clonedeep';
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
4
5
|
import { vec3 } from 'gl-matrix';
|
|
5
6
|
|
|
6
7
|
function _iterableToArrayLimit(arr, i) {
|
|
@@ -51,6 +52,337 @@ function _objectSpread2(target) {
|
|
|
51
52
|
}
|
|
52
53
|
return target;
|
|
53
54
|
}
|
|
55
|
+
function _regeneratorRuntime() {
|
|
56
|
+
_regeneratorRuntime = function () {
|
|
57
|
+
return exports;
|
|
58
|
+
};
|
|
59
|
+
var exports = {},
|
|
60
|
+
Op = Object.prototype,
|
|
61
|
+
hasOwn = Op.hasOwnProperty,
|
|
62
|
+
defineProperty = Object.defineProperty || function (obj, key, desc) {
|
|
63
|
+
obj[key] = desc.value;
|
|
64
|
+
},
|
|
65
|
+
$Symbol = "function" == typeof Symbol ? Symbol : {},
|
|
66
|
+
iteratorSymbol = $Symbol.iterator || "@@iterator",
|
|
67
|
+
asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator",
|
|
68
|
+
toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
|
|
69
|
+
function define(obj, key, value) {
|
|
70
|
+
return Object.defineProperty(obj, key, {
|
|
71
|
+
value: value,
|
|
72
|
+
enumerable: !0,
|
|
73
|
+
configurable: !0,
|
|
74
|
+
writable: !0
|
|
75
|
+
}), obj[key];
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
define({}, "");
|
|
79
|
+
} catch (err) {
|
|
80
|
+
define = function (obj, key, value) {
|
|
81
|
+
return obj[key] = value;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function wrap(innerFn, outerFn, self, tryLocsList) {
|
|
85
|
+
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,
|
|
86
|
+
generator = Object.create(protoGenerator.prototype),
|
|
87
|
+
context = new Context(tryLocsList || []);
|
|
88
|
+
return defineProperty(generator, "_invoke", {
|
|
89
|
+
value: makeInvokeMethod(innerFn, self, context)
|
|
90
|
+
}), generator;
|
|
91
|
+
}
|
|
92
|
+
function tryCatch(fn, obj, arg) {
|
|
93
|
+
try {
|
|
94
|
+
return {
|
|
95
|
+
type: "normal",
|
|
96
|
+
arg: fn.call(obj, arg)
|
|
97
|
+
};
|
|
98
|
+
} catch (err) {
|
|
99
|
+
return {
|
|
100
|
+
type: "throw",
|
|
101
|
+
arg: err
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.wrap = wrap;
|
|
106
|
+
var ContinueSentinel = {};
|
|
107
|
+
function Generator() {}
|
|
108
|
+
function GeneratorFunction() {}
|
|
109
|
+
function GeneratorFunctionPrototype() {}
|
|
110
|
+
var IteratorPrototype = {};
|
|
111
|
+
define(IteratorPrototype, iteratorSymbol, function () {
|
|
112
|
+
return this;
|
|
113
|
+
});
|
|
114
|
+
var getProto = Object.getPrototypeOf,
|
|
115
|
+
NativeIteratorPrototype = getProto && getProto(getProto(values([])));
|
|
116
|
+
NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);
|
|
117
|
+
var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
|
|
118
|
+
function defineIteratorMethods(prototype) {
|
|
119
|
+
["next", "throw", "return"].forEach(function (method) {
|
|
120
|
+
define(prototype, method, function (arg) {
|
|
121
|
+
return this._invoke(method, arg);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function AsyncIterator(generator, PromiseImpl) {
|
|
126
|
+
function invoke(method, arg, resolve, reject) {
|
|
127
|
+
var record = tryCatch(generator[method], generator, arg);
|
|
128
|
+
if ("throw" !== record.type) {
|
|
129
|
+
var result = record.arg,
|
|
130
|
+
value = result.value;
|
|
131
|
+
return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) {
|
|
132
|
+
invoke("next", value, resolve, reject);
|
|
133
|
+
}, function (err) {
|
|
134
|
+
invoke("throw", err, resolve, reject);
|
|
135
|
+
}) : PromiseImpl.resolve(value).then(function (unwrapped) {
|
|
136
|
+
result.value = unwrapped, resolve(result);
|
|
137
|
+
}, function (error) {
|
|
138
|
+
return invoke("throw", error, resolve, reject);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
reject(record.arg);
|
|
142
|
+
}
|
|
143
|
+
var previousPromise;
|
|
144
|
+
defineProperty(this, "_invoke", {
|
|
145
|
+
value: function (method, arg) {
|
|
146
|
+
function callInvokeWithMethodAndArg() {
|
|
147
|
+
return new PromiseImpl(function (resolve, reject) {
|
|
148
|
+
invoke(method, arg, resolve, reject);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function makeInvokeMethod(innerFn, self, context) {
|
|
156
|
+
var state = "suspendedStart";
|
|
157
|
+
return function (method, arg) {
|
|
158
|
+
if ("executing" === state) throw new Error("Generator is already running");
|
|
159
|
+
if ("completed" === state) {
|
|
160
|
+
if ("throw" === method) throw arg;
|
|
161
|
+
return doneResult();
|
|
162
|
+
}
|
|
163
|
+
for (context.method = method, context.arg = arg;;) {
|
|
164
|
+
var delegate = context.delegate;
|
|
165
|
+
if (delegate) {
|
|
166
|
+
var delegateResult = maybeInvokeDelegate(delegate, context);
|
|
167
|
+
if (delegateResult) {
|
|
168
|
+
if (delegateResult === ContinueSentinel) continue;
|
|
169
|
+
return delegateResult;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) {
|
|
173
|
+
if ("suspendedStart" === state) throw state = "completed", context.arg;
|
|
174
|
+
context.dispatchException(context.arg);
|
|
175
|
+
} else "return" === context.method && context.abrupt("return", context.arg);
|
|
176
|
+
state = "executing";
|
|
177
|
+
var record = tryCatch(innerFn, self, context);
|
|
178
|
+
if ("normal" === record.type) {
|
|
179
|
+
if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue;
|
|
180
|
+
return {
|
|
181
|
+
value: record.arg,
|
|
182
|
+
done: context.done
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
"throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function maybeInvokeDelegate(delegate, context) {
|
|
190
|
+
var methodName = context.method,
|
|
191
|
+
method = delegate.iterator[methodName];
|
|
192
|
+
if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel;
|
|
193
|
+
var record = tryCatch(method, delegate.iterator, context.arg);
|
|
194
|
+
if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel;
|
|
195
|
+
var info = record.arg;
|
|
196
|
+
return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel);
|
|
197
|
+
}
|
|
198
|
+
function pushTryEntry(locs) {
|
|
199
|
+
var entry = {
|
|
200
|
+
tryLoc: locs[0]
|
|
201
|
+
};
|
|
202
|
+
1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);
|
|
203
|
+
}
|
|
204
|
+
function resetTryEntry(entry) {
|
|
205
|
+
var record = entry.completion || {};
|
|
206
|
+
record.type = "normal", delete record.arg, entry.completion = record;
|
|
207
|
+
}
|
|
208
|
+
function Context(tryLocsList) {
|
|
209
|
+
this.tryEntries = [{
|
|
210
|
+
tryLoc: "root"
|
|
211
|
+
}], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);
|
|
212
|
+
}
|
|
213
|
+
function values(iterable) {
|
|
214
|
+
if (iterable) {
|
|
215
|
+
var iteratorMethod = iterable[iteratorSymbol];
|
|
216
|
+
if (iteratorMethod) return iteratorMethod.call(iterable);
|
|
217
|
+
if ("function" == typeof iterable.next) return iterable;
|
|
218
|
+
if (!isNaN(iterable.length)) {
|
|
219
|
+
var i = -1,
|
|
220
|
+
next = function next() {
|
|
221
|
+
for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;
|
|
222
|
+
return next.value = undefined, next.done = !0, next;
|
|
223
|
+
};
|
|
224
|
+
return next.next = next;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
next: doneResult
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function doneResult() {
|
|
232
|
+
return {
|
|
233
|
+
value: undefined,
|
|
234
|
+
done: !0
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", {
|
|
238
|
+
value: GeneratorFunctionPrototype,
|
|
239
|
+
configurable: !0
|
|
240
|
+
}), defineProperty(GeneratorFunctionPrototype, "constructor", {
|
|
241
|
+
value: GeneratorFunction,
|
|
242
|
+
configurable: !0
|
|
243
|
+
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) {
|
|
244
|
+
var ctor = "function" == typeof genFun && genFun.constructor;
|
|
245
|
+
return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name));
|
|
246
|
+
}, exports.mark = function (genFun) {
|
|
247
|
+
return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun;
|
|
248
|
+
}, exports.awrap = function (arg) {
|
|
249
|
+
return {
|
|
250
|
+
__await: arg
|
|
251
|
+
};
|
|
252
|
+
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
|
|
253
|
+
return this;
|
|
254
|
+
}), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
|
|
255
|
+
void 0 === PromiseImpl && (PromiseImpl = Promise);
|
|
256
|
+
var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
|
|
257
|
+
return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {
|
|
258
|
+
return result.done ? result.value : iter.next();
|
|
259
|
+
});
|
|
260
|
+
}, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () {
|
|
261
|
+
return this;
|
|
262
|
+
}), define(Gp, "toString", function () {
|
|
263
|
+
return "[object Generator]";
|
|
264
|
+
}), exports.keys = function (val) {
|
|
265
|
+
var object = Object(val),
|
|
266
|
+
keys = [];
|
|
267
|
+
for (var key in object) keys.push(key);
|
|
268
|
+
return keys.reverse(), function next() {
|
|
269
|
+
for (; keys.length;) {
|
|
270
|
+
var key = keys.pop();
|
|
271
|
+
if (key in object) return next.value = key, next.done = !1, next;
|
|
272
|
+
}
|
|
273
|
+
return next.done = !0, next;
|
|
274
|
+
};
|
|
275
|
+
}, exports.values = values, Context.prototype = {
|
|
276
|
+
constructor: Context,
|
|
277
|
+
reset: function (skipTempReset) {
|
|
278
|
+
if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);
|
|
279
|
+
},
|
|
280
|
+
stop: function () {
|
|
281
|
+
this.done = !0;
|
|
282
|
+
var rootRecord = this.tryEntries[0].completion;
|
|
283
|
+
if ("throw" === rootRecord.type) throw rootRecord.arg;
|
|
284
|
+
return this.rval;
|
|
285
|
+
},
|
|
286
|
+
dispatchException: function (exception) {
|
|
287
|
+
if (this.done) throw exception;
|
|
288
|
+
var context = this;
|
|
289
|
+
function handle(loc, caught) {
|
|
290
|
+
return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught;
|
|
291
|
+
}
|
|
292
|
+
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
293
|
+
var entry = this.tryEntries[i],
|
|
294
|
+
record = entry.completion;
|
|
295
|
+
if ("root" === entry.tryLoc) return handle("end");
|
|
296
|
+
if (entry.tryLoc <= this.prev) {
|
|
297
|
+
var hasCatch = hasOwn.call(entry, "catchLoc"),
|
|
298
|
+
hasFinally = hasOwn.call(entry, "finallyLoc");
|
|
299
|
+
if (hasCatch && hasFinally) {
|
|
300
|
+
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
|
|
301
|
+
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
|
|
302
|
+
} else if (hasCatch) {
|
|
303
|
+
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
|
|
304
|
+
} else {
|
|
305
|
+
if (!hasFinally) throw new Error("try statement without catch or finally");
|
|
306
|
+
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
abrupt: function (type, arg) {
|
|
312
|
+
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
313
|
+
var entry = this.tryEntries[i];
|
|
314
|
+
if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
|
|
315
|
+
var finallyEntry = entry;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);
|
|
320
|
+
var record = finallyEntry ? finallyEntry.completion : {};
|
|
321
|
+
return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);
|
|
322
|
+
},
|
|
323
|
+
complete: function (record, afterLoc) {
|
|
324
|
+
if ("throw" === record.type) throw record.arg;
|
|
325
|
+
return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;
|
|
326
|
+
},
|
|
327
|
+
finish: function (finallyLoc) {
|
|
328
|
+
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
329
|
+
var entry = this.tryEntries[i];
|
|
330
|
+
if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
catch: function (tryLoc) {
|
|
334
|
+
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
335
|
+
var entry = this.tryEntries[i];
|
|
336
|
+
if (entry.tryLoc === tryLoc) {
|
|
337
|
+
var record = entry.completion;
|
|
338
|
+
if ("throw" === record.type) {
|
|
339
|
+
var thrown = record.arg;
|
|
340
|
+
resetTryEntry(entry);
|
|
341
|
+
}
|
|
342
|
+
return thrown;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
throw new Error("illegal catch attempt");
|
|
346
|
+
},
|
|
347
|
+
delegateYield: function (iterable, resultName, nextLoc) {
|
|
348
|
+
return this.delegate = {
|
|
349
|
+
iterator: values(iterable),
|
|
350
|
+
resultName: resultName,
|
|
351
|
+
nextLoc: nextLoc
|
|
352
|
+
}, "next" === this.method && (this.arg = undefined), ContinueSentinel;
|
|
353
|
+
}
|
|
354
|
+
}, exports;
|
|
355
|
+
}
|
|
356
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
357
|
+
try {
|
|
358
|
+
var info = gen[key](arg);
|
|
359
|
+
var value = info.value;
|
|
360
|
+
} catch (error) {
|
|
361
|
+
reject(error);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (info.done) {
|
|
365
|
+
resolve(value);
|
|
366
|
+
} else {
|
|
367
|
+
Promise.resolve(value).then(_next, _throw);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function _asyncToGenerator(fn) {
|
|
371
|
+
return function () {
|
|
372
|
+
var self = this,
|
|
373
|
+
args = arguments;
|
|
374
|
+
return new Promise(function (resolve, reject) {
|
|
375
|
+
var gen = fn.apply(self, args);
|
|
376
|
+
function _next(value) {
|
|
377
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
378
|
+
}
|
|
379
|
+
function _throw(err) {
|
|
380
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
381
|
+
}
|
|
382
|
+
_next(undefined);
|
|
383
|
+
});
|
|
384
|
+
};
|
|
385
|
+
}
|
|
54
386
|
function _classCallCheck(instance, Constructor) {
|
|
55
387
|
if (!(instance instanceof Constructor)) {
|
|
56
388
|
throw new TypeError("Cannot call a class as a function");
|
|
@@ -187,19 +519,43 @@ function _toPropertyKey(arg) {
|
|
|
187
519
|
return typeof key === "symbol" ? key : String(key);
|
|
188
520
|
}
|
|
189
521
|
|
|
190
|
-
var toArray = function
|
|
191
|
-
|
|
522
|
+
var toArray = function (x) { return (Array.isArray(x) ? x : [x]); };
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Returns a function that checks if a given content item's ConceptNameCodeSequence.CodeMeaning
|
|
526
|
+
* matches the provided codeMeaningName.
|
|
527
|
+
* @param codeMeaningName - The CodeMeaning to match against.
|
|
528
|
+
* @returns A function that takes a content item and returns a boolean indicating whether the
|
|
529
|
+
* content item's CodeMeaning matches the provided codeMeaningName.
|
|
530
|
+
*/
|
|
531
|
+
var codeMeaningEquals = function (codeMeaningName) {
|
|
532
|
+
return function (contentItem) {
|
|
533
|
+
return (contentItem.ConceptNameCodeSequence.CodeMeaning === codeMeaningName);
|
|
534
|
+
};
|
|
192
535
|
};
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Checks if a given content item's GraphicType property matches a specified value.
|
|
539
|
+
* @param {string} graphicType - The value to compare the content item's GraphicType property to.
|
|
540
|
+
* @returns {function} A function that takes a content item and returns a boolean indicating whether its GraphicType property matches the specified value.
|
|
541
|
+
*/
|
|
542
|
+
var graphicTypeEquals = function (graphicType) {
|
|
543
|
+
return function (contentItem) {
|
|
544
|
+
return contentItem && contentItem.GraphicType === graphicType;
|
|
545
|
+
};
|
|
197
546
|
};
|
|
198
547
|
|
|
548
|
+
var index$1 = /*#__PURE__*/Object.freeze({
|
|
549
|
+
__proto__: null,
|
|
550
|
+
codeMeaningEquals: codeMeaningEquals,
|
|
551
|
+
graphicTypeEquals: graphicTypeEquals,
|
|
552
|
+
toArray: toArray
|
|
553
|
+
});
|
|
554
|
+
|
|
199
555
|
var TID1500$1 = utilities.TID1500,
|
|
200
556
|
addAccessors$1 = utilities.addAccessors;
|
|
201
557
|
var StructuredReport$1 = derivations.StructuredReport;
|
|
202
|
-
var Normalizer$
|
|
558
|
+
var Normalizer$4 = normalizers.Normalizer;
|
|
203
559
|
var TID1500MeasurementReport$1 = TID1500$1.TID1500MeasurementReport,
|
|
204
560
|
TID1501MeasurementGroup$1 = TID1500$1.TID1501MeasurementGroup;
|
|
205
561
|
var DicomMetaDictionary$3 = data.DicomMetaDictionary;
|
|
@@ -331,7 +687,7 @@ var MeasurementReport$1 = /*#__PURE__*/function () {
|
|
|
331
687
|
ReferencedSOPClassUID: sopCommonModule.sopClassUID,
|
|
332
688
|
ReferencedSOPInstanceUID: sopCommonModule.sopInstanceUID
|
|
333
689
|
};
|
|
334
|
-
if (Normalizer$
|
|
690
|
+
if (Normalizer$4.isMultiframeSOPClassUID(sopCommonModule.sopClassUID)) {
|
|
335
691
|
ReferencedSOPSequence.ReferencedFrameNumber = frameNumber;
|
|
336
692
|
}
|
|
337
693
|
|
|
@@ -1165,80 +1521,353 @@ ArrowAnnotate$1.isValidCornerstoneTrackingIdentifier = function (TrackingIdentif
|
|
|
1165
1521
|
};
|
|
1166
1522
|
MeasurementReport$1.registerTool(ArrowAnnotate$1);
|
|
1167
1523
|
|
|
1168
|
-
var
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
var datasetToBlob$1 = utilities.datasetToBlob,
|
|
1174
|
-
BitArray$2 = utilities.BitArray,
|
|
1175
|
-
DicomMessage$1 = utilities.DicomMessage,
|
|
1176
|
-
DicomMetaDictionary$2 = utilities.DicomMetaDictionary;
|
|
1177
|
-
var Normalizer$2 = normalizers.Normalizer;
|
|
1178
|
-
var SegmentationDerivation$1 = derivations.Segmentation;
|
|
1179
|
-
var Segmentation$3 = {
|
|
1180
|
-
generateSegmentation: generateSegmentation$2,
|
|
1181
|
-
generateToolState: generateToolState$2
|
|
1182
|
-
};
|
|
1183
|
-
|
|
1184
|
-
/**
|
|
1185
|
-
*
|
|
1186
|
-
* @typedef {Object} BrushData
|
|
1187
|
-
* @property {Object} toolState - The cornerstoneTools global toolState.
|
|
1188
|
-
* @property {Object[]} segments - The cornerstoneTools segment metadata that corresponds to the
|
|
1189
|
-
* seriesInstanceUid.
|
|
1190
|
-
*/
|
|
1191
|
-
|
|
1192
|
-
/**
|
|
1193
|
-
* generateSegmentation - Generates cornerstoneTools brush data, given a stack of
|
|
1194
|
-
* imageIds, images and the cornerstoneTools brushData.
|
|
1195
|
-
*
|
|
1196
|
-
* @param {object[]} images An array of the cornerstone image objects.
|
|
1197
|
-
* @param {BrushData} brushData and object containing the brushData.
|
|
1198
|
-
* @returns {type} description
|
|
1199
|
-
*/
|
|
1200
|
-
function generateSegmentation$2(images, brushData) {
|
|
1201
|
-
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
1202
|
-
includeSliceSpacing: true
|
|
1203
|
-
};
|
|
1204
|
-
var toolState = brushData.toolState,
|
|
1205
|
-
segments = brushData.segments;
|
|
1206
|
-
|
|
1207
|
-
// Calculate the dimensions of the data cube.
|
|
1208
|
-
var image0 = images[0];
|
|
1209
|
-
var dims = {
|
|
1210
|
-
x: image0.columns,
|
|
1211
|
-
y: image0.rows,
|
|
1212
|
-
z: images.length
|
|
1213
|
-
};
|
|
1214
|
-
dims.xy = dims.x * dims.y;
|
|
1215
|
-
var numSegments = _getSegCount(seg, segments);
|
|
1216
|
-
if (!numSegments) {
|
|
1217
|
-
throw new Error("No segments to export!");
|
|
1524
|
+
var TID300CobbAngle$2 = utilities.TID300.CobbAngle;
|
|
1525
|
+
var COBB_ANGLE = "CobbAngle";
|
|
1526
|
+
var CobbAngle$1 = /*#__PURE__*/function () {
|
|
1527
|
+
function CobbAngle() {
|
|
1528
|
+
_classCallCheck(this, CobbAngle);
|
|
1218
1529
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1530
|
+
_createClass(CobbAngle, null, [{
|
|
1531
|
+
key: "getMeasurementData",
|
|
1532
|
+
value:
|
|
1533
|
+
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
|
|
1534
|
+
function getMeasurementData(MeasurementGroup) {
|
|
1535
|
+
var _MeasurementReport$ge = MeasurementReport$1.getSetupMeasurementData(MeasurementGroup),
|
|
1536
|
+
defaultState = _MeasurementReport$ge.defaultState,
|
|
1537
|
+
NUMGroup = _MeasurementReport$ge.NUMGroup,
|
|
1538
|
+
SCOORDGroup = _MeasurementReport$ge.SCOORDGroup;
|
|
1539
|
+
var state = _objectSpread2(_objectSpread2({}, defaultState), {}, {
|
|
1540
|
+
rAngle: NUMGroup.MeasuredValueSequence.NumericValue,
|
|
1541
|
+
toolType: CobbAngle.toolType,
|
|
1542
|
+
handles: {
|
|
1543
|
+
start: {},
|
|
1544
|
+
end: {},
|
|
1545
|
+
start2: {
|
|
1546
|
+
highlight: true,
|
|
1547
|
+
drawnIndependently: true
|
|
1548
|
+
},
|
|
1549
|
+
end2: {
|
|
1550
|
+
highlight: true,
|
|
1551
|
+
drawnIndependently: true
|
|
1552
|
+
},
|
|
1553
|
+
textBox: {
|
|
1554
|
+
hasMoved: false,
|
|
1555
|
+
movesIndependently: false,
|
|
1556
|
+
drawnIndependently: true,
|
|
1557
|
+
allowedOutsideImage: true,
|
|
1558
|
+
hasBoundingBox: true
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
var _SCOORDGroup$GraphicD = _slicedToArray(SCOORDGroup.GraphicData, 8);
|
|
1563
|
+
state.handles.start.x = _SCOORDGroup$GraphicD[0];
|
|
1564
|
+
state.handles.start.y = _SCOORDGroup$GraphicD[1];
|
|
1565
|
+
state.handles.end.x = _SCOORDGroup$GraphicD[2];
|
|
1566
|
+
state.handles.end.y = _SCOORDGroup$GraphicD[3];
|
|
1567
|
+
state.handles.start2.x = _SCOORDGroup$GraphicD[4];
|
|
1568
|
+
state.handles.start2.y = _SCOORDGroup$GraphicD[5];
|
|
1569
|
+
state.handles.end2.x = _SCOORDGroup$GraphicD[6];
|
|
1570
|
+
state.handles.end2.y = _SCOORDGroup$GraphicD[7];
|
|
1571
|
+
return state;
|
|
1572
|
+
}
|
|
1573
|
+
}, {
|
|
1574
|
+
key: "getTID300RepresentationArguments",
|
|
1575
|
+
value: function getTID300RepresentationArguments(tool) {
|
|
1576
|
+
var handles = tool.handles,
|
|
1577
|
+
finding = tool.finding,
|
|
1578
|
+
findingSites = tool.findingSites;
|
|
1579
|
+
var point1 = handles.start;
|
|
1580
|
+
var point2 = handles.end;
|
|
1581
|
+
var point3 = handles.start2;
|
|
1582
|
+
var point4 = handles.end2;
|
|
1583
|
+
var rAngle = tool.rAngle;
|
|
1584
|
+
var trackingIdentifierTextValue = "cornerstoneTools@^4.0.0:CobbAngle";
|
|
1585
|
+
return {
|
|
1586
|
+
point1: point1,
|
|
1587
|
+
point2: point2,
|
|
1588
|
+
point3: point3,
|
|
1589
|
+
point4: point4,
|
|
1590
|
+
rAngle: rAngle,
|
|
1591
|
+
trackingIdentifierTextValue: trackingIdentifierTextValue,
|
|
1592
|
+
finding: finding,
|
|
1593
|
+
findingSites: findingSites || []
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
}]);
|
|
1597
|
+
return CobbAngle;
|
|
1598
|
+
}();
|
|
1599
|
+
CobbAngle$1.toolType = COBB_ANGLE;
|
|
1600
|
+
CobbAngle$1.utilityToolType = COBB_ANGLE;
|
|
1601
|
+
CobbAngle$1.TID300Representation = TID300CobbAngle$2;
|
|
1602
|
+
CobbAngle$1.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
1603
|
+
if (!TrackingIdentifier.includes(":")) {
|
|
1604
|
+
return false;
|
|
1227
1605
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1606
|
+
var _TrackingIdentifier$s = TrackingIdentifier.split(":"),
|
|
1607
|
+
_TrackingIdentifier$s2 = _slicedToArray(_TrackingIdentifier$s, 2),
|
|
1608
|
+
cornerstone4Tag = _TrackingIdentifier$s2[0],
|
|
1609
|
+
toolType = _TrackingIdentifier$s2[1];
|
|
1610
|
+
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1611
|
+
return false;
|
|
1612
|
+
}
|
|
1613
|
+
return toolType === COBB_ANGLE;
|
|
1614
|
+
};
|
|
1615
|
+
MeasurementReport$1.registerTool(CobbAngle$1);
|
|
1232
1616
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
seg.addSegment(segment, _extractCornerstoneToolsPixelData(segmentIndex, referencedFrameIndicies, toolState, images, dims), referencedFrameNumbers);
|
|
1617
|
+
var TID300Angle = utilities.TID300.Angle;
|
|
1618
|
+
var ANGLE = "Angle";
|
|
1619
|
+
var Angle$1 = /*#__PURE__*/function () {
|
|
1620
|
+
function Angle() {
|
|
1621
|
+
_classCallCheck(this, Angle);
|
|
1239
1622
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1623
|
+
_createClass(Angle, null, [{
|
|
1624
|
+
key: "getMeasurementData",
|
|
1625
|
+
value:
|
|
1626
|
+
/**
|
|
1627
|
+
* Generate TID300 measurement data for a plane angle measurement - use a Angle, but label it as Angle
|
|
1628
|
+
*/
|
|
1629
|
+
function getMeasurementData(MeasurementGroup) {
|
|
1630
|
+
var _MeasurementReport$ge = MeasurementReport$1.getSetupMeasurementData(MeasurementGroup),
|
|
1631
|
+
defaultState = _MeasurementReport$ge.defaultState,
|
|
1632
|
+
NUMGroup = _MeasurementReport$ge.NUMGroup,
|
|
1633
|
+
SCOORDGroup = _MeasurementReport$ge.SCOORDGroup;
|
|
1634
|
+
var state = _objectSpread2(_objectSpread2({}, defaultState), {}, {
|
|
1635
|
+
rAngle: NUMGroup.MeasuredValueSequence.NumericValue,
|
|
1636
|
+
toolType: Angle.toolType,
|
|
1637
|
+
handles: {
|
|
1638
|
+
start: {},
|
|
1639
|
+
middle: {},
|
|
1640
|
+
end: {},
|
|
1641
|
+
textBox: {
|
|
1642
|
+
hasMoved: false,
|
|
1643
|
+
movesIndependently: false,
|
|
1644
|
+
drawnIndependently: true,
|
|
1645
|
+
allowedOutsideImage: true,
|
|
1646
|
+
hasBoundingBox: true
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
var _SCOORDGroup$GraphicD = _slicedToArray(SCOORDGroup.GraphicData, 8);
|
|
1651
|
+
state.handles.start.x = _SCOORDGroup$GraphicD[0];
|
|
1652
|
+
state.handles.start.y = _SCOORDGroup$GraphicD[1];
|
|
1653
|
+
state.handles.middle.x = _SCOORDGroup$GraphicD[2];
|
|
1654
|
+
state.handles.middle.y = _SCOORDGroup$GraphicD[3];
|
|
1655
|
+
state.handles.middle.x = _SCOORDGroup$GraphicD[4];
|
|
1656
|
+
state.handles.middle.y = _SCOORDGroup$GraphicD[5];
|
|
1657
|
+
state.handles.end.x = _SCOORDGroup$GraphicD[6];
|
|
1658
|
+
state.handles.end.y = _SCOORDGroup$GraphicD[7];
|
|
1659
|
+
return state;
|
|
1660
|
+
}
|
|
1661
|
+
}, {
|
|
1662
|
+
key: "getTID300RepresentationArguments",
|
|
1663
|
+
value: function getTID300RepresentationArguments(tool) {
|
|
1664
|
+
var handles = tool.handles,
|
|
1665
|
+
finding = tool.finding,
|
|
1666
|
+
findingSites = tool.findingSites;
|
|
1667
|
+
var point1 = handles.start;
|
|
1668
|
+
var point2 = handles.middle;
|
|
1669
|
+
var point3 = handles.middle;
|
|
1670
|
+
var point4 = handles.end;
|
|
1671
|
+
var rAngle = tool.rAngle;
|
|
1672
|
+
var trackingIdentifierTextValue = "cornerstoneTools@^4.0.0:Angle";
|
|
1673
|
+
return {
|
|
1674
|
+
point1: point1,
|
|
1675
|
+
point2: point2,
|
|
1676
|
+
point3: point3,
|
|
1677
|
+
point4: point4,
|
|
1678
|
+
rAngle: rAngle,
|
|
1679
|
+
trackingIdentifierTextValue: trackingIdentifierTextValue,
|
|
1680
|
+
finding: finding,
|
|
1681
|
+
findingSites: findingSites || []
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
}]);
|
|
1685
|
+
return Angle;
|
|
1686
|
+
}();
|
|
1687
|
+
Angle$1.toolType = ANGLE;
|
|
1688
|
+
Angle$1.utilityToolType = ANGLE;
|
|
1689
|
+
Angle$1.TID300Representation = TID300Angle;
|
|
1690
|
+
Angle$1.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
1691
|
+
if (!TrackingIdentifier.includes(":")) {
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
var _TrackingIdentifier$s = TrackingIdentifier.split(":"),
|
|
1695
|
+
_TrackingIdentifier$s2 = _slicedToArray(_TrackingIdentifier$s, 2),
|
|
1696
|
+
cornerstone4Tag = _TrackingIdentifier$s2[0],
|
|
1697
|
+
toolType = _TrackingIdentifier$s2[1];
|
|
1698
|
+
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1699
|
+
return false;
|
|
1700
|
+
}
|
|
1701
|
+
return toolType === ANGLE;
|
|
1702
|
+
};
|
|
1703
|
+
MeasurementReport$1.registerTool(Angle$1);
|
|
1704
|
+
|
|
1705
|
+
var TID300Polyline$2 = utilities.TID300.Polyline;
|
|
1706
|
+
var RectangleRoi = /*#__PURE__*/function () {
|
|
1707
|
+
function RectangleRoi() {
|
|
1708
|
+
_classCallCheck(this, RectangleRoi);
|
|
1709
|
+
}
|
|
1710
|
+
_createClass(RectangleRoi, null, [{
|
|
1711
|
+
key: "getMeasurementData",
|
|
1712
|
+
value: function getMeasurementData(MeasurementGroup) {
|
|
1713
|
+
var _MeasurementReport$ge = MeasurementReport$1.getSetupMeasurementData(MeasurementGroup),
|
|
1714
|
+
defaultState = _MeasurementReport$ge.defaultState,
|
|
1715
|
+
SCOORDGroup = _MeasurementReport$ge.SCOORDGroup,
|
|
1716
|
+
NUMGroup = _MeasurementReport$ge.NUMGroup;
|
|
1717
|
+
var state = _objectSpread2(_objectSpread2({}, defaultState), {}, {
|
|
1718
|
+
toolType: RectangleRoi.toolType,
|
|
1719
|
+
handles: {
|
|
1720
|
+
start: {},
|
|
1721
|
+
end: {},
|
|
1722
|
+
textBox: {
|
|
1723
|
+
active: false,
|
|
1724
|
+
hasMoved: false,
|
|
1725
|
+
movesIndependently: false,
|
|
1726
|
+
drawnIndependently: true,
|
|
1727
|
+
allowedOutsideImage: true,
|
|
1728
|
+
hasBoundingBox: true
|
|
1729
|
+
},
|
|
1730
|
+
initialRotation: 0
|
|
1731
|
+
},
|
|
1732
|
+
cachedStats: {
|
|
1733
|
+
area: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : 0
|
|
1734
|
+
},
|
|
1735
|
+
color: undefined,
|
|
1736
|
+
invalidated: true
|
|
1737
|
+
});
|
|
1738
|
+
var _SCOORDGroup$GraphicD = _slicedToArray(SCOORDGroup.GraphicData, 6);
|
|
1739
|
+
state.handles.start.x = _SCOORDGroup$GraphicD[0];
|
|
1740
|
+
state.handles.start.y = _SCOORDGroup$GraphicD[1];
|
|
1741
|
+
_SCOORDGroup$GraphicD[2];
|
|
1742
|
+
_SCOORDGroup$GraphicD[3];
|
|
1743
|
+
state.handles.end.x = _SCOORDGroup$GraphicD[4];
|
|
1744
|
+
state.handles.end.y = _SCOORDGroup$GraphicD[5];
|
|
1745
|
+
return state;
|
|
1746
|
+
}
|
|
1747
|
+
}, {
|
|
1748
|
+
key: "getTID300RepresentationArguments",
|
|
1749
|
+
value: function getTID300RepresentationArguments(tool) {
|
|
1750
|
+
var finding = tool.finding,
|
|
1751
|
+
findingSites = tool.findingSites,
|
|
1752
|
+
_tool$cachedStats = tool.cachedStats,
|
|
1753
|
+
cachedStats = _tool$cachedStats === void 0 ? {} : _tool$cachedStats,
|
|
1754
|
+
handles = tool.handles;
|
|
1755
|
+
var start = handles.start,
|
|
1756
|
+
end = handles.end;
|
|
1757
|
+
var points = [start, {
|
|
1758
|
+
x: start.x,
|
|
1759
|
+
y: end.y
|
|
1760
|
+
}, end, {
|
|
1761
|
+
x: end.x,
|
|
1762
|
+
y: start.y
|
|
1763
|
+
}];
|
|
1764
|
+
var area = cachedStats.area,
|
|
1765
|
+
perimeter = cachedStats.perimeter;
|
|
1766
|
+
var trackingIdentifierTextValue = "cornerstoneTools@^4.0.0:RectangleRoi";
|
|
1767
|
+
return {
|
|
1768
|
+
points: points,
|
|
1769
|
+
area: area,
|
|
1770
|
+
perimeter: perimeter,
|
|
1771
|
+
trackingIdentifierTextValue: trackingIdentifierTextValue,
|
|
1772
|
+
finding: finding,
|
|
1773
|
+
findingSites: findingSites || []
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
}]);
|
|
1777
|
+
return RectangleRoi;
|
|
1778
|
+
}();
|
|
1779
|
+
RectangleRoi.toolType = "RectangleRoi";
|
|
1780
|
+
RectangleRoi.utilityToolType = "RectangleRoi";
|
|
1781
|
+
RectangleRoi.TID300Representation = TID300Polyline$2;
|
|
1782
|
+
RectangleRoi.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
1783
|
+
if (!TrackingIdentifier.includes(":")) {
|
|
1784
|
+
return false;
|
|
1785
|
+
}
|
|
1786
|
+
var _TrackingIdentifier$s = TrackingIdentifier.split(":"),
|
|
1787
|
+
_TrackingIdentifier$s2 = _slicedToArray(_TrackingIdentifier$s, 2),
|
|
1788
|
+
cornerstone4Tag = _TrackingIdentifier$s2[0],
|
|
1789
|
+
toolType = _TrackingIdentifier$s2[1];
|
|
1790
|
+
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
1791
|
+
return false;
|
|
1792
|
+
}
|
|
1793
|
+
return toolType === RectangleRoi.toolType;
|
|
1794
|
+
};
|
|
1795
|
+
MeasurementReport$1.registerTool(RectangleRoi);
|
|
1796
|
+
|
|
1797
|
+
var _utilities$orientatio$1 = utilities.orientation,
|
|
1798
|
+
rotateDirectionCosinesInPlane$1 = _utilities$orientatio$1.rotateDirectionCosinesInPlane,
|
|
1799
|
+
flipIOP$1 = _utilities$orientatio$1.flipImageOrientationPatient,
|
|
1800
|
+
flipMatrix2D$1 = _utilities$orientatio$1.flipMatrix2D,
|
|
1801
|
+
rotateMatrix902D$1 = _utilities$orientatio$1.rotateMatrix902D;
|
|
1802
|
+
var datasetToBlob = utilities.datasetToBlob,
|
|
1803
|
+
BitArray$2 = utilities.BitArray,
|
|
1804
|
+
DicomMessage$1 = utilities.DicomMessage,
|
|
1805
|
+
DicomMetaDictionary$2 = utilities.DicomMetaDictionary;
|
|
1806
|
+
var Normalizer$3 = normalizers.Normalizer;
|
|
1807
|
+
var SegmentationDerivation$2 = derivations.Segmentation;
|
|
1808
|
+
var Segmentation$5 = {
|
|
1809
|
+
generateSegmentation: generateSegmentation$3,
|
|
1810
|
+
generateToolState: generateToolState$3
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
*
|
|
1815
|
+
* @typedef {Object} BrushData
|
|
1816
|
+
* @property {Object} toolState - The cornerstoneTools global toolState.
|
|
1817
|
+
* @property {Object[]} segments - The cornerstoneTools segment metadata that corresponds to the
|
|
1818
|
+
* seriesInstanceUid.
|
|
1819
|
+
*/
|
|
1820
|
+
|
|
1821
|
+
/**
|
|
1822
|
+
* generateSegmentation - Generates cornerstoneTools brush data, given a stack of
|
|
1823
|
+
* imageIds, images and the cornerstoneTools brushData.
|
|
1824
|
+
*
|
|
1825
|
+
* @param {object[]} images An array of the cornerstone image objects.
|
|
1826
|
+
* @param {BrushData} brushData and object containing the brushData.
|
|
1827
|
+
* @returns {type} description
|
|
1828
|
+
*/
|
|
1829
|
+
function generateSegmentation$3(images, brushData) {
|
|
1830
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
1831
|
+
includeSliceSpacing: true
|
|
1832
|
+
};
|
|
1833
|
+
var toolState = brushData.toolState,
|
|
1834
|
+
segments = brushData.segments;
|
|
1835
|
+
|
|
1836
|
+
// Calculate the dimensions of the data cube.
|
|
1837
|
+
var image0 = images[0];
|
|
1838
|
+
var dims = {
|
|
1839
|
+
x: image0.columns,
|
|
1840
|
+
y: image0.rows,
|
|
1841
|
+
z: images.length
|
|
1842
|
+
};
|
|
1843
|
+
dims.xy = dims.x * dims.y;
|
|
1844
|
+
var numSegments = _getSegCount(seg, segments);
|
|
1845
|
+
if (!numSegments) {
|
|
1846
|
+
throw new Error("No segments to export!");
|
|
1847
|
+
}
|
|
1848
|
+
var isMultiframe = image0.imageId.includes("?frame");
|
|
1849
|
+
var seg = _createSegFromImages$1(images, isMultiframe, options);
|
|
1850
|
+
var _getNumberOfFramesPer = _getNumberOfFramesPerSegment(toolState, images, segments),
|
|
1851
|
+
referencedFramesPerSegment = _getNumberOfFramesPer.referencedFramesPerSegment,
|
|
1852
|
+
segmentIndicies = _getNumberOfFramesPer.segmentIndicies;
|
|
1853
|
+
var NumberOfFrames = 0;
|
|
1854
|
+
for (var i = 0; i < referencedFramesPerSegment.length; i++) {
|
|
1855
|
+
NumberOfFrames += referencedFramesPerSegment[i].length;
|
|
1856
|
+
}
|
|
1857
|
+
seg.setNumberOfFrames(NumberOfFrames);
|
|
1858
|
+
for (var _i = 0; _i < segmentIndicies.length; _i++) {
|
|
1859
|
+
var segmentIndex = segmentIndicies[_i];
|
|
1860
|
+
var referencedFrameIndicies = referencedFramesPerSegment[_i];
|
|
1861
|
+
|
|
1862
|
+
// Frame numbers start from 1.
|
|
1863
|
+
var referencedFrameNumbers = referencedFrameIndicies.map(function (element) {
|
|
1864
|
+
return element + 1;
|
|
1865
|
+
});
|
|
1866
|
+
var segment = segments[segmentIndex];
|
|
1867
|
+
seg.addSegment(segment, _extractCornerstoneToolsPixelData(segmentIndex, referencedFrameIndicies, toolState, images, dims), referencedFrameNumbers);
|
|
1868
|
+
}
|
|
1869
|
+
seg.bitPackPixelData();
|
|
1870
|
+
var segBlob = datasetToBlob(seg.dataset);
|
|
1242
1871
|
return segBlob;
|
|
1243
1872
|
}
|
|
1244
1873
|
function _extractCornerstoneToolsPixelData(segmentIndex, referencedFrames, toolState, images, dims) {
|
|
@@ -1316,8 +1945,8 @@ function _createSegFromImages$1(images, isMultiframe, options) {
|
|
|
1316
1945
|
datasets.push(_dataset);
|
|
1317
1946
|
}
|
|
1318
1947
|
}
|
|
1319
|
-
var multiframe = Normalizer$
|
|
1320
|
-
return new SegmentationDerivation$
|
|
1948
|
+
var multiframe = Normalizer$3.normalizeToDataset(datasets);
|
|
1949
|
+
return new SegmentationDerivation$2([multiframe], options);
|
|
1321
1950
|
}
|
|
1322
1951
|
|
|
1323
1952
|
/**
|
|
@@ -1330,11 +1959,11 @@ function _createSegFromImages$1(images, isMultiframe, options) {
|
|
|
1330
1959
|
* @returns {Object} The toolState and an object from which the
|
|
1331
1960
|
* segment metadata can be derived.
|
|
1332
1961
|
*/
|
|
1333
|
-
function generateToolState$
|
|
1962
|
+
function generateToolState$3(imageIds, arrayBuffer, metadataProvider) {
|
|
1334
1963
|
var dicomData = DicomMessage$1.readFile(arrayBuffer);
|
|
1335
1964
|
var dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
|
|
1336
1965
|
dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
|
|
1337
|
-
var multiframe = Normalizer$
|
|
1966
|
+
var multiframe = Normalizer$3.normalizeToDataset([dataset]);
|
|
1338
1967
|
var imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
|
|
1339
1968
|
if (!imagePlaneModule) {
|
|
1340
1969
|
console.warn("Insufficient metadata, imagePlaneModule missing.");
|
|
@@ -1449,7 +2078,7 @@ function addImageIdSpecificBrushToolState(toolState, imageId, segmentIndex, pixe
|
|
|
1449
2078
|
function getImageIdOfSourceImage(SourceImageSequence, imageIds, metadataProvider) {
|
|
1450
2079
|
var ReferencedSOPInstanceUID = SourceImageSequence.ReferencedSOPInstanceUID,
|
|
1451
2080
|
ReferencedFrameNumber = SourceImageSequence.ReferencedFrameNumber;
|
|
1452
|
-
return ReferencedFrameNumber ? getImageIdOfReferencedFrame$1(ReferencedSOPInstanceUID, ReferencedFrameNumber, imageIds, metadataProvider) : getImageIdOfReferencedSingleFramedSOPInstance
|
|
2081
|
+
return ReferencedFrameNumber ? getImageIdOfReferencedFrame$1(ReferencedSOPInstanceUID, ReferencedFrameNumber, imageIds, metadataProvider) : getImageIdOfReferencedSingleFramedSOPInstance(ReferencedSOPInstanceUID, imageIds, metadataProvider);
|
|
1453
2082
|
}
|
|
1454
2083
|
|
|
1455
2084
|
/**
|
|
@@ -1462,7 +2091,7 @@ function getImageIdOfSourceImage(SourceImageSequence, imageIds, metadataProvider
|
|
|
1462
2091
|
* from the cornerstone imageIds.
|
|
1463
2092
|
* @return {String} The imageId that corresponds to the sopInstanceUid.
|
|
1464
2093
|
*/
|
|
1465
|
-
function getImageIdOfReferencedSingleFramedSOPInstance
|
|
2094
|
+
function getImageIdOfReferencedSingleFramedSOPInstance(sopInstanceUid, imageIds, metadataProvider) {
|
|
1466
2095
|
return imageIds.find(function (imageId) {
|
|
1467
2096
|
var sopCommonModule = metadataProvider.get("sopCommonModule", imageId);
|
|
1468
2097
|
if (!sopCommonModule) {
|
|
@@ -1588,26 +2217,38 @@ function getSegmentMetadata$1(multiframe) {
|
|
|
1588
2217
|
};
|
|
1589
2218
|
}
|
|
1590
2219
|
|
|
2220
|
+
/**
|
|
2221
|
+
* Cornerstone adapters events
|
|
2222
|
+
*/
|
|
2223
|
+
var Events;
|
|
2224
|
+
(function (Events) {
|
|
2225
|
+
/**
|
|
2226
|
+
* Cornerstone segmentation load progress event
|
|
2227
|
+
*/
|
|
2228
|
+
Events["SEGMENTATION_LOAD_PROGRESS"] = "CORNERSTONE_ADAPTER_SEGMENTATION_LOAD_PROGRESS";
|
|
2229
|
+
})(Events || (Events = {}));
|
|
2230
|
+
var Events$1 = Events;
|
|
2231
|
+
|
|
2232
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
2233
|
+
__proto__: null,
|
|
2234
|
+
Events: Events$1
|
|
2235
|
+
});
|
|
2236
|
+
|
|
1591
2237
|
var _utilities$orientatio = utilities.orientation,
|
|
1592
2238
|
rotateDirectionCosinesInPlane = _utilities$orientatio.rotateDirectionCosinesInPlane,
|
|
1593
2239
|
flipIOP = _utilities$orientatio.flipImageOrientationPatient,
|
|
1594
2240
|
flipMatrix2D = _utilities$orientatio.flipMatrix2D,
|
|
1595
2241
|
rotateMatrix902D = _utilities$orientatio.rotateMatrix902D,
|
|
1596
2242
|
nearlyEqual = _utilities$orientatio.nearlyEqual;
|
|
1597
|
-
var
|
|
1598
|
-
BitArray$1 =
|
|
1599
|
-
DicomMessage =
|
|
1600
|
-
DicomMetaDictionary$1 =
|
|
1601
|
-
var Normalizer$
|
|
1602
|
-
var SegmentationDerivation = derivations.Segmentation;
|
|
2243
|
+
var datasetToDict = data.datasetToDict,
|
|
2244
|
+
BitArray$1 = data.BitArray,
|
|
2245
|
+
DicomMessage = data.DicomMessage,
|
|
2246
|
+
DicomMetaDictionary$1 = data.DicomMetaDictionary;
|
|
2247
|
+
var Normalizer$2 = normalizers.Normalizer;
|
|
2248
|
+
var SegmentationDerivation$1 = derivations.Segmentation;
|
|
1603
2249
|
var _utilities$compressio = utilities.compression,
|
|
1604
2250
|
encode = _utilities$compressio.encode,
|
|
1605
2251
|
decode = _utilities$compressio.decode;
|
|
1606
|
-
var Segmentation$2 = {
|
|
1607
|
-
generateSegmentation: generateSegmentation$1,
|
|
1608
|
-
generateToolState: generateToolState$1,
|
|
1609
|
-
fillSegmentation: fillSegmentation$1
|
|
1610
|
-
};
|
|
1611
2252
|
|
|
1612
2253
|
/**
|
|
1613
2254
|
*
|
|
@@ -1616,10 +2257,9 @@ var Segmentation$2 = {
|
|
|
1616
2257
|
* @property {Object[]} segments - The cornerstoneTools segment metadata that corresponds to the
|
|
1617
2258
|
* seriesInstanceUid.
|
|
1618
2259
|
*/
|
|
1619
|
-
|
|
1620
2260
|
var generateSegmentationDefaultOptions = {
|
|
1621
2261
|
includeSliceSpacing: true,
|
|
1622
|
-
rleEncode:
|
|
2262
|
+
rleEncode: false
|
|
1623
2263
|
};
|
|
1624
2264
|
|
|
1625
2265
|
/**
|
|
@@ -1632,7 +2272,7 @@ var generateSegmentationDefaultOptions = {
|
|
|
1632
2272
|
* @param {Object} userOptions Options to pass to the segmentation derivation and `fillSegmentation`.
|
|
1633
2273
|
* @returns {Blob}
|
|
1634
2274
|
*/
|
|
1635
|
-
function generateSegmentation$
|
|
2275
|
+
function generateSegmentation$2(images, inputLabelmaps3D) {
|
|
1636
2276
|
var userOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
1637
2277
|
var isMultiframe = images[0].imageId.includes("?frame");
|
|
1638
2278
|
var segmentation = _createSegFromImages(images, isMultiframe, userOptions);
|
|
@@ -1698,7 +2338,7 @@ function fillSegmentation$1(segmentation, inputLabelmaps3D) {
|
|
|
1698
2338
|
return element + 1;
|
|
1699
2339
|
});
|
|
1700
2340
|
var segmentMetadata = metadata[segmentIndex];
|
|
1701
|
-
var labelmaps =
|
|
2341
|
+
var labelmaps = _getLabelmapsFromReferencedFrameIndicies(labelmap3D, referencedFrameIndicies);
|
|
1702
2342
|
segmentation.addSegmentFromLabelmap(segmentMetadata, labelmaps, segmentIndex, referencedFrameNumbers);
|
|
1703
2343
|
}
|
|
1704
2344
|
}
|
|
@@ -1727,10 +2367,13 @@ function fillSegmentation$1(segmentation, inputLabelmaps3D) {
|
|
|
1727
2367
|
// If no rleEncoding, at least bitpack the data.
|
|
1728
2368
|
segmentation.bitPackPixelData();
|
|
1729
2369
|
}
|
|
1730
|
-
var
|
|
2370
|
+
var buffer = Buffer.from(datasetToDict(segmentation.dataset).write());
|
|
2371
|
+
var segBlob = new Blob([buffer], {
|
|
2372
|
+
type: "application/dicom"
|
|
2373
|
+
});
|
|
1731
2374
|
return segBlob;
|
|
1732
2375
|
}
|
|
1733
|
-
function
|
|
2376
|
+
function _getLabelmapsFromReferencedFrameIndicies(labelmap3D, referencedFrameIndicies) {
|
|
1734
2377
|
var labelmaps2D = labelmap3D.labelmaps2D;
|
|
1735
2378
|
var labelmaps = [];
|
|
1736
2379
|
for (var i = 0; i < referencedFrameIndicies.length; i++) {
|
|
@@ -1766,8 +2409,8 @@ function _createSegFromImages(images, isMultiframe, options) {
|
|
|
1766
2409
|
datasets.push(_dataset);
|
|
1767
2410
|
}
|
|
1768
2411
|
}
|
|
1769
|
-
var multiframe = Normalizer$
|
|
1770
|
-
return new SegmentationDerivation([multiframe], options);
|
|
2412
|
+
var multiframe = Normalizer$2.normalizeToDataset(datasets);
|
|
2413
|
+
return new SegmentationDerivation$1([multiframe], options);
|
|
1771
2414
|
}
|
|
1772
2415
|
|
|
1773
2416
|
/**
|
|
@@ -1777,8 +2420,7 @@ function _createSegFromImages(images, isMultiframe, options) {
|
|
|
1777
2420
|
* @param {string[]} imageIds - An array of the imageIds.
|
|
1778
2421
|
* @param {ArrayBuffer} arrayBuffer - The SEG arrayBuffer.
|
|
1779
2422
|
* @param {*} metadataProvider.
|
|
1780
|
-
* @param {
|
|
1781
|
-
* @param {number} tolerance - default value 1.e-3.
|
|
2423
|
+
* @param {obj} options - Options object.
|
|
1782
2424
|
*
|
|
1783
2425
|
* @return {[]ArrayBuffer}a list of array buffer for each labelMap
|
|
1784
2426
|
* @return {Object} an object from which the segment metadata can be derived
|
|
@@ -1786,83 +2428,9 @@ function _createSegFromImages(images, isMultiframe, options) {
|
|
|
1786
2428
|
* @return {[][][]} 3D list containing the track of segments per frame for each labelMap
|
|
1787
2429
|
* (available only for the overlapping case).
|
|
1788
2430
|
*/
|
|
1789
|
-
function generateToolState$
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
var dicomData = DicomMessage.readFile(arrayBuffer);
|
|
1793
|
-
var dataset = DicomMetaDictionary$1.naturalizeDataset(dicomData.dict);
|
|
1794
|
-
dataset._meta = DicomMetaDictionary$1.namifyDataset(dicomData.meta);
|
|
1795
|
-
var multiframe = Normalizer$1.normalizeToDataset([dataset]);
|
|
1796
|
-
var imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
|
|
1797
|
-
var generalSeriesModule = metadataProvider.get("generalSeriesModule", imageIds[0]);
|
|
1798
|
-
var SeriesInstanceUID = generalSeriesModule.seriesInstanceUID;
|
|
1799
|
-
if (!imagePlaneModule) {
|
|
1800
|
-
console.warn("Insufficient metadata, imagePlaneModule missing.");
|
|
1801
|
-
}
|
|
1802
|
-
var ImageOrientationPatient = Array.isArray(imagePlaneModule.rowCosines) ? [].concat(_toConsumableArray(imagePlaneModule.rowCosines), _toConsumableArray(imagePlaneModule.columnCosines)) : [imagePlaneModule.rowCosines.x, imagePlaneModule.rowCosines.y, imagePlaneModule.rowCosines.z, imagePlaneModule.columnCosines.x, imagePlaneModule.columnCosines.y, imagePlaneModule.columnCosines.z];
|
|
1803
|
-
|
|
1804
|
-
// Get IOP from ref series, compute supported orientations:
|
|
1805
|
-
var validOrientations = getValidOrientations(ImageOrientationPatient);
|
|
1806
|
-
var sliceLength = multiframe.Columns * multiframe.Rows;
|
|
1807
|
-
var segMetadata = getSegmentMetadata(multiframe, SeriesInstanceUID);
|
|
1808
|
-
var TransferSyntaxUID = multiframe._meta.TransferSyntaxUID.Value[0];
|
|
1809
|
-
var pixelData;
|
|
1810
|
-
if (TransferSyntaxUID === "1.2.840.10008.1.2.5") {
|
|
1811
|
-
var rleEncodedFrames = Array.isArray(multiframe.PixelData) ? multiframe.PixelData : [multiframe.PixelData];
|
|
1812
|
-
pixelData = decode(rleEncodedFrames, multiframe.Rows, multiframe.Columns);
|
|
1813
|
-
if (multiframe.BitsStored === 1) {
|
|
1814
|
-
console.warn("No implementation for rle + bitbacking.");
|
|
1815
|
-
return;
|
|
1816
|
-
}
|
|
1817
|
-
} else {
|
|
1818
|
-
pixelData = unpackPixelData(multiframe);
|
|
1819
|
-
if (!pixelData) {
|
|
1820
|
-
throw new Error("Fractional segmentations are not yet supported");
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
var orientation = checkOrientation(multiframe, validOrientations, [imagePlaneModule.rows, imagePlaneModule.columns, imageIds.length], tolerance);
|
|
1824
|
-
var overlapping = false;
|
|
1825
|
-
if (!skipOverlapping) {
|
|
1826
|
-
overlapping = checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance);
|
|
1827
|
-
}
|
|
1828
|
-
var insertFunction;
|
|
1829
|
-
switch (orientation) {
|
|
1830
|
-
case "Planar":
|
|
1831
|
-
if (overlapping) {
|
|
1832
|
-
insertFunction = insertOverlappingPixelDataPlanar;
|
|
1833
|
-
} else {
|
|
1834
|
-
insertFunction = insertPixelDataPlanar;
|
|
1835
|
-
}
|
|
1836
|
-
break;
|
|
1837
|
-
case "Perpendicular":
|
|
1838
|
-
//insertFunction = insertPixelDataPerpendicular;
|
|
1839
|
-
throw new Error("Segmentations orthogonal to the acquisition plane of the source data are not yet supported.");
|
|
1840
|
-
case "Oblique":
|
|
1841
|
-
throw new Error("Segmentations oblique to the acquisition plane of the source data are not yet supported.");
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
/* if SEGs are overlapping:
|
|
1845
|
-
1) the labelmapBuffer will contain M volumes which have non-overlapping segments;
|
|
1846
|
-
2) segmentsOnFrame will have M * numberOfFrames values to track in which labelMap are the segments;
|
|
1847
|
-
3) insertFunction will return the number of LabelMaps
|
|
1848
|
-
4) generateToolState return is an array*/
|
|
1849
|
-
|
|
1850
|
-
var segmentsOnFrameArray = [];
|
|
1851
|
-
segmentsOnFrameArray[0] = [];
|
|
1852
|
-
var segmentsOnFrame = [];
|
|
1853
|
-
var arrayBufferLength = sliceLength * imageIds.length * 2; // 2 bytes per label voxel in cst4.
|
|
1854
|
-
var labelmapBufferArray = [];
|
|
1855
|
-
labelmapBufferArray[0] = new ArrayBuffer(arrayBufferLength);
|
|
1856
|
-
insertFunction(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance);
|
|
1857
|
-
return {
|
|
1858
|
-
labelmapBufferArray: labelmapBufferArray,
|
|
1859
|
-
segMetadata: segMetadata,
|
|
1860
|
-
segmentsOnFrame: segmentsOnFrame,
|
|
1861
|
-
segmentsOnFrameArray: segmentsOnFrameArray
|
|
1862
|
-
};
|
|
1863
|
-
}
|
|
1864
|
-
|
|
1865
|
-
// function insertPixelDataPerpendicular(
|
|
2431
|
+
function generateToolState$2(_x, _x2, _x3, _x4) {
|
|
2432
|
+
return _generateToolState.apply(this, arguments);
|
|
2433
|
+
} // function insertPixelDataPerpendicular(
|
|
1866
2434
|
// segmentsOnFrame,
|
|
1867
2435
|
// labelmapBuffer,
|
|
1868
2436
|
// pixelData,
|
|
@@ -1877,30 +2445,23 @@ function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1877
2445
|
// Rows,
|
|
1878
2446
|
// Columns
|
|
1879
2447
|
// } = multiframe;
|
|
1880
|
-
|
|
1881
2448
|
// const firstImagePlaneModule = metadataProvider.get(
|
|
1882
2449
|
// "imagePlaneModule",
|
|
1883
2450
|
// imageIds[0]
|
|
1884
2451
|
// );
|
|
1885
|
-
|
|
1886
2452
|
// const lastImagePlaneModule = metadataProvider.get(
|
|
1887
2453
|
// "imagePlaneModule",
|
|
1888
2454
|
// imageIds[imageIds.length - 1]
|
|
1889
2455
|
// );
|
|
1890
|
-
|
|
1891
2456
|
// console.log(firstImagePlaneModule);
|
|
1892
2457
|
// console.log(lastImagePlaneModule);
|
|
1893
|
-
|
|
1894
2458
|
// const corners = [
|
|
1895
2459
|
// ...getCorners(firstImagePlaneModule),
|
|
1896
2460
|
// ...getCorners(lastImagePlaneModule)
|
|
1897
2461
|
// ];
|
|
1898
|
-
|
|
1899
2462
|
// console.log(`corners:`);
|
|
1900
2463
|
// console.log(corners);
|
|
1901
|
-
|
|
1902
2464
|
// const indexToWorld = mat4.create();
|
|
1903
|
-
|
|
1904
2465
|
// const ippFirstFrame = firstImagePlaneModule.imagePositionPatient;
|
|
1905
2466
|
// const rowCosines = Array.isArray(firstImagePlaneModule.rowCosines)
|
|
1906
2467
|
// ? [...firstImagePlaneModule.rowCosines]
|
|
@@ -1909,7 +2470,6 @@ function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1909
2470
|
// firstImagePlaneModule.rowCosines.y,
|
|
1910
2471
|
// firstImagePlaneModule.rowCosines.z
|
|
1911
2472
|
// ];
|
|
1912
|
-
|
|
1913
2473
|
// const columnCosines = Array.isArray(firstImagePlaneModule.columnCosines)
|
|
1914
2474
|
// ? [...firstImagePlaneModule.columnCosines]
|
|
1915
2475
|
// : [
|
|
@@ -1917,9 +2477,7 @@ function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1917
2477
|
// firstImagePlaneModule.columnCosines.y,
|
|
1918
2478
|
// firstImagePlaneModule.columnCosines.z
|
|
1919
2479
|
// ];
|
|
1920
|
-
|
|
1921
2480
|
// const { pixelSpacing } = firstImagePlaneModule;
|
|
1922
|
-
|
|
1923
2481
|
// mat4.set(
|
|
1924
2482
|
// indexToWorld,
|
|
1925
2483
|
// // Column 1
|
|
@@ -1943,50 +2501,36 @@ function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1943
2501
|
// 0,
|
|
1944
2502
|
// 1
|
|
1945
2503
|
// );
|
|
1946
|
-
|
|
1947
2504
|
// // TODO -> Get origin and (x,y,z) increments to build a translation matrix:
|
|
1948
2505
|
// // TODO -> Equation C.7.6.2.1-1
|
|
1949
|
-
|
|
1950
2506
|
// // | cx*di rx* Xx 0 | |x|
|
|
1951
2507
|
// // | cy*di ry Xy 0 | |y|
|
|
1952
2508
|
// // | cz*di rz Xz 0 | |z|
|
|
1953
2509
|
// // | tx ty tz 1 | |1|
|
|
1954
|
-
|
|
1955
2510
|
// // const [
|
|
1956
2511
|
// // 0, 0 , 0 , 0,
|
|
1957
2512
|
// // 0, 0 , 0 , 0,
|
|
1958
2513
|
// // 0, 0 , 0 , 0,
|
|
1959
2514
|
// // ipp[0], ipp[1] , ipp[2] , 1,
|
|
1960
2515
|
// // ]
|
|
1961
|
-
|
|
1962
2516
|
// // Each frame:
|
|
1963
|
-
|
|
1964
2517
|
// // Find which corner the first voxel lines up with (one of 8 corners.)
|
|
1965
|
-
|
|
1966
2518
|
// // Find how i,j,k orient with respect to source volume.
|
|
1967
2519
|
// // Go through each frame, find location in source to start, and whether to increment +/ix,+/-y,+/-z
|
|
1968
2520
|
// // through each voxel.
|
|
1969
|
-
|
|
1970
2521
|
// // [1,0,0,0,1,0]
|
|
1971
|
-
|
|
1972
2522
|
// // const [
|
|
1973
|
-
|
|
1974
2523
|
// // ]
|
|
1975
|
-
|
|
1976
2524
|
// // Invert transformation matrix to get worldToIndex
|
|
1977
|
-
|
|
1978
2525
|
// // Apply world to index on each point to fill up the matrix.
|
|
1979
|
-
|
|
1980
2526
|
// // const sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence
|
|
1981
2527
|
// // ? SharedFunctionalGroupsSequence.PlaneOrientationSequence
|
|
1982
2528
|
// // .ImageOrientationPatient
|
|
1983
2529
|
// // : undefined;
|
|
1984
2530
|
// // const sliceLength = Columns * Rows;
|
|
1985
2531
|
// }
|
|
1986
|
-
|
|
1987
2532
|
// function getCorners(imagePlaneModule) {
|
|
1988
2533
|
// // console.log(imagePlaneModule);
|
|
1989
|
-
|
|
1990
2534
|
// const {
|
|
1991
2535
|
// rows,
|
|
1992
2536
|
// columns,
|
|
@@ -1996,22 +2540,18 @@ function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
|
1996
2540
|
// rowPixelSpacing,
|
|
1997
2541
|
// columnPixelSpacing
|
|
1998
2542
|
// } = imagePlaneModule;
|
|
1999
|
-
|
|
2000
2543
|
// const rowLength = columns * columnPixelSpacing;
|
|
2001
2544
|
// const columnLength = rows * rowPixelSpacing;
|
|
2002
|
-
|
|
2003
2545
|
// const entireRowVector = [
|
|
2004
2546
|
// rowLength * columnCosines[0],
|
|
2005
2547
|
// rowLength * columnCosines[1],
|
|
2006
2548
|
// rowLength * columnCosines[2]
|
|
2007
2549
|
// ];
|
|
2008
|
-
|
|
2009
2550
|
// const entireColumnVector = [
|
|
2010
2551
|
// columnLength * rowCosines[0],
|
|
2011
2552
|
// columnLength * rowCosines[1],
|
|
2012
2553
|
// columnLength * rowCosines[2]
|
|
2013
2554
|
// ];
|
|
2014
|
-
|
|
2015
2555
|
// const topLeft = [ipp[0], ipp[1], ipp[2]];
|
|
2016
2556
|
// const topRight = [
|
|
2017
2557
|
// topLeft[0] + entireRowVector[0],
|
|
@@ -2023,29 +2563,160 @@ function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
|
2023
2563
|
// topLeft[1] + entireColumnVector[1],
|
|
2024
2564
|
// topLeft[2] + entireColumnVector[2]
|
|
2025
2565
|
// ];
|
|
2026
|
-
|
|
2027
2566
|
// const bottomRight = [
|
|
2028
2567
|
// bottomLeft[0] + entireRowVector[0],
|
|
2029
2568
|
// bottomLeft[1] + entireRowVector[1],
|
|
2030
2569
|
// bottomLeft[2] + entireRowVector[2]
|
|
2031
2570
|
// ];
|
|
2032
|
-
|
|
2033
2571
|
// return [topLeft, topRight, bottomLeft, bottomRight];
|
|
2034
2572
|
// }
|
|
2035
|
-
|
|
2036
2573
|
/**
|
|
2037
2574
|
* Find the reference frame of the segmentation frame in the source data.
|
|
2038
2575
|
*
|
|
2039
2576
|
* @param {Object} multiframe dicom metadata
|
|
2040
2577
|
* @param {Int} frameSegment frame dicom index
|
|
2041
2578
|
* @param {String[]} imageIds A list of imageIds.
|
|
2042
|
-
* @param {Object}
|
|
2043
|
-
* metadata from imageIds.
|
|
2579
|
+
* @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUID to imageId
|
|
2044
2580
|
* @param {Float} tolerance The tolerance parameter
|
|
2045
2581
|
*
|
|
2046
2582
|
* @returns {String} Returns the imageId
|
|
2047
2583
|
*/
|
|
2048
|
-
function
|
|
2584
|
+
function _generateToolState() {
|
|
2585
|
+
_generateToolState = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(imageIds, arrayBuffer, metadataProvider, options) {
|
|
2586
|
+
var _options$skipOverlapp, skipOverlapping, _options$tolerance, tolerance, _options$TypedArrayCo, TypedArrayConstructor, _options$maxBytesPerC, maxBytesPerChunk, eventTarget, triggerEvent, dicomData, dataset, multiframe, imagePlaneModule, generalSeriesModule, SeriesInstanceUID, ImageOrientationPatient, validOrientations, sliceLength, segMetadata, TransferSyntaxUID, pixelData, pixelDataChunks, rleEncodedFrames, orientation, sopUIDImageIdIndexMap, overlapping, insertFunction, segmentsOnFrameArray, segmentsOnFrame, arrayBufferLength, labelmapBufferArray, imageIdMaps, segmentsPixelIndices, centroidXYZ;
|
|
2587
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
2588
|
+
while (1) switch (_context.prev = _context.next) {
|
|
2589
|
+
case 0:
|
|
2590
|
+
_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
|
+
dicomData = DicomMessage.readFile(arrayBuffer);
|
|
2592
|
+
dataset = DicomMetaDictionary$1.naturalizeDataset(dicomData.dict);
|
|
2593
|
+
dataset._meta = DicomMetaDictionary$1.namifyDataset(dicomData.meta);
|
|
2594
|
+
multiframe = Normalizer$2.normalizeToDataset([dataset]);
|
|
2595
|
+
imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
|
|
2596
|
+
generalSeriesModule = metadataProvider.get("generalSeriesModule", imageIds[0]);
|
|
2597
|
+
SeriesInstanceUID = generalSeriesModule.seriesInstanceUID;
|
|
2598
|
+
if (!imagePlaneModule) {
|
|
2599
|
+
console.warn("Insufficient metadata, imagePlaneModule missing.");
|
|
2600
|
+
}
|
|
2601
|
+
ImageOrientationPatient = Array.isArray(imagePlaneModule.rowCosines) ? [].concat(_toConsumableArray(imagePlaneModule.rowCosines), _toConsumableArray(imagePlaneModule.columnCosines)) : [imagePlaneModule.rowCosines.x, imagePlaneModule.rowCosines.y, imagePlaneModule.rowCosines.z, imagePlaneModule.columnCosines.x, imagePlaneModule.columnCosines.y, imagePlaneModule.columnCosines.z]; // Get IOP from ref series, compute supported orientations:
|
|
2602
|
+
validOrientations = getValidOrientations(ImageOrientationPatient);
|
|
2603
|
+
sliceLength = multiframe.Columns * multiframe.Rows;
|
|
2604
|
+
segMetadata = getSegmentMetadata(multiframe, SeriesInstanceUID);
|
|
2605
|
+
TransferSyntaxUID = multiframe._meta.TransferSyntaxUID.Value[0];
|
|
2606
|
+
if (!(TransferSyntaxUID === "1.2.840.10008.1.2.5")) {
|
|
2607
|
+
_context.next = 23;
|
|
2608
|
+
break;
|
|
2609
|
+
}
|
|
2610
|
+
rleEncodedFrames = Array.isArray(multiframe.PixelData) ? multiframe.PixelData : [multiframe.PixelData];
|
|
2611
|
+
pixelData = decode(rleEncodedFrames, multiframe.Rows, multiframe.Columns);
|
|
2612
|
+
if (!(multiframe.BitsStored === 1)) {
|
|
2613
|
+
_context.next = 20;
|
|
2614
|
+
break;
|
|
2615
|
+
}
|
|
2616
|
+
console.warn("No implementation for rle + bitbacking.");
|
|
2617
|
+
return _context.abrupt("return");
|
|
2618
|
+
case 20:
|
|
2619
|
+
// Todo: need to test this with rle data
|
|
2620
|
+
pixelDataChunks = [pixelData];
|
|
2621
|
+
_context.next = 26;
|
|
2622
|
+
break;
|
|
2623
|
+
case 23:
|
|
2624
|
+
pixelDataChunks = unpackPixelData(multiframe, {
|
|
2625
|
+
maxBytesPerChunk: maxBytesPerChunk
|
|
2626
|
+
});
|
|
2627
|
+
if (pixelDataChunks) {
|
|
2628
|
+
_context.next = 26;
|
|
2629
|
+
break;
|
|
2630
|
+
}
|
|
2631
|
+
throw new Error("Fractional segmentations are not yet supported");
|
|
2632
|
+
case 26:
|
|
2633
|
+
orientation = checkOrientation(multiframe, validOrientations, [imagePlaneModule.rows, imagePlaneModule.columns, imageIds.length], tolerance); // Pre-compute the sop UID to imageId index map so that in the for loop
|
|
2634
|
+
// we don't have to call metadataProvider.get() for each imageId over
|
|
2635
|
+
// and over again.
|
|
2636
|
+
sopUIDImageIdIndexMap = imageIds.reduce(function (acc, imageId) {
|
|
2637
|
+
var _metadataProvider$get = metadataProvider.get("generalImageModule", imageId),
|
|
2638
|
+
sopInstanceUid = _metadataProvider$get.sopInstanceUid;
|
|
2639
|
+
acc[sopInstanceUid] = imageId;
|
|
2640
|
+
return acc;
|
|
2641
|
+
}, {});
|
|
2642
|
+
overlapping = false;
|
|
2643
|
+
if (!skipOverlapping) {
|
|
2644
|
+
overlapping = checkSEGsOverlapping(pixelDataChunks, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, sopUIDImageIdIndexMap);
|
|
2645
|
+
}
|
|
2646
|
+
_context.t0 = orientation;
|
|
2647
|
+
_context.next = _context.t0 === "Planar" ? 33 : _context.t0 === "Perpendicular" ? 35 : _context.t0 === "Oblique" ? 36 : 37;
|
|
2648
|
+
break;
|
|
2649
|
+
case 33:
|
|
2650
|
+
if (overlapping) {
|
|
2651
|
+
insertFunction = insertOverlappingPixelDataPlanar;
|
|
2652
|
+
} else {
|
|
2653
|
+
insertFunction = insertPixelDataPlanar;
|
|
2654
|
+
}
|
|
2655
|
+
return _context.abrupt("break", 37);
|
|
2656
|
+
case 35:
|
|
2657
|
+
throw new Error("Segmentations orthogonal to the acquisition plane of the source data are not yet supported.");
|
|
2658
|
+
case 36:
|
|
2659
|
+
throw new Error("Segmentations oblique to the acquisition plane of the source data are not yet supported.");
|
|
2660
|
+
case 37:
|
|
2661
|
+
/* if SEGs are overlapping:
|
|
2662
|
+
1) the labelmapBuffer will contain M volumes which have non-overlapping segments;
|
|
2663
|
+
2) segmentsOnFrame will have M * numberOfFrames values to track in which labelMap are the segments;
|
|
2664
|
+
3) insertFunction will return the number of LabelMaps
|
|
2665
|
+
4) generateToolState return is an array*/
|
|
2666
|
+
segmentsOnFrameArray = [];
|
|
2667
|
+
segmentsOnFrameArray[0] = [];
|
|
2668
|
+
segmentsOnFrame = [];
|
|
2669
|
+
arrayBufferLength = sliceLength * imageIds.length * TypedArrayConstructor.BYTES_PER_ELEMENT;
|
|
2670
|
+
labelmapBufferArray = [];
|
|
2671
|
+
labelmapBufferArray[0] = new ArrayBuffer(arrayBufferLength);
|
|
2672
|
+
|
|
2673
|
+
// Precompute the indices and metadata so that we don't have to call
|
|
2674
|
+
// a function for each imageId in the for loop.
|
|
2675
|
+
imageIdMaps = imageIds.reduce(function (acc, curr, index) {
|
|
2676
|
+
acc.indices[curr] = index;
|
|
2677
|
+
acc.metadata[curr] = metadataProvider.get("instance", curr);
|
|
2678
|
+
return acc;
|
|
2679
|
+
}, {
|
|
2680
|
+
indices: {},
|
|
2681
|
+
metadata: {}
|
|
2682
|
+
}); // This is the centroid calculation for each segment Index, the data structure
|
|
2683
|
+
// is a Map with key = segmentIndex and value = {imageIdIndex: centroid, ...}
|
|
2684
|
+
// later on we will use this data structure to calculate the centroid of the
|
|
2685
|
+
// segment in the labelmapBuffer
|
|
2686
|
+
segmentsPixelIndices = new Map();
|
|
2687
|
+
_context.next = 47;
|
|
2688
|
+
return insertFunction(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelDataChunks, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, segmentsPixelIndices, sopUIDImageIdIndexMap, imageIdMaps, eventTarget, triggerEvent);
|
|
2689
|
+
case 47:
|
|
2690
|
+
// calculate the centroid of each segment
|
|
2691
|
+
centroidXYZ = new Map();
|
|
2692
|
+
segmentsPixelIndices.forEach(function (imageIdIndexBufferIndex, segmentIndex) {
|
|
2693
|
+
var _calculateCentroid = calculateCentroid(imageIdIndexBufferIndex, multiframe),
|
|
2694
|
+
xAcc = _calculateCentroid.xAcc,
|
|
2695
|
+
yAcc = _calculateCentroid.yAcc,
|
|
2696
|
+
zAcc = _calculateCentroid.zAcc,
|
|
2697
|
+
count = _calculateCentroid.count;
|
|
2698
|
+
centroidXYZ.set(segmentIndex, {
|
|
2699
|
+
x: Math.floor(xAcc / count),
|
|
2700
|
+
y: Math.floor(yAcc / count),
|
|
2701
|
+
z: Math.floor(zAcc / count)
|
|
2702
|
+
});
|
|
2703
|
+
});
|
|
2704
|
+
return _context.abrupt("return", {
|
|
2705
|
+
labelmapBufferArray: labelmapBufferArray,
|
|
2706
|
+
segMetadata: segMetadata,
|
|
2707
|
+
segmentsOnFrame: segmentsOnFrame,
|
|
2708
|
+
segmentsOnFrameArray: segmentsOnFrameArray,
|
|
2709
|
+
centroids: centroidXYZ
|
|
2710
|
+
});
|
|
2711
|
+
case 50:
|
|
2712
|
+
case "end":
|
|
2713
|
+
return _context.stop();
|
|
2714
|
+
}
|
|
2715
|
+
}, _callee);
|
|
2716
|
+
}));
|
|
2717
|
+
return _generateToolState.apply(this, arguments);
|
|
2718
|
+
}
|
|
2719
|
+
function findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap) {
|
|
2049
2720
|
var imageId = undefined;
|
|
2050
2721
|
if (!multiframe) {
|
|
2051
2722
|
return imageId;
|
|
@@ -2085,7 +2756,7 @@ function findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadata
|
|
|
2085
2756
|
}
|
|
2086
2757
|
}
|
|
2087
2758
|
if (frameSourceImageSequence) {
|
|
2088
|
-
imageId =
|
|
2759
|
+
imageId = getImageIdOfSourceImageBySourceImageSequence(frameSourceImageSequence, sopUIDImageIdIndexMap);
|
|
2089
2760
|
}
|
|
2090
2761
|
if (imageId === undefined && ReferencedSeriesSequence) {
|
|
2091
2762
|
var referencedSeriesSequence = Array.isArray(ReferencedSeriesSequence) ? ReferencedSeriesSequence[0] : ReferencedSeriesSequence;
|
|
@@ -2100,7 +2771,7 @@ function findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadata
|
|
|
2100
2771
|
* @returns {boolean} Returns a flag if segmentations overlapping
|
|
2101
2772
|
*/
|
|
2102
2773
|
|
|
2103
|
-
function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance) {
|
|
2774
|
+
function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, sopUIDImageIdIndexMap) {
|
|
2104
2775
|
var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
|
|
2105
2776
|
PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
|
|
2106
2777
|
SegmentSequence = multiframe.SegmentSequence,
|
|
@@ -2127,7 +2798,7 @@ function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations
|
|
|
2127
2798
|
console.warn("Could not retrieve the segment index for frame segment " + frameSegment + ", skipping this frame.");
|
|
2128
2799
|
return "continue";
|
|
2129
2800
|
}
|
|
2130
|
-
var imageId = findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadataProvider, tolerance);
|
|
2801
|
+
var imageId = findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
2131
2802
|
if (!imageId) {
|
|
2132
2803
|
console.warn("Image not present in stack, can't import frame : " + frameSegment + ".");
|
|
2133
2804
|
return "continue";
|
|
@@ -2155,12 +2826,13 @@ function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations
|
|
|
2155
2826
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
2156
2827
|
var _step$value = _slicedToArray(_step.value, 2),
|
|
2157
2828
|
role = _step$value[1];
|
|
2158
|
-
var temp2DArray = new
|
|
2829
|
+
var temp2DArray = new TypedArrayConstructor(sliceLength).fill(0);
|
|
2159
2830
|
for (var i = 0; i < role.length; ++i) {
|
|
2160
2831
|
var _frameSegment = role[i];
|
|
2161
2832
|
var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[_frameSegment];
|
|
2162
2833
|
var ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
|
|
2163
|
-
var
|
|
2834
|
+
var view = readFromUnpackedChunks(pixelData, _frameSegment * sliceLength, sliceLength);
|
|
2835
|
+
var pixelDataI2D = ndarray(view, [Rows, Columns]);
|
|
2164
2836
|
var alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
2165
2837
|
if (!alignedPixelDataI) {
|
|
2166
2838
|
console.warn("Individual SEG frames are out of plane with respect to the first SEG frame, this is not yet supported, skipping this frame.");
|
|
@@ -2184,15 +2856,14 @@ function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations
|
|
|
2184
2856
|
}
|
|
2185
2857
|
return false;
|
|
2186
2858
|
}
|
|
2187
|
-
function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance) {
|
|
2859
|
+
function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, segmentsPixelIndices, sopUIDImageIdIndexMap) {
|
|
2188
2860
|
var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
|
|
2189
2861
|
PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
|
|
2190
2862
|
Rows = multiframe.Rows,
|
|
2191
2863
|
Columns = multiframe.Columns;
|
|
2192
2864
|
var sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence ? SharedFunctionalGroupsSequence.PlaneOrientationSequence.ImageOrientationPatient : undefined;
|
|
2193
2865
|
var sliceLength = Columns * Rows;
|
|
2194
|
-
var arrayBufferLength = sliceLength * imageIds.length *
|
|
2195
|
-
|
|
2866
|
+
var arrayBufferLength = sliceLength * imageIds.length * TypedArrayConstructor.BYTES_PER_ELEMENT;
|
|
2196
2867
|
// indicate the number of labelMaps
|
|
2197
2868
|
var M = 1;
|
|
2198
2869
|
|
|
@@ -2225,12 +2896,17 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
|
|
|
2225
2896
|
return "continue";
|
|
2226
2897
|
}
|
|
2227
2898
|
var ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
|
|
2228
|
-
|
|
2899
|
+
|
|
2900
|
+
// Since we moved to the chunks approach, we need to read the data
|
|
2901
|
+
// and handle scenarios where the portion of data is in one chunk
|
|
2902
|
+
// and the other portion is in another chunk
|
|
2903
|
+
var view = readFromUnpackedChunks(pixelData, _i2 * sliceLength, sliceLength);
|
|
2904
|
+
var pixelDataI2D = ndarray(view, [Rows, Columns]);
|
|
2229
2905
|
var alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
2230
2906
|
if (!alignedPixelDataI) {
|
|
2231
2907
|
throw new Error("Individual SEG frames are out of plane with respect to the first SEG frame. " + "This is not yet supported. Aborting segmentation loading.");
|
|
2232
2908
|
}
|
|
2233
|
-
var imageId = findReferenceSourceImageId(multiframe, _i2, imageIds, metadataProvider, tolerance);
|
|
2909
|
+
var imageId = findReferenceSourceImageId(multiframe, _i2, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
2234
2910
|
if (!imageId) {
|
|
2235
2911
|
console.warn("Image not present in stack, can't import frame : " + _i2 + ".");
|
|
2236
2912
|
i = _i2;
|
|
@@ -2243,9 +2919,8 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
|
|
|
2243
2919
|
var imageIdIndex = imageIds.findIndex(function (element) {
|
|
2244
2920
|
return element === imageId;
|
|
2245
2921
|
});
|
|
2246
|
-
var byteOffset = sliceLength *
|
|
2247
|
-
|
|
2248
|
-
var labelmap2DView = new Uint16Array(tempBuffer, byteOffset, sliceLength);
|
|
2922
|
+
var byteOffset = sliceLength * imageIdIndex * TypedArrayConstructor.BYTES_PER_ELEMENT;
|
|
2923
|
+
var labelmap2DView = new TypedArrayConstructor(tempBuffer, byteOffset, sliceLength);
|
|
2249
2924
|
var data = alignedPixelDataI.data;
|
|
2250
2925
|
var segmentOnFrame = false;
|
|
2251
2926
|
for (var j = 0, len = alignedPixelDataI.data.length; j < len; ++j) {
|
|
@@ -2298,60 +2973,93 @@ var getSegmentIndex = function getSegmentIndex(multiframe, frame) {
|
|
|
2298
2973
|
var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[frame];
|
|
2299
2974
|
return PerFrameFunctionalGroups && PerFrameFunctionalGroups.SegmentIdentificationSequence ? PerFrameFunctionalGroups.SegmentIdentificationSequence.ReferencedSegmentNumber : SharedFunctionalGroupsSequence.SegmentIdentificationSequence ? SharedFunctionalGroupsSequence.SegmentIdentificationSequence.ReferencedSegmentNumber : undefined;
|
|
2300
2975
|
};
|
|
2301
|
-
function insertPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance) {
|
|
2976
|
+
function insertPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, segmentsPixelIndices, sopUIDImageIdIndexMap, imageIdMaps, eventTarget, triggerEvent) {
|
|
2302
2977
|
var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
|
|
2303
2978
|
PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
|
|
2304
2979
|
Rows = multiframe.Rows,
|
|
2305
2980
|
Columns = multiframe.Columns;
|
|
2306
2981
|
var sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence ? SharedFunctionalGroupsSequence.PlaneOrientationSequence.ImageOrientationPatient : undefined;
|
|
2307
2982
|
var sliceLength = Columns * Rows;
|
|
2308
|
-
var
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
}
|
|
2329
|
-
var imageIdIndex = imageIds.findIndex(function (element) {
|
|
2330
|
-
return element === imageId;
|
|
2331
|
-
});
|
|
2332
|
-
var byteOffset = sliceLength * 2 * imageIdIndex; // 2 bytes/pixel
|
|
2333
|
-
|
|
2334
|
-
var labelmap2DView = new Uint16Array(labelmapBufferArray[0], byteOffset, sliceLength);
|
|
2335
|
-
var data = alignedPixelDataI.data;
|
|
2336
|
-
for (var j = 0, len = alignedPixelDataI.data.length; j < len; ++j) {
|
|
2337
|
-
if (data[j]) {
|
|
2338
|
-
for (var x = j; x < len; ++x) {
|
|
2339
|
-
if (data[x]) {
|
|
2340
|
-
labelmap2DView[x] = segmentIndex;
|
|
2341
|
-
}
|
|
2983
|
+
var i = 0;
|
|
2984
|
+
var groupsLen = PerFrameFunctionalGroupsSequence.length;
|
|
2985
|
+
var chunkSize = Math.ceil(groupsLen / 10); // 10% of total length
|
|
2986
|
+
|
|
2987
|
+
var shouldTriggerEvent = triggerEvent && eventTarget;
|
|
2988
|
+
|
|
2989
|
+
// Below, we chunk the processing of the frames to avoid blocking the main thread
|
|
2990
|
+
// if the segmentation is large. We also use a promise to allow the caller to
|
|
2991
|
+
// wait for the processing to finish.
|
|
2992
|
+
return new Promise(function (resolve) {
|
|
2993
|
+
function processInChunks() {
|
|
2994
|
+
// process one chunk
|
|
2995
|
+
for (var end = Math.min(i + chunkSize, groupsLen); i < end; ++i) {
|
|
2996
|
+
var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[i];
|
|
2997
|
+
var ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
|
|
2998
|
+
var view = readFromUnpackedChunks(pixelData, i * sliceLength, sliceLength);
|
|
2999
|
+
var pixelDataI2D = ndarray(view, [Rows, Columns]);
|
|
3000
|
+
var alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
|
|
3001
|
+
if (!alignedPixelDataI) {
|
|
3002
|
+
throw new Error("Individual SEG frames are out of plane with respect to the first SEG frame. " + "This is not yet supported. Aborting segmentation loading.");
|
|
2342
3003
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
3004
|
+
var segmentIndex = getSegmentIndex(multiframe, i);
|
|
3005
|
+
if (segmentIndex === undefined) {
|
|
3006
|
+
throw new Error("Could not retrieve the segment index. Aborting segmentation loading.");
|
|
2345
3007
|
}
|
|
2346
|
-
|
|
2347
|
-
|
|
3008
|
+
if (!segmentsPixelIndices.has(segmentIndex)) {
|
|
3009
|
+
segmentsPixelIndices.set(segmentIndex, {});
|
|
3010
|
+
}
|
|
3011
|
+
var imageId = findReferenceSourceImageId(multiframe, i, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
|
|
3012
|
+
if (!imageId) {
|
|
3013
|
+
console.warn("Image not present in stack, can't import frame : " + i + ".");
|
|
3014
|
+
continue;
|
|
3015
|
+
}
|
|
3016
|
+
var sourceImageMetadata = imageIdMaps.metadata[imageId];
|
|
3017
|
+
if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
|
|
3018
|
+
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. ");
|
|
3019
|
+
}
|
|
3020
|
+
var imageIdIndex = imageIdMaps.indices[imageId];
|
|
3021
|
+
var byteOffset = sliceLength * imageIdIndex * TypedArrayConstructor.BYTES_PER_ELEMENT;
|
|
3022
|
+
var labelmap2DView = new TypedArrayConstructor(labelmapBufferArray[0], byteOffset, sliceLength);
|
|
3023
|
+
var data = alignedPixelDataI.data;
|
|
3024
|
+
var indexCache = [];
|
|
3025
|
+
for (var j = 0, len = alignedPixelDataI.data.length; j < len; ++j) {
|
|
3026
|
+
if (data[j]) {
|
|
3027
|
+
for (var x = j; x < len; ++x) {
|
|
3028
|
+
if (data[x]) {
|
|
3029
|
+
labelmap2DView[x] = segmentIndex;
|
|
3030
|
+
indexCache.push(x);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
if (!segmentsOnFrame[imageIdIndex]) {
|
|
3034
|
+
segmentsOnFrame[imageIdIndex] = [];
|
|
3035
|
+
}
|
|
3036
|
+
segmentsOnFrame[imageIdIndex].push(segmentIndex);
|
|
3037
|
+
break;
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
var segmentIndexObject = segmentsPixelIndices.get(segmentIndex);
|
|
3041
|
+
segmentIndexObject[imageIdIndex] = indexCache;
|
|
3042
|
+
segmentsPixelIndices.set(segmentIndex, segmentIndexObject);
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
// trigger an event after each chunk
|
|
3046
|
+
if (shouldTriggerEvent) {
|
|
3047
|
+
var percentComplete = Math.round(i / groupsLen * 100);
|
|
3048
|
+
triggerEvent(eventTarget, Events$1.SEGMENTATION_LOAD_PROGRESS, {
|
|
3049
|
+
percentComplete: percentComplete
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
// schedule next chunk
|
|
3054
|
+
if (i < groupsLen) {
|
|
3055
|
+
setTimeout(processInChunks, 0);
|
|
3056
|
+
} else {
|
|
3057
|
+
// resolve the Promise when all chunks have been processed
|
|
3058
|
+
resolve();
|
|
2348
3059
|
}
|
|
2349
3060
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
var _ret3 = _loop5();
|
|
2353
|
-
if (_ret3 === "continue") continue;
|
|
2354
|
-
}
|
|
3061
|
+
processInChunks();
|
|
3062
|
+
});
|
|
2355
3063
|
}
|
|
2356
3064
|
function checkOrientation(multiframe, validOrientations, sourceDataDimensions, tolerance) {
|
|
2357
3065
|
var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
|
|
@@ -2390,12 +3098,13 @@ function checkIfPerpendicular(iop1, iop2, tolerance) {
|
|
|
2390
3098
|
}
|
|
2391
3099
|
|
|
2392
3100
|
/**
|
|
2393
|
-
* unpackPixelData - Unpacks
|
|
3101
|
+
* unpackPixelData - Unpacks bit packed pixelData if the Segmentation is BINARY.
|
|
2394
3102
|
*
|
|
2395
3103
|
* @param {Object} multiframe The multiframe dataset.
|
|
3104
|
+
* @param {Object} options Options for the unpacking.
|
|
2396
3105
|
* @return {Uint8Array} The unpacked pixelData.
|
|
2397
3106
|
*/
|
|
2398
|
-
function unpackPixelData(multiframe) {
|
|
3107
|
+
function unpackPixelData(multiframe, options) {
|
|
2399
3108
|
var segType = multiframe.SegmentationType;
|
|
2400
3109
|
var data;
|
|
2401
3110
|
if (Array.isArray(multiframe.PixelData)) {
|
|
@@ -2407,7 +3116,10 @@ function unpackPixelData(multiframe) {
|
|
|
2407
3116
|
log.error("This segmentation pixeldata is undefined.");
|
|
2408
3117
|
}
|
|
2409
3118
|
if (segType === "BINARY") {
|
|
2410
|
-
|
|
3119
|
+
// For extreme big data, we can't unpack the data at once and we need to
|
|
3120
|
+
// chunk it and unpack each chunk separately.
|
|
3121
|
+
// MAX 2GB is the limit right now to allocate a buffer
|
|
3122
|
+
return getUnpackedChunks(data, options.maxBytesPerChunk);
|
|
2411
3123
|
}
|
|
2412
3124
|
var pixelData = new Uint8Array(data);
|
|
2413
3125
|
var max = multiframe.MaximumFractionalValue;
|
|
@@ -2421,20 +3133,35 @@ function unpackPixelData(multiframe) {
|
|
|
2421
3133
|
log.warn("This segmentation object is actually binary... processing as such.");
|
|
2422
3134
|
return pixelData;
|
|
2423
3135
|
}
|
|
3136
|
+
function getUnpackedChunks(data, maxBytesPerChunk) {
|
|
3137
|
+
var bitArray = new Uint8Array(data);
|
|
3138
|
+
var chunks = [];
|
|
3139
|
+
var maxBitsPerChunk = maxBytesPerChunk * 8;
|
|
3140
|
+
var numberOfChunks = Math.ceil(bitArray.length * 8 / maxBitsPerChunk);
|
|
3141
|
+
for (var i = 0; i < numberOfChunks; i++) {
|
|
3142
|
+
var startBit = i * maxBitsPerChunk;
|
|
3143
|
+
var endBit = Math.min(startBit + maxBitsPerChunk, bitArray.length * 8);
|
|
3144
|
+
var startByte = Math.floor(startBit / 8);
|
|
3145
|
+
var endByte = Math.ceil(endBit / 8);
|
|
3146
|
+
var chunk = bitArray.slice(startByte, endByte);
|
|
3147
|
+
var unpackedChunk = BitArray$1.unpack(chunk);
|
|
3148
|
+
chunks.push(unpackedChunk);
|
|
3149
|
+
}
|
|
3150
|
+
return chunks;
|
|
3151
|
+
}
|
|
2424
3152
|
|
|
2425
3153
|
/**
|
|
2426
|
-
*
|
|
3154
|
+
* getImageIdOfSourceImageBySourceImageSequence - Returns the Cornerstone imageId of the source image.
|
|
2427
3155
|
*
|
|
2428
3156
|
* @param {Object} SourceImageSequence Sequence describing the source image.
|
|
2429
3157
|
* @param {String[]} imageIds A list of imageIds.
|
|
2430
|
-
* @param {Object}
|
|
2431
|
-
* metadata from imageIds.
|
|
3158
|
+
* @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUIDs to imageIds.
|
|
2432
3159
|
* @return {String} The corresponding imageId.
|
|
2433
3160
|
*/
|
|
2434
|
-
function
|
|
3161
|
+
function getImageIdOfSourceImageBySourceImageSequence(SourceImageSequence, sopUIDImageIdIndexMap) {
|
|
2435
3162
|
var ReferencedSOPInstanceUID = SourceImageSequence.ReferencedSOPInstanceUID,
|
|
2436
3163
|
ReferencedFrameNumber = SourceImageSequence.ReferencedFrameNumber;
|
|
2437
|
-
return ReferencedFrameNumber ? getImageIdOfReferencedFrame(ReferencedSOPInstanceUID, ReferencedFrameNumber,
|
|
3164
|
+
return ReferencedFrameNumber ? getImageIdOfReferencedFrame(ReferencedSOPInstanceUID, ReferencedFrameNumber, sopUIDImageIdIndexMap) : sopUIDImageIdIndexMap[ReferencedSOPInstanceUID];
|
|
2438
3165
|
}
|
|
2439
3166
|
|
|
2440
3167
|
/**
|
|
@@ -2444,7 +3171,7 @@ function getImageIdOfSourceImagebySourceImageSequence(SourceImageSequence, image
|
|
|
2444
3171
|
* @param {String} FrameOfReferenceUID Frame of reference.
|
|
2445
3172
|
* @param {Object} PerFrameFunctionalGroup Sequence describing segmentation reference attributes per frame.
|
|
2446
3173
|
* @param {String[]} imageIds A list of imageIds.
|
|
2447
|
-
* @param {Object}
|
|
3174
|
+
* @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUIDs to imageIds.
|
|
2448
3175
|
* @param {Float} tolerance The tolerance parameter
|
|
2449
3176
|
*
|
|
2450
3177
|
* @return {String} The corresponding imageId.
|
|
@@ -2464,26 +3191,6 @@ function getImageIdOfSourceImagebyGeometry(ReferencedSeriesInstanceUID, FrameOfR
|
|
|
2464
3191
|
}
|
|
2465
3192
|
}
|
|
2466
3193
|
|
|
2467
|
-
/**
|
|
2468
|
-
* getImageIdOfReferencedSingleFramedSOPInstance - Returns the imageId
|
|
2469
|
-
* corresponding to the specified sopInstanceUid for single-frame images.
|
|
2470
|
-
*
|
|
2471
|
-
* @param {String} sopInstanceUid The sopInstanceUid of the desired image.
|
|
2472
|
-
* @param {String[]} imageIds The list of imageIds.
|
|
2473
|
-
* @param {Object} metadataProvider The metadataProvider to obtain sopInstanceUids
|
|
2474
|
-
* from the cornerstone imageIds.
|
|
2475
|
-
* @return {String} The imageId that corresponds to the sopInstanceUid.
|
|
2476
|
-
*/
|
|
2477
|
-
function getImageIdOfReferencedSingleFramedSOPInstance(sopInstanceUid, imageIds, metadataProvider) {
|
|
2478
|
-
return imageIds.find(function (imageId) {
|
|
2479
|
-
var sopCommonModule = metadataProvider.get("sopCommonModule", imageId);
|
|
2480
|
-
if (!sopCommonModule) {
|
|
2481
|
-
return;
|
|
2482
|
-
}
|
|
2483
|
-
return sopCommonModule.sopInstanceUID === sopInstanceUid;
|
|
2484
|
-
});
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
3194
|
/**
|
|
2488
3195
|
* getImageIdOfReferencedFrame - Returns the imageId corresponding to the
|
|
2489
3196
|
* specified sopInstanceUid and frameNumber for multi-frame images.
|
|
@@ -2491,23 +3198,16 @@ function getImageIdOfReferencedSingleFramedSOPInstance(sopInstanceUid, imageIds,
|
|
|
2491
3198
|
* @param {String} sopInstanceUid The sopInstanceUid of the desired image.
|
|
2492
3199
|
* @param {Number} frameNumber The frame number.
|
|
2493
3200
|
* @param {String} imageIds The list of imageIds.
|
|
2494
|
-
* @param {Object}
|
|
2495
|
-
* from the cornerstone imageIds.
|
|
3201
|
+
* @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUIDs to imageIds.
|
|
2496
3202
|
* @return {String} The imageId that corresponds to the sopInstanceUid.
|
|
2497
3203
|
*/
|
|
2498
|
-
function getImageIdOfReferencedFrame(sopInstanceUid, frameNumber,
|
|
2499
|
-
var imageId =
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
return (
|
|
2506
|
-
//frameNumber is zero indexed for cornerstoneDICOMImageLoader image Ids.
|
|
2507
|
-
sopCommonModule.sopInstanceUID === sopInstanceUid && imageIdFrameNumber === frameNumber - 1
|
|
2508
|
-
);
|
|
2509
|
-
});
|
|
2510
|
-
return imageId;
|
|
3204
|
+
function getImageIdOfReferencedFrame(sopInstanceUid, frameNumber, sopUIDImageIdIndexMap) {
|
|
3205
|
+
var imageId = sopUIDImageIdIndexMap[sopInstanceUid];
|
|
3206
|
+
if (!imageId) {
|
|
3207
|
+
return;
|
|
3208
|
+
}
|
|
3209
|
+
var imageIdFrameNumber = Number(imageId.split("frame=")[1]);
|
|
3210
|
+
return imageIdFrameNumber === frameNumber - 1 ? imageId : undefined;
|
|
2511
3211
|
}
|
|
2512
3212
|
|
|
2513
3213
|
/**
|
|
@@ -2587,387 +3287,216 @@ function alignPixelDataWithSourceData(pixelData2D, iop, orientations, tolerance)
|
|
|
2587
3287
|
/**
|
|
2588
3288
|
* compareArrays - Returns true if array1 and array2 are equal
|
|
2589
3289
|
* within a tolerance.
|
|
2590
|
-
*
|
|
2591
|
-
* @param {Number[]} array1 - An array.
|
|
2592
|
-
* @param {Number[]} array2 - An array.
|
|
2593
|
-
* @param {Number} tolerance.
|
|
2594
|
-
* @return {Boolean} True if array1 and array2 are equal.
|
|
2595
|
-
*/
|
|
2596
|
-
function compareArrays(array1, array2, tolerance) {
|
|
2597
|
-
if (array1.length != array2.length) {
|
|
2598
|
-
return false;
|
|
2599
|
-
}
|
|
2600
|
-
for (var i = 0; i < array1.length; ++i) {
|
|
2601
|
-
if (!nearlyEqual(array1[i], array2[i], tolerance)) {
|
|
2602
|
-
return false;
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
return true;
|
|
2606
|
-
}
|
|
2607
|
-
function getSegmentMetadata(multiframe, seriesInstanceUid) {
|
|
2608
|
-
var segmentSequence = multiframe.SegmentSequence;
|
|
2609
|
-
var data = [];
|
|
2610
|
-
if (Array.isArray(segmentSequence)) {
|
|
2611
|
-
data = [undefined].concat(_toConsumableArray(segmentSequence));
|
|
2612
|
-
} else {
|
|
2613
|
-
// Only one segment, will be stored as an object.
|
|
2614
|
-
data = [undefined, segmentSequence];
|
|
2615
|
-
}
|
|
2616
|
-
return {
|
|
2617
|
-
seriesInstanceUid: seriesInstanceUid,
|
|
2618
|
-
data: data
|
|
2619
|
-
};
|
|
2620
|
-
}
|
|
2621
|
-
|
|
2622
|
-
var Segmentation$1 = {
|
|
2623
|
-
generateSegmentation: generateSegmentation,
|
|
2624
|
-
generateToolState: generateToolState,
|
|
2625
|
-
fillSegmentation: fillSegmentation
|
|
2626
|
-
};
|
|
2627
|
-
|
|
2628
|
-
/**
|
|
2629
|
-
* generateSegmentation - Generates a DICOM Segmentation object given cornerstoneTools data.
|
|
2630
|
-
*
|
|
2631
|
-
* @param {object[]} images An array of the cornerstone image objects.
|
|
2632
|
-
* @param {Object|Object[]} labelmaps3DorBrushData For 4.X: The cornerstone `Labelmap3D` object, or an array of objects.
|
|
2633
|
-
* For 3.X: the BrushData.
|
|
2634
|
-
* @param {number} cornerstoneToolsVersion The cornerstoneTools major version to map against.
|
|
2635
|
-
* @returns {Object}
|
|
2636
|
-
*/
|
|
2637
|
-
function generateSegmentation(images, labelmaps3DorBrushData) {
|
|
2638
|
-
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
2639
|
-
includeSliceSpacing: true
|
|
2640
|
-
};
|
|
2641
|
-
var cornerstoneToolsVersion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 4;
|
|
2642
|
-
if (cornerstoneToolsVersion === 4) {
|
|
2643
|
-
return Segmentation$2.generateSegmentation(images, labelmaps3DorBrushData, options);
|
|
2644
|
-
}
|
|
2645
|
-
if (cornerstoneToolsVersion === 3) {
|
|
2646
|
-
return Segmentation$3.generateSegmentation(images, labelmaps3DorBrushData, options);
|
|
2647
|
-
}
|
|
2648
|
-
console.warn("No generateSegmentation adapater for cornerstone version ".concat(cornerstoneToolsVersion, ", exiting."));
|
|
2649
|
-
}
|
|
2650
|
-
|
|
2651
|
-
/**
|
|
2652
|
-
* generateToolState - Given a set of cornrstoneTools imageIds and a Segmentation buffer,
|
|
2653
|
-
* derive cornerstoneTools toolState and brush metadata.
|
|
2654
|
-
*
|
|
2655
|
-
* @param {string[]} imageIds An array of the imageIds.
|
|
2656
|
-
* @param {ArrayBuffer} arrayBuffer The SEG arrayBuffer.
|
|
2657
|
-
* @param {*} metadataProvider
|
|
2658
|
-
* @param {bool} skipOverlapping - skip checks for overlapping segs, default value false.
|
|
2659
|
-
* @param {number} tolerance - default value 1.e-3.
|
|
2660
|
-
* @param {number} cornerstoneToolsVersion - default value 4.
|
|
2661
|
-
*
|
|
2662
|
-
* @returns {Object} The toolState and an object from which the
|
|
2663
|
-
* segment metadata can be derived.
|
|
2664
|
-
*/
|
|
2665
|
-
function generateToolState(imageIds, arrayBuffer, metadataProvider) {
|
|
2666
|
-
var skipOverlapping = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
2667
|
-
var tolerance = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1e-3;
|
|
2668
|
-
var cornerstoneToolsVersion = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 4;
|
|
2669
|
-
if (cornerstoneToolsVersion === 4) {
|
|
2670
|
-
return Segmentation$2.generateToolState(imageIds, arrayBuffer, metadataProvider, skipOverlapping, tolerance);
|
|
2671
|
-
}
|
|
2672
|
-
if (cornerstoneToolsVersion === 3) {
|
|
2673
|
-
return Segmentation$3.generateToolState(imageIds, arrayBuffer, metadataProvider);
|
|
2674
|
-
}
|
|
2675
|
-
console.warn("No generateToolState adapater for cornerstone version ".concat(cornerstoneToolsVersion, ", exiting."));
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
|
-
/**
|
|
2679
|
-
* fillSegmentation - Fills a derived segmentation dataset with cornerstoneTools `LabelMap3D` data.
|
|
2680
|
-
*
|
|
2681
|
-
* @param {object[]} segmentation An empty segmentation derived dataset.
|
|
2682
|
-
* @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects.
|
|
2683
|
-
* @param {Object} userOptions Options object to override default options.
|
|
2684
|
-
* @returns {Blob} description
|
|
2685
|
-
*/
|
|
2686
|
-
function fillSegmentation(segmentation, inputLabelmaps3D) {
|
|
2687
|
-
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
2688
|
-
includeSliceSpacing: true
|
|
2689
|
-
};
|
|
2690
|
-
var cornerstoneToolsVersion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 4;
|
|
2691
|
-
if (cornerstoneToolsVersion === 4) {
|
|
2692
|
-
return Segmentation$2.fillSegmentation(segmentation, inputLabelmaps3D, options);
|
|
2693
|
-
}
|
|
2694
|
-
console.warn("No generateSegmentation adapater for cornerstone version ".concat(cornerstoneToolsVersion, ", exiting."));
|
|
2695
|
-
}
|
|
2696
|
-
|
|
2697
|
-
var TID300CobbAngle$2 = utilities.TID300.CobbAngle;
|
|
2698
|
-
var COBB_ANGLE = "CobbAngle";
|
|
2699
|
-
var CobbAngle$1 = /*#__PURE__*/function () {
|
|
2700
|
-
function CobbAngle() {
|
|
2701
|
-
_classCallCheck(this, CobbAngle);
|
|
2702
|
-
}
|
|
2703
|
-
_createClass(CobbAngle, null, [{
|
|
2704
|
-
key: "getMeasurementData",
|
|
2705
|
-
value:
|
|
2706
|
-
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
|
|
2707
|
-
function getMeasurementData(MeasurementGroup) {
|
|
2708
|
-
var _MeasurementReport$ge = MeasurementReport$1.getSetupMeasurementData(MeasurementGroup),
|
|
2709
|
-
defaultState = _MeasurementReport$ge.defaultState,
|
|
2710
|
-
NUMGroup = _MeasurementReport$ge.NUMGroup,
|
|
2711
|
-
SCOORDGroup = _MeasurementReport$ge.SCOORDGroup;
|
|
2712
|
-
var state = _objectSpread2(_objectSpread2({}, defaultState), {}, {
|
|
2713
|
-
rAngle: NUMGroup.MeasuredValueSequence.NumericValue,
|
|
2714
|
-
toolType: CobbAngle.toolType,
|
|
2715
|
-
handles: {
|
|
2716
|
-
start: {},
|
|
2717
|
-
end: {},
|
|
2718
|
-
start2: {
|
|
2719
|
-
highlight: true,
|
|
2720
|
-
drawnIndependently: true
|
|
2721
|
-
},
|
|
2722
|
-
end2: {
|
|
2723
|
-
highlight: true,
|
|
2724
|
-
drawnIndependently: true
|
|
2725
|
-
},
|
|
2726
|
-
textBox: {
|
|
2727
|
-
hasMoved: false,
|
|
2728
|
-
movesIndependently: false,
|
|
2729
|
-
drawnIndependently: true,
|
|
2730
|
-
allowedOutsideImage: true,
|
|
2731
|
-
hasBoundingBox: true
|
|
2732
|
-
}
|
|
2733
|
-
}
|
|
2734
|
-
});
|
|
2735
|
-
var _SCOORDGroup$GraphicD = _slicedToArray(SCOORDGroup.GraphicData, 8);
|
|
2736
|
-
state.handles.start.x = _SCOORDGroup$GraphicD[0];
|
|
2737
|
-
state.handles.start.y = _SCOORDGroup$GraphicD[1];
|
|
2738
|
-
state.handles.end.x = _SCOORDGroup$GraphicD[2];
|
|
2739
|
-
state.handles.end.y = _SCOORDGroup$GraphicD[3];
|
|
2740
|
-
state.handles.start2.x = _SCOORDGroup$GraphicD[4];
|
|
2741
|
-
state.handles.start2.y = _SCOORDGroup$GraphicD[5];
|
|
2742
|
-
state.handles.end2.x = _SCOORDGroup$GraphicD[6];
|
|
2743
|
-
state.handles.end2.y = _SCOORDGroup$GraphicD[7];
|
|
2744
|
-
return state;
|
|
2745
|
-
}
|
|
2746
|
-
}, {
|
|
2747
|
-
key: "getTID300RepresentationArguments",
|
|
2748
|
-
value: function getTID300RepresentationArguments(tool) {
|
|
2749
|
-
var handles = tool.handles,
|
|
2750
|
-
finding = tool.finding,
|
|
2751
|
-
findingSites = tool.findingSites;
|
|
2752
|
-
var point1 = handles.start;
|
|
2753
|
-
var point2 = handles.end;
|
|
2754
|
-
var point3 = handles.start2;
|
|
2755
|
-
var point4 = handles.end2;
|
|
2756
|
-
var rAngle = tool.rAngle;
|
|
2757
|
-
var trackingIdentifierTextValue = "cornerstoneTools@^4.0.0:CobbAngle";
|
|
2758
|
-
return {
|
|
2759
|
-
point1: point1,
|
|
2760
|
-
point2: point2,
|
|
2761
|
-
point3: point3,
|
|
2762
|
-
point4: point4,
|
|
2763
|
-
rAngle: rAngle,
|
|
2764
|
-
trackingIdentifierTextValue: trackingIdentifierTextValue,
|
|
2765
|
-
finding: finding,
|
|
2766
|
-
findingSites: findingSites || []
|
|
2767
|
-
};
|
|
2768
|
-
}
|
|
2769
|
-
}]);
|
|
2770
|
-
return CobbAngle;
|
|
2771
|
-
}();
|
|
2772
|
-
CobbAngle$1.toolType = COBB_ANGLE;
|
|
2773
|
-
CobbAngle$1.utilityToolType = COBB_ANGLE;
|
|
2774
|
-
CobbAngle$1.TID300Representation = TID300CobbAngle$2;
|
|
2775
|
-
CobbAngle$1.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
2776
|
-
if (!TrackingIdentifier.includes(":")) {
|
|
2777
|
-
return false;
|
|
2778
|
-
}
|
|
2779
|
-
var _TrackingIdentifier$s = TrackingIdentifier.split(":"),
|
|
2780
|
-
_TrackingIdentifier$s2 = _slicedToArray(_TrackingIdentifier$s, 2),
|
|
2781
|
-
cornerstone4Tag = _TrackingIdentifier$s2[0],
|
|
2782
|
-
toolType = _TrackingIdentifier$s2[1];
|
|
2783
|
-
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
2784
|
-
return false;
|
|
2785
|
-
}
|
|
2786
|
-
return toolType === COBB_ANGLE;
|
|
2787
|
-
};
|
|
2788
|
-
MeasurementReport$1.registerTool(CobbAngle$1);
|
|
2789
|
-
|
|
2790
|
-
var TID300Angle = utilities.TID300.Angle;
|
|
2791
|
-
var ANGLE = "Angle";
|
|
2792
|
-
var Angle$1 = /*#__PURE__*/function () {
|
|
2793
|
-
function Angle() {
|
|
2794
|
-
_classCallCheck(this, Angle);
|
|
2795
|
-
}
|
|
2796
|
-
_createClass(Angle, null, [{
|
|
2797
|
-
key: "getMeasurementData",
|
|
2798
|
-
value:
|
|
2799
|
-
/**
|
|
2800
|
-
* Generate TID300 measurement data for a plane angle measurement - use a Angle, but label it as Angle
|
|
2801
|
-
*/
|
|
2802
|
-
function getMeasurementData(MeasurementGroup) {
|
|
2803
|
-
var _MeasurementReport$ge = MeasurementReport$1.getSetupMeasurementData(MeasurementGroup),
|
|
2804
|
-
defaultState = _MeasurementReport$ge.defaultState,
|
|
2805
|
-
NUMGroup = _MeasurementReport$ge.NUMGroup,
|
|
2806
|
-
SCOORDGroup = _MeasurementReport$ge.SCOORDGroup;
|
|
2807
|
-
var state = _objectSpread2(_objectSpread2({}, defaultState), {}, {
|
|
2808
|
-
rAngle: NUMGroup.MeasuredValueSequence.NumericValue,
|
|
2809
|
-
toolType: Angle.toolType,
|
|
2810
|
-
handles: {
|
|
2811
|
-
start: {},
|
|
2812
|
-
middle: {},
|
|
2813
|
-
end: {},
|
|
2814
|
-
textBox: {
|
|
2815
|
-
hasMoved: false,
|
|
2816
|
-
movesIndependently: false,
|
|
2817
|
-
drawnIndependently: true,
|
|
2818
|
-
allowedOutsideImage: true,
|
|
2819
|
-
hasBoundingBox: true
|
|
2820
|
-
}
|
|
2821
|
-
}
|
|
2822
|
-
});
|
|
2823
|
-
var _SCOORDGroup$GraphicD = _slicedToArray(SCOORDGroup.GraphicData, 8);
|
|
2824
|
-
state.handles.start.x = _SCOORDGroup$GraphicD[0];
|
|
2825
|
-
state.handles.start.y = _SCOORDGroup$GraphicD[1];
|
|
2826
|
-
state.handles.middle.x = _SCOORDGroup$GraphicD[2];
|
|
2827
|
-
state.handles.middle.y = _SCOORDGroup$GraphicD[3];
|
|
2828
|
-
state.handles.middle.x = _SCOORDGroup$GraphicD[4];
|
|
2829
|
-
state.handles.middle.y = _SCOORDGroup$GraphicD[5];
|
|
2830
|
-
state.handles.end.x = _SCOORDGroup$GraphicD[6];
|
|
2831
|
-
state.handles.end.y = _SCOORDGroup$GraphicD[7];
|
|
2832
|
-
return state;
|
|
2833
|
-
}
|
|
2834
|
-
}, {
|
|
2835
|
-
key: "getTID300RepresentationArguments",
|
|
2836
|
-
value: function getTID300RepresentationArguments(tool) {
|
|
2837
|
-
var handles = tool.handles,
|
|
2838
|
-
finding = tool.finding,
|
|
2839
|
-
findingSites = tool.findingSites;
|
|
2840
|
-
var point1 = handles.start;
|
|
2841
|
-
var point2 = handles.middle;
|
|
2842
|
-
var point3 = handles.middle;
|
|
2843
|
-
var point4 = handles.end;
|
|
2844
|
-
var rAngle = tool.rAngle;
|
|
2845
|
-
var trackingIdentifierTextValue = "cornerstoneTools@^4.0.0:Angle";
|
|
2846
|
-
return {
|
|
2847
|
-
point1: point1,
|
|
2848
|
-
point2: point2,
|
|
2849
|
-
point3: point3,
|
|
2850
|
-
point4: point4,
|
|
2851
|
-
rAngle: rAngle,
|
|
2852
|
-
trackingIdentifierTextValue: trackingIdentifierTextValue,
|
|
2853
|
-
finding: finding,
|
|
2854
|
-
findingSites: findingSites || []
|
|
2855
|
-
};
|
|
2856
|
-
}
|
|
2857
|
-
}]);
|
|
2858
|
-
return Angle;
|
|
2859
|
-
}();
|
|
2860
|
-
Angle$1.toolType = ANGLE;
|
|
2861
|
-
Angle$1.utilityToolType = ANGLE;
|
|
2862
|
-
Angle$1.TID300Representation = TID300Angle;
|
|
2863
|
-
Angle$1.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
2864
|
-
if (!TrackingIdentifier.includes(":")) {
|
|
3290
|
+
*
|
|
3291
|
+
* @param {Number[]} array1 - An array.
|
|
3292
|
+
* @param {Number[]} array2 - An array.
|
|
3293
|
+
* @param {Number} tolerance.
|
|
3294
|
+
* @return {Boolean} True if array1 and array2 are equal.
|
|
3295
|
+
*/
|
|
3296
|
+
function compareArrays(array1, array2, tolerance) {
|
|
3297
|
+
if (array1.length != array2.length) {
|
|
2865
3298
|
return false;
|
|
2866
3299
|
}
|
|
2867
|
-
var
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
2872
|
-
return false;
|
|
3300
|
+
for (var i = 0; i < array1.length; ++i) {
|
|
3301
|
+
if (!nearlyEqual(array1[i], array2[i], tolerance)) {
|
|
3302
|
+
return false;
|
|
3303
|
+
}
|
|
2873
3304
|
}
|
|
2874
|
-
return
|
|
2875
|
-
}
|
|
2876
|
-
|
|
3305
|
+
return true;
|
|
3306
|
+
}
|
|
3307
|
+
function getSegmentMetadata(multiframe, seriesInstanceUid) {
|
|
3308
|
+
var segmentSequence = multiframe.SegmentSequence;
|
|
3309
|
+
var data = [];
|
|
3310
|
+
if (Array.isArray(segmentSequence)) {
|
|
3311
|
+
data = [undefined].concat(_toConsumableArray(segmentSequence));
|
|
3312
|
+
} else {
|
|
3313
|
+
// Only one segment, will be stored as an object.
|
|
3314
|
+
data = [undefined, segmentSequence];
|
|
3315
|
+
}
|
|
3316
|
+
return {
|
|
3317
|
+
seriesInstanceUid: seriesInstanceUid,
|
|
3318
|
+
data: data
|
|
3319
|
+
};
|
|
3320
|
+
}
|
|
2877
3321
|
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
3322
|
+
/**
|
|
3323
|
+
* Reads a range of bytes from an array of ArrayBuffer chunks and
|
|
3324
|
+
* aggregate them into a new Uint8Array.
|
|
3325
|
+
*
|
|
3326
|
+
* @param {ArrayBuffer[]} chunks - An array of ArrayBuffer chunks.
|
|
3327
|
+
* @param {number} offset - The offset of the first byte to read.
|
|
3328
|
+
* @param {number} length - The number of bytes to read.
|
|
3329
|
+
* @returns {Uint8Array} A new Uint8Array containing the requested bytes.
|
|
3330
|
+
*/
|
|
3331
|
+
function readFromUnpackedChunks(chunks, offset, length) {
|
|
3332
|
+
var mapping = getUnpackedOffsetAndLength(chunks, offset, length);
|
|
3333
|
+
|
|
3334
|
+
// If all the data is in one chunk, we can just slice that chunk
|
|
3335
|
+
if (mapping.start.chunkIndex === mapping.end.chunkIndex) {
|
|
3336
|
+
return new Uint8Array(chunks[mapping.start.chunkIndex].buffer, mapping.start.offset, length);
|
|
3337
|
+
} else {
|
|
3338
|
+
// If the data spans multiple chunks, we need to create a new Uint8Array and copy the data from each chunk
|
|
3339
|
+
var result = new Uint8Array(length);
|
|
3340
|
+
var resultOffset = 0;
|
|
3341
|
+
for (var i = mapping.start.chunkIndex; i <= mapping.end.chunkIndex; i++) {
|
|
3342
|
+
var start = i === mapping.start.chunkIndex ? mapping.start.offset : 0;
|
|
3343
|
+
var end = i === mapping.end.chunkIndex ? mapping.end.offset : chunks[i].length;
|
|
3344
|
+
result.set(new Uint8Array(chunks[i].buffer, start, end - start), resultOffset);
|
|
3345
|
+
resultOffset += end - start;
|
|
3346
|
+
}
|
|
3347
|
+
return result;
|
|
2882
3348
|
}
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
var _SCOORDGroup$GraphicD = _slicedToArray(SCOORDGroup.GraphicData, 6);
|
|
2912
|
-
state.handles.start.x = _SCOORDGroup$GraphicD[0];
|
|
2913
|
-
state.handles.start.y = _SCOORDGroup$GraphicD[1];
|
|
2914
|
-
_SCOORDGroup$GraphicD[2];
|
|
2915
|
-
_SCOORDGroup$GraphicD[3];
|
|
2916
|
-
state.handles.end.x = _SCOORDGroup$GraphicD[4];
|
|
2917
|
-
state.handles.end.y = _SCOORDGroup$GraphicD[5];
|
|
2918
|
-
return state;
|
|
3349
|
+
}
|
|
3350
|
+
function getUnpackedOffsetAndLength(chunks, offset, length) {
|
|
3351
|
+
var totalBytes = chunks.reduce(function (total, chunk) {
|
|
3352
|
+
return total + chunk.length;
|
|
3353
|
+
}, 0);
|
|
3354
|
+
if (offset < 0 || offset + length > totalBytes) {
|
|
3355
|
+
throw new Error("Offset and length out of bounds");
|
|
3356
|
+
}
|
|
3357
|
+
var startChunkIndex = 0;
|
|
3358
|
+
var startOffsetInChunk = offset;
|
|
3359
|
+
while (startOffsetInChunk >= chunks[startChunkIndex].length) {
|
|
3360
|
+
startOffsetInChunk -= chunks[startChunkIndex].length;
|
|
3361
|
+
startChunkIndex++;
|
|
3362
|
+
}
|
|
3363
|
+
var endChunkIndex = startChunkIndex;
|
|
3364
|
+
var endOffsetInChunk = startOffsetInChunk + length;
|
|
3365
|
+
while (endOffsetInChunk > chunks[endChunkIndex].length) {
|
|
3366
|
+
endOffsetInChunk -= chunks[endChunkIndex].length;
|
|
3367
|
+
endChunkIndex++;
|
|
3368
|
+
}
|
|
3369
|
+
return {
|
|
3370
|
+
start: {
|
|
3371
|
+
chunkIndex: startChunkIndex,
|
|
3372
|
+
offset: startOffsetInChunk
|
|
3373
|
+
},
|
|
3374
|
+
end: {
|
|
3375
|
+
chunkIndex: endChunkIndex,
|
|
3376
|
+
offset: endOffsetInChunk
|
|
2919
3377
|
}
|
|
2920
|
-
}
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
function calculateCentroid(imageIdIndexBufferIndex, multiframe) {
|
|
3381
|
+
var xAcc = 0;
|
|
3382
|
+
var yAcc = 0;
|
|
3383
|
+
var zAcc = 0;
|
|
3384
|
+
var count = 0;
|
|
3385
|
+
for (var _i3 = 0, _Object$entries = Object.entries(imageIdIndexBufferIndex); _i3 < _Object$entries.length; _i3++) {
|
|
3386
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i3], 2),
|
|
3387
|
+
imageIdIndex = _Object$entries$_i[0],
|
|
3388
|
+
bufferIndices = _Object$entries$_i[1];
|
|
3389
|
+
var z = Number(imageIdIndex);
|
|
3390
|
+
if (!bufferIndices || bufferIndices.length === 0) {
|
|
3391
|
+
continue;
|
|
3392
|
+
}
|
|
3393
|
+
var _iterator2 = _createForOfIteratorHelper(bufferIndices),
|
|
3394
|
+
_step2;
|
|
3395
|
+
try {
|
|
3396
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
3397
|
+
var bufferIndex = _step2.value;
|
|
3398
|
+
var y = Math.floor(bufferIndex / multiframe.Rows);
|
|
3399
|
+
var x = bufferIndex % multiframe.Rows;
|
|
3400
|
+
xAcc += x;
|
|
3401
|
+
yAcc += y;
|
|
3402
|
+
zAcc += z;
|
|
3403
|
+
count++;
|
|
3404
|
+
}
|
|
3405
|
+
} catch (err) {
|
|
3406
|
+
_iterator2.e(err);
|
|
3407
|
+
} finally {
|
|
3408
|
+
_iterator2.f();
|
|
2948
3409
|
}
|
|
2949
|
-
}]);
|
|
2950
|
-
return RectangleRoi;
|
|
2951
|
-
}();
|
|
2952
|
-
RectangleRoi.toolType = "RectangleRoi";
|
|
2953
|
-
RectangleRoi.utilityToolType = "RectangleRoi";
|
|
2954
|
-
RectangleRoi.TID300Representation = TID300Polyline$2;
|
|
2955
|
-
RectangleRoi.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
2956
|
-
if (!TrackingIdentifier.includes(":")) {
|
|
2957
|
-
return false;
|
|
2958
|
-
}
|
|
2959
|
-
var _TrackingIdentifier$s = TrackingIdentifier.split(":"),
|
|
2960
|
-
_TrackingIdentifier$s2 = _slicedToArray(_TrackingIdentifier$s, 2),
|
|
2961
|
-
cornerstone4Tag = _TrackingIdentifier$s2[0],
|
|
2962
|
-
toolType = _TrackingIdentifier$s2[1];
|
|
2963
|
-
if (cornerstone4Tag !== CORNERSTONE_4_TAG) {
|
|
2964
|
-
return false;
|
|
2965
3410
|
}
|
|
2966
|
-
return
|
|
3411
|
+
return {
|
|
3412
|
+
xAcc: xAcc,
|
|
3413
|
+
yAcc: yAcc,
|
|
3414
|
+
zAcc: zAcc,
|
|
3415
|
+
count: count
|
|
3416
|
+
};
|
|
3417
|
+
}
|
|
3418
|
+
var Segmentation$4 = {
|
|
3419
|
+
generateSegmentation: generateSegmentation$2,
|
|
3420
|
+
generateToolState: generateToolState$2,
|
|
3421
|
+
fillSegmentation: fillSegmentation$1
|
|
2967
3422
|
};
|
|
2968
|
-
MeasurementReport$1.registerTool(RectangleRoi);
|
|
2969
3423
|
|
|
2970
|
-
var
|
|
3424
|
+
var Segmentation$3 = {
|
|
3425
|
+
generateSegmentation: generateSegmentation$1,
|
|
3426
|
+
generateToolState: generateToolState$1,
|
|
3427
|
+
fillSegmentation: fillSegmentation
|
|
3428
|
+
};
|
|
3429
|
+
|
|
3430
|
+
/**
|
|
3431
|
+
* generateSegmentation - Generates a DICOM Segmentation object given cornerstoneTools data.
|
|
3432
|
+
*
|
|
3433
|
+
* @param {object[]} images An array of the cornerstone image objects.
|
|
3434
|
+
* @param {Object|Object[]} labelmaps3DorBrushData For 4.X: The cornerstone `Labelmap3D` object, or an array of objects.
|
|
3435
|
+
* For 3.X: the BrushData.
|
|
3436
|
+
* @param {number} cornerstoneToolsVersion The cornerstoneTools major version to map against.
|
|
3437
|
+
* @returns {Object}
|
|
3438
|
+
*/
|
|
3439
|
+
function generateSegmentation$1(images, labelmaps3DorBrushData) {
|
|
3440
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
3441
|
+
includeSliceSpacing: true
|
|
3442
|
+
};
|
|
3443
|
+
var cornerstoneToolsVersion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 4;
|
|
3444
|
+
if (cornerstoneToolsVersion === 4) {
|
|
3445
|
+
return Segmentation$4.generateSegmentation(images, labelmaps3DorBrushData, options);
|
|
3446
|
+
}
|
|
3447
|
+
if (cornerstoneToolsVersion === 3) {
|
|
3448
|
+
return Segmentation$5.generateSegmentation(images, labelmaps3DorBrushData, options);
|
|
3449
|
+
}
|
|
3450
|
+
console.warn("No generateSegmentation adapater for cornerstone version ".concat(cornerstoneToolsVersion, ", exiting."));
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
/**
|
|
3454
|
+
* generateToolState - Given a set of cornrstoneTools imageIds and a Segmentation buffer,
|
|
3455
|
+
* derive cornerstoneTools toolState and brush metadata.
|
|
3456
|
+
*
|
|
3457
|
+
* @param {string[]} imageIds An array of the imageIds.
|
|
3458
|
+
* @param {ArrayBuffer} arrayBuffer The SEG arrayBuffer.
|
|
3459
|
+
* @param {*} metadataProvider
|
|
3460
|
+
* @param {bool} skipOverlapping - skip checks for overlapping segs, default value false.
|
|
3461
|
+
* @param {number} tolerance - default value 1.e-3.
|
|
3462
|
+
* @param {number} cornerstoneToolsVersion - default value 4.
|
|
3463
|
+
*
|
|
3464
|
+
* @returns {Object} The toolState and an object from which the
|
|
3465
|
+
* segment metadata can be derived.
|
|
3466
|
+
*/
|
|
3467
|
+
function generateToolState$1(imageIds, arrayBuffer, metadataProvider) {
|
|
3468
|
+
var skipOverlapping = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
3469
|
+
var tolerance = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1e-3;
|
|
3470
|
+
var cornerstoneToolsVersion = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 4;
|
|
3471
|
+
if (cornerstoneToolsVersion === 4) {
|
|
3472
|
+
return Segmentation$4.generateToolState(imageIds, arrayBuffer, metadataProvider, skipOverlapping, tolerance);
|
|
3473
|
+
}
|
|
3474
|
+
if (cornerstoneToolsVersion === 3) {
|
|
3475
|
+
return Segmentation$5.generateToolState(imageIds, arrayBuffer, metadataProvider);
|
|
3476
|
+
}
|
|
3477
|
+
console.warn("No generateToolState adapater for cornerstone version ".concat(cornerstoneToolsVersion, ", exiting."));
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3480
|
+
/**
|
|
3481
|
+
* fillSegmentation - Fills a derived segmentation dataset with cornerstoneTools `LabelMap3D` data.
|
|
3482
|
+
*
|
|
3483
|
+
* @param {object[]} segmentation An empty segmentation derived dataset.
|
|
3484
|
+
* @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects.
|
|
3485
|
+
* @param {Object} userOptions Options object to override default options.
|
|
3486
|
+
* @returns {Blob} description
|
|
3487
|
+
*/
|
|
3488
|
+
function fillSegmentation(segmentation, inputLabelmaps3D) {
|
|
3489
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
3490
|
+
includeSliceSpacing: true
|
|
3491
|
+
};
|
|
3492
|
+
var cornerstoneToolsVersion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 4;
|
|
3493
|
+
if (cornerstoneToolsVersion === 4) {
|
|
3494
|
+
return Segmentation$4.fillSegmentation(segmentation, inputLabelmaps3D, options);
|
|
3495
|
+
}
|
|
3496
|
+
console.warn("No generateSegmentation adapater for cornerstone version ".concat(cornerstoneToolsVersion, ", exiting."));
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
var CornerstoneSR = {
|
|
2971
3500
|
Length: Length$1,
|
|
2972
3501
|
FreehandRoi: FreehandRoi,
|
|
2973
3502
|
Bidirectional: Bidirectional$1,
|
|
@@ -2975,11 +3504,13 @@ var Cornerstone = {
|
|
|
2975
3504
|
CircleRoi: CircleRoi,
|
|
2976
3505
|
ArrowAnnotate: ArrowAnnotate$1,
|
|
2977
3506
|
MeasurementReport: MeasurementReport$1,
|
|
2978
|
-
Segmentation: Segmentation$1,
|
|
2979
3507
|
CobbAngle: CobbAngle$1,
|
|
2980
3508
|
Angle: Angle$1,
|
|
2981
3509
|
RectangleRoi: RectangleRoi
|
|
2982
3510
|
};
|
|
3511
|
+
var CornerstoneSEG = {
|
|
3512
|
+
Segmentation: Segmentation$3
|
|
3513
|
+
};
|
|
2983
3514
|
|
|
2984
3515
|
/******************************************************************************
|
|
2985
3516
|
Copyright (c) Microsoft Corporation.
|
|
@@ -3033,7 +3564,7 @@ var CodingScheme = {
|
|
|
3033
3564
|
|
|
3034
3565
|
var TID1500 = utilities.TID1500, addAccessors = utilities.addAccessors;
|
|
3035
3566
|
var StructuredReport = derivations.StructuredReport;
|
|
3036
|
-
var Normalizer = normalizers.Normalizer;
|
|
3567
|
+
var Normalizer$1 = normalizers.Normalizer;
|
|
3037
3568
|
var TID1500MeasurementReport = TID1500.TID1500MeasurementReport, TID1501MeasurementGroup = TID1500.TID1501MeasurementGroup;
|
|
3038
3569
|
var DicomMetaDictionary = data.DicomMetaDictionary;
|
|
3039
3570
|
var FINDING = { CodingSchemeDesignator: "DCM", CodeValue: "121071" };
|
|
@@ -3202,7 +3733,7 @@ var MeasurementReport = /** @class */ (function () {
|
|
|
3202
3733
|
if ((instance &&
|
|
3203
3734
|
instance.NumberOfFrames &&
|
|
3204
3735
|
instance.NumberOfFrames > 1) ||
|
|
3205
|
-
Normalizer.isMultiframeSOPClassUID(sopClassUID)) {
|
|
3736
|
+
Normalizer$1.isMultiframeSOPClassUID(sopClassUID)) {
|
|
3206
3737
|
ReferencedSOPSequence.ReferencedFrameNumber = frameNumber;
|
|
3207
3738
|
}
|
|
3208
3739
|
// Loop through each tool type for the image
|
|
@@ -4313,7 +4844,115 @@ Probe.isValidCornerstoneTrackingIdentifier = function (TrackingIdentifier) {
|
|
|
4313
4844
|
};
|
|
4314
4845
|
MeasurementReport.registerTool(Probe);
|
|
4315
4846
|
|
|
4316
|
-
var
|
|
4847
|
+
var Normalizer = normalizers.Normalizer;
|
|
4848
|
+
var SegmentationDerivation = derivations.Segmentation;
|
|
4849
|
+
/**
|
|
4850
|
+
* generateSegmentation - Generates a DICOM Segmentation object given cornerstoneTools data.
|
|
4851
|
+
*
|
|
4852
|
+
* @param images - An array of the cornerstone image objects, which includes imageId and metadata
|
|
4853
|
+
* @param labelmaps - An array of the 3D Volumes that contain the segmentation data.
|
|
4854
|
+
*/
|
|
4855
|
+
function generateSegmentation(images, labelmaps, metadata, options) {
|
|
4856
|
+
var segmentation = _createMultiframeSegmentationFromReferencedImages(images, metadata, options);
|
|
4857
|
+
return fillSegmentation$1(segmentation, labelmaps, options);
|
|
4858
|
+
}
|
|
4859
|
+
/**
|
|
4860
|
+
* _createMultiframeSegmentationFromReferencedImages - description
|
|
4861
|
+
*
|
|
4862
|
+
* @param images - An array of the cornerstone image objects related to the reference
|
|
4863
|
+
* series that the segmentation is derived from. You can use methods such as
|
|
4864
|
+
* volume.getCornerstoneImages() to get this array.
|
|
4865
|
+
*
|
|
4866
|
+
* @param options - the options object for the SegmentationDerivation.
|
|
4867
|
+
* @returns The Seg derived dataSet.
|
|
4868
|
+
*/
|
|
4869
|
+
function _createMultiframeSegmentationFromReferencedImages(images, metadata, options) {
|
|
4870
|
+
var datasets = images.map(function (image) {
|
|
4871
|
+
// add the sopClassUID to the dataset
|
|
4872
|
+
var instance = metadata.get("instance", image.imageId);
|
|
4873
|
+
return __assign(__assign(__assign({}, image), instance), {
|
|
4874
|
+
// Todo: move to dcmjs tag style
|
|
4875
|
+
SOPClassUID: instance.SopClassUID, SOPInstanceUID: instance.SopInstanceUID, PixelData: image.getPixelData(), _vrMap: {
|
|
4876
|
+
PixelData: "OW"
|
|
4877
|
+
}, _meta: {} });
|
|
4878
|
+
});
|
|
4879
|
+
var multiframe = Normalizer.normalizeToDataset(datasets);
|
|
4880
|
+
return new SegmentationDerivation([multiframe], options);
|
|
4881
|
+
}
|
|
4882
|
+
|
|
4883
|
+
/**
|
|
4884
|
+
* Generates 2D label maps from a 3D label map.
|
|
4885
|
+
* @param labelmap3D - The 3D label map object to generate 2D label maps from. It is derived
|
|
4886
|
+
* from the volume labelmap.
|
|
4887
|
+
* @returns The label map object containing the 2D label maps and segments on label maps.
|
|
4888
|
+
*/
|
|
4889
|
+
function generateLabelMaps2DFrom3D(labelmap3D) {
|
|
4890
|
+
// 1. we need to generate labelmaps2D from labelmaps3D, a labelmap2D is for each
|
|
4891
|
+
// slice
|
|
4892
|
+
var scalarData = labelmap3D.scalarData, dimensions = labelmap3D.dimensions;
|
|
4893
|
+
// scalarData is a flat array of all the pixels in the volume.
|
|
4894
|
+
var labelmaps2D = [];
|
|
4895
|
+
var segmentsOnLabelmap3D = new Set();
|
|
4896
|
+
// X-Y are the row and column dimensions, Z is the number of slices.
|
|
4897
|
+
for (var z = 0; z < dimensions[2]; z++) {
|
|
4898
|
+
var pixelData = scalarData.slice(z * dimensions[0] * dimensions[1], (z + 1) * dimensions[0] * dimensions[1]);
|
|
4899
|
+
var segmentsOnLabelmap = [];
|
|
4900
|
+
for (var i = 0; i < pixelData.length; i++) {
|
|
4901
|
+
var segment = pixelData[i];
|
|
4902
|
+
if (!segmentsOnLabelmap.includes(segment) && segment !== 0) {
|
|
4903
|
+
segmentsOnLabelmap.push(segment);
|
|
4904
|
+
}
|
|
4905
|
+
}
|
|
4906
|
+
var labelmap2D = {
|
|
4907
|
+
segmentsOnLabelmap: segmentsOnLabelmap,
|
|
4908
|
+
pixelData: pixelData,
|
|
4909
|
+
rows: dimensions[1],
|
|
4910
|
+
columns: dimensions[0]
|
|
4911
|
+
};
|
|
4912
|
+
if (segmentsOnLabelmap.length === 0) {
|
|
4913
|
+
continue;
|
|
4914
|
+
}
|
|
4915
|
+
segmentsOnLabelmap.forEach(function (segmentIndex) {
|
|
4916
|
+
segmentsOnLabelmap3D.add(segmentIndex);
|
|
4917
|
+
});
|
|
4918
|
+
labelmaps2D[dimensions[2] - 1 - z] = labelmap2D;
|
|
4919
|
+
}
|
|
4920
|
+
// remove segment 0 from segmentsOnLabelmap3D
|
|
4921
|
+
labelmap3D.segmentsOnLabelmap = Array.from(segmentsOnLabelmap3D);
|
|
4922
|
+
labelmap3D.labelmaps2D = labelmaps2D;
|
|
4923
|
+
return labelmap3D;
|
|
4924
|
+
}
|
|
4925
|
+
|
|
4926
|
+
var Segmentation$2 = CornerstoneSEG.Segmentation;
|
|
4927
|
+
var generateToolStateCornerstoneLegacy = Segmentation$2.generateToolState;
|
|
4928
|
+
/**
|
|
4929
|
+
* generateToolState - Given a set of cornerstoneTools imageIds and a Segmentation buffer,
|
|
4930
|
+
* derive cornerstoneTools toolState and brush metadata.
|
|
4931
|
+
*
|
|
4932
|
+
* @param imageIds - An array of the imageIds.
|
|
4933
|
+
* @param arrayBuffer - The SEG arrayBuffer.
|
|
4934
|
+
* @param skipOverlapping - skip checks for overlapping segs, default value false.
|
|
4935
|
+
* @param tolerance - default value 1.e-3.
|
|
4936
|
+
*
|
|
4937
|
+
* @returns a list of array buffer for each labelMap
|
|
4938
|
+
* an object from which the segment metadata can be derived
|
|
4939
|
+
* list containing the track of segments per frame
|
|
4940
|
+
* list containing the track of segments per frame for each labelMap (available only for the overlapping case).
|
|
4941
|
+
*/
|
|
4942
|
+
function generateToolState(imageIds, arrayBuffer, metadataProvider, skipOverlapping, tolerance) {
|
|
4943
|
+
if (skipOverlapping === void 0) { skipOverlapping = false; }
|
|
4944
|
+
if (tolerance === void 0) { tolerance = 1e-3; }
|
|
4945
|
+
return generateToolStateCornerstoneLegacy(imageIds, arrayBuffer, metadataProvider, skipOverlapping, tolerance);
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4948
|
+
var Segmentation$1 = /*#__PURE__*/Object.freeze({
|
|
4949
|
+
__proto__: null,
|
|
4950
|
+
generateLabelMaps2DFrom3D: generateLabelMaps2DFrom3D,
|
|
4951
|
+
generateSegmentation: generateSegmentation,
|
|
4952
|
+
generateToolState: generateToolState
|
|
4953
|
+
});
|
|
4954
|
+
|
|
4955
|
+
var Cornerstone3DSR = {
|
|
4317
4956
|
Bidirectional: Bidirectional,
|
|
4318
4957
|
CobbAngle: CobbAngle,
|
|
4319
4958
|
Angle: Angle,
|
|
@@ -4328,6 +4967,9 @@ var Cornerstone3D = {
|
|
|
4328
4967
|
CodeScheme: CodingScheme,
|
|
4329
4968
|
CORNERSTONE_3D_TAG: CORNERSTONE_3D_TAG
|
|
4330
4969
|
};
|
|
4970
|
+
var Cornerstone3DSEG = {
|
|
4971
|
+
Segmentation: Segmentation$1
|
|
4972
|
+
};
|
|
4331
4973
|
|
|
4332
4974
|
var Colors = data.Colors,
|
|
4333
4975
|
BitArray = data.BitArray;
|
|
@@ -4512,15 +5154,19 @@ var Segmentation = /*#__PURE__*/function () {
|
|
|
4512
5154
|
return Segmentation;
|
|
4513
5155
|
}();
|
|
4514
5156
|
|
|
4515
|
-
var
|
|
5157
|
+
var VTKjsSEG = {
|
|
4516
5158
|
Segmentation: Segmentation
|
|
4517
5159
|
};
|
|
4518
5160
|
|
|
4519
|
-
var
|
|
4520
|
-
Cornerstone:
|
|
4521
|
-
Cornerstone3D:
|
|
4522
|
-
|
|
5161
|
+
var adaptersSR = {
|
|
5162
|
+
Cornerstone: CornerstoneSR,
|
|
5163
|
+
Cornerstone3D: Cornerstone3DSR
|
|
5164
|
+
};
|
|
5165
|
+
var adaptersSEG = {
|
|
5166
|
+
Cornerstone: CornerstoneSR,
|
|
5167
|
+
Cornerstone3D: Cornerstone3DSEG,
|
|
5168
|
+
VTKjs: VTKjsSEG
|
|
4523
5169
|
};
|
|
4524
5170
|
|
|
4525
|
-
export {
|
|
5171
|
+
export { index as Enums, adaptersSEG, adaptersSR, index$1 as helpers };
|
|
4526
5172
|
//# sourceMappingURL=adapters.es.js.map
|