Spaces:
Paused
Paused
fix: Invert PNG/JPEG X-rays before HU conversion for accurate segmentation
Browse filesProblem: PNG/JPEG X-rays have inverted intensities compared to DICOM
- DICOM: lungs = dark (low HU), bones = bright (high HU)
- PNG/JPEG: lungs = bright (high pixels), bones = dark (low pixels)
Solution: Invert PNG/JPEG images (255 - pixel_value) before converting
to Hounsfield Units. This ensures consistent input for TorchXRayVision.
Result: PNG/JPEG segmentation accuracy now matches DICOM accuracy.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
medrax/tools/segmentation/segmentation.py
CHANGED
|
@@ -286,15 +286,19 @@ class ChestXRaySegmentationTool(BaseTool):
|
|
| 286 |
|
| 287 |
# TorchXRayVision models expect images in the range [-1024, 1024] (Hounsfield units)
|
| 288 |
# NOT normalized to [0, 1]! We need to scale 8-bit images to this range.
|
| 289 |
-
#
|
|
|
|
| 290 |
if original_img.dtype == np.uint8 or original_img.max() <= 255:
|
|
|
|
|
|
|
|
|
|
| 291 |
# Scale from [0, 255] to [-1024, 600] (typical lung window in HU)
|
| 292 |
-
img = (
|
| 293 |
-
print(f"
|
| 294 |
else:
|
| 295 |
-
# Assume already in HU or similar range
|
| 296 |
img = original_img.astype(np.float32)
|
| 297 |
-
print(f"Kept original range: [{img.min():.1f}, {img.max():.1f}]")
|
| 298 |
|
| 299 |
img = img[None, ...]
|
| 300 |
print(f"After adding batch dim: {img.shape}")
|
|
|
|
| 286 |
|
| 287 |
# TorchXRayVision models expect images in the range [-1024, 1024] (Hounsfield units)
|
| 288 |
# NOT normalized to [0, 1]! We need to scale 8-bit images to this range.
|
| 289 |
+
# IMPORTANT: PNG/JPEG X-rays are typically INVERTED compared to DICOM
|
| 290 |
+
# (lungs appear bright instead of dark), so we need to invert them first
|
| 291 |
if original_img.dtype == np.uint8 or original_img.max() <= 255:
|
| 292 |
+
# Invert for PNG/JPEG: 255 - pixel_value
|
| 293 |
+
# This makes lungs dark (like DICOM) before HU conversion
|
| 294 |
+
inverted = 255 - original_img.astype(np.float32)
|
| 295 |
# Scale from [0, 255] to [-1024, 600] (typical lung window in HU)
|
| 296 |
+
img = (inverted / 255.0) * 1624 - 1024
|
| 297 |
+
print(f"Inverted and converted 8-bit to HU-like range: [{img.min():.1f}, {img.max():.1f}]")
|
| 298 |
else:
|
| 299 |
+
# Assume already in HU or similar range (DICOM)
|
| 300 |
img = original_img.astype(np.float32)
|
| 301 |
+
print(f"Kept original range (DICOM): [{img.min():.1f}, {img.max():.1f}]")
|
| 302 |
|
| 303 |
img = img[None, ...]
|
| 304 |
print(f"After adding batch dim: {img.shape}")
|