All files / packages/core/src/utilities createSigmoidRGBTransferFunction.ts

0% Statements 0/13
0% Branches 0/1
0% Functions 0/5
0% Lines 0/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64                                                                                                                               
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
import { VOIRange } from '../types';
import * as windowLevelUtil from './windowLevel';
 
/**
 * A utility that can be used to generate an Sigmoid RgbTransferFunction.
 * Sigmoid transfer functions are used in the dicom specification:
 * https://dicom.nema.org/medical/dicom/2018b/output/chtml/part03/sect_C.11.2.html
 *
 * @example
 * Setting an RGB Transfer function from the viewport:
 * ```
 * const sigmoidRGBTransferFunction = createSigmoidRGBTransferFunction(0, 255, { lower: 0, upper: 255} );
 * viewport
 *   .getActor()
 *   .getProperty()
 *   .setRGBTransferFunction(0, sigmoidRGBTransferFunction);
 * ```
 *
 * @see {@link https://kitware.github.io/vtk-js/api/Rendering_Core_ColorTransferFunction.html|VTK.js: ColorTransferFunction}
 * @param rgbTransferFunction
 */
export default function createSigmoidRGBTransferFunction(
  voiRange: VOIRange,
  approximationNodes = 1024 // humans can precieve no more than 900 shades of gray doi: 10.1007/s10278-006-1052-3
): vtkColorTransferFunction {
  const { windowWidth, windowCenter } = windowLevelUtil.toWindowLevel(
    voiRange.lower,
    voiRange.upper
  );
 
  // Function is defined by dicom spec
  // https://dicom.nema.org/medical/dicom/2018b/output/chtml/part03/sect_C.11.2.html
  const sigmoid = (x: number, wc: number, ww: number) => {
    return 1 / (1 + Math.exp((-4 * (x - wc)) / ww));
  };
 
  // This function is the analytical inverse of the dicom spec sigmoid function
  // for values y = [0, 1] exclusive. We use this to perform better sampling of
  // points for the LUT as some images can have 2^16 unique values. This method
  // can be deprecated if vtk supports LUTFunctions rather than look up tables
  // or if vtk supports logistic scale. It currently only supports linear and
  // log10 scaling which can be set on the vtkColorTransferFunction
  const logit = (y: number, wc: number, ww: number) => {
    return wc - (ww / 4) * Math.log((1 - y) / y);
  };
 
  // we slice out the first and last value to avoid 0 and 1 Infinity values
  const range = [...Array(approximationNodes + 2).keys()]
    .map((v) => v / (approximationNodes + 2))
    .slice(1, -1);
  const table = range.reduce((res, y) => {
    const x = logit(y, windowCenter, windowWidth);
    return res.concat(x, y, y, y, 0.5, 0.0);
  }, []);
 
  const cfun = vtkColorTransferFunction.newInstance();
  cfun.buildFunctionFromArray(
    vtkDataArray.newInstance({ values: table, numberOfComponents: 6 })
  );
  return cfun;
}