@cornerstonejs/core
Version:
Cornerstone3D Core
54 lines (53 loc) • 2.09 kB
JavaScript
import VOILUTFunctionType from '../enums/VOILUTFunctionType.js';
import { logit } from './logit.js';
import * as windowLevelUtil from './windowLevel.js';
const Y_EPS = 1e-6;
export function mapScalarToViewportVoiIntensity(value, props) {
const { lower, upper } = props.voiRange;
const span = upper - lower;
const fn = props.VOILUTFunction;
const applyInvert = (y) => (props.invert === true ? 1 - y : y);
if (fn === VOILUTFunctionType.SAMPLED_SIGMOID || fn === 'SIGMOID') {
const { windowCenter, windowWidth } = windowLevelUtil.toWindowLevel(lower, upper);
const w = Math.max(Math.abs(windowWidth), 1e-12);
return applyInvert(1 / (1 + Math.exp((-4 * (value - windowCenter)) / w)));
}
if (span === 0 || !Number.isFinite(span)) {
return applyInvert(0);
}
return applyInvert(clamp01((value - lower) / span));
}
export function mapViewportVoiIntensityToScalar(mapped01, props) {
const { lower, upper } = props.voiRange;
const fn = props.VOILUTFunction;
const y = props.invert === true ? clamp01(1 - clamp01(mapped01)) : clamp01(mapped01);
if (fn === VOILUTFunctionType.SAMPLED_SIGMOID || fn === 'SIGMOID') {
const { windowCenter, windowWidth } = windowLevelUtil.toWindowLevel(lower, upper);
const yy = clamp(y, Y_EPS, 1 - Y_EPS);
return logit(yy, windowCenter, windowWidth);
}
const span = upper - lower;
if (span === 0 || !Number.isFinite(span)) {
return lower;
}
return lower + y * span;
}
export function mapMappedBandToRawRange(mappedMin, mappedMax, props) {
const a = Math.min(mappedMin, mappedMax);
const b = Math.max(mappedMin, mappedMax);
const rawAtA = mapViewportVoiIntensityToScalar(a, props);
const rawAtB = mapViewportVoiIntensityToScalar(b, props);
return {
rawMin: Math.min(rawAtA, rawAtB),
rawMax: Math.max(rawAtA, rawAtB),
};
}
function clamp01(x) {
if (!Number.isFinite(x)) {
return 0;
}
return clamp(x, 0, 1);
}
function clamp(x, lo, hi) {
return Math.min(hi, Math.max(lo, x));
}