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