| c@389 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| c@389 | 2 | 
| c@390 | 3 /* | 
| c@390 | 4     QM DSP Library | 
| c@390 | 5 | 
| c@390 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| c@390 | 7     This file Copyright 2010 Chris Cannam. | 
| c@390 | 8 | 
| c@390 | 9     This program is free software; you can redistribute it and/or | 
| c@390 | 10     modify it under the terms of the GNU General Public License as | 
| c@390 | 11     published by the Free Software Foundation; either version 2 of the | 
| c@390 | 12     License, or (at your option) any later version.  See the file | 
| c@390 | 13     COPYING included with this distribution for more information. | 
| c@390 | 14 */ | 
| c@390 | 15 | 
| c@389 | 16 #ifndef MEDIAN_FILTER_H | 
| c@389 | 17 #define MEDIAN_FILTER_H | 
| c@389 | 18 | 
| c@389 | 19 #include <algorithm> | 
| c@389 | 20 #include <cassert> | 
| c@389 | 21 #include <cmath> | 
| c@389 | 22 #include <iostream> | 
| c@392 | 23 #include <vector> | 
| c@389 | 24 | 
| c@389 | 25 template <typename T> | 
| c@389 | 26 class MedianFilter | 
| c@389 | 27 { | 
| c@389 | 28 public: | 
| c@389 | 29     MedianFilter(int size, float percentile = 50.f) : | 
| c@389 | 30 	m_size(size), | 
| c@389 | 31 	m_frame(new T[size]), | 
| c@389 | 32 	m_sorted(new T[size]), | 
| c@389 | 33 	m_sortend(m_sorted + size - 1) { | 
| c@389 | 34         setPercentile(percentile); | 
| c@389 | 35 	reset(); | 
| c@389 | 36     } | 
| c@389 | 37 | 
| c@389 | 38     ~MedianFilter() { | 
| c@389 | 39 	delete[] m_frame; | 
| c@389 | 40 	delete[] m_sorted; | 
| c@389 | 41     } | 
| c@389 | 42 | 
| c@389 | 43     void setPercentile(float p) { | 
| c@389 | 44         m_index = int((m_size * p) / 100.f); | 
| c@389 | 45         if (m_index >= m_size) m_index = m_size-1; | 
| c@389 | 46         if (m_index < 0) m_index = 0; | 
| c@389 | 47     } | 
| c@389 | 48 | 
| c@389 | 49     void push(T value) { | 
| c@394 | 50         if (value != value) { | 
| c@394 | 51             std::cerr << "WARNING: MedianFilter::push: attempt to push NaN" << std::endl; | 
| c@394 | 52             return; // nan | 
| c@394 | 53         } | 
| c@389 | 54 	drop(m_frame[0]); | 
| c@389 | 55 	const int sz1 = m_size-1; | 
| c@389 | 56 	for (int i = 0; i < sz1; ++i) m_frame[i] = m_frame[i+1]; | 
| c@389 | 57 	m_frame[m_size-1] = value; | 
| c@389 | 58 	put(value); | 
| c@389 | 59     } | 
| c@389 | 60 | 
| c@389 | 61     T get() const { | 
| c@389 | 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) { | 
| c@389 | 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; | 
| c@389 | 73 	return m_sorted[ix]; | 
| c@389 | 74     } | 
| c@389 | 75 | 
| c@389 | 76     void reset() { | 
| c@389 | 77 	for (int i = 0; i < m_size; ++i) m_frame[i] = 0; | 
| c@389 | 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) { | 
| c@389 | 104 	// precondition: m_sorted contains m_size-1 values, packed at start | 
| c@389 | 105 	// postcondition: m_sorted contains m_size values, one of which is value | 
| c@389 | 106 	T *point = std::lower_bound(m_sorted, m_sortend, value); | 
| c@389 | 107 	const int n = m_sortend - point; | 
| c@389 | 108 	for (int i = n; i > 0; --i) point[i] = point[i-1]; | 
| c@389 | 109 	*point = value; | 
| c@389 | 110     } | 
| c@389 | 111 | 
| c@389 | 112     void drop(T value) { | 
| c@389 | 113 	// precondition: m_sorted contains m_size values, one of which is value | 
| c@389 | 114 	// postcondition: m_sorted contains m_size-1 values, packed at start | 
| c@389 | 115 	T *point = std::lower_bound(m_sorted, m_sortend + 1, value); | 
| c@389 | 116 	if (*point != value) { | 
| c@389 | 117 	    std::cerr << "WARNING: MedianFilter::drop: *point is " << *point | 
| c@389 | 118 		      << ", expected " << value << std::endl; | 
| c@389 | 119 	} | 
| c@389 | 120 	const int n = m_sortend - point; | 
| c@389 | 121 	for (int i = 0; i < n; ++i) point[i] = point[i+1]; | 
| c@389 | 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 |