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