From 9f406197b68ff37af51c6f3825be007edf044566 Mon Sep 17 00:00:00 2001 From: Mika Date: Sun, 22 Mar 2026 03:08:31 +0000 Subject: [PATCH] Add image_processing/src/image_processing/core.py --- image_processing/src/image_processing/core.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 image_processing/src/image_processing/core.py diff --git a/image_processing/src/image_processing/core.py b/image_processing/src/image_processing/core.py new file mode 100644 index 0000000..26932f9 --- /dev/null +++ b/image_processing/src/image_processing/core.py @@ -0,0 +1,75 @@ +from __future__ import annotations +import os +from pathlib import Path +from typing import List +import logging +import numpy as np +import cv2 + + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) +ch = logging.StreamHandler() +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + + +class ImageProcessingError(Exception): + """Custom exception for image processing errors.""" + pass + + +def _validate_image_paths(image_list: List[str]) -> List[Path]: + if not isinstance(image_list, list): + raise ValueError("image_list must be a list of file paths.") + valid_paths = [] + for img_path in image_list: + p = Path(img_path) + if not p.exists() or not p.is_file(): + logger.error(f"Invalid image path: {img_path}") + raise ImageProcessingError(f"File not found or invalid: {img_path}") + if p.suffix.lower() not in ['.jpg', '.jpeg', '.png']: + logger.error(f"Unsupported file type: {img_path}") + raise ImageProcessingError(f"Unsupported image format: {p.suffix}") + valid_paths.append(p) + return valid_paths + + +def process_images(image_list: List[str]) -> np.ndarray: + """Verarbeitet eine Liste von Rohbildern und erstellt ein gestacktes, rauschreduziertes Ergebnisbild. + + Args: + image_list (list[str]): Liste von Pfaden zu den zu verarbeitenden Bilddateien. + + Returns: + np.ndarray: Gestacktes kombiniertes Bildarray. + """ + valid_paths = _validate_image_paths(image_list) + + if not valid_paths: + raise ImageProcessingError("No valid image paths provided.") + + images = [] + for path in valid_paths: + img = cv2.imread(str(path), cv2.IMREAD_COLOR) + if img is None: + logger.error(f"Unable to load image: {path}") + raise ImageProcessingError(f"Unable to load image: {path}") + images.append(img.astype(np.float32)) + + # Sicherstellen, dass alle Bilder die gleiche Größe haben + shapes = {im.shape for im in images} + if len(shapes) != 1: + logger.error("Images have differing shapes, unable to stack.") + raise ImageProcessingError("All images must have the same dimensions.") + + # Stacken durch Mittelung + logger.info(f"Stacking {len(images)} images...") + stacked_image = np.mean(images, axis=0) + stacked_image = np.clip(stacked_image, 0, 255).astype(np.uint8) + + logger.info("Stacking complete.") + assert isinstance(stacked_image, np.ndarray), "Output must be a numpy array." + + return stacked_image