1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-28 23:03:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2023-09-28 16:42:08 +03:00
202 changed files with 14784 additions and 7242 deletions
+113
View File
@@ -42,6 +42,93 @@ def get_conversion_error_msg(value, expected, actual):
def get_no_exception_msg(value):
return 'Exception is not risen for {} of type {}'.format(value, type(value).__name__)
def rpad(src, dst_size, pad_value=0):
"""Extend `src` up to `dst_size` with given value.
Args:
src (np.ndarray | tuple | list): 1d array like object to pad.
dst_size (_type_): Desired `src` size after padding.
pad_value (int, optional): Padding value. Defaults to 0.
Returns:
np.ndarray: 1d array with len == `dst_size`.
"""
src = np.asarray(src)
if len(src.shape) != 1:
raise ValueError("Only 1d arrays are supported")
# Considering the meaning, it is desirable to use np.pad().
# However, the old numpy doesn't include the following fixes and cannot work as expected.
# So an alternative fix that combines np.append() and np.fill() is used.
# https://docs.scipy.org/doc/numpy-1.13.0/release.html#support-for-returning-arrays-of-arbitrary-dimensions-in-apply-along-axis
return np.append(src, np.full( dst_size - len(src), pad_value, dtype=src.dtype) )
def get_ocv_arithm_op_table(apply_saturation=False):
def saturate(func):
def wrapped_func(x, y):
dst_dtype = x.dtype
if apply_saturation:
if np.issubdtype(x.dtype, np.integer):
x = x.astype(np.int64)
# Apply padding or truncation for array-like `y` inputs
if not isinstance(y, (float, int)):
if len(y) > x.shape[-1]:
y = y[:x.shape[-1]]
else:
y = rpad(y, x.shape[-1], pad_value=0)
dst = func(x, y)
if apply_saturation:
min_val, max_val = get_limits(dst_dtype)
dst = np.clip(dst, min_val, max_val)
return dst.astype(dst_dtype)
return wrapped_func
@saturate
def subtract(x, y):
return x - y
@saturate
def add(x, y):
return x + y
@saturate
def divide(x, y):
if not isinstance(y, (int, float)):
dst_dtype = np.result_type(x, y)
y = np.array(y).astype(dst_dtype)
_, max_value = get_limits(dst_dtype)
y[y == 0] = max_value
# to compatible between python2 and python3, it calicurates with float.
# python2: int / int = int
# python3: int / int = float
dst = 1.0 * x / y
if np.issubdtype(x.dtype, np.integer):
dst = np.rint(dst)
return dst
@saturate
def multiply(x, y):
return x * y
@saturate
def absdiff(x, y):
res = np.abs(x - y)
return res
return {
cv.subtract: subtract,
cv.add: add,
cv.multiply: multiply,
cv.divide: divide,
cv.absdiff: absdiff
}
class Bindings(NewOpenCVTests):
def test_inheritance(self):
@@ -816,6 +903,32 @@ class Arguments(NewOpenCVTests):
np.testing.assert_equal(dst, src_copy)
self.assertEqual(arguments_dump, 'lambda=25, sigma=5.5')
def test_arithm_op_without_saturation(self):
np.random.seed(4231568)
src = np.random.randint(20, 40, 8 * 4 * 3).astype(np.uint8).reshape(8, 4, 3)
operations = get_ocv_arithm_op_table(apply_saturation=False)
for ocv_op, numpy_op in operations.items():
for val in (2, 4, (5, ), (6, 4), (2., 4., 1.),
np.uint8([1, 2, 2]), np.float64([5, 2, 6, 3]),):
dst = ocv_op(src, val)
expected = numpy_op(src, val)
# Temporarily allows a difference of 1 for arm64 workaround.
self.assertLess(np.max(np.abs(dst - expected)), 2,
msg="Operation '{}' is failed for {}".format(ocv_op.__name__, val ) )
def test_arithm_op_with_saturation(self):
np.random.seed(4231568)
src = np.random.randint(20, 40, 4 * 8 * 4).astype(np.uint8).reshape(4, 8, 4)
operations = get_ocv_arithm_op_table(apply_saturation=True)
for ocv_op, numpy_op in operations.items():
for val in (10, 4, (40, ), (15, 12), (25., 41., 15.),
np.uint8([1, 2, 20]), np.float64([50, 21, 64, 30]),):
dst = ocv_op(src, val)
expected = numpy_op(src, val)
# Temporarily allows a difference of 1 for arm64 workaround.
self.assertLess(np.max(np.abs(dst - expected)), 2,
msg="Saturated Operation '{}' is failed for {}".format(ocv_op.__name__, val ) )
class CanUsePurePythonModuleFunction(NewOpenCVTests):
def test_can_get_ocv_version(self):
+2
View File
@@ -36,6 +36,8 @@ class NewOpenCVTests(unittest.TestCase):
return candidate
if required:
self.fail('File ' + filename + ' not found')
else:
self.skipTest('File ' + filename + ' not found')
return None