@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.
@@ -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)) {
@@ -10,6 +10,7 @@ export default function computeAutoVoi(viewport, image) {
10
10
  viewport.voi = {
11
11
  windowWidth: ww,
12
12
  windowCenter: wc,
13
+ voiLUTFunction: image.voiLUTFunction,
13
14
  };
14
15
  }
15
16
  else {
@@ -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.length) {
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?.windowWidth && voiLutModule.windowCenter) {
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;
@@ -1,5 +1,6 @@
1
1
  declare enum VOILUTFunctionType {
2
2
  LINEAR = "LINEAR",
3
- SAMPLED_SIGMOID = "SIGMOID"
3
+ SAMPLED_SIGMOID = "SIGMOID",
4
+ LINEAR_EXACT = "LINEAR_EXACT"
4
5
  }
5
6
  export default VOILUTFunctionType;
@@ -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: string;
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;
@@ -0,0 +1,3 @@
1
+ export const logit = (y, wc, ww) => {
2
+ return wc - (ww / 4) * Math.log((1 - y) / y);
3
+ };
@@ -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
- const lower = windowCenter - 0.5 - (windowWidth - 1) / 2;
8
- const upper = windowCenter - 0.5 + (windowWidth - 1) / 2;
9
- return { lower, upper };
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.12.3",
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": "dcb9f773764b5937faa31932b84d18ec023587f7"
85
+ "gitHead": "df90c42c63dc8392c9ebc2cdd953ee0dd1a974de"
86
86
  }