Skip to content

Conversation

@mbellehumeur
Copy link
Contributor

@mbellehumeur mbellehumeur commented Sep 18, 2025

Context

ticket: 9788261802

Decimated volume loader that creates a StreamingImageVolume while delegating
volume mutations to a plugin-style modifier chain. The loader still handles the
responsibilities of preparing imageIds (including optional k-axis decimation),
instantiating the streaming volume, and updating VTK/voxel-manager state, but it
now relies on enhancedVolumeModifiers to encapsulate any transformations that
are specific to projection parameters such as decimation.

The loader currently wires a dedicated modifier set for:

  • K-axis decimation handling: Removes slices before metadata generation so
    that spacing reflects the decimated stack without manual scaling.
  • In-plane decimation: Implemented by InPlaneDecimationModifier, which
    updates dimensions, spacing, and DICOM metadata in a self-contained class.

Additional modifiers can be introduced by implementing the shared
decimatedVolumeModifier` interface. For example:

const modifiers = [
  inPlaneDecimationModifier,
  orientationModifier,         // rotates the direction matrix or redefines axis order
  partialRangeModifier,        // limits the volume to a subset of frames / slices
  windowingModifier,           // applies window/level or LUT adjustments at load time
];

The decimation part of this PR allows viewing of volumes that are too large for WebGL and to improve latency for low performance GPU hardware. The features are:

Downsizing with Decimation factor [i,j,k] in enhancedVolumeLoader.

K-axis decimation: Reduces the number of slices by keeping every Nth slice
(e.g., decimation=2 keeps every other slice). This is applied before volume creation
unless already decimated at the displaySet level.

In-plane decimation: Downsamples the resolution of each slice by reducing pixel
dimensions. This is achieved by appending a decimation parameter to imageIds, which
is processed during image loading.

The BaseStreamingVolume has been adjusted to handle the desired dimensions (targetRows and targetColumns)
DecodeImageFrame is used to decode produce the PixelData. The volume spacing, dimensions, and DICOM metadata are adjusted to reflect the decimated resolution.

Downsampling with SampleDistanceMultiplier

Sets the VTK toolkit sampling distance when rendering volumes.

Changes & Results

For downsizing:

  • Added decimatedVolumeLoader which adds i,j decimation parameter to imageIDs.
  • Added VolumeDecimatededLoading example.
  • Modified BaseStreamingImageVolume to set the target dimensions of the image.
  • Added decimation to JLS retrieve.

For downsampling:
Added sampleDistanceMultiplier to

  • ViewportProperties,
  • Cornerstone3DConfig,
  • VolumeViewport3D,
  • createVolumeMapper,
  • BaseVolumeViewport,

Added sampling distance drop down to the the VolumeViewport3D example.

Testing

Example implementation in a viewer:

Exampleviewerusage.1.mp4

Checklist

PR

  • [] My Pull Request title is descriptive, accurate and follows the
    semantic-release format and guidelines.

Code

  • [] My code has been well-documented (function documentation, inline comments,
    etc.)

Public Documentation Updates

  • [] The documentation page has been updated as necessary for any public API
    additions or removals.

Tested Environment

  • [] "OS:
  • [] "Node version:
  • [] "Browser:

@daker
Copy link
Contributor

daker commented Sep 23, 2025

@mbellehumeur great feature, what's still missing to ship it ? do you need help to finish it ?

@mbellehumeur
Copy link
Contributor Author

@mbellehumeur great feature, what's still missing to ship it ? do you need help to finish it ?

Thanks, that would be nice. I'm wondering if additional smoothing can be done.
image

@wayfarer3130
Copy link
Collaborator

@sedghi - how do we want to handle segmentations and annotations in combination with the decimated volumes? There are a few things to think about:

  1. volumeId is different between volumes at different positions
  2. Available world coordinates are not the same, so annotations on one volume may not correspond to image positions on a second one (eg 1/3 and 1/2 decimations only correspond every 6 frames)
  3. Segmentations are also large instances, so probably need a way to create segmentations on the decimation. Indeed having a decimated segmentation might be desirable even in the presence of full resolution data.

Over time, we will have other alternate volume representations - should there be a volume specific method to get the desired alternate volume(s), or should there be a custom actor for displaying decimated volumes, and we can add more actors in the future for other volume types?

…age decimation, including parameter descriptions, examples, and value changes
…ers with a single ijkDecimation array for improved clarity and flexibility; update related interfaces and example usage
@mbellehumeur mbellehumeur changed the title feat(enhancedVolumeLoader): Downsizing and downsampling of volumes. feat(decimatedVolumeLoader): Downsizing and downsampling of volumes. Dec 17, 2025
@mbellehumeur mbellehumeur requested a review from sedghi December 17, 2025 12:14
Copy link
Member

@sedghi sedghi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d

Removing optional chaining since it could hide bugs since it is always required. dimension comes from ImageVolumeProps which uses  DICOM metadata via generateVolumePropsFromImageIds().
@wayfarer3130
Copy link
Collaborator

Please make sure the decimation=... parameter is NOT included in the URL to the back end server.

@wayfarer3130
Copy link
Collaborator

This seems to be failing a number of the required checks - unit tests, format, docusaurus build etc.

Adds detailed documentation for inPlaneDecimationModifier.
Updated comments to provide detailed explanation of the low resolution image loader functionality and its requirements.
@mbellehumeur
Copy link
Contributor Author

Please make sure the decimation=... parameter is NOT included in the URL to the back end server.

That is the name agreed with Denny. What is your suggestion?

@sedghi sedghi changed the title feat(decimatedVolumeLoader): Downsizing and downsampling of volumes. feat(decimatedVolumeLoader): optional downsizing and downsampling of volumes. Dec 18, 2025
@wayfarer3130
Copy link
Collaborator

Please make sure the decimation=... parameter is NOT included in the URL to the back end server.

That is the name agreed with Denny. What is your suggestion?

It isn't a standard DICOM request attribute, so you can't just add a parameter like that. You need to change the load path, or else add a parameter to the DICOM loader to allow using custom names. Basically you need a configuration somewhere that says whether or not to include any extra attributes when applying decimation. If those are not provided, then the server can't respond with a decimated version, and you would have to live with the fact that the image needs to be decimated locally before displaying.

@wayfarer3130 wayfarer3130 merged commit 9b7e311 into cornerstonejs:main Dec 19, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants