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.