[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

nonlineardiffusion.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2002 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35
36 #ifndef VIGRA_NONLINEARDIFFUSION_HXX
37 #define VIGRA_NONLINEARDIFFUSION_HXX
38
39 #include <vector>
40 #include "stdimage.hxx"
41 #include "stdimagefunctions.hxx"
42 #include "imageiteratoradapter.hxx"
43 #include "functortraits.hxx"
44 #include "multi_shape.hxx"
45
46 namespace vigra {
47
48 template <class SrcIterator, class SrcAccessor,
49 class CoeffIterator, class DestIterator>
50 void internalNonlinearDiffusionDiagonalSolver(
51 SrcIterator sbegin, SrcIterator send, SrcAccessor sa,
52 CoeffIterator diag, CoeffIterator upper, CoeffIterator lower,
53 DestIterator dbegin)
54 {
55 int w = send - sbegin - 1;
56
57 int i;
58
59 for(i=0; i<w; ++i)
60 {
61 lower[i] = lower[i] / diag[i];
62
63 diag[i+1] = diag[i+1] - lower[i] * upper[i];
64 }
65
66 dbegin[0] = sa(sbegin);
67
68 for(i=1; i<=w; ++i)
69 {
70 dbegin[i] = sa(sbegin, i) - lower[i-1] * dbegin[i-1];
71 }
72
73 dbegin[w] = dbegin[w] / diag[w];
74
75 for(i=w-1; i>=0; --i)
76 {
77 dbegin[i] = (dbegin[i] - upper[i] * dbegin[i+1]) / diag[i];
78 }
79 }
80
81
82 template <class SrcIterator, class SrcAccessor,
83 class WeightIterator, class WeightAccessor,
84 class DestIterator, class DestAccessor>
85 void internalNonlinearDiffusionAOSStep(
86 SrcIterator sul, SrcIterator slr, SrcAccessor as,
87 WeightIterator wul, WeightAccessor aw,
88 DestIterator dul, DestAccessor ad, double timestep)
89 {
90 // use traits to determine SumType as to prevent possible overflow
91 typedef typename
92 NumericTraits<typename WeightAccessor::value_type>::RealPromote
93 WeightType;
94
95 // calculate width and height of the image
96 int w = slr.x - sul.x;
97 int h = slr.y - sul.y;
98 int d = (w < h) ? h : w;
99
100 std::vector<WeightType> lower(d),
101 diag(d),
102 upper(d),
103 res(d);
104
105 int x,y;
106
107 WeightType one = NumericTraits<WeightType>::one();
108
109 // create y iterators
110 SrcIterator ys = sul;
111 WeightIterator yw = wul;
112 DestIterator yd = dul;
113
114 // x-direction
115 for(y=0; y<h; ++y, ++ys.y, ++yd.y, ++yw.y)
116 {
117 typename SrcIterator::row_iterator xs = ys.rowIterator();
118 typename WeightIterator::row_iterator xw = yw.rowIterator();
119 typename DestIterator::row_iterator xd = yd.rowIterator();
120
121 // fill 3-diag matrix
122
123 diag[0] = one + timestep * (aw(xw) + aw(xw, 1));
124 for(x=1; x<w-1; ++x)
125 {
126 diag[x] = one + timestep * (2.0 * aw(xw, x) + aw(xw, x+1) + aw(xw, x-1));
127 }
128 diag[w-1] = one + timestep * (aw(xw, w-1) + aw(xw, w-2));
129
130 for(x=0; x<w-1; ++x)
131 {
132 lower[x] = -timestep * (aw(xw, x) + aw(xw, x+1));
133 upper[x] = lower[x];
134 }
135
136 internalNonlinearDiffusionDiagonalSolver(xs, xs+w, as,
137 diag.begin(), upper.begin(), lower.begin(), res.begin());
138
139 for(x=0; x<w; ++x, ++xd)
140 {
141 ad.set(res[x], xd);
142 }
143 }
144
145 // y-direction
146 ys = sul;
147 yw = wul;
148 yd = dul;
149
150 for(x=0; x<w; ++x, ++ys.x, ++yd.x, ++yw.x)
151 {
152 typename SrcIterator::column_iterator xs = ys.columnIterator();
153 typename WeightIterator::column_iterator xw = yw.columnIterator();
154 typename DestIterator::column_iterator xd = yd.columnIterator();
155
156 // fill 3-diag matrix
157
158 diag[0] = one + timestep * (aw(xw) + aw(xw, 1));
159 for(y=1; y<h-1; ++y)
160 {
161 diag[y] = one + timestep * (2.0 * aw(xw, y) + aw(xw, y+1) + aw(xw, y-1));
162 }
163 diag[h-1] = one + timestep * (aw(xw, h-1) + aw(xw, h-2));
164
165 for(y=0; y<h-1; ++y)
166 {
167 lower[y] = -timestep * (aw(xw, y) + aw(xw, y+1));
168 upper[y] = lower[y];
169 }
170
171 internalNonlinearDiffusionDiagonalSolver(xs, xs+h, as,
172 diag.begin(), upper.begin(), lower.begin(), res.begin());
173
174 for(y=0; y<h; ++y, ++xd)
175 {
176 ad.set(0.5 * (ad(xd) + res[y]), xd);
177 }
178 }
179 }
180
181 /** \addtogroup NonLinearDiffusion Non-linear Diffusion and Total Variation
182
183 Perform edge-preserving smoothing.
184 */
185 //@{
186
187 /********************************************************/
188 /* */
189 /* nonlinearDiffusion */
190 /* */
191 /********************************************************/
192
193 /** \brief Perform edge-preserving smoothing at the given scale.
194
195 The algorithm solves the non-linear diffusion equation
196
197 \f[
198 \frac{\partial}{\partial t} u =
199 \frac{\partial}{\partial x}
200 \left( g(|\nabla u|)
201 \frac{\partial}{\partial x} u
202 \right)
203 \f]
204
205 where <em> t</em> is the time, <b> x</b> is the location vector,
206 <em> u(</em><b> x</b><em> , t)</em> is the smoothed image at time <em> t</em>, and
207 <em> g(.)</em> is the location dependent diffusivity. At time zero, the image
208 <em> u(</em><b> x</b><em> , 0)</em> is simply the original image. The time is
209 proportional to the square of the scale parameter: \f$t = s^2\f$.
210 The diffusion equation is solved iteratively according
211 to the Additive Operator Splitting Scheme (AOS) from
212
213 J. Weickert: <em>"Recursive Separable Schemes for Nonlinear Diffusion
214 Filters"</em>,
215 in: B. ter Haar Romeny, L. Florack, J. Koenderingk, M. Viergever (eds.):
216 1st Intl. Conf. on Scale-Space Theory in Computer Vision 1997,
217 Springer LNCS 1252
218
219 <TT>DiffusivityFunctor</TT> implements the gradient-dependent local diffusivity.
220 It is passed
221 as an argument to \ref gradientBasedTransform(). The return value must be
222 between 0 and 1 and determines the weight a pixel gets when
223 its neighbors are smoothed. Weickert recommends the use of the diffusivity
224 implemented by class \ref DiffusivityFunctor. It's also possible to use
225 other functors, for example one that always returns 1, in which case
226 we obtain the solution to the linear diffusion equation, i.e.
227 Gaussian convolution.
228
229 The source value type must be a
230 linear space with internal addition, scalar multiplication, and
231 NumericTraits defined. The value_type of the DiffusivityFunctor must be the
232 scalar field over wich the source value type's linear space is defined.
233
234 In addition to <TT>nonlinearDiffusion()</TT>, there is an algorithm
235 <TT>nonlinearDiffusionExplicit()</TT> which implements the Explicit Scheme
236 described in the above article. Both algorithms have the same interface,
237 but the explicit scheme gives slightly more accurate approximations of
238 the diffusion process at the cost of much slower processing.
239
240 <b> Declarations:</b>
241
242 pass 2D array views:
243 \code
244 namespace vigra {
245 template <class T1, class S1,
246 class T2, class S2,
247 class DiffusivityFunc>
248 void
249 nonlinearDiffusion(MultiArrayView<2, T1, S1> const & src,
250 MultiArrayView<2, T2, S2> dest,
251 DiffusivityFunc const & weight, double scale);
252
253 template <class T1, class S1,
254 class T2, class S2,
255 class DiffusivityFunc>
256 void
257 nonlinearDiffusionExplicit(MultiArrayView<2, T1, S1> const & src,
258 MultiArrayView<2, T2, S2> dest,
259 DiffusivityFunc const & weight, double scale);
260 }
261 \endcode
262
263 \deprecatedAPI{nonlinearDiffusion}
264 pass \ref ImageIterators and \ref DataAccessors :
265 \code
266 namespace vigra {
267 template <class SrcIterator, class SrcAccessor,
268 class DestIterator, class DestAccessor,
269 class DiffusivityFunctor>
270 void nonlinearDiffusion(SrcIterator sul, SrcIterator slr, SrcAccessor as,
271 DestIterator dul, DestAccessor ad,
272 DiffusivityFunctor const & weight, double scale);
273 }
274 \endcode
275 use argument objects in conjunction with \ref ArgumentObjectFactories :
276 \code
277 namespace vigra {
278 template <class SrcIterator, class SrcAccessor,
279 class DestIterator, class DestAccessor,
280 class DiffusivityFunctor>
281 void nonlinearDiffusion(
282 triple<SrcIterator, SrcIterator, SrcAccessor> src,
283 pair<DestIterator, DestAccessor> dest,
284 DiffusivityFunctor const & weight, double scale);
285 }
286 \endcode
287 \deprecatedEnd
288
289 <b> Usage:</b>
290
291 <b>\#include</b> <vigra/nonlineardiffusion.hxx><br/>
292 Namespace: vigra
293
294 \code
295 MultiArray<2, float> src(w,h), dest(w,h);
296 float edge_threshold, scale;
297 ...
298
299 nonlinearDiffusion(src, dest,
300 DiffusivityFunctor<float>(edge_threshold), scale);
301 \endcode
302
303 \deprecatedUsage{nonlinearDiffusion}
304 \code
305 FImage src(w,h), dest(w,h);
306 float edge_threshold, scale;
307 ...
308
309 nonlinearDiffusion(srcImageRange(src), destImage(dest),
310 DiffusivityFunctor<float>(edge_threshold), scale);
311 \endcode
312 <b> Required Interface:</b>
313 <ul>
314 <li> <TT>SrcIterator</TT> and <TT>DestIterator</TT> are models of ImageIterator
315 <li> <TT>SrcAccessor</TT> and <TT>DestAccessor</TT> are models of StandardAccessor
316 <li> <TT>SrcAccessor::value_type</TT> is a linear space
317 <li> <TT>DiffusivityFunctor</TT> conforms to the requirements of
318 \ref gradientBasedTransform(). Its range is between 0 and 1.
319 <li> <TT>DiffusivityFunctor::value_type</TT> is an algebraic field
320 </ul>
321 \deprecatedEnd
322
323 <b> Precondition:</b>
324
325 <TT>scale > 0</TT>
326
327 \see vigra::DiffusivityFunctor
328 */
329 doxygen_overloaded_function(template <...> void nonlinearDiffusion)
330
331 template <class SrcIterator, class SrcAccessor,
332 class DestIterator, class DestAccessor,
333 class DiffusivityFunc>
334 void nonlinearDiffusion(SrcIterator sul, SrcIterator slr, SrcAccessor as,
335 DestIterator dul, DestAccessor ad,
336 DiffusivityFunc const & weight, double scale)
337 {
338 vigra_precondition(scale > 0.0, "nonlinearDiffusion(): scale must be > 0");
339
340 double total_time = scale*scale/2.0;
341 const double time_step = 5.0;
342 int number_of_steps = (int)(total_time / time_step);
343 double rest_time = total_time - time_step * number_of_steps;
344
345 Size2D size(slr.x - sul.x, slr.y - sul.y);
346
347 typedef typename
348 NumericTraits<typename SrcAccessor::value_type>::RealPromote
349 TmpType;
350 typedef typename DiffusivityFunc::value_type WeightType;
351
352 BasicImage<TmpType> smooth1(size);
353 BasicImage<TmpType> smooth2(size);
354
355 BasicImage<WeightType> weights(size);
356
357 typename BasicImage<TmpType>::Iterator s1 = smooth1.upperLeft(),
358 s2 = smooth2.upperLeft();
359 typename BasicImage<TmpType>::Accessor a = smooth1.accessor();
360
361 typename BasicImage<WeightType>::Iterator wi = weights.upperLeft();
362 typename BasicImage<WeightType>::Accessor wa = weights.accessor();
363
364 gradientBasedTransform(sul, slr, as, wi, wa, weight);
365
366 internalNonlinearDiffusionAOSStep(sul, slr, as, wi, wa, s1, a, rest_time);
367
368 for(int i = 0; i < number_of_steps; ++i)
369 {
370 gradientBasedTransform(s1, s1+size, a, wi, wa, weight);
371
372 internalNonlinearDiffusionAOSStep(s1, s1+size, a, wi, wa, s2, a, time_step);
373
374 std::swap(s1, s2);
375 }
376
377 copyImage(s1, s1+size, a, dul, ad);
378 }
379
380 template <class SrcIterator, class SrcAccessor,
381 class DestIterator, class DestAccessor,
382 class DiffusivityFunc>
383 inline void
384 nonlinearDiffusion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
385 pair<DestIterator, DestAccessor> dest,
386 DiffusivityFunc const & weight, double scale)
387 {
388 nonlinearDiffusion(src.first, src.second, src.third,
389 dest.first, dest.second,
390 weight, scale);
391 }
392
393 template <class T1, class S1,
394 class T2, class S2,
395 class DiffusivityFunc>
396 inline void
397 nonlinearDiffusion(MultiArrayView<2, T1, S1> const & src,
398 MultiArrayView<2, T2, S2> dest,
399 DiffusivityFunc const & weight, double scale)
400 {
401 vigra_precondition(src.shape() == dest.shape(),
402 "nonlinearDiffusion(): shape mismatch between input and output.");
403 nonlinearDiffusion(srcImageRange(src),
404 destImage(dest),
405 weight, scale);
406 }
407
408 /********************************************************/
409
410 template <class SrcIterator, class SrcAccessor,
411 class WeightIterator, class WeightAccessor,
412 class DestIterator, class DestAccessor>
413 void internalNonlinearDiffusionExplicitStep(
414 SrcIterator sul, SrcIterator slr, SrcAccessor as,
415 WeightIterator wul, WeightAccessor aw,
416 DestIterator dul, DestAccessor ad,
417 double time_step)
418 {
419 // use traits to determine SumType as to prevent possible overflow
420 typedef typename
421 NumericTraits<typename SrcAccessor::value_type>::RealPromote
422 SumType;
423
424 typedef typename
425 NumericTraits<typename WeightAccessor::value_type>::RealPromote
426 WeightType;
427
428 // calculate width and height of the image
429 int w = slr.x - sul.x;
430 int h = slr.y - sul.y;
431
432 int x,y;
433
434 const Diff2D left(-1, 0);
435 const Diff2D right(1, 0);
436 const Diff2D top(0, -1);
437 const Diff2D bottom(0, 1);
438
439 WeightType gt, gb, gl, gr, g0;
440 WeightType one = NumericTraits<WeightType>::one();
441 SumType sum;
442
443 time_step /= 2.0;
444
445 // create y iterators
446 SrcIterator ys = sul;
447 WeightIterator yw = wul;
448 DestIterator yd = dul;
449
450 SrcIterator xs = ys;
451 WeightIterator xw = yw;
452 DestIterator xd = yd;
453
454 gt = (aw(xw) + aw(xw, bottom)) * time_step;
455 gb = (aw(xw) + aw(xw, bottom)) * time_step;
456 gl = (aw(xw) + aw(xw, right)) * time_step;
457 gr = (aw(xw) + aw(xw, right)) * time_step;
458 g0 = one - gt - gb - gr - gl;
459
460 sum = g0 * as(xs);
461 sum += gt * as(xs, bottom);
462 sum += gb * as(xs, bottom);
463 sum += gl * as(xs, right);
464 sum += gr * as(xs, right);
465
466 ad.set(sum, xd);
467
468 for(x=2, ++xs.x, ++xd.x, ++xw.x; x<w; ++x, ++xs.x, ++xd.x, ++xw.x)
469 {
470 gt = (aw(xw) + aw(xw, bottom)) * time_step;
471 gb = (aw(xw) + aw(xw, bottom)) * time_step;
472 gl = (aw(xw) + aw(xw, left)) * time_step;
473 gr = (aw(xw) + aw(xw, right)) * time_step;
474 g0 = one - gt - gb - gr - gl;
475
476 sum = g0 * as(xs);
477 sum += gt * as(xs, bottom);
478 sum += gb * as(xs, bottom);
479 sum += gl * as(xs, left);
480 sum += gr * as(xs, right);
481
482 ad.set(sum, xd);
483 }
484
485 gt = (aw(xw) + aw(xw, bottom)) * time_step;
486 gb = (aw(xw) + aw(xw, bottom)) * time_step;
487 gl = (aw(xw) + aw(xw, left)) * time_step;
488 gr = (aw(xw) + aw(xw, left)) * time_step;
489 g0 = one - gt - gb - gr - gl;
490
491 sum = g0 * as(xs);
492 sum += gt * as(xs, bottom);
493 sum += gb * as(xs, bottom);
494 sum += gl * as(xs, left);
495 sum += gr * as(xs, left);
496
497 ad.set(sum, xd);
498
499 for(y=2, ++ys.y, ++yd.y, ++yw.y; y<h; ++y, ++ys.y, ++yd.y, ++yw.y)
500 {
501 xs = ys;
502 xd = yd;
503 xw = yw;
504
505 gt = (aw(xw) + aw(xw, top)) * time_step;
506 gb = (aw(xw) + aw(xw, bottom)) * time_step;
507 gl = (aw(xw) + aw(xw, right)) * time_step;
508 gr = (aw(xw) + aw(xw, right)) * time_step;
509 g0 = one - gt - gb - gr - gl;
510
511 sum = g0 * as(xs);
512 sum += gt * as(xs, top);
513 sum += gb * as(xs, bottom);
514 sum += gl * as(xs, right);
515 sum += gr * as(xs, right);
516
517 ad.set(sum, xd);
518
519 for(x=2, ++xs.x, ++xd.x, ++xw.x; x<w; ++x, ++xs.x, ++xd.x, ++xw.x)
520 {
521 gt = (aw(xw) + aw(xw, top)) * time_step;
522 gb = (aw(xw) + aw(xw, bottom)) * time_step;
523 gl = (aw(xw) + aw(xw, left)) * time_step;
524 gr = (aw(xw) + aw(xw, right)) * time_step;
525 g0 = one - gt - gb - gr - gl;
526
527 sum = g0 * as(xs);
528 sum += gt * as(xs, top);
529 sum += gb * as(xs, bottom);
530 sum += gl * as(xs, left);
531 sum += gr * as(xs, right);
532
533 ad.set(sum, xd);
534 }
535
536 gt = (aw(xw) + aw(xw, top)) * time_step;
537 gb = (aw(xw) + aw(xw, bottom)) * time_step;
538 gl = (aw(xw) + aw(xw, left)) * time_step;
539 gr = (aw(xw) + aw(xw, left)) * time_step;
540 g0 = one - gt - gb - gr - gl;
541
542 sum = g0 * as(xs);
543 sum += gt * as(xs, top);
544 sum += gb * as(xs, bottom);
545 sum += gl * as(xs, left);
546 sum += gr * as(xs, left);
547
548 ad.set(sum, xd);
549 }
550
551 xs = ys;
552 xd = yd;
553 xw = yw;
554
555 gt = (aw(xw) + aw(xw, top)) * time_step;
556 gb = (aw(xw) + aw(xw, top)) * time_step;
557 gl = (aw(xw) + aw(xw, right)) * time_step;
558 gr = (aw(xw) + aw(xw, right)) * time_step;
559 g0 = one - gt - gb - gr - gl;
560
561 sum = g0 * as(xs);
562 sum += gt * as(xs, top);
563 sum += gb * as(xs, top);
564 sum += gl * as(xs, right);
565 sum += gr * as(xs, right);
566
567 ad.set(sum, xd);
568
569 for(x=2, ++xs.x, ++xd.x, ++xw.x; x<w; ++x, ++xs.x, ++xd.x, ++xw.x)
570 {
571 gt = (aw(xw) + aw(xw, top)) * time_step;
572 gb = (aw(xw) + aw(xw, top)) * time_step;
573 gl = (aw(xw) + aw(xw, left)) * time_step;
574 gr = (aw(xw) + aw(xw, right)) * time_step;
575 g0 = one - gt - gb - gr - gl;
576
577 sum = g0 * as(xs);
578 sum += gt * as(xs, top);
579 sum += gb * as(xs, top);
580 sum += gl * as(xs, left);
581 sum += gr * as(xs, right);
582
583 ad.set(sum, xd);
584 }
585
586 gt = (aw(xw) + aw(xw, top)) * time_step;
587 gb = (aw(xw) + aw(xw, top)) * time_step;
588 gl = (aw(xw) + aw(xw, left)) * time_step;
589 gr = (aw(xw) + aw(xw, left)) * time_step;
590 g0 = one - gt - gb - gr - gl;
591
592 sum = g0 * as(xs);
593 sum += gt * as(xs, top);
594 sum += gb * as(xs, top);
595 sum += gl * as(xs, left);
596 sum += gr * as(xs, left);
597
598 ad.set(sum, xd);
599 }
600
601 /** \brief Perform edge-preserving smoothing at the given scale using an explicit scheme.
602
603 See \ref nonlinearDiffusion().
604 */
605 doxygen_overloaded_function(template <...> void nonlinearDiffusionExplicit)
606
607 template <class SrcIterator, class SrcAccessor,
608 class DestIterator, class DestAccessor,
609 class DiffusivityFunc>
610 void nonlinearDiffusionExplicit(SrcIterator sul, SrcIterator slr, SrcAccessor as,
611 DestIterator dul, DestAccessor ad,
612 DiffusivityFunc const & weight, double scale)
613 {
614 vigra_precondition(scale > 0.0, "nonlinearDiffusionExplicit(): scale must be > 0");
615
616 double total_time = scale*scale/2.0;
617 const double time_step = 0.25;
618 int number_of_steps = total_time / time_step;
619 double rest_time = total_time - time_step * number_of_steps;
620
621 Size2D size(slr.x - sul.x, slr.y - sul.y);
622
623 typedef typename
624 NumericTraits<typename SrcAccessor::value_type>::RealPromote
625 TmpType;
626 typedef typename DiffusivityFunc::value_type WeightType;
627
628 BasicImage<TmpType> smooth1(size);
629 BasicImage<TmpType> smooth2(size);
630
631 BasicImage<WeightType> weights(size);
632
633 typename BasicImage<TmpType>::Iterator s1 = smooth1.upperLeft(),
634 s2 = smooth2.upperLeft();
635 typename BasicImage<TmpType>::Accessor a = smooth1.accessor();
636
637 typename BasicImage<WeightType>::Iterator wi = weights.upperLeft();
638 typename BasicImage<WeightType>::Accessor wa = weights.accessor();
639
640 gradientBasedTransform(sul, slr, as, wi, wa, weight);
641
642 internalNonlinearDiffusionExplicitStep(sul, slr, as, wi, wa, s1, a, rest_time);
643
644 for(int i = 0; i < number_of_steps; ++i)
645 {
646 gradientBasedTransform(s1, s1+size, a, wi, wa, weight);
647
648 internalNonlinearDiffusionExplicitStep(s1, s1+size, a, wi, wa, s2, a, time_step);
649
650 swap(s1, s2);
651 }
652
653 copyImage(s1, s1+size, a, dul, ad);
654 }
655
656 template <class SrcIterator, class SrcAccessor,
657 class DestIterator, class DestAccessor,
658 class DiffusivityFunc>
659 inline void
660 nonlinearDiffusionExplicit(triple<SrcIterator, SrcIterator, SrcAccessor> src,
661 pair<DestIterator, DestAccessor> dest,
662 DiffusivityFunc const & weight, double scale)
663 {
664 nonlinearDiffusionExplicit(src.first, src.second, src.third,
665 dest.first, dest.second,
666 weight, scale);
667 }
668
669 template <class T1, class S1,
670 class T2, class S2,
671 class DiffusivityFunc>
672 inline void
673 nonlinearDiffusionExplicit(MultiArrayView<2, T1, S1> const & src,
674 MultiArrayView<2, T2, S2> dest,
675 DiffusivityFunc const & weight, double scale)
676 {
677 vigra_precondition(src.shape() == dest.shape(),
678 "nonlinearDiffusionExplicit(): shape mismatch between input and output.");
679 nonlinearDiffusionExplicit(srcImageRange(src),
680 destImage(dest),
681 weight, scale);
682 }
683
684 /********************************************************/
685 /* */
686 /* DiffusivityFunctor */
687 /* */
688 /********************************************************/
689
690 /** \brief Diffusivity functor for non-linear diffusion.
691
692 This functor implements the diffusivity recommended by Weickert:
693
694 \f[
695 g(|\nabla u|) = 1 -
696 \exp{\left(\frac{-3.315}{(|\nabla u| / thresh)^4}\right)}
697 \f]
698
699
700 where <TT>thresh</TT> is a threshold that determines whether a specific gradient
701 magnitude is interpreted as a significant edge (above the threshold)
702 or as noise. It is meant to be used with \ref nonlinearDiffusion().
703 */
704 template <class Value>
705 class DiffusivityFunctor
706 {
707 public:
708 /** the functors first argument type (must be an algebraic field with <TT>exp()</TT> defined).
709 However, the functor also works with RGBValue<first_argument_type> (this hack is
710 necessary since Microsoft C++ doesn't support partial specialization).
711 */
712 typedef Value first_argument_type;
713
714 /** the functors second argument type (same as first).
715 However, the functor also works with RGBValue<second_argument_type> (this hack is
716 necessary since Microsoft C++ doesn't support partial specialization).
717 */
718 typedef Value second_argument_type;
719
720 /** the functors result type
721 */
722 typedef typename NumericTraits<Value>::RealPromote result_type;
723
724 /** \deprecated use first_argument_type, second_argument_type, result_type
725 */
726 typedef Value value_type;
727
728 /** init functor with given edge threshold
729 */
730 DiffusivityFunctor(Value const & thresh)
731 : weight_(thresh*thresh),
732 one_(NumericTraits<result_type>::one()),
733 zero_(NumericTraits<result_type>::zero())
734 {}
735
736 /** calculate diffusivity from scalar arguments
737 */
738 result_type operator()(first_argument_type const & gx, second_argument_type const & gy) const
739 {
740 Value mag = (gx*gx + gy*gy) / weight_;
741
742 return (mag == zero_) ? one_ : one_ - VIGRA_CSTD::exp(-3.315 / mag / mag);
743 }
744
745 /** calculate diffusivity from RGB arguments
746 */
747 result_type operator()(RGBValue<Value> const & gx, RGBValue<Value> const & gy) const
748 {
749 result_type mag = (gx.red()*gx.red() +
750 gx.green()*gx.green() +
751 gx.blue()*gx.blue() +
752 gy.red()*gy.red() +
753 gy.green()*gy.green() +
754 gy.blue()*gy.blue()) / weight_;
755
756 return (mag == zero_) ? one_ : one_ - VIGRA_CSTD::exp(-3.315 / mag / mag);
757 }
758
759 result_type weight_;
760 result_type one_;
761 result_type zero_;
762 };
763
764 template <class ValueType>
765 class FunctorTraits<DiffusivityFunctor<ValueType> >
766 : public FunctorTraitsBase<DiffusivityFunctor<ValueType> >
767 {
768 public:
769 typedef VigraTrueType isBinaryFunctor;
770 };
771
772
773 //@}
774
775 } // namespace vigra
776
777 #endif /* VIGRA_NONLINEARDIFFUSION_HXX */
vigra::nonlinearDiffusionExplicit
void nonlinearDiffusionExplicit(...)
Perform edge-preserving smoothing at the given scale using an explicit scheme.
vigra::DiffusivityFunctor::result_type
NumericTraits< Value >::RealPromote result_type
Definition: nonlineardiffusion.hxx:722
vigra::RGBValue::red
value_type & red()
Definition: rgbvalue.hxx:278
vigra::nonlinearDiffusion
void nonlinearDiffusion(...)
Perform edge-preserving smoothing at the given scale.
vigra
vigra::gradientBasedTransform
void gradientBasedTransform(...)
Calculate a function of the image gradient.
vigra::doxygen_overloaded_function
doxygen_overloaded_function(template<... > void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
vigra::sum
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition: tinyvector.hxx:2073
vigra::BasicImage::Iterator
BasicImageIterator< PIXELTYPE, PIXELTYPE ** > Iterator
Definition: basicimage.hxx:532
vigra::RGBValue::blue
value_type & blue()
Definition: rgbvalue.hxx:286
vigra::RGBValue::green
value_type & green()
Definition: rgbvalue.hxx:282
vigra::DiffusivityFunctor::operator()
result_type operator()(RGBValue< Value > const &gx, RGBValue< Value > const &gy) const
Definition: nonlineardiffusion.hxx:747
vigra::BasicImage::Accessor
IteratorTraits< traverser >::DefaultAccessor Accessor
Definition: basicimage.hxx:573
vigra::DiffusivityFunctor::operator()
result_type operator()(first_argument_type const &gx, second_argument_type const &gy) const
Definition: nonlineardiffusion.hxx:738
vigra::RGBValue
Class for a single RGB value.
Definition: accessor.hxx:938
vigra::copyImage
void copyImage(...)
Copy source image into destination image.
vigra::DiffusivityFunctor::first_argument_type
Value first_argument_type
Definition: nonlineardiffusion.hxx:712
vigra::DiffusivityFunctor::second_argument_type
Value second_argument_type
Definition: nonlineardiffusion.hxx:718
vigra::DiffusivityFunctor::value_type
Value value_type
Definition: nonlineardiffusion.hxx:726
vigra::DiffusivityFunctor
Diffusivity functor for non-linear diffusion.
Definition: nonlineardiffusion.hxx:705
vigra::DiffusivityFunctor::DiffusivityFunctor
DiffusivityFunctor(Value const &thresh)
Definition: nonlineardiffusion.hxx:730

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.11.1