larvitar 2.0.5 → 2.0.7
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/README.md +2 -2
- package/dist/imaging/imageRendering.d.ts +1 -71
- package/dist/imaging/imageStore.d.ts +5 -0
- package/dist/imaging/loaders/commonLoader.d.ts +4 -4
- package/dist/imaging/loaders/nrrdLoader.d.ts +1 -51
- package/dist/larvitar.js +13 -1
- package/dist/larvitar.js.map +1 -1
- package/imaging/tools/types.d.ts +19 -19
- package/imaging/types.d.ts +110 -2
- package/package.json +7 -2
- package/.github/workflows/build-docs.yml +0 -59
- package/.github/workflows/codeql-analysis.yml +0 -71
- package/.github/workflows/deploy.yml +0 -37
- package/.vscode/settings.json +0 -4
- package/CODE_OF_CONDUCT.md +0 -76
- package/MIGRATION.md +0 -25
- package/bundler/webpack.common.js +0 -27
- package/bundler/webpack.dev.js +0 -23
- package/bundler/webpack.prod.js +0 -19
- package/decs.d.ts +0 -12
- package/dist/imaging/MetaDataReadable.d.ts +0 -41
- package/dist/imaging/MetaDataTypes.d.ts +0 -3489
- package/imaging/dataDictionary.json +0 -21866
- package/imaging/imageAnonymization.ts +0 -135
- package/imaging/imageColormaps.ts +0 -217
- package/imaging/imageContours.ts +0 -196
- package/imaging/imageIo.ts +0 -251
- package/imaging/imageLayers.ts +0 -121
- package/imaging/imageLoading.ts +0 -299
- package/imaging/imageParsing.ts +0 -444
- package/imaging/imagePresets.ts +0 -156
- package/imaging/imageRendering.ts +0 -1091
- package/imaging/imageReslice.ts +0 -87
- package/imaging/imageStore.ts +0 -487
- package/imaging/imageTags.ts +0 -609
- package/imaging/imageTools.js +0 -708
- package/imaging/imageUtils.ts +0 -1079
- package/imaging/loaders/commonLoader.ts +0 -275
- package/imaging/loaders/dicomLoader.ts +0 -66
- package/imaging/loaders/fileLoader.ts +0 -71
- package/imaging/loaders/multiframeLoader.ts +0 -435
- package/imaging/loaders/nrrdLoader.ts +0 -630
- package/imaging/loaders/resliceLoader.ts +0 -205
- package/imaging/monitors/memory.ts +0 -151
- package/imaging/monitors/performance.ts +0 -34
- package/imaging/parsers/ecg.ts +0 -54
- package/imaging/parsers/nrrd.js +0 -485
- package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
- package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
- package/imaging/tools/custom/contourTool.js +0 -1884
- package/imaging/tools/custom/diameterTool.js +0 -141
- package/imaging/tools/custom/editMaskTool.js +0 -141
- package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
- package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
- package/imaging/tools/custom/polylineScissorsTool.js +0 -59
- package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
- package/imaging/tools/custom/seedTool.js +0 -342
- package/imaging/tools/custom/setLabelMap3D.ts +0 -242
- package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
- package/imaging/tools/default.ts +0 -594
- package/imaging/tools/interaction.ts +0 -266
- package/imaging/tools/io.ts +0 -229
- package/imaging/tools/main.ts +0 -427
- package/imaging/tools/segmentation.ts +0 -532
- package/imaging/tools/segmentations.md +0 -38
- package/imaging/tools/state.ts +0 -74
- package/imaging/tools/strategies/eraseFreehand.js +0 -76
- package/imaging/tools/strategies/fillFreehand.js +0 -79
- package/imaging/tools/strategies/index.js +0 -2
- package/imaging/waveforms/ecg.ts +0 -191
- package/index.ts +0 -431
- package/jsdoc.json +0 -52
- package/rollup.config.js +0 -51
- package/template/.gitkeep +0 -0
- package/tsconfig.json +0 -102
- /package/imaging/{MetaDataReadable.ts → MetaDataReadable.d.ts} +0 -0
- /package/imaging/{MetaDataTypes.ts → MetaDataTypes.d.ts} +0 -0
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/** @module imaging/imageAnonymization
|
|
2
|
-
* @desc This file provides anonymization functionalities on DICOM images
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// internal libraries
|
|
6
|
-
import { MetaDataTypes } from "./MetaDataTypes";
|
|
7
|
-
import { MetaData, Series } from "./types";
|
|
8
|
-
|
|
9
|
-
/*
|
|
10
|
-
* This module provides the following functions to be exported:
|
|
11
|
-
* anonymize(series: Series): Series
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Anonymize a series by replacing all metadata with random values
|
|
16
|
-
* @function anonymize
|
|
17
|
-
* @param {Series} series - series to anonymize
|
|
18
|
-
* @returns {Series} anonymized series
|
|
19
|
-
*/
|
|
20
|
-
export const anonymize = function (series: Series): Series {
|
|
21
|
-
// anonymize series bytearray
|
|
22
|
-
for (const id in series.imageIds) {
|
|
23
|
-
const imageId = series.imageIds[id];
|
|
24
|
-
let image = series.instances[imageId];
|
|
25
|
-
if (image.dataSet) {
|
|
26
|
-
for (const tag in image.dataSet.elements) {
|
|
27
|
-
let element = image.dataSet.elements[tag];
|
|
28
|
-
let text = "";
|
|
29
|
-
const vr = element.vr;
|
|
30
|
-
if (element !== undefined) {
|
|
31
|
-
let str = image.dataSet.string(tag);
|
|
32
|
-
if (str !== undefined) {
|
|
33
|
-
text = str;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (vr) {
|
|
37
|
-
const deIdentifiedValue = makeDeIdentifiedValue(text.length, vr);
|
|
38
|
-
if (deIdentifiedValue !== undefined) {
|
|
39
|
-
for (let i: number = 0; i < element.length; i++) {
|
|
40
|
-
const char =
|
|
41
|
-
deIdentifiedValue.length > i
|
|
42
|
-
? deIdentifiedValue.charCodeAt(i)
|
|
43
|
-
: 32;
|
|
44
|
-
image.dataSet.byteArray[element.dataOffset + i] = char;
|
|
45
|
-
}
|
|
46
|
-
// @ts-ignore always string
|
|
47
|
-
image.metadata[tag] = deIdentifiedValue;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
image.metadata.seriesUID = image.metadata["x0020000e"];
|
|
52
|
-
image.metadata.instanceUID = image.metadata["x00080018"];
|
|
53
|
-
image.metadata.studyUID = image.metadata["x0020000d"];
|
|
54
|
-
image.metadata.accessionNumber = image.metadata["x00080050"];
|
|
55
|
-
image.metadata.studyDescription = image.metadata["x00081030"];
|
|
56
|
-
image.metadata.patientName = image.metadata["x00100010"] as string;
|
|
57
|
-
image.metadata.patientBirthdate = image.metadata["x00100030"];
|
|
58
|
-
image.metadata.seriesDescription = image.metadata["x0008103e"] as string;
|
|
59
|
-
image.metadata.anonymized = true;
|
|
60
|
-
} else {
|
|
61
|
-
console.warn(`No dataset found for image ${imageId}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// update parsed metadata
|
|
66
|
-
series.anonymized = true;
|
|
67
|
-
series.seriesDescription = series.instances[series.imageIds[0]].metadata[
|
|
68
|
-
"x0008103e"
|
|
69
|
-
] as string;
|
|
70
|
-
|
|
71
|
-
return series;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Internal functions
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Generate a random string of a given length
|
|
78
|
-
* @function makeRandomString
|
|
79
|
-
* @param {number} length - length of the string to generate
|
|
80
|
-
* @returns {string} random string
|
|
81
|
-
*/
|
|
82
|
-
const makeRandomString = function (length: number): string {
|
|
83
|
-
let text: string = "";
|
|
84
|
-
const possible: string =
|
|
85
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
86
|
-
for (let i: number = 0; i < length; i++) {
|
|
87
|
-
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
88
|
-
}
|
|
89
|
-
return text;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Pad a number with 0s to a given size
|
|
94
|
-
* @function pad
|
|
95
|
-
* @param {number} num - number to pad
|
|
96
|
-
* @param {number} size - size of the padded number
|
|
97
|
-
* @returns {string} padded number
|
|
98
|
-
*/
|
|
99
|
-
const pad = function (num: number, size: number): string {
|
|
100
|
-
var s: string = num + "";
|
|
101
|
-
while (s.length < size) s = "0" + s;
|
|
102
|
-
return s;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Make a de-identified value for a given length and VR
|
|
107
|
-
* @function makeDeIdentifiedValue
|
|
108
|
-
* @param {number} length - length of the value to generate
|
|
109
|
-
* @param {string} vr - VR of the value to generate
|
|
110
|
-
* @returns {string} de-identified value
|
|
111
|
-
*/
|
|
112
|
-
const makeDeIdentifiedValue = function (
|
|
113
|
-
length: number,
|
|
114
|
-
vr: string
|
|
115
|
-
): string | undefined {
|
|
116
|
-
if (vr === "LO" || vr === "SH" || vr === "PN") {
|
|
117
|
-
return makeRandomString(length);
|
|
118
|
-
} else if (vr === "DA") {
|
|
119
|
-
let oldDate = new Date(1900, 0, 1);
|
|
120
|
-
return (
|
|
121
|
-
oldDate.getFullYear() +
|
|
122
|
-
pad(oldDate.getMonth() + 1, 2) +
|
|
123
|
-
pad(oldDate.getDate(), 2)
|
|
124
|
-
);
|
|
125
|
-
} else if (vr === "TM") {
|
|
126
|
-
var now = new Date();
|
|
127
|
-
return (
|
|
128
|
-
pad(now.getHours(), 2) +
|
|
129
|
-
pad(now.getMinutes(), 2) +
|
|
130
|
-
pad(now.getSeconds(), 2)
|
|
131
|
-
);
|
|
132
|
-
} else {
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
};
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/** @module imaging/imageColormaps
|
|
2
|
-
* @desc This file provides functionalities for
|
|
3
|
-
* handling colormaps
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import cornerstone from "cornerstone-core";
|
|
7
|
-
import { EnabledElementLayer } from "cornerstone-core";
|
|
8
|
-
import { each } from "lodash";
|
|
9
|
-
|
|
10
|
-
/*
|
|
11
|
-
* This module provides the following functions to be exported:
|
|
12
|
-
* getColormapsList()
|
|
13
|
-
* addColorMap(colormapId, colormapName, colors)
|
|
14
|
-
* fillPixelData(canvas, colormapId)
|
|
15
|
-
* applyColorMap(colormapId)
|
|
16
|
-
* HSVToRGB(hue, sat, val)
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Fill a canvas with pixelData representing the colormap
|
|
21
|
-
* @instance
|
|
22
|
-
* @function getColormapsList
|
|
23
|
-
* @returns {Array} A list of cornerstone colormaps
|
|
24
|
-
*/
|
|
25
|
-
export function getColormapsList() {
|
|
26
|
-
return cornerstone.colors.getColormapsList();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Add a custom color map to cornerstone list
|
|
31
|
-
* @instance
|
|
32
|
-
* @function addColorMap
|
|
33
|
-
* @param {String} colormapId - the new colormap id
|
|
34
|
-
* @param {String} colormapName - the new colormap name
|
|
35
|
-
* @param {Array} colors - array containing 255 rgb colors (ie [[r,g,b], [r,g,b], ...])
|
|
36
|
-
*/
|
|
37
|
-
export function addColorMap(
|
|
38
|
-
colormapId: string,
|
|
39
|
-
colormapName: string,
|
|
40
|
-
colors: Array<Array<number>>
|
|
41
|
-
) {
|
|
42
|
-
const colormap = cornerstone.colors.getColormap(colormapId, null);
|
|
43
|
-
colormap.setColorSchemeName(colormapName);
|
|
44
|
-
let noc = colors.length;
|
|
45
|
-
colormap.setNumberOfColors(noc);
|
|
46
|
-
|
|
47
|
-
for (let i = 0; i < noc; i++) {
|
|
48
|
-
let rgb = colors[i];
|
|
49
|
-
colormap.insertColor(i, rgb);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return colormap;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Fill a canvas with pixelData representing the colormap
|
|
57
|
-
* @instance
|
|
58
|
-
* @function fillPixelData
|
|
59
|
-
* @param {HTMLCanvasElement} canvas - target canvas
|
|
60
|
-
* @param {String} colormapId - the colormap name
|
|
61
|
-
*/
|
|
62
|
-
export function fillPixelData(canvas: HTMLCanvasElement, colormapId: string) {
|
|
63
|
-
const ctx = canvas.getContext("2d");
|
|
64
|
-
const height = canvas.height;
|
|
65
|
-
const width = canvas.width;
|
|
66
|
-
if (ctx) {
|
|
67
|
-
const colorbar = ctx.createImageData(width, height);
|
|
68
|
-
const colormap = cornerstone.colors.getColormap(colormapId, {});
|
|
69
|
-
const lookupTable = colormap.createLookupTable();
|
|
70
|
-
|
|
71
|
-
// Set the min and max values then the lookup table
|
|
72
|
-
// will be able to return the right color for this range
|
|
73
|
-
lookupTable.setTableRange(0, width);
|
|
74
|
-
|
|
75
|
-
// Update the colorbar pixel by pixel
|
|
76
|
-
for (let col = 0; col < width; col++) {
|
|
77
|
-
const color = lookupTable.mapValue(col);
|
|
78
|
-
|
|
79
|
-
for (let row = 0; row < height; row++) {
|
|
80
|
-
const pixel = (col + row * width) * 4;
|
|
81
|
-
colorbar.data[pixel] = color[0];
|
|
82
|
-
colorbar.data[pixel + 1] = color[1];
|
|
83
|
-
colorbar.data[pixel + 2] = color[2];
|
|
84
|
-
colorbar.data[pixel + 3] = color[3];
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
ctx.putImageData(colorbar, 0, 0);
|
|
88
|
-
} else {
|
|
89
|
-
console.error("No context found for canvas", canvas);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Apply a color map on a viewport
|
|
95
|
-
* @instance
|
|
96
|
-
* @function applyColorMap
|
|
97
|
-
* @param {String} colormapId - the colormap name
|
|
98
|
-
* @param {Array} viewportNames - List of viewports where to apply preset
|
|
99
|
-
*/
|
|
100
|
-
export function applyColorMap(
|
|
101
|
-
colormapId: string,
|
|
102
|
-
viewportNames?: Array<string>
|
|
103
|
-
) {
|
|
104
|
-
// for retro-compatibility
|
|
105
|
-
if (!viewportNames) {
|
|
106
|
-
viewportNames = cornerstone.getEnabledElements().map(e => e.element.id);
|
|
107
|
-
}
|
|
108
|
-
let colormap = cornerstone.colors.getColormap(colormapId, {});
|
|
109
|
-
|
|
110
|
-
each(viewportNames, viewportName => {
|
|
111
|
-
let element = document.getElementById(viewportName);
|
|
112
|
-
|
|
113
|
-
if (!element) {
|
|
114
|
-
console.error("No element with id:", viewportName);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let enabledElement: EnabledElementLayer;
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
enabledElement = cornerstone.getEnabledElement(element);
|
|
122
|
-
} catch {
|
|
123
|
-
console.error("No enabledElement with id", viewportName);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
enabledElement.options = {}; // HACK to bypass cornerstone bug
|
|
128
|
-
|
|
129
|
-
if (!enabledElement) {
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const viewport = cornerstone.getViewport(element);
|
|
133
|
-
if (viewport) {
|
|
134
|
-
viewport.colormap = colormap;
|
|
135
|
-
cornerstone.setViewport(element, viewport);
|
|
136
|
-
cornerstone.updateImage(element, true);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
return colormap;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Converts an HSV (Hue, Saturation, Value) color to RGB (Red, Green, Blue) color value
|
|
145
|
-
* @param {Number} hue A number representing the hue color value
|
|
146
|
-
* @param {Number} sat A number representing the saturation color value
|
|
147
|
-
* @param {Number} val A number representing the value color value
|
|
148
|
-
* @returns {Number[]} An RGB color array
|
|
149
|
-
*/
|
|
150
|
-
export function HSVToRGB(hue: number, sat: number, val: number) {
|
|
151
|
-
if (hue > 1) {
|
|
152
|
-
throw new Error("HSVToRGB expects hue < 1");
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const rgb = [];
|
|
156
|
-
|
|
157
|
-
if (sat === 0) {
|
|
158
|
-
rgb[0] = val;
|
|
159
|
-
rgb[1] = val;
|
|
160
|
-
rgb[2] = val;
|
|
161
|
-
|
|
162
|
-
return rgb;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const hueCase = Math.floor(hue * 6);
|
|
166
|
-
const frac = 6 * hue - hueCase;
|
|
167
|
-
const lx = val * (1 - sat);
|
|
168
|
-
const ly = val * (1 - sat * frac);
|
|
169
|
-
const lz = val * (1 - sat * (1 - frac));
|
|
170
|
-
|
|
171
|
-
switch (hueCase) {
|
|
172
|
-
/* 0<hue<1/6 */
|
|
173
|
-
case 0:
|
|
174
|
-
case 6:
|
|
175
|
-
rgb[0] = val;
|
|
176
|
-
rgb[1] = lz;
|
|
177
|
-
rgb[2] = lx;
|
|
178
|
-
break;
|
|
179
|
-
|
|
180
|
-
/* 1/6<hue<2/6 */
|
|
181
|
-
case 1:
|
|
182
|
-
rgb[0] = ly;
|
|
183
|
-
rgb[1] = val;
|
|
184
|
-
rgb[2] = lx;
|
|
185
|
-
break;
|
|
186
|
-
|
|
187
|
-
/* 2/6<hue<3/6 */
|
|
188
|
-
case 2:
|
|
189
|
-
rgb[0] = lx;
|
|
190
|
-
rgb[1] = val;
|
|
191
|
-
rgb[2] = lz;
|
|
192
|
-
break;
|
|
193
|
-
|
|
194
|
-
/* 3/6<hue/4/6 */
|
|
195
|
-
case 3:
|
|
196
|
-
rgb[0] = lx;
|
|
197
|
-
rgb[1] = ly;
|
|
198
|
-
rgb[2] = val;
|
|
199
|
-
break;
|
|
200
|
-
|
|
201
|
-
/* 4/6<hue<5/6 */
|
|
202
|
-
case 4:
|
|
203
|
-
rgb[0] = lz;
|
|
204
|
-
rgb[1] = lx;
|
|
205
|
-
rgb[2] = val;
|
|
206
|
-
break;
|
|
207
|
-
|
|
208
|
-
/* 5/6<hue<1 */
|
|
209
|
-
case 5:
|
|
210
|
-
rgb[0] = val;
|
|
211
|
-
rgb[1] = lx;
|
|
212
|
-
rgb[2] = ly;
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return rgb;
|
|
217
|
-
}
|
package/imaging/imageContours.ts
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
/** @module imaging/imageContours
|
|
2
|
-
* @desc This file provides functionalities to render a set of points on a canvas.
|
|
3
|
-
* Use this in order to render image contours (e.g. from binary masks).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// external libraries
|
|
7
|
-
import { each, range } from "lodash";
|
|
8
|
-
import { vec2 } from "cornerstone-core";
|
|
9
|
-
import { Contours } from "./types";
|
|
10
|
-
|
|
11
|
-
/*
|
|
12
|
-
* This module provides the following functions to be exported:
|
|
13
|
-
* parseContours(contoursData,pointBatchSize,segmentationName, viewports)
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Parse raw data to contours object for each viewport
|
|
18
|
-
* @export
|
|
19
|
-
* @function parseContours
|
|
20
|
-
* @param {Array} contoursData - Raw data
|
|
21
|
-
* @param {Number} pointBatchSize - Number of points that defines a contour segment (default to 2)
|
|
22
|
-
* @param {String} segmentationName - Mask object name
|
|
23
|
-
* @param {Array} viewports - Viewport array ids
|
|
24
|
-
* @returns {Number} Number of array elements consumed
|
|
25
|
-
*/
|
|
26
|
-
export const parseContours = function (
|
|
27
|
-
contoursData: { [key: string]: Uint8Array }, // TODO-ts: check if this is correct @mronzoni
|
|
28
|
-
pointBatchSize: number,
|
|
29
|
-
segmentationName: string,
|
|
30
|
-
viewports: Array<string>
|
|
31
|
-
) {
|
|
32
|
-
let contours: Contours = {};
|
|
33
|
-
each(viewports, viewport => {
|
|
34
|
-
contours[viewport] = {};
|
|
35
|
-
contours[viewport][segmentationName] = [];
|
|
36
|
-
let points = contoursData[viewport];
|
|
37
|
-
|
|
38
|
-
if (!points) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let numberOfSlices = points[0];
|
|
43
|
-
points = points.slice(1);
|
|
44
|
-
|
|
45
|
-
each(range(numberOfSlices), function () {
|
|
46
|
-
let sliceSize = extractSlicePoints(
|
|
47
|
-
contours,
|
|
48
|
-
pointBatchSize,
|
|
49
|
-
points,
|
|
50
|
-
segmentationName,
|
|
51
|
-
viewport
|
|
52
|
-
);
|
|
53
|
-
points = points.slice(sliceSize);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
return contours;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/* Internal module functions */
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* From raw data, fill cornerstone tool data structure for ContoursTool for a single slice
|
|
64
|
-
* @instance
|
|
65
|
-
* @function populateContoursObject
|
|
66
|
-
* @param {Number} pointBatchSize - Number of points that defines a contour segment
|
|
67
|
-
* @param {Object} contours - Main contour tool object dict (to be filled)
|
|
68
|
-
* @param {Number} lineNumber - Number of line to be rendered (a contour is made of n lines)
|
|
69
|
-
* @param {Number} sliceNumber - Number of the slice in which the contour should be rendered
|
|
70
|
-
* @param {String} segmentationName - Mask object name
|
|
71
|
-
* @param {String} viewport - Viewport id
|
|
72
|
-
* @param {Array} data - Raw data (array of pixel values)
|
|
73
|
-
*/
|
|
74
|
-
const populateContoursObject = function (
|
|
75
|
-
pointBatchSize: number,
|
|
76
|
-
contours: Contours,
|
|
77
|
-
lineNumber: number,
|
|
78
|
-
sliceNumber: number,
|
|
79
|
-
segmentationName: string,
|
|
80
|
-
viewport: string,
|
|
81
|
-
data: Uint8Array
|
|
82
|
-
) {
|
|
83
|
-
let coords: Array<{ x: number; y: number; lines: Array<vec2> }> = [];
|
|
84
|
-
|
|
85
|
-
for (let i = 0; i < data.length; i += pointBatchSize) {
|
|
86
|
-
let xy = data.slice(i, pointBatchSize + i);
|
|
87
|
-
|
|
88
|
-
// always add the first item
|
|
89
|
-
if (!coords.length) {
|
|
90
|
-
coords.push({
|
|
91
|
-
x: xy[0],
|
|
92
|
-
y: xy[1],
|
|
93
|
-
lines: []
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// add new items if different from the previous one
|
|
98
|
-
else {
|
|
99
|
-
//if (coords[coords.length - 1].x !== xy[0] &&
|
|
100
|
-
// coords[coords.length - 1].y !== xy[1]) {
|
|
101
|
-
coords.push({
|
|
102
|
-
x: xy[0],
|
|
103
|
-
y: xy[1],
|
|
104
|
-
lines: [
|
|
105
|
-
{
|
|
106
|
-
x: coords[coords.length - 1].x,
|
|
107
|
-
y: coords[coords.length - 1].y
|
|
108
|
-
}
|
|
109
|
-
]
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// add line element to the first item
|
|
115
|
-
if (coords[0]) {
|
|
116
|
-
coords[0].lines = [
|
|
117
|
-
{
|
|
118
|
-
x: coords[coords.length - 1].x,
|
|
119
|
-
y: coords[coords.length - 1].y
|
|
120
|
-
}
|
|
121
|
-
];
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
contours[viewport][segmentationName][sliceNumber].lines[lineNumber] = coords;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Extract each slice points from raw data array
|
|
129
|
-
* @instance
|
|
130
|
-
* @function extractSlicePoints
|
|
131
|
-
* @param {Object} contours - Main contour tool object dict (to be filled)
|
|
132
|
-
* @param {Number} pointBatchSize - Number of points that defines a contour segment (default to 2)
|
|
133
|
-
* @param {Number} slicePoints - Number of contour points on a slice
|
|
134
|
-
* @param {String} segmentationName - Mask object name
|
|
135
|
-
* @param {String} viewport - Viewport id
|
|
136
|
-
* @returns {Number} Number of array elements consumed
|
|
137
|
-
*/
|
|
138
|
-
const extractSlicePoints = function (
|
|
139
|
-
contours: Contours,
|
|
140
|
-
pointBatchSize: number,
|
|
141
|
-
slicePoints: Uint8Array, // TODO-ts: check if this is correct @mronzoni
|
|
142
|
-
segmentationName: string,
|
|
143
|
-
viewport: string
|
|
144
|
-
) {
|
|
145
|
-
// read slice number and number of lines for current slice, then remove from array
|
|
146
|
-
let sliceNumber = slicePoints[0];
|
|
147
|
-
let numberOfLines = slicePoints[1];
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
slicePoints = slicePoints.subarray(2);
|
|
151
|
-
} catch (err) {
|
|
152
|
-
slicePoints = slicePoints.slice(2);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
let numberOfPoints = 0;
|
|
156
|
-
contours[viewport][segmentationName][sliceNumber] = {
|
|
157
|
-
lines: [] as vec2[][]
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
if (numberOfLines) {
|
|
161
|
-
// for each line
|
|
162
|
-
each(range(numberOfLines), function (l: number) {
|
|
163
|
-
// get number of points for current line
|
|
164
|
-
let numberOfPointsPerLine = slicePoints[0];
|
|
165
|
-
// compute coordinates size
|
|
166
|
-
let lineCoordSize = numberOfPointsPerLine * pointBatchSize;
|
|
167
|
-
|
|
168
|
-
// remove numberOfPointsPerLine and the coordinates for this line
|
|
169
|
-
let subCoords;
|
|
170
|
-
try {
|
|
171
|
-
subCoords = slicePoints.subarray(1, lineCoordSize + 1);
|
|
172
|
-
} catch (err) {
|
|
173
|
-
subCoords = slicePoints.slice(1, lineCoordSize + 1);
|
|
174
|
-
}
|
|
175
|
-
populateContoursObject(
|
|
176
|
-
pointBatchSize,
|
|
177
|
-
contours,
|
|
178
|
-
l,
|
|
179
|
-
sliceNumber,
|
|
180
|
-
segmentationName,
|
|
181
|
-
viewport,
|
|
182
|
-
subCoords
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
let lineSize = 1 + lineCoordSize;
|
|
186
|
-
numberOfPoints += lineSize;
|
|
187
|
-
try {
|
|
188
|
-
slicePoints = slicePoints.subarray(lineSize);
|
|
189
|
-
} catch (err) {
|
|
190
|
-
slicePoints = slicePoints.slice(lineSize);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return 2 + numberOfPoints;
|
|
196
|
-
};
|