Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pixel normalization #1135

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions packages/core/src/RenderingEngine/StackViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
private voiUpdatedWithSetProperties = false;
private VOILUTFunction: VOILUTFunctionType;
//
private outOfRange = false;
private invert = false;
// The initial invert of the image loaded as opposed to the invert status of the viewport itself (see above).
private initialInvert = false;
Expand Down Expand Up @@ -1386,7 +1387,8 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {

let voiRangeToUse = voiRange;

if (typeof voiRangeToUse === 'undefined') {
if (typeof voiRangeToUse === 'undefined' || this.outOfRange) {
this.outOfRange = false;
const imageData = imageActor.getMapper().getInputData();
const range = imageData.getPointData().getScalars().getRange();
const maxVoiRange = { lower: range[0], upper: range[1] };
Expand Down Expand Up @@ -1782,7 +1784,10 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {

// Update the pixel data in the vtkImageData object with the pixelData
// from the loaded Cornerstone image
updateVTKImageDataWithCornerstoneImage(this._imageData, image);
this.outOfRange = updateVTKImageDataWithCornerstoneImage(
this._imageData,
image
);
}

/**
Expand Down Expand Up @@ -3047,7 +3052,6 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
};

triggerEvent(this.element, Events.COLORMAP_MODIFIED, eventDetail);

}

private unsetColormapGPU() {
Expand Down
51 changes: 51 additions & 0 deletions packages/core/src/RenderingEngine/helpers/normalizePixels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { IImage } from '../../types';
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
import generateLut from './cpuFallback/rendering/generateLut';

export function normalizePixels(vtkImage: vtkImageData, image: IImage): any {
const { windowCenter, windowWidth } = image;
const width = Array.isArray(windowWidth) ? windowWidth[0] : windowWidth;
const center = Array.isArray(windowCenter) ? windowCenter[0] : windowCenter;

const lut = generateLut(image, width, center, false, undefined, undefined);
const pixelData = image.getPixelData();

const numPixels = pixelData.length;
const minPixelValue = image.minPixelValue;
let storedPixelDataIndex = 0;

const numComp = vtkImage.getPointData().getNumberOfComponents();
const textureData = new Float32Array(numPixels);
for (let i = 0; i < numPixels; i++) {
textureData[i * numComp] = 255; // Red
textureData[i * numComp + 1] = 255; // Green
textureData[i * numComp + 2] = 255; // Blue
textureData[i * numComp + 3] = 255; // Alpha
}

if (pixelData instanceof Float32Array) {
while (storedPixelDataIndex < numPixels) {
if (minPixelValue < 0) {
textureData[storedPixelDataIndex * numComp + 3] =
lut[pixelData[storedPixelDataIndex++] + -minPixelValue]; // Alpha
} else {
textureData[storedPixelDataIndex * numComp + 3] =
lut[pixelData[storedPixelDataIndex++]]; // Alpha
}
}
} else {
while (storedPixelDataIndex < numPixels) {
textureData[storedPixelDataIndex * numComp + 3] =
lut[pixelData[storedPixelDataIndex++]]; // Alpha
}
}

const dataArray = vtkDataArray.newInstance({
name: 'Pixels',
numberOfComponents: numComp,
values: textureData,
});

return dataArray;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
import { IImage, PixelDataTypedArray } from '../types';
import { normalizePixels } from '../RenderingEngine/helpers/normalizePixels';

function updateVTKImageDataWithCornerstoneImage(
sourceImageData: vtkImageData,
image: IImage
) {
let outOfRange = false;
const pixelData = image.getPixelData();
if (!sourceImageData.getPointData) {
// This happens for a CanvasActor, that doesn't have the getPointData
Expand All @@ -31,12 +33,22 @@ function updateVTKImageDataWithCornerstoneImage(
image.getPixelData = () => newPixelData;
scalarData.set(newPixelData);
} else {
scalarData.set(pixelData);
const maxPixelValue = image.maxPixelValue;
const minPixelValue = image.minPixelValue;

if (maxPixelValue < 0 && minPixelValue < 0) {
outOfRange = true;
const newPixelData = normalizePixels(sourceImageData, image);
sourceImageData.getPointData().setScalars(newPixelData);
} else {
scalarData.set(pixelData);
}
}

// Trigger modified on the VTK Object so the texture is updated
// TODO: evaluate directly changing things with texSubImage3D later
sourceImageData.modified();
return outOfRange;
}

export { updateVTKImageDataWithCornerstoneImage };