import pydicom import numpy as np import logging from PIL import Image logger = logging.getLogger(__name__) def read_dicom_image(file_path): """ Reads a DICOM file and returns it as a NumPy array (grayscale). Handles pixel value scaling and content storage mechanism. """ try: ds = pydicom.dcmread(file_path) # Handle pixel data if 'PixelData' not in ds: raise ValueError(f"No pixel data found in {file_path}") image_data = ds.pixel_array.astype(float) # Handle RescaleSlope and RescaleIntercept if present (Map to Hounsfield Units or physical values) slope = getattr(ds, 'RescaleSlope', 1.0) intercept = getattr(ds, 'RescaleIntercept', 0.0) image_data = image_data * slope + intercept # Normalize to 0-255 range for consistency with standard image processing # Note: This discards absolute physical values but preserves structure for the model image_min = np.min(image_data) image_max = np.max(image_data) if image_max != image_min: image_data = (image_data - image_min) / (image_max - image_min) * 255.0 else: image_data = np.zeros_like(image_data) image_data = image_data.astype(np.uint8) # Handle photometric interpretation (invert if needed) # MONOCHROME1 typically means 0 is white, 255 is black (inverse of standard X-ray) # We generally want air (black) to be low, bone (white) to be high if ds.PhotometricInterpretation == "MONOCHROME1": image_data = 255 - image_data return image_data except Exception as e: logger.error(f"Error reading DICOM {file_path}: {e}") raise