fix(adapters): load co-planar SEGs whose ImageOrientationPatient is DICOM strings#2816
Conversation
…ICOM strings DICOMweb JSON metadata delivers ImageOrientationPatient as DS strings, while the source cosines used to build validOrientations are numeric. The orientation check uses a type-strict equality (utilities.isEqual), so a SEG that is perfectly in-plane with its source was misclassified as perpendicular and rejected with "Segmentations orthogonal to the acquisition plane of the source data are not yet supported." Coerce ImageOrientationPatient to numbers in checkOrientation and when preparing the SEG multiframe metadata (shared + per-frame functional groups), so a string-vs-number mismatch never defeats the comparison. Adds a checkOrientation unit test covering the numeric, string, genuinely-perpendicular, and per-frame-fallback cases.
📝 WalkthroughWalkthroughThe adapter now converts DICOMweb-derived ChangesSegmentation orientation normalization
Estimated code review effort: 3 (Moderate) | ~15–30 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/adapters/src/adapters/helpers/checkOrientation.ts (1)
22-24: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winUse optional chaining to prevent runtime errors.
If a frame is missing the
PlaneOrientationSequence, this direct access will throw aTypeError. Consider using optional chaining, which provides resilience against malformed metadata and aligns with how this sequence is safely accessed in other areas of the codebase.💡 Proposed refactor
const iopRaw = sharedImageOrientationPatient || - PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient; + PerFrameFunctionalGroups?.PlaneOrientationSequence?.ImageOrientationPatient;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/adapters/src/adapters/helpers/checkOrientation.ts` around lines 22 - 24, Update the iopRaw assignment in checkOrientation to use optional chaining when accessing PlaneOrientationSequence and ImageOrientationPatient, while preserving the existing sharedImageOrientationPatient fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/adapters/src/adapters/helpers/checkOrientation.ts`:
- Around line 22-24: Update the iopRaw assignment in checkOrientation to use
optional chaining when accessing PlaneOrientationSequence and
ImageOrientationPatient, while preserving the existing
sharedImageOrientationPatient fallback.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6bf669c3-138c-4eb9-b733-4f951adbc254
📒 Files selected for processing (3)
packages/adapters/src/adapters/Cornerstone3D/Segmentation/labelmapImagesFromBuffer.tspackages/adapters/src/adapters/helpers/checkOrientation.tspackages/adapters/test/checkOrientation.jest.js
Problem
Loading a DICOM SEG that is perfectly in-plane with its source series fails with:
Reproducible against a DICOMweb source (e.g. Orthanc): create a SEG on an axial series, store it, reload — the SEG is rejected as "orthogonal" even though its
ImageOrientationPatientis identical to the source.Root cause
checkOrientationdecides in-plane vs perpendicular withutilities.isEqual(iop, sourceCosines, tolerance), which is type-strict. The source cosines are numeric (parsed from the image'simagePlaneModule), but the SEG'sImageOrientationPatientarrives from DICOMweb JSON metadata as DS strings (["1","0","0","0","1","0"]).isEqual(["1","0",…], [1,0,…], 1e-3)→false→ not in-plane, even though the values are numerically identical.checkIfPerpendicular, which uses arithmetic (string-coercing) and returns true for the parallel row/column cosines → the SEG is classifiedPerpendicularand rejected.So a co-planar SEG is misclassified purely due to a string-vs-number mismatch.
Fix
Coerce
ImageOrientationPatientto numbers before comparison:helpers/checkOrientation.ts— coerce the SEG's IOP in the shared helper (also protects the legacySegmentation_4Xpath).Cornerstone3D/Segmentation/labelmapImagesFromBuffer.ts— normalize the shared and per-framePlaneOrientationSequence.ImageOrientationPatientinprepareSegMultiframeMetadata, so the subsequent per-frame alignment (alignPixelDataWithSourceData) also sees numbers.Test
Adds
packages/adapters/test/checkOrientation.jest.jscovering:PlanarPlanar(the regression; wasPerpendicular)Perpendicular(coercion must not mask real perpendicular SEGs)PlanarAll pass; the string case fails without the fix.
Summary by CodeRabbit