Coverage for openhcs/processing/backends/lib_registry/scikit_image_registry.py: 81.6%
38 statements
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-14 05:57 +0000
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-14 05:57 +0000
1"""
2Clean Scikit-Image Registry Implementation
4Implements clean abstraction with internal library-specific logic.
5All scikit-image-specific details (array compliance, channel_axis, etc.)
6are handled internally without leaking into the ABC.
7"""
8from __future__ import annotations
10import inspect
11import numpy as np
12from functools import wraps
13from typing import Tuple, Callable, List, Any, Dict
15from openhcs.constants import MemoryType
16from openhcs.core.utils import optional_import
17from .unified_registry import LibraryRegistryBase, ProcessingContract, FunctionMetadata
19skimage = optional_import("skimage")
22class SkimageRegistry(LibraryRegistryBase):
23 """Clean scikit-image registry with internal array compliance logic."""
25 # Library-specific exclusions (uses common ones)
26 EXCLUSIONS = LibraryRegistryBase.COMMON_EXCLUSIONS
28 # Modules to scan for functions
29 MODULES_TO_SCAN = ['filters', 'morphology', 'segmentation', 'feature',
30 'measure', 'transform', 'restoration', 'exposure']
32 # Memory type for this registry
33 MEMORY_TYPE = MemoryType.NUMPY.value
35 # Float dtype for this registry
36 FLOAT_DTYPE = np.float32
38 def __init__(self):
39 super().__init__("skimage")
41 # ===== ESSENTIAL ABC METHODS =====
42 def get_library_version(self) -> str:
43 return skimage.__version__
45 def is_library_available(self) -> bool:
46 return skimage is not None
48 def get_library_object(self):
49 return skimage
51 # ===== HOOK IMPLEMENTATIONS =====
52 def _create_array(self, shape: Tuple[int, ...], dtype):
53 return np.random.rand(*shape).astype(dtype)
55 def _check_first_parameter(self, first_param, func_name: str) -> bool:
56 return (first_param.annotation in [np.ndarray, "np.ndarray", "ndarray"] or
57 first_param.name.lower() in {'image', 'input', 'array', 'img'})
59 def _preprocess_input(self, image, func_name: str):
60 return image # No preprocessing needed for scikit-image
62 def _postprocess_output(self, result, original_image, func_name: str):
63 # ProcessingContract system handles dimensional behavior - no categorization needed
64 return result
66 # ===== LIBRARY-SPECIFIC IMPLEMENTATIONS =====
67 def _generate_function_name(self, name: str, module_name: str) -> str:
68 """Generate function name with module prefix."""
69 return f"{module_name}.{name}"
71 def _stack_2d_results(self, func, test_3d):
72 """Stack 2D results using NumPy."""
73 return np.stack([func(test_3d[z]) for z in range(test_3d.shape[0])])
75 def _arrays_close(self, arr1, arr2):
76 """Compare arrays using NumPy."""
77 return np.allclose(arr1, arr2, rtol=1e-5, atol=1e-8)
79 def _expand_2d_to_3d(self, array_2d):
80 """Expand 2D array to 3D using NumPy expansion."""
81 return np.expand_dims(array_2d, 0)