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