-
Notifications
You must be signed in to change notification settings - Fork 248
[Draft] Add HTJ2K DICOM support #1863
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
base: main
Are you sure you want to change the base?
Conversation
abd51e4 to
a3a54b3
Compare
Key Changes: - Upgrade to pydicom 3.0.0 for HTJ2K support - Replace pydicom-seg with highdicom (pydicom-seg unmaintained) - Add NvDicomReader for GPU-accelerated DICOM decoding with nvidia-nvimgcodec NvDicomReader Features: - HTJ2K transfer syntax support (1.2.840.10008.1.2.4.201/202/203) - Batch decoding optimization for HTJ2K series - Proper spatial slice ordering and affine matrix calculation - Configurable layouts (NumPy D,H,W or ITK W,H,D) - Fallback to pydicom/SimpleITK when nvimgcodec unavailable DICOM SEG Improvements: - Migrate to highdicom for DICOM SEG creation - Memory-efficient processing with stop_before_pixels - Support up to 65,535 segments (uint16) - Preserve ITK/dcmqi fallback path Optional Dependencies: - nvidia-nvimgcodec and dcmqi are now optional - Runtime checks with clear installation instructions Testing: - Comprehensive NvDicomReader tests (HTJ2K decoding, consistency, metadata) - DICOM ↔ NIfTI conversion tests for original and HTJ2K files - Automatic HTJ2K test data generation Signed-off-by: Joaquin Anton Guirao <[email protected]>
3736a2b to
119f000
Compare
Signed-off-by: Joaquin Anton Guirao <[email protected]>
638fd66 to
7e9e7de
Compare
|
Looks good to me.. however better if all E2E is tested and verified for existing use cases to make sure new changes does break. Thank you for trying to improve monai label. |
Signed-off-by: Joaquin Anton Guirao <[email protected]>
…ch processing for large directories Signed-off-by: Joaquin Anton Guirao <[email protected]>
37ca835 to
b652ca7
Compare
… to different series and run monailabel Signed-off-by: Joaquin Anton Guirao <[email protected]>
352defc to
4c70c1f
Compare
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@jantonguirao The frame offsets are used for progressive decoding, download and rendering. References: https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_A.4.html |
@dmoore247 Currently looking into that. I will let you know once I have something ready for evaluation. |
Signed-off-by: Joaquin Anton Guirao <[email protected]>
This commit fixes two critical issues with segmentation display:
1. Segmentations appearing misaligned/misplaced in multi-frame volumes
2. Segmentations misaligned when switching back to previously segmented series
Files modified:
- MonaiLabelPanel.tsx: Core segmentation logic
- PointPrompts.tsx: Removed obsolete method calls
Key changes:
- Use series-specific segmentation IDs (seg-{SeriesUID}) instead of hardcoded '1'
* Prevents conflicts when working with multiple series
* Each series maintains its own independent segmentation
- Defer segmentation creation until first inference run
* Prevents conflicts with default segmentation ID
* Creates segmentation per-series on demand
- Add origin correction: adapt segmentation to image volume origin
* Simple approach: copy image volume origin to segmentation
* No complex camera adjustments or offset calculations
* Segmentation follows image volume's coordinate system
- Detect series switches and reapply origin correction
* Subscribe to viewport grid ACTIVE_VIEWPORT_ID_CHANGED event
* Automatically corrects alignment when switching to existing segmentations
* Handles both tab changes and thumbnail clicks
- Simplify segmentation creation on demand
* Single 500ms retry instead of complex 50-attempt retry mechanism
* Cleaner error handling
Impact:
- Removed 548 lines of complex retry/tracking/correction logic
- Added 136 lines of focused, essential functionality
- Net reduction: 412 lines (41% smaller)
- More maintainable and robust
The solution is elegant: instead of trying to fix the image volume's origin
and adjust cameras accordingly, we simply make the segmentation adapt to
whatever coordinate system the image volume is using. This eliminates all
the complexity around camera position management and origin offset calculations.
Signed-off-by: Joaquin Anton Guirao <[email protected]>
1854d7e to
0a3fd79
Compare
…ation validation
This commit adds extensive test coverage for multi-frame HTJ2K DICOM handling
and improves segmentation output validation across different DICOM formats.
Test Improvements - test_dicom_segmentation.py:
- Add _load_segmentation_array() helper for consistent segmentation loading
- Add _compare_segmentations() helper using Dice coefficient and pixel accuracy
- Refactor test_04 to test_04_compare_all_formats for comprehensive cross-format comparison
* Compares Standard DICOM, HTJ2K, and Multi-frame HTJ2K outputs
* Validates all formats produce highly similar segmentations (Dice > 0.95)
- Improve test_05_compare_dicom_vs_nifti with actual segmentation comparison logic
- Update test_06_multiframe_htj2k_inference with corrected test data path
- Remove redundant tests (test_07, test_08, test_09) - functionality consolidated in test_04
Multi-frame HTJ2K Tests - test_convert.py:
- Add HTJ2K_TRANSFER_SYNTAXES constant for explicit transfer syntax validation
- Add test_transcode_dicom_to_htj2k_multiframe_metadata()
* Validates all DICOM metadata preservation (ImagePositionPatient, ImageOrientationPatient, etc.)
* Verifies per-frame functional groups match original files
* Checks frame ordering and spatial attributes
- Add test_transcode_dicom_to_htj2k_multiframe_lossless()
* Validates pixel-perfect lossless compression
* Verifies all frames match original pixel data
- Add test_transcode_dicom_to_htj2k_multiframe_nifti_consistency()
* Ensures multi-frame HTJ2K produces identical NIfTI output as original series
- Update all transfer syntax checks to use HTJ2K_TRANSFER_SYNTAXES constant
* Replaces .startswith("1.2.840.10008.1.2.4.20") with explicit UID list
* Covers all three HTJ2K variants (lossless, RPCL, lossy)
Code Cleanup:
- Revert debug logging in monailabel/endpoints/infer.py
- Add HTJ2K transfer syntax documentation in convert.py
All tests pass successfully, validating that:
1. Segmentation outputs are consistent across all DICOM formats
2. Multi-frame HTJ2K transcoding preserves all metadata correctly
3. Multi-frame HTJ2K compression is lossless
4. Multi-frame HTJ2K produces identical results to single-frame series
Signed-off-by: Joaquin Anton Guirao <[email protected]>
a4fa128 to
c768909
Compare
- Extract helper functions for frame extraction and validation
- _extract_frames_from_compressed: Extract frames from encapsulated DICOM
(now defaults to 1 frame for single-frame images without NumberOfFrames tag)
- _extract_frames_from_uncompressed: Extract frames from pixel arrays
- _validate_frames: Check for None values in decoded/encoded frames
- _find_dicom_files: Recursively find DICOM files with proper sorting
- Add PhotometricInterpretation update from YBR to RGB
- Prevents double color space conversion by DICOM readers
- Updates metadata to match actual RGB pixel data after nvimgcodec decoding
- Add fancy_upsampling=1 option to nvimgcodec decoder
- Add comprehensive test coverage using pydicom built-in examples:
- test_transcode_multiframe_jpeg_ybr_to_htj2k:
30-frame JPEG with YBR_FULL_422 color space, verifies color space
conversion and PhotometricInterpretation update (max_diff: 4.0, atol=5)
- test_transcode_ct_example_to_htj2k:
Uncompressed CT grayscale (MONOCHROME2), verifies lossless transcoding
- test_transcode_mr_example_to_htj2k:
Uncompressed MR grayscale (MONOCHROME2), verifies lossless transcoding
- test_transcode_rgb_color_example_to_htj2k:
Uncompressed RGB color image, verifies PhotometricInterpretation
preservation and lossless transcoding
- test_transcode_jpeg2k_example_to_htj2k:
JPEG 2000 with YBR_RCT (reversible color transform), verifies
PhotometricInterpretation update and perfect lossless conversion
(max_diff: 0.0)
e2c9b44 to
546e4dc
Compare
…retations. Group frames per PhotometricInterpretation before sending them to decode. Signed-off-by: Joaquin Anton Guirao <[email protected]>
663bdf7 to
13f3377
Compare
This commit adds support for all five JPEG2000 progression orders in HTJ2K encoding, allowing users to optimize compression for different use cases: - LRCP: Layer-Resolution-Component-Position (quality scalability) - RLCP: Resolution-Layer-Component-Position (resolution scalability) - RPCL: Resolution-Position-Component-Layer (progressive by resolution, default) - PCRL: Position-Component-Resolution-Layer (progressive by spatial area) - CPRL: Component-Position-Resolution-Layer (component scalability) Changes: - Extended _setup_htj2k_encode_params() to accept progression_order parameter with validation against supported values - Added proper Transfer Syntax UID mapping for each progression order (1.2.840.10008.1.2.4.201 for LRCP/RLCP/PCRL/CPRL, 1.2.840.10008.1.2.4.202 for RPCL) - Changed bitstream type from JP2 to J2K format - Updated transcode_dicom_to_htj2k() to expose progression_order parameter - Added comprehensive test suite covering all progression orders with various DICOM configurations This enables better control over HTJ2K encoding characteristics based on specific deployment requirements (streaming, quality, resolution scalability). Signed-off-by: Joaquin Anton Guirao <[email protected]>
Introduces a skip_transfer_syntaxes parameter to transcode_dicom_to_htj2k() that allows skipping transcoding for files already in desired formats. Files with specified transfer syntaxes are copied directly to output, avoiding unnecessary re-encoding of already-compressed formats. Default skip list includes: - HTJ2K transfer syntaxes (to avoid re-encoding) - Lossy JPEG 2000 (1.2.840.10008.1.2.4.91) - Lossy JPEG formats (1.2.840.10008.1.2.4.50, 1.2.840.10008.1.2.4.51) Also simplifies Basic Offset Table conditional logic and adds comprehensive unit tests covering skip behavior, statistics tracking, and edge cases. Signed-off-by: Joaquin Anton Guirao <[email protected]>
d3f4725 to
cfab9d0
Compare
Signed-off-by: Joaquin Anton Guirao <[email protected]>
1dba624 to
7b2fd01
Compare
- transcode_dicom_to_htj2k now accepts file_loader (Iterable) instead of input_dir/output_dir - Add DicomFileLoader class for simple file discovery and batching - DicomFileLoader preserves directory structure in output paths - Support for PyTorch DataLoader and any custom iterable - Add proper error handling for files without PixelData in both nvimgcodec and pydicom paths - Files causing exceptions during frame extraction are now properly skipped - Add test demonstrating PyTorch DataLoader compatibility Signed-off-by: Joaquin Anton Guirao <[email protected]>
807548e to
641315a
Compare
for more information, see https://pre-commit.ci
Removed top-level ImagePositionPatient (line ~1102) Was causing OHIF to use same position for all frames → spacing[2] = 0 Removed top-level ImageOrientationPatient (line ~1108) Was interfering with functional groups parsing Added SOPClassUID setting (line ~1115) Now sets 1.2.840.10008.5.1.4.1.1.2.1 (Enhanced CT Image Storage) Removed per-frame PlaneOrientationSequence (line ~1163) Was triggering wrong parsing logic in OHIF Now only in SharedFunctionalGroupsSequence Updated logging messages Reflects actual OHIF requirements and warnings
Remove top-level ImagePositionPatient (prevents 1/Infinity) Keep top-level ImageOrientationPatient (enables MPR button) Remove per-frame PlaneOrientationSequence (prevents wrong parsing) Set correct SOPClassUID (Enhanced CT)
✅ PlanePositionSequence added to every frame (with default if missing) ✅ PlaneOrientationSequence added to SharedFunctionalGroupsSequence (with standard axial if missing) Both are MANDATORY for Enhanced CT multi-frame files to enable MPR in OHIF. Now regenerate your multi-frame files with the updated script and the MPR button should be active
Multi-frame DICOM file showed "1/Infinity" in OHIF MPR-axial viewport while working fine in stack view.
Signed-off-by: Joaquin Anton Guirao <[email protected]>
6051d0d to
f88d03e
Compare
Signed-off-by: Joaquin Anton Guirao <[email protected]>
661ee86 to
2bd3b9e
Compare
for more information, see https://pre-commit.ci
Signed-off-by: Joaquin Anton Guirao <[email protected]>
63a8a1b to
e00d77b
Compare
Signed-off-by: Joaquin Anton Guirao <[email protected]>
for more information, see https://pre-commit.ci
Set top level tags.
Fix washout in CT Scans
for more information, see https://pre-commit.ci
Add HTJ2K DICOM support and upgrade to pydicom 3.0
Key Changes:
NvDicomReader Features:
DICOM SEG Improvements:
Optional Dependencies:
Testing: