WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@cdinea
Copy link
Contributor

@cdinea cdinea commented Nov 21, 2025

cuslide2: GPU-Accelerated decoding via nvImageCodec v0.6.0

Overview

cucim.kit.cuslide2 plugin implementing GPU-accelerated whole-slide imaging (WSI) decoding using nvImageCodec v0.6.0. Replaces CPU-based decoders (libjpeg-turbo, OpenJPEG, libtiff) with GPU equivalents

Vendor Support:

  • ✅ Aperio SVS (JPEG, JPEG2000)
  • ✅ Philips TIFF (JPEG, multi-resolution pyramids)
  • ✅ Generic TIFF (all compression types)

Key Features

  • Direct ROI Decoding: nvImageCodec decodes regions without loading full tiles
  • GPU Memory Path: Direct CUDA allocation, no CPU→GPU copy overhead
  • Metadata Parsing: Enhanced Aperio/Philips XML metadata extraction with nvImageCodec v0.6.0 workarounds
  • Backward Compatible: Maintains same API as cucim.kit.cuslide

Build Instructions

Create Conda Environment:

# Create conda environment with all dependencies based on your CUDA system version - use all_cuda-130 for CUDA 13 and all_cuda-129 for CUDA 12
conda env create -n cucim -f ./conda/environments/all_cuda-130_arch-x86_64.yaml

# Activate environment
conda activate cucim

Build cuslide2 Plugin:

# Set CUDA compiler (uses conda's CUDA toolkit)
export CUDACXX=$CONDA_PREFIX/pkgs/cuda-toolkit/bin/nvcc

# Build libcucim + cuslide2 plugin
./run build_local all release $CONDA_PREFIX

Install Python Package:

# Install in editable mode for development
python -m pip install --editable python/cucim

Testing

Unit Tests (26 tests)

cd python/cucim
python -m pytest tests/unit/clara/test_tiff_read_region.py -v

Expected Output:

================================== test session starts ================================== platform linux -- Python 3.13.9, pytest-8.4.2, pluggy-1.6.0 -- /home/cdinea/miniconda3/envs/cucimcuda/bin/python cachedir: .pytest_cache rootdir: /home/cdinea/Downloads/cucim_pr2/branchremote/cucim/python/cucim configfile: pyproject.toml plugins: cov-7.0.0, xdist-3.8.0, lazy-fixtures-1.4.0 collected 26 items tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_inner[testimg_tiff_stripe_32x24_16_jpeg] PASSED [ 3%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_boundary[testimg_tiff_stripe_32x24_16_jpeg] PASSED [ 7%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_outside[testimg_tiff_stripe_32x24_16_jpeg] PASSED [ 11%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_inner[testimg_tiff_stripe_32x24_16_deflate] PASSED [ 15%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_boundary[testimg_tiff_stripe_32x24_16_deflate] PASSED [ 19%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_outside[testimg_tiff_stripe_32x24_16_deflate] PASSED [ 23%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_inner[testimg_tiff_stripe_32x24_16_raw] PASSED [ 26%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_boundary[testimg_tiff_stripe_32x24_16_raw] PASSED [ 30%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_outside[testimg_tiff_stripe_32x24_16_raw] PASSED [ 34%] tests/unit/clara/test_tiff_read_region.py::test_tiff_outside_of_resolution_level[testimg_tiff_stripe_4096x4096_256_jpeg] PASSED [ 38%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_multiresolution[testimg_tiff_stripe_4096x4096_256_jpeg] PASSED [ 42%] tests/unit/clara/test_tiff_read_region.py::test_region_image_level_data[testimg_tiff_stripe_4096x4096_256_jpeg] PASSED [ 46%] tests/unit/clara/test_tiff_read_region.py::test_region_image_dtype[testimg_tiff_stripe_4096x4096_256_jpeg] PASSED [ 50%] tests/unit/clara/test_tiff_read_region.py::test_tiff_iterator[testimg_tiff_stripe_4096x4096_256_jpeg] PASSED [ 53%] tests/unit/clara/test_tiff_read_region.py::test_tiff_outside_of_resolution_level[testimg_tiff_stripe_4096x4096_256_deflate] PASSED [ 57%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_multiresolution[testimg_tiff_stripe_4096x4096_256_deflate] PASSED [ 61%] tests/unit/clara/test_tiff_read_region.py::test_region_image_level_data[testimg_tiff_stripe_4096x4096_256_deflate] PASSED [ 65%] tests/unit/clara/test_tiff_read_region.py::test_region_image_dtype[testimg_tiff_stripe_4096x4096_256_deflate] PASSED [ 69%] tests/unit/clara/test_tiff_read_region.py::test_tiff_iterator[testimg_tiff_stripe_4096x4096_256_deflate] PASSED [ 73%] tests/unit/clara/test_tiff_read_region.py::test_tiff_outside_of_resolution_level[testimg_tiff_stripe_4096x4096_256_raw] PASSED [ 76%] tests/unit/clara/test_tiff_read_region.py::test_tiff_stripe_multiresolution[testimg_tiff_stripe_4096x4096_256_raw] PASSED [ 80%] tests/unit/clara/test_tiff_read_region.py::test_region_image_level_data[testimg_tiff_stripe_4096x4096_256_raw] PASSED [ 84%] tests/unit/clara/test_tiff_read_region.py::test_region_image_dtype[testimg_tiff_stripe_4096x4096_256_raw] PASSED [ 88%] tests/unit/clara/test_tiff_read_region.py::test_tiff_iterator[testimg_tiff_stripe_4096x4096_256_raw] PASSED [ 92%] tests/unit/clara/test_tiff_read_region.py::test_array_interface_support PASSED [ 96%] tests/unit/clara/test_tiff_read_region.py::test_cuda_array_interface_support PASSED [100%] ================================== 26 passed in 4.04s ===================================

Aperio SVS Validation

python scripts/test_aperio_svs.py --download

Tests:

  • Multi-level pyramid (3 levels expected)
  • GPU decode correctness (1.90× speedup on 2048×2048 tiles)
  • CPU/GPU output comparison
  • ImageDescription XML metadata parsing
  • Associated images (label, macro, thumbnail)
`📥 Downloading Aperio SVS test file...
✅ Test file already exists: /tmp/CMU-1-Small-Region.svs
✅ Plugin configuration: /tmp/.cucim_aperio_test.json
🔬 Testing cuslide2 plugin with Aperio SVS
============================================================
📁 File: /tmp/CMU-1-Small-Region.svs
📂 Loading SVS file...
🔧 Creating IFD[0] from nvImageCodec metadata
Dimensions: 2220x2967, 3 channels, 8 bits/sample
Codec: jpeg (compression=7)
✅ IFD[0] initialization complete
🔧 Creating IFD[1] from nvImageCodec metadata
Dimensions: 574x768, 3 channels, 8 bits/sample
✅ IFD[1] initialization complete
🔧 Creating IFD[2] from nvImageCodec metadata
Dimensions: 387x463, 3 channels, 8 bits/sample
✅ IFD[2] initialization complete
🔧 Creating IFD[3] from nvImageCodec metadata
Dimensions: 1280x431, 3 channels, 8 bits/sample
✅ IFD[3] initialization complete
✅ Loaded in 0.380s
📊 Image Information:
Dimensions: [2967, 2220, 3]
Levels: 3
Device: cpu
🔍 Resolution Levels:
Level 0: 2220x2967 (downsample: 1.0x)
Level 1: 1280x431 (downsample: 4.3x)
Level 2: 387x463 (downsample: 6.1x)
🚀 Testing GPU decode (nvImageCodec)...
✅ GPU decode successful!
Time: 0.5288s
Shape: [512, 512, 3]
🖥️ Testing CPU decode (baseline)...
✅ CPU decode successful!
Time: 0.0029s
📏 Testing larger tile (2048x2048)...
GPU: 0.0092s
CPU: 0.0174s
🎯 Speedup: 1.90x
✅ Test completed successfully!
`

Philips TIFF Validation

python scripts/test_philips_tiff.py /tmp/Philips-1.tiff

Tests:

  • Multi-level pyramid (8 levels expected)
  • GPU decode correctness
  • Philips XML metadata (DPUfsImport format)
  • Associated images (label, macro, thumbnail)
  • DICOM_PIXEL_SPACING extraction
`✅ Plugin configuration: /tmp/.cucim_philips_test.json
============================================================
🔬 Testing Philips TIFF with cuslide2
============================================================
📁 File: /tmp/Philips-1.tiff
📂 Loading Philips TIFF file...
🔧 Creating IFD[0] from nvImageCodec metadata
Dimensions: 45056x35840, 3 channels, 8 bits/sample
✅ IFD[0] initialization complete
[... 7 more IFDs ...]
✅ Loaded in 0.379s
📊 Image Information:
Format: Philips TIFF
Dimensions: [35840, 45056, 3]
Levels: 8
🔍 Resolution Levels:
Level 0: 45056x35840 (downsample: 1.0x)
Level 1: 22528x17920 (downsample: 2.0x)
Level 2: 11264x8960 (downsample: 4.0x)
Level 3: 5632x4480 (downsample: 8.0x)
Level 4: 2816x2240 (downsample: 16.0x)
Level 5: 1408x1120 (downsample: 32.0x)
Level 6: 704x560 (downsample: 64.0x)
Level 7: 352x280 (downsample: 128.0x)
📋 Philips Metadata:
✅ Found 22 Philips metadata entries
DICOM_PIXEL_SPACING: [0.000226891, 0.000226907]
DICOM_MANUFACTURER: Hamamatsu
PIM_DP_IMAGE_TYPE: WSI
... and 16 more entries
📏 Pixel Spacing:
DICOM Pixel Spacing: 0.2269 x 0.2269 μm/pixel
🚀 Testing GPU decode (nvImageCodec)...
✅ GPU decode successful!
Time: 0.5250s
Shape: [512, 512, 3]
🖥️ Testing CPU decode...
✅ CPU decode successful:
Time: 0.0014s
Pixel sum: 189181125, mean: 240.56
📏 Testing larger tile (2048x2048)...
✅ GPU: 0.0168s
🔀 Testing multi-level reads...
✅ Level 0: 0.0010s ([512, 512, 3])
✅ Level 1: 0.0009s ([512, 512, 3])
✅ Level 2: 0.0007s ([512, 512, 3])
✅ Philips TIFF test completed!
`

Known Limitations

  • nvImageCodec v0.6.0 doesn't expose individual TIFF tags (SOFTWARE, etc.) - requires metadata blob inspection
  • Associated images with strip-based layout require full decode (no ROI support for strips)
  • Base64-encoded associated images (macro/label in XML metadata) not yet supported

Migration Guide

No code changes required for existing cuCIM users:

# Same API works with cuslide2
from cucim import CuImage
img = CuImage("slide.svs")
region = img.read_region(location=(0, 0), size=(1024, 1024), device="cuda")

@cdinea cdinea requested review from a team as code owners November 21, 2025 02:50
@copy-pr-bot
Copy link

copy-pr-bot bot commented Nov 21, 2025

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@cdinea
Copy link
Contributor Author

cdinea commented Nov 21, 2025

/ok to test d173ee9

@cdinea cdinea changed the base branch from main to release/25.12 November 21, 2025 18:35
@cdinea cdinea closed this Nov 22, 2025
@cdinea cdinea reopened this Nov 24, 2025
@cdinea cdinea force-pushed the feature/nvimagecodec-v0.6.0 branch from 17e6bb5 to cee8f57 Compare November 24, 2025 19:51
@cdinea cdinea added improvement Improves an existing functionality breaking Introduces a breaking change labels Nov 24, 2025
@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 5d8ae8c

@cdinea cdinea changed the title [WIP] Feat: PR #2 decoding with nvImageCodec v0.6.0 [REVIEW] Feat: PR #2 decoding with nvImageCodec v0.6.0 Nov 25, 2025
@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test ecd8e10

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test cdb1c26

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 9a56b59

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 082014a

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test ad4d5af

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 07979f8

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 367a4f5

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 124307c

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test dea5b27

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 1eb30d0

@cdinea
Copy link
Contributor Author

cdinea commented Nov 25, 2025

/ok to test 27fbe30

@cdinea
Copy link
Contributor Author

cdinea commented Dec 4, 2025

/ok to test b8ae2dd

@cdinea
Copy link
Contributor Author

cdinea commented Dec 4, 2025

/ok to test 4360b5c

Copy link
Contributor

@grlee77 grlee77 left a comment

Choose a reason for hiding this comment

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

Thanks for working on this cuslide2 plugin. It is great to see all the various 3rdparty library functionality being replaced with GPU-accelerated solutions from nvimgcodec!

I have left some minor comments around dependencies, licenses and stray comments. I have now reviewed most files aside from the core new nvimgcodec*.* ones. If you have already gotten good feedback on those from the nvimgcodec team, Gigon or others, please do not hold off merging on my account.

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that this file can be removed? I see there is already a cucim.kit.cuslide2-config.cmake.in and the
cucim.kit.cuslide2/CMakeLists.txt uses that one

    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${CUCIM_PLUGIN_NAME}-config.cmake.in

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you @grlee77 - i addressed this feedback in this commit

Copy link
Contributor

Choose a reason for hiding this comment

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

Can this file be removed like SuperBuildUtils.cmake was? (It seems to be identical to the one in the cpp/plubins/cucuim.kit.cuslide/cmake/modules folder)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you @grlee77 - this will be addressed in the third PR

Copy link
Contributor

Choose a reason for hiding this comment

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

These test scripts are okay for this MR, but let's make a future task to move the testing into automated cases that will be run by pytest on CI. (e.g. move out of this folder and put the tests somewhere under python/cucim/tests/)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you @grlee77 - yes, we added sperataley because they use Aperio SVS and Philips TIFF images and , AFAIK the tests in cucim use synthetic data. But I agree, we should make it part of the test suite

@jakirkham
Copy link
Member

/ok to test 5124f91

@jakirkham
Copy link
Member

The style check is trying to change the license file copyright headers in a way that is inaccurate. Here is the change it proposes:

diff --git a/cpp/plugins/cucim.kit.cuslide2/benchmarks/main.cpp b/cpp/plugins/cucim.kit.cuslide2/benchmarks/main.cpp
index 45dacba..de11f8a 100644
--- a/cpp/plugins/cucim.kit.cuslide2/benchmarks/main.cpp
+++ b/cpp/plugins/cucim.kit.cuslide2/benchmarks/main.cpp
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION.
  * SPDX-License-Identifier: Apache-2.0
  */
 
diff --git a/cpp/plugins/cucim.kit.cuslide2/tests/main.cpp b/cpp/plugins/cucim.kit.cuslide2/tests/main.cpp
index 7d9541b..10ded7e 100644
--- a/cpp/plugins/cucim.kit.cuslide2/tests/main.cpp
+++ b/cpp/plugins/cucim.kit.cuslide2/tests/main.cpp
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
+ * SPDX-FileCopyrightText: Copyright (c) 2020, NVIDIA CORPORATION.
  * SPDX-License-Identifier: Apache-2.0
  */

However both of these files came from cucim.kit.cuslide and are being added/updated for cucim.kit.cuslide2, which will superseded the older version. So the lower bound of the ranges make sense. Also the upper bounds should be 2025, which differs from what the check above tries to do

How can we fix this?

@jakirkham
Copy link
Member

/ok to test 6d2767d

@KyleFromNVIDIA
Copy link
Member

The style check is trying to change the license file copyright headers in a way that is inaccurate.

This is because it's detecting that those files were copied from elsewhere in the repository with no modifications, so it's deferring to the old files' copyright updates.

Making a small change to the contents of the file (outside of the copyright header) should fix it if desired. Otherwise, since it's effectively the same file, it should have the same copyright dates.

@cdinea
Copy link
Contributor Author

cdinea commented Dec 4, 2025

/ok to test 2f22839

@jakirkham
Copy link
Member

Let's address the style check as Kyle noted above ( #978 (comment) ) as the rest of the CI won't run without that

@cdinea
Copy link
Contributor Author

cdinea commented Dec 4, 2025

/ok to test 2f22839

@copy-pr-bot
Copy link

copy-pr-bot bot commented Dec 4, 2025

/ok to test 2f22839

@cdinea, there was an error processing your request: E2

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/

@cdinea
Copy link
Contributor Author

cdinea commented Dec 4, 2025

/ok to test 75515df

@cdinea
Copy link
Contributor Author

cdinea commented Dec 4, 2025

/merge

@rapids-bot rapids-bot bot merged commit a053416 into rapidsai:release/25.12 Dec 4, 2025
60 checks passed
@jakirkham
Copy link
Member

Thanks everyone! 🙏

Remaining items will be addressed in the 3rd PR in this series: #983

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants