annotate maths/MedianFilter.h @ 515:08bcc06c38ec tip master

Remove fast-math
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 28 Jan 2020 15:27:37 +0000
parents 701233f8ed41
children
rev   line source
c@389 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@390 2 /*
c@390 3 QM DSP Library
c@390 4
c@390 5 Centre for Digital Music, Queen Mary, University of London.
c@390 6 This file Copyright 2010 Chris Cannam.
c@390 7
c@390 8 This program is free software; you can redistribute it and/or
c@390 9 modify it under the terms of the GNU General Public License as
c@390 10 published by the Free Software Foundation; either version 2 of the
c@390 11 License, or (at your option) any later version. See the file
c@390 12 COPYING included with this distribution for more information.
c@390 13 */
c@390 14
cannam@489 15 #ifndef QM_DSP_MEDIAN_FILTER_H
cannam@489 16 #define QM_DSP_MEDIAN_FILTER_H
c@389 17
c@389 18 #include <algorithm>
c@389 19 #include <cassert>
c@389 20 #include <cmath>
c@389 21 #include <iostream>
c@392 22 #include <vector>
c@389 23
c@389 24 template <typename T>
c@389 25 class MedianFilter
c@389 26 {
c@389 27 public:
c@389 28 MedianFilter(int size, float percentile = 50.f) :
cannam@477 29 m_size(size),
cannam@477 30 m_frame(new T[size]),
cannam@477 31 m_sorted(new T[size]),
cannam@477 32 m_sortend(m_sorted + size - 1) {
c@389 33 setPercentile(percentile);
cannam@477 34 reset();
c@389 35 }
c@389 36
c@389 37 ~MedianFilter() {
cannam@477 38 delete[] m_frame;
cannam@477 39 delete[] m_sorted;
c@389 40 }
c@389 41
c@389 42 void setPercentile(float p) {
c@389 43 m_index = int((m_size * p) / 100.f);
c@389 44 if (m_index >= m_size) m_index = m_size-1;
c@389 45 if (m_index < 0) m_index = 0;
c@389 46 }
c@389 47
c@389 48 void push(T value) {
c@394 49 if (value != value) {
c@407 50 std::cerr << "WARNING: MedianFilter::push: attempt to push NaN, pushing zero instead" << std::endl;
c@407 51 // we do need to push something, to maintain the filter length
c@407 52 value = T();
c@394 53 }
cannam@477 54 drop(m_frame[0]);
cannam@477 55 const int sz1 = m_size-1;
cannam@477 56 for (int i = 0; i < sz1; ++i) m_frame[i] = m_frame[i+1];
cannam@477 57 m_frame[m_size-1] = value;
cannam@477 58 put(value);
c@389 59 }
c@389 60
c@389 61 T get() const {
cannam@477 62 return m_sorted[m_index];
c@389 63 }
c@389 64
c@393 65 int getSize() const {
c@393 66 return m_size;
c@393 67 }
c@393 68
c@389 69 T getAt(float percentile) {
cannam@477 70 int ix = int((m_size * percentile) / 100.f);
c@389 71 if (ix >= m_size) ix = m_size-1;
c@389 72 if (ix < 0) ix = 0;
cannam@477 73 return m_sorted[ix];
c@389 74 }
c@389 75
c@389 76 void reset() {
cannam@477 77 for (int i = 0; i < m_size; ++i) m_frame[i] = 0;
cannam@477 78 for (int i = 0; i < m_size; ++i) m_sorted[i] = 0;
c@389 79 }
c@389 80
c@392 81 static std::vector<T> filter(int size, const std::vector<T> &in) {
c@392 82 std::vector<T> out;
c@392 83 MedianFilter<T> f(size);
c@392 84 for (int i = 0; i < int(in.size()); ++i) {
c@392 85 f.push(in[i]);
c@392 86 T median = f.get();
c@392 87 if (i >= size/2) out.push_back(median);
c@392 88 }
c@392 89 while (out.size() < in.size()) {
c@392 90 f.push(T());
c@392 91 out.push_back(f.get());
c@392 92 }
c@392 93 return out;
c@392 94 }
c@392 95
c@389 96 private:
c@389 97 const int m_size;
c@389 98 T *const m_frame;
c@389 99 T *const m_sorted;
c@389 100 T *const m_sortend;
c@389 101 int m_index;
c@389 102
c@389 103 void put(T value) {
cannam@477 104 // precondition: m_sorted contains m_size-1 values, packed at start
cannam@477 105 // postcondition: m_sorted contains m_size values, one of which is value
cannam@477 106 T *point = std::lower_bound(m_sorted, m_sortend, value);
cannam@477 107 const int n = m_sortend - point;
cannam@477 108 for (int i = n; i > 0; --i) point[i] = point[i-1];
cannam@477 109 *point = value;
c@389 110 }
c@389 111
c@389 112 void drop(T value) {
cannam@477 113 // precondition: m_sorted contains m_size values, one of which is value
cannam@477 114 // postcondition: m_sorted contains m_size-1 values, packed at start
cannam@477 115 T *point = std::lower_bound(m_sorted, m_sortend + 1, value);
cannam@477 116 if (*point != value) {
cannam@477 117 std::cerr << "WARNING: MedianFilter::drop: *point is " << *point
cannam@477 118 << ", expected " << value << std::endl;
cannam@477 119 }
cannam@477 120 const int n = m_sortend - point;
cannam@477 121 for (int i = 0; i < n; ++i) point[i] = point[i+1];
cannam@477 122 *m_sortend = T(0);
c@389 123 }
c@390 124
c@390 125 MedianFilter(const MedianFilter &); // not provided
c@390 126 MedianFilter &operator=(const MedianFilter &); // not provided
c@389 127 };
c@389 128
c@389 129 #endif
c@389 130