1010FromNumpy = Callable [[Any , Any , int ], Any ]
1111StackArrays = Callable [[Sequence [Any ], Any ], Any ]
1212ScaleDtype = Callable [[Any , Any , Any ], Any ]
13+ DtypeName = Callable [[Any ], str ]
14+ CastArray = Callable [[Any , Any , Any ], Any ]
15+ LogicalAnd = Callable [[Any , Any , Any ], Any ]
1316
1417_SCALING_RANGES : dict [str , float | tuple [float , float ]] = {
1518 "uint8" : 255.0 ,
2124
2225
2326def _dtype_name (dtype : Any ) -> str :
27+ declared_name = getattr (dtype , "name" , None )
28+ if declared_name is not None :
29+ return str (declared_name )
2430 return getattr (dtype , "__name__" , str (dtype ).rsplit ("." , maxsplit = 1 )[- 1 ])
2531
2632
33+ def _numpy_dtype_name (dtype : Any ) -> str :
34+ return np .dtype (dtype ).name
35+
36+
37+ def _torch_dtype_name (dtype : Any ) -> str :
38+ return str (dtype ).rsplit ("." , maxsplit = 1 )[- 1 ]
39+
40+
41+ def _tensorflow_dtype_name (dtype : Any ) -> str :
42+ numpy_dtype = getattr (dtype , "as_numpy_dtype" , dtype )
43+ return np .dtype (numpy_dtype ).name
44+
45+
2746def _scaled_values (result : Any , result_min : Any , result_max : Any , target_dtype : Any ) -> Any :
2847 normalized = (result - result_min ) / (result_max - result_min )
2948 range_info = _SCALING_RANGES .get (_dtype_name (target_dtype ))
@@ -59,6 +78,15 @@ def _numpy_stack(values: Sequence[Any], module: Any) -> Any:
5978 return module .stack (values , axis = 0 )
6079
6180
81+ def _numpy_cast (data : Any , dtype : Any , module : Any ) -> Any :
82+ del module
83+ return data .astype (dtype , copy = False )
84+
85+
86+ def _module_logical_and (left : Any , right : Any , module : Any ) -> Any :
87+ return module .logical_and (left , right )
88+
89+
6290def _numpy_scale (result : Any , target_dtype : Any , module : Any ) -> Any :
6391 if not hasattr (result , "dtype" ):
6492 return result
@@ -129,6 +157,10 @@ def _torch_stack(values: Sequence[Any], module: Any) -> Any:
129157 return module .stack (tuple (values ), dim = 0 )
130158
131159
160+ def _torch_cast (data : Any , dtype : Any , module : Any ) -> Any :
161+ return data .to (dtype = _mapped_dtype (dtype , module ))
162+
163+
132164def _mapped_dtype (target_dtype : Any , module : Any ) -> Any :
133165 try :
134166 dtype_name = np .dtype (target_dtype ).name
@@ -173,6 +205,10 @@ def _tensorflow_stack(values: Sequence[Any], module: Any) -> Any:
173205 return module .stack (tuple (values ), axis = 0 )
174206
175207
208+ def _tensorflow_cast (data : Any , dtype : Any , module : Any ) -> Any :
209+ return module .cast (data , _mapped_dtype (dtype , module ))
210+
211+
176212def _tensorflow_scale (result : Any , target_dtype : Any , module : Any ) -> Any :
177213 if not hasattr (result , "dtype" ):
178214 return result
@@ -205,6 +241,14 @@ def _jax_stack(values: Sequence[Any], module: Any) -> Any:
205241 return module .numpy .stack (tuple (values ), axis = 0 )
206242
207243
244+ def _jax_cast (data : Any , dtype : Any , module : Any ) -> Any :
245+ return data .astype (_mapped_dtype (dtype , module .numpy ))
246+
247+
248+ def _jax_logical_and (left : Any , right : Any , module : Any ) -> Any :
249+ return module .numpy .logical_and (left , right )
250+
251+
208252def _jax_scale (result : Any , target_dtype : Any , module : Any ) -> Any :
209253 if not hasattr (result , "dtype" ):
210254 return result
@@ -254,17 +298,18 @@ def _pyclesperanto_stack(values: Sequence[Any], module: Any) -> Any:
254298 return result
255299
256300
301+ def _pyclesperanto_cast (data : Any , dtype : Any , module : Any ) -> Any :
302+ return module .push (module .pull (data ).astype (dtype , copy = False ))
303+
304+
305+ def _pyclesperanto_logical_and (left : Any , right : Any , module : Any ) -> Any :
306+ return module .push (np .logical_and (module .pull (left ), module .pull (right )))
307+
308+
257309def _pyclesperanto_scale (result : Any , target_dtype : Any , module : Any ) -> Any :
258310 if not hasattr (result , "dtype" ):
259311 return result
260- target_is_int = target_dtype in {
261- np .uint8 ,
262- np .uint16 ,
263- np .uint32 ,
264- np .int8 ,
265- np .int16 ,
266- np .int32 ,
267- }
312+ target_is_int = np .issubdtype (np .dtype (target_dtype ), np .integer )
268313 if not (np .issubdtype (result .dtype , np .floating ) and target_is_int ):
269314 return module .push (module .pull (result ).astype (target_dtype ))
270315 result_min = float (module .minimum_of_all_pixels (result ))
@@ -300,6 +345,9 @@ class ArrayOperations:
300345 from_numpy : FromNumpy
301346 stack : StackArrays
302347 scale_dtype : ScaleDtype
348+ dtype_name : DtypeName = _numpy_dtype_name
349+ cast : CastArray = _numpy_cast
350+ logical_and : LogicalAnd = _module_logical_and
303351
304352
305353NUMPY_OPERATIONS = ArrayOperations (
@@ -319,22 +367,30 @@ class ArrayOperations:
319367 from_numpy = _torch_from_numpy ,
320368 stack = _torch_stack ,
321369 scale_dtype = _torch_scale ,
370+ dtype_name = _torch_dtype_name ,
371+ cast = _torch_cast ,
322372)
323373TENSORFLOW_OPERATIONS = ArrayOperations (
324374 to_numpy = _tensorflow_to_numpy ,
325375 from_numpy = _tensorflow_from_numpy ,
326376 stack = _tensorflow_stack ,
327377 scale_dtype = _tensorflow_scale ,
378+ dtype_name = _tensorflow_dtype_name ,
379+ cast = _tensorflow_cast ,
328380)
329381JAX_OPERATIONS = ArrayOperations (
330382 to_numpy = _jax_to_numpy ,
331383 from_numpy = _jax_from_numpy ,
332384 stack = _jax_stack ,
333385 scale_dtype = _jax_scale ,
386+ cast = _jax_cast ,
387+ logical_and = _jax_logical_and ,
334388)
335389PYCLESPERANTO_OPERATIONS = ArrayOperations (
336390 to_numpy = _pyclesperanto_to_numpy ,
337391 from_numpy = _pyclesperanto_from_numpy ,
338392 stack = _pyclesperanto_stack ,
339393 scale_dtype = _pyclesperanto_scale ,
394+ cast = _pyclesperanto_cast ,
395+ logical_and = _pyclesperanto_logical_and ,
340396)
0 commit comments