1 /************************************************************************/
2 /*                                                                      */
3 /*               Copyright 2007-2014 by Benjamin Seppke                 */
4 /*       Cognitive Systems Group, University of Hamburg, Germany        */
5 /*                                                                      */
6 /************************************************************************/
7 
8 #ifndef VIGRA_MEDIANFILTER_HXX
9 #define VIGRA_MEDIANFILTER_HXX
10 
11 #include <vector>
12 #include <algorithm>
13 
14 #include "applywindowfunction.hxx"
15 
16 namespace vigra
17 {
18 
19 /********************************************************/
20 /*                                                      */
21 /*              Generic median filter                   */
22 /*                                                      */
23 /********************************************************/
24 /**
25     This function calculates the median of a window of given size for the complete image.
26     It also allows a correct border handling, since it uses the \ref applyWindowFunction
27     environment for computation!
28 */
29 //@{
30 
31 /** \brief This function calculates the median of a window of given size for the complete image.
32 
33     All \ref BorderTreatmentMode "border treatment modes"  (except BORDER_TREATMENT_CLIP)  are supported.
34 
35     The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
36     the window functions' value_type <tt>T</tt>. Especially, the values must be sortable by
37     std::sort, to derive the mean values aka the median.
38 
39     <b> Declarations:</b>
40 
41     pass 2D array views:
42     \code
43     namespace vigra {
44         template <class T1, class S1,
45                   class T2, class S2>
46         void
47         medianFilter(MultiArrayView<2, T1, S1> const & src,
48                      MultiArrayView<2, T2, S2> dest,
49                      Diff2D window_shape,
50                      BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
51 
52     }
53     \endcode
54 
55     \deprecatedAPI{medianFilter}
56     pass \ref ImageIterators and \ref DataAccessors :
57     \code
58     namespace vigra {
59         template <class SrcIterator, class SrcAccessor,
60                   class DestIterator, class DestAccessor>
61         void medianFilter(SrcIterator supperleft,
62                           SrcIterator slowerright, SrcAccessor sa,
63                           DestIterator dupperleft, DestAccessor da,
64                           Diff2D window_shape,
65                           BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
66     }
67     \endcode
68     use argument objects in conjunction with \ref ArgumentObjectFactories :
69     \code
70     namespace vigra {
71         template <class SrcIterator, class SrcAccessor,
72                   class DestIterator, class DestAccessor>
73         void
74         medianFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
75                      pair<DestIterator, DestAccessor> dest,
76                      Diff2D window_shape,
77                      BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
78     }
79     \endcode
80     \deprecatedEnd
81 
82     <b> Usage:</b>
83 
84     <b>\#include</b> \<vigra/medianfilter.hxx\><br/>
85     Namespace: vigra
86 
87     \code
88     unsigned int w=1000, h=1000;
89     MultiArray<2, float> src(w,h), dest(w,h);
90     ...
91 
92     // apply a median filter with a window size of 5x5
93     medianFilter(src, dest, Diff2D(5,5));
94     \endcode
95 
96     <b> Preconditions:</b>
97 
98     The image must be larger than the window size of the filter.
99 */
100 
101 doxygen_overloaded_function(template <...> void medianFilter)
102 
103 template<class VALUETYPE>
104 class MedianFunctor
105 {
106 public:
MedianFunctor(Diff2D window_shape)107     MedianFunctor(Diff2D window_shape)
108     : m_window_shape(window_shape),
109       m_buffer(window_shape.x*window_shape.y)
110     {
111     }
112 
113     template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
operator ()(SrcIterator s,SrcAccessor s_acc,DestIterator d,DestAccessor d_acc)114     void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
115     {
116         SrcIterator s_ul = s - m_window_shape/2,
117                     s_lr = s_ul + m_window_shape;
118 
119         std::fill(m_buffer.begin(), m_buffer.end(), VALUETYPE());
120 
121         SrcIterator ys = s_ul;
122         SrcIterator xs = ys;
123 
124         typename std::vector<VALUETYPE>::iterator iter = m_buffer.begin(),
125                                                   median_iter = m_buffer.begin()+m_buffer.size()/2;
126 
127         for( ; ys.y != s_lr.y; ys.y++)
128         {
129             for(xs = ys; xs.x != s_lr.x; xs.x++, iter++)
130             {
131                 *iter = s_acc(xs);
132             }
133         }
134 
135         std::nth_element(m_buffer.begin(), median_iter, m_buffer.end());
136         d_acc.set(*median_iter,d);
137     }
138 
windowShape() const139     Diff2D windowShape() const
140     {
141         return m_window_shape;
142     }
143 
144 private:
145     Diff2D m_window_shape;
146     std::vector<VALUETYPE> m_buffer;
147 };
148 
149 
150 template <class SrcIterator, class SrcAccessor,
151           class DestIterator, class DestAccessor>
medianFilter(SrcIterator s_ul,SrcIterator s_lr,SrcAccessor s_acc,DestIterator d_ul,DestAccessor d_acc,Diff2D window_shape,BorderTreatmentMode border=BORDER_TREATMENT_REPEAT)152 inline void medianFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
153                          DestIterator d_ul, DestAccessor d_acc,
154                          Diff2D window_shape,
155                          BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
156 {
157     MedianFunctor<typename SrcIterator::value_type> func(window_shape);
158     applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
159 }
160 
161 template <class SrcIterator, class SrcAccessor,
162           class DestIterator, class DestAccessor>
medianFilter(triple<SrcIterator,SrcIterator,SrcAccessor> s,pair<DestIterator,DestAccessor> d,Diff2D window_shape,BorderTreatmentMode border=BORDER_TREATMENT_REPEAT)163 inline void medianFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
164                          pair<DestIterator, DestAccessor> d,
165                          Diff2D window_shape,
166                          BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
167 {
168     medianFilter(s.first, s.second, s.third,
169                  d.first, d.second,
170                  window_shape,
171                  border);
172 }
173 
174 template <class T1, class S1,
175           class T2, class S2>
medianFilter(MultiArrayView<2,T1,S1> const & src,MultiArrayView<2,T2,S2> dest,Diff2D window_shape,BorderTreatmentMode border=BORDER_TREATMENT_REPEAT)176 inline void medianFilter(MultiArrayView<2, T1, S1> const & src,
177                          MultiArrayView<2, T2, S2> dest,
178                          Diff2D window_shape,
179                          BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
180 {
181     vigra_precondition(src.shape() == dest.shape(),
182                         "vigra::medianFilter(): shape mismatch between input and output.");
183     medianFilter(srcImageRange(src),
184                  destImage(dest),
185                  window_shape,
186                  border);
187 }
188 
189 //@}
190 
191 } //end of namespace vigra
192 
193 #endif //VIGRA_MEDIANFILTER_HXX
194