# SCOPE-XR (Single-image Characterization Of PErformance in X-Ray systems)
# Copyright (C) 2026 Jacopo Altieri
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from pathlib import Path
import xml.etree.ElementTree as ET
import numpy as np
from PIL import Image
import pydicom
[docs]
def load_raw_as_ndarray(img_path: str) -> np.ndarray:
"""
Load a RAW image as a numpy ndarray using metadata from the corresponding XML file.
Parameters
----------
img_path
Path to the raw image file (.raw).
Returns
-------
np.ndarray
2D numpy ndarray representing the image.
Raises
------
FileNotFoundError
If the XML metadata file is not found.
"""
img_path_obj = Path(img_path)
xml_path = img_path_obj.with_suffix(".xml")
if not xml_path.exists():
raise FileNotFoundError(f"Metadata XML not found: '{xml_path}'")
# Parse XML and get width and height
tree = ET.parse(xml_path)
root = tree.getroot()
frame = root.find("frame")
img_width = int(frame.find("imgWidth").text)
img_height = int(frame.find("imgHeight").text)
# Read and reshape raw data
with open(img_path, "rb") as f:
img = np.fromfile(f, dtype=np.uint16)
img = img.reshape(img_height, img_width)
return img
[docs]
def load_tiff_as_ndarray(img_path: str) -> np.ndarray:
"""
Load a TIFF image using PIL and convert it to a numpy array.
Parameters
----------
img_path
Path to the TIFF image file (.tif or .tiff)
Returns
-------
np.ndarray
2D numpy ndarray representing the image.
"""
with Image.open(img_path) as img:
return np.array(img)
[docs]
def load_png_as_ndarray(img_path: str) -> np.ndarray:
"""
Load a PNG image using PIL and convert it to a numpy array.
Parameters
----------
img_path
Path to the PNG image file (.png)
Returns
-------
np.ndarray
2D numpy ndarray representing the image.
"""
with Image.open(img_path) as img:
return np.array(img)
[docs]
def load_dicom_as_ndarray(img_path: str) -> np.ndarray:
"""
Load a DICOM image using pydicom and convert it to a numpy array.
Parameters
----------
img_path
Path to the DICOM image file (.dcm)
Returns
-------
np.ndarray
2D numpy ndarray representing the image.
"""
dataset = pydicom.dcmread(img_path)
return dataset.pixel_array
[docs]
def load_image(img_path: str) -> np.ndarray:
"""
Load an image and dispatch to the correct loader based on file extension.
Parameters
----------
img_path
Path to the image file.
Returns
-------
np.ndarray
2D numpy ndarray representing the image.
Notes
-----
Supported formats: ``.raw`` (with matching ``.xml``), ``.tif``/``.tiff``,
``.png``, and ``.dcm``.
"""
ext = Path(img_path).suffix.lower()
if ext == ".raw":
return load_raw_as_ndarray(img_path)
elif ext in [".tif", ".tiff"]:
return load_tiff_as_ndarray(img_path)
elif ext == ".png":
return load_png_as_ndarray(img_path)
elif ext == ".dcm":
return load_dicom_as_ndarray(img_path)
else:
raise ValueError(f"Unsupported image format: {ext}")