c@391: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@391: c@391: #include "maths/MedianFilter.h" c@391: c@391: #include c@407: #include c@391: c@391: #define BOOST_TEST_DYN_LINK c@391: #define BOOST_TEST_MAIN c@391: c@391: #include c@391: c@391: BOOST_AUTO_TEST_SUITE(TestMedianFilter) c@391: c@391: BOOST_AUTO_TEST_CASE(odd) c@391: { c@391: // A median filter of size N always retains a pool of N elements, c@391: // which start out all-zero. So the output median will remain zero c@391: // until N/2 elements have been pushed. c@391: MedianFilter f(3); cannam@476: f.push(1); // 0 0 1 c@391: BOOST_CHECK_EQUAL(f.get(), 0); c@391: BOOST_CHECK_EQUAL(f.get(), 0); cannam@476: f.push(-3); // 0 1 -3 c@391: BOOST_CHECK_EQUAL(f.get(), 0); cannam@476: f.push(5); // 1 -3 5 c@391: BOOST_CHECK_EQUAL(f.get(), 1); cannam@476: f.push(7); // -3 5 7 c@391: BOOST_CHECK_EQUAL(f.get(), 5); c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(3); // 5 7 3 c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(3); // 7 3 3 c@391: BOOST_CHECK_EQUAL(f.get(), 3); c@391: } c@391: c@391: BOOST_AUTO_TEST_CASE(even) c@391: { c@391: // Our median does not halve the difference (should it??), it just c@391: // returns the next element from the input set c@391: MedianFilter f(4); cannam@476: f.push(1); // 0 0 0 1 c@391: BOOST_CHECK_EQUAL(f.get(), 0); c@391: BOOST_CHECK_EQUAL(f.get(), 0); cannam@476: f.push(-3); // 0 0 1 -3 c@391: BOOST_CHECK_EQUAL(f.get(), 0); cannam@476: f.push(5); // 0 1 -3 5 c@391: BOOST_CHECK_EQUAL(f.get(), 1); cannam@476: f.push(7); // 1 -3 5 7 c@391: BOOST_CHECK_EQUAL(f.get(), 5); c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(3); // -3 5 7 3 c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(3); // 5 7 3 3 c@391: BOOST_CHECK_EQUAL(f.get(), 5); c@391: } c@391: c@391: BOOST_AUTO_TEST_CASE(odd75) c@391: { c@391: MedianFilter f(5, 75.f); cannam@476: f.push(1); // 0 0 0 0 1 c@391: BOOST_CHECK_EQUAL(f.get(), 0); c@391: BOOST_CHECK_EQUAL(f.get(), 0); cannam@476: f.push(-3); // 0 0 0 1 -3 c@391: BOOST_CHECK_EQUAL(f.get(), 0); cannam@476: f.push(5); // 0 0 1 -3 5 c@391: BOOST_CHECK_EQUAL(f.get(), 1); cannam@476: f.push(7); // 0 1 -3 5 7 c@391: BOOST_CHECK_EQUAL(f.get(), 5); c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(3); // 0 -3 5 7 3 c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(3); // 0 5 7 3 3 c@391: BOOST_CHECK_EQUAL(f.get(), 5); c@391: } c@391: c@391: BOOST_AUTO_TEST_CASE(even75) c@391: { c@391: MedianFilter f(4, 75.f); cannam@476: f.push(1); // 0 0 0 1 c@391: BOOST_CHECK_EQUAL(f.get(), 1); c@391: BOOST_CHECK_EQUAL(f.get(), 1); cannam@476: f.push(-3); // 0 0 1 -3 c@391: BOOST_CHECK_EQUAL(f.get(), 1); cannam@476: f.push(5); // 0 1 -3 5 c@391: BOOST_CHECK_EQUAL(f.get(), 5); cannam@476: f.push(7); // 1 -3 5 7 c@391: BOOST_CHECK_EQUAL(f.get(), 7); c@391: BOOST_CHECK_EQUAL(f.get(), 7); cannam@476: f.push(3); // -3 5 7 3 c@391: BOOST_CHECK_EQUAL(f.get(), 7); cannam@476: f.push(3); // 5 7 3 3 c@391: BOOST_CHECK_EQUAL(f.get(), 7); c@391: } c@391: c@392: BOOST_AUTO_TEST_CASE(oddStandalone) c@392: { c@392: // The standalone (static filter() method) function is intended to c@392: // match e.g. MATLAB median filter, filtering a row at once c@392: // assuming the values beyond its edges are zeroes. This basically c@392: // just means it needs to compensate for the latency in the raw c@392: // filter: c@392: // c@392: // Raw filter c@392: // 1 3 5 7 -> 0 1 3 5 (N=3) c@392: // (because at each step only the values up to that step are c@392: // available) c@392: // c@392: // Standalone function: c@392: // 1 3 5 7 -> 1 3 5 5 (N=3) c@392: c@392: std::vector in; c@392: in.push_back(1); c@392: in.push_back(3); c@392: in.push_back(5); c@392: in.push_back(7); c@392: c@392: std::vector out = MedianFilter::filter(3, in); c@392: BOOST_CHECK_EQUAL(out[0], 1); c@392: BOOST_CHECK_EQUAL(out[1], 3); c@392: BOOST_CHECK_EQUAL(out[2], 5); c@392: BOOST_CHECK_EQUAL(out[3], 5); c@392: } c@392: c@392: BOOST_AUTO_TEST_CASE(evenStandalone) c@392: { c@392: // See above. But note that the even length does not match the c@392: // MATLAB because it doesn't halve the middle, as MATLAB does c@392: c@392: std::vector in; c@392: in.push_back(1); c@392: in.push_back(3); c@392: in.push_back(5); c@392: in.push_back(7); c@392: c@392: std::vector out = MedianFilter::filter(4, in); c@392: BOOST_CHECK_EQUAL(out[0], 3); c@392: BOOST_CHECK_EQUAL(out[1], 5); c@392: BOOST_CHECK_EQUAL(out[2], 5); c@392: BOOST_CHECK_EQUAL(out[3], 5); c@392: } c@392: c@392: BOOST_AUTO_TEST_CASE(standaloneEmpty) c@392: { c@392: std::vector in; c@392: std::vector out1 = MedianFilter::filter(3, in); c@392: BOOST_CHECK_EQUAL(out1.size(), 0); c@392: std::vector out2 = MedianFilter::filter(4, in); c@392: BOOST_CHECK_EQUAL(out2.size(), 0); c@392: } c@392: c@392: BOOST_AUTO_TEST_CASE(types) c@392: { c@392: MedianFilter dfilt(3); c@392: dfilt.push(1.2); c@392: BOOST_CHECK_EQUAL(dfilt.get(), 0.0); c@392: dfilt.push(2.4); c@392: BOOST_CHECK_EQUAL(dfilt.get(), 1.2); c@392: dfilt.push(1e-6); c@392: BOOST_CHECK_EQUAL(dfilt.get(), 1.2); c@392: dfilt.push(1e6); c@392: BOOST_CHECK_EQUAL(dfilt.get(), 2.4); c@392: c@392: MedianFilter ifilt(3); c@392: ifilt.push(1); c@392: BOOST_CHECK_EQUAL(ifilt.get(), 0); c@392: ifilt.push(2); c@392: BOOST_CHECK_EQUAL(ifilt.get(), 1); c@392: ifilt.push(0); c@392: BOOST_CHECK_EQUAL(ifilt.get(), 1); c@392: ifilt.push(1000); c@392: BOOST_CHECK_EQUAL(ifilt.get(), 2); c@392: } c@392: c@407: BOOST_AUTO_TEST_CASE(inf) c@407: { c@407: // Inf and -Inf should behave normally c@407: double pinf = strtod("Inf", 0); c@407: double ninf = strtod("-Inf", 0); c@407: MedianFilter dfilt(3); c@407: dfilt.push(1.0); c@407: dfilt.push(2.0); c@407: dfilt.push(pinf); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 2.0); c@407: dfilt.push(pinf); c@407: BOOST_CHECK_EQUAL(dfilt.get(), pinf); c@407: dfilt.push(pinf); c@407: BOOST_CHECK_EQUAL(dfilt.get(), pinf); c@407: dfilt.push(2.0); c@407: BOOST_CHECK_EQUAL(dfilt.get(), pinf); c@407: dfilt.push(1.0); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 2.0); c@407: dfilt.push(ninf); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 1.0); c@407: dfilt.push(pinf); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 1.0); c@407: dfilt.push(ninf); c@407: BOOST_CHECK_EQUAL(dfilt.get(), ninf); c@407: } c@407: c@407: BOOST_AUTO_TEST_CASE(nan) c@407: { c@407: // The filter should never accept a NaN, because it breaks sorting c@407: // and comparison and that will break the filter. Instead it c@407: // should insert 0. c@407: double nan = strtod("NaN", 0); c@407: MedianFilter dfilt(3); c@407: dfilt.push(1.0); c@407: dfilt.push(2.0); c@407: dfilt.push(nan); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 1.0); c@407: dfilt.push(nan); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 0.0); c@407: dfilt.push(-11.0); c@407: BOOST_CHECK_EQUAL(dfilt.get(), 0.0); c@407: dfilt.push(-1.0); c@407: BOOST_CHECK_EQUAL(dfilt.get(), -1.0); c@407: } c@407: c@391: BOOST_AUTO_TEST_SUITE_END() c@391: c@391: