annotate src/MedianFilter.h @ 372:af71cbdab621 tip

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