@cornerstonejs/core 2.12.3 → 2.14.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/esm/RenderingEngine/StackViewport.js +11 -9
- package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/computeAutoVoi.js +1 -0
- package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/createViewport.js +2 -0
- package/dist/esm/RenderingEngine/helpers/setDefaultVolumeVOI.js +4 -3
- package/dist/esm/enums/VOILUTFunctionType.d.ts +2 -1
- package/dist/esm/enums/VOILUTFunctionType.js +1 -0
- package/dist/esm/types/CPUFallbackViewport.d.ts +2 -0
- package/dist/esm/types/IImage.d.ts +2 -2
- package/dist/esm/utilities/createSigmoidRGBTransferFunction.js +1 -6
- package/dist/esm/utilities/logit.d.ts +1 -0
- package/dist/esm/utilities/logit.js +3 -0
- package/dist/esm/utilities/windowLevel.d.ts +2 -1
- package/dist/esm/utilities/windowLevel.js +26 -4
- package/package.json +2 -2
|
@@ -905,8 +905,9 @@ class StackViewport extends Viewport {
|
|
|
905
905
|
viewport.voi = {
|
|
906
906
|
windowWidth: wwToUse,
|
|
907
907
|
windowCenter: wcToUse,
|
|
908
|
+
voiLUTFunction: image.voiLUTFunction,
|
|
908
909
|
};
|
|
909
|
-
const { lower, upper } = windowLevelUtil.toLowHighRange(wwToUse, wcToUse);
|
|
910
|
+
const { lower, upper } = windowLevelUtil.toLowHighRange(wwToUse, wcToUse, image.voiLUTFunction);
|
|
910
911
|
voiRange = { lower, upper };
|
|
911
912
|
}
|
|
912
913
|
else {
|
|
@@ -916,6 +917,7 @@ class StackViewport extends Viewport {
|
|
|
916
917
|
viewport.voi = {
|
|
917
918
|
windowWidth: 0,
|
|
918
919
|
windowCenter: 0,
|
|
920
|
+
voiLUTFunction: image.voiLUTFunction,
|
|
919
921
|
};
|
|
920
922
|
}
|
|
921
923
|
viewport.voi.windowWidth = windowWidth;
|
|
@@ -1416,8 +1418,8 @@ class StackViewport extends Viewport {
|
|
|
1416
1418
|
_updateToDisplayImageCPU(image) {
|
|
1417
1419
|
const metadata = this.getImageDataMetadata(image);
|
|
1418
1420
|
const viewport = getDefaultViewport(this.canvas, image, this.modality, this._cpuFallbackEnabledElement.viewport.colormap);
|
|
1419
|
-
const { windowCenter, windowWidth } = viewport.voi;
|
|
1420
|
-
this.voiRange = windowLevelUtil.toLowHighRange(windowWidth, windowCenter);
|
|
1421
|
+
const { windowCenter, windowWidth, voiLUTFunction } = viewport.voi;
|
|
1422
|
+
this.voiRange = windowLevelUtil.toLowHighRange(windowWidth, windowCenter, voiLUTFunction);
|
|
1421
1423
|
this._cpuFallbackEnabledElement.image = image;
|
|
1422
1424
|
this._cpuFallbackEnabledElement.metadata = {
|
|
1423
1425
|
...metadata,
|
|
@@ -1519,8 +1521,8 @@ class StackViewport extends Viewport {
|
|
|
1519
1521
|
if (this.voiRange && this.voiUpdatedWithSetProperties) {
|
|
1520
1522
|
return this.globalDefaultProperties.voiRange;
|
|
1521
1523
|
}
|
|
1522
|
-
const { windowCenter, windowWidth } = image;
|
|
1523
|
-
let voiRange = this._getVOIRangeFromWindowLevel(windowWidth, windowCenter);
|
|
1524
|
+
const { windowCenter, windowWidth, voiLUTFunction } = image;
|
|
1525
|
+
let voiRange = this._getVOIRangeFromWindowLevel(windowWidth, windowCenter, voiLUTFunction);
|
|
1524
1526
|
voiRange = this._getPTPreScaledRange() || voiRange;
|
|
1525
1527
|
return voiRange;
|
|
1526
1528
|
}
|
|
@@ -1542,7 +1544,7 @@ class StackViewport extends Viewport {
|
|
|
1542
1544
|
_getDefaultPTPrescaledVOIRange() {
|
|
1543
1545
|
return { lower: 0, upper: 5 };
|
|
1544
1546
|
}
|
|
1545
|
-
_getVOIRangeFromWindowLevel(windowWidth, windowCenter) {
|
|
1547
|
+
_getVOIRangeFromWindowLevel(windowWidth, windowCenter, voiLUTFunction = VOILUTFunctionType.LINEAR) {
|
|
1546
1548
|
let center, width;
|
|
1547
1549
|
if (typeof windowCenter === 'number' && typeof windowWidth === 'number') {
|
|
1548
1550
|
center = windowCenter;
|
|
@@ -1553,7 +1555,7 @@ class StackViewport extends Viewport {
|
|
|
1553
1555
|
width = windowWidth[0];
|
|
1554
1556
|
}
|
|
1555
1557
|
if (center !== undefined && width !== undefined) {
|
|
1556
|
-
return windowLevelUtil.toLowHighRange(width, center);
|
|
1558
|
+
return windowLevelUtil.toLowHighRange(width, center, voiLUTFunction);
|
|
1557
1559
|
}
|
|
1558
1560
|
}
|
|
1559
1561
|
async _setImageIdIndex(imageIdIndex) {
|
|
@@ -1687,8 +1689,8 @@ class StackViewport extends Viewport {
|
|
|
1687
1689
|
return true;
|
|
1688
1690
|
}
|
|
1689
1691
|
_getVOIRangeForCurrentImage() {
|
|
1690
|
-
const { windowCenter, windowWidth } = this.csImage;
|
|
1691
|
-
return this._getVOIRangeFromWindowLevel(windowWidth, windowCenter);
|
|
1692
|
+
const { windowCenter, windowWidth, voiLUTFunction } = this.csImage;
|
|
1693
|
+
return this._getVOIRangeFromWindowLevel(windowWidth, windowCenter, voiLUTFunction);
|
|
1692
1694
|
}
|
|
1693
1695
|
_getValidVOILUTFunction(voiLUTFunction) {
|
|
1694
1696
|
if (!Object.values(VOILUTFunctionType).includes(voiLUTFunction)) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { state } from './setDefaultViewport';
|
|
2
|
+
import { VOILUTFunctionType } from '../../../../enums';
|
|
2
3
|
function createDefaultDisplayedArea() {
|
|
3
4
|
return {
|
|
4
5
|
tlhc: {
|
|
@@ -25,6 +26,7 @@ export default function createViewport() {
|
|
|
25
26
|
voi: {
|
|
26
27
|
windowWidth: undefined,
|
|
27
28
|
windowCenter: undefined,
|
|
29
|
+
voiLUTFunction: VOILUTFunctionType.LINEAR,
|
|
28
30
|
},
|
|
29
31
|
invert: false,
|
|
30
32
|
pixelReplication: false,
|
|
@@ -37,11 +37,12 @@ function handlePreScaledVolume(imageVolume, voi) {
|
|
|
37
37
|
function getVOIFromMetadata(imageVolume) {
|
|
38
38
|
const { imageIds, metadata } = imageVolume;
|
|
39
39
|
let voi;
|
|
40
|
-
if (imageIds
|
|
40
|
+
if (imageIds?.length) {
|
|
41
41
|
const imageIdIndex = Math.floor(imageIds.length / 2);
|
|
42
42
|
const imageId = imageIds[imageIdIndex];
|
|
43
43
|
const voiLutModule = metaData.get('voiLutModule', imageId);
|
|
44
|
-
if (voiLutModule
|
|
44
|
+
if (voiLutModule && voiLutModule.windowWidth && voiLutModule.windowCenter) {
|
|
45
|
+
voi.voiLUTFunction = voiLutModule.voiLUTFunction;
|
|
45
46
|
const { windowWidth, windowCenter } = voiLutModule;
|
|
46
47
|
const width = Array.isArray(windowWidth) ? windowWidth[0] : windowWidth;
|
|
47
48
|
const center = Array.isArray(windowCenter)
|
|
@@ -56,7 +57,7 @@ function getVOIFromMetadata(imageVolume) {
|
|
|
56
57
|
voi = metadata.voiLut[0];
|
|
57
58
|
}
|
|
58
59
|
if (voi && (voi.windowWidth !== 0 || voi.windowCenter !== 0)) {
|
|
59
|
-
const { lower, upper } = windowLevel.toLowHighRange(Number(voi.windowWidth), Number(voi.windowCenter));
|
|
60
|
+
const { lower, upper } = windowLevel.toLowHighRange(Number(voi.windowWidth), Number(voi.windowCenter), voi.voiLUTFunction);
|
|
60
61
|
return { lower, upper };
|
|
61
62
|
}
|
|
62
63
|
return undefined;
|
|
@@ -2,5 +2,6 @@ var VOILUTFunctionType;
|
|
|
2
2
|
(function (VOILUTFunctionType) {
|
|
3
3
|
VOILUTFunctionType["LINEAR"] = "LINEAR";
|
|
4
4
|
VOILUTFunctionType["SAMPLED_SIGMOID"] = "SIGMOID";
|
|
5
|
+
VOILUTFunctionType["LINEAR_EXACT"] = "LINEAR_EXACT";
|
|
5
6
|
})(VOILUTFunctionType || (VOILUTFunctionType = {}));
|
|
6
7
|
export default VOILUTFunctionType;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type CPUFallbackViewportDisplayedArea from './CPUFallbackViewportDisplayedArea';
|
|
2
2
|
import type CPUFallbackColormap from './CPUFallbackColormap';
|
|
3
3
|
import type CPUFallbackLUT from './CPUFallbackLUT';
|
|
4
|
+
import type VOILUTFunctionType from '../enums/VOILUTFunctionType';
|
|
4
5
|
interface CPUFallbackViewport {
|
|
5
6
|
scale?: number;
|
|
6
7
|
parallelScale?: number;
|
|
@@ -12,6 +13,7 @@ interface CPUFallbackViewport {
|
|
|
12
13
|
voi?: {
|
|
13
14
|
windowWidth: number;
|
|
14
15
|
windowCenter: number;
|
|
16
|
+
voiLUTFunction: VOILUTFunctionType;
|
|
15
17
|
};
|
|
16
18
|
invert?: boolean;
|
|
17
19
|
pixelReplication?: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type CPUFallbackLUT from './CPUFallbackLUT';
|
|
2
2
|
import type { PixelDataTypedArray, PixelDataTypedArrayString } from './PixelDataTypedArray';
|
|
3
|
-
import type { ImageQualityStatus } from '../enums';
|
|
3
|
+
import type { ImageQualityStatus, VOILUTFunctionType } from '../enums';
|
|
4
4
|
import type IImageCalibration from './IImageCalibration';
|
|
5
5
|
import type RGB from './RGB';
|
|
6
6
|
import type IImageFrame from './IImageFrame';
|
|
@@ -35,7 +35,7 @@ interface IImage {
|
|
|
35
35
|
intercept: number;
|
|
36
36
|
windowCenter: number[] | number;
|
|
37
37
|
windowWidth: number[] | number;
|
|
38
|
-
voiLUTFunction:
|
|
38
|
+
voiLUTFunction: VOILUTFunctionType;
|
|
39
39
|
getPixelData: () => PixelDataTypedArray;
|
|
40
40
|
getCanvas: () => HTMLCanvasElement;
|
|
41
41
|
rows: number;
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
|
|
2
2
|
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
|
|
3
3
|
import * as windowLevelUtil from './windowLevel';
|
|
4
|
+
import { logit } from './logit';
|
|
4
5
|
export default function createSigmoidRGBTransferFunction(voiRange, approximationNodes = 1024) {
|
|
5
6
|
const { windowWidth, windowCenter } = windowLevelUtil.toWindowLevel(voiRange.lower, voiRange.upper);
|
|
6
|
-
const sigmoid = (x, wc, ww) => {
|
|
7
|
-
return 1 / (1 + Math.exp((-4 * (x - wc)) / ww));
|
|
8
|
-
};
|
|
9
|
-
const logit = (y, wc, ww) => {
|
|
10
|
-
return wc - (ww / 4) * Math.log((1 - y) / y);
|
|
11
|
-
};
|
|
12
7
|
const range = Array.from({ length: approximationNodes }, (_, i) => (i + 1) / (approximationNodes + 2));
|
|
13
8
|
const table = range.flatMap((y) => {
|
|
14
9
|
const x = logit(y, windowCenter, windowWidth);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const logit: (y: number, wc: number, ww: number) => number;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import VOILUTFunctionType from '../enums/VOILUTFunctionType';
|
|
1
2
|
declare function toWindowLevel(low: number, high: number): {
|
|
2
3
|
windowWidth: number;
|
|
3
4
|
windowCenter: number;
|
|
4
5
|
};
|
|
5
|
-
declare function toLowHighRange(windowWidth: number, windowCenter: number): {
|
|
6
|
+
declare function toLowHighRange(windowWidth: number, windowCenter: number, voiLUTFunction?: VOILUTFunctionType): {
|
|
6
7
|
lower: number;
|
|
7
8
|
upper: number;
|
|
8
9
|
};
|
|
@@ -1,11 +1,33 @@
|
|
|
1
|
+
import VOILUTFunctionType from '../enums/VOILUTFunctionType';
|
|
2
|
+
import { logit } from './logit';
|
|
1
3
|
function toWindowLevel(low, high) {
|
|
2
4
|
const windowWidth = Math.abs(high - low) + 1;
|
|
3
5
|
const windowCenter = (low + high + 1) / 2;
|
|
4
6
|
return { windowWidth, windowCenter };
|
|
5
7
|
}
|
|
6
|
-
function toLowHighRange(windowWidth, windowCenter) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
function toLowHighRange(windowWidth, windowCenter, voiLUTFunction = VOILUTFunctionType.LINEAR) {
|
|
9
|
+
if (voiLUTFunction === VOILUTFunctionType.LINEAR) {
|
|
10
|
+
return {
|
|
11
|
+
lower: windowCenter - 0.5 - (windowWidth - 1) / 2,
|
|
12
|
+
upper: windowCenter - 0.5 + (windowWidth - 1) / 2,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
else if (voiLUTFunction === VOILUTFunctionType.LINEAR_EXACT) {
|
|
16
|
+
return {
|
|
17
|
+
lower: windowCenter - windowWidth / 2,
|
|
18
|
+
upper: windowCenter + windowWidth / 2,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
else if (voiLUTFunction === VOILUTFunctionType.SAMPLED_SIGMOID) {
|
|
22
|
+
const xLower = logit(0.01, windowCenter, windowWidth);
|
|
23
|
+
const xUpper = logit(0.99, windowCenter, windowWidth);
|
|
24
|
+
return {
|
|
25
|
+
lower: xLower,
|
|
26
|
+
upper: xUpper,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
throw new Error('Invalid VOI LUT function');
|
|
31
|
+
}
|
|
10
32
|
}
|
|
11
33
|
export { toWindowLevel, toLowHighRange };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "Cornerstone3D Core",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"types": "./dist/esm/index.d.ts",
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
"type": "individual",
|
|
83
83
|
"url": "https://ohif.org/donate"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "df90c42c63dc8392c9ebc2cdd953ee0dd1a974de"
|
|
86
86
|
}
|