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;
}
|