1#!/usr/bin/env python
2
3from itertools import product
4from functools import reduce
5
6import numpy as np
7import cv2 as cv
8
9from tests_common import NewOpenCVTests
10
11
12def norm_inf(x, y=None):
13    def norm(vec):
14        return np.linalg.norm(vec.flatten(), np.inf)
15
16    x = x.astype(np.float64)
17    return norm(x) if y is None else norm(x - y.astype(np.float64))
18
19
20def norm_l1(x, y=None):
21    def norm(vec):
22        return np.linalg.norm(vec.flatten(), 1)
23
24    x = x.astype(np.float64)
25    return norm(x) if y is None else norm(x - y.astype(np.float64))
26
27
28def norm_l2(x, y=None):
29    def norm(vec):
30        return np.linalg.norm(vec.flatten())
31
32    x = x.astype(np.float64)
33    return norm(x) if y is None else norm(x - y.astype(np.float64))
34
35
36def norm_l2sqr(x, y=None):
37    def norm(vec):
38        return np.square(vec).sum()
39
40    x = x.astype(np.float64)
41    return norm(x) if y is None else norm(x - y.astype(np.float64))
42
43
44def norm_hamming(x, y=None):
45    def norm(vec):
46        return sum(bin(i).count('1') for i in vec.flatten())
47
48    return norm(x) if y is None else norm(np.bitwise_xor(x, y))
49
50
51def norm_hamming2(x, y=None):
52    def norm(vec):
53        def element_norm(element):
54            binary_str = bin(element).split('b')[-1]
55            if len(binary_str) % 2 == 1:
56                binary_str = '0' + binary_str
57            gen = filter(lambda p: p != '00',
58                         (binary_str[i:i+2]
59                          for i in range(0, len(binary_str), 2)))
60            return sum(1 for _ in gen)
61
62        return sum(element_norm(element) for element in vec.flatten())
63
64    return norm(x) if y is None else norm(np.bitwise_xor(x, y))
65
66
67norm_type_under_test = {
68    cv.NORM_INF: norm_inf,
69    cv.NORM_L1: norm_l1,
70    cv.NORM_L2: norm_l2,
71    cv.NORM_L2SQR: norm_l2sqr,
72    cv.NORM_HAMMING: norm_hamming,
73    cv.NORM_HAMMING2: norm_hamming2
74}
75
76norm_name = {
77    cv.NORM_INF: 'inf',
78    cv.NORM_L1: 'L1',
79    cv.NORM_L2: 'L2',
80    cv.NORM_L2SQR: 'L2SQR',
81    cv.NORM_HAMMING: 'Hamming',
82    cv.NORM_HAMMING2: 'Hamming2'
83}
84
85
86def get_element_types(norm_type):
87    if norm_type in (cv.NORM_HAMMING, cv.NORM_HAMMING2):
88        return (np.uint8,)
89    else:
90        return (np.uint8, np.int8, np.uint16, np.int16, np.int32, np.float32,
91                np.float64)
92
93
94def generate_vector(shape, dtype):
95    if np.issubdtype(dtype, np.integer):
96        return np.random.randint(0, 100, shape).astype(dtype)
97    else:
98        return np.random.normal(10., 12.5, shape).astype(dtype)
99
100
101shapes = (1, 2, 3, 5, 7, 16, (1, 1), (2, 2), (3, 5), (1, 7))
102
103
104class norm_test(NewOpenCVTests):
105
106    def test_norm_for_one_array(self):
107        np.random.seed(123)
108        for norm_type, norm in norm_type_under_test.items():
109            element_types = get_element_types(norm_type)
110            for shape, element_type in product(shapes, element_types):
111                array = generate_vector(shape, element_type)
112                expected = norm(array)
113                actual = cv.norm(array, norm_type)
114                self.assertAlmostEqual(
115                    expected, actual, places=2,
116                    msg='Array {0} of {1} and norm {2}'.format(
117                        array, element_type.__name__, norm_name[norm_type]
118                    )
119                )
120
121    def test_norm_for_two_arrays(self):
122        np.random.seed(456)
123        for norm_type, norm in norm_type_under_test.items():
124            element_types = get_element_types(norm_type)
125            for shape, element_type in product(shapes, element_types):
126                first = generate_vector(shape, element_type)
127                second = generate_vector(shape, element_type)
128                expected = norm(first, second)
129                actual = cv.norm(first, second, norm_type)
130                self.assertAlmostEqual(
131                    expected, actual, places=2,
132                    msg='Arrays {0} {1} of type {2} and norm {3}'.format(
133                        first, second, element_type.__name__,
134                        norm_name[norm_type]
135                    )
136                )
137
138    def test_norm_fails_for_wrong_type(self):
139        for norm_type in (cv.NORM_HAMMING, cv.NORM_HAMMING2):
140            with self.assertRaises(Exception,
141                                   msg='Type is not checked {0}'.format(
142                                       norm_name[norm_type]
143                                   )):
144                cv.norm(np.array([1, 2], dtype=np.int32), norm_type)
145
146    def test_norm_fails_for_array_and_scalar(self):
147        for norm_type in norm_type_under_test:
148            with self.assertRaises(Exception,
149                                   msg='Exception is not thrown for {0}'.format(
150                                       norm_name[norm_type]
151                                   )):
152                cv.norm(np.array([1, 2], dtype=np.uint8), 123, norm_type)
153
154    def test_norm_fails_for_scalar_and_array(self):
155        for norm_type in norm_type_under_test:
156            with self.assertRaises(Exception,
157                                   msg='Exception is not thrown for {0}'.format(
158                                       norm_name[norm_type]
159                                   )):
160                cv.norm(4, np.array([1, 2], dtype=np.uint8), norm_type)
161
162    def test_norm_fails_for_array_and_norm_type_as_scalar(self):
163        for norm_type in norm_type_under_test:
164            with self.assertRaises(Exception,
165                                   msg='Exception is not thrown for {0}'.format(
166                                       norm_name[norm_type]
167                                   )):
168                cv.norm(np.array([3, 4, 5], dtype=np.uint8),
169                        norm_type, normType=norm_type)
170
171
172if __name__ == '__main__':
173    NewOpenCVTests.bootstrap()
174