median.hh 6.19 KB
Newer Older
Thierry Geraud's avatar
Thierry Geraud committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Copyright (C) 2007 EPITA Research and Development Laboratory
//
// This file is part of the Olena Library.  This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING.  If not, write to
// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
// Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free
// software library without restriction.  Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License.  This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.

#ifndef MLN_LEVEL_MEDIAN_HH
# define MLN_LEVEL_MEDIAN_HH

/*! \file mln/level/median.hh
 *
33
 * \brief Median filtering of an image.
Thierry Geraud's avatar
Thierry Geraud committed
34
35
36
 */

# include <mln/core/concept/image.hh>
37
# include <mln/geom/size2d.hh>
38

Thierry Geraud's avatar
Thierry Geraud committed
39
# include <mln/core/window2d.hh>
40
# include <mln/core/win/hline2d.hh>
41
# include <mln/core/t_image.hh>
42

43
# include <mln/accu/median.hh>
44
# include <mln/canvas/browsing/snake_fwd.hh>
Thierry Geraud's avatar
Thierry Geraud committed
45

46
47
48
# include <mln/geom/shift.hh>
# include <mln/set/diff.hh>

Thierry Geraud's avatar
Thierry Geraud committed
49
50
51
52
53
54
55

namespace mln
{

  namespace level
  {

56
57
    /*! Compute in \p output the median filter of image \p input by
     *  the window \p win.
Thierry Geraud's avatar
Thierry Geraud committed
58
59
60
61
62
     *
     * \param[in] input The image to be filtered.
     * \param[in] win The window.
     * \param[in,out] output The output image.
     *
63
     * \pre \p input and \p output have to be initialized.
Thierry Geraud's avatar
Thierry Geraud committed
64
65
66
67
68
69
70
71
72
73
74
75
     */
    template <typename I, typename W, typename O>
    void median(const Image<I>& input, const Window<W>& win,
		Image<O>& output);


# ifndef MLN_INCLUDE_ONLY


    namespace impl
    {

Thierry Geraud's avatar
Thierry Geraud committed
76
77
78
79
80
81
82
83
84
85
86
87

      template <typename I, typename W, typename O>
      struct median_functor
      { 
	// i/o

	const I& input;
	const W& win;
	O& output;

	// aux data

88
	accu::median<mln_vset(I)> med;
Thierry Geraud's avatar
Thierry Geraud committed
89
90
91
92
93
94
	mln_point(I) p;
	window2d     win_fp, win_fm, win_bp, win_bm, win_dp, win_dm;
	mln_qiter(W)   q_fp,   q_fm,   q_bp,   q_bm,   q_dp,   q_dm;

	// ctor

95
	median_functor(const I& input_, const W& win_, O& output_)
Thierry Geraud's avatar
Thierry Geraud committed
96
97
98
99
100
101
	  :
	  // i/o
	  input(exact(input_)),
	  win(exact(win_)),
	  output(exact(output_)),
	  // aux data
102
	  med(input.values()),
Thierry Geraud's avatar
Thierry Geraud committed
103
	  p(),
104
105
106
107
108
109
	  win_fp(set::diff(win, geom::shift(win, left))),
	  win_fm(set::diff(geom::shift(win, left),  win)),
	  win_bp(set::diff(win, geom::shift(win, right))),
	  win_bm(set::diff(geom::shift(win, right), win)),
	  win_dp(set::diff(win, geom::shift(win, up))),
	  win_dm(set::diff(geom::shift(win, up),    win)),
Thierry Geraud's avatar
Thierry Geraud committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
	  q_fp(win_fp, p),  q_fm(win_fm, p),
	  q_bp(win_bp, p),  q_bm(win_bm, p),
	  q_dp(win_dp, p),  q_dm(win_dm, p)
	{
	}

	// parts

	void init()
	{
	  med.init();
	  mln_qiter(W) q(win, p);
	  for_all(q) if (input.has(q))
	    med.take(input(q));
	}

	void down()
	{
	  for_all(q_dm) if (input.has(q_dm))
	    med.untake(input(q_dm));
	  for_all(q_dp) if (input.has(q_dp))
	    med.take(input(q_dp));
132
	  output(p) = med.to_value();
Thierry Geraud's avatar
Thierry Geraud committed
133
134
135
136
137
138
139
140
	}

	void fwd()
	{
	  for_all(q_fm) if (input.has(q_fm))
	    med.untake(input(q_fm));
	  for_all(q_fp) if (input.has(q_fp))
	    med.take(input(q_fp));
141
	  output(p) = med.to_value();
Thierry Geraud's avatar
Thierry Geraud committed
142
143
144
145
146
147
148
149
	}

	void bkd()
	{
	  for_all(q_bm) if (input.has(q_bm))
	    med.untake(input(q_bm));
	  for_all(q_bp) if (input.has(q_bp))
	    med.take(input(q_bp));
150
	  output(p) = med.to_value();
Thierry Geraud's avatar
Thierry Geraud committed
151
152
153
154
155
	}

      }; // end of median_functor


156
157


Thierry Geraud's avatar
Thierry Geraud committed
158
      template <typename I, typename W, typename O>
159
      void median(const I& input, const Window<W>& win, O& output)
Thierry Geraud's avatar
Thierry Geraud committed
160
161
      {
	// FIXME: resize border!
162
	impl::median_functor<I,W,O> f(input, exact(win), output);
163
	canvas::browsing::snake_fwd(f);
Thierry Geraud's avatar
Thierry Geraud committed
164
165
166
      }


167
      template <typename I, typename O>
168
      void median(const I& input, const win::hline2d& win, O& output)
169
      {
170
171
	typedef mln_coord(I) coord;
	const coord
172
173
174
175
	  min_row = geom::min_row(input),
	  max_row = geom::max_row(input),
	  min_col = geom::min_col(input),
	  max_col = geom::max_col(input);
176
	const coord half = win.length() / 2;
177
178

	point2d p;
179
180
	coord& row = p.row();
	coord& col = p.col();
181

182
183
184
185
186
187
	point2d pt;
	coord& ct = pt.col();

	point2d pu;
	coord& cu = pu.col();

188
	accu::median<mln_vset(I)> med(input.values());
189

190
	for (row = min_row; row <= max_row; ++row)
191
	  {
192
	    pt.row() = pu.row() = row;
193
194
195
196

	    // initialization (before first point of the row)
	    med.init();
	    for (ct = min_col; ct < min_col + half; ++ct)
197
	      med.take(input(pt));
198
199
200
201

	    // left columns (just take new points)
	    for (col = min_col; col <= min_col + half; ++col, ++ct)
	      {
202
		med.take(input(pt));
203
		output(p) = med.to_value();
204
205
206
207
208
209
	      }
	    
	    // middle columns (both take and untake)
	    cu = min_col;
	    for (; col <= max_col - half; ++cu, ++col, ++ct)
	      {
210
211
		med.take(input(pt));
		med.untake(input(pu));
212
		output(p) = med.to_value();
213
214
215
216
217
	      }

	    // right columns (now just untake old points)
	    for (; col <= max_col; ++cu, ++col)
	      {
218
		med.untake(input(pu));
219
		output(p) = med.to_value();
220
221
222
223
224
	      }
	  }
      }


225
226
227
228
229
230
231
232
      template <typename I, typename O>
      void median(const I& input, const win::vline2d& win, O& output)
      {
	t_image<O> swap_output = swap_coords(output, 0, 1);
	impl::median(swap_coords(input, 0, 1),
		     win::hline2d(win.length()),
		     swap_output);
      }
233
234


Thierry Geraud's avatar
Thierry Geraud committed
235
236
237
238
239
240
241
242
243
    } // end of namespace mln::level::impl


    // facade

    template <typename I, typename W, typename O>
    void median(const Image<I>& input, const Window<W>& win,
		Image<O>& output)
    {
244
      mln_assertion(exact(output).domain() == exact(input).domain());
Thierry Geraud's avatar
Thierry Geraud committed
245
246
247
248
249
250
251
252
253
254
255
      impl::median(exact(input), exact(win), exact(output)); 
    }

# endif // ! MLN_INCLUDE_ONLY

  } // end of namespace mln::level

} // end of namespace mln


#endif // ! MLN_LEVEL_MEDIAN_HH