Source code for Stoner.Image.util

# -*- coding: utf-8 -*-
"""Code adapted from skimage module."""

from __future__ import division

__all__ = ["sign_loss", "prec_loss", "dtype_range", "_dtype", "_dtype2"]
from warnings import warn

import numpy as np

from ..compat import np_version
from ..tools.classes import Options

dtype_range = {
    np.bool_: (False, True),
    np.uint8: (0, 255),
    np.uint16: (0, 65535),
    np.int8: (-128, 127),
    np.int16: (-32768, 32767),
    np.int64: (-(2**63), 2**63 - 1),
    np.uint64: (0, 2**64 - 1),
    np.int32: (-(2**31), 2**31 - 1),
    np.uint32: (0, 2**32 - 1),
    np.float32: (-1.0, 1.0),
    np.float64: (-1.0, 1.0),
}

if np_version.major == 1 and np_version.minor < 24:
    dtype_range[np.bool8] = (False, True)

integer_types = (np.uint8, np.uint16, np.int8, np.int16)

_supported_types = (
    np.bool_,
    np.uint8,
    np.uint16,
    np.uint32,
    np.uint64,
    np.int8,
    np.int16,
    np.int32,
    np.int64,
    np.float32,
    np.float64,
)

dtype_range[np.float16] = (-1, 1)
_supported_types += (np.float16,)


[docs] def sign_loss(dtypeobj_in, dtypeobj): """Warn over loss of sign information when converting image.""" if Options().warnings: warn( "Possible sign loss when converting negative image of type " f"{dtypeobj_in} to positive image of type {dtypeobj}." )
[docs] def prec_loss(dtypeobj_in, dtypeobj): """Warn over precision loss when converting image.""" if Options().warnings: warn(f"Possible precision loss when converting from {dtypeobj_in} to {dtypeobj}")
[docs] def _dtype(itemsize, *dtypes): """Return first of `dtypes` with itemsize greater than `itemsize.""" try: ret = next(dt for dt in dtypes if itemsize < np.dtype(dt).itemsize) except StopIteration: ret = dtypes[0] return ret
[docs] def _dtype2(kind, bits, itemsize=1): """Return dtype of `kind` that can store a `bits` wide unsigned int.""" def _calc(x, y): return x <= y if kind == "u" else x < y s = next(i for i in (itemsize,) + (2, 4, 8) if _calc(bits, i * 8)) return np.dtype(kind + str(s))
def _scale(image, src_bits, dest_bits, dtypeobj_in, dtypeobj, copy=True): """Scale unsigned/positive integers from src_bitsto dest_bits_bits. Numbers can be represented exactly only if dest_bits_is a multiple of n Output array is of same kind as input. """ if src_bits == dest_bits: # Trivial case no scale necessary return image.copy() if copy else image if src_bits > dest_bits: return _down_scale(image, src_bits, dest_bits, dtypeobj_in, dtypeobj) return _up_scale(image, src_bits, dest_bits, dtypeobj_in, dtypeobj) def _down_scale(image, src_bits, dest_bits, dtypeobj_in, dtypeobj, copy=True): """Downscale and image from src_bits to dest_bits.""" kind = image.dtype.kind if image.max() <= 2**dest_bits: prefix = ["uint", "int"][dest_bits % 2] dest_bits += dest_bits % 2 dtype = f"{prefix}{dest_bits}" src_bits += src_bits % 2 if Options().warnings: warn( f"Downcasting {image.dtype} to {dtype} without scaling" + f"because max value {image.max()} fits in {dtype}." ) return image.astype(_dtype2(kind, dest_bits)) prec_loss(dtypeobj_in, dtypeobj) if copy: image2 = np.empty(image.shape, _dtype2(kind, dest_bits)) else: image2 = image np.floor_divide(image, 2 ** (src_bits - dest_bits), out=image2, dtype=image.dtype, casting="unsafe") return image2 def _up_scale(image, src_bits, dest_bits, dtypeobj_in, dtypeobj, copy=True): """Upscale an image from src_bits to dest_bits.""" kind = image.dtype.kind if dest_bits % src_bits == 0: # exact upscale to a multiple of src_bitsbits if copy: image2 = np.empty(image.shape, _dtype2(kind, dest_bits)) else: image2 = np.array(image, _dtype2(kind, dest_bits, image.dtype.itemsize), copy=False) np.multiply(image, (2**dest_bits - 1) // (2**src_bits - 1), out=image2, dtype=image2.dtype) return image2 # upscale to a multiple of src_bitsbits, # then downscale with precision loss prec_loss(dtypeobj_in, dtypeobj) upscale_factor = (dest_bits // src_bits + 1) * src_bits if copy: image2 = np.empty(image.shape, _dtype2(kind, upscale_factor)) else: image2 = image np.multiply(image, (2**upscale_factor - 1) // (2**src_bits - 1), out=image2, dtype=image2.dtype) image2 //= 2 ** (upscale_factor - dest_bits) return image2