Files
2026-07-13 12:46:08 +08:00

1344 lines
48 KiB
Python

from __future__ import print_function, division, absolute_import
import warnings
import sys
# unittest only added in 3.4 self.subTest()
if sys.version_info[0] < 3 or sys.version_info[1] < 4:
import unittest2 as unittest
else:
import unittest
# unittest.mock is not available in 2.7 (though unittest2 might contain it?)
try:
import unittest.mock as mock
except ImportError:
import mock
import numpy as np
from imgaug import dtypes as iadt
from imgaug.testutils import ensure_deprecation_warning
class Test_normalize_dtypes(unittest.TestCase):
@mock.patch("imgaug.dtypes.normalize_dtype")
def test_single_non_list(self, mock_nd):
mock_nd.return_value = "foo"
dtypes = iadt.normalize_dtypes("int16")
assert dtypes == ["foo"]
assert mock_nd.call_count == 1
assert mock_nd.call_args_list[0][0][0] == "int16"
def test_single_dtype(self):
dtypes = iadt.normalize_dtypes(np.dtype("int16"))
assert isinstance(dtypes, list)
assert len(dtypes) == 1
assert isinstance(dtypes[0], np.dtype)
assert dtypes[0].name == "int16"
def test_empty_list(self):
dtypes = iadt.normalize_dtypes([])
assert isinstance(dtypes, list)
assert len(dtypes) == 0
@mock.patch("imgaug.dtypes.normalize_dtype")
def test_list_of_dtype_names(self, mock_nd):
mock_nd.return_value = "foo"
dtypes = iadt.normalize_dtypes(["int16", "int32"])
assert dtypes == ["foo", "foo"]
assert mock_nd.call_count == 2
assert mock_nd.call_args_list[0][0][0] == "int16"
assert mock_nd.call_args_list[1][0][0] == "int32"
class Test_normalize_dtype(unittest.TestCase):
def test_dtype(self):
dtype = iadt.normalize_dtype(np.dtype("int16"))
assert isinstance(dtype, np.dtype)
assert dtype.name == "int16"
def test_dtype_name(self):
dtype = iadt.normalize_dtype("int16")
assert isinstance(dtype, np.dtype)
assert dtype.name == "int16"
def test_dtype_name_short(self):
dtype = iadt.normalize_dtype("i2")
assert isinstance(dtype, np.dtype)
assert dtype.name == "int16"
def test_dtype_function(self):
dtype = iadt.normalize_dtype(np.int16)
assert isinstance(dtype, np.dtype)
assert dtype.name == "int16"
def test_ndarray(self):
arr = np.zeros((1,), dtype=np.int16)
dtype = iadt.normalize_dtype(arr)
assert isinstance(dtype, np.dtype)
assert dtype.name == "int16"
def test_numpy_scalar(self):
scalar = np.int16(0)
dtype = iadt.normalize_dtype(scalar)
assert isinstance(dtype, np.dtype)
assert dtype.name == "int16"
# change_dtype_() is already indirectly tested via Test_change_dtypes_(),
# so were don't have to be very thorough here
class Test_change_dtype_(unittest.TestCase):
def test_no_clip_no_round(self):
arr = np.array([[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0]],
dtype=np.float32)
dtype = np.int8
observed = iadt.change_dtype_(np.copy(arr), dtype,
clip=False, round=False)
expected = np.array([[0, 0, 0, -128+1-1, 127-1+1]], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
def test_clip_and_round(self):
arr = np.array([[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0]],
dtype=np.float32)
dtype = np.int8
observed = iadt.restore_dtypes_(np.copy(arr), dtype)
expected = np.array([[0, 0, 1, 127, -128]], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
def test_dtype_not_changed(self):
arr = np.array([[-128, -1, 0, 1, 127]], dtype=np.int8)
dtype = np.int8
observed = iadt.restore_dtypes_(arr, dtype,
clip=False, round=False)
assert observed is arr
@mock.patch('numpy.round')
def test_no_round_if_dtype_not_changed(self, mock_round):
arr = np.array([[-128, -1, 0, 1, 127]], dtype=np.int8)
dtype = np.int8
observed = iadt.restore_dtypes_(arr, dtype, clip=False)
assert observed is arr
assert mock_round.call_count == 0
def test_round_float_dtypes(self):
arr = np.array([[-128, -1.1, 0.7, 1.1, 127]], dtype=np.float32)
dtype = np.int8
observed = iadt.restore_dtypes_(np.copy(arr), dtype, clip=False)
expected = np.array([[-128, -1, 1, 1, 127]], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
@mock.patch('numpy.round')
def test_dont_round_non_float_dtypes(self, mock_round):
arr = np.array([[-128, -1, 0, 1, 127]], dtype=np.int8)
dtype = np.float32
_ = iadt.restore_dtypes_(np.copy(arr), dtype, clip=False)
assert mock_round.call_count == 0
def test_int16_to_int8(self):
arr = np.zeros((1,), dtype=np.int16) + 1
observed = iadt.change_dtype_(arr, np.int8, clip=False, round=False)
assert observed.shape == (1,)
assert observed.dtype.name == "int8"
assert np.all(observed == 1)
def test_int16_to_int8_with_overflow(self):
arr = np.zeros((1,), dtype=np.int16) + 128
observed = iadt.change_dtype_(arr, np.int8, clip=False, round=False)
assert observed.shape == (1,)
assert observed.dtype.name == "int8"
assert np.all(observed == -128)
def test_float32_to_int8(self):
arr = np.zeros((1,), dtype=np.int32) + 1
observed = iadt.change_dtype_(arr, np.int8, clip=False, round=False)
assert observed.shape == (1,)
assert observed.dtype.name == "int8"
assert np.all(observed == 1)
def test_float32_to_int8_with_overflow(self):
arr = np.zeros((1,), dtype=np.int32) + 1
observed = iadt.change_dtype_(arr, np.int8, clip=False, round=False)
assert observed.shape == (1,)
assert observed.dtype.name == "int8"
assert np.all(observed == 1)
def test_dtype_given_as_string(self):
arr = np.zeros((1,), dtype=np.int8) + 1
observed = iadt.change_dtype_(arr, "int16", clip=False, round=False)
assert observed.shape == (1,)
assert observed.dtype.name == "int16"
assert np.all(observed == 1)
class Test_change_dtypes_(unittest.TestCase):
def test_array_input_single_dtype_no_clip_no_round(self):
arr = np.array([[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0]],
dtype=np.float32)
dtype = np.int8
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=False, round=False)
expected = np.array([[0, 0, 0, -128+1-1, 127-1+1]], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
def test_array_input_single_dtype_with_clip_no_round(self):
arr = np.array([[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0]],
dtype=np.float32)
dtype = np.int8
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=True, round=False)
expected = np.array([[0, 0, 0, 127, -128]], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
def test_array_input_single_dtype_no_clip_with_round(self):
arr = np.array([[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0]],
dtype=np.float32)
dtype = np.int8
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=False, round=True)
expected = np.array([[0, 0, 1, -128+1-1, 127-1+1]], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
def test_array_input_fail_if_many_different_dtypes(self):
arr = np.array([
[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0],
[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0],
], dtype=np.float32)
dtypes = [np.int8, np.int16]
with self.assertRaises(AssertionError) as context:
_observed = iadt.restore_dtypes_(np.copy(arr), dtypes,
clip=False, round=False)
assert (
"or an iterable of N times the *same* dtype"
in str(context.exception)
)
def test_array_input_many_dtypes_no_clip_no_round(self):
arr = np.array([
[0.0, 0.1, 0.9, 127.0+0.0, -128.0-0.0],
[0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0],
], dtype=np.float32)
dtypes = [np.int8, np.int8]
observed = iadt.restore_dtypes_(np.copy(arr), dtypes,
clip=False, round=False)
expected = np.array([
[0, 0, 0, 127, -128],
[0, 0, 0, -128+1-1, 127-1+1]
], dtype=np.int8)
assert observed.dtype.name == "int8"
assert np.array_equal(observed, expected)
def test_empty_array_input(self):
arr = np.zeros((0, 5), dtype=np.float32)
dtypes = np.int8
observed = iadt.restore_dtypes_(np.copy(arr), dtypes,
clip=False, round=False)
assert observed.dtype.name == "int8"
assert observed.shape == (0, 5)
def test_empty_list_input(self):
arrs = []
dtypes = np.int8
observed = iadt.restore_dtypes_(arrs, dtypes,
clip=False, round=False)
assert len(observed) == 0
def test_many_items_list_input_single_dtype(self):
arrs = [
np.array([0.0, 0.1, 0.9, 127.0+0.0, -128.0-0.0], dtype=np.float32),
np.array([0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0], dtype=np.float32)
]
dtypes = np.int8
observed = iadt.restore_dtypes_(
[np.copy(arr) for arr in arrs],
dtypes,
clip=False,
round=False)
expected = [
np.array([0, 0, 0, 127, -128], dtype=np.int8),
np.array([0, 0, 0, -128+1-1, 127-1+1], dtype=np.int8)
]
assert len(observed) == 2
assert observed[0].dtype.name == "int8"
assert observed[1].dtype.name == "int8"
assert np.array_equal(observed[0], expected[0])
assert np.array_equal(observed[1], expected[1])
def test_many_items_list_input_many_dtypes(self):
arrs = [
np.array([0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0], dtype=np.float32),
np.array([0.0, 0.1, 0.9, 127.0+1.0, -128.0-1.0], dtype=np.float32)
]
dtypes = [np.int8, np.int16]
observed = iadt.restore_dtypes_(
[np.copy(arr) for arr in arrs],
dtypes,
clip=False,
round=False)
expected = [
np.array([0, 0, 0, -128+1-1, 127-1+1], dtype=np.int8),
np.array([0, 0, 0, 127+1, -128-1], dtype=np.int16)
]
assert len(observed) == 2
assert observed[0].dtype.name == "int8"
assert observed[1].dtype.name == "int16"
assert np.array_equal(observed[0], expected[0])
assert np.array_equal(observed[1], expected[1])
def test_invalid_input(self):
arr = False
with self.assertRaises(Exception) as context:
_ = iadt.restore_dtypes_(arr, np.int8)
assert "Expected numpy array or " in str(context.exception)
def test_int_to_float(self):
arr = np.array([[-100, -1, 0, 1, 100]], dtype=np.int8)
dtype = np.float32
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=False, round=False)
expected = np.array([[-100.0, -1.0, 0.0, 1.0, 100.0]],
dtype=np.float32)
assert observed.dtype.name == "float32"
assert np.allclose(observed, expected)
def test_increase_float_resolution(self):
arr = np.array([[-100.0, -1.0, 0.0, 1.0, 100.0]], dtype=np.float32)
dtype = np.float64
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=False, round=False)
expected = np.array([[-100.0, -1.0, 0.0, 1.0, 100.0]],
dtype=np.float32)
assert observed.dtype.name == "float64"
assert np.allclose(observed, expected)
def test_int_to_uint(self):
arr = np.array([[-100, -1, 0, 1, 100]], dtype=np.int8)
dtype = np.uint8
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=False, round=False)
expected = np.array([[255-100+1, 255-1+1, 0, 1, 100]],
dtype=np.uint8)
assert observed.dtype.name == "uint8"
assert np.allclose(observed, expected)
def test_int_to_uint_with_clip(self):
arr = np.array([[-100, -1, 0, 1, 100]], dtype=np.int8)
dtype = np.uint8
observed = iadt.restore_dtypes_(np.copy(arr), dtype,
clip=True, round=False)
expected = np.array([[0, 0, 0, 1, 100]], dtype=np.uint8)
assert observed.dtype.name == "uint8"
assert np.allclose(observed, expected)
# TODO is the copy_* function still used anywhere
class Test_copy_dtypes_for_restore(unittest.TestCase):
def test_images_as_list(self):
# TODO using dtype=np.bool is causing this to fail as it ends up
# being <type bool> instead of <type 'numpy.bool_'>.
# Any problems from that for the library?
images = [
np.zeros((1, 1, 3), dtype=np.uint8),
np.zeros((10, 16, 3), dtype=np.float32),
np.zeros((20, 10, 6), dtype=np.int32)
]
dtypes_copy = iadt.copy_dtypes_for_restore(images, force_list=False)
assert np.all([
dtype_observed.name == dtype_expected
for dtype_observed, dtype_expected
in zip(
dtypes_copy,
["uint8", "float32", "int32"]
)
])
def test_images_as_single_array(self):
dts = ["uint8", "float32", "int32"]
for dt in dts:
with self.subTest(dtype=dt):
images = np.zeros((10, 16, 32, 3), dtype=dt)
dtypes_copy = iadt.copy_dtypes_for_restore(images)
assert isinstance(dtypes_copy, np.dtype)
assert dtypes_copy.name == dt
def test_images_as_single_array_force_list(self):
dts = ["uint8", "float32", "int32"]
for dt in dts:
with self.subTest(dtype=dt):
images = np.zeros((10, 16, 32, 3), dtype=dt)
dtypes_copy = iadt.copy_dtypes_for_restore(images,
force_list=True)
assert isinstance(dtypes_copy, list)
assert np.all([dtype_i.name == dt for dtype_i in dtypes_copy])
class Test_increase_itemsize_of_dtype(unittest.TestCase):
def test_factor_is_1(self):
dts = [
np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64,
np.float16, np.float32, np.float64
]
for dt in dts:
dt = np.dtype(dt)
with self.subTest(dtype=dt.name):
dt_increased = iadt.increase_itemsize_of_dtype(dt, 1)
assert dt_increased.name == dt.name
def test_factor_is_2(self):
dts = [
np.int8, np.int16, np.int32,
np.uint8, np.uint16, np.uint32,
np.float16, np.float32
]
expecteds = [
np.int16, np.int32, np.int64,
np.uint16, np.uint32, np.uint64,
np.float32, np.float64
]
for dt, expected in zip(dts, expecteds):
dt = np.dtype(dt)
expected = np.dtype(expected)
with self.subTest(dtype=dt.name):
dt_increased = iadt.increase_itemsize_of_dtype(dt, 2)
assert dt_increased.name == expected.name
def test_dtype_as_string(self):
dt_names = [
"int8", "int16", "int32",
"uint8", "uint16", "uint32",
"float16", "float32"
]
expecteds = [
np.int16, np.int32, np.int64,
np.uint16, np.uint32, np.uint64,
np.float32, np.float64
]
for dt_name, expected in zip(dt_names, expecteds):
expected = np.dtype(expected)
with self.subTest(dtype=dt_name):
dt_increased = iadt.increase_itemsize_of_dtype(dt_name, 2)
assert dt_increased.name == expected.name
def test_unknown_dtype(self):
with self.assertRaises(TypeError) as context:
_ = iadt.increase_itemsize_of_dtype(np.uint64, 2)
assert (
"Unable to create a numpy dtype matching"
in str(context.exception))
class Test_get_minimal_dtype(unittest.TestCase):
def test_with_dtype_function(self):
dt_funcs = [
np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64,
np.float16, np.float32, np.float64,
np.bool_
]
for dt_func in dt_funcs:
with self.subTest(dtype=np.dtype(dt_func).name):
inputs = [dt_func]
promoted_dt = iadt.get_minimal_dtype(inputs)
assert promoted_dt.name == np.dtype(dt_func).name
def test_with_lists_of_identical_dtypes(self):
dts = [
np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64,
np.float16, np.float32, np.float64,
np.bool_
]
for dt in dts:
dt = np.dtype(dt)
for length in [1, 2, 3]:
with self.subTest(dtype=dt.name, length=length):
inputs = [dt for _ in range(length)]
promoted_dt = iadt.get_minimal_dtype(inputs)
assert promoted_dt.name == dt.name
def test_with_lists_of_identical_dtype_arrays(self):
dts = [
np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64,
np.float16, np.float32, np.float64,
np.bool_
]
for dt in dts:
dt = np.dtype(dt)
for length in [1, 2, 3]:
with self.subTest(dtype=dt.name, length=length):
inputs = [np.zeros((1, 1, 3), dtype=dt)
for _ in range(length)]
promoted_dt = iadt.get_minimal_dtype(inputs)
assert promoted_dt.name == dt.name
def test_with_lists_of_different_arrays(self):
dt_lists = [
[np.uint8, np.uint16],
[np.uint8, np.uint32],
[np.uint8, np.int8],
[np.uint8, np.bool_],
[np.int8, np.int16],
[np.float16, np.float32],
[np.uint8, np.float32],
[np.uint8, np.int8, np.int16],
[np.uint8, np.int8, np.bool_],
[np.uint8, np.int8, np.float32],
]
expecteds = [
np.uint16,
np.uint32,
np.int16,
np.uint8,
np.int16,
np.float32,
np.float32,
np.int16,
np.int16,
np.float32
]
for dt_list, expected in zip(dt_lists, expecteds):
expected = np.dtype(expected)
dt_list = [np.dtype(dt) for dt in dt_list]
dt_names = ", ".join([dt.name for dt in dt_list])
with self.subTest(dtypes=dt_names):
promoted_dt = iadt.get_minimal_dtype(dt_list)
assert promoted_dt.name == expected.name
@mock.patch("imgaug.dtypes.increase_itemsize_of_dtype")
def test_calls_increase_itemsize_factor(self, mock_iibf):
dt = np.int8
factor = 2
_ = iadt.get_minimal_dtype([dt], factor)
assert mock_iibf.call_count == 1
class Test_promote_array_dtypes_(unittest.TestCase):
@mock.patch("imgaug.dtypes.get_minimal_dtype")
@mock.patch("imgaug.dtypes.change_dtypes_")
def test_calls_subfunctions(self, mock_cd, mock_gmd):
mock_gmd.return_value = np.dtype("int16")
mock_cd.return_value = "foo"
arrays = [np.zeros((1,), dtype=np.int8)]
observed = iadt.promote_array_dtypes_(arrays)
assert mock_gmd.call_count == 1
assert mock_cd.call_count == 1
# call 0, args, arg 0, dtype 0
assert mock_gmd.call_args_list[0][0][0][0].name == "int8"
assert mock_gmd.call_args_list[0][1]["increase_itemsize_factor"] == 1
assert mock_cd.call_args_list[0][0][0] is arrays
assert observed == "foo"
@mock.patch("imgaug.dtypes.get_minimal_dtype")
@mock.patch("imgaug.dtypes.change_dtypes_")
def test_calls_subfunctions_dtypes_set(self, mock_cd, mock_gmd):
mock_gmd.return_value = np.dtype("int16")
mock_cd.return_value = "foo"
arrays = [np.zeros((1,), dtype=np.int8)]
observed = iadt.promote_array_dtypes_(
arrays,
dtypes=["float32"])
assert mock_gmd.call_count == 1
assert mock_cd.call_count == 1
# call 0, args, arg 0, dtype 0
assert mock_gmd.call_args_list[0][0][0][0] == "float32"
assert mock_gmd.call_args_list[0][1]["increase_itemsize_factor"] == 1
assert mock_cd.call_args_list[0][0][0] is arrays
assert observed == "foo"
@mock.patch("imgaug.dtypes.get_minimal_dtype")
@mock.patch("imgaug.dtypes.change_dtypes_")
def test_calls_subfunctions_increase_itemsize_factor_set(self, mock_cd,
mock_gmd):
mock_gmd.return_value = np.dtype("int16")
mock_cd.return_value = "foo"
arrays = [np.zeros((1,), dtype=np.int8)]
observed = iadt.promote_array_dtypes_(
arrays,
increase_itemsize_factor=2)
assert mock_gmd.call_count == 1
assert mock_cd.call_count == 1
# call 0, args, arg 0, dtype 0
assert mock_gmd.call_args_list[0][0][0][0].name == "int8"
assert mock_gmd.call_args_list[0][1]["increase_itemsize_factor"] == 2
assert mock_cd.call_args_list[0][0][0] is arrays
assert observed == "foo"
def test_promote_single_array(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.promote_array_dtypes_(arr)
assert observed.dtype.name == "int8"
def test_promote_single_array_single_dtype_set(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.promote_array_dtypes_(arr, np.int16)
assert observed.dtype.name == "int16"
def test_promote_single_array_dtypes_set(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.promote_array_dtypes_(arr, [np.int16])
assert observed.dtype.name == "int16"
def test_promote_single_array_increase_itemsize_factor_set(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.promote_array_dtypes_(arr, increase_itemsize_factor=2)
assert observed.dtype.name == "int16"
def test_promote_list_of_single_array(self):
arrays = [np.zeros((1,), dtype=np.int8)]
observed = iadt.promote_array_dtypes_(arrays,
increase_itemsize_factor=2)
assert observed[0].dtype.name == "int16"
def test_promote_list_of_two_arrays(self):
arrays = [np.zeros((1,), dtype=np.int8),
np.zeros((1,), dtype=np.int16)]
observed = iadt.promote_array_dtypes_(arrays,
increase_itemsize_factor=2)
assert observed[0].dtype.name == "int32"
assert observed[1].dtype.name == "int32"
def test_promote_list_of_two_arrays_dtypes_set(self):
arrays = [np.zeros((1,), dtype=np.int8),
np.zeros((1,), dtype=np.int16)]
observed = iadt.promote_array_dtypes_(arrays,
dtypes=[np.float32, np.float64])
assert observed[0].dtype.name == "float64"
assert observed[1].dtype.name == "float64"
def test_promote_list_of_three_arrays(self):
arrays = [np.zeros((1,), dtype=np.int8),
np.zeros((1,), dtype=np.int16),
np.zeros((1,), dtype=np.uint8)]
observed = iadt.promote_array_dtypes_(arrays,
increase_itemsize_factor=2)
assert observed[0].dtype.name == "int32"
assert observed[1].dtype.name == "int32"
assert observed[2].dtype.name == "int32"
class Test_increase_array_resolutions_(unittest.TestCase):
def test_single_array_factor_1(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.increase_array_resolutions_(arr, 1)
assert observed.dtype.name == "int8"
def test_single_array_factor_2(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.increase_array_resolutions_(arr, 2)
assert observed.dtype.name == "int16"
def test_list_of_one_array(self):
arr = np.zeros((1,), dtype=np.int8)
observed = iadt.increase_array_resolutions_([arr], 2)
assert observed[0].dtype.name == "int16"
def test_list_of_two_arrays(self):
arrays = [
np.zeros((1,), dtype=np.int8),
np.zeros((1,), dtype=np.int16)
]
observed = iadt.increase_array_resolutions_(arrays, 2)
assert observed[0].dtype.name == "int16"
assert observed[1].dtype.name == "int32"
class Test_get_value_range_of_dtype(unittest.TestCase):
def test_bool(self):
minv, center, maxv = iadt.get_value_range_of_dtype(np.dtype(bool))
assert minv == 0
assert center is None
assert maxv == 1
def test_uint8_string_name(self):
assert (
iadt.get_value_range_of_dtype("uint8")
== iadt.get_value_range_of_dtype(np.dtype("uint8"))
)
def test_uint8(self):
minv, center, maxv = iadt.get_value_range_of_dtype(np.dtype("uint8"))
assert minv == 0
assert np.isclose(center, 0.5*255)
assert maxv == 255
def test_uint16(self):
minv, center, maxv = iadt.get_value_range_of_dtype(np.dtype("uint16"))
assert minv == 0
assert np.isclose(center, 0.5*65535)
assert maxv == 65535
def test_int8(self):
minv, center, maxv = iadt.get_value_range_of_dtype(np.dtype("int8"))
assert minv == -128
assert np.isclose(center, -0.5)
assert maxv == 127
def test_int16(self):
minv, center, maxv = iadt.get_value_range_of_dtype(np.dtype("int16"))
assert minv == -32768
assert np.isclose(center, -0.5)
assert maxv == 32767
def test_float16(self):
minv, center, maxv = iadt.get_value_range_of_dtype(np.dtype("float16"))
assert minv < 100.0
assert np.isclose(center, 0.0)
assert maxv > 100.0
# TODO extend tests towards all dtypes and actual minima/maxima of value ranges
# TODO what happens if both bounds are negative, but input dtype is uint*?
class Test_clip_(unittest.TestCase):
def test_values_hit_lower_bound_int32(self):
arr = np.int32([0, 1, 2, 3, 4, 5])
observed = iadt.clip_(arr, 0, 10)
assert np.array_equal(observed, np.int32([0, 1, 2, 3, 4, 5]))
def test_values_hit_lower_and_upper_bound_int32(self):
arr = np.int32([0, 1, 2, 3, 4, 5])
observed = iadt.clip_(arr, 0, 5)
assert np.array_equal(observed, np.int32([0, 1, 2, 3, 4, 5]))
def test_values_hit_lower_bound_exceed_upper_bound_int32(self):
arr = np.int32([0, 1, 2, 3, 4, 5])
observed = iadt.clip_(arr, 0, 4)
assert np.array_equal(observed, np.int32([0, 1, 2, 3, 4, 4]))
def test_values_exceed_lower_bound_float32(self):
arr = np.float32([-1.0])
observed = iadt.clip_(arr, 0, 1)
assert np.allclose(observed, np.float32([0.0]))
def test_values_hit_lower_bound_float32(self):
arr = np.float32([-1.0])
observed = iadt.clip_(arr, -1.0, 1)
assert np.allclose(observed, np.float32([-1.0]))
def test_values_hit_lower_bound_uint32(self):
arr = np.uint32([0])
observed = iadt.clip_(arr, 0, 1)
assert np.array_equal(observed, np.uint32([0]))
def test_values_hit_upper_bound_uint32(self):
arr = np.uint32([1])
observed = iadt.clip_(arr, 0, 1)
assert np.array_equal(observed, np.uint32([1]))
def test_values_exceed_upper_bound_uint32(self):
arr = np.uint32([2])
observed = iadt.clip_(arr, 0, 1)
assert np.array_equal(observed, np.uint32([1]))
def test_values_hit_upper_bound_negative_lower_bound_uint32(self):
arr = np.uint32([1])
observed = iadt.clip_(arr, -1, 1)
assert np.array_equal(observed, np.uint32([1]))
def test_values_exceed_upper_bound_negative_lower_bound_uint32(self):
arr = np.uint32([10])
observed = iadt.clip_(arr, -1, 1)
assert np.array_equal(observed, np.uint32([1]))
def test_values_hit_upper_bound_int8(self):
arr = np.int8([127])
observed = iadt.clip_(arr, 0, 127)
assert np.array_equal(observed, np.int8([127]))
def test_values_within_bounds_upper_bound_is_dtype_limit_int8(self):
arr = np.int8([127])
observed = iadt.clip_(arr, 0, 128)
assert np.array_equal(observed, np.int8([127]))
def test_values_hit_upper_bound_negative_lower_bound_int8(self):
arr = np.int8([127])
observed = iadt.clip_(arr, -1, 127)
assert np.array_equal(observed, np.int8([127]))
def test_both_bounds_are_none_int8(self):
arr = np.int8([1])
observed = iadt.clip_(arr, None, None)
assert np.array_equal(observed, np.int8([1]))
def test_lower_bound_is_none_int8(self):
arr = np.int8([1])
observed = iadt.clip_(arr, None, 10)
assert np.array_equal(observed, np.int8([1]))
def test_upper_bound_is_none_int8(self):
arr = np.int8([1])
observed = iadt.clip_(arr, -10, None)
assert np.array_equal(observed, np.int8([1]))
def test_values_exceed_upper_bound_and_lower_bound_is_none_int8(self):
arr = np.int8([10])
observed = iadt.clip_(arr, None, 1)
assert np.array_equal(observed, np.int8([1]))
def test_values_exceed_lower_bound_and_upper_bound_is_none_int8(self):
arr = np.int8([-10])
observed = iadt.clip_(arr, -1, None)
assert np.array_equal(observed, np.int8([-1]))
def test_numpy_scalar_hits_lower_bound_int8(self):
# single value arrays, shape == tuple()
arr = np.int8(-10)
observed = iadt.clip_(arr, -10, 10)
assert np.array_equal(observed, np.int8(-10))
def test_numpy_scalar_exceeds_lower_bound_int8(self):
arr = np.int8(-10)
observed = iadt.clip_(arr, -1, 10)
assert np.array_equal(observed, np.int8(-1))
def test_numpy_scalar_exceeds_upper_bound_int8(self):
arr = np.int8(10)
observed = iadt.clip_(arr, -10, 1)
assert np.array_equal(observed, np.int8(1))
class Test_clip_to_dtype_value_range(unittest.TestCase):
def test_clip_to_wider_dtype(self):
arr = np.array([-10, -1, 0, 1, 10, 255, 256], dtype=np.int16)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int32, validate=False)
assert np.array_equal(arr_clipped, arr)
assert arr_clipped.dtype.name == "int16"
def test_clip_to_wider_dtype_given_by_name(self):
arr = np.array([-10, -1, 0, 1, 10, 255, 256], dtype=np.int16)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), "int32", validate=False)
assert np.array_equal(arr_clipped, arr)
assert arr_clipped.dtype.name == "int16"
def test_clip_to_wider_dtype_different_kind(self):
arr = np.array([-10, -1, 0, 1, 10, 255, 256], dtype=np.int16)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.float64, validate=False)
assert np.array_equal(arr_clipped, arr)
assert arr_clipped.dtype.name == "int16"
def test_clip_to_same_dtype(self):
arr = np.array([-10, -1, 0, 1, 10, 255, 256], dtype=np.int16)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int16, validate=False)
assert np.array_equal(arr_clipped, arr)
assert arr_clipped.dtype.name == "int16"
def test_clip_to_narrower_dtype(self):
arr = np.array([-10, -1, 0, 1, 10, 255, 256], dtype=np.int16)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=False)
expected = np.array([-10, -1, 0, 1, 10, 127, 127], dtype=np.int16)
assert np.array_equal(arr_clipped, expected)
assert arr_clipped.dtype.name == "int16"
def test_dtype_is_array(self):
arr = np.array([-10, -1, 0, 1, 10, 255, 256], dtype=np.int16)
dt_arr = np.array([1], dtype=np.int32)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), dt_arr, validate=False)
assert np.array_equal(arr_clipped, arr)
assert arr_clipped.dtype.name == "int16"
def test_validate_true_all_values_within_value_range(self):
arr = np.array([-10, -1, 0, 1, 10, 126, 127], dtype=np.int16)
arr_clipped = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=True)
assert np.array_equal(arr_clipped, arr)
assert arr_clipped.dtype.name == "int16"
def test_validate_true_min_value_outside_value_range(self):
arr = np.array([-200, -1, 0, 1, 10, 126, 127], dtype=np.int16)
with self.assertRaises(AssertionError) as context:
_ = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=True)
assert (
"Minimum value of array is outside of allowed value range "
"(-200.0000 vs -128.0000 to 127.0000)." in str(context.exception))
def test_validate_true_max_value_outside_value_range(self):
arr = np.array([-10, -1, 0, 1, 10, 126, 200], dtype=np.int16)
with self.assertRaises(AssertionError) as context:
_ = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=True)
assert (
"Maximum value of array is outside of allowed value range "
"(200.0000 vs -128.0000 to 127.0000)." in str(context.exception))
def test_validate_too_few_values(self):
arr = np.array([-10, 0, 200], dtype=np.int16)
_ = iadt.clip_to_dtype_value_range_(np.copy(arr), np.int8, validate=2)
def test_validate_enough_values(self):
arr = np.array([-10, 0, 200], dtype=np.int16)
with self.assertRaises(AssertionError) as context:
_ = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=3)
assert (
"Maximum value of array is outside of allowed value range "
"(200.0000 vs -128.0000 to 127.0000)." in str(context.exception))
def test_validate_too_many_values(self):
arr = np.array([-10, 0, 200], dtype=np.int16)
with self.assertRaises(AssertionError) as context:
_ = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=100)
assert (
"Maximum value of array is outside of allowed value range "
"(200.0000 vs -128.0000 to 127.0000)." in str(context.exception))
def test_validate_values_set(self):
arr = np.array([-10, -1, 0, 1, 10, 126, 200], dtype=np.int16)
with self.assertRaises(AssertionError) as context:
_ = iadt.clip_to_dtype_value_range_(
np.copy(arr), np.int8, validate=True,
validate_values=(-5, 201))
assert (
"Maximum value of array is outside of allowed value range "
"(201.0000 vs -128.0000 to 127.0000)." in str(context.exception))
class Test_gate_dtypes_strs(unittest.TestCase):
def test_standard_scenario_all_allowed(self):
for _ in range(3):
dtypes = {np.dtype("uint8"), np.dtype("uint8"),
np.dtype("float32"), np.dtype("int64")}
allowed = "uint8 float32 int64"
disallowed = "bool"
iadt.gate_dtypes_strs(dtypes, allowed, disallowed)
def test_standard_scenario_one_disallowed(self):
for _ in range(3):
dtypes = {np.dtype("uint8"), np.dtype("uint8"),
np.dtype("float32"), np.dtype("int64")}
allowed = "uint8 float32"
disallowed = "bool int64"
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes_strs(dtypes, allowed, disallowed)
assert "Got dtype 'int64'" in str(context.exception)
def test_empty_set_as_dtypes(self):
for _ in range(3):
dtypes = set()
allowed = "uint8 float32 int64"
disallowed = "bool"
iadt.gate_dtypes_strs(dtypes, allowed, disallowed)
def test_allowed_dtype_does_not_exist(self):
dtypes = {np.dtype("uint8")}
with self.assertRaises(KeyError):
iadt.gate_dtypes_strs(dtypes, "uint8 int1000", "int8")
def test_disallowed_dtype_does_not_exist(self):
dtypes = {np.dtype("uint8")}
with self.assertRaises(KeyError):
iadt.gate_dtypes_strs(dtypes, "uint8", "int8 int1000")
def test_overlap_between_allowed_and_disallowed(self):
dtypes = {np.dtype("uint8"), np.dtype("float32"), np.dtype("int64")}
allowed = "uint8 float32 int64"
disallowed = "uint8 bool"
with self.assertRaises(AssertionError) as context:
iadt.gate_dtypes_strs(dtypes, allowed, disallowed)
assert (
"Expected 'allowed' and 'disallowed' dtypes to not contain "
"the same dtypes" in str(context.exception)
)
def test_single_array_allowed(self):
arr = np.zeros((1, 1, 3), dtype=np.int8)
iadt.gate_dtypes_strs(arr, "int8", "")
def test_single_array_disallowed(self):
arr = np.zeros((1, 1, 3), dtype=np.int8)
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes_strs(arr, "uint8", "int8")
assert "Got dtype 'int8'" in str(context.exception)
def test_list_of_single_array(self):
arr = np.zeros((1, 1, 3), dtype=np.int8)
iadt.gate_dtypes_strs([arr], "int8", "")
def test_list_of_two_arrays_same_dtypes(self):
arrays = [
np.zeros((1, 1, 3), dtype=np.int8),
np.zeros((1, 1, 3), dtype=np.int8)
]
iadt.gate_dtypes_strs(arrays, "int8", "")
def test_list_of_two_arrays_different_dtypes(self):
arrays = [
np.zeros((1, 1, 3), dtype=np.int8),
np.zeros((1, 1, 3), dtype=np.uint8)
]
iadt.gate_dtypes_strs(arrays, "int8 uint8", "")
def test_list_of_two_arrays_same_dtypes_one_disallowed(self):
arrays = [
np.zeros((1, 1, 3), dtype=np.int8),
np.zeros((1, 1, 3), dtype=np.uint8)
]
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes_strs(arrays, "int8", "uint8")
assert "Got dtype 'uint8', which" in str(context.exception)
class Test_gate_dtypes(unittest.TestCase):
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_standard_scenario_all_allowed(self):
dtypes = [np.dtype("uint8"), np.dtype("uint8"),
np.dtype("float32"), np.dtype("int64")]
allowed = [np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")]
disallowed = [np.dtype("bool")]
iadt.gate_dtypes(dtypes, allowed, disallowed)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_standard_scenario_one_disallowed(self):
dtypes = [np.dtype("uint8"), np.dtype("uint8"),
np.dtype("float32"), np.dtype("int64")]
allowed = [np.dtype("uint8"), np.dtype("float32")]
disallowed = [np.dtype("bool"), np.dtype("int64")]
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes(dtypes, allowed, disallowed)
assert "Got dtype 'int64'" in str(context.exception)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_standard_scenario_all_allowed_dtype_names(self):
dtypes = [np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")]
allowed = ["uint8", "float32", "int64"]
disallowed = ["bool"]
iadt.gate_dtypes(dtypes, allowed, disallowed)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_standard_scenario_one_disallowed_dtype_names(self):
dtypes = [np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")]
allowed = ["uint8", "float32"]
disallowed = ["bool", "int64"]
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes(dtypes, allowed, disallowed)
assert "Got dtype 'int64'" in str(context.exception)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_standard_scenario_all_allowed_dtype_functions(self):
dtypes = [np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")]
allowed = [np.uint8, np.float32, np.int64]
disallowed = [np.bool_]
iadt.gate_dtypes(dtypes, allowed, disallowed)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_standard_scenario_one_disallowed_dtype_functions(self):
dtypes = [np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")]
allowed = [np.uint8, np.float32]
disallowed = [np.bool_, np.int64]
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes(dtypes, allowed, disallowed)
assert "Got dtype 'int64'" in str(context.exception)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_single_array_allowed(self):
arr = np.zeros((1, 1, 3), dtype=np.int8)
iadt.gate_dtypes(arr, ["int8"], [])
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_single_array_disallowed(self):
arr = np.zeros((1, 1, 3), dtype=np.int8)
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes(arr, ["uint8"], ["int8"])
assert "Got dtype 'int8'" in str(context.exception)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_list_of_single_array(self):
arr = np.zeros((1, 1, 3), dtype=np.int8)
iadt.gate_dtypes([arr], [np.dtype("int8")], [])
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_list_of_two_arrays_same_dtypes(self):
arrays = [
np.zeros((1, 1, 3), dtype=np.int8),
np.zeros((1, 1, 3), dtype=np.int8)
]
iadt.gate_dtypes(arrays, [np.dtype("int8")], [])
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_list_of_two_arrays_different_dtypes(self):
arrays = [
np.zeros((1, 1, 3), dtype=np.int8),
np.zeros((1, 1, 3), dtype=np.uint8)
]
iadt.gate_dtypes(arrays, ["int8", "uint8"], [])
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_list_of_two_arrays_same_dtypes_one_disallowed(self):
arrays = [
np.zeros((1, 1, 3), dtype=np.int8),
np.zeros((1, 1, 3), dtype=np.uint8)
]
with self.assertRaises(ValueError) as context:
iadt.gate_dtypes(arrays, "int8", "uint8")
assert "Got dtype 'uint8', which" in str(context.exception)
@ensure_deprecation_warning("imgaug.dtypes.gate_dtypes_strs")
def test_single_dtype_function(self):
dtype = np.int8
iadt.gate_dtypes(dtype, ["int8"], [])
class Test__gate_dtypes(unittest.TestCase):
def test_standard_scenario_all_allowed(self):
dtypes = {np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")}
allowed = {np.dtype("uint8"), np.dtype("float32"), np.dtype("int64")}
disallowed = {np.dtype("bool")}
iadt._gate_dtypes(dtypes, allowed, disallowed)
def test_standard_scenario_one_disallowed(self):
dtypes = {np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")}
allowed = {np.dtype("uint8"), np.dtype("float32")}
disallowed = {np.dtype("bool"), np.dtype("int64")}
with self.assertRaises(ValueError) as context:
iadt._gate_dtypes(dtypes, allowed, disallowed)
assert "Got dtype 'int64'" in str(context.exception)
def test_all_allowed_input_is_list_of_dtypes(self):
dtypes = {np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")}
allowed = {np.dtype("uint8"), np.dtype("float32"), np.dtype("int64")}
disallowed = {np.dtype("bool")}
iadt._gate_dtypes(dtypes, allowed, disallowed)
def test_all_allowed_input_is_list_of_dtype_functions(self):
dtypes = {np.dtype("uint8"), np.dtype("uint8"), np.dtype("float32"),
np.dtype("int64")}
allowed = {np.dtype("uint8"), np.dtype("float32"), np.dtype("int64")}
disallowed = {np.dtype("bool")}
iadt._gate_dtypes(dtypes, allowed, disallowed)
def test_empty_set_as_dtypes(self):
dtypes = set()
allowed = {np.dtype("uint8"), np.dtype("float32"), np.dtype("int64")}
disallowed = {np.dtype("bool")}
iadt._gate_dtypes(dtypes, allowed, disallowed)
def test_single_dtype_allowed(self):
dtype = np.dtype("int8")
iadt._gate_dtypes({dtype}, {np.dtype("int8")}, None)
def test_single_dtype_disallowed(self):
dtype = np.dtype("int8")
with self.assertRaises(ValueError) as context:
iadt._gate_dtypes({dtype}, {np.dtype("uint8")}, {np.dtype("int8")})
assert "Got dtype 'int8', which" in str(context.exception)
def test_single_dtype_disallowed_augmenter_set(self):
class _DummyAugmenter(object):
def __init__(self):
self.name = "foo"
dtype = np.dtype("int8")
dummy_augmenter = _DummyAugmenter()
with self.assertRaises(ValueError) as context:
iadt._gate_dtypes(
{dtype},
{np.dtype("uint8")},
{np.dtype("int8")},
augmenter=dummy_augmenter
)
assert "Got dtype 'int8' in augmenter 'foo'" in str(context.exception)
def test_list_of_two_dtypes_both_same(self):
dtypes = {
np.dtype("int8"),
np.dtype("int8")
}
iadt._gate_dtypes(dtypes, {np.dtype("int8")}, None)
def test_list_of_two_dtypes_both_different(self):
dtypes = {
np.dtype("int8"),
np.dtype("uint8")
}
iadt._gate_dtypes(dtypes, {np.dtype("int8"), np.dtype("uint8")}, None)
def test_list_of_two_dtypes_both_different_one_disallowed(self):
dtypes = {
np.dtype("int8"),
np.dtype("uint8")
}
with self.assertRaises(ValueError) as context:
iadt._gate_dtypes(dtypes, {np.dtype("int8")}, {np.dtype("uint8")})
assert "Got dtype 'uint8', which" in str(context.exception)
def test_dtype_not_in_allowed_or_disallowed(self):
dtypes = {
np.dtype("int8"),
np.dtype("float32")
}
with warnings.catch_warnings(record=True) as caught_warnings:
warnings.simplefilter("always")
iadt._gate_dtypes(dtypes, {np.dtype("int8")}, {np.dtype("uint8")})
assert len(caught_warnings) == 1
assert (
"Got dtype 'float32', which" in str(caught_warnings[-1].message))
def test_dtype_not_in_allowed_or_disallowed_augmenter_set(self):
class _DummyAugmenter(object):
def __init__(self):
self.name = "foo"
dtypes = {
np.dtype("int8"),
np.dtype("float32")
}
dummy_augmenter = _DummyAugmenter()
with warnings.catch_warnings(record=True) as caught_warnings:
warnings.simplefilter("always")
iadt._gate_dtypes(
dtypes,
{np.dtype("int8")},
{np.dtype("uint8")},
augmenter=dummy_augmenter
)
assert len(caught_warnings) == 1
assert (
"Got dtype 'float32' in augmenter 'foo'"
in str(caught_warnings[-1].message))