annotate maths/MedianFilter.h @ 187:5b065087cb7e qm-vamp-plugins-v1.7.1

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