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@4
|
34 drop(m_frame[0]);
|
Chris@4
|
35 const int sz1 = m_size-1;
|
Chris@4
|
36 for (int i = 0; i < sz1; ++i) m_frame[i] = m_frame[i+1];
|
Chris@4
|
37 m_frame[m_size-1] = value;
|
Chris@4
|
38 put(value);
|
Chris@4
|
39 }
|
Chris@4
|
40
|
Chris@4
|
41 T get() const {
|
Chris@4
|
42 return m_sorted[m_index];
|
Chris@4
|
43 }
|
Chris@4
|
44
|
Chris@4
|
45 T getAt(float percentile) {
|
Chris@4
|
46 int ix = int((m_size * percentile) / 100.f);
|
Chris@4
|
47 if (ix >= m_size) ix = m_size-1;
|
Chris@4
|
48 if (ix < 0) ix = 0;
|
Chris@4
|
49 return m_sorted[ix];
|
Chris@4
|
50 }
|
Chris@4
|
51
|
Chris@4
|
52 void reset() {
|
Chris@4
|
53 for (int i = 0; i < m_size; ++i) m_frame[i] = 0;
|
Chris@4
|
54 for (int i = 0; i < m_size; ++i) m_sorted[i] = 0;
|
Chris@4
|
55 }
|
Chris@4
|
56
|
Chris@4
|
57 private:
|
Chris@4
|
58 const int m_size;
|
Chris@4
|
59 T *const m_frame;
|
Chris@4
|
60 T *const m_sorted;
|
Chris@4
|
61 T *const m_sortend;
|
Chris@4
|
62 int m_index;
|
Chris@4
|
63
|
Chris@4
|
64 void put(T value) {
|
Chris@4
|
65 // precondition: m_sorted contains m_size-1 values, packed at start
|
Chris@4
|
66 // postcondition: m_sorted contains m_size values, one of which is value
|
Chris@4
|
67 T *point = std::lower_bound(m_sorted, m_sortend, value);
|
Chris@4
|
68 const int n = m_sortend - point;
|
Chris@4
|
69 for (int i = n; i > 0; --i) point[i] = point[i-1];
|
Chris@4
|
70 *point = value;
|
Chris@4
|
71 }
|
Chris@4
|
72
|
Chris@4
|
73 void drop(T value) {
|
Chris@4
|
74 // precondition: m_sorted contains m_size values, one of which is value
|
Chris@4
|
75 // postcondition: m_sorted contains m_size-1 values, packed at start
|
Chris@4
|
76 T *point = std::lower_bound(m_sorted, m_sortend + 1, value);
|
Chris@4
|
77 if (*point != value) {
|
Chris@4
|
78 std::cerr << "WARNING: MedianFilter::drop: *point is " << *point
|
Chris@4
|
79 << ", expected " << value << std::endl;
|
Chris@4
|
80 }
|
Chris@4
|
81 const int n = m_sortend - point;
|
Chris@4
|
82 for (int i = 0; i < n; ++i) point[i] = point[i+1];
|
Chris@4
|
83 *m_sortend = T(0);
|
Chris@4
|
84 }
|
Chris@4
|
85 };
|
Chris@4
|
86
|
Chris@4
|
87 #endif
|
Chris@4
|
88
|