annotate tests/TestMedianFilter.cpp @ 182:5ec47007b873

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