Source code for machinevisiontoolbox.base.types

"""
NumPy array conversion utilities for integer and floating-point image data.
"""

from __future__ import annotations

import numpy as np

from machinevisiontoolbox.mvtb_types import Dtype


[docs] def int_image( image: np.ndarray, intclass: Dtype = "uint8", maxintval: int | None = None ) -> np.ndarray: """ Convert image to integer type :param image: input image :type image: ndarray(H,W), ndarray(H,W,P) :param intclass: integer class to convert to, the name of any integer class supported by NumPy, defaults to ``'uint8'`` :type intclass: str or NumPy dtype :param maxintval: maximum value of integer, defaults to maximum positive value of ``image`` datatype :type maxintval: int :return: image with integer pixel types :rtype: ndarray(H,W), ndarray(H,W,P) Return a copy of the image as a NumPy array with pixel values scaled and converted to the integer class ``intclass``. If the input image is: * a floating point class, the pixel values are scaled from an input range of [0.0, 1.0] to a range spanning zero to the maximum positive value of ``intclass``. * an integer class, the pixels are scaled and cast to ``intclass``. The scale factor is the ratio of ``maxintval`` to the maximum positive value of ``inclass``. * the boolean class, False is mapped to zero and True is mapped to the maximum positive value of ``inclass``. Example: .. runblock:: pycon >>> from machinevisiontoolbox import int_image >>> import numpy as np >>> im = np.array([[1,2],[3,4]], 'uint8') >>> int_image(im, 'int16') >>> im = np.array([[False, True],[True, False]]) >>> int_image(im) .. note:: Works for greyscale or color (arbitrary number of planes) image :references: - |RVC3|, Section 10.1. :seealso: :func:`float_image` """ intclass = np.dtype(intclass) if np.issubdtype(image.dtype, bool): return image.astype(intclass) * np.iinfo(intclass).max elif np.issubdtype(image.dtype, np.floating): # rescale to integer scaled = image * np.float64(np.iinfo(intclass).max) return np.rint(scaled).astype(intclass) elif np.issubdtype(image.dtype, np.integer): # scale and cast to different integer type if maxintval is None: maxintval = np.iinfo(image.dtype).max image = image * (np.iinfo(intclass).max / maxintval) return image.astype(intclass) else: raise ValueError("unsupported image data type")
[docs] def float_image( image: np.ndarray, floatclass: Dtype = "float32", maxintval: int | None = None ) -> np.ndarray: """ Convert image to float type :param image: input image :type image: ndarray(H,W), ndarray(H,W,P) :param floatclass: 'single', 'double', 'float32' [default], 'float64' :type floatclass: str or NumPy dtype :param maxintval: maximum value of integer, defaults to maximum positive value of ``image`` datatype :type maxintval: int :return: image with floating point pixel types :rtype: ndarray(H,W), ndarray(H,W,P) Return a copy of the image as a NumPy array with pixels scaled and converted to the float class ``floatclass`` with pixel values spanning the range 0.0 to 1.0. If the input image is: * an integer class, the pixel values are scaled from an input range spanning zero to ``maxintval`` to [0.0, 1.0] * a floating point class, the pixels are cast to change type but not their value. * the boolean class, False is mapped to 0.0 and True is mapped to 1.0. Example: .. runblock:: pycon >>> from machinevisiontoolbox import float_image >>> import numpy as np >>> im = np.array([[1,2],[3,4]], 'uint8') >>> float_image(im) >>> im = np.array([[False, True],[True, False]]) >>> float_image(im) .. note:: Works for greyscale or color (arbitrary number of planes) image :references: - |RVC3|, Section 10.1. :seealso: :func:`int_image` """ floatclass = np.dtype(floatclass) if not np.issubdtype(floatclass, np.floating): raise ValueError("bad float type") if np.issubdtype(image.dtype, np.integer): # rescale the pixel values if maxintval is None: maxintval = np.iinfo(image.dtype).max return image.astype(floatclass) / maxintval elif np.issubdtype(image.dtype, np.floating): # cast to different float type return image.astype(floatclass) elif np.issubdtype(image.dtype, bool): return image.astype(floatclass) else: raise ValueError("unsupported image data type") def image_to_dtype(image: np.ndarray, dtype: str | np.dtype) -> np.ndarray: dtype = np.dtype(dtype) # convert to dtype if it's a string if np.issubdtype(dtype, np.integer): return int_image(dtype) elif np.issubdtype(dtype, np.floating): return float_image(dtype)