26 #ifndef MLN_LINEAR_GAUSSIAN_DIRECTIONAL_2D_HH
27 # define MLN_LINEAR_GAUSSIAN_DIRECTIONAL_2D_HH
35 #include <mln/core/image/image2d.hh>
36 #include <mln/extension/adjust_fill.hh>
37 #include <mln/extension/adjust_duplicate.hh>
50 gaussian_directional_2d(const Image<I>& input,
51 unsigned dir,
double sigma,
52 const mln_value(I)& bdr);
56 # ifndef MLN_INCLUDE_ONLY
61 struct recursivefilter_coef_
63 enum FilterType { DericheGaussian,
64 DericheGaussianFirstDerivative,
65 DericheGaussianSecondDerivative };
67 std::vector<double> n, d, nm, dm;
70 recursivefilter_coef_(
double a0,
double a1,
74 double s, FilterType filter_type)
86 double sin0 = sin(w0);
87 double sin1 = sin(w1);
88 double cos0 = cos(w0);
89 double cos1 = cos(w1);
91 switch (filter_type) {
93 case DericheGaussian :
96 (2.0 * a1 * exp( b0 ) * cos0 * cos0 - a0 * sin0 * exp( 2.0 * b0 )
97 + a0 * sin0 - 2.0 * a1 * exp( b0 )) /
98 (( 2.0 * cos0 * exp( b0 ) - exp( 2.0 * b0 ) - 1 ) * sin0);
101 (2.0 * c1 * exp( b1 ) * cos1 * cos1 - c0 * sin1 * exp( 2.0 * b1 )
102 + c0 * sin1 - 2.0 * c1 * exp( b1 ))
103 / (( 2.0 * cos1 * exp( b1 ) - exp( 2.0 * b1 ) - 1 ) * sin1);
107 case DericheGaussianFirstDerivative :
110 (a0 * cos0 - a1 * sin0 + a1 * sin0 * exp( 2.0 * b0 )
111 + a0 * cos0 * exp( 2.0 * b0 ) - 2.0 * a0 * exp( b0 ))
113 / (exp( 4.0 * b0 ) - 4.0 * cos0 * exp( 3.0 * b0 )
114 + 2.0 * exp( 2.0 * b0 ) + 4.0 * cos0 * cos0 * exp( 2.0 * b0 )
115 + 1.0 - 4.0 * cos0 * exp( b0 ));
117 (c0 * cos1 - c1 * sin1 + c1 * sin1 * exp( 2.0 * b1 )
118 + c0 * cos1 * exp( 2.0 * b1 ) - 2.0 * c0 * exp( b1 ))
120 (exp( 4.0 * b1 ) - 4.0 * cos1 * exp( 3.0 * b1 )
121 + 2.0 * exp( 2.0 * b1 ) + 4.0 * cos1 * cos1 * exp( 2.0 * b1 )
122 + 1.0 - 4.0 * cos1 * exp( b1 ));
126 case DericheGaussianSecondDerivative :
130 12.0 * cos0 * exp( 3.0 * b0 ) - 3.0 * exp( 2.0 * b0 )
131 + 8.0 * cos0 * cos0 * cos0 * exp( 3.0 * b0 ) - 12.0 * cos0 * cos0 *
133 - (3.0 * exp( 4.0 * b0 ))
134 + 6.0 * cos0 * exp( 5.0 * b0 ) - exp( 6.0 * b0 ) + 6.0 * cos0 * exp
136 - ( 1.0 + 12.0 * cos0 * cos0 * exp( 2.0 * b0 ) );
138 4.0 * a0 * sin0 * exp( 3.0 * b0 ) + a1 * cos0 * cos0 * exp( 4.0 * b0 )
139 - ( 4.0 * a0 * sin0 * exp( b0 ) + 6.0 * a1 * cos0 * cos0 * exp( 2.0 * b0 ) )
140 + 2.0 * a1 * cos0 * cos0 * cos0 * exp( b0 ) - 2.0 * a1 * cos0 * exp(b0)
141 + 2.0 * a1 * cos0 * cos0 * cos0 * exp( 3.0 * b0 ) - 2.0 * a1 * cos0
143 + a1 * cos0 * cos0 - a1 * exp( 4.0 * b0 )
144 + 2.0 * a0 * sin0 * cos0 * cos0 * exp( b0 ) - 2.0 * a0 * sin0 * cos0
145 * cos0 * exp( 3.0 * b0 )
146 - ( a0 * sin0 * cos0 * exp( 4.0 * b0 ) + a1 )
147 + 6.0 * a1 * exp( 2.0 * b0 ) + a0 * cos0 * sin0
148 * 2.0 * exp( b0 ) / ( aux * sin0 );
150 12.0 * cos1 * exp( 3.0 * b1 ) - 3.0 * exp( 2.0 * b1 )
151 + 8.0 * cos1 * cos1 * cos1 * exp( 3.0 * b1 ) - 12.0 * cos1 * cos1 *
153 - 3.0 * exp( 4.0 * b1 )
154 + 6.0 * cos1 * exp( 5.0 * b1 ) - exp( 6.0 * b1 ) + 6.0 * cos1 * exp
156 - ( 1.0 + 12.0 * cos1 * cos1 * exp( 2.0 * b1 ) );
157 sumC = 4.0 * c0 * sin1 * exp( 3.0 * b1 ) + c1 * cos1 * cos1 * exp( 4.0 * b1 )
158 - ( 4.0 * c0 * sin1 * exp( b1 ) + 6.0 * c1 * cos1 * cos1 * exp( 2.0 * b1 ) )
159 + 2.0 * c1 * cos1 * cos1 * cos1 * exp( b1 ) - 2.0 * c1 * cos1 * exp( b1 )
160 + 2.0 * c1 * cos1 * cos1 * cos1 * exp( 3.0 * b1 ) - 2.0 * c1 * cos1
162 + c1 * cos1 * cos1 - c1 * exp( 4.0 * b1 )
163 + 2.0 * c0 * sin1 * cos1 * cos1 * exp( b1 ) - 2.0 * c0 * sin1 * cos1
164 * cos1 * exp( 3.0 * b1 )
165 - ( c0 * sin1 * cos1 * exp( 4.0 * b1 ) + c1 )
166 + 6.0 * c1 * exp( 2.0 * b1 ) + c0 * cos1 * sin1
167 * 2.0 * exp( b1 ) / ( aux * sin1 );
180 exp( -b1 - 2*b0 ) * (c1 * sin1 - cos1 * c0) +
181 exp( -b0 - 2*b1 ) * (a1 * sin0 - cos0 * a0);
183 2 * exp(-b0 - b1) * ((a0 + c0) * cos1 * cos0 -
186 c0 * exp(-2 * b0) + a0 * exp(-2 * b1);
188 exp(-b1) * (c1 * sin1 - (c0 + 2*a0) * cos1) +
189 exp(-b0) * (a1 * sin0 - (2*c0 + a0) * cos0);
193 d[4] = exp(-2 * b0 - 2 * b1);
195 -2 * cos0 * exp(-b0 - 2*b1) -
196 2 * cos1 * exp(-b1 - 2*b0);
198 4 * cos1 * cos0 * exp(-b0 - b1) +
199 exp(-2*b1) + exp(-2*b0);
201 -2*exp(-b1) * cos1 - 2 * exp(-b0) * cos0;
203 switch (filter_type) {
204 case DericheGaussian :
205 case DericheGaussianSecondDerivative :
207 for (
unsigned i = 1; i <= 3; ++i)
210 nm[i] = n[i] - d[i] * n[0];
213 nm[4] = -d[4] * n[0];
216 case DericheGaussianFirstDerivative :
218 for (
unsigned i = 1; i <= 3; ++i)
221 nm[i] = - (n[i] - d[i] * n[0]);
241 template <
typename I,
typename C>
244 recursivefilter_directional_generic(I& ima,
246 const mln_psite(I)& start,
247 const mln_psite(I)& finish,
249 const mln_deduce(I, psite, delta)& d)
251 std::vector<double> tmp1(len);
252 std::vector<double> tmp2(len);
258 c.n[0]*ima(start + d)
263 c.n[0]*ima(start + d + d)
264 + c.n[1]*ima(start + d)
270 c.n[0]*ima(start + d + d + d)
271 + c.n[1]*ima(start + d + d)
272 + c.n[2]*ima(start + d)
274 - c.d[1]*tmp1[2] - c.d[2]*tmp1[1]
277 mln_site(I) current = start + d + d + d + d;
278 for (
int i = 4; i < len; ++i)
282 + c.n[1]*ima(current - d)
283 + c.n[2]*ima(current - d - d)
284 + c.n[3]*ima(current - d - d - d)
285 - c.d[1]*tmp1[i - 1] - c.d[2]*tmp1[i - 2]
286 - c.d[3]*tmp1[i - 3] - c.d[4]*tmp1[i - 4];
298 c.nm[1]*ima(finish - d)
299 + c.nm[2]*ima(finish)
300 - c.dm[1]*tmp2[len-2];
303 c.nm[1]*ima(finish - d - d)
304 + c.nm[2]*ima(finish - d)
305 + c.nm[3]*ima(finish)
306 - c.dm[1]*tmp2[len-3]
307 - c.dm[2]*tmp2[len-2];
309 current = finish - d - d - d ;
311 for (
int i = len - 5; i >= 0; --i)
315 + c.nm[2]*ima(current + d)
316 + c.nm[3]*ima(current + d + d)
317 + c.nm[4]*ima(current + d + d + d)
318 - c.dm[1]*tmp2[i+1] - c.dm[2]*tmp2[i+2]
319 - c.dm[3]*tmp2[i+3] - c.dm[4]*tmp2[i+4];
326 for (
int i = 0; i < len; ++i)
328 ima(current) = (tmp1[i] + tmp2[i]);
336 template <
typename I,
typename C>
339 recursivefilter_directional_fastest(I& ima,
341 const mln_psite(I)& start,
342 const mln_psite(I)& finish,
344 const mln_deduce(I, psite, delta)& d,
345 const mln_value(I)& bdr)
350 std::vector<double> tmp1(len);
351 std::vector<double> tmp2(len);
353 unsigned delta_offset = ima.delta_index(d);
355 o_start = ima.index_of_point(start),
356 o_start_d = o_start + delta_offset,
357 o_start_dd = o_start + 2 * delta_offset,
358 o_start_ddd = o_start + 3 * delta_offset;
361 c.n[0] * ima.element(o_start);
364 + c.n[0] * ima.element(o_start_d)
365 + c.n[1] * ima.element(o_start)
369 + c.n[0] * ima.element(o_start_dd)
370 + c.n[1] * ima.element(o_start_d)
371 + c.n[2] * ima.element(o_start)
376 + c.n[0] * ima.element(o_start_ddd)
377 + c.n[1] * ima.element(o_start_dd)
378 + c.n[2] * ima.element(o_start_d)
379 + c.n[3] * ima.element(o_start)
380 - c.d[1] * tmp1[2] - c.d[2] * tmp1[1]
384 o_current = o_start + 4 * delta_offset,
385 o_current_d = o_current - delta_offset,
386 o_current_dd = o_current - 2 * delta_offset,
387 o_current_ddd = o_current - 3 * delta_offset;
389 for (
int i = 4; i < len; ++i)
392 + c.n[0] * ima.element(o_current)
393 + c.n[1] * ima.element(o_current_d)
394 + c.n[2] * ima.element(o_current_dd)
395 + c.n[3] * ima.element(o_current_ddd)
396 - c.d[1] * tmp1[i - 1] - c.d[2] * tmp1[i - 2]
397 - c.d[3] * tmp1[i - 3] - c.d[4] * tmp1[i - 4];
398 o_current += delta_offset;
399 o_current_d += delta_offset;
400 o_current_dd += delta_offset;
401 o_current_ddd += delta_offset;
410 o_finish = ima.index_of_point(finish),
411 o_finish_d = o_finish - delta_offset,
412 o_finish_dd = o_finish - 2 * delta_offset;
417 c.nm[1] * ima.element(o_finish);
420 + c.nm[1] * ima.element(o_finish_d)
421 + c.nm[2] * ima.element(o_finish)
422 - c.dm[1] * tmp2[len-2];
425 + c.nm[1] * ima.element(o_finish_dd)
426 + c.nm[2] * ima.element(o_finish_d)
427 + c.nm[3] * ima.element(o_finish)
428 - c.dm[1] * tmp2[len-3]
429 - c.dm[2] * tmp2[len-2];
431 o_current = o_finish - 3 * delta_offset;
432 o_current_d = o_current + delta_offset;
433 o_current_dd = o_current + 2 * delta_offset;
434 o_current_ddd = o_current + 3 * delta_offset;
436 for (
int i = len - 5; i >= 0; --i)
439 + c.nm[1] * ima.element(o_current)
440 + c.nm[2] * ima.element(o_current_d)
441 + c.nm[3] * ima.element(o_current_dd)
442 + c.nm[4] * ima.element(o_current_ddd)
443 - c.dm[1] * tmp2[i+1] - c.dm[2] * tmp2[i+2]
444 - c.dm[3] * tmp2[i+3] - c.dm[4] * tmp2[i+4];
445 o_current -= delta_offset;
446 o_current_d -= delta_offset;
447 o_current_dd -= delta_offset;
448 o_current_ddd -= delta_offset;
454 for (
int i = 0; i < len; ++i)
456 ima.element(o_current) =
static_cast<mln_value(I)
>(tmp1[i] + tmp2[i]);
457 o_current += delta_offset;
462 template <
typename I>
465 gaussian_directional_2d(const Image<I>& input_,
466 unsigned dir,
double sigma,
467 const mln_value(I)& bdr)
469 trace::entering(
"linear::gaussian_directional_2d");
471 typedef mln_site(I) P;
472 mlc_bool(P::dim == 2)::check();
474 const I& input = exact(input_);
476 mln_precondition(dir == 0 || dir == 1);
477 mln_precondition(input.is_valid());
479 my::recursivefilter_coef_ coef(1.68f, 3.735f,
484 my::recursivefilter_coef_::DericheGaussian);
486 extension::adjust_fill(input, 5 *
int(sigma + .50001) + 1, bdr);
487 mln_concrete(I) output =
duplicate(input);
493 nrows = geom::nrows(input),
494 ncols = geom::ncols(input),
499 for (
int j = 0; j <
ncols; ++j)
500 recursivefilter_directional_fastest(output, coef,
510 for (
int i = 0; i <
nrows; ++i)
511 recursivefilter_directional_fastest(output, coef,
519 trace::exiting(
"linear::gaussian_directional_2d");
523 # endif // ! MLN_INCLUDE_ONLY
530 #endif // ! MLN_LINEAR_GAUSSIAN_DIRECTIONAL_2D_HH