Chris@4
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@4
|
2
|
Chris@4
|
3 #ifndef _MEDIAN_H_
|
Chris@4
|
4 #define _MEDIAN_H_
|
Chris@4
|
5
|
Chris@4
|
6 #include <algorithm>
|
Chris@4
|
7 #include <cassert>
|
Chris@4
|
8
|
Chris@4
|
9 template <typename T>
|
Chris@4
|
10 class MedianFilter
|
Chris@4
|
11 {
|
Chris@4
|
12 public:
|
Chris@4
|
13 MedianFilter(int size, float percentile = 50.f) :
|
Chris@4
|
14 m_size(size),
|
Chris@4
|
15 m_frame(new T[size]),
|
Chris@4
|
16 m_sorted(new T[size]),
|
Chris@4
|
17 m_sortend(m_sorted + size - 1) {
|
Chris@4
|
18 setPercentile(percentile);
|
Chris@4
|
19 reset();
|
Chris@4
|
20 }
|
Chris@4
|
21
|
Chris@4
|
22 ~MedianFilter() {
|
Chris@4
|
23 delete[] m_frame;
|
Chris@4
|
24 delete[] m_sorted;
|
Chris@4
|
25 }
|
Chris@4
|
26
|
Chris@4
|
27 void setPercentile(float p) {
|
Chris@4
|
28 m_index = int((m_size * p) / 100.f);
|
Chris@4
|
29 if (m_index >= m_size) m_index = m_size-1;
|
Chris@4
|
30 if (m_index < 0) m_index = 0;
|
Chris@4
|
31 }
|
Chris@4
|
32
|
Chris@4
|
33 void push(T value) {
|
Chris@7
|
34 if (value != value) return; // nan
|
Chris@4
|
35 drop(m_frame[0]);
|
Chris@4
|
36 const int sz1 = m_size-1;
|
Chris@4
|
37 for (int i = 0; i < sz1; ++i) m_frame[i] = m_frame[i+1];
|
Chris@4
|
38 m_frame[m_size-1] = value;
|
Chris@4
|
39 put(value);
|
Chris@4
|
40 }
|
Chris@4
|
41
|
Chris@4
|
42 T get() const {
|
Chris@4
|
43 return m_sorted[m_index];
|
Chris@4
|
44 }
|
Chris@4
|
45
|
Chris@4
|
46 T getAt(float percentile) {
|
Chris@4
|
47 int ix = int((m_size * percentile) / 100.f);
|
Chris@4
|
48 if (ix >= m_size) ix = m_size-1;
|
Chris@4
|
49 if (ix < 0) ix = 0;
|
Chris@4
|
50 return m_sorted[ix];
|
Chris@4
|
51 }
|
Chris@4
|
52
|
Chris@4
|
53 void reset() {
|
Chris@4
|
54 for (int i = 0; i < m_size; ++i) m_frame[i] = 0;
|
Chris@4
|
55 for (int i = 0; i < m_size; ++i) m_sorted[i] = 0;
|
Chris@4
|
56 }
|
Chris@4
|
57
|
Chris@4
|
58 private:
|
Chris@4
|
59 const int m_size;
|
Chris@4
|
60 T *const m_frame;
|
Chris@4
|
61 T *const m_sorted;
|
Chris@4
|
62 T *const m_sortend;
|
Chris@4
|
63 int m_index;
|
Chris@4
|
64
|
Chris@4
|
65 void put(T value) {
|
Chris@4
|
66 // precondition: m_sorted contains m_size-1 values, packed at start
|
Chris@4
|
67 // postcondition: m_sorted contains m_size values, one of which is value
|
Chris@4
|
68 T *point = std::lower_bound(m_sorted, m_sortend, value);
|
Chris@4
|
69 const int n = m_sortend - point;
|
Chris@4
|
70 for (int i = n; i > 0; --i) point[i] = point[i-1];
|
Chris@4
|
71 *point = value;
|
Chris@4
|
72 }
|
Chris@4
|
73
|
Chris@4
|
74 void drop(T value) {
|
Chris@4
|
75 // precondition: m_sorted contains m_size values, one of which is value
|
Chris@4
|
76 // postcondition: m_sorted contains m_size-1 values, packed at start
|
Chris@4
|
77 T *point = std::lower_bound(m_sorted, m_sortend + 1, value);
|
Chris@4
|
78 if (*point != value) {
|
Chris@4
|
79 std::cerr << "WARNING: MedianFilter::drop: *point is " << *point
|
Chris@4
|
80 << ", expected " << value << std::endl;
|
Chris@4
|
81 }
|
Chris@4
|
82 const int n = m_sortend - point;
|
Chris@4
|
83 for (int i = 0; i < n; ++i) point[i] = point[i+1];
|
Chris@4
|
84 *m_sortend = T(0);
|
Chris@4
|
85 }
|
Chris@4
|
86 };
|
Chris@4
|
87
|
Chris@4
|
88 #endif
|
Chris@4
|
89
|