36 #ifndef VIGRA_VECTOR_DISTANCE_HXX 
   37 #define VIGRA_VECTOR_DISTANCE_HXX 
   42 #include "array_vector.hxx" 
   43 #include "multi_array.hxx" 
   44 #include "accessor.hxx" 
   45 #include "numerictraits.hxx" 
   46 #include "navigator.hxx" 
   47 #include "metaprogramming.hxx" 
   48 #include "multi_pointoperators.hxx" 
   49 #include "functorexpression.hxx" 
   50 #include "multi_distance.hxx" 
   52 #undef VECTORIAL_DIST_DEBUG 
   60 template <
class Vector, 
class Value>
 
   61 struct VectorialDistParabolaStackEntry
 
   63     double left, center, right;
 
   67     VectorialDistParabolaStackEntry(
const Vector& vec, Value prev, 
double l, 
double c, 
double r)
 
   68     : left(l), center(c), right(r), apex_height(prev), point(vec)
 
   72 #ifdef VECTORIAL_DIST_DEBUG 
   73 template <
class Vector, 
class Value>
 
   74 std::ostream& operator<<(std::ostream&o, const VectorialDistParabolaStackEntry<Vector, Value>& e) {
 
   75     o << 
"l=" << e.left << 
", c=" << e.center << 
", r=" << e.right << 
", pV=" << e.apex_height << 
", pVec=" << e.point;
 
   86 template <
class VEC, 
class ARRAY>
 
   88 partialSquaredMagnitude(
const VEC& vec, 
MultiArrayIndex dim, ARRAY 
const & pixel_pitch)
 
   95         sqMag += 
sq(pixel_pitch[i]*vec[i]);
 
  100 template <
class SrcIterator,
 
  104                       SrcIterator is, SrcIterator iend,
 
  105                       Array 
const & pixel_pitch )
 
  107     typedef typename SrcIterator::value_type SrcType;
 
  108     typedef VectorialDistParabolaStackEntry<SrcType, double> Influence;
 
  110     double sigma = pixel_pitch[dimension],
 
  112     double w = iend - is; 
 
  116     std::vector<Influence> _stack; 
 
  117     double apex_height = partialSquaredMagnitude(*is, dimension, pixel_pitch);
 
  118     _stack.push_back(Influence(*is, apex_height, 0.0, 0.0, w));
 
  120     double current = 1.0;
 
  123         apex_height = partialSquaredMagnitude(*is, dimension, pixel_pitch);
 
  124         Influence & s = _stack.back();
 
  125         double diff = current - s.center;
 
  126         double intersection = current + (apex_height - s.apex_height - 
sq(sigma*diff)) / (2.0*sigma2 * diff);
 
  128         if( intersection < s.left) 
 
  132                 _stack.push_back(Influence(*is, apex_height, 0.0, current, w));
 
  136         else if(intersection < s.right)
 
  138             s.right = intersection;
 
  139             _stack.push_back(Influence(*is, apex_height, intersection, current, w));
 
  148     typename std::vector<Influence>::iterator it = _stack.begin();
 
  149     for(current = 0.0; current < w; ++current, ++id)
 
  151         while( current >= it->right)
 
  155         (*id)[dimension] = it->center - current;
 
  159 template <
class DestIterator,
 
  161           class Array1, 
class Array2>
 
  164                            DestIterator is, DestIterator iend,
 
  165                            LabelIterator ilabels,
 
  166                            Array1 
const & pixel_pitch,
 
  168                            bool array_border_is_active=
false)
 
  170     double w = iend - is;
 
  174     typedef typename LabelIterator::value_type LabelType;
 
  175     typedef typename DestIterator::value_type DestType;
 
  176     typedef VectorialDistParabolaStackEntry<DestType, double> Influence;
 
  177     typedef std::vector<Influence> Stack;
 
  179     DestIterator 
id = is;
 
  180     DestType border_point = array_border_is_active
 
  183     double apex_height = partialSquaredMagnitude(border_point, dimension, pixel_pitch);
 
  184     Stack _stack(1, Influence(border_point, apex_height, 0.0, -1.0, w));
 
  185     LabelType current_label = *ilabels;
 
  186     for(
double begin = 0.0, current = 0.0; current <= w; ++ilabels, ++is, ++current)
 
  188         DestType point = (current < w)
 
  189                              ? (current_label == *ilabels)
 
  193         apex_height = partialSquaredMagnitude(point, dimension, pixel_pitch);
 
  196             Influence & s = _stack.back();
 
  197             double diff = (current - s.center)*pixel_pitch[dimension];
 
  198             double intersection = current + (apex_height - s.apex_height - 
sq(diff)) / (2.0 * diff);
 
  200             if(intersection < s.left) 
 
  204                     intersection = begin; 
 
  208             else if(intersection < s.right)
 
  210                 s.right = intersection;
 
  213                 _stack.push_back(Influence(point, apex_height, intersection, current, w));
 
  214             if(current < w && current_label == *ilabels)
 
  218             typename Stack::iterator it = _stack.begin();
 
  219             for(
double c = begin; c < current; ++c, ++id)
 
  221                 while(c >= it->right)
 
  224                 (*id)[dimension] = it->center - c;
 
  231             current_label = *ilabels;
 
  233             apex_height = partialSquaredMagnitude(point, dimension, pixel_pitch);
 
  234             Stack(1, Influence(DestType(0), 0.0, begin-1.0, begin-1.0, w)).swap(_stack);
 
  241 template <
unsigned int N, 
class T1, 
class S1,
 
  245 interpixelBoundaryVectorDistance(MultiArrayView<N, T1, S1> 
const & labels,
 
  246                                  MultiArrayView<N, T2, S2> dest,
 
  247                                  Array 
const & pixelPitch)
 
  249     typedef typename MultiArrayShape<N>::type  Shape;
 
  250     typedef GridGraph<N>                       Graph;
 
  251     typedef typename Graph::Node               Node;
 
  252     typedef typename Graph::NodeIt             graph_scanner;
 
  253     typedef typename Graph::OutArcIt           neighbor_iterator;
 
  255     Graph g(labels.shape());
 
  256     for (graph_scanner node(g); node != lemon_graph::INVALID; ++node)
 
  258         T1 label = labels[*node];
 
  259         double min_dist = NumericTraits<double>::max();
 
  261              boundary = point + Node(dest[point]),
 
  262              min_pos  = lemon::INVALID;
 
  266         if(labels.isInside(boundary))
 
  268             for (neighbor_iterator arc(g, boundary); arc != lemon_graph::INVALID; ++arc)
 
  270                 if(label == labels[g.target(*arc)])
 
  272                     double dist = 
squaredNorm(pixelPitch*(g.target(*arc) - point));
 
  276                         min_pos = g.target(*arc);
 
  280             if(min_pos == lemon::INVALID)
 
  282             min_dist = NumericTraits<double>::max();
 
  286             min_pos = 
clip(boundary, Shape(0), labels.shape()-Shape(1));
 
  287             min_diff = 0.5*(boundary + min_pos) - point;
 
  292         for (neighbor_iterator arc(g, min_pos); arc != lemon_graph::INVALID; ++arc)
 
  294             if(label != labels[g.target(*arc)])
 
  296                 T2 diff = 0.5*(g.target(*arc) + min_pos) - point;
 
  305         dest[point] = min_diff;
 
  316 struct Error_output_pixel_type_must_be_TinyVector_of_appropriate_length
 
  317 : vigra::staticAssert::AssertBool<PRED> {};
 
  364 template <
unsigned int N, 
class T1, 
class S1,
 
  365           class T2, 
class S2, 
class Array>
 
  368                         MultiArrayView<N, T2, S2> dest,
 
  370                         Array 
const & pixelPitch)
 
  372     using namespace vigra::functor;
 
  373     typedef typename MultiArrayView<N, T2, S2>::traverser Traverser;
 
  374     typedef MultiArrayNavigator<Traverser, N> Navigator;
 
  376     VIGRA_STATIC_ASSERT((Error_output_pixel_type_must_be_TinyVector_of_appropriate_length<N == T2::static_size>));
 
  377     vigra_precondition(source.shape() == dest.shape(),
 
  378         "separableVectorDistance(): shape mismatch between input and output.");
 
  379     vigra_precondition(pixelPitch.size() == N,
 
  380         "separableVectorDistance(): pixelPitch has wrong length.");
 
  382     T2 maxDist(2*
sum(source.shape()*pixelPitch)), rzero;
 
  383     if(background == 
true)
 
  385                                 ifThenElse( Arg1() == Param(0), Param(maxDist), Param(rzero) ));
 
  388                                 ifThenElse( Arg1() != Param(0), Param(maxDist), Param(rzero) ));
 
  390     for(
unsigned d = 0; d < N; ++d )
 
  392         Navigator nav( dest.traverser_begin(), dest.shape(), d);
 
  393         for( ; nav.hasMore(); nav++ )
 
  395              detail::vectorialDistParabola(d, nav.begin(), nav.end(), pixelPitch);
 
  400 template <
unsigned int N, 
class T1, 
class S1,
 
  404                         MultiArrayView<N, T2, S2> dest,
 
  405                         bool background=
true)
 
  407     TinyVector<double, N> pixelPitch(1.0);
 
  457 template <
unsigned int N, 
class T1, 
class S1,
 
  462                        MultiArrayView<N, T2, S2> dest,
 
  463                        bool array_border_is_active,
 
  465                        Array 
const & pixelPitch)
 
  467     VIGRA_STATIC_ASSERT((Error_output_pixel_type_must_be_TinyVector_of_appropriate_length<N == T2::static_size>));
 
  468     vigra_precondition(labels.shape() == dest.shape(),
 
  469         "boundaryVectorDistance(): shape mismatch between input and output.");
 
  470     vigra_precondition(pixelPitch.size() == N,
 
  471         "boundaryVectorDistance(): pixelPitch has wrong length.");
 
  473     using namespace vigra::functor;
 
  477         MultiArray<N, unsigned char> boundaries(labels.shape());
 
  480         if(array_border_is_active)
 
  488             vigra_precondition(!NumericTraits<T2>::isIntegral::value,
 
  489                 "boundaryVectorDistance(..., InterpixelBoundary): output pixel type must be float or double.");
 
  492         typedef typename MultiArrayView<N, T1, S1>::const_traverser LabelIterator;
 
  493         typedef typename MultiArrayView<N, T2, S2>::traverser DestIterator;
 
  494         typedef MultiArrayNavigator<LabelIterator, N> LabelNavigator;
 
  495         typedef MultiArrayNavigator<DestIterator, N> DNavigator;
 
  497         T2 maxDist(2*
sum(labels.shape()*pixelPitch));
 
  499         for( 
unsigned d = 0; d < N; ++d )
 
  501             LabelNavigator lnav( labels.traverser_begin(), labels.shape(), d );
 
  502             DNavigator dnav( dest.traverser_begin(), dest.shape(), d );
 
  504             for( ; dnav.hasMore(); dnav++, lnav++ )
 
  506                 detail::boundaryVectorDistParabola(d, dnav.begin(), dnav.end(), lnav.begin(),
 
  507                                                    pixelPitch, maxDist, array_border_is_active);
 
  513            detail::interpixelBoundaryVectorDistance(labels, dest, pixelPitch);
 
  518 template <
unsigned int N, 
class T1, 
class S1,
 
  522                        MultiArrayView<N, T2, S2> dest,
 
  523                        bool array_border_is_active=
false,
 
  526     TinyVector<double, N> pixelPitch(1.0);
 
  534 #endif        //-- VIGRA_VECTOR_DISTANCE_HXX 
void initMultiArrayBorder(...)
Write values to the specified border values in the array. 
FFTWComplex< R >::SquaredNormType squaredNorm(const FFTWComplex< R > &a)
squared norm (= squared magnitude) 
Definition: fftw3.hxx:1044
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
TinyVector< V, SIZE > clip(TinyVector< V, SIZE > const &t, const V valLower, const V valUpper)
Clip values to an interval. 
Definition: tinyvector.hxx:2307
NumericTraits< T >::Promote sq(T t)
The square function. 
Definition: mathutil.hxx:382
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements 
Definition: tinyvector.hxx:2073
vigra::GridGraph< N, DirectedTag >::vertex_descriptor source(typename vigra::GridGraph< N, DirectedTag >::edge_descriptor const &e, vigra::GridGraph< N, DirectedTag > const &g)
Get a vertex descriptor for the start vertex of edge e in graph g (API: boost). 
Definition: multi_gridgraph.hxx:2943
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays. 
use direct and indirect neighbors 
Definition: multi_fwd.hxx:188
void transformMultiArray(...)
Transform a multi-dimensional array with a unary function or functor.