Skip to content

Commit

Permalink
fix(multiframe): fix frameNumber for pixelData and windowlevel issue (#…
Browse files Browse the repository at this point in the history
…603)

* fix multiframe index problem

* fix non scaled pt window level lazyniess

* build api

* apply review comments
  • Loading branch information
sedghi authored May 9, 2023
1 parent 5856c93 commit 6bf51b1
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 16 deletions.
4 changes: 4 additions & 0 deletions common/reviews/api/core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,9 @@ function isImageActor(actorEntry: Types.ActorEntry): boolean;
// @public (undocumented)
function isOpposite(v1: Point3, v2: Point3, tolerance?: number): boolean;

// @public (undocumented)
const isPTPrescaledWithSUV: (image: IImage) => number;

// @public (undocumented)
interface IStackViewport extends IViewport {
// (undocumented)
Expand Down Expand Up @@ -2428,6 +2431,7 @@ declare namespace utilities {
snapFocalPointToSlice,
getImageSliceDataForVolumeViewport,
isImageActor,
isPTPrescaledWithSUV,
actorIsA,
getViewportsWithImageURI,
getClosestStackImageIndexForPoint,
Expand Down
5 changes: 4 additions & 1 deletion common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5551,11 +5551,14 @@ export class WindowLevelTool extends BaseTool {
upper: number;
};
// (undocumented)
getPTNewRange({ deltaPointsCanvas, lower, upper, clientHeight }: {
getPTScaledNewRange({ deltaPointsCanvas, lower, upper, clientHeight, viewport, volumeId, isPreScaled, }: {
deltaPointsCanvas: any;
lower: any;
upper: any;
clientHeight: any;
viewport: any;
volumeId: any;
isPreScaled: any;
}): {
lower: any;
upper: any;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/utilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import applyPreset from './applyPreset';
import deepMerge from './deepMerge';
import getScalingParameters from './getScalingParameters';
import getScalarDataType from './getScalarDataType';
import isPTPrescaledWithSUV from './isPTPrescaledWithSUV';

// name spaces
import * as planar from './planar';
Expand Down Expand Up @@ -89,6 +90,7 @@ export {
snapFocalPointToSlice,
getImageSliceDataForVolumeViewport,
isImageActor,
isPTPrescaledWithSUV,
actorIsA,
getViewportsWithImageURI,
getClosestStackImageIndexForPoint,
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/utilities/isPTPrescaledWithSUV.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IImage } from '../types';

const isPTPrescaledWithSUV = (image: IImage) => {
return image.preScale?.scaled && image.preScale.scalingParameters?.suvbw;
};

export default isPTPrescaledWithSUV;
10 changes: 5 additions & 5 deletions packages/core/src/utilities/renderToCanvasGPU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import StackViewport from '../RenderingEngine/StackViewport';
import { IImage } from '../types';
import { getRenderingEngine } from '../RenderingEngine/getRenderingEngine';
import RenderingEngine from '../RenderingEngine';
import isPTPrescaledWithSUV from './isPTPrescaledWithSUV';

/**
* Renders an cornerstone image to a Canvas. This method will handle creation
Expand Down Expand Up @@ -112,7 +113,10 @@ export default function renderToCanvasGPU(
element.addEventListener(Events.IMAGE_RENDERED, onImageRendered);
viewport.renderImageObject(image);

if (modality === 'PT' && !_isPTImagePreScaledWithSUV(image)) {
// force a reset camera to center the image
viewport.resetCamera();

if (modality === 'PT' && !isPTPrescaledWithSUV(image)) {
viewport.setProperties({
voiRange: {
lower: image.minPixelValue,
Expand All @@ -124,7 +128,3 @@ export default function renderToCanvasGPU(
viewport.render();
});
}

const _isPTImagePreScaledWithSUV = (image: IImage) => {
return image.preScale.scaled && image.preScale.scalingParameters.suvbw;
};
17 changes: 16 additions & 1 deletion packages/dicomImageLoader/src/imageLoader/wadouri/loadImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ function addDecache(imageLoadObject: Types.IImageLoadObject, imageId: string) {
};
}

/**
* Given the dataSetPromise and imageId this will return a promise to be
* resolved with an image object containing the loaded image.
*
* @param dataSetPromise - A promise that resolves to a DataSet object.
* @param imageId - The imageId of the image to be loaded.
* @param frame - The frame number to be loaded in case of multiframe. it should
* be noted that this is used to extract the pixelData from dicomParser and
* dicomParser is 0-based index (the first pixelData is frame 0); however,
* in metadata and imageId frame is 1-based index (the first frame is frame 1).
* @param sharedCacheKey - A key to be used to cache the loaded image.
* @param options - Options to be used when loading the image.
* @param callbacks - Callbacks to be called when the image is loaded.
* @returns An object containing a promise to be resolved with the loaded image
*/
function loadImageFromPromise(
dataSetPromise: Promise<DataSet>,
imageId: string,
Expand Down Expand Up @@ -179,7 +194,7 @@ function loadImage(
return loadImageFromDataSet(
dataSet,
imageId,
parsedImageId.frame,
parsedImageId.pixelDataFrame,
parsedImageId.url,
options
);
Expand Down
18 changes: 15 additions & 3 deletions packages/dicomImageLoader/src/imageLoader/wadouri/parseImageId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface CornerstoneImageUrl {
scheme: string;
url: string;
frame: number;
pixelDataFrame: number;
}

function parseImageId(imageId: string): CornerstoneImageUrl {
Expand All @@ -14,16 +15,27 @@ function parseImageId(imageId: string): CornerstoneImageUrl {
let frame;

if (frameIndex !== -1) {
const frameStr = url.substr(frameIndex + 6);
const frameStr = url.substring(frameIndex + 6);

frame = parseInt(frameStr, 10);
url = url.substr(0, frameIndex - 1);
url = url.substring(0, frameIndex - 1);
}

const scheme = imageId.substring(0, firstColonIndex);
/**
* Why we adjust frameNumber? since in the above we are extracting the
* frame number from the imageId (from the metadata), and the frame number
* starts from 1, but in the loader which uses the dicomParser
* the frame number starts from 0.
*/

const adjustedFrame = frame !== undefined ? frame - 1 : undefined;

return {
scheme: imageId.substr(0, firstColonIndex),
scheme,
url,
frame,
pixelDataFrame: adjustedFrame,
};
}

Expand Down
33 changes: 27 additions & 6 deletions packages/tools/src/tools/WindowLevelTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ class WindowLevelTool extends BaseTool {
modality = viewport.modality;
({ lower, upper } = properties.voiRange);
const { preScale } = viewport.getImageData();
isPreScaled = preScale.scaled;
isPreScaled =
preScale.scaled && preScale.scalingParameters?.suvbw !== undefined;
} else {
throw new Error('Viewport is not a valid type');
}
Expand All @@ -74,12 +75,15 @@ class WindowLevelTool extends BaseTool {
// the x direction. For other modalities, use the canvas delta in both
// directions, and if the viewport is a volumeViewport, the multiplier
// is calculate using the volume min and max.
if (modality === PT && isPreScaled) {
newRange = this.getPTNewRange({
if (modality === PT) {
newRange = this.getPTScaledNewRange({
deltaPointsCanvas: deltaPoints.canvas,
lower,
upper,
clientHeight: element.clientHeight,
isPreScaled,
viewport,
volumeId,
});
} else {
newRange = this.getNewRange({
Expand Down Expand Up @@ -112,13 +116,30 @@ class WindowLevelTool extends BaseTool {
}
}

getPTNewRange({ deltaPointsCanvas, lower, upper, clientHeight }) {
getPTScaledNewRange({
deltaPointsCanvas,
lower,
upper,
clientHeight,
viewport,
volumeId,
isPreScaled,
}) {
let multiplier = DEFAULT_MULTIPLIER;

if (isPreScaled) {
multiplier = 5 / clientHeight;
} else {
multiplier =
this._getMultiplierFromDynamicRange(viewport, volumeId) ||
DEFAULT_MULTIPLIER;
}

const deltaY = deltaPointsCanvas[1];
const multiplier = 5 / clientHeight;
const wcDelta = deltaY * multiplier;

upper -= wcDelta;
upper = Math.max(upper, 0.1);
upper = isPreScaled ? Math.max(upper, 0.1) : upper;

return { lower, upper };
}
Expand Down

0 comments on commit 6bf51b1

Please sign in to comment.