IDS peak ICV v1.1.0
Loading...
Searching...
No Matches
utils.py
Go to the documentation of this file.
1from __future__ import annotations
2import atexit
3import ctypes
4import os
5import site
6import sys
7from typing import Callable, Type, TypeVar, Sequence, Any, MutableSequence, Union
8
9from ids_peak_common import Metadata, MetadataKey, Rectangle, Point, Size
10from ids_peak_icv.backend.datatypes import (peak_icv_status, peak_icv_point_f, peak_icv_point_type,
11 peak_icv_capture_information)
12from ids_peak_icv.exceptions import (InvalidConfigurationException, MismatchException, NotSupportedException,
13 NotPossibleException, OutOfRangeException, MathErrorException,
14 TargetNotFoundException, CorruptedException, IOException, InternalErrorException,
15 ICVException, NullPointerException)
16from numpy.typing import NDArray
17
18
19def create_array(c_type: Any, size: int) -> ctypes.Array:
20 array_class: Type[ctypes.Array] = c_type * size
21 return array_class()
22
23
24def metadata_to_capture_information(metadata: Metadata, size: Size | None = None) -> peak_icv_capture_information:
25 c_capture_information = peak_icv_capture_information()
26
27 if metadata.has_entry_by_key(MetadataKey.DEVICE_TIMESTAMP):
28 c_capture_information.relative_timestamp = metadata.get_value_by_key(MetadataKey.DEVICE_TIMESTAMP)
29 else:
30 c_capture_information.relative_timestamp = 0
31 if metadata.has_entry_by_key(MetadataKey.BINNING_HORIZONTAL):
32 c_capture_information.binning_factor.x = metadata.get_value_by_key(MetadataKey.BINNING_HORIZONTAL)
33 else:
34 c_capture_information.binning_factor.x = 1
35 if metadata.has_entry_by_key(MetadataKey.BINNING_VERTICAL):
36 c_capture_information.binning_factor.y = metadata.get_value_by_key(MetadataKey.BINNING_VERTICAL)
37 else:
38 c_capture_information.binning_factor.y = 1
39 if metadata.has_entry_by_key(MetadataKey.ROI):
40 roi = metadata.get_value_by_key(MetadataKey.ROI)
41 c_capture_information.region_of_interest.x = ctypes.c_uint32(roi.x)
42 c_capture_information.region_of_interest.y = ctypes.c_uint32(roi.y)
43 c_capture_information.region_of_interest.width = ctypes.c_uint32(roi.width)
44 c_capture_information.region_of_interest.height = ctypes.c_uint32(roi.height)
45 else:
46 c_capture_information.region_of_interest.x = 0
47 c_capture_information.region_of_interest.y = 0
48
49 if size is not None:
50 c_capture_information.region_of_interest.width = size.width
51 c_capture_information.region_of_interest.height = size.height
52 else:
53 c_capture_information.region_of_interest.width = 0
54 c_capture_information.region_of_interest.height = 0
55
56 return c_capture_information
57
58
59def metadata_from_capture_information(capture_information: peak_icv_capture_information) -> Metadata:
60 metadata = Metadata()
61 metadata.set_value_by_key(MetadataKey.DEVICE_TIMESTAMP, capture_information.relative_timestamp)
62 metadata.set_value_by_key(MetadataKey.BINNING_HORIZONTAL, capture_information.binning_factor.x)
63 metadata.set_value_by_key(MetadataKey.BINNING_VERTICAL, capture_information.binning_factor.y)
64 metadata.set_value_by_key(MetadataKey.ROI, Rectangle(Point(capture_information.region_of_interest.x,
65 capture_information.region_of_interest.y),
66 Size(capture_information.region_of_interest.width,
67 capture_information.region_of_interest.height)))
68 return metadata
69
70
71def image_handle_to_ctypes(image_handle: int) -> ctypes.c_void_p:
72 return ctypes.c_void_p(int(image_handle))
73
74
75def map_point_type_to_native_type(point_type: Type) -> Type:
76 if point_type == peak_icv_point_f:
77 return float
78
80 "Point type not supported.")
81
82
83def map_point_type_to_enum(point_type: Type) -> peak_icv_point_type:
84 if point_type == peak_icv_point_f:
85 return peak_icv_point_type.PEAK_ICV_POINT_TYPE_XY
86
88 "Point type not supported.")
89
90
91def map_enum_to_point_type(point_enum: peak_icv_point_type) -> Type:
92 if point_enum == peak_icv_point_type.PEAK_ICV_POINT_TYPE_XY:
93 return peak_icv_point_f
94
96 "point_enum not supported " + str(point_enum.value))
97
98
99T = TypeVar('T', bound=Any)
100InputType = Union[Sequence[T], NDArray[T], ctypes.Array[Any]]
101OutputType = Union[MutableSequence[T], NDArray[T], ctypes.Array[Any]]
102
103
104def transform(input_: InputType, output: OutputType, func: Callable) -> None:
105 for i in range(len(input_)):
106 output[i] = func(input_[i])
107
108
109def execute_and_map_return_codes(func: Callable, *args: Any, **kwargs: Any) -> None:
110 def execute_and_map_return_codes_light(func_light: Callable, *args_light: Any, **kwargs_light: Any) -> None:
111 ec = func_light(*args_light, **kwargs_light)
112 ec = peak_icv_status(ec)
113
114 if ec != peak_icv_status.PEAK_ICV_STATUS_SUCCESS:
115 raise ICVException("Could not query the last error!", ec)
116
117 error_code = func(*args, **kwargs)
118
119 try:
120 error_code = peak_icv_status(error_code)
121 except ValueError:
122 # ignore key error here and throw the exception later, which then contains the error message
123 pass
124
125 if error_code != peak_icv_status.PEAK_ICV_STATUS_SUCCESS:
126
127 c_count = ctypes.c_size_t()
128 execute_and_map_return_codes_light(
129 Loader().dll().peak_icv_GetLastErrorMessage_GetCount,
130 ctypes.pointer(c_count))
131
132 if c_count.value == 0:
133 exception_msg = ""
134 else:
135 c_array = create_array(ctypes.c_char, c_count.value)
136 execute_and_map_return_codes_light(Loader().dll().peak_icv_GetLastErrorMessage,
137 c_array, c_count)
138 exception_msg = c_array.value
139
140 if error_code in {
141 peak_icv_status.PEAK_ICV_STATUS_LIBRARY_NOT_INITIALIZED,
142 peak_icv_status.PEAK_ICV_STATUS_DYNAMIC_DEPENDENCY_MISSING,
143 }:
144 raise InvalidConfigurationException(exception_msg, error_code)
145
146 elif error_code == peak_icv_status.PEAK_ICV_STATUS_NULL_POINTER:
147 raise NullPointerException(exception_msg)
148
149 elif error_code == peak_icv_status.PEAK_ICV_STATUS_MISMATCH:
150 raise MismatchException(exception_msg)
151
152 elif error_code == peak_icv_status.PEAK_ICV_STATUS_NOT_SUPPORTED:
153 raise NotSupportedException(exception_msg)
154
155 elif error_code == peak_icv_status.PEAK_ICV_STATUS_NOT_POSSIBLE:
156 raise NotPossibleException(exception_msg)
157
158 elif error_code == peak_icv_status.PEAK_ICV_STATUS_OUT_OF_RANGE:
159 raise OutOfRangeException(exception_msg)
160
161 elif error_code == peak_icv_status.PEAK_ICV_STATUS_MATH_ERROR:
162 raise MathErrorException(exception_msg)
163
164 elif error_code == peak_icv_status.PEAK_ICV_STATUS_TARGET_NOT_FOUND:
165 raise TargetNotFoundException(exception_msg)
166
167 elif error_code == peak_icv_status.PEAK_ICV_STATUS_CORRUPTED:
168 raise CorruptedException(exception_msg)
169
170 elif error_code == peak_icv_status.PEAK_ICV_STATUS_IO_ERROR:
171 raise IOException(exception_msg)
172
173 elif error_code in {
174 peak_icv_status.PEAK_ICV_STATUS_INTERNAL_ERROR,
175 peak_icv_status.PEAK_ICV_STATUS_INVALID_BUFFER_SIZE,
176 peak_icv_status.PEAK_ICV_STATUS_INVALID_HANDLE,
177 }:
178 raise InternalErrorException(exception_msg)
179 else:
180 raise ICVException(exception_msg, error_code)
181
182
184 for path in site.getsitepackages():
185 package_path = os.path.join(path, "ids_peak_ipl")
186 if os.path.isdir(package_path):
187 return package_path
188 raise InvalidConfigurationException("ids_peak_ipl.dll not found.",
189 peak_icv_status.PEAK_ICV_STATUS_DYNAMIC_DEPENDENCY_MISSING)
190
191
192class Loader:
193 _instance = None
194 _dll: ctypes.CDLL | None = None
195
196 def __new__(cls) -> Loader:
197 if cls._instance is None:
198 cls._instance = super(Loader, cls).__new__(cls)
199 file_dir = os.path.dirname(os.path.realpath(__file__))
200
201 if sys.platform.startswith('win'):
202 lib_name = "ids_peak_icv.dll"
203 dll_path = os.path.join(file_dir, "..")
204 os.add_dll_directory(dll_path)
205 ids_peak_ipl_dll_path = find_ids_peak_ipl_dll()
206 os.add_dll_directory(ids_peak_ipl_dll_path)
207 else:
208 lib_name = "libids_peak_icv.so"
209
210 lib_path = os.path.abspath(os.path.join(file_dir, "..", lib_name))
211
212 cls._instance._dll = ctypes.cdll.LoadLibrary(lib_path)
213
214 execute_and_map_return_codes(cls._instance._dll.peak_icv_Init)
215
216 atexit.register(Loader._library_exit)
217
218 return cls._instance
219
220 def dll(self) -> ctypes.CDLL:
221 if self._dll is None:
222 raise NotPossibleException("DLL is not loaded")
223 return self._dll
224
225 # https://docs.python.org/3/reference/datamodel.html From Python Docs: It is not guaranteed that __del__() methods
226 # are called for objects that still exist when the interpreter exits.
227 @staticmethod
228 def _library_exit() -> None:
229 execute_and_map_return_codes(Loader().dll().peak_icv_Exit)
230
231
232ReturnType = TypeVar('ReturnType', bound=ctypes.c_void_p)
233
234
235def check_init_for_classes_with_classmethods_only(class_name: str, return_type: Type[ReturnType],
236 *args: Any, **kwargs: Any) -> ReturnType:
237 try:
238 handle = kwargs["_handle"]
239 if type(handle) is not return_type:
240 raise NotPossibleException(f"Invalid handle type {type(handle)} found.")
241
242 return handle
243 except KeyError:
245 f"Cannot initialize {class_name} with __init__. Please use a classmethod.")
Thrown when input data or a file is malformed, unreadable, or otherwise corrupted.
Base class for all exceptions thrown by the IDS peak ICV library.
Definition exceptions.py:5
Thrown when a file input/output operation fails.
Thrown on unexpected internal system errors.
Definition exceptions.py:39
Thrown when the library configuration is invalid.
Definition exceptions.py:21
Thrown when a mathematical computation fails.
Thrown when input parameters do not match the expected conditions.
Definition exceptions.py:54
Thrown when an operation cannot be performed due to logical constraints.
Definition exceptions.py:85
Thrown when a requested operation is not implemented or supported.
Definition exceptions.py:71
Thrown when attempting to access an object or value that has not been initialized.
Thrown when a value is outside the allowed range.
Thrown when an expected target object is not detected in the input image.
ctypes.Array create_array(Any c_type, int size)
Definition utils.py:19
Metadata metadata_from_capture_information(peak_icv_capture_information capture_information)
Definition utils.py:59
Type map_enum_to_point_type(peak_icv_point_type point_enum)
Definition utils.py:91
ctypes.c_void_p image_handle_to_ctypes(int image_handle)
Definition utils.py:71
ReturnType check_init_for_classes_with_classmethods_only(str class_name, Type[ReturnType] return_type, *Any args, **Any kwargs)
Definition utils.py:236
Type map_point_type_to_native_type(Type point_type)
Definition utils.py:75
None transform(InputType input_, OutputType output, Callable func)
Definition utils.py:104
None execute_and_map_return_codes(Callable func, *Any args, **Any kwargs)
Definition utils.py:109
peak_icv_point_type map_point_type_to_enum(Type point_type)
Definition utils.py:83
peak_icv_capture_information metadata_to_capture_information(Metadata metadata, Size|None size=None)
Definition utils.py:24