IDS peak ICV v1.2.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 if metadata.has_entry_by_key(MetadataKey.DEVICE_EXPOSURE_TIME):
56 c_capture_information.exposure_time = metadata.get_value_by_key(MetadataKey.DEVICE_EXPOSURE_TIME)
57 else:
58 c_capture_information.exposure_time = 0
59
60 return c_capture_information
61
62
63def metadata_from_capture_information(capture_information: peak_icv_capture_information) -> Metadata:
64 return add_metadata_from_capture_information_to_metadata(Metadata(), capture_information)
65
66
68 capture_information: peak_icv_capture_information) -> Metadata:
69 metadata.set_value_by_key(MetadataKey.DEVICE_TIMESTAMP, capture_information.relative_timestamp)
70 metadata.set_value_by_key(MetadataKey.BINNING_HORIZONTAL, capture_information.binning_factor.x)
71 metadata.set_value_by_key(MetadataKey.BINNING_VERTICAL, capture_information.binning_factor.y)
72 metadata.set_value_by_key(MetadataKey.ROI, Rectangle(Point(capture_information.region_of_interest.x,
73 capture_information.region_of_interest.y),
74 Size(capture_information.region_of_interest.width,
75 capture_information.region_of_interest.height)))
76 metadata.set_value_by_key(MetadataKey.DEVICE_EXPOSURE_TIME, capture_information.exposure_time)
77 return metadata
78
79
80def image_handle_to_ctypes(image_handle: int) -> ctypes.c_void_p:
81 return ctypes.c_void_p(int(image_handle))
82
83
84def map_point_type_to_native_type(point_type: Type) -> Type:
85 if point_type == peak_icv_point_f:
86 return float
87
89 "Point type not supported.")
90
91
92def map_point_type_to_enum(point_type: Type) -> peak_icv_point_type:
93 if point_type == peak_icv_point_f:
94 return peak_icv_point_type.PEAK_ICV_POINT_TYPE_XY
95
97 "Point type not supported.")
98
99
100def map_enum_to_point_type(point_enum: peak_icv_point_type) -> Type:
101 if point_enum == peak_icv_point_type.PEAK_ICV_POINT_TYPE_XY:
102 return peak_icv_point_f
103
105 "point_enum not supported " + str(point_enum.value))
106
107
108T = TypeVar('T', bound=Any)
109InputType = Union[Sequence[T], NDArray[T], ctypes.Array[Any]]
110OutputType = Union[MutableSequence[T], NDArray[T], ctypes.Array[Any]]
111
112
113def transform(input_: InputType, output: OutputType, func: Callable) -> None:
114 for i in range(len(input_)):
115 output[i] = func(input_[i])
116
117
118def execute_and_map_return_codes(func: Callable, *args: Any, **kwargs: Any) -> None:
119 def execute_and_map_return_codes_light(func_light: Callable, *args_light: Any, **kwargs_light: Any) -> None:
120 ec = func_light(*args_light, **kwargs_light)
121 ec = peak_icv_status(ec)
122
123 if ec != peak_icv_status.PEAK_ICV_STATUS_SUCCESS:
124 raise ICVException("Could not query the last error!", ec)
125
126 error_code = func(*args, **kwargs)
127
128 try:
129 error_code = peak_icv_status(error_code)
130 except ValueError:
131 # ignore key error here and throw the exception later, which then contains the error message
132 pass
133
134 if error_code != peak_icv_status.PEAK_ICV_STATUS_SUCCESS:
135
136 c_count = ctypes.c_size_t()
137 execute_and_map_return_codes_light(
138 Loader().dll().peak_icv_GetLastErrorMessage_GetCount,
139 ctypes.pointer(c_count))
140
141 if c_count.value == 0:
142 exception_msg = ""
143 else:
144 c_array = create_array(ctypes.c_char, c_count.value)
145 execute_and_map_return_codes_light(Loader().dll().peak_icv_GetLastErrorMessage,
146 c_array, c_count)
147 exception_msg = c_array.value
148
149 if error_code in {
150 peak_icv_status.PEAK_ICV_STATUS_LIBRARY_NOT_INITIALIZED,
151 peak_icv_status.PEAK_ICV_STATUS_DYNAMIC_DEPENDENCY_MISSING,
152 }:
153 raise InvalidConfigurationException(exception_msg, error_code)
154
155 elif error_code == peak_icv_status.PEAK_ICV_STATUS_NULL_POINTER:
156 raise NullPointerException(exception_msg)
157
158 elif error_code == peak_icv_status.PEAK_ICV_STATUS_MISMATCH:
159 raise MismatchException(exception_msg)
160
161 elif error_code == peak_icv_status.PEAK_ICV_STATUS_NOT_SUPPORTED:
162 raise NotSupportedException(exception_msg)
163
164 elif error_code == peak_icv_status.PEAK_ICV_STATUS_NOT_POSSIBLE:
165 raise NotPossibleException(exception_msg)
166
167 elif error_code == peak_icv_status.PEAK_ICV_STATUS_OUT_OF_RANGE:
168 raise OutOfRangeException(exception_msg)
169
170 elif error_code == peak_icv_status.PEAK_ICV_STATUS_MATH_ERROR:
171 raise MathErrorException(exception_msg)
172
173 elif error_code == peak_icv_status.PEAK_ICV_STATUS_TARGET_NOT_FOUND:
174 raise TargetNotFoundException(exception_msg)
175
176 elif error_code == peak_icv_status.PEAK_ICV_STATUS_CORRUPTED:
177 raise CorruptedException(exception_msg)
178
179 elif error_code == peak_icv_status.PEAK_ICV_STATUS_IO_ERROR:
180 raise IOException(exception_msg)
181
182 elif error_code in {
183 peak_icv_status.PEAK_ICV_STATUS_INTERNAL_ERROR,
184 peak_icv_status.PEAK_ICV_STATUS_INVALID_BUFFER_SIZE,
185 peak_icv_status.PEAK_ICV_STATUS_INVALID_HANDLE,
186 }:
187 raise InternalErrorException(exception_msg)
188 else:
189 raise ICVException(exception_msg, error_code)
190
191
193 for path in site.getsitepackages():
194 package_path = os.path.join(path, "ids_peak_ipl")
195 if os.path.isdir(package_path):
196 return package_path
197 raise InvalidConfigurationException("ids_peak_ipl.dll not found.",
198 peak_icv_status.PEAK_ICV_STATUS_DYNAMIC_DEPENDENCY_MISSING)
199
200
201class Loader:
202 _instance = None
203 _dll: ctypes.CDLL | None = None
204
205 def __new__(cls) -> Loader:
206 if cls._instance is None:
207 cls._instance = super(Loader, cls).__new__(cls)
208 file_dir = os.path.dirname(os.path.realpath(__file__))
209
210 if sys.platform.startswith('win'):
211 lib_name = "ids_peak_icv.dll"
212 dll_path = os.path.join(file_dir, "..")
213 os.add_dll_directory(dll_path)
214 ids_peak_ipl_dll_path = find_ids_peak_ipl_dll()
215 os.add_dll_directory(ids_peak_ipl_dll_path)
216 else:
217 lib_name = "libids_peak_icv.so"
218
219 lib_path = os.path.abspath(os.path.join(file_dir, "..", lib_name))
220
221 cls._instance._dll = ctypes.cdll.LoadLibrary(lib_path)
222
223 execute_and_map_return_codes(cls._instance._dll.peak_icv_Init)
224
225 atexit.register(Loader._library_exit)
226
227 return cls._instance
228
229 def dll(self) -> ctypes.CDLL:
230 if self._dll is None:
231 raise NotPossibleException("DLL is not loaded")
232 return self._dll
233
234 # https://docs.python.org/3/reference/datamodel.html From Python Docs: It is not guaranteed that __del__() methods
235 # are called for objects that still exist when the interpreter exits.
236 @staticmethod
237 def _library_exit() -> None:
238 execute_and_map_return_codes(Loader().dll().peak_icv_Exit)
239
240
241ReturnType = TypeVar('ReturnType', bound=ctypes.c_void_p)
242
243
244def check_init_for_classes_with_classmethods_only(class_name: str, return_type: Type[ReturnType],
245 *args: Any, **kwargs: Any) -> ReturnType:
246 try:
247 handle = kwargs["_handle"]
248 if type(handle) is not return_type:
249 raise NotPossibleException(f"Invalid handle type {type(handle)} found.")
250
251 return handle
252 except KeyError:
254 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:63
Type map_enum_to_point_type(peak_icv_point_type point_enum)
Definition utils.py:100
ctypes.c_void_p image_handle_to_ctypes(int image_handle)
Definition utils.py:80
Metadata add_metadata_from_capture_information_to_metadata(Metadata metadata, peak_icv_capture_information capture_information)
Definition utils.py:68
ReturnType check_init_for_classes_with_classmethods_only(str class_name, Type[ReturnType] return_type, *Any args, **Any kwargs)
Definition utils.py:245
Type map_point_type_to_native_type(Type point_type)
Definition utils.py:84
None transform(InputType input_, OutputType output, Callable func)
Definition utils.py:113
None execute_and_map_return_codes(Callable func, *Any args, **Any kwargs)
Definition utils.py:118
peak_icv_point_type map_point_type_to_enum(Type point_type)
Definition utils.py:92
peak_icv_capture_information metadata_to_capture_information(Metadata metadata, Size|None size=None)
Definition utils.py:24