c@391
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@391
|
2
|
c@391
|
3 #include "maths/MedianFilter.h"
|
c@391
|
4
|
c@391
|
5 #include <cmath>
|
c@407
|
6 #include <cstdlib>
|
c@391
|
7
|
c@391
|
8 #define BOOST_TEST_DYN_LINK
|
c@391
|
9 #define BOOST_TEST_MAIN
|
c@391
|
10
|
c@391
|
11 #include <boost/test/unit_test.hpp>
|
c@391
|
12
|
c@391
|
13 BOOST_AUTO_TEST_SUITE(TestMedianFilter)
|
c@391
|
14
|
c@391
|
15 BOOST_AUTO_TEST_CASE(odd)
|
c@391
|
16 {
|
c@391
|
17 // A median filter of size N always retains a pool of N elements,
|
c@391
|
18 // which start out all-zero. So the output median will remain zero
|
c@391
|
19 // until N/2 elements have been pushed.
|
c@391
|
20 MedianFilter<double> f(3);
|
c@391
|
21 f.push(1); // 0 0 1
|
c@391
|
22 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
23 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
24 f.push(-3); // 0 1 -3
|
c@391
|
25 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
26 f.push(5); // 1 -3 5
|
c@391
|
27 BOOST_CHECK_EQUAL(f.get(), 1);
|
c@391
|
28 f.push(7); // -3 5 7
|
c@391
|
29 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
30 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
31 f.push(3); // 5 7 3
|
c@391
|
32 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
33 f.push(3); // 7 3 3
|
c@391
|
34 BOOST_CHECK_EQUAL(f.get(), 3);
|
c@391
|
35 }
|
c@391
|
36
|
c@391
|
37 BOOST_AUTO_TEST_CASE(even)
|
c@391
|
38 {
|
c@391
|
39 // Our median does not halve the difference (should it??), it just
|
c@391
|
40 // returns the next element from the input set
|
c@391
|
41 MedianFilter<double> f(4);
|
c@391
|
42 f.push(1); // 0 0 0 1
|
c@391
|
43 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
44 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
45 f.push(-3); // 0 0 1 -3
|
c@391
|
46 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
47 f.push(5); // 0 1 -3 5
|
c@391
|
48 BOOST_CHECK_EQUAL(f.get(), 1);
|
c@391
|
49 f.push(7); // 1 -3 5 7
|
c@391
|
50 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
51 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
52 f.push(3); // -3 5 7 3
|
c@391
|
53 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
54 f.push(3); // 5 7 3 3
|
c@391
|
55 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
56 }
|
c@391
|
57
|
c@391
|
58 BOOST_AUTO_TEST_CASE(odd75)
|
c@391
|
59 {
|
c@391
|
60 MedianFilter<double> f(5, 75.f);
|
c@391
|
61 f.push(1); // 0 0 0 0 1
|
c@391
|
62 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
63 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
64 f.push(-3); // 0 0 0 1 -3
|
c@391
|
65 BOOST_CHECK_EQUAL(f.get(), 0);
|
c@391
|
66 f.push(5); // 0 0 1 -3 5
|
c@391
|
67 BOOST_CHECK_EQUAL(f.get(), 1);
|
c@391
|
68 f.push(7); // 0 1 -3 5 7
|
c@391
|
69 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
70 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
71 f.push(3); // 0 -3 5 7 3
|
c@391
|
72 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
73 f.push(3); // 0 5 7 3 3
|
c@391
|
74 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
75 }
|
c@391
|
76
|
c@391
|
77 BOOST_AUTO_TEST_CASE(even75)
|
c@391
|
78 {
|
c@391
|
79 MedianFilter<double> f(4, 75.f);
|
c@391
|
80 f.push(1); // 0 0 0 1
|
c@391
|
81 BOOST_CHECK_EQUAL(f.get(), 1);
|
c@391
|
82 BOOST_CHECK_EQUAL(f.get(), 1);
|
c@391
|
83 f.push(-3); // 0 0 1 -3
|
c@391
|
84 BOOST_CHECK_EQUAL(f.get(), 1);
|
c@391
|
85 f.push(5); // 0 1 -3 5
|
c@391
|
86 BOOST_CHECK_EQUAL(f.get(), 5);
|
c@391
|
87 f.push(7); // 1 -3 5 7
|
c@391
|
88 BOOST_CHECK_EQUAL(f.get(), 7);
|
c@391
|
89 BOOST_CHECK_EQUAL(f.get(), 7);
|
c@391
|
90 f.push(3); // -3 5 7 3
|
c@391
|
91 BOOST_CHECK_EQUAL(f.get(), 7);
|
c@391
|
92 f.push(3); // 5 7 3 3
|
c@391
|
93 BOOST_CHECK_EQUAL(f.get(), 7);
|
c@391
|
94 }
|
c@391
|
95
|
c@392
|
96 BOOST_AUTO_TEST_CASE(oddStandalone)
|
c@392
|
97 {
|
c@392
|
98 // The standalone (static filter() method) function is intended to
|
c@392
|
99 // match e.g. MATLAB median filter, filtering a row at once
|
c@392
|
100 // assuming the values beyond its edges are zeroes. This basically
|
c@392
|
101 // just means it needs to compensate for the latency in the raw
|
c@392
|
102 // filter:
|
c@392
|
103 //
|
c@392
|
104 // Raw filter
|
c@392
|
105 // 1 3 5 7 -> 0 1 3 5 (N=3)
|
c@392
|
106 // (because at each step only the values up to that step are
|
c@392
|
107 // available)
|
c@392
|
108 //
|
c@392
|
109 // Standalone function:
|
c@392
|
110 // 1 3 5 7 -> 1 3 5 5 (N=3)
|
c@392
|
111
|
c@392
|
112 std::vector<double> in;
|
c@392
|
113 in.push_back(1);
|
c@392
|
114 in.push_back(3);
|
c@392
|
115 in.push_back(5);
|
c@392
|
116 in.push_back(7);
|
c@392
|
117
|
c@392
|
118 std::vector<double> out = MedianFilter<double>::filter(3, in);
|
c@392
|
119 BOOST_CHECK_EQUAL(out[0], 1);
|
c@392
|
120 BOOST_CHECK_EQUAL(out[1], 3);
|
c@392
|
121 BOOST_CHECK_EQUAL(out[2], 5);
|
c@392
|
122 BOOST_CHECK_EQUAL(out[3], 5);
|
c@392
|
123 }
|
c@392
|
124
|
c@392
|
125 BOOST_AUTO_TEST_CASE(evenStandalone)
|
c@392
|
126 {
|
c@392
|
127 // See above. But note that the even length does not match the
|
c@392
|
128 // MATLAB because it doesn't halve the middle, as MATLAB does
|
c@392
|
129
|
c@392
|
130 std::vector<double> in;
|
c@392
|
131 in.push_back(1);
|
c@392
|
132 in.push_back(3);
|
c@392
|
133 in.push_back(5);
|
c@392
|
134 in.push_back(7);
|
c@392
|
135
|
c@392
|
136 std::vector<double> out = MedianFilter<double>::filter(4, in);
|
c@392
|
137 BOOST_CHECK_EQUAL(out[0], 3);
|
c@392
|
138 BOOST_CHECK_EQUAL(out[1], 5);
|
c@392
|
139 BOOST_CHECK_EQUAL(out[2], 5);
|
c@392
|
140 BOOST_CHECK_EQUAL(out[3], 5);
|
c@392
|
141 }
|
c@392
|
142
|
c@392
|
143 BOOST_AUTO_TEST_CASE(standaloneEmpty)
|
c@392
|
144 {
|
c@392
|
145 std::vector<double> in;
|
c@392
|
146 std::vector<double> out1 = MedianFilter<double>::filter(3, in);
|
c@392
|
147 BOOST_CHECK_EQUAL(out1.size(), 0);
|
c@392
|
148 std::vector<double> out2 = MedianFilter<double>::filter(4, in);
|
c@392
|
149 BOOST_CHECK_EQUAL(out2.size(), 0);
|
c@392
|
150 }
|
c@392
|
151
|
c@392
|
152 BOOST_AUTO_TEST_CASE(types)
|
c@392
|
153 {
|
c@392
|
154 MedianFilter<double> dfilt(3);
|
c@392
|
155 dfilt.push(1.2);
|
c@392
|
156 BOOST_CHECK_EQUAL(dfilt.get(), 0.0);
|
c@392
|
157 dfilt.push(2.4);
|
c@392
|
158 BOOST_CHECK_EQUAL(dfilt.get(), 1.2);
|
c@392
|
159 dfilt.push(1e-6);
|
c@392
|
160 BOOST_CHECK_EQUAL(dfilt.get(), 1.2);
|
c@392
|
161 dfilt.push(1e6);
|
c@392
|
162 BOOST_CHECK_EQUAL(dfilt.get(), 2.4);
|
c@392
|
163
|
c@392
|
164 MedianFilter<int> ifilt(3);
|
c@392
|
165 ifilt.push(1);
|
c@392
|
166 BOOST_CHECK_EQUAL(ifilt.get(), 0);
|
c@392
|
167 ifilt.push(2);
|
c@392
|
168 BOOST_CHECK_EQUAL(ifilt.get(), 1);
|
c@392
|
169 ifilt.push(0);
|
c@392
|
170 BOOST_CHECK_EQUAL(ifilt.get(), 1);
|
c@392
|
171 ifilt.push(1000);
|
c@392
|
172 BOOST_CHECK_EQUAL(ifilt.get(), 2);
|
c@392
|
173 }
|
c@392
|
174
|
c@407
|
175 BOOST_AUTO_TEST_CASE(inf)
|
c@407
|
176 {
|
c@407
|
177 // Inf and -Inf should behave normally
|
c@407
|
178 double pinf = strtod("Inf", 0);
|
c@407
|
179 double ninf = strtod("-Inf", 0);
|
c@407
|
180 MedianFilter<double> dfilt(3);
|
c@407
|
181 dfilt.push(1.0);
|
c@407
|
182 dfilt.push(2.0);
|
c@407
|
183 dfilt.push(pinf);
|
c@407
|
184 BOOST_CHECK_EQUAL(dfilt.get(), 2.0);
|
c@407
|
185 dfilt.push(pinf);
|
c@407
|
186 BOOST_CHECK_EQUAL(dfilt.get(), pinf);
|
c@407
|
187 dfilt.push(pinf);
|
c@407
|
188 BOOST_CHECK_EQUAL(dfilt.get(), pinf);
|
c@407
|
189 dfilt.push(2.0);
|
c@407
|
190 BOOST_CHECK_EQUAL(dfilt.get(), pinf);
|
c@407
|
191 dfilt.push(1.0);
|
c@407
|
192 BOOST_CHECK_EQUAL(dfilt.get(), 2.0);
|
c@407
|
193 dfilt.push(ninf);
|
c@407
|
194 BOOST_CHECK_EQUAL(dfilt.get(), 1.0);
|
c@407
|
195 dfilt.push(pinf);
|
c@407
|
196 BOOST_CHECK_EQUAL(dfilt.get(), 1.0);
|
c@407
|
197 dfilt.push(ninf);
|
c@407
|
198 BOOST_CHECK_EQUAL(dfilt.get(), ninf);
|
c@407
|
199 }
|
c@407
|
200
|
c@407
|
201 BOOST_AUTO_TEST_CASE(nan)
|
c@407
|
202 {
|
c@407
|
203 // The filter should never accept a NaN, because it breaks sorting
|
c@407
|
204 // and comparison and that will break the filter. Instead it
|
c@407
|
205 // should insert 0.
|
c@407
|
206 double nan = strtod("NaN", 0);
|
c@407
|
207 MedianFilter<double> dfilt(3);
|
c@407
|
208 dfilt.push(1.0);
|
c@407
|
209 dfilt.push(2.0);
|
c@407
|
210 dfilt.push(nan);
|
c@407
|
211 BOOST_CHECK_EQUAL(dfilt.get(), 1.0);
|
c@407
|
212 dfilt.push(nan);
|
c@407
|
213 BOOST_CHECK_EQUAL(dfilt.get(), 0.0);
|
c@407
|
214 dfilt.push(-11.0);
|
c@407
|
215 BOOST_CHECK_EQUAL(dfilt.get(), 0.0);
|
c@407
|
216 dfilt.push(-1.0);
|
c@407
|
217 BOOST_CHECK_EQUAL(dfilt.get(), -1.0);
|
c@407
|
218 }
|
c@407
|
219
|
c@391
|
220 BOOST_AUTO_TEST_SUITE_END()
|
c@391
|
221
|
c@391
|
222
|