36 #ifndef VIGRA_ORIENTEDTENSORFILTERS_HXX
37 #define VIGRA_ORIENTEDTENSORFILTERS_HXX
41 #include "initimage.hxx"
42 #include "stdconvolution.hxx"
43 #include "multi_shape.hxx"
154 template <
class SrcIterator,
class SrcAccessor,
155 class DestIterator,
class DestAccessor>
156 void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
157 DestIterator dul, DestAccessor dest,
158 double sigma,
double rho)
160 vigra_precondition(sigma >= 0.0 && rho >= 0.0,
161 "hourGlassFilter(): sigma and rho must be >= 0.0");
162 vigra_precondition(src.size(sul) == 3,
163 "hourGlassFilter(): input image must have 3 bands.");
164 vigra_precondition(dest.size(dul) == 3,
165 "hourGlassFilter(): output image must have 3 bands.");
169 int w = slr.x - sul.x;
170 int h = slr.y - sul.y;
173 double sigma2 = -0.5 / sigma / sigma;
174 double rho2 = -0.5 / rho / rho;
175 double norm = 1.0 / (2.0 * M_PI * sigma * sigma);
177 initImage(dul, dul+Diff2D(w,h), dest, NumericTraits<typename DestAccessor::value_type>::zero());
179 for(
int y=0; y<h; ++y, ++sul.y, ++dul.y)
182 DestIterator d = dul;
183 for(
int x=0; x<w; ++x, ++s.x, ++d.x)
186 2.0*src.getComponent(s,1),
187 (double)src.getComponent(s,0) - src.getComponent(s,2));
191 double x0 = x - radius < 0 ? -x : -radius;
192 double y0 = y - radius < 0 ? -y : -radius;
193 double x1 = x + radius >= w ? w - x - 1 : radius;
194 double y1 = y + radius >= h ? h - y - 1 : radius;
196 DestIterator dwul = d + Diff2D((
int)x0, (
int)y0);
198 for(
double yy=y0; yy <= y1; ++yy, ++dwul.y)
200 typename DestIterator::row_iterator dw = dwul.rowIterator();
201 for(
double xx=x0; xx <= x1; ++xx, ++dw)
203 double r2 = xx*xx + yy*yy;
204 double p = u*xx - v*yy;
205 double q = v*xx + u*yy;
206 double kernel = (p == 0.0) ?
211 dest.set(dest(dw) + kernel*src(s), dw);
218 template <
class SrcIterator,
class SrcAccessor,
219 class DestIterator,
class DestAccessor>
222 pair<DestIterator, DestAccessor> d,
223 double sigma,
double rho)
225 hourGlassFilter(s.first, s.second, s.third, d.first, d.second, sigma, rho);
228 template <
class T1,
class S1,
232 MultiArrayView<2, T2, S2> dest,
233 double sigma,
double rho)
235 vigra_precondition(src.shape() == dest.shape(),
236 "hourGlassFilter(): shape mismatch between input and output.");
246 template <
class SrcIterator,
class SrcAccessor,
247 class DestIterator,
class DestAccessor>
248 void ellipticGaussian(SrcIterator sul, SrcIterator slr, SrcAccessor src,
249 DestIterator dul, DestAccessor dest,
250 double sigmax,
double sigmin)
252 vigra_precondition(sigmax >= sigmin && sigmin >= 0.0,
253 "ellipticGaussian(): "
254 "sigmax >= sigmin and sigmin >= 0.0 required");
256 int w = slr.x - sul.x;
257 int h = slr.y - sul.y;
260 double sigmin2 = -0.5 / sigmin / sigmin;
261 double norm = 1.0 / (2.0 * M_PI * sigmin * sigmax);
263 initImage(dul, dul+Diff2D(w,h), dest, NumericTraits<typename DestAccessor::value_type>::zero());
265 for(
int y=0; y<h; ++y, ++sul.y, ++dul.y)
268 DestIterator d = dul;
269 for(
int x=0; x<w; ++x, ++s.x, ++d.x)
272 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
273 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
274 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
275 TmpType d3 = 2.0 * src.getComponent(s,1);
277 TmpType excentricity = 1.0 - (d1 - d4) / (d1 + d4);
278 double sigmax2 = -0.5 /
sq((sigmax - sigmin)*excentricity + sigmin);
284 double x0 = x - radius < 0 ? -x : -radius;
285 double y0 = y - radius < 0 ? -y : -radius;
286 double x1 = x + radius >= w ? w - x - 1 : radius;
287 double y1 = y + radius >= h ? h - y - 1 : radius;
289 DestIterator dwul = d + Diff2D((
int)x0, (
int)y0);
291 for(
double yy=y0; yy <= y1; ++yy, ++dwul.y)
293 typename DestIterator::row_iterator dw = dwul.rowIterator();
294 for(
double xx=x0; xx <= x1; ++xx, ++dw)
296 double p = u*xx - v*yy;
297 double q = v*xx + u*yy;
299 dest.set(dest(dw) + kernel*src(s), dw);
306 template <
class SrcIterator,
class SrcAccessor,
307 class DestIterator,
class DestAccessor>
309 ellipticGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
310 pair<DestIterator, DestAccessor> dest,
311 double sigmax,
double sigmin)
313 ellipticGaussian(src.first, src.second, src.third, dest.first, dest.second, sigmax, sigmin);
316 template <
class T1,
class S1,
319 ellipticGaussian(MultiArrayView<2, T1, S1>
const & src,
320 MultiArrayView<2, T2, S2> dest,
321 double sigmax,
double sigmin)
323 vigra_precondition(src.shape() == dest.shape(),
324 "ellipticGaussian(): shape mismatch between input and output.");
325 ellipticGaussian(srcImageRange(src), destImage(dest), sigmax, sigmin);
334 class FoerstnerKernelBase
337 typedef double ResultType;
338 typedef double WeightType;
340 typedef VectorType::value_type ValueType;
342 FoerstnerKernelBase(
double scale,
bool ringShaped =
false)
343 : radius_((int)(3.0*scale+0.5)),
344 weights_(2*radius_+1, 2*radius_+1),
345 vectors_(2*radius_+1, 2*radius_+1)
347 double norm = 1.0 / (2.0 * M_PI * scale * scale);
348 double s2 = -0.5 / scale / scale;
350 for(
int y = -radius_; y <= radius_; ++y)
352 for(
int x = -radius_; x <= radius_; ++x)
354 double d2 = x*x + y*y;
356 vectors_(x+radius_,y+radius_) = d != 0.0 ?
357 VectorType(x/d, -y/d) :
358 VectorType(ValueType(0), ValueType(0));
359 weights_(x+radius_,y+radius_) = ringShaped ?
361 norm * VIGRA_CSTD::
exp(d2 * s2);
366 ResultType operator()(
int ,
int , VectorType
const &)
const
369 return weights_(radius_, radius_);
377 class FoerstnerRingKernelBase
378 :
public FoerstnerKernelBase
381 FoerstnerRingKernelBase(
double scale)
382 : FoerstnerKernelBase(scale, true)
387 :
public FoerstnerKernelBase
390 typedef double ResultType;
391 typedef double WeightType;
394 Cos2RingKernel(
double scale)
395 : FoerstnerKernelBase(scale, true)
398 ResultType operator()(
int x,
int y, VectorType
const & v)
const
401 return weights_(radius_, radius_);
402 double d =
dot(vectors_(x+radius_, y+radius_), v);
403 return d * d * weights_(x+radius_, y+radius_);
408 :
public FoerstnerKernelBase
411 typedef double ResultType;
412 typedef double WeightType;
415 Cos2Kernel(
double scale)
416 : FoerstnerKernelBase(scale, false)
419 ResultType operator()(
int x,
int y, VectorType
const & v)
const
422 return weights_(radius_, radius_);
423 double d =
dot(vectors_(x+radius_, y+radius_), v);
424 return d * d * weights_(x+radius_, y+radius_);
429 :
public FoerstnerKernelBase
432 typedef double ResultType;
433 typedef double WeightType;
436 Sin2RingKernel(
double scale)
437 : FoerstnerKernelBase(scale, true)
440 ResultType operator()(
int x,
int y, VectorType
const & v)
const
443 return weights_(radius_, radius_);
444 double d =
dot(vectors_(x+radius_, y+radius_), v);
445 return (1.0 - d * d) * weights_(x+radius_, y+radius_);
450 :
public FoerstnerKernelBase
453 typedef double ResultType;
454 typedef double WeightType;
457 Sin2Kernel(
double scale)
458 : FoerstnerKernelBase(scale, false)
461 ResultType operator()(
int x,
int y, VectorType
const & v)
const
464 return weights_(radius_, radius_);
465 double d =
dot(vectors_(x+radius_, y+radius_), v);
466 return (1.0 - d * d) * weights_(x+radius_, y+radius_);
471 :
public FoerstnerKernelBase
474 typedef double ResultType;
475 typedef double WeightType;
478 Sin6RingKernel(
double scale)
479 : FoerstnerKernelBase(scale, true)
482 ResultType operator()(
int x,
int y, VectorType
const & v)
const
485 return weights_(radius_, radius_);
486 double d =
dot(vectors_(x+radius_, y+radius_), v);
487 return VIGRA_CSTD::pow(1.0 - d * d, 3) * weights_(x+radius_, y+radius_);
492 :
public FoerstnerKernelBase
495 typedef double ResultType;
496 typedef double WeightType;
499 Sin6Kernel(
double scale)
500 : FoerstnerKernelBase(scale, false)
503 ResultType operator()(
int x,
int y, VectorType
const & v)
const
506 return weights_(radius_, radius_);
507 double d =
dot(vectors_(x+radius_, y+radius_), v);
508 return VIGRA_CSTD::pow(1.0 - d * d, 3) * weights_(x+radius_, y+radius_);
513 :
public FoerstnerKernelBase
516 typedef double ResultType;
517 typedef double WeightType;
520 Cos6RingKernel(
double scale)
521 : FoerstnerKernelBase(scale, true)
524 ResultType operator()(
int x,
int y, VectorType
const & v)
const
527 return weights_(radius_, radius_);
528 double d =
dot(vectors_(x+radius_, y+radius_), v);
529 return (1.0 - VIGRA_CSTD::pow(1.0 - d * d, 3)) * weights_(x+radius_, y+radius_);
534 :
public FoerstnerKernelBase
537 typedef double ResultType;
538 typedef double WeightType;
541 Cos6Kernel(
double scale)
542 : FoerstnerKernelBase(scale, false)
545 ResultType operator()(
int x,
int y, VectorType
const & v)
const
548 return weights_(radius_, radius_);
549 double d =
dot(vectors_(x+radius_, y+radius_), v);
550 return (1.0 - VIGRA_CSTD::pow(1.0 - d * d, 3)) * weights_(x+radius_, y+radius_);
560 template <
class SrcIterator,
class SrcAccessor,
561 class DestIterator,
class DestAccessor,
563 void orientedTrigonometricFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
564 DestIterator dul, DestAccessor dest,
565 Kernel
const & kernel)
567 vigra_precondition(src.size(sul) == 2,
568 "orientedTrigonometricFilter(): input image must have 2 bands.");
569 vigra_precondition(dest.size(dul) == 3,
570 "orientedTrigonometricFilter(): output image must have 3 bands.");
572 int w = slr.x - sul.x;
573 int h = slr.y - sul.y;
574 int radius = kernel.radius_;
576 typedef typename SrcAccessor::value_type VectorType;
577 typedef typename DestAccessor::value_type TensorType;
579 initImage(dul, dul+Diff2D(w,h), dest, NumericTraits<TensorType>::zero());
581 for(
int y=0; y<h; ++y, ++sul.y, ++dul.y)
584 DestIterator d = dul;
585 for(
int x=0; x<w; ++x, ++s.x, ++d.x)
587 int x0 = x - radius < 0 ? -x : -radius;
588 int y0 = y - radius < 0 ? -y : -radius;
589 int x1 = x + radius >= w ? w - x - 1 : radius;
590 int y1 = y + radius >= h ? h - y - 1 : radius;
592 VectorType v(src(s));
593 TensorType t(
sq(v[0]), v[0]*v[1],
sq(v[1]));
594 double sqMag = t[0] + t[2];
601 for(dd.y = y0; dd.y <= y1; ++dd.y)
603 for(dd.x = x0; dd.x <= x1; ++dd.x)
605 dest.set(dest(d, dd) + kernel(dd.x, dd.y, v) * t, d, dd);
612 template <
class SrcIterator,
class SrcAccessor,
613 class DestIterator,
class DestAccessor,
616 orientedTrigonometricFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
617 pair<DestIterator, DestAccessor> dest,
618 Kernel
const & kernel)
620 orientedTrigonometricFilter(src.first, src.second, src.third, dest.first, dest.second, kernel);
623 template <
class T1,
class S1,
627 orientedTrigonometricFilter(MultiArrayView<2, T1, S1>
const & src,
628 MultiArrayView<2, T2, S2> dest,
629 Kernel
const & kernel)
631 vigra_precondition(src.shape() == dest.shape(),
632 "orientedTrigonometricFilter(): shape mismatch between input and output.");
633 orientedTrigonometricFilter(srcImageRange(src), destImage(dest), kernel);
FixedPoint16< 2, OverflowHandling > atan2(FixedPoint16< IntBits, OverflowHandling > y, FixedPoint16< IntBits, OverflowHandling > x)
Arctangent. Accuracy better than 1/3 degree (9 significant bits).
Definition: fixedpoint.hxx:1654
PromoteTraits< V1, V2 >::Promote dot(RGBValue< V1, RIDX1, GIDX1, BIDX1 > const &r1, RGBValue< V2, RIDX2, GIDX2, BIDX2 > const &r2)
dot product
Definition: rgbvalue.hxx:906
void initImage(...)
Write a value to every pixel in an image or rectangular ROI.
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
linalg::TemporaryMatrix< T > exp(MultiArrayView< 2, T, C > const &v)
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
NumericTraits< T >::Promote sq(T t)
The square function.
Definition: mathutil.hxx:382
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void hourGlassFilter(...)
Anisotropic tensor smoothing with the hourglass filter.
linalg::TemporaryMatrix< T > cos(MultiArrayView< 2, T, C > const &v)
BasicImage< double > DImage
Definition: stdimage.hxx:153
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
TinyVector< double, 2 > value_type
Definition: basicimage.hxx:481
BasicImage< TinyVector< double, 2 > > DVector2Image
Definition: stdimage.hxx:306