accessor.hxx   accessor.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_ACCESSOR_HXX #define VIGRA_ACCESSOR_HXX
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "tuple.hxx" #include "tuple.hxx"
namespace vigra { namespace vigra {
/** \addtogroup DataAccessors Data Accessors /** \addtogroup DataAccessors Data Accessors
Basic templates to encapsulate access to the data of an iterator. Basic templates to encapsulate access to the data of an iterator.
Data accessors are used to allow for flexible access to the data
an iterator points to. When we access the data directly, we
are bound to what <TT>operator*()</TT> returns, if this method exists at
all. Encapsulating access in an accessor enables a better
decoupling of data structures and algorithms.
<a href="http://hci.iwr.uni-heidelberg.de/vigra/documents/DataAccessors.ps"
>This paper</a> contains
a detailed description of the concept. Here is a brief list of the basic
accessor requirements:
Data accessors are used to allow for flexible access to the data
an iterator points to. When we access the data directly, we
are bound to what <TT>operator*()</TT> returns, if this method exists a
t
all. Encapsulating access in an accessor enables a better
decoupling of data structures and algorithms.
<a href="http://hci.iwr.uni-heidelberg.de/vigra/documents/DataAccessors
.ps">This paper</a> contains
a detailed description of the concept. Here is a brief list of the basi
c
accessor requirements:
<p> <p>
<table border=2 cellspacing=0 cellpadding=2 width="100%"> <table border=2 cellspacing=0 cellpadding=2 width="100%">
<tr><th> <tr><th>
Operation Operation
</th><th> </th><th>
Result Result
</th><th> </th><th>
Semantics Semantics
</th> </th>
</tr> </tr>
skipping to change at line 98 skipping to change at line 99
</tr> </tr>
<tr><td colspan=3> <tr><td colspan=3>
<tt>iter</tt> is an iterator<br> <tt>iter</tt> is an iterator<br>
<tt>index</tt> has the iterator's index type (<tt>Iterator::differe nce_type</tt>)<br> <tt>index</tt> has the iterator's index type (<tt>Iterator::differe nce_type</tt>)<br>
<tt>value</tt> is convertible to <tt>Accessor::value_type const &</ tt> <tt>value</tt> is convertible to <tt>Accessor::value_type const &</ tt>
</td> </td>
</tr> </tr>
</table> </table>
</p> </p>
The template <tt>AccessorTraits<T></tt> can be used to find the default The template <tt>AccessorTraits<T></tt> can be used to find the default acc
accessor essor
associated with the type <tt>T</tt>, e.g. associated with the type <tt>T</tt>, e.g.
\code \code
typedef typename AccessorTraits<typename Image::value_type>::default_ac typedef typename AccessorTraits<typename Image::value_type>::default_access
cessor Accessor; or Accessor;
typedef typename AccessorTraits<typename Image::value_type>::default_co typedef typename AccessorTraits<typename Image::value_type>::default_const_
nst_accessor ConstAccessor; accessor ConstAccessor;
\endcode \endcode
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* StandardAccessor */ /* StandardAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Encapsulate access to the values an iterator points to. /** \brief Encapsulate access to the values an iterator points to.
skipping to change at line 148 skipping to change at line 149
/** read the current data item /** read the current data item
*/ */
template <class ITERATOR> template <class ITERATOR>
VALUETYPE const & operator()(ITERATOR const & i) const { return *i; } VALUETYPE const & operator()(ITERATOR const & i) const { return *i; }
VALUETYPE const & operator()(VALUETYPE const * i) const { return *i; } VALUETYPE const & operator()(VALUETYPE const * i) const { return *i; }
/** read the data item at an offset (can be 1D or 2D or higher orde r difference). /** read the data item at an offset (can be 1D or 2D or higher orde r difference).
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
VALUETYPE const & operator()(ITERATOR const & i, DIFFERENCE const & dif VALUETYPE const & operator()(ITERATOR const & i, OFFSET const & diff) c
f) const onst
{ {
return i[diff]; return i[diff];
} }
/** Write the current data item. The type <TT>V</TT> of the passed /** Write the current data item. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>. in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V const & value, ITERATOR const & i) const void set(V const & value, ITERATOR const & i) const
skipping to change at line 172 skipping to change at line 173
/* This overload is needed to make the accessor work with a std::ba ck_inserter */ /* This overload is needed to make the accessor work with a std::ba ck_inserter */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V const & value, ITERATOR & i) const void set(V const & value, ITERATOR & i) const
{ *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); } { *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); }
/** Write the data item at an offset (can be 1D or 2D or higher ord er difference).. /** Write the data item at an offset (can be 1D or 2D or higher ord er difference)..
The type <TT>V</TT> of the passed The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>. in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR, class DIFFERENCE> template <class V, class ITERATOR, class OFFSET>
void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) void set(V const & value, ITERATOR const & i, OFFSET const & diff) cons
const t
{ {
i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value); i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value);
} }
}; };
/** \brief Encapsulate access to the values an iterator points to. /** \brief Encapsulate access to the values an iterator points to.
StandardValueAccessor is a trivial accessor that simply encapsulates StandardValueAccessor is a trivial accessor that simply encapsulates
the iterator's operator*() and operator[]() in its the iterator's operator*() and operator[]() in its
read and write functions. It passes its arguments <em>by value</em>. read and write functions. It passes its arguments <em>by value</em>.
skipping to change at line 217 skipping to change at line 218
*/ */
template <class ITERATOR> template <class ITERATOR>
VALUETYPE operator()(ITERATOR const & i) const VALUETYPE operator()(ITERATOR const & i) const
{ return detail::RequiresExplicitCast<VALUETYPE>::cast(*i); } { return detail::RequiresExplicitCast<VALUETYPE>::cast(*i); }
/** Read the data item at an offset (can be 1D or 2D or higher orde r difference). /** Read the data item at an offset (can be 1D or 2D or higher orde r difference).
The type <TT>ITERATOR::index_reference</TT> The type <TT>ITERATOR::index_reference</TT>
is automatically converted to <TT>VALUETYPE</TT>. is automatically converted to <TT>VALUETYPE</TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const VALUETYPE operator()(ITERATOR const & i, OFFSET const & diff) const
{ {
return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]); return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]);
} }
/** Write the current data item. The type <TT>V</TT> of the passed /** Write the current data item. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>. in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V value, ITERATOR const & i) const void set(V value, ITERATOR const & i) const
{ *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); } { *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); }
skipping to change at line 240 skipping to change at line 241
/* This overload is needed to make the accessor work with a std::ba ck_inserter */ /* This overload is needed to make the accessor work with a std::ba ck_inserter */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V value, ITERATOR & i) const void set(V value, ITERATOR & i) const
{ *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); } { *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); }
/** Write the data item at an offset (can be 1D or 2D or higher ord er difference).. /** Write the data item at an offset (can be 1D or 2D or higher ord er difference)..
The type <TT>V</TT> of the passed The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>. in <TT>value</TT> is automatically converted to <TT>VALUETYPE</ TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR, class DIFFERENCE> template <class V, class ITERATOR, class OFFSET>
void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V value, ITERATOR const & i, OFFSET const & diff) const
{ {
i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value); i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value);
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* StandardConstAccessor */ /* StandardConstAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 281 skipping to change at line 282
typedef VALUETYPE value_type; typedef VALUETYPE value_type;
/** read the current data item /** read the current data item
*/ */
template <class ITERATOR> template <class ITERATOR>
VALUETYPE const & operator()(ITERATOR const & i) const VALUETYPE const & operator()(ITERATOR const & i) const
{ return *i; } { return *i; }
/** read the data item at an offset (can be 1D or 2D or higher orde r difference). /** read the data item at an offset (can be 1D or 2D or higher orde r difference).
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
VALUETYPE const & operator()(ITERATOR const & i, DIFFERENCE const & dif VALUETYPE const & operator()(ITERATOR const & i, OFFSET const & diff) c
f) const onst
{ {
return i[diff]; return i[diff];
} }
}; };
/** \brief Encapsulate access to the values an iterator points to. /** \brief Encapsulate access to the values an iterator points to.
StandardConstValueAccessor is a trivial accessor that simply encapsulat es StandardConstValueAccessor is a trivial accessor that simply encapsulat es
the iterator's operator*() and operator[]() in its the iterator's operator*() and operator[]() in its
read functions. It passes its arguments <em>by value</em>. read functions. It passes its arguments <em>by value</em>.
skipping to change at line 324 skipping to change at line 325
*/ */
template <class ITERATOR> template <class ITERATOR>
VALUETYPE operator()(ITERATOR const & i) const VALUETYPE operator()(ITERATOR const & i) const
{ return detail::RequiresExplicitCast<VALUETYPE>::cast(*i); } { return detail::RequiresExplicitCast<VALUETYPE>::cast(*i); }
/** Read the data item at an offset (can be 1D or 2D or higher orde r difference). /** Read the data item at an offset (can be 1D or 2D or higher orde r difference).
The type <TT>ITERATOR::index_reference</TT> The type <TT>ITERATOR::index_reference</TT>
is automatically converted to <TT>VALUETYPE</TT>. is automatically converted to <TT>VALUETYPE</TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const VALUETYPE operator()(ITERATOR const & i, OFFSET const & diff) const
{ {
return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]); return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]);
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* VectorComponentAccessor */ /* VectorComponentAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 386 skipping to change at line 387
{} {}
/** read the current data item /** read the current data item
*/ */
template <class ITERATOR> template <class ITERATOR>
value_type const & operator()(ITERATOR const & i) const value_type const & operator()(ITERATOR const & i) const
{ return (*i)[index_]; } { return (*i)[index_]; }
/** read the data item at an offset (can be 1D or 2D or higher orde r difference). /** read the data item at an offset (can be 1D or 2D or higher orde r difference).
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
value_type const & operator()(ITERATOR const & i, DIFFERENCE const & di value_type const & operator()(ITERATOR const & i, OFFSET const & diff)
ff) const const
{ {
return i[diff][index_]; return i[diff][index_];
} }
/** Write the current data item. The type <TT>V</TT> of the passed /** Write the current data item. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>value_type< /TT>. in <TT>value</TT> is automatically converted to <TT>value_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V const & value, ITERATOR const & i) const void set(V const & value, ITERATOR const & i) const
{ {
(*i)[index_] = detail::RequiresExplicitCast<value_type>::cast(value ); (*i)[index_] = detail::RequiresExplicitCast<value_type>::cast(value );
} }
/** Write the data item at an offset (can be 1D or 2D or higher ord er difference).. /** Write the data item at an offset (can be 1D or 2D or higher ord er difference)..
The type <TT>V</TT> of the passed The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>value_type< /TT>. in <TT>value</TT> is automatically converted to <TT>value_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR, class DIFFERENCE> template <class V, class ITERATOR, class OFFSET>
void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) void set(V const & value, ITERATOR const & i, OFFSET const & diff) cons
const t
{ {
i[diff][index_]= detail::RequiresExplicitCast<value_type>::cast(val ue); i[diff][index_]= detail::RequiresExplicitCast<value_type>::cast(val ue);
} }
/** Reset the index to the given number. /** Reset the index to the given number.
*/ */
void setIndex(int i) void setIndex(int i)
{ {
index_ = i; index_ = i;
} }
skipping to change at line 476 skipping to change at line 477
*/ */
template <class ITERATOR> template <class ITERATOR>
value_type operator()(ITERATOR const & i) const value_type operator()(ITERATOR const & i) const
{ return detail::RequiresExplicitCast<value_type>::cast((*i)[index_ ]); } { return detail::RequiresExplicitCast<value_type>::cast((*i)[index_ ]); }
/** Read the data item at an offset (can be 1D or 2D or higher orde r difference). /** Read the data item at an offset (can be 1D or 2D or higher orde r difference).
The type <TT>ITERATOR::index_reference::value_type</TT> The type <TT>ITERATOR::index_reference::value_type</TT>
is automatically converted to <TT>value_type</TT>. is automatically converted to <TT>value_type</TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
value_type operator()(ITERATOR const & i, DIFFERENCE const & diff) cons value_type operator()(ITERATOR const & i, OFFSET const & diff) const
t
{ {
return detail::RequiresExplicitCast<value_type>::cast(i[diff][index _]); return detail::RequiresExplicitCast<value_type>::cast(i[diff][index _]);
} }
/** Write the current data item. The type <TT>V</TT> of the passed /** Write the current data item. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>value_type< /TT>. in <TT>value</TT> is automatically converted to <TT>value_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V value, ITERATOR const & i) const void set(V value, ITERATOR const & i) const
{ {
(*i)[index_] = detail::RequiresExplicitCast<value_type>::cast(value ); (*i)[index_] = detail::RequiresExplicitCast<value_type>::cast(value );
} }
/** Write the data item at an offset (can be 1D or 2D or higher ord er difference).. /** Write the data item at an offset (can be 1D or 2D or higher ord er difference)..
The type <TT>V</TT> of the passed The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>value_type< /TT>. in <TT>value</TT> is automatically converted to <TT>value_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR, class DIFFERENCE> template <class V, class ITERATOR, class OFFSET>
void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V value, ITERATOR const & i, OFFSET const & diff) const
{ {
i[diff][index_]= detail::RequiresExplicitCast<value_type>::cast(val ue); i[diff][index_]= detail::RequiresExplicitCast<value_type>::cast(val ue);
} }
/** Reset the index to the given number. /** Reset the index to the given number.
*/ */
void setIndex(int i) void setIndex(int i)
{ {
index_ = i; index_ = i;
} }
skipping to change at line 562 skipping to change at line 563
{} {}
/** read the current data item /** read the current data item
*/ */
template <class ITERATOR> template <class ITERATOR>
value_type const & operator()(ITERATOR const & i) const value_type const & operator()(ITERATOR const & i) const
{ return a_.getComponent(i, index_); } { return a_.getComponent(i, index_); }
/** read the data item at an offset (can be 1D or 2D or higher orde r difference). /** read the data item at an offset (can be 1D or 2D or higher orde r difference).
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
value_type const & operator()(ITERATOR const & i, DIFFERENCE const & di value_type const & operator()(ITERATOR const & i, OFFSET const & diff)
ff) const const
{ {
return a_.getComponent(i, diff, index_); return a_.getComponent(i, diff, index_);
} }
/** Write the current data item. The type <TT>V</TT> of the passed /** Write the current data item. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>value_type< /TT>. in <TT>value</TT> is automatically converted to <TT>value_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void set(V const & value, ITERATOR const & i) const void set(V const & value, ITERATOR const & i) const
{ {
a_.setComponent(detail::RequiresExplicitCast<value_type>::cast(valu e), i, index_); a_.setComponent(detail::RequiresExplicitCast<value_type>::cast(valu e), i, index_);
} }
/** Write the data item at an offset (can be 1D or 2D or higher ord er difference).. /** Write the data item at an offset (can be 1D or 2D or higher ord er difference)..
The type <TT>V</TT> of the passed The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>value_type< /TT>. in <TT>value</TT> is automatically converted to <TT>value_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR, class DIFFERENCE> template <class V, class ITERATOR, class OFFSET>
void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) void set(V const & value, ITERATOR const & i, OFFSET const & diff) cons
const t
{ {
a_.setComponent(detail::RequiresExplicitCast<value_type>::cast(value ), i, diff, index_); a_.setComponent(detail::RequiresExplicitCast<value_type>::cast(value ), i, diff, index_);
} }
/** Reset the index to the given number. /** Reset the index to the given number.
*/ */
void setIndex(int i) void setIndex(int i)
{ {
index_ = i; index_ = i;
} }
skipping to change at line 670 skipping to change at line 671
*/ */
template <class ITERATOR> template <class ITERATOR>
iterator end(ITERATOR const & i) const iterator end(ITERATOR const & i) const
{ {
return (*i).end(); return (*i).end();
} }
/** get begin iterator for sequence at an offset /** get begin iterator for sequence at an offset
of given iterator position of given iterator position
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
iterator begin(ITERATOR const & i, DIFFERENCE const & diff) const iterator begin(ITERATOR const & i, OFFSET const & diff) const
{ {
return i[diff].begin(); return i[diff].begin();
} }
/** get end iterator for sequence at a 2D difference vector /** get end iterator for sequence at a 2D difference vector
of given iterator position of given iterator position
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
iterator end(ITERATOR const & i, DIFFERENCE const & diff) const iterator end(ITERATOR const & i, OFFSET const & diff) const
{ {
return i[diff].end(); return i[diff].end();
} }
/** get size of sequence at given iterator position /** get size of sequence at given iterator position
*/ */
template <class ITERATOR> template <class ITERATOR>
unsigned int size(ITERATOR const & i) const { return (*i).size(); } unsigned int size(ITERATOR const & i) const { return (*i).size(); }
/** get size of sequence at 2D difference vector of given iterator position /** get size of sequence at 2D difference vector of given iterator position
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
unsigned int size(ITERATOR const & i, DIFFERENCE const & diff) const unsigned int size(ITERATOR const & i, OFFSET const & diff) const
{ return i[diff].size(); } { return i[diff].size(); }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* VectorAccessor */ /* VectorAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Accessor for items that are STL compatible vectors. /** \brief Accessor for items that are STL compatible vectors.
skipping to change at line 806 skipping to change at line 807
*/ */
template <class V, class ITERATOR> template <class V, class ITERATOR>
void setComponent(V const & value, ITERATOR const & i, int idx) const void setComponent(V const & value, ITERATOR const & i, int idx) const
{ {
(*i)[idx] = detail::RequiresExplicitCast<component_type>::cast(valu e); (*i)[idx] = detail::RequiresExplicitCast<component_type>::cast(valu e);
} }
/** Read the component data at given vector index /** Read the component data at given vector index
at an offset of given iterator position at an offset of given iterator position
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class OFFSET>
component_type const & getComponent(ITERATOR const & i, DIFFERENCE cons component_type const & getComponent(ITERATOR const & i, OFFSET const &
t & diff, int idx) const diff, int idx) const
{ {
return i[diff][idx]; return i[diff][idx];
} }
/** Set the component data at given vector index /** Set the component data at given vector index
at an offset of given iterator position. The type <TT>V</TT> of the passed at an offset of given iterator position. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>component_type< /TT>. in <TT>value</TT> is automatically converted to <TT>component_type< /TT>.
In case of a conversion floating point -> integral this include s rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
template <class V, class ITERATOR, class DIFFERENCE> template <class V, class ITERATOR, class OFFSET>
void void
setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & di ff, int idx) const setComponent(V const & value, ITERATOR const & i, OFFSET const & diff, int idx) const
{ {
i[diff][idx] = detail::RequiresExplicitCast<component_type>::cast(v alue); i[diff][idx] = detail::RequiresExplicitCast<component_type>::cast(v alue);
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiImageAccessor2 */ /* MultiImageAccessor2 */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 886 skipping to change at line 887
value_type; value_type;
/** Construct from two image iterators and associated accessors. /** Construct from two image iterators and associated accessors.
*/ */
MultiImageAccessor2(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2) MultiImageAccessor2(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2)
: i1_(i1), a1_(a1), i2_(i2), a2_(a2) : i1_(i1), a1_(a1), i2_(i2), a2_(a2)
{} {}
/** read the current data item /** read the current data item
*/ */
template <class DIFFERENCE> template <class OFFSET>
value_type operator()(DIFFERENCE const & d) const value_type operator()(OFFSET const & d) const
{ {
return std::make_pair(a1_(i1_, d), a2_(i2_, d)); return std::make_pair(a1_(i1_, d), a2_(i2_, d));
} }
/** read the data item at an offset /** read the data item at an offset
*/ */
template <class DIFFERENCE1, class DIFFERENCE2> template <class OFFSET1, class OFFSET2>
value_type operator()(DIFFERENCE1 d1, DIFFERENCE2 const & d2) const value_type operator()(OFFSET1 d1, OFFSET2 const & d2) const
{ {
d1 += d2; d1 += d2;
return std::make_pair(a1_(i1_, d1), a2_(i2_, d1)); return std::make_pair(a1_(i1_, d1), a2_(i2_, d1));
} }
private: private:
Iter1 i1_; Iter1 i1_;
Acc1 a1_; Acc1 a1_;
Iter2 i2_; Iter2 i2_;
Acc2 a2_; Acc2 a2_;
 End of changes. 24 change blocks. 
68 lines changed or deleted 66 lines changed or added


 accumulator-grammar.hxx   accumulator-grammar.hxx 
skipping to change at line 74 skipping to change at line 74
class UnbiasedKurtosis; // unbiased estimator for ex cess kurtosis class UnbiasedKurtosis; // unbiased estimator for ex cess kurtosis
class FlatScatterMatrix; // flattened upper-triangula r part of the scatter matrix class FlatScatterMatrix; // flattened upper-triangula r part of the scatter matrix
class ScatterMatrixEigensystem; // eigenvalues and eigenvect ors of the scatter matrix class ScatterMatrixEigensystem; // eigenvalues and eigenvect ors of the scatter matrix
// in all histogram classes: set bin count at runtime if BinCount == 0 // in all histogram classes: set bin count at runtime if BinCount == 0
template <int BinCount> class IntegerHistogram; // use data values dir ectly as bin indices template <int BinCount> class IntegerHistogram; // use data values dir ectly as bin indices
template <int BinCount> class UserRangeHistogram; // set min/max explici tly at runtime template <int BinCount> class UserRangeHistogram; // set min/max explici tly at runtime
template <int BinCount> class AutoRangeHistogram; // get min/max from ac cumulators template <int BinCount> class AutoRangeHistogram; // get min/max from ac cumulators
template <int BinCount> class GlobalRangeHistogram; // like AutoRangeHisto gram, but use global min/max rather than region min/max template <int BinCount> class GlobalRangeHistogram; // like AutoRangeHisto gram, but use global min/max rather than region min/max
class FirstSeen; // remember the first value seen
class Minimum; // minimum class Minimum; // minimum
class Maximum; // maximum class Maximum; // maximum
class Range; // minimum and maximum as a <tt>std::pair</tt>
template <class Hist> class StandardQuantiles; // compute (min, 10%, 25%, 5 0%, 75%, 90%, max) quantiles from template <class Hist> class StandardQuantiles; // compute (min, 10%, 25%, 5 0%, 75%, 90%, max) quantiles from
// min/max accumulators and given histogram // min/max accumulators and given histogram
class ArgMinWeight; // store the value (or coord inate) where weight was minimal class ArgMinWeight; // store the value (or coord inate) where weight was minimal
class ArgMaxWeight; // store the value (or coord inate) where weight was maximal class ArgMaxWeight; // store the value (or coord inate) where weight was maximal
// FIXME: not yet implemented // FIXME: not yet implemented
template <unsigned NDim> class MultiHistogram; // multi-dimensional histogr am template <unsigned NDim> class MultiHistogram; // multi-dimensional histogr am
// (always specify number of bins at runtime) // (always specify number of bins at runtime)
skipping to change at line 97 skipping to change at line 99
class PrincipalProjection; // cache values after princi pal projection class PrincipalProjection; // cache values after princi pal projection
// FIXME: not yet implemented // FIXME: not yet implemented
class Whiten; // cache values after whiten ing class Whiten; // cache values after whiten ing
class RangeMapping; // map value from [min, max] to another range and cache result (e.g. for histogram creation) class RangeMapping; // map value from [min, max] to another range and cache result (e.g. for histogram creation)
template <int INDEX> class DataArg; // specifiy the index of the data member in a CoupledHandle template <int INDEX> class DataArg; // specifiy the index of the data member in a CoupledHandle
template <int INDEX> class WeightArg; // specifiy the index of the weight member in a CoupledHandle template <int INDEX> class WeightArg; // specifiy the index of the weight member in a CoupledHandle
template <int INDEX> class LabelArg; // specifiy the index of the label member in a CoupledHandle template <int INDEX> class LabelArg; // specifiy the index of the label member in a CoupledHandle
template <int INDEX> class CoordArg; // specifiy the index of the coord member in a CoupledHandle template <int INDEX> class CoordArg; // specifiy the index of the coord member in a CoupledHandle
class RegionContour; // compute the contour of a
2D region
class RegionPerimeter; // compute the perimeter of
a 2D region
class RegionCircularity; // compare perimeter of a 2D
region with a circle of same area
class RegionEccentricity; // ecentricity of a 2D regio
n from major and minor axis
class ConvexHull; // base class for convex hul
l features
/* /*
Quantiles other than minimum and maximum require more thought: Quantiles other than minimum and maximum require more thought:
-------------------------------------------------------------- --------------------------------------------------------------
* Exact quantiles can be found in time O(n) using recursive partitioning ( quickselect), * Exact quantiles can be found in time O(n) using recursive partitioning ( quickselect),
but this requires the data (or an auxiliary index array) to be re-arrang ed. but this requires the data (or an auxiliary index array) to be re-arrang ed.
* Exact quantiles can be found in time O(k*n) using recursive histogram re finement, * Exact quantiles can be found in time O(k*n) using recursive histogram re finement,
were k = O(log(n)/log(BinCount)) is the expected number of required pass es over the were k = O(log(n)/log(BinCount)) is the expected number of required pass es over the
data, provided that bins are filled approximately evenly. If data can be re-arranged, data, provided that bins are filled approximately evenly. If data can be re-arranged,
such that we remember the items corresponding to each bin, running time reduces to O(n) such that we remember the items corresponding to each bin, running time reduces to O(n)
(this is Tibshirani's 'binmedian' algorithm). For the median, Tibshirani proves that (this is Tibshirani's 'binmedian' algorithm). For the median, Tibshirani proves that
skipping to change at line 204 skipping to change at line 213
/** \brief Alias. Covariance eigensystem. */ /** \brief Alias. Covariance eigensystem. */
typedef DivideByCount<ScatterMatrixEigensystem> CovarianceEigensystem; typedef DivideByCount<ScatterMatrixEigensystem> CovarianceEigensystem;
/** \brief Alias. Absolute sum. */ /** \brief Alias. Absolute sum. */
typedef AbsPowerSum<1> AbsSum; typedef AbsPowerSum<1> AbsSum;
/** \brief Alias. Sum of absolute differences. */ /** \brief Alias. Sum of absolute differences. */
typedef Central<AbsSum> SumOfAbsDifferences; typedef Central<AbsSum> SumOfAbsDifferences;
/** \brief Alias. Mean absolute deviation. */ /** \brief Alias. Mean absolute deviation. */
typedef DivideByCount<SumOfAbsDifferences> MeanAbsoluteDeviation; typedef DivideByCount<SumOfAbsDifferences> MeanAbsoluteDeviation;
/** \brief Alias. Rectangle enclosing the region, as a <tt>std::pair</tt> o
f coordinates. */
typedef Coord<Range> BoundingBox;
/** \brief Alias. Anchor point (first point of the region seen by scan-orde
r traversal. */
typedef Coord<FirstSeen> RegionAnchor;
/** \brief Alias. Region center. */ /** \brief Alias. Region center. */
typedef Coord<Mean> RegionCenter; typedef Coord<Mean> RegionCenter;
/** \brief Alias. Region radii. */ /** \brief Alias. Region radii. */
typedef Coord<Principal<StdDev> > RegionRadii; typedef Coord<Principal<StdDev> > RegionRadii;
/** \brief Alias. Region axes. */ /** \brief Alias. Region axes. */
typedef Coord<Principal<CoordinateSystem> > RegionAxes; typedef Coord<Principal<CoordinateSystem> > RegionAxes;
/** \brief Alias. Center of mass. */ /** \brief Alias. Center of mass. */
typedef Weighted<RegionCenter> CenterOfMass; typedef Weighted<RegionCenter> CenterOfMass;
/** \brief Alias. Region center weighted by the region intensity (center of
mass). */
typedef Weighted<RegionCenter> WeightedRegionCenter;
/** \brief Alias. Moments of inertia. */ /** \brief Alias. Moments of inertia. */
typedef Weighted<Coord<Principal<Variance> > > MomentsOfInertia; typedef Weighted<Coord<Principal<Variance> > > MomentsOfInertia;
/** \brief Alias. Region radius weighted by region intensity (square root o
f the moments of inertia). */
typedef Weighted<RegionRadii> WeightedRegionRadii;
/** \brief Alias. Axes of inertia. */ /** \brief Alias. Axes of inertia. */
typedef Weighted<RegionAxes> AxesOfInertia; typedef Weighted<RegionAxes> AxesOfInertia;
/************************************************************************** / /************************************************************************** /
/* * / /* * /
/* Tag standardization rules * / /* Tag standardization rules * /
/* * / /* * /
/************************************************************************** / /************************************************************************** /
namespace detail { namespace acc_detail {
template <class A> template <class A>
struct ModifierRule struct ModifierRule
{ {
typedef A type; typedef A type;
}; };
} // namespace detail } // namespace acc_detail
template <class A> template <class A>
struct Error___Tag_modifiers_of_same_kind_must_not_be_combined; struct Error___Tag_modifiers_of_same_kind_must_not_be_combined;
// apply rules as long as the Tag type changes ... // apply rules as long as the Tag type changes ...
template <class A, class S=typename detail::ModifierRule<A>::type> template <class A, class S=typename acc_detail::ModifierRule<A>::type>
struct StandardizeTag struct StandardizeTag
{ {
typedef typename StandardizeTag<S>::type type; typedef typename StandardizeTag<S>::type type;
}; };
// ... and stop otherwise ... // ... and stop otherwise ...
template <class A> template <class A>
struct StandardizeTag<A, A> struct StandardizeTag<A, A>
{ {
typedef A type; typedef A type;
}; };
// ... or fail when the tag spec was non-conforming // ... or fail when the tag spec was non-conforming
template <class A, class B> template <class A, class B>
struct StandardizeTag<A, Error___Tag_modifiers_of_same_kind_must_not_be_com bined<B> > struct StandardizeTag<A, Error___Tag_modifiers_of_same_kind_must_not_be_com bined<B> >
: public Error___Tag_modifiers_of_same_kind_must_not_be_combined<B> : public Error___Tag_modifiers_of_same_kind_must_not_be_combined<B>
{}; {};
namespace detail { namespace acc_detail {
// Assign priorities to modifiers to determine their standard order (by ascending priority). // Assign priorities to modifiers to determine their standard order (by ascending priority).
// SubstitutionMask determines which modifiers must be automatically tr ansferred to dependencies. // SubstitutionMask determines which modifiers must be automatically tr ansferred to dependencies.
enum { MinPriority = 1, enum { MinPriority = 1,
AccumulatorPriority = 32, AccumulatorPriority = 32,
PrepareDataPriority = 16, PrepareDataPriority = 16,
NormalizePriority = 8, NormalizePriority = 8,
AccessDataPriority = 4, AccessDataPriority = 4,
WeightingPriority = 2, WeightingPriority = 2,
GlobalPriority = 1, GlobalPriority = 1,
skipping to change at line 471 skipping to change at line 489
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Central<Kurtosis>, Kurtosis) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Central<Kurtosis>, Kurtosis)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Central<FlatScatterMatrix>, FlatScatterMat rix) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Central<FlatScatterMatrix>, FlatScatterMat rix)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Central<ScatterMatrixEigensystem>, Scatter MatrixEigensystem) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Central<ScatterMatrixEigensystem>, Scatter MatrixEigensystem)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Principal<Centralize>, PrincipalProjection ) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Principal<Centralize>, PrincipalProjection )
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<Centralize>, Whiten) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<Centralize>, Whiten)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Principal<PrincipalProjection>, PrincipalP rojection) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Principal<PrincipalProjection>, PrincipalP rojection)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<PrincipalProjection>, Whiten) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<PrincipalProjection>, Whiten)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<Whiten>, Whiten) VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<Whiten>, Whiten)
// ignore all modifiers of RegionContour and related features
VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionContour>, RegionCont
our)
VIGRA_REDUCE_MODFIER(template <class> class A, A<ConvexHull>, ConvexHull)
VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionPerimeter>, RegionPe
rimeter)
VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionCircularity>, Region
Circularity)
VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionEccentricity>, Regio
nEccentricity)
VIGRA_REDUCE_MODFIER(VIGRA_VOID, Weighted<RegionEccentricity>, Weighted<Reg
ionEccentricity>)
// reduce even absolute powers to plain powers // reduce even absolute powers to plain powers
template <unsigned N> template <unsigned N>
struct ModifierRule<AbsPowerSum<N> > struct ModifierRule<AbsPowerSum<N> >
{ {
typedef typename IfBool<(N % 2 == 0), PowerSum<N>, AbsPowerSum<N> >::ty pe type; typedef typename IfBool<(N % 2 == 0), PowerSum<N>, AbsPowerSum<N> >::ty pe type;
}; };
#undef VIGRA_VOID #undef VIGRA_VOID
#undef VIGRA_REDUCE_MODFIER #undef VIGRA_REDUCE_MODFIER
skipping to change at line 507 skipping to change at line 533
{ {
typedef VigraTrueType type; typedef VigraTrueType type;
static const bool value = true; static const bool value = true;
}; };
template <class A, template <class> class B> template <class A, template <class> class B>
struct ShouldBeWeighted<B<A> > struct ShouldBeWeighted<B<A> >
: public ShouldBeWeighted<A> : public ShouldBeWeighted<A>
{}; {};
} // namespace detail } // namespace acc_detail
template <class A> template <class A>
struct IsCoordinateFeature struct IsCoordinateFeature
{ {
typedef VigraFalseType type; typedef VigraFalseType type;
static const bool value = false; static const bool value = false;
}; };
template <class A, template <class> class B> template <class A, template <class> class B>
struct IsCoordinateFeature<B<A> > struct IsCoordinateFeature<B<A> >
skipping to change at line 564 skipping to change at line 590
typedef VigraTrueType type; typedef VigraTrueType type;
static const bool value = true; static const bool value = true;
}; };
/************************************************************************** / /************************************************************************** /
/* * / /* * /
/* Tag transfer rules * / /* Tag transfer rules * /
/* * / /* * /
/************************************************************************** / /************************************************************************** /
namespace detail { namespace acc_detail {
template <class A> template <class A>
struct DefaultModifier; struct DefaultModifier;
template <class A> template <class A>
struct ModifierPriority<DefaultModifier<A> > struct ModifierPriority<DefaultModifier<A> >
{ {
static const int value = ModifierPriority<A>::value << 1; static const int value = ModifierPriority<A>::value << 1;
}; };
skipping to change at line 681 skipping to change at line 707
template <class A, class B, template <class A, class B,
bool substitute=CheckSubstitutionFlag<A>::value> bool substitute=CheckSubstitutionFlag<A>::value>
struct SubstituteModifiers; struct SubstituteModifiers;
template <class A, class B> template <class A, class B>
struct SubstituteModifiers<A, B, false> struct SubstituteModifiers<A, B, false>
{ {
typedef B type; typedef B type;
}; };
template <class A0, template <class> class A1, class B0, template <class> c template <class A, template <class> class AA, class B, template <class> cla
lass B1> ss BB>
struct SubstituteModifiers<A1<A0>, B1<B0>, true> struct SubstituteModifiers<AA<A>, BB<B>, true>
{ {
typedef A1<typename SubstituteModifiers<A0, B0>::type> type; typedef AA<typename SubstituteModifiers<A, B>::type> type;
}; };
template <class A0, class B0, template <class> class B1> template <class A, class B, template <class> class BB>
struct SubstituteModifiers<DefaultModifier<A0>, B1<B0>, true> struct SubstituteModifiers<DefaultModifier<A>, BB<B>, true>
{ {
typedef B1<typename SubstituteModifiers<A0, B0>::type> type; typedef BB<typename SubstituteModifiers<A, B>::type> type;
}; };
template <class A0, template <class> class A1, class B0, template <class> c template <class A, template <class> class AA, class B, template <class> cla
lass B1> ss BB>
struct SubstituteModifiers<A1<A0>, B1<B0>, false> struct SubstituteModifiers<AA<A>, BB<B>, false>
{ {
typedef B1<typename SubstituteModifiers<A0, B0>::type> type; typedef BB<typename SubstituteModifiers<A, B>::type> type;
}; };
} // namespace detail } // namespace acc_detail
template <class A, class B> template <class A, class B>
struct TransferModifiers struct TransferModifiers
{ {
typedef typename StandardizeTag<A>::type StdA; typedef typename StandardizeTag<A>::type StdA;
typedef typename StandardizeTag<B>::type StdB; typedef typename StandardizeTag<B>::type StdB;
typedef typename detail::TagLongForm<StdA, detail::MinPriority>::type A typedef typename acc_detail::TagLongForm<StdA, acc_detail::MinPriority>
A; ::type AA;
typedef typename detail::TagLongForm<StdB, detail::MinPriority>::type B typedef typename acc_detail::TagLongForm<StdB, acc_detail::MinPriority>
B; ::type BB;
typedef typename detail::SubstituteModifiers<AA, BB>::type AB; typedef typename acc_detail::SubstituteModifiers<AA, BB>::type AB;
typedef typename detail::StandardizeTagLongForm<AB>::type StdAB; typedef typename acc_detail::StandardizeTagLongForm<AB>::type StdAB;
typedef typename StandardizeTag<StdAB>::type type; typedef typename StandardizeTag<StdAB>::type type;
}; };
template <class A, class HEAD, class TAIL> template <class A, class HEAD, class TAIL>
struct TransferModifiers<A, TypeList<HEAD, TAIL> > struct TransferModifiers<A, TypeList<HEAD, TAIL> >
{ {
typedef TypeList<typename TransferModifiers<A, HEAD>::type, typedef TypeList<typename TransferModifiers<A, HEAD>::type,
typename TransferModifiers<A, TAIL>::type> type; typename TransferModifiers<A, TAIL>::type> type;
}; };
 End of changes. 21 change blocks. 
24 lines changed or deleted 64 lines changed or added


 accumulator.hxx   accumulator.hxx 
skipping to change at line 55 skipping to change at line 55
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "bit_array.hxx" #include "bit_array.hxx"
#include "static_assert.hxx" #include "static_assert.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "utilities.hxx" #include "utilities.hxx"
#include "multi_iterator_coupled.hxx" #include "multi_iterator_coupled.hxx"
#include "matrix.hxx" #include "matrix.hxx"
#include "multi_math.hxx" #include "multi_math.hxx"
#include "eigensystem.hxx" #include "eigensystem.hxx"
#include "histogram.hxx" #include "histogram.hxx"
#include "polygon.hxx"
#include "functorexpression.hxx"
#include "labelimage.hxx"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
namespace vigra { namespace vigra {
/** \defgroup FeatureAccumulators Feature Accumulators /** \defgroup FeatureAccumulators Feature Accumulators
The namespace <tt>vigra::acc</tt> provides the function \ref vigra::acc::ex tractFeatures() along with associated statistics functors and accumulator c lasses. Together, they provide a framework for efficient compution of a wid e variety of statistical features, both globally for an entire image, and l ocally for each region defined by a label array. Many different statistics can be composed out of a small number of fundamental statistics and suitabl e modifiers. The user simply selects the desired statistics by means of the ir <i>tags</i> (see below), and a template meta-program automatically gener ates an efficient functor that computes exactly those statistics. The namespace <tt>vigra::acc</tt> provides the function \ref vigra::acc::ex tractFeatures() along with associated statistics functors and accumulator c lasses. Together, they provide a framework for efficient compution of a wid e variety of statistical features, both globally for an entire image, and l ocally for each region defined by a label array. Many different statistics can be composed out of a small number of fundamental statistics and suitabl e modifiers. The user simply selects the desired statistics by means of the ir <i>tags</i> (see below), and a template meta-program automatically gener ates an efficient functor that computes exactly those statistics.
The function \ref acc::extractFeatures() "extractFeatures()" scans the data in as few passes as the selected statstics permit (usually one or two pass es are sufficient). Statistics are computed by accurate incremental algorit hms, whose internal state is maintained by accumulator objects. The state i s updated by passing data to the accumulator one sample at a time. Accumula tors are grouped within an accumulator chain. Dependencies between accumula tors in the accumulator chain are automatically resolved and missing depend encies are inserted. For example, to compute the mean, you also need to cou nt the number of samples. This allows accumulators to offload some of their computations on other accumulators, making the algorithms more efficient. Each accumulator only sees data in the appropriate pass through the data, c alled its "working pass". The function \ref acc::extractFeatures() "extractFeatures()" scans the data in as few passes as the selected statstics permit (usually one or two pass es are sufficient). Statistics are computed by accurate incremental algorit hms, whose internal state is maintained by accumulator objects. The state i s updated by passing data to the accumulator one sample at a time. Accumula tors are grouped within an accumulator chain. Dependencies between accumula tors in the accumulator chain are automatically resolved and missing depend encies are inserted. For example, to compute the mean, you also need to cou nt the number of samples. This allows accumulators to offload some of their computations on other accumulators, making the algorithms more efficient. Each accumulator only sees data in the appropriate pass through the data, c alled its "working pass".
<b>\#include</b> \<vigra/accumulator.hxx\> <b>\#include</b> \<vigra/accumulator.hxx\>
<b>Basic statistics:</b> <b>Basic statistics:</b>
- PowerSum<N> (@f$ \sum_i x_i^N @f$) - PowerSum<N> (computes @f$ \sum_i x_i^N @f$)
- AbsPowerSum<N> (@f$ \sum_i |x_i|^N @f$) - AbsPowerSum<N> (computes @f$ \sum_i |x_i|^N @f$)
- Skewness, UnbiasedSkewness - Skewness, UnbiasedSkewness
- Kurtosis, UnbiasedKurtosis - Kurtosis, UnbiasedKurtosis
- Minimum, Maximum - Minimum, Maximum
- FlatScatterMatrix (flattened upper-triangular part of scatter matrix) - FlatScatterMatrix (flattened upper-triangular part of scatter matrix)
- 4 histogram classes (see \ref histogram "below") - 4 histogram classes (see \ref histogram "below")
- StandardQuantiles (0%, 10%, 25%, 50%, 75%, 90%, 100%) - StandardQuantiles (0%, 10%, 25%, 50%, 75%, 90%, 100%)
- ArgMinWeight, ArgMaxWeight (store data or coordinate where weight ass umes its minimal or maximal value) - ArgMinWeight, ArgMaxWeight (store data or coordinate where weight ass umes its minimal or maximal value)
- CoordinateSystem (identity matrix of appropriate size) - CoordinateSystem (identity matrix of appropriate size)
<b>Modifiers:</b> (S is the statistc to be modified) <b>Modifiers:</b> (S is the statistc to be modified)
skipping to change at line 98 skipping to change at line 101
- Data preparation: - Data preparation:
<table border="0"> <table border="0">
<tr><td> Central<S> </td><td> substract mean before computing S </ td></tr> <tr><td> Central<S> </td><td> substract mean before computing S </ td></tr>
<tr><td> Principal<S> </td><td> project onto PCA eigenvectors </td ></tr> <tr><td> Principal<S> </td><td> project onto PCA eigenvectors </td ></tr>
<tr><td> Whitened<S> &nbsp; &nbsp; </td><td> scale to unit variance after PCA </td></tr> <tr><td> Whitened<S> &nbsp; &nbsp; </td><td> scale to unit variance after PCA </td></tr>
<tr><td> Coord<S> </td><td> compute S from pixel coordinates rather than from pixel values </td></tr> <tr><td> Coord<S> </td><td> compute S from pixel coordinates rather than from pixel values </td></tr>
<tr><td> Weighted<S> </td><td> compute weighted version of S < /td></tr> <tr><td> Weighted<S> </td><td> compute weighted version of S < /td></tr>
<tr><td> Global<S> </td><td> compute S globally rather than pe r region (per region is default if labels are given) </td></tr> <tr><td> Global<S> </td><td> compute S globally rather than pe r region (per region is default if labels are given) </td></tr>
</table> </table>
Aliases for a couple of important features are implemented (mainly as < Aliases for many important features are implemented (mainly as <tt>type
tt>typedef FullName Alias</tt>). The alias names are equivalent to full nam def FullName Alias</tt>). The alias names are equivalent to full names. Bel
es. ow are some examples for supported alias names. A full list of all availabl
Here are some examples for supported alias names (these examples also s e statistics and alias names can be found in the namespace reference <tt>vi
how how to compose statistics from the fundamental statistics and modifiers gra::acc</tt>. These examples also show how to compose statistics from the
): fundamental statistics and modifiers:
<table border="0"> <table border="0">
<tr><th> Alias </th><th> Full Name </th></t r> <tr><th> Alias </th><th> Full Name </th></t r>
<tr><td> Count </td><td> PowerSum<0> </td></t r> <tr><td> Count </td><td> PowerSum<0> </td></t r>
<tr><td> Sum </td><td> PowerSum<1> </td></t r> <tr><td> Sum </td><td> PowerSum<1> </td></t r>
<tr><td> SumOfSquares </td><td> PowerSum<2> </td></t r> <tr><td> SumOfSquares </td><td> PowerSum<2> </td></t r>
<tr><td> Mean </td><td> DivideByCount<PowerSum<1>> </td></t r> <tr><td> Mean </td><td> DivideByCount<PowerSum<1>> </td></t r>
<tr><td> RootMeanSquares &nbsp; </td><td> RootDivideByCount<PowerSum<2 >> </td></tr> <tr><td> RootMeanSquares &nbsp; </td><td> RootDivideByCount<PowerSum<2 >> </td></tr>
<tr><td> Moment<N> </td><td> DivideByCount<PowerSum<N>> </td></ tr> <tr><td> Moment<N> </td><td> DivideByCount<PowerSum<N>> </td></ tr>
<tr><td> Variance </td><td> DivideByCount<Central<PowerSum<2>>> </td></tr> <tr><td> Variance </td><td> DivideByCount<Central<PowerSum<2>>> </td></tr>
skipping to change at line 136 skipping to change at line 138
#include <vigra/multi_array.hxx> #include <vigra/multi_array.hxx>
#include <vigra/impex.hxx> #include <vigra/impex.hxx>
#include <vigra/accumulator.hxx> #include <vigra/accumulator.hxx>
using namespace vigra::acc; using namespace vigra::acc;
typedef double DataType; typedef double DataType;
int size = 1000; int size = 1000;
vigra::MultiArray<2, DataType> data(vigra::Shape2(size, size)); vigra::MultiArray<2, DataType> data(vigra::Shape2(size, size));
AccumulatorChain<DataType, AccumulatorChain<DataType,
Select<Variance, Mean, StdDev, Minimum, Maximum, RootMeanSquares, S kewness, Covariance> > Select<Variance, Mean, StdDev, Minimum, Maximum, RootMeanSquares, S kewness, Covariance> >
a; a;
std::cout << "passes required: " << a.passesRequired() << std::endl; std::cout << "passes required: " << a.passesRequired() << std::endl;
extractFeatures(data.begin(), data.end(), a); extractFeatures(data.begin(), data.end(), a);
std::cout << "Mean: " << get<Mean>(a) << std::endl; std::cout << "Mean: " << get<Mean>(a) << std::endl;
std::cout << "Variance: " << get<Variance>(a) << std::endl; std::cout << "Variance: " << get<Variance>(a) << std::endl;
\endcode \endcode
The \ref acc::AccumulatorChain object contains the selected statistics and their dependencies. Statistics have to be wrapped with \ref acc::Select . The statistics are computed with the acc::extractFeatures function and th e statistics can be accessed with acc::get . The \ref acc::AccumulatorChain object contains the selected statistics and their dependencies. Statistics have to be wrapped with \ref acc::Select . The statistics are computed with the acc::extractFeatures function and th e statistics can be accessed with acc::get .
skipping to change at line 163 skipping to change at line 165
- each accumulator only sees data in the appropriate pass (its "working pass") - each accumulator only sees data in the appropriate pass (its "working pass")
The Accumulators can also be used with vector-valued data (vigra::RGBVa lue, vigra::TinyVector, vigra::MultiArray or vigra::MultiArrayView): The Accumulators can also be used with vector-valued data (vigra::RGBVa lue, vigra::TinyVector, vigra::MultiArray or vigra::MultiArrayView):
\code \code
typedef vigra::RGBValue<double> DataType; typedef vigra::RGBValue<double> DataType;
AccumulatorChain<DataType, Select<...> > a; AccumulatorChain<DataType, Select<...> > a;
... ...
\endcode \endcode
To compute <b>weighted statistics</b> (Weighted<>) or <b>statistics ove r coordinates</b> (Coord<>), the accumulator chain can be used with \ref Co upledScanOrderIterator. The coupled iterator provides simultaneous access t o several images (e.g. weight and data) and pixel coordinates. The first pa rameter in the accumulator chain is the type of the CoupledHandle. The inde ces at which the CoupledHandle holds the data, weights etc. can be specifie d inside the Select wrapper. To compute <b>weighted statistics</b> (Weighted<>) or <b>statistics ove r coordinates</b> (Coord<>), the accumulator chain can be used with several coupled arrays, one for the data and another for the weights and/or the la bels. "Coupled" means that statistics are computed over the corresponding e lements of the involved arrays. This is internally done by means of \ref Co upledScanOrderIterator and \ref vigra::CoupledHandle which provide simultan eous access to several arrays (e.g. weight and data) and corresponding coor dinates. The types of the coupled arrays are best specified by means of the helper class \ref vigra::CoupledArrays :
These <b>index specifiers</b> are: (INDEX is of type int) \code
vigra::MultiArray<3, RGBValue<unsigned char> > data(...);
vigra::MultiArray<3, double> weights(...);
- DataArg<INDEX>: CoupledHandle holds data at index 'INDEX' (default IN AccumulatorChain<CoupledArrays<3, RGBValue<unsigned char>, double>,
DEX=1) Select<...> > a;
- LabelArg<INDEX>: CoupledHandle holds labels at index 'INDEX' (default \endcode
INDEX=2)
- WeightArg<INDEX>: CoupledHandle holds weights at index 'INDEX' (defau
lt INDEX=outermost index)
Pixel coordinates are always at index 0. This works likewise for label images which are needed for region statistics
(see below). The indxx of the array holding data, weights, or labels respe
ctively can be specified inside the Select wrapper. These <b>index specifie
rs</b> are: (INDEX is of type int)
- DataArg<INDEX>: data are in array 'INDEX' (default INDEX=1)
- LabelArg<INDEX>: labels are in array 'INDEX' (default INDEX=2)
- WeightArg<INDEX>: weights are in array 'INDEX' (default INDEX=rightmo
st index)
Pixel coordinates are always at index 0. To collect statistics, you simply pass all arrays to the <tt>extractFeatures()</tt> function:
\code \code
using namespace vigra::acc; using namespace vigra::acc;
vigra::MultiArray<3, double> data(...), weights(...); vigra::MultiArray<3, double> data(...), weights(...);
typedef vigra::CoupledIteratorType<3, double, double>::type Iterator; /
/type of the CoupledScanOrderIterator
typedef Iterator::value_type Handle; //type of the corresponding Couple
dHandle
AccumulatorChain<Handle, AccumulatorChain<CoupledArrays<3, double, double>, // two 3D arrays for
Select<DataArg<1>, WeightArg<2>, //where to look in the Handl data and weights
e (coordinates are always arg 0) Select<DataArg<1>, WeightArg<2>, // in which array to loo
Mean, Variance, //statistics over values k (coordinates are always arg 0)
Coord<Mean>, Coord<Variance>, //statistics over coordin Mean, Variance, //statistics over values
ates, Coord<Mean>, Coord<Variance>, //statistics over coordi
Weighted<Mean>, Weighted<Variance>, //weighted values, nates,
Weighted<Coord<Mean> > > > //weighted coordinates. Weighted<Mean>, Weighted<Variance>, //weighted values,
a; Weighted<Coord<Mean> > > > //weighted coordinates.
a;
Iterator start = createCoupledIterator(data, weights); //coord->index 0 extractFeatures(data, weights, a);
, data->index 1, weights->index 2 \endcode
Iterator end = start.getEndIterator();
extractFeatures(start,end,a); This even works for a single array, which is useful if you want to comb
ine values with coordinates. For example, to find the location of the minim
um element in an array, you interpret the data as weights and select the <t
t>Coord<ArgMinWeight></tt> statistic (note that the version of <tt>extractF
eatures()</tt> below only works in conjunction with <tt>CoupledArrays</tt>,
despite the fact that there is only one array involved):
\code
using namespace vigra::acc;
vigra::MultiArray<3, double> data(...);
AccumulatorChain<CoupledArrays<3, double>,
Select<WeightArg<1>, // we interprete the da
ta as weights
Coord<ArgMinWeight> > > // and look for the coo
rdinate with minimal weight
a;
extractFeatures(data, a);
std::cout << "minimum is at " << get<Coord<ArgMinWeight> >(a) << std::e
ndl;
\endcode \endcode
To compute <b>region statistics</b>, use \ref acc::AccumulatorChainArra y : To compute <b>region statistics</b>, you use \ref acc::AccumulatorChain Array. Regions are defined by means of a label array whose elements specify the region ID of the corresponding point. Therefore, you will always need at least two arrays here, which are again best specified using the <tt>Coup ledArrays</tt> helper:
\code \code
using namespace vigra::acc; using namespace vigra::acc;
vigra::MultiArray<3, double> data(...); vigra::MultiArray<3, double> data(...);
vigra::MultiArray<3, int> labels(...); vigra::MultiArray<3, int> labels(...);
typedef vigra::CoupledIteratorType<3, double, int>::type Iterator;
typedef Iterator::value_type Handle;
AccumulatorChainArray<Handle, AccumulatorChainArray<CoupledArrays<3, double, int>,
Select<DataArg<1>, LabelArg<2>, //where to look in the Handle Select<DataArg<1>, LabelArg<2>, // in which array to look (co
(coordinates are always arg 0) ordinates are always arg 0)
Mean, Variance, //per-region statistics ov Mean, Variance, //per-region statistics o
er values ver values
Coord<Mean>, Coord<Variance>, //per-region statistics ov Coord<Mean>, Coord<Variance>, //per-region statistics o
er coordinates ver coordinates
Global<Mean>, Global<Variance> > > //global statistics Global<Mean>, Global<Variance> > > //global statistics
a; a;
Iterator start = createCoupledIterator(data, labels);
Iterator end = start.getEndIterator();
a.ignoreLabel(0); //statistics will not be computed for region 0 (e.g. background) a.ignoreLabel(0); //statistics will not be computed for region 0 (e.g. background)
extractFeatures(start,end,a); extractFeatures(data, labels, a);
int regionlabel = ...; int regionlabel = ...;
std::cout << get<Mean>(a, regionlabel) << std::endl; //get Mean of regi on with label 'regionlabel' std::cout << get<Mean>(a, regionlabel) << std::endl; //get Mean of regi on with label 'regionlabel'
\endcode \endcode
In some application it will be known only at run-time which statistics have to be computed. An Accumulator with <b>run-time activation</b> is prov ided by the \ref acc::DynamicAccumulatorChain class. One specifies a set of statistics at compile-time and from this set one can activate the needed s tatistics at run-time: In some application it will be known only at run-time which statistics have to be computed. An Accumulator with <b>run-time activation</b> is prov ided by the \ref acc::DynamicAccumulatorChain class. One specifies a set of statistics at compile-time and from this set one can activate the needed s tatistics at run-time:
\code \code
using namespace vigra::acc; using namespace vigra::acc;
vigra::MultiArray<2, double> data(...); vigra::MultiArray<2, double> data(...);
skipping to change at line 247 skipping to change at line 259
<b>Accumulator merging</b> (e.g. for parallelization or hierarchical se gmentation) is possible for many accumulators: <b>Accumulator merging</b> (e.g. for parallelization or hierarchical se gmentation) is possible for many accumulators:
\code \code
using namespace vigra::acc; using namespace vigra::acc;
vigra::MultiArray<2, double> data(...); vigra::MultiArray<2, double> data(...);
AccumulatorChain<double, Select<Mean, Variance, Skewness> > a, a1, a2; AccumulatorChain<double, Select<Mean, Variance, Skewness> > a, a1, a2;
extractFeatures(data.begin(), data.end(), a); //process entire data set at once extractFeatures(data.begin(), data.end(), a); //process entire data set at once
extractFeatures(data.begin(), data.begin()+data.size()/2, a1); //proces s first half extractFeatures(data.begin(), data.begin()+data.size()/2, a1); //proces s first half
extractFeatures(data.begin()+data.size()/2, data.end(), a2); //process second half extractFeatures(data.begin()+data.size()/2, data.end(), a2); //process second half
a1 += a2; // merge: a1 now equals a0 (with numerical tolerances) a1 += a2; // merge: a1 now equals a0 (within numerical tolerances)
\endcode \endcode
Not all statistics can be merged (e.g. Principal<A> usually cannot, exc ept for some important specializations). A statistic can be merged if the " +=" operator is supported (see the documentation of that particular statist ic). If the accumulator chain only requires one pass to collect the data, i t is also possible to just apply the extractFeatures() function repeatedly: Not all statistics can be merged (e.g. Principal<A> usually cannot, exc ept for some important specializations). A statistic can be merged if the " +=" operator is supported (see the documentation of that particular statist ic). If the accumulator chain only requires one pass to collect the data, i t is also possible to just apply the extractFeatures() function repeatedly:
\code \code
using namespace vigra::acc; using namespace vigra::acc;
vigra::MultiArray<2, double> data(...); vigra::MultiArray<2, double> data(...);
AccumulatorChain<double, Select<Mean, Variance> > a; AccumulatorChain<double, Select<Mean, Variance> > a;
extractFeatures(data.begin(), data.begin()+data.size()/2, a); // this w orks because extractFeatures(data.begin(), data.begin()+data.size()/2, a); // this w orks because
extractFeatures(data.begin()+data.size()/2, data.end(), a); // all st extractFeatures(data.begin()+data.size()/2, data.end(), a); // all st
atistics only work in pass 1 atistics only need pass 1
\endcode
More care is needed to merge coordinate-based statistics. By default, a
ll coordinate statistics are computed in the local coordinate system of the
current region of interest. That is, the upper left corner of the ROI has
the coordinate (0, 0) by default. This behavior is not desirable when you w
ant to merge coordinate statistics from different ROIs: then, all accumulat
ors should use the same coordinate system, usually the global system of the
entire dataset. This can be achieved by the <tt>setCoordinateOffset()</tt>
function. The following code demonstrates this for the <tt>RegionCenter</t
t> statistic:
\code
using namespace vigra;
using namespace vigra::acc;
MultiArray<2, double> data(width, height);
MultiArray<2, int> labels(width, height);
AccumulatorChainArray<CoupledArrays<2, double, int>,
Select<DataArg<1>, LabelArg<2>,
RegionCenter> >
a1, a2;
// a1 is responsible for the left half of the image. The local coordina
te system of this ROI
// happens to be identical to the global coordinate system, so the offs
et is zero.
Shape2 origin(0,0);
a1.setCoordinateOffset(origin);
extractFeatures(data.subarray(origin, Shape2(width/2, height)),
labels.subarray(origin, Shape2(width/2, height)),
a1);
// a2 is responsible for the right half, so the offset of the local coo
rdinate system is (width/2, 0)
origin = Shape2(width/2, 0);
a2.setCoordinateOffset(origin);
extractFeatures(data.subarray(origin, Shape2(width, height)),
labels.subarray(origin, Shape2(width, height)),
a2);
// since both accumulators worked in the same global coordinate system,
we can safely merge them
a1.merge(a2);
\endcode
When you compute region statistics in ROIs, it is sometimes desirable t
o use a local region labeling in each ROI. In this way, the labels of each
ROI cover a consecutive range of numbers starting with 0. This can save a l
ot of memory, because <tt>AccumulatorChainArray</tt> internally uses dense
arrays -- accumulators will be allocated for all labels from 0 to the maxmi
mum label, even when many of them are unused. This is avoided by a local la
beling. However, this means that label 1 (say) may refer to two different r
egions in different ROIs. To adjust for this mismatch, you can pass a label
mapping to <tt>merge()</tt> that provides a global label for each label of
the accumulator to be merged. Thus, each region on the right hand side wil
l be merged into the left-hand-side accumulator with the given <i>global</i
> label. For example, let us assume that the left and right half of the ima
ge contain just one region and background. Then, the accumulators of both R
OIs have the label 0 (background) and 1 (the region). Upon merging, the reg
ion from the right ROI should be given the global label 2, whereas the back
ground should keep its label 0. This is achieved like this:
\code
std::vector<int> labelMapping(2);
labelMapping[0] = 0; // background keeps label 0
labelMapping[1] = 2; // local region 1 becomes global region 2
a1.merge(a2, labelMapping);
\endcode \endcode
\anchor histogram \anchor histogram
Four kinds of <b>histograms</b> are currently implemented: Four kinds of <b>histograms</b> are currently implemented:
<table border="0"> <table border="0">
<tr><td> IntegerHistogram </td><td> Data values are equal to b in indices </td></tr> <tr><td> IntegerHistogram </td><td> Data values are equal to b in indices </td></tr>
<tr><td> UserRangeHistogram </td><td> User provides lower and upp er bounds for linear range mapping from values to indices. </td></tr> <tr><td> UserRangeHistogram </td><td> User provides lower and upp er bounds for linear range mapping from values to indices. </td></tr>
<tr><td> AutoRangeHistogram </td><td> Range mapping bounds are de fiend by minimum and maximum of the data (2 passes needed!) </td></tr> <tr><td> AutoRangeHistogram </td><td> Range mapping bounds are de fiend by minimum and maximum of the data (2 passes needed!) </td></tr>
<tr><td> GlobalRangeHistogram &nbsp; </td><td> Likewise, but use gl obal min/max rather than region min/max as AutoRangeHistogram will </td></t r> <tr><td> GlobalRangeHistogram &nbsp; </td><td> Likewise, but use gl obal min/max rather than region min/max as AutoRangeHistogram will </td></t r>
skipping to change at line 366 skipping to change at line 420
typedef typename Select<T01, T02, T03, T04, T05, typedef typename Select<T01, T02, T03, T04, T05,
T06, T07, T08, T09, T10, T06, T07, T08, T09, T10,
T11, T12, T13, T14, T15, T11, T12, T13, T14, T15,
T16, T17, T18, T19, T20>::type type; T16, T17, T18, T19, T20>::type type;
}; };
struct AccumulatorBegin struct AccumulatorBegin
{ {
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("AccumulatorBegin (internal)"); return "AccumulatorBegin (internal)";
return n; // static const std::string n("AccumulatorBegin (internal)");
// return n;
} }
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{}; {};
}; };
struct AccumulatorEnd; struct AccumulatorEnd;
struct DataArgTag; struct DataArgTag;
struct WeightArgTag; struct WeightArgTag;
struct LabelArgTag; struct LabelArgTag;
struct CoordArgTag; struct CoordArgTag;
struct LabelDispatchTag; struct LabelDispatchTag;
template <class T, class TAG, class CHAIN>
struct HandleArgSelector; // find the correct handle in a CoupledHandle
struct Error__Global_statistics_are_only_defined_for_AccumulatorChainArray; struct Error__Global_statistics_are_only_defined_for_AccumulatorChainArray;
/** \brief Specifies index of labels in CoupledHandle. /** \brief Specifies index of labels in CoupledHandle.
LabelArg<INDEX> tells the acc::AccumulatorChainArray which index of the Handle contains the labels. (Note that coordinates are always index 0) LabelArg<INDEX> tells the acc::AccumulatorChainArray which index of the Handle contains the labels. (Note that coordinates are always index 0)
*/ */
template <int INDEX> template <int INDEX>
class LabelArg class LabelArg
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("LabelArg<") + asString(IN return std::string("LabelArg<") + asString(INDEX) + "> (internal)";
DEX) + "> (internal)"; // static const std::string n = std::string("LabelArg<") + asString
return n; (INDEX) + "> (internal)";
// return n;
} }
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef LabelArgTag Tag; typedef LabelArgTag Tag;
typedef void value_type; typedef void value_type;
typedef void result_type; typedef void result_type;
skipping to change at line 422 skipping to change at line 481
static const unsigned int workInPass = 0; static const unsigned int workInPass = 0;
}; };
}; };
template <int INDEX> template <int INDEX>
class CoordArg class CoordArg
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("CoordArg<") + asString(IN return std::string("CoordArg<") + asString(INDEX) + "> (internal)";
DEX) + "> (internal)"; // static const std::string n = std::string("CoordArg<") + asString
return n; (INDEX) + "> (internal)";
// return n;
} }
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef CoordArgTag Tag; typedef CoordArgTag Tag;
typedef void value_type; typedef void value_type;
typedef void result_type; typedef void result_type;
skipping to change at line 462 skipping to change at line 522
template <class TAG, class A> template <class TAG, class A>
typename LookupTag<TAG, A>::reference typename LookupTag<TAG, A>::reference
getAccumulator(A & a); getAccumulator(A & a);
template <class TAG, class A> template <class TAG, class A>
typename LookupDependency<TAG, A>::result_type typename LookupDependency<TAG, A>::result_type
getDependency(A const & a); getDependency(A const & a);
#endif #endif
namespace detail { namespace acc_detail {
/************************************************************************** **/ /************************************************************************** **/
/* */ /* */
/* internal tag handling meta-functions */ /* internal tag handling meta-functions */
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
// we must make sure that Arg<INDEX> tags are at the end of the chain b ecause // we must make sure that Arg<INDEX> tags are at the end of the chain b ecause
// all other tags potentially depend on them // all other tags potentially depend on them
template <class T> template <class T>
skipping to change at line 592 skipping to change at line 652
{ {
typedef SeparateGlobalAndRegionTags<TAIL> Inner; typedef SeparateGlobalAndRegionTags<TAIL> Inner;
typedef TypeList<DataArg<INDEX>, typename Inner::RegionTags> RegionTag s; typedef TypeList<DataArg<INDEX>, typename Inner::RegionTags> RegionTag s;
typedef TypeList<DataArg<INDEX>, typename Inner::GlobalTags> GlobalTag s; typedef TypeList<DataArg<INDEX>, typename Inner::GlobalTags> GlobalTag s;
}; };
template <int INDEX, class TAIL> template <int INDEX, class TAIL>
struct SeparateGlobalAndRegionTags<TypeList<LabelArg<INDEX>, TAIL> > struct SeparateGlobalAndRegionTags<TypeList<LabelArg<INDEX>, TAIL> >
{ {
typedef SeparateGlobalAndRegionTags<TAIL> Inner; typedef SeparateGlobalAndRegionTags<TAIL> Inner;
typedef typename Inner::RegionTags RegionTags; typedef TypeList<LabelArg<INDEX>, typename Inner::RegionTags> RegionTa gs;
typedef TypeList<LabelArg<INDEX>, typename Inner::GlobalTags> GlobalTa gs; typedef TypeList<LabelArg<INDEX>, typename Inner::GlobalTags> GlobalTa gs;
}; };
template <int INDEX, class TAIL> template <int INDEX, class TAIL>
struct SeparateGlobalAndRegionTags<TypeList<WeightArg<INDEX>, TAIL> > struct SeparateGlobalAndRegionTags<TypeList<WeightArg<INDEX>, TAIL> >
{ {
typedef SeparateGlobalAndRegionTags<TAIL> Inner; typedef SeparateGlobalAndRegionTags<TAIL> Inner;
typedef TypeList<WeightArg<INDEX>, typename Inner::RegionTags> RegionT ags; typedef TypeList<WeightArg<INDEX>, typename Inner::RegionTags> RegionT ags;
typedef TypeList<WeightArg<INDEX>, typename Inner::GlobalTags> GlobalT ags; typedef TypeList<WeightArg<INDEX>, typename Inner::GlobalTags> GlobalT ags;
}; };
skipping to change at line 657 skipping to change at line 717
template <class T> template <class T>
struct ApplyVisitorToTag; struct ApplyVisitorToTag;
template <class HEAD, class TAIL> template <class HEAD, class TAIL>
struct ApplyVisitorToTag<TypeList<HEAD, TAIL> > struct ApplyVisitorToTag<TypeList<HEAD, TAIL> >
{ {
template <class Accu, class Visitor> template <class Accu, class Visitor>
static bool exec(Accu & a, std::string const & tag, Visitor const & v) static bool exec(Accu & a, std::string const & tag, Visitor const & v)
{ {
static const std::string name = normalizeString(HEAD::name()); static std::string * name = VIGRA_SAFE_STATIC(name, new std::string
if(name == tag) (normalizeString(HEAD::name())));
if(*name == tag)
{ {
v.template exec<HEAD>(a); v.template exec<HEAD>(a);
return true; return true;
} }
else else
{ {
return ApplyVisitorToTag<TAIL>::exec(a, tag, v); return ApplyVisitorToTag<TAIL>::exec(a, tag, v);
} }
} }
}; };
skipping to change at line 849 skipping to change at line 909
template <unsigned, class U> template <unsigned, class U>
void pass(U const &) void pass(U const &)
{} {}
template <unsigned, class U> template <unsigned, class U>
void pass(U const &, double) void pass(U const &, double)
{} {}
template <class U> template <class U>
void merge(U const &) void mergeImpl(U const &)
{} {}
template <class U> template <class U>
void resize(U const &) void resize(U const &)
{} {}
template <class U>
void setCoordinateOffsetImpl(U const &)
{}
void activate() void activate()
{} {}
bool isActive() const bool isActive() const
{ {
return false; return false;
} }
template <class Flags> template <class Flags>
static void activateImpl(Flags &) static void activateImpl(Flags &)
skipping to change at line 949 skipping to change at line 1013
static void exec(A & a, T const & t, double weight) static void exec(A & a, T const & t, double weight)
{ {
a.update(t, weight); a.update(t, weight);
} }
static typename A::result_type get(A const & a) static typename A::result_type get(A const & a)
{ {
return a(); return a();
} }
static void merge(A & a, A const & o) static void mergeImpl(A & a, A const & o)
{ {
a += o; a += o;
} }
template <class T> template <class T>
static void resize(A & a, T const & t) static void resize(A & a, T const & t)
{ {
a.reshape(t); a.reshape(t);
} }
static void applyHistogramOptions(A & a, HistogramOptions const & optio ns) static void applyHistogramOptions(A & a, HistogramOptions const & optio ns)
{ {
ApplyHistogramOptions<typename A::Tag>::exec(a, options); ApplyHistogramOptions<typename A::Tag>::exec(a, options);
} }
static unsigned int passesRequired() static unsigned int passesRequired()
{ {
static const unsigned int A_workInPass = A::workInPass; static const unsigned int A_workInPass = A::workInPass;
return std::max(A_workInPass, A::InternalBaseType::passesRequired()) ; return std::max(A_workInPass, A::InternalBaseType::passesRequired() );
} }
}; };
template <class A, unsigned CurrentPass> template <class A, unsigned CurrentPass>
struct DecoratorImpl<A, CurrentPass, true, CurrentPass> struct DecoratorImpl<A, CurrentPass, true, CurrentPass>
{ {
static bool isActive(A const & a) static bool isActive(A const & a)
{ {
return A::isActiveImpl(getAccumulator<AccumulatorEnd>(a).active_acc umulators_); return A::isActiveImpl(getAccumulator<AccumulatorEnd>(a).active_acc umulators_);
} }
skipping to change at line 996 skipping to change at line 1060
template <class T> template <class T>
static void exec(A & a, T const & t, double weight) static void exec(A & a, T const & t, double weight)
{ {
if(isActive(a)) if(isActive(a))
a.update(t, weight); a.update(t, weight);
} }
static typename A::result_type get(A const & a) static typename A::result_type get(A const & a)
{ {
static const std::string message = std::string("get(accumulator): a if(!isActive(a))
ttempt to access inactive statistic '") + {
std::string message = std::string("get(accumulator): attempt to
typeid(typename A::Tag).name() + "'."; access inactive statistic '") +
vigra_precondition(isActive(a), message); A::Tag::name() + "'.";
vigra_precondition(false, message);
}
return a(); return a();
} }
static void merge(A & a, A const & o) static void mergeImpl(A & a, A const & o)
{ {
if(isActive(a)) if(isActive(a))
a += o; a += o;
} }
template <class T> template <class T>
static void resize(A & a, T const & t) static void resize(A & a, T const & t)
{ {
if(isActive(a)) if(isActive(a))
a.reshape(t); a.reshape(t);
skipping to change at line 1053 skipping to change at line 1120
{ {
MultiArray<N, T, Alloc>(s, initial).swap(a); MultiArray<N, T, Alloc>(s, initial).swap(a);
} }
template <class T, class Alloc, class Shape> template <class T, class Alloc, class Shape>
void reshapeImpl(Matrix<T, Alloc> & a, Shape const & s, T const & initial = T()) void reshapeImpl(Matrix<T, Alloc> & a, Shape const & s, T const & initial = T())
{ {
Matrix<T, Alloc>(s, initial).swap(a); Matrix<T, Alloc>(s, initial).swap(a);
} }
template <class T, class U>
void copyShapeImpl(T const &, U const &) // to be used for scalars and st
atic arrays
{}
template <unsigned int N, class T, class Alloc, class U>
void copyShapeImpl(MultiArray<N, T, Alloc> const & from, U & to)
{
to.reshape(from.shape());
}
template <class T, class Alloc, class U>
void copyShapeImpl(Matrix<T, Alloc> const & from, U & to)
{
to.reshape(from.shape());
}
template <class T, class U>
bool hasDataImpl(T const &) // to be used for scalars and static arrays
{
return true;
}
template <unsigned int N, class T, class Stride>
bool hasDataImpl(MultiArrayView<N, T, Stride> const & a)
{
return a.hasData();
}
// generic functions to create suitable shape objects from various inpu t data types // generic functions to create suitable shape objects from various inpu t data types
template <unsigned int N, class T, class Stride> template <unsigned int N, class T, class Stride>
inline typename MultiArrayShape<N>::type inline typename MultiArrayShape<N>::type
shapeOf(MultiArrayView<N, T, Stride> const & a) shapeOf(MultiArrayView<N, T, Stride> const & a)
{ {
return a.shape(); return a.shape();
} }
template <class T, int N> template <class T, int N>
inline Shape1 inline Shape1
skipping to change at line 1126 skipping to change at line 1221
typedef LabelDispatch const & const_reference; typedef LabelDispatch const & const_reference;
typedef GlobalAccumulatorChain InternalBaseType; typedef GlobalAccumulatorChain InternalBaseType;
typedef T const & argument_type; typedef T const & argument_type;
typedef argument_type first_argument_type; typedef argument_type first_argument_type;
typedef double second_argument_type; typedef double second_argument_type;
typedef RegionAccumulatorChain & result_type; typedef RegionAccumulatorChain & result_type;
static const int index = GlobalAccumulatorChain::index + 1; static const int index = GlobalAccumulatorChain::index + 1;
GlobalAccumulatorChain next_;
RegionAccumulatorArray regions_;
HistogramOptions region_histogram_options_;
MultiArrayIndex ignore_label_;
ActiveFlagsType active_region_accumulators_;
template <class IndexDefinition, class TagFound=typename IndexDefinitio n::Tag> template <class IndexDefinition, class TagFound=typename IndexDefinitio n::Tag>
struct LabelIndexSelector struct CoordIndexSelector
{ {
static const int value = 2; // default: CoupledHandle holds labels static const int value = 0; // default: CoupledHandle holds coordin
at index 2 ates at index 0
template <class U, class NEXT>
static MultiArrayIndex exec(CoupledHandle<U, NEXT> const & t)
{
return (MultiArrayIndex)get<value>(t);
}
}; };
template <class IndexDefinition> template <class IndexDefinition>
struct LabelIndexSelector<IndexDefinition, LabelArgTag> struct CoordIndexSelector<IndexDefinition, CoordArgTag>
{ {
static const int value = IndexDefinition::value; static const int value = IndexDefinition::value;
template <class U, class NEXT>
static MultiArrayIndex exec(CoupledHandle<U, NEXT> const & t)
{
return (MultiArrayIndex)get<value>(t);
}
}; };
static const int coordIndex = CoordIndexSelector<typename LookupTag<Coo
rdArgTag, GlobalAccumulatorChain>::type>::value;
static const int coordSize = CoupledHandleCast<coordIndex, T>::type::v
alue_type::static_size;
typedef TinyVector<double, coordSize> CoordinateType;
GlobalAccumulatorChain next_;
RegionAccumulatorArray regions_;
HistogramOptions region_histogram_options_;
MultiArrayIndex ignore_label_;
ActiveFlagsType active_region_accumulators_;
CoordinateType coordinateOffset_;
template <class TAG> template <class TAG>
struct ActivateImpl struct ActivateImpl
{ {
typedef typename LookupTag<TAG, type>::type TargetAccumulator; typedef typename LookupTag<TAG, type>::type TargetAccumulator;
static void activate(GlobalAccumulatorChain & globals, RegionAccumu latorArray & regions, static void activate(GlobalAccumulatorChain & globals, RegionAccumu latorArray & regions,
ActiveFlagsType & flags) ActiveFlagsType & flags)
{ {
TargetAccumulator::template activateImpl<LabelDispatch>( TargetAccumulator::template activateImpl<LabelDispatch>(
flags, getAccumulator<AccumulatorEnd>(globals).active _accumulators_); flags, getAccumulator<AccumulatorEnd>(globals).active _accumulators_);
skipping to change at line 1202 skipping to change at line 1290
{ {
static void activate(GlobalAccumulatorChain &, RegionAccumulatorArr ay &, ActiveFlagsType &) static void activate(GlobalAccumulatorChain &, RegionAccumulatorArr ay &, ActiveFlagsType &)
{} {}
static bool isActive(GlobalAccumulatorChain const & globals, Active FlagsType const &) static bool isActive(GlobalAccumulatorChain const & globals, Active FlagsType const &)
{ {
return getAccumulator<LabelArg<INDEX> >(globals).isActive(); return getAccumulator<LabelArg<INDEX> >(globals).isActive();
} }
}; };
typedef typename LookupTag<LabelArgTag, GlobalAccumulatorChain>::type F
indLabelIndex;
LabelDispatch() LabelDispatch()
: next_(), : next_(),
regions_(), regions_(),
region_histogram_options_(), region_histogram_options_(),
ignore_label_(-1), ignore_label_(-1),
active_region_accumulators_() active_region_accumulators_()
{} {}
LabelDispatch(LabelDispatch const & o) LabelDispatch(LabelDispatch const & o)
: next_(o.next_), : next_(o.next_),
skipping to change at line 1241 skipping to change at line 1327
{ {
if(maxRegionLabel() == (MultiArrayIndex)maxlabel) if(maxRegionLabel() == (MultiArrayIndex)maxlabel)
return; return;
unsigned int oldSize = regions_.size(); unsigned int oldSize = regions_.size();
regions_.resize(maxlabel + 1); regions_.resize(maxlabel + 1);
for(unsigned int k=oldSize; k<regions_.size(); ++k) for(unsigned int k=oldSize; k<regions_.size(); ++k)
{ {
getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulato r(&next_); getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulato r(&next_);
getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators _ = active_region_accumulators_; getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators _ = active_region_accumulators_;
regions_[k].applyHistogramOptions(region_histogram_options_); regions_[k].applyHistogramOptions(region_histogram_options_);
regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
} }
} }
void ignoreLabel(MultiArrayIndex l) void ignoreLabel(MultiArrayIndex l)
{ {
ignore_label_ = l; ignore_label_ = l;
} }
MultiArrayIndex ignoredLabel() const
{
return ignore_label_;
}
void applyHistogramOptions(HistogramOptions const & options) void applyHistogramOptions(HistogramOptions const & options)
{ {
applyHistogramOptions(options, options); applyHistogramOptions(options, options);
} }
void applyHistogramOptions(HistogramOptions const & regionoptions, Hist void applyHistogramOptions(HistogramOptions const & regionoptions,
ogramOptions const & globaloptions) HistogramOptions const & globaloptions)
{ {
region_histogram_options_ = regionoptions; region_histogram_options_ = regionoptions;
for(unsigned int k=0; k<regions_.size(); ++k)
{
regions_[k].applyHistogramOptions(region_histogram_options_);
}
next_.applyHistogramOptions(globaloptions); next_.applyHistogramOptions(globaloptions);
} }
void setCoordinateOffsetImpl(CoordinateType const & offset)
{
coordinateOffset_ = offset;
for(unsigned int k=0; k<regions_.size(); ++k)
{
regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
}
next_.setCoordinateOffsetImpl(coordinateOffset_);
}
void setCoordinateOffsetImpl(MultiArrayIndex k, CoordinateType const &
offset)
{
vigra_precondition(0 <= k && k < (MultiArrayIndex)regions_.size(),
"Accumulator::setCoordinateOffset(k, offset): region k does no
t exist.");
regions_[k].setCoordinateOffsetImpl(offset);
}
template <class U> template <class U>
void resize(U const & t) void resize(U const & t)
{ {
if(regions_.size() == 0) if(regions_.size() == 0)
{ {
static const int labelIndex = LabelIndexSelector<FindLabelIndex typedef HandleArgSelector<U, LabelArgTag, GlobalAccumulatorChai
>::value; n> LabelHandle;
typedef typename CoupledHandleCast<labelIndex, T>::type LabelHa
ndle;
typedef typename LabelHandle::value_type LabelType; typedef typename LabelHandle::value_type LabelType;
typedef MultiArrayView<LabelHandle::dimensions, LabelType, Stri typedef MultiArrayView<LabelHandle::size, LabelType, StridedArr
dedArrayTag> LabelArray; ayTag> LabelArray;
LabelArray labelArray(t.shape(), cast<labelIndex>(t).strides(), LabelArray labelArray(t.shape(), LabelHandle::getHandle(t).stri
const_cast<LabelType *>(cast<labelIndex>(t).ptr())); des(),
const_cast<LabelType *>(LabelHandle::getH
andle(t).ptr()));
LabelType minimum, maximum; LabelType minimum, maximum;
labelArray.minmax(&minimum, &maximum); labelArray.minmax(&minimum, &maximum);
setMaxRegionLabel(maximum); setMaxRegionLabel(maximum);
} }
next_.resize(t); next_.resize(t);
// FIXME: only call resize when label k actually exists? // FIXME: only call resize when label k actually exists?
for(unsigned int k=0; k<regions_.size(); ++k) for(unsigned int k=0; k<regions_.size(); ++k)
regions_[k].resize(t); regions_[k].resize(t);
} }
template <unsigned N> template <unsigned N>
void pass(T const & t) void pass(T const & t)
{ {
if(LabelIndexSelector<FindLabelIndex>::exec(t) != ignore_label_) typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> L
abelHandle;
if(LabelHandle::getValue(t) != ignore_label_)
{ {
next_.template pass<N>(t); next_.template pass<N>(t);
regions_[LabelIndexSelector<FindLabelIndex>::exec(t)].template pass<N>(t); regions_[LabelHandle::getValue(t)].template pass<N>(t);
} }
} }
template <unsigned N> template <unsigned N>
void pass(T const & t, double weight) void pass(T const & t, double weight)
{ {
if(LabelIndexSelector<FindLabelIndex>::exec(t) != ignore_label_) typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> L
abelHandle;
if(LabelHandle::getValue(t) != ignore_label_)
{ {
next_.template pass<N>(t, weight); next_.template pass<N>(t, weight);
regions_[LabelIndexSelector<FindLabelIndex>::exec(t)].template pass<N>(t, weight); regions_[LabelHandle::getValue(t)].template pass<N>(t, weight);
} }
} }
static unsigned int passesRequired() static unsigned int passesRequired()
{ {
return std::max(GlobalAccumulatorChain::passesRequired(), RegionAcc umulatorChain::passesRequired()); return std::max(GlobalAccumulatorChain::passesRequired(), RegionAcc umulatorChain::passesRequired());
} }
unsigned int passesRequiredDynamic() const unsigned int passesRequiredDynamic() const
{ {
skipping to change at line 1343 skipping to change at line 1459
for(unsigned int k=0; k<regions_.size(); ++k) for(unsigned int k=0; k<regions_.size(); ++k)
getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators _.set(); getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators _.set();
} }
template <class TAG> template <class TAG>
bool isActive() const bool isActive() const
{ {
return ActivateImpl<TAG>::isActive(next_, active_region_accumulator s_); return ActivateImpl<TAG>::isActive(next_, active_region_accumulator s_);
} }
void merge(LabelDispatch const & o) void mergeImpl(LabelDispatch const & o)
{ {
for(unsigned int k=0; k<regions_.size(); ++k) for(unsigned int k=0; k<regions_.size(); ++k)
regions_[k].merge(o.regions_[k]); regions_[k].mergeImpl(o.regions_[k]);
next_.merge(o.next_); next_.mergeImpl(o.next_);
} }
void merge(unsigned i, unsigned j) void mergeImpl(unsigned i, unsigned j)
{ {
regions_[i].merge(regions_[j]); regions_[i].mergeImpl(regions_[j]);
regions_[j].reset(); regions_[j].reset();
getAccumulator<AccumulatorEnd>(regions_[j]).active_accumulators_ = active_region_accumulators_; getAccumulator<AccumulatorEnd>(regions_[j]).active_accumulators_ = active_region_accumulators_;
} }
template <class ArrayLike> template <class ArrayLike>
void merge(LabelDispatch const & o, ArrayLike const & labelMapping) void mergeImpl(LabelDispatch const & o, ArrayLike const & labelMapping)
{ {
MultiArrayIndex newMaxLabel = std::max<MultiArrayIndex>(maxRegionLa bel(), *argMax(labelMapping.begin(), labelMapping.end())); MultiArrayIndex newMaxLabel = std::max<MultiArrayIndex>(maxRegionLa bel(), *argMax(labelMapping.begin(), labelMapping.end()));
setMaxRegionLabel(newMaxLabel); setMaxRegionLabel(newMaxLabel);
for(unsigned int k=0; k<labelMapping.size(); ++k) for(unsigned int k=0; k<labelMapping.size(); ++k)
regions_[labelMapping[k]].merge(o.regions_[k]); regions_[labelMapping[k]].mergeImpl(o.regions_[k]);
next_.merge(o.next_); next_.mergeImpl(o.next_);
} }
}; };
template <class TargetTag, class TagList> template <class TargetTag, class TagList>
struct FindNextTag; struct FindNextTag;
template <class TargetTag, class HEAD, class TAIL> template <class TargetTag, class HEAD, class TAIL>
struct FindNextTag<TargetTag, TypeList<HEAD, TAIL> > struct FindNextTag<TargetTag, TypeList<HEAD, TAIL> >
{ {
typedef typename FindNextTag<TargetTag, TAIL>::type type; typedef typename FindNextTag<TargetTag, TAIL>::type type;
skipping to change at line 1450 skipping to change at line 1566
static std::string name() static std::string name()
{ {
return TAG::name(); return TAG::name();
} }
template <class ActiveFlags> template <class ActiveFlags>
static void activateImpl(ActiveFlags & flags) static void activateImpl(ActiveFlags & flags)
{ {
flags.template set<index>(); flags.template set<index>();
typedef typename StandardizeDependencies<Tag>::type StdDeps; typedef typename StandardizeDependencies<Tag>::type StdDeps;
detail::ActivateDependencies<StdDeps>::template exec<ThisType>( flags); acc_detail::ActivateDependencies<StdDeps>::template exec<ThisTy pe>(flags);
} }
template <class Accu, class ActiveFlags, class GlobalFlags> template <class Accu, class ActiveFlags, class GlobalFlags>
static void activateImpl(ActiveFlags & flags, GlobalFlags & gflags) static void activateImpl(ActiveFlags & flags, GlobalFlags & gflags)
{ {
flags.template set<index>(); flags.template set<index>();
typedef typename StandardizeDependencies<Tag>::type StdDeps; typedef typename StandardizeDependencies<Tag>::type StdDeps;
detail::ActivateDependencies<StdDeps>::template exec<Accu>(flag s, gflags); acc_detail::ActivateDependencies<StdDeps>::template exec<Accu>( flags, gflags);
} }
template <class ActiveFlags> template <class ActiveFlags>
static bool isActiveImpl(ActiveFlags & flags) static bool isActiveImpl(ActiveFlags & flags)
{ {
return flags.template test<index>(); return flags.template test<index>();
} }
void setDirty() const void setDirty() const
{ {
skipping to change at line 1504 skipping to change at line 1620
template <int INDEX> template <int INDEX>
bool isDirtyImpl() const bool isDirtyImpl() const
{ {
return next_.template isDirtyImpl<INDEX>(); return next_.template isDirtyImpl<INDEX>();
} }
void reset() void reset()
{} {}
template <class Shape> template <class Shape>
void setCoordinateOffset(Shape const &)
{}
template <class Shape>
void reshape(Shape const &) void reshape(Shape const &)
{} {}
void operator+=(AccumulatorBase const &) void operator+=(AccumulatorBase const &)
{} {}
template <class U> template <class U>
void update(U const &) void update(U const &)
{} {}
skipping to change at line 1541 skipping to change at line 1661
// * ensure that each accumulator is only called in its desired pa ss as defined in A::workInPass // * ensure that each accumulator is only called in its desired pa ss as defined in A::workInPass
// * determine how many passes through the data are required // * determine how many passes through the data are required
struct Accumulator struct Accumulator
: public AccumulatorImpl : public AccumulatorImpl
{ {
typedef Accumulator type; typedef Accumulator type;
typedef Accumulator & reference; typedef Accumulator & reference;
typedef Accumulator const & const_reference; typedef Accumulator const & const_reference;
typedef AccumulatorImpl A; typedef AccumulatorImpl A;
static const unsigned int workInPass = A::workInPass; static const unsigned int workInPass = A::workInPass;
static const bool allowRuntimeActivation = CONFIG::allowRuntimeActi vation; static const bool allowRuntimeActivation = CONFIG::allowRuntimeActi vation;
template <class T> template <class T>
void resize(T const & t) void resize(T const & t)
{ {
this->next_.resize(t); this->next_.resize(t);
DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>: :resize(*this, t); DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>: :resize(*this, t);
} }
void reset() void reset()
skipping to change at line 1576 skipping to change at line 1696
DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*th is, t); DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*th is, t);
} }
template <unsigned N, class T> template <unsigned N, class T>
void pass(T const & t, double weight) void pass(T const & t, double weight)
{ {
this->next_.template pass<N>(t, weight); this->next_.template pass<N>(t, weight);
DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*th is, t, weight); DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*th is, t, weight);
} }
void merge(Accumulator const & o) void mergeImpl(Accumulator const & o)
{ {
DecoratorImpl<Accumulator, Accumulator::workInPass, allowRuntim DecoratorImpl<Accumulator, Accumulator::workInPass, allowRuntim
eActivation>::merge(*this, o); eActivation>::mergeImpl(*this, o);
this->next_.merge(o.next_); this->next_.mergeImpl(o.next_);
} }
void applyHistogramOptions(HistogramOptions const & options) void applyHistogramOptions(HistogramOptions const & options)
{ {
DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>: :applyHistogramOptions(*this, options); DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>: :applyHistogramOptions(*this, options);
this->next_.applyHistogramOptions(options); this->next_.applyHistogramOptions(options);
} }
template <class SHAPE>
void setCoordinateOffsetImpl(SHAPE const & offset)
{
this->setCoordinateOffset(offset);
this->next_.setCoordinateOffsetImpl(offset);
}
static unsigned int passesRequired() static unsigned int passesRequired()
{ {
return DecoratorImpl<Accumulator, workInPass, allowRuntimeActiv ation>::passesRequired(); return DecoratorImpl<Accumulator, workInPass, allowRuntimeActiv ation>::passesRequired();
} }
template <class ActiveFlags> template <class ActiveFlags>
static unsigned int passesRequired(ActiveFlags const & flags) static unsigned int passesRequired(ActiveFlags const & flags)
{ {
return DecoratorImpl<Accumulator, workInPass, allowRuntimeActiv ation>::passesRequired(flags); return DecoratorImpl<Accumulator, workInPass, allowRuntimeActiv ation>::passesRequired(flags);
} }
skipping to change at line 1673 skipping to change at line 1800
{} {}
type const * pointer_; type const * pointer_;
}; };
typedef typename ConfigureAccumulatorChain<T, RegionTags, dynamic, Glob alAccumulatorHandle>::type RegionAccumulatorChain; typedef typename ConfigureAccumulatorChain<T, RegionTags, dynamic, Glob alAccumulatorHandle>::type RegionAccumulatorChain;
typedef LabelDispatch<T, GlobalAccumulatorChain, RegionAccumulatorChain > type; typedef LabelDispatch<T, GlobalAccumulatorChain, RegionAccumulatorChain > type;
}; };
} // namespace detail } // namespace acc_detail
/************************************************************************** **/ /************************************************************************** **/
/* */ /* */
/* accumulator chain */ /* accumulator chain */
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
// Implement the high-level interface of an accumulator chain // Implement the high-level interface of an accumulator chain
template <class T, class NEXT> template <class T, class NEXT>
class AccumulatorChainImpl class AccumulatorChainImpl
skipping to change at line 1720 skipping to change at line 1847
next_.applyHistogramOptions(options); next_.applyHistogramOptions(options);
} }
/** Set regional and global options for all histograms in the accumulat or chain. /** Set regional and global options for all histograms in the accumulat or chain.
*/ */
void setHistogramOptions(HistogramOptions const & regionoptions, Histog ramOptions const & globaloptions) void setHistogramOptions(HistogramOptions const & regionoptions, Histog ramOptions const & globaloptions)
{ {
next_.applyHistogramOptions(regionoptions, globaloptions); next_.applyHistogramOptions(regionoptions, globaloptions);
} }
/** Set an offset for <tt>Coord<...></tt> statistics.
If the offset is non-zero, coordinate statistics such as <tt>Region
Center</tt> are computed
in the global coordinate system defined by the \a offset. Without a
n offset, these statistics
are computed in the local coordinate system of the current region o
f interest.
*/
template <class SHAPE>
void setCoordinateOffset(SHAPE const & offset)
{
next_.setCoordinateOffsetImpl(offset);
}
/** Reset current_pass_ of the accumulator chain to 'reset_to_pass'. /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'.
*/ */
void reset(unsigned int reset_to_pass = 0) void reset(unsigned int reset_to_pass = 0)
{ {
current_pass_ = reset_to_pass; current_pass_ = reset_to_pass;
if(reset_to_pass == 0) if(reset_to_pass == 0)
next_.reset(); next_.reset();
} }
template <unsigned N> template <unsigned N>
void update(T const & t) void update(T const & t)
{ {
if(current_pass_ == N) if(current_pass_ == N)
{ {
next_.template pass<N>(t); next_.template pass<N>(t);
} }
else if(current_pass_ < N) else if(current_pass_ < N)
{ {
current_pass_ = N; current_pass_ = N;
if(N == 1) if(N == 1)
next_.resize(detail::shapeOf(t)); next_.resize(acc_detail::shapeOf(t));
next_.template pass<N>(t); next_.template pass<N>(t);
} }
else else
{ {
std::string message("AccumulatorChain::update(): cannot return to pass "); std::string message("AccumulatorChain::update(): cannot return to pass ");
message << N << " after working on pass " << current_pass_ << " ."; message << N << " after working on pass " << current_pass_ << " .";
vigra_precondition(false, message); vigra_precondition(false, message);
} }
} }
skipping to change at line 1762 skipping to change at line 1901
void update(T const & t, double weight) void update(T const & t, double weight)
{ {
if(current_pass_ == N) if(current_pass_ == N)
{ {
next_.template pass<N>(t, weight); next_.template pass<N>(t, weight);
} }
else if(current_pass_ < N) else if(current_pass_ < N)
{ {
current_pass_ = N; current_pass_ = N;
if(N == 1) if(N == 1)
next_.resize(detail::shapeOf(t)); next_.resize(acc_detail::shapeOf(t));
next_.template pass<N>(t, weight); next_.template pass<N>(t, weight);
} }
else else
{ {
std::string message("AccumulatorChain::update(): cannot return to pass "); std::string message("AccumulatorChain::update(): cannot return to pass ");
message << N << " after working on pass " << current_pass_ << " ."; message << N << " after working on pass " << current_pass_ << " .";
vigra_precondition(false, message); vigra_precondition(false, message);
} }
} }
skipping to change at line 1784 skipping to change at line 1923
*/ */
void operator+=(AccumulatorChainImpl const & o) void operator+=(AccumulatorChainImpl const & o)
{ {
merge(o); merge(o);
} }
/** Merge the accumulator chain with accumulator chain 'o'. This only w orks if all selected statistics in the accumulator chain support the '+=' o perator. See the documentations of the particular statistics for support in formation. /** Merge the accumulator chain with accumulator chain 'o'. This only w orks if all selected statistics in the accumulator chain support the '+=' o perator. See the documentations of the particular statistics for support in formation.
*/ */
void merge(AccumulatorChainImpl const & o) void merge(AccumulatorChainImpl const & o)
{ {
next_.merge(o.next_); next_.mergeImpl(o.next_);
} }
result_type operator()() const result_type operator()() const
{ {
return next_.get(); return next_.get();
} }
void operator()(T const & t) void operator()(T const & t)
{ {
update<1>(t); update<1>(t);
skipping to change at line 1886 skipping to change at line 2025
typedef double WeightType; typedef double WeightType;
typedef vigra::CoupledIteratorType<dim, DataType, WeightType>::HandleTy pe Handle; typedef vigra::CoupledIteratorType<dim, DataType, WeightType>::HandleTy pe Handle;
AccumulatorChain<Handle, Select<DataArg<1>, WeightArg<2>, Mean,...> > a ; AccumulatorChain<Handle, Select<DataArg<1>, WeightArg<2>, Mean,...> > a ;
\endcode \endcode
See \ref FeatureAccumulators for more information and examples of use. See \ref FeatureAccumulators for more information and examples of use.
*/ */
template <class T, class Selected, bool dynamic=false> template <class T, class Selected, bool dynamic=false>
class AccumulatorChain class AccumulatorChain
#ifndef DOXYGEN // hide AccumulatorChainImpl from documentation #ifndef DOXYGEN // hide AccumulatorChainImpl from documentation
: public AccumulatorChainImpl<T, typename detail::ConfigureAccumulatorChain <T, Selected, dynamic>::type> : public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorC hain<T, Selected, dynamic>::type>
#endif #endif
{ {
public: public:
// \brief TypeList of Tags in the accumulator chain (?). // \brief TypeList of Tags in the accumulator chain (?).
typedef typename detail::ConfigureAccumulatorChain<T, Selected, dynamic >::TagList AccumulatorTags; typedef typename acc_detail::ConfigureAccumulatorChain<T, Selected, dyn amic>::TagList AccumulatorTags;
/** Before having seen data (current_pass_==0), the shape of the data c an be changed... (?) /** Before having seen data (current_pass_==0), the shape of the data c an be changed... (?)
*/ */
template <class U, int N> template <class U, int N>
void reshape(TinyVector<U, N> const & s) void reshape(TinyVector<U, N> const & s)
{ {
vigra_precondition(this->current_pass_ == 0, vigra_precondition(this->current_pass_ == 0,
"AccumulatorChain::reshape(): cannot reshape after seeing data . Call AccumulatorChain::reset() first."); "AccumulatorChain::reshape(): cannot reshape after seeing data . Call AccumulatorChain::reset() first.");
this->next_.resize(s); this->next_.resize(s);
this->current_pass_ = 1; this->current_pass_ = 1;
} }
/** Return the names of all tags in the accumulator chain (selected sta tistics and their dependencies). /** Return the names of all tags in the accumulator chain (selected sta tistics and their dependencies).
*/ */
static ArrayVector<std::string> const & tagNames() static ArrayVector<std::string> const & tagNames()
{ {
static const ArrayVector<std::string> n = collectTagNames(); static ArrayVector<std::string> * n = VIGRA_SAFE_STATIC(n, new Arra
return n; yVector<std::string>(collectTagNames()));
return *n;
} }
#ifdef DOXYGEN // hide AccumulatorChainImpl from documentation #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
/** Set options for all histograms in the accumulator chain. See histogra m accumulators for possible options. The function is ignored if there is no histogram in the accumulator chain. /** Set options for all histograms in the accumulator chain. See histogra m accumulators for possible options. The function is ignored if there is no histogram in the accumulator chain.
*/ */
void setHistogramOptions(HistogramOptions const & options); void setHistogramOptions(HistogramOptions const & options);
/** Set an offset for <tt>Coord<...></tt> statistics.
If the offset is non-zero, coordinate statistics such as <tt>RegionCe
nter</tt> are computed
in the global coordinate system defined by the \a offset. Without an
offset, these statistics
are computed in the local coordinate system of the current region of
interest.
*/
template <class SHAPE>
void setCoordinateOffset(SHAPE const & offset);
/** Reset current_pass_ of the accumulator chain to 'reset_to_pass'. */ /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'. */
void reset(unsigned int reset_to_pass = 0); void reset(unsigned int reset_to_pass = 0);
/** Equivalent to merge(o) . */ /** Equivalent to merge(o) . */
void operator+=(AccumulatorChainImpl const & o); void operator+=(AccumulatorChainImpl const & o);
/** Merge the accumulator chain with accumulator chain 'o'. This only wor ks if all selected statistics in the accumulator chain support the '+=' ope rator. See the documentations of the particular statistics for support info rmation. /** Merge the accumulator chain with accumulator chain 'o'. This only wor ks if all selected statistics in the accumulator chain support the '+=' ope rator. See the documentations of the particular statistics for support info rmation.
*/ */
void merge(AccumulatorChainImpl const & o); void merge(AccumulatorChainImpl const & o);
skipping to change at line 1946 skipping to change at line 2094
/** Return the number of passes required to compute all statistics in the accumulator chain. /** Return the number of passes required to compute all statistics in the accumulator chain.
*/ */
unsigned int passesRequired() const; unsigned int passesRequired() const;
#endif #endif
private: private:
static ArrayVector<std::string> collectTagNames() static ArrayVector<std::string> collectTagNames()
{ {
ArrayVector<std::string> n; ArrayVector<std::string> n;
detail::CollectAccumulatorNames<AccumulatorTags>::exec(n); acc_detail::CollectAccumulatorNames<AccumulatorTags>::exec(n);
std::sort(n.begin(), n.end()); std::sort(n.begin(), n.end());
return n; return n;
} }
}; };
template <unsigned int N, class T1, class T2, class T3, class T4, class T5,
class Selected, bool dynamic>
class AccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dyna
mic>
: public AccumulatorChain<typename CoupledArrays<N, T1, T2, T3, T4, T5>::Ha
ndleType, Selected, dynamic>
{};
// Create a dynamic accumulator chain containing the Selected statistic s and their dependencies. // Create a dynamic accumulator chain containing the Selected statistic s and their dependencies.
// Statistics will only be computed if activate<Tag>() is called at run time. // Statistics will only be computed if activate<Tag>() is called at run time.
/** \brief Create a dynamic accumulator chain containing the selected stati stics and their dependencies. /** \brief Create a dynamic accumulator chain containing the selected stati stics and their dependencies.
DynamicAccumulatorChain is used to compute global statistics with run-t ime activation. A set of statistics is selected at run-time and from this s et statistics can be activated at run-time by calling activate<stat>() or a ctivate(std::string stat). DynamicAccumulatorChain is used to compute global statistics with run-t ime activation. A set of statistics is selected at run-time and from this s et statistics can be activated at run-time by calling activate<stat>() or a ctivate(std::string stat).
The template parameters are as follows: The template parameters are as follows:
- T: The input type - T: The input type
- either element type of the data(e.g. double, int, RGBValue, ...) - either element type of the data(e.g. double, int, RGBValue, ...)
- or type of CoupledHandle (for access to coordinates and/or weight s) - or type of CoupledHandle (for access to coordinates and/or weight s)
skipping to change at line 2015 skipping to change at line 2168
/** Activate all statistics in the accumulator chain. /** Activate all statistics in the accumulator chain.
*/ */
void activateAll() void activateAll()
{ {
getAccumulator<AccumulatorEnd>(*this).active_accumulators_.set(); getAccumulator<AccumulatorEnd>(*this).active_accumulators_.set();
} }
/** Return true if the statistic 'tag' is active, i.e. activate(std::st ring tag) or activate<TAG>() has been called. If the statistic is not in th e accumulator chain a PreconditionViolation is thrown. (Note that alias nam es are not recognized.) /** Return true if the statistic 'tag' is active, i.e. activate(std::st ring tag) or activate<TAG>() has been called. If the statistic is not in th e accumulator chain a PreconditionViolation is thrown. (Note that alias nam es are not recognized.)
*/ */
bool isActive(std::string tag) const bool isActive(std::string tag) const
{ {
detail::TagIsActive_Visitor v; acc_detail::TagIsActive_Visitor v;
vigra_precondition(isActiveImpl(tag, v), vigra_precondition(isActiveImpl(tag, v),
std::string("DynamicAccumulatorChain::isActive(): Tag '") + tag + "' not found."); std::string("DynamicAccumulatorChain::isActive(): Tag '") + tag + "' not found.");
return v.result; return v.result;
} }
/** %isActive\<TAG\>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statis tic is not in the accumulator chain, true is returned. (?) /** %isActive\<TAG\>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statis tic is not in the accumulator chain, true is returned. (?)
*/ */
template <class TAG> template <class TAG>
bool isActive() const bool isActive() const
{ {
skipping to change at line 2051 skipping to change at line 2204
*/ */
unsigned int passesRequired() const unsigned int passesRequired() const
{ {
return InternalBaseType::passesRequired(getAccumulator<AccumulatorE nd>(*this).active_accumulators_); return InternalBaseType::passesRequired(getAccumulator<AccumulatorE nd>(*this).active_accumulators_);
} }
protected: protected:
bool activateImpl(std::string tag) bool activateImpl(std::string tag)
{ {
return detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this,
normalizeString(tag), detail::Acti normalizeString(tag), acc_detail::
vateTag_Visitor()); ActivateTag_Visitor());
} }
bool isActiveImpl(std::string tag, detail::TagIsActive_Visitor & v) con st bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
{ {
return detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, norm alizeString(tag), v); return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, normalizeString(tag), v);
} }
}; };
template <unsigned int N, class T1, class T2, class T3, class T4, class T5,
class Selected>
class DynamicAccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selecte
d>
: public DynamicAccumulatorChain<typename CoupledArrays<N, T1, T2, T3, T4,
T5>::HandleType, Selected>
{};
/** \brief Create an array of accumulator chains containing the selected pe r-region and global statistics and their dependencies. /** \brief Create an array of accumulator chains containing the selected pe r-region and global statistics and their dependencies.
AccumulatorChainArray is used to compute per-region statistics (as well as global statistics). The statistics are selected at compile-time. An arr ay of accumulator chains (one per region) for region statistics is created and one accumulator chain for global statistics. The region labels always s tart at 0. Use the Global modifier to compute global statistics (by default per-region statistics are computed). AccumulatorChainArray is used to compute per-region statistics (as well as global statistics). The statistics are selected at compile-time. An arr ay of accumulator chains (one per region) for region statistics is created and one accumulator chain for global statistics. The region labels always s tart at 0. Use the Global modifier to compute global statistics (by default per-region statistics are computed).
The template parameters are as follows: The template parameters are as follows:
- T: The input type, type of CoupledHandle (for access to coordinates, labels and weights) - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
- Selected: statistics to be computed and index specifier for the Coupl edHandle, wrapped with Select - Selected: statistics to be computed and index specifier for the Coupl edHandle, wrapped with Select
Usage: Usage:
\code \code
skipping to change at line 2084 skipping to change at line 2242
typedef unsigned int LabelType; typedef unsigned int LabelType;
typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType >::HandleType Handle; typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType >::HandleType Handle;
AccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg <3>, Mean, Variance, ...> > a; AccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg <3>, Mean, Variance, ...> > a;
\endcode \endcode
See \ref FeatureAccumulators for more information and examples of use. See \ref FeatureAccumulators for more information and examples of use.
*/ */
template <class T, class Selected, bool dynamic=false> template <class T, class Selected, bool dynamic=false>
class AccumulatorChainArray class AccumulatorChainArray
#ifndef DOXYGEN //hide AccumulatorChainImpl vom documentation #ifndef DOXYGEN //hide AccumulatorChainImpl vom documentation
: public AccumulatorChainImpl<T, typename detail::ConfigureAccumulatorChain Array<T, Selected, dynamic>::type> : public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorC hainArray<T, Selected, dynamic>::type>
#endif #endif
{ {
public: public:
typedef typename detail::ConfigureAccumulatorChainArray<T, Selected, dy typedef AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulat
namic> Creator; orChainArray<T, Selected, dynamic>::type> base_type;
typedef typename acc_detail::ConfigureAccumulatorChainArray<T, Selected
, dynamic> Creator;
typedef typename Creator::TagList AccumulatorTags; typedef typename Creator::TagList AccumulatorTags;
typedef typename Creator::GlobalTags GlobalTags; typedef typename Creator::GlobalTags GlobalTags;
typedef typename Creator::RegionTags RegionTags; typedef typename Creator::RegionTags RegionTags;
/** Statistics will not be computed for label l. Note that only one lab el can be ignored. /** Statistics will not be computed for label l. Note that only one lab el can be ignored.
*/ */
void ignoreLabel(MultiArrayIndex l) void ignoreLabel(MultiArrayIndex l)
{ {
this->next_.ignoreLabel(l); this->next_.ignoreLabel(l);
} }
/** Ask for a label to be ignored. Default: -1 (meaning that no label i
s ignored).
*/
MultiArrayIndex ignoredLabel() const
{
return this->next_.ignoredLabel();
}
/** Set the maximum region label (e.g. for merging two accumulator chai ns). /** Set the maximum region label (e.g. for merging two accumulator chai ns).
*/ */
void setMaxRegionLabel(unsigned label) void setMaxRegionLabel(unsigned label)
{ {
this->next_.setMaxRegionLabel(label); this->next_.setMaxRegionLabel(label);
} }
/** %Maximum region label. (equal to regionCount() - 1) /** Maximum region label. (equal to regionCount() - 1)
*/ */
MultiArrayIndex maxRegionLabel() const MultiArrayIndex maxRegionLabel() const
{ {
return this->next_.maxRegionLabel(); return this->next_.maxRegionLabel();
} }
/** Number of Regions. (equal to maxRegionLabel() + 1) /** Number of Regions. (equal to maxRegionLabel() + 1)
*/ */
unsigned int regionCount() const unsigned int regionCount() const
{ {
return this->next_.regions_.size(); return this->next_.regions_.size();
} }
/** Equivalent to <tt>merge(o)</tt>.
*/
void operator+=(AccumulatorChainArray const & o)
{
merge(o);
}
/** Merge region i with region j. /** Merge region i with region j.
*/ */
void merge(unsigned i, unsigned j) void merge(unsigned i, unsigned j)
{ {
vigra_precondition(i <= maxRegionLabel() && j <= maxRegionLabel(), vigra_precondition(i <= maxRegionLabel() && j <= maxRegionLabel(),
"AccumulatorChainArray::merge(): region labels out of range."); "AccumulatorChainArray::merge(): region labels out of range.");
this->next_.merge(i, j); this->next_.mergeImpl(i, j);
} }
/** Merge with accumulator chain o. maxRegionLabel() of the two accumul ators must be equal. /** Merge with accumulator chain o. maxRegionLabel() of the two accumul ators must be equal.
*/ */
void merge(AccumulatorChainArray const & o) void merge(AccumulatorChainArray const & o)
{ {
if(maxRegionLabel() == -1) if(maxRegionLabel() == -1)
setMaxRegionLabel(o.maxRegionLabel()); setMaxRegionLabel(o.maxRegionLabel());
vigra_precondition(maxRegionLabel() == o.maxRegionLabel(), vigra_precondition(maxRegionLabel() == o.maxRegionLabel(),
"AccumulatorChainArray::merge(): maxRegionLabel must be equal." ); "AccumulatorChainArray::merge(): maxRegionLabel must be equal." );
this->next_.merge(o.next_); this->next_.mergeImpl(o.next_);
} }
/** Merge with accumulator chain o using a mapping between labels of th e two accumulators. Label l of accumulator chain o is mapped to labelMappin g[l]. Hence, all elements of labelMapping must be <= maxRegionLabel() and s ize of labelMapping must match o.regionCount(). /** Merge with accumulator chain o using a mapping between labels of th e two accumulators. Label l of accumulator chain o is mapped to labelMappin g[l]. Hence, all elements of labelMapping must be <= maxRegionLabel() and s ize of labelMapping must match o.regionCount().
*/ */
template <class ArrayLike> template <class ArrayLike>
void merge(AccumulatorChainArray const & o, ArrayLike const & labelMapp ing) void merge(AccumulatorChainArray const & o, ArrayLike const & labelMapp ing)
{ {
vigra_precondition(labelMapping.size() == o.regionCount(), vigra_precondition(labelMapping.size() == o.regionCount(),
"AccumulatorChainArray::merge(): labelMapping.size() must match regionCount() of RHS."); "AccumulatorChainArray::merge(): labelMapping.size() must match regionCount() of RHS.");
this->next_.merge(o.next_, labelMapping); this->next_.mergeImpl(o.next_, labelMapping);
} }
/** Return names of all tags in the accumulator chain (selected statist ics and their dependencies). /** Return names of all tags in the accumulator chain (selected statist ics and their dependencies).
*/ */
static ArrayVector<std::string> const & tagNames() static ArrayVector<std::string> const & tagNames()
{ {
static const ArrayVector<std::string> n = collectTagNames(); static const ArrayVector<std::string> n = collectTagNames();
return n; return n;
} }
using base_type::setCoordinateOffset;
/** Set an offset for <tt>Coord<...></tt> statistics for region \a k.
If the offset is non-zero, coordinate statistics such as <tt>Region
Center</tt> are computed
in the global coordinate system defined by the \a offset. Without a
n offset, these statistics
are computed in the local coordinate system of the current region o
f interest.
*/
template <class SHAPE>
void setCoordinateOffset(MultiArrayIndex k, SHAPE const & offset)
{
this->next_.setCoordinateOffsetImpl(k, offset);
}
#ifdef DOXYGEN // hide AccumulatorChainImpl from documentation #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
/** \copydoc AccumulatorChain::setHistogramOptions(HistogramOptions const &) */ /** \copydoc vigra::acc::AccumulatorChain::setHistogramOptions(HistogramO ptions const &) */
void setHistogramOptions(HistogramOptions const & options); void setHistogramOptions(HistogramOptions const & options);
/** Set regional and global options for all histograms in the accumulator chain. /** Set regional and global options for all histograms in the accumulator chain.
*/ */
void setHistogramOptions(HistogramOptions const & regionoptions, Histogra mOptions const & globaloptions); void setHistogramOptions(HistogramOptions const & regionoptions, Histogra mOptions const & globaloptions);
/** \copydoc AccumulatorChain::reset() */ /** \copydoc vigra::acc::AccumulatorChain::setCoordinateOffset(SHAPE cons
t &)
*/
template <class SHAPE>
void setCoordinateOffset(SHAPE const & offset)
/** \copydoc vigra::acc::AccumulatorChain::reset() */
void reset(unsigned int reset_to_pass = 0); void reset(unsigned int reset_to_pass = 0);
/** \copydoc AccumulatorChain::operator+=() */ /** \copydoc vigra::acc::AccumulatorChain::operator+=() */
void operator+=(AccumulatorChainImpl const & o); void operator+=(AccumulatorChainImpl const & o);
/** \copydoc AccumulatorChain::updatePassN(T const &,unsigned int) */ /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,unsigned int) */
void updatePassN(T const & t, unsigned int N); void updatePassN(T const & t, unsigned int N);
/** \copydoc AccumulatorChain::updatePassN(T const &,double,unsigned int) */ /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,double,u nsigned int) */
void updatePassN(T const & t, double weight, unsigned int N); void updatePassN(T const & t, double weight, unsigned int N);
#endif #endif
private: private:
static ArrayVector<std::string> collectTagNames() static ArrayVector<std::string> collectTagNames()
{ {
ArrayVector<std::string> n; ArrayVector<std::string> n;
detail::CollectAccumulatorNames<AccumulatorTags>::exec(n); acc_detail::CollectAccumulatorNames<AccumulatorTags>::exec(n);
std::sort(n.begin(), n.end()); std::sort(n.begin(), n.end());
return n; return n;
} }
}; };
template <unsigned int N, class T1, class T2, class T3, class T4, class T5,
class Selected, bool dynamic>
class AccumulatorChainArray<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected,
dynamic>
: public AccumulatorChainArray<typename CoupledArrays<N, T1, T2, T3, T4, T5
>::HandleType, Selected, dynamic>
{};
/** \brief Create an array of dynamic accumulator chains containing the sel ected per-region and global statistics and their dependencies. /** \brief Create an array of dynamic accumulator chains containing the sel ected per-region and global statistics and their dependencies.
DynamicAccumulatorChainArray is used to compute per-region statistics ( as well as global statistics) with run-time activation. A set of statistics is selected at run-time and from this set statistics can be activated at r un-time by calling activate<stat>() or activate(std::string stat). DynamicAccumulatorChainArray is used to compute per-region statistics ( as well as global statistics) with run-time activation. A set of statistics is selected at run-time and from this set statistics can be activated at r un-time by calling activate<stat>() or activate(std::string stat).
The template parameters are as follows: The template parameters are as follows:
- T: The input type, type of CoupledHandle (for access to coordinates, labels and weights) - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
- Selected: statistics to be computed and index specifier for the Coupl edHandle, wrapped with Select - Selected: statistics to be computed and index specifier for the Coupl edHandle, wrapped with Select
Usage: Usage:
\code \code
skipping to change at line 2243 skipping to change at line 2440
/** \copydoc DynamicAccumulatorChain::activateAll() */ /** \copydoc DynamicAccumulatorChain::activateAll() */
void activateAll() void activateAll()
{ {
this->next_.activateAll(); this->next_.activateAll();
} }
/** Return true if the statistic 'tag' is active, i.e. activate(std::st ring tag) or activate<TAG>() has been called. If the statistic is not in th e accumulator chain a PreconditionViolation is thrown. (Note that alias nam es are not recognized.) /** Return true if the statistic 'tag' is active, i.e. activate(std::st ring tag) or activate<TAG>() has been called. If the statistic is not in th e accumulator chain a PreconditionViolation is thrown. (Note that alias nam es are not recognized.)
*/ */
bool isActive(std::string tag) const bool isActive(std::string tag) const
{ {
detail::TagIsActive_Visitor v; acc_detail::TagIsActive_Visitor v;
vigra_precondition(isActiveImpl(tag, v), vigra_precondition(isActiveImpl(tag, v),
std::string("DynamicAccumulatorChainArray::isActive(): Tag '") + tag + "' not found."); std::string("DynamicAccumulatorChainArray::isActive(): Tag '") + tag + "' not found.");
return v.result; return v.result;
} }
/** %isActive\<TAG\>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statis tic is not in the accumulator chain, true is returned. (?) /** %isActive\<TAG\>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statis tic is not in the accumulator chain, true is returned. (?)
*/ */
template <class TAG> template <class TAG>
bool isActive() const bool isActive() const
{ {
skipping to change at line 2277 skipping to change at line 2474
/** \copydoc DynamicAccumulatorChain::passesRequired() */ /** \copydoc DynamicAccumulatorChain::passesRequired() */
unsigned int passesRequired() const unsigned int passesRequired() const
{ {
return this->next_.passesRequiredDynamic(); return this->next_.passesRequiredDynamic();
} }
protected: protected:
bool activateImpl(std::string tag) bool activateImpl(std::string tag)
{ {
return detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_ return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->n
, ext_,
normalizeString(tag), detail::Acti normalizeString(tag), acc_detail::
vateTag_Visitor()); ActivateTag_Visitor());
} }
bool isActiveImpl(std::string tag, detail::TagIsActive_Visitor & v) con st bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
{ {
return detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_ , normalizeString(tag), v); return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->n ext_, normalizeString(tag), v);
} }
}; };
template <unsigned int N, class T1, class T2, class T3, class T4, class T5,
class Selected>
class DynamicAccumulatorChainArray<CoupledArrays<N, T1, T2, T3, T4, T5>, Se
lected>
: public DynamicAccumulatorChainArray<typename CoupledArrays<N, T1, T2, T3,
T4, T5>::HandleType, Selected>
{};
/************************************************************************** **/ /************************************************************************** **/
/* */ /* */
/* generic access functions */ /* generic access functions */
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
template <class TAG> template <class TAG>
struct Error__Attempt_to_access_inactive_statistic; struct Error__Attempt_to_access_inactive_statistic;
namespace detail { namespace acc_detail {
// accumulator lookup rules: find the accumulator that implements TAG // accumulator lookup rules: find the accumulator that implements TAG
// When A does not implement TAG, continue search in A::InternalBaseTyp e. // When A does not implement TAG, continue search in A::InternalBaseTyp e.
template <class TAG, class A, class FromTag=typename A::Tag> template <class TAG, class A, class FromTag=typename A::Tag>
struct LookupTagImpl struct LookupTagImpl
#ifndef DOXYGEN #ifndef DOXYGEN
: public LookupTagImpl<TAG, typename A::InternalBaseType> : public LookupTagImpl<TAG, typename A::InternalBaseType>
#endif #endif
{}; {};
skipping to change at line 2402 skipping to change at line 2604
struct LookupTagImpl<LabelDispatchTag, A, LabelDispatchTag> struct LookupTagImpl<LabelDispatchTag, A, LabelDispatchTag>
{ {
typedef LabelDispatchTag Tag; typedef LabelDispatchTag Tag;
typedef A type; typedef A type;
typedef A & reference; typedef A & reference;
typedef A * pointer; typedef A * pointer;
typedef void value_type; typedef void value_type;
typedef void result_type; typedef void result_type;
}; };
} // namespace detail } // namespace acc_detail
// Lookup the accumulator in the chain A that implements the given TAG. // Lookup the accumulator in the chain A that implements the given TAG.
template <class Tag, class A> template <class Tag, class A>
struct LookupTag struct LookupTag
: public detail::LookupTagImpl<typename StandardizeTag<Tag>::type, A> : public acc_detail::LookupTagImpl<typename StandardizeTag<Tag>::type, A>
{}; {};
// Lookup the dependency TAG of the accumulator A. // Lookup the dependency TAG of the accumulator A.
// This template ensures that dependencies are used with matching modif iers. // This template ensures that dependencies are used with matching modif iers.
// Specifically, if you search for Count as a dependency of Weighted<Me an>, the search // Specifically, if you search for Count as a dependency of Weighted<Me an>, the search
// actually returns Weighted<Count>, wheras Count will be returned for plain Mean. // actually returns Weighted<Count>, wheras Count will be returned for plain Mean.
template <class Tag, class A, class TargetTag> template <class Tag, class A, class TargetTag>
struct LookupDependency struct LookupDependency
: public detail::LookupTagImpl< : public acc_detail::LookupTagImpl<
typename TransferModifiers<TargetTag, typename StandardizeTag<Tag>:: type>::type, A> typename TransferModifiers<TargetTag, typename StandardizeTag<Tag>:: type>::type, A>
{}; {};
namespace detail { namespace acc_detail {
// CastImpl applies the same rules as LookupTagImpl, but returns a refe rence to an // CastImpl applies the same rules as LookupTagImpl, but returns a refe rence to an
// accumulator instance rather than an accumulator type // accumulator instance rather than an accumulator type
template <class Tag, class FromTag, class reference> template <class Tag, class FromTag, class reference>
struct CastImpl struct CastImpl
{ {
template <class A> template <class A>
static reference exec(A & a) static reference exec(A & a)
{ {
return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>: :exec(a.next_); return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>: :exec(a.next_);
skipping to change at line 2538 skipping to change at line 2740
template <class reference> template <class reference>
struct CastImpl<LabelDispatchTag, LabelDispatchTag, reference> struct CastImpl<LabelDispatchTag, LabelDispatchTag, reference>
{ {
template <class A> template <class A>
static reference exec(A & a) static reference exec(A & a)
{ {
return a; return a;
} }
}; };
} // namespace detail } // namespace acc_detail
// Get a reference to the accumulator TAG in the accumulator chain A // Get a reference to the accumulator TAG in the accumulator chain A
/** Get a reference to the accumulator 'TAG' in the accumulator chain 'a'. This can be useful for example to update a certain accumulator with data, s et individual options or get information about a certain accumulator.\n /** Get a reference to the accumulator 'TAG' in the accumulator chain 'a'. This can be useful for example to update a certain accumulator with data, s et individual options or get information about a certain accumulator.\n
Example of use (set options): Example of use (set options):
\code \code
vigra::MultiArray<2, double> data(...); vigra::MultiArray<2, double> data(...);
typedef UserRangeHistogram<40> SomeHistogram; //binCount set at compi le time typedef UserRangeHistogram<40> SomeHistogram; //binCount set at compi le time
typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set a t run-time typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set a t run-time
AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2> > a; AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2> > a;
skipping to change at line 2571 skipping to change at line 2773
std::cout << "passes required by Mean: " << getAccumulator<Mean>(a).passe sRequired() << std::endl; std::cout << "passes required by Mean: " << getAccumulator<Mean>(a).passe sRequired() << std::endl;
\endcode \endcode
See \ref FeatureAccumulators for more information about feature computation via accumulators. See \ref FeatureAccumulators for more information about feature computation via accumulators.
*/ */
template <class TAG, class A> template <class TAG, class A>
inline typename LookupTag<TAG, A>::reference inline typename LookupTag<TAG, A>::reference
getAccumulator(A & a) getAccumulator(A & a)
{ {
typedef typename LookupTag<TAG, A>::Tag StandardizedTag; typedef typename LookupTag<TAG, A>::Tag StandardizedTag;
typedef typename LookupTag<TAG, A>::reference reference; typedef typename LookupTag<TAG, A>::reference reference;
return detail::CastImpl<StandardizedTag, typename A::Tag, reference>::e xec(a); return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference >::exec(a);
} }
// Get a reference to the accumulator TAG for region 'label' in the acc umulator chain A // Get a reference to the accumulator TAG for region 'label' in the acc umulator chain A
/** Get a reference to the accumulator 'TAG' for region 'label' in the accu mulator chain 'a'. /** Get a reference to the accumulator 'TAG' for region 'label' in the accu mulator chain 'a'.
*/ */
template <class TAG, class A> template <class TAG, class A>
inline typename LookupTag<TAG, A>::reference inline typename LookupTag<TAG, A>::reference
getAccumulator(A & a, MultiArrayIndex label) getAccumulator(A & a, MultiArrayIndex label)
{ {
typedef typename LookupTag<TAG, A>::Tag StandardizedTag; typedef typename LookupTag<TAG, A>::Tag StandardizedTag;
typedef typename LookupTag<TAG, A>::reference reference; typedef typename LookupTag<TAG, A>::reference reference;
return detail::CastImpl<StandardizedTag, typename A::Tag, reference>::e xec(a, label); return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference >::exec(a, label);
} }
// get the result of the accumulator specified by TAG // get the result of the accumulator specified by TAG
/** Get the result of the accumulator 'TAG' in the accumulator chain 'a'.\n /** Get the result of the accumulator 'TAG' in the accumulator chain 'a'.\n
Example of use: Example of use:
\code \code
vigra::MultiArray<2, double> data(...); vigra::MultiArray<2, double> data(...);
AccumulatorChain<DataType, Select<Variance, Mean, StdDev> > a; AccumulatorChain<DataType, Select<Variance, Mean, StdDev> > a;
extractFeatures(data.begin(), data.end(), a); extractFeatures(data.begin(), data.end(), a);
double mean = get<Mean>(a); double mean = get<Mean>(a);
skipping to change at line 2642 skipping to change at line 2844
// Get the result of the accumulator specified by TAG without checking if the accumulator is active. // Get the result of the accumulator specified by TAG without checking if the accumulator is active.
// This must be used within an accumulator implementation to access dep endencies because // This must be used within an accumulator implementation to access dep endencies because
// it applies the approprate modifiers to the given TAG. It must not be used in other situations. // it applies the approprate modifiers to the given TAG. It must not be used in other situations.
// FIXME: is there a shorter name? // FIXME: is there a shorter name?
template <class TAG, class A> template <class TAG, class A>
inline typename LookupDependency<TAG, A>::result_type inline typename LookupDependency<TAG, A>::result_type
getDependency(A const & a) getDependency(A const & a)
{ {
typedef typename LookupDependency<TAG, A>::Tag StandardizedTag; typedef typename LookupDependency<TAG, A>::Tag StandardizedTag;
typedef typename LookupDependency<TAG, A>::reference reference; typedef typename LookupDependency<TAG, A>::reference reference;
return detail::CastImpl<StandardizedTag, typename A::Tag, reference>::e xec(a)(); return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference >::exec(a)();
} }
// activate the dynamic accumulator specified by Tag // activate the dynamic accumulator specified by Tag
/** Activate the dynamic accumulator 'Tag' in the dynamic accumulator chain 'a'. Same as a.activate<Tag>() (see DynamicAccumulatorChain::activate<Tag> () or DynamicAccumulatorChainArray::activate<Tag>()). For run-time activati on use DynamicAccumulatorChain::activate(std::string tag) or DynamicAccumul atorChainArray::activate(std::string tag) instead.\n /** Activate the dynamic accumulator 'Tag' in the dynamic accumulator chain 'a'. Same as a.activate<Tag>() (see DynamicAccumulatorChain::activate<Tag> () or DynamicAccumulatorChainArray::activate<Tag>()). For run-time activati on use DynamicAccumulatorChain::activate(std::string tag) or DynamicAccumul atorChainArray::activate(std::string tag) instead.\n
See \ref FeatureAccumulators for more information about feature computation via accumulators. See \ref FeatureAccumulators for more information about feature computation via accumulators.
*/ */
template <class Tag, class A> template <class Tag, class A>
inline void inline void
activate(A & a) activate(A & a)
{ {
skipping to change at line 2673 skipping to change at line 2875
{ {
return a.template isActive<Tag>(); return a.template isActive<Tag>();
} }
/************************************************************************** **/ /************************************************************************** **/
/* */ /* */
/* generic loops */ /* generic loops */
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
/** Generic loop to collect the statistics of the accumulator chain 'a' in as many passes over the data as necessary.\n /** Generic loop to collect statistics from one or several arrays.
Example of use: This function automatically performs as many passes over the data as necess ary for the selected statistics. The basic version of <tt>extractFeatures() </tt> takes an iterator pair and a reference to an accumulator chain:
\code \code
vigra::MultiArray<3, double> data(...); namespace vigra { namespace acc {
vigra::MultiArray<3, int> labels(...);
typedef vigra::CoupledIteratorType<3, double, int>::type Iterator;
typedef Iterator::value_type Handle;
AccumulatorChainArray<Handle, template <class ITERATOR, class ACCUMULATOR>
Select<DataArg<1>, LabelArg<2>, Mean, Variance> > a; void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a);
}}
\endcode
The <tt>ITERATOR</tt> can be any STL-conforming <i>forward iterator</i> (in
cluding raw pointers and \ref vigra::CoupledScanOrderIterator). The <tt>ACC
UMULATOR</tt> must be instantiated with the <tt>ITERATOR</tt>'s <tt>value_t
ype</tt> as its first template argument. For example, to use a raw pointer
you write:
\code
AccumulatorChain<double, Select<Mean, Variance> > a;
Iterator start = createCoupledIterator(data, labels); double * start = ...,
Iterator end = start.getEndIterator(); * end = ...;
extractFeatures(start, end, a);
\endcode
Similarly, you can use MultiArray's scan-order iterator:
\code
AccumulatorChain<TinyVector<float, 2>, Select<Mean, Variance> > a;
extractFeatures(start,end,a); MultiArray<3, TinyVector<float, 2> > data(...);
extractFeatures(data.begin(), data.end(), a);
\endcode
An alternative syntax is used when you want to compute weighted or region s
tatistics (or both). Then it is necessary to iterate over several arrays si
multaneously. This fact is best conveyed to the accumulator via the helper
class \ref vigra::CoupledArrays that is used as the accumulator's first tem
plate argument and holds the dimension and value types of the arrays involv
ed. To actually compute the features, you then pass appropriate arrays to t
he <tt>extractfeatures()</tt> function directly. For example, region statis
tics can be obtained like this:
\code
MultiArray<3, double> data(...);
MultiArray<3, int> labels(...);
AccumulatorChainArray<CoupledArrays<3, double, int>,
Select<DataArg<1>, LabelArg<2>, // where to look
for data and region labels
Mean, Variance> > // what statistic
s to compute
a;
extractFeatures(data, labels, a);
\endcode
This form of <tt>extractFeatures()</tt> is supported for up to five arrays
(although at most three are currently making sense in practice):
\code
namespace vigra { namespace acc {
template <unsigned int N, class T1, class S1,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
ACCUMULATOR & a);
...
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T3, class S3,
class T4, class S4,
class T5, class S5,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
MultiArrayView<N, T2, S2> const & a2,
MultiArrayView<N, T3, S3> const & a3,
MultiArrayView<N, T4, S4> const & a4,
MultiArrayView<N, T5, S5> const & a5,
ACCUMULATOR & a);
}}
\endcode \endcode
Of course, the number and types of the arrays specified in <tt>CoupledArray
s</tt> must conform to the number and types of the arrays passed to <tt>ext
ractFeatures()</tt>.
See \ref FeatureAccumulators for more information about feature computation via accumulators. See \ref FeatureAccumulators for more information about feature computation via accumulators.
*/ */
doxygen_overloaded_function(template <...> void extractFeatures)
template <class ITERATOR, class ACCUMULATOR> template <class ITERATOR, class ACCUMULATOR>
void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a) void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a)
{ {
for(unsigned int k=1; k <= a.passesRequired(); ++k) for(unsigned int k=1; k <= a.passesRequired(); ++k)
for(ITERATOR i=start; i < end; ++i) for(ITERATOR i=start; i < end; ++i)
a.updatePassN(*i, k); a.updatePassN(*i, k);
} }
template <unsigned int N, class T1, class S1,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
ACCUMULATOR & a)
{
typedef typename CoupledIteratorType<N, T1>::type Iterator;
Iterator start = createCoupledIterator(a1),
end = start.getEndIterator();
extractFeatures(start, end, a);
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
MultiArrayView<N, T2, S2> const & a2,
ACCUMULATOR & a)
{
typedef typename CoupledIteratorType<N, T1, T2>::type Iterator;
Iterator start = createCoupledIterator(a1, a2),
end = start.getEndIterator();
extractFeatures(start, end, a);
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T3, class S3,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
MultiArrayView<N, T2, S2> const & a2,
MultiArrayView<N, T3, S3> const & a3,
ACCUMULATOR & a)
{
typedef typename CoupledIteratorType<N, T1, T2, T3>::type Iterator;
Iterator start = createCoupledIterator(a1, a2, a3),
end = start.getEndIterator();
extractFeatures(start, end, a);
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T3, class S3,
class T4, class S4,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
MultiArrayView<N, T2, S2> const & a2,
MultiArrayView<N, T3, S3> const & a3,
MultiArrayView<N, T4, S4> const & a4,
ACCUMULATOR & a)
{
typedef typename CoupledIteratorType<N, T1, T2, T3, T4>::type Iterator;
Iterator start = createCoupledIterator(a1, a2, a3, a4),
end = start.getEndIterator();
extractFeatures(start, end, a);
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T3, class S3,
class T4, class S4,
class T5, class S5,
class ACCUMULATOR>
void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
MultiArrayView<N, T2, S2> const & a2,
MultiArrayView<N, T3, S3> const & a3,
MultiArrayView<N, T4, S4> const & a4,
MultiArrayView<N, T5, S5> const & a5,
ACCUMULATOR & a)
{
typedef typename CoupledIteratorType<N, T1, T2, T3, T4, T5>::type Itera
tor;
Iterator start = createCoupledIterator(a1, a2, a3, a4, a5),
end = start.getEndIterator();
extractFeatures(start, end, a);
}
/************************************************************************** **/ /************************************************************************** **/
/* */ /* */
/* AccumulatorResultTraits */ /* AccumulatorResultTraits */
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
template <class T> template <class T>
struct AccumulatorResultTraits struct AccumulatorResultTraits
{ {
typedef T type; typedef T type;
skipping to change at line 2785 skipping to change at line 3111
This modifier only works when labels are given (with (Dynamic)AccumulatorCh ainArray), in which case statistics are computed per-region by default. This modifier only works when labels are given (with (Dynamic)AccumulatorCh ainArray), in which case statistics are computed per-region by default.
*/ */
template <class TAG> template <class TAG>
class Global class Global
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename StandardizeTag<TAG>::type TargetTag;
typedef typename TargetTag::Dependencies Dependencies; typedef typename TargetTag::Dependencies Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("Global<") + TargetTag::na return std::string("Global<") + TargetTag::name() + " >";
me() + " >"; // static const std::string n = std::string("Global<") + TargetTag:
return n; :name() + " >";
// return n;
} }
}; };
/** \brief Specifies index of data in CoupledHandle. /** \brief Specifies index of data in CoupledHandle.
If AccumulatorChain is used with CoupledIterator, DataArg<INDEX> tells the accumulator chain which index of the Handle contains the data. (Coordin ates are always index 0) If AccumulatorChain is used with CoupledIterator, DataArg<INDEX> tells the accumulator chain which index of the Handle contains the data. (Coordin ates are always index 0)
*/ */
template <int INDEX> template <int INDEX>
class DataArg class DataArg
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("DataArg<") + asString(IND return std::string("DataArg<") + asString(INDEX) + "> (internal)";
EX) + "> (internal)"; // static const std::string n = std::string("DataArg<") + asString(
return n; INDEX) + "> (internal)";
// return n;
} }
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef DataArgTag Tag; typedef DataArgTag Tag;
typedef void value_type; typedef void value_type;
typedef void result_type; typedef void result_type;
static const int value = INDEX; static const int value = INDEX;
static const unsigned int workInPass = 0; static const unsigned int workInPass = 0;
}; };
}; };
// Tags are automatically wrapped with DataFromHandle if CoupledHandle used namespace acc_detail {
template <class TAG>
class DataFromHandle template <class T, int DEFAULT, class TAG, class IndexDefinition,
class TagFound=typename IndexDefinition::Tag>
struct HandleArgSelectorImpl
{ {
public: static const int value = DEFAULT;
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename CoupledHandleCast<value, T>::type type;
typedef typename TargetTag::Dependencies Dependencies; typedef typename CoupledHandleCast<value, T>::value_type value_type;
static const int size = type::dimensions;
static std::string const & name() template <class U, class NEXT>
static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type
const &
getHandle(CoupledHandle<U, NEXT> const & t)
{ {
static const std::string n = std::string("DataFromHandle<") + Targe return vigra::cast<value>(t);
tTag::name() + " > (internal)";
return n;
} }
template <class IndexDefinition, class TagFound=typename IndexDefinitio template <class U, class NEXT>
n::Tag> static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type
struct DataIndexSelector ::const_reference
getValue(CoupledHandle<U, NEXT> const & t)
{ {
static const int value = 1; // default: CoupledHandle holds data at return vigra::get<value>(t);
index 1 }
};
template <class U, class NEXT> template <class T, int DEFAULT, class TAG, class IndexDefinition>
static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >:: struct HandleArgSelectorImpl<T, DEFAULT, TAG, IndexDefinition, TAG>
type::const_reference {
exec(CoupledHandle<U, NEXT> const & t) static const int value = IndexDefinition::value;
{ typedef typename CoupledHandleCast<value, T>::type type;
return get<value>(t); typedef typename CoupledHandleCast<value, T>::value_type value_type;
} static const int size = type::dimensions;
};
template <class IndexDefinition> template <class U, class NEXT>
struct DataIndexSelector<IndexDefinition, DataArgTag> static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type
const &
getHandle(CoupledHandle<U, NEXT> const & t)
{ {
static const int value = IndexDefinition::value; return vigra::cast<value>(t);
}
template <class U, class NEXT> template <class U, class NEXT>
static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >:: static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type
type::const_reference ::const_reference
exec(CoupledHandle<U, NEXT> const & t) getValue(CoupledHandle<U, NEXT> const & t)
{ {
return get<value>(t); return vigra::get<value>(t);
} }
}; };
template <class T, class BASE> } // namespace acc_detail
struct SelectInputType
template <class T, class CHAIN>
struct HandleArgSelector<T, LabelArgTag, CHAIN>
: public acc_detail::HandleArgSelectorImpl<T, 2, LabelArgTag,
typename LookupTag<LabelArgTag,
CHAIN>::type>
{};
template <class T, class CHAIN>
struct HandleArgSelector<T, DataArgTag, CHAIN>
: public acc_detail::HandleArgSelectorImpl<T, 1, DataArgTag,
typename LookupTag<DataArgTag, C
HAIN>::type>
{};
template <class T, class CHAIN>
struct HandleArgSelector<T, CoordArgTag, CHAIN>
: public acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
typename LookupTag<CoordArgTag,
CHAIN>::type>
{
typedef acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
typename LookupTag<CoordArgTag, CHAIN>::type> base
_type;
typedef TinyVector<double, base_type::size> value_type;
};
// Tags are automatically wrapped with DataFromHandle if CoupledHandle used
template <class TAG>
class DataFromHandle
{
public:
typedef typename StandardizeTag<TAG>::type TargetTag;
typedef typename TargetTag::Dependencies Dependencies;
static std::string name()
{ {
typedef typename LookupTag<DataArgTag, BASE>::type FindDataIndex; return std::string("DataFromHandle<") + TargetTag::name() + " > (in
typedef DataIndexSelector<FindDataIndex> DataIndex; ternal)";
typedef typename CoupledHandleCast<DataIndex::value, T>::type::valu // static const std::string n = std::string("DataFromHandle<") + Ta
e_type type; rgetTag::name() + " > (internal)";
}; // return n;
}
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public TargetTag::template Impl<typename SelectInputType<T, BASE>::ty pe, BASE> : public TargetTag::template Impl<typename HandleArgSelector<T, DataArg Tag, BASE>::value_type, BASE>
{ {
typedef SelectInputType<T, BASE> InputTypeSelector; typedef HandleArgSelector<T, DataArgTag, BASE> DataHandle;
typedef typename InputTypeSelector::DataIndex DataIndex; typedef typename DataHandle::value_type input_type;
typedef typename InputTypeSelector::type input_type; typedef input_type const & argument_type;
typedef input_type const & argument_type; typedef argument_type first_argument_typ
typedef argument_type first_argument_type e;
;
typedef typename TargetTag::template Impl<input_type, BASE> ImplTyp e; typedef typename TargetTag::template Impl<input_type, BASE> ImplTyp e;
using ImplType::reshape; using ImplType::reshape;
template <class U, class NEXT> template <class U, class NEXT>
void reshape(CoupledHandle<U, NEXT> const & t) void reshape(CoupledHandle<U, NEXT> const & t)
{ {
ImplType::reshape(detail::shapeOf(DataIndex::exec(t))); ImplType::reshape(acc_detail::shapeOf(DataHandle::getValue(t))) ;
} }
template <class U, class NEXT> template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t) void update(CoupledHandle<U, NEXT> const & t)
{ {
ImplType::update(DataIndex::exec(t)); ImplType::update(DataHandle::getValue(t));
} }
template <class U, class NEXT> template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t, double weight) void update(CoupledHandle<U, NEXT> const & t, double weight)
{ {
ImplType::update(DataIndex::exec(t), weight); ImplType::update(DataHandle::getValue(t), weight);
} }
}; };
}; };
/** \brief Modifier. Compute statistic from pixel coordinates rather than f rom pixel values. /** \brief Modifier. Compute statistic from pixel coordinates rather than f rom pixel values.
AccumulatorChain must be used with CoupledIterator in order to have acc ess to pixel coordinates. AccumulatorChain must be used with CoupledIterator in order to have acc ess to pixel coordinates.
*/ */
template <class TAG> template <class TAG>
class Coord class Coord
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename StandardizeTag<TAG>::type TargetTag;
typedef typename TargetTag::Dependencies Dependencies; typedef typename TargetTag::Dependencies Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("Coord<") + TargetTag::nam return std::string("Coord<") + TargetTag::name() + " >";
e() + " >"; // static const std::string n = std::string("Coord<") + TargetTag::
return n; name() + " >";
// return n;
} }
template <class IndexDefinition, class TagFound=typename IndexDefinitio template <class T, class BASE>
n::Tag> struct Impl
struct CoordIndexSelector : public TargetTag::template Impl<typename HandleArgSelector<T, CoordAr
gTag, BASE>::value_type, BASE>
{ {
static const int value = 0; // default: CoupledHandle holds coordin typedef HandleArgSelector<T, CoordArgTag, BASE> CoordHandle;
ates at index 0 typedef typename CoordHandle::value_type input_type;
typedef input_type const & argument_type;
typedef argument_type first_argument_ty
pe;
template <class U, class NEXT> typedef typename TargetTag::template Impl<input_type, BASE> ImplTyp
static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >:: e;
type::const_reference
exec(CoupledHandle<U, NEXT> const & t)
{
return get<value>(t);
}
};
template <class IndexDefinition> input_type offset_;
struct CoordIndexSelector<IndexDefinition, CoordArgTag>
{
static const int value = IndexDefinition::value;
template <class U, class NEXT> Impl()
static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >:: : offset_()
type::const_reference {}
exec(CoupledHandle<U, NEXT> const & t)
void setCoordinateOffset(input_type const & offset)
{ {
return get<value>(t); offset_ = offset;
} }
};
template <class T, class BASE>
struct SelectInputType
{
typedef typename LookupTag<CoordArgTag, BASE>::type FindDataIndex;
typedef CoordIndexSelector<FindDataIndex> CoordIndex;
typedef typename CoupledHandleCast<CoordIndex::value, T>::type::val
ue_type type;
};
template <class T, class BASE>
struct Impl
: public TargetTag::template Impl<typename SelectInputType<T, BASE>::ty
pe, BASE>
{
typedef SelectInputType<T, BASE> InputTypeSelector;
typedef typename InputTypeSelector::CoordIndex CoordIndex;
typedef typename InputTypeSelector::type input_type;
typedef input_type const & argument_type;
typedef argument_type first_argument_type
;
typedef typename TargetTag::template Impl<input_type, BASE> ImplTyp
e;
using ImplType::reshape; using ImplType::reshape;
template <class U, class NEXT> template <class U, class NEXT>
void reshape(CoupledHandle<U, NEXT> const & t) void reshape(CoupledHandle<U, NEXT> const & t)
{ {
ImplType::reshape(detail::shapeOf(CoordIndex::exec(t))); ImplType::reshape(acc_detail::shapeOf(CoordHandle::getValue(t)) );
} }
template <class U, class NEXT> template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t) void update(CoupledHandle<U, NEXT> const & t)
{ {
ImplType::update(CoordIndex::exec(t)); ImplType::update(CoordHandle::getValue(t)+offset_);
} }
template <class U, class NEXT> template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t, double weight) void update(CoupledHandle<U, NEXT> const & t, double weight)
{ {
ImplType::update(CoordIndex::exec(t), weight); ImplType::update(CoordHandle::getValue(t)+offset_, weight);
} }
}; };
}; };
/** \brief Specifies index of data in CoupledHandle. /** \brief Specifies index of data in CoupledHandle.
If AccumulatorChain is used with CoupledIterator, WeightArg<INDEX> tell s the accumulator chain which index of the Handle contains the weights. (No te that coordinates are always index 0.) If AccumulatorChain is used with CoupledIterator, WeightArg<INDEX> tell s the accumulator chain which index of the Handle contains the weights. (No te that coordinates are always index 0.)
*/ */
template <int INDEX> template <int INDEX>
class WeightArg class WeightArg
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("WeightArg<") + asString(I return std::string("WeightArg<") + asString(INDEX) + "> (internal)"
NDEX) + "> (internal)"; ;
return n; // static const std::string n = std::string("WeightArg<") + asStrin
g(INDEX) + "> (internal)";
// return n;
} }
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef WeightArgTag Tag; typedef WeightArgTag Tag;
typedef void value_type; typedef void value_type;
typedef void result_type; typedef void result_type;
skipping to change at line 3026 skipping to change at line 3371
/** \brief Compute weighted version of the statistic. /** \brief Compute weighted version of the statistic.
*/ */
template <class TAG> template <class TAG>
class Weighted class Weighted
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename StandardizeTag<TAG>::type TargetTag;
typedef typename TargetTag::Dependencies Dependencies; typedef typename TargetTag::Dependencies Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("Weighted<") + TargetTag:: return std::string("Weighted<") + TargetTag::name() + " >";
name() + " >"; // static const std::string n = std::string("Weighted<") + TargetTa
return n; g::name() + " >";
// return n;
} }
template <class IndexDefinition, class TagFound=typename IndexDefinitio n::Tag> template <class IndexDefinition, class TagFound=typename IndexDefinitio n::Tag>
struct WeightIndexSelector struct WeightIndexSelector
{ {
template <class U, class NEXT> template <class U, class NEXT>
static double exec(CoupledHandle<U, NEXT> const & t) static double exec(CoupledHandle<U, NEXT> const & t)
{ {
return (double)*t; // default: CoupledHandle holds weights at t he last (outermost) index return (double)*t; // default: CoupledHandle holds weights at t he last (outermost) index
} }
skipping to change at line 3074 skipping to change at line 3420
} }
}; };
}; };
// Centralize by subtracting the mean and cache the result // Centralize by subtracting the mean and cache the result
class Centralize class Centralize
{ {
public: public:
typedef Select<Mean> Dependencies; typedef Select<Mean> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Centralize (internal)"); return "Centralize (internal)";
return n; // static const std::string n("Centralize (internal)");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
typedef typename AccumulatorResultTraits<U>::element_promote_type e lement_type; typedef typename AccumulatorResultTraits<U>::element_promote_type e lement_type;
typedef typename AccumulatorResultTraits<U>::SumType v alue_type; typedef typename AccumulatorResultTraits<U>::SumType v alue_type;
skipping to change at line 3104 skipping to change at line 3451
{} {}
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
void update(U const & t) const void update(U const & t) const
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
value_ = t - getDependency<Mean>(*this); value_ = t - getDependency<Mean>(*this);
} }
void update(U const & t, double) const void update(U const & t, double) const
{ {
skipping to change at line 3142 skipping to change at line 3489
Works in pass 2, %operator+=() not supported (merging not supported). Works in pass 2, %operator+=() not supported (merging not supported).
*/ */
template <class TAG> template <class TAG>
class Central class Central
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag ; typedef typename StandardizeTag<TAG>::type TargetTag ;
typedef Select<Centralize, typename TargetTag::Dependencies> Dependenc ies; typedef Select<Centralize, typename TargetTag::Dependencies> Dependenc ies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("Central<") + TargetTag::n return std::string("Central<") + TargetTag::name() + " >";
ame() + " >"; // static const std::string n = std::string("Central<") + TargetTag
return n; ::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public TargetTag::template Impl<typename AccumulatorResultTraits<U>:: SumType, BASE> : public TargetTag::template Impl<typename AccumulatorResultTraits<U>:: SumType, BASE>
{ {
typedef typename TargetTag::template Impl<typename AccumulatorResul tTraits<U>::SumType, BASE> ImplType; typedef typename TargetTag::template Impl<typename AccumulatorResul tTraits<U>::SumType, BASE> ImplType;
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
skipping to change at line 3218 skipping to change at line 3566
// ImplType::update(t - getDependency<Mean>(*this), weight); // ImplType::update(t - getDependency<Mean>(*this), weight);
// } // }
// }; // };
// }; // };
class PrincipalProjection class PrincipalProjection
{ {
public: public:
typedef Select<Centralize, Principal<CoordinateSystem> > Dependencies; typedef Select<Centralize, Principal<CoordinateSystem> > Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("PrincipalProjection (internal)"); return "PrincipalProjection (internal)";
return n; // static const std::string n("PrincipalProjection (internal)");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
typedef typename AccumulatorResultTraits<U>::element_promote_type e lement_type; typedef typename AccumulatorResultTraits<U>::element_promote_type e lement_type;
typedef typename AccumulatorResultTraits<U>::SumType v alue_type; typedef typename AccumulatorResultTraits<U>::SumType v alue_type;
skipping to change at line 3248 skipping to change at line 3597
{} {}
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
void update(U const & t) const void update(U const & t) const
{ {
for(unsigned int k=0; k<t.size(); ++k) for(unsigned int k=0; k<t.size(); ++k)
{ {
value_[k] = getDependency<Principal<CoordinateSystem> >(*th is)(0, k)*getDependency<Centralize>(*this)[0]; value_[k] = getDependency<Principal<CoordinateSystem> >(*th is)(0, k)*getDependency<Centralize>(*this)[0];
for(unsigned int d=1; d<t.size(); ++d) for(unsigned int d=1; d<t.size(); ++d)
value_[k] += getDependency<Principal<CoordinateSystem> >(*this)(d, k)*getDependency<Centralize>(*this)[d]; value_[k] += getDependency<Principal<CoordinateSystem> >(*this)(d, k)*getDependency<Centralize>(*this)[d];
} }
skipping to change at line 3291 skipping to change at line 3640
Works in pass 2, %operator+=() not supported (merging not supported). Works in pass 2, %operator+=() not supported (merging not supported).
*/ */
template <class TAG> template <class TAG>
class Principal class Principal
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename StandardizeTag<TAG>::type TargetTag;
typedef Select<PrincipalProjection, typename TargetTag::Dependencies> Dependencies; typedef Select<PrincipalProjection, typename TargetTag::Dependencies> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("Principal<") + TargetTag: return std::string("Principal<") + TargetTag::name() + " >";
:name() + " >"; // static const std::string n = std::string("Principal<") + TargetT
return n; ag::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public TargetTag::template Impl<typename AccumulatorResultTraits<U>:: SumType, BASE> : public TargetTag::template Impl<typename AccumulatorResultTraits<U>:: SumType, BASE>
{ {
typedef typename TargetTag::template Impl<typename AccumulatorResul tTraits<U>::SumType, BASE> ImplType; typedef typename TargetTag::template Impl<typename AccumulatorResul tTraits<U>::SumType, BASE> ImplType;
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
skipping to change at line 3357 skipping to change at line 3707
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
/** \brief Basic statistic. Identity matrix of appropriate size. /** \brief Basic statistic. Identity matrix of appropriate size.
*/ */
class CoordinateSystem class CoordinateSystem
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("CoordinateSystem"); return "CoordinateSystem";
return n; // static const std::string n("CoordinateSystem");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef double element_type; typedef double element_type;
typedef Matrix<double> value_type; typedef Matrix<double> value_type;
typedef value_type const & result_type; typedef value_type const & result_type;
skipping to change at line 3385 skipping to change at line 3736
{} {}
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
result_type operator()() const result_type operator()() const
{ {
return value_; return value_;
} }
}; };
}; };
template <class BASE, class T, template <class BASE, class T,
skipping to change at line 3419 skipping to change at line 3770
{} {}
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
void operator+=(SumBaseImpl const & o) void operator+=(SumBaseImpl const & o)
{ {
value_ += o.value_; value_ += o.value_;
} }
result_type operator()() const result_type operator()() const
{ {
return value_; return value_;
} }
}; };
// Count // Count
template <> template <>
class PowerSum<0> class PowerSum<0>
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("PowerSum<0>"); return "PowerSum<0>";
return n; // static const std::string n("PowerSum<0>");
// return n;
} }
template <class T, class BASE> template <class T, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, T, double, double> : public SumBaseImpl<BASE, T, double, double>
{ {
void update(T const & t) void update(T const & t)
{ {
++this->value_; ++this->value_;
} }
skipping to change at line 3469 skipping to change at line 3821
}; };
}; };
// Sum // Sum
template <> template <>
class PowerSum<1> class PowerSum<1>
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("PowerSum<1>"); return "PowerSum<1>";
return n; // static const std::string n("PowerSum<1>");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
void update(U const & t) void update(U const & t)
{ {
this->value_ += t; this->value_ += t;
} }
void update(U const & t, double weight) void update(U const & t, double weight)
{ {
using namespace multi_math;
this->value_ += weight*t; this->value_ += weight*t;
} }
}; };
}; };
/** \brief Basic statistic. PowerSum<N> =@f$ \sum_i x_i^N @f$ /** \brief Basic statistic. PowerSum<N> =@f$ \sum_i x_i^N @f$
Works in pass 1, %operator+=() supported (merging supported). Works in pass 1, %operator+=() supported (merging supported).
*/ */
template <unsigned N> template <unsigned N>
class PowerSum class PowerSum
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("PowerSum<") + asString(N) return std::string("PowerSum<") + asString(N) + ">";
+ ">"; // static const std::string n = std::string("PowerSum<") + asString
return n; (N) + ">";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
void update(U const & t) void update(U const & t)
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
this->value_ += pow(t, (int)N); this->value_ += pow(t, (int)N);
skipping to change at line 3531 skipping to change at line 3887
} }
}; };
}; };
template <> template <>
class AbsPowerSum<1> class AbsPowerSum<1>
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("AbsPowerSum<1>"); return "AbsPowerSum<1>";
return n; // static const std::string n("AbsPowerSum<1>");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
void update(U const & t) void update(U const & t)
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
this->value_ += abs(t); this->value_ += abs(t);
skipping to change at line 3565 skipping to change at line 3922
/** \brief Basic statistic. AbsPowerSum<N> =@f$ \sum_i |x_i|^N @f$ /** \brief Basic statistic. AbsPowerSum<N> =@f$ \sum_i |x_i|^N @f$
Works in pass 1, %operator+=() supported (merging supported). Works in pass 1, %operator+=() supported (merging supported).
*/ */
template <unsigned N> template <unsigned N>
class AbsPowerSum class AbsPowerSum
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("AbsPowerSum<") + asString return std::string("AbsPowerSum<") + asString(N) + ">";
(N) + ">"; // static const std::string n = std::string("AbsPowerSum<") + asStr
return n; ing(N) + ">";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
void update(U const & t) void update(U const & t)
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
this->value_ += pow(abs(t), (int)N); this->value_ += pow(abs(t), (int)N);
skipping to change at line 3612 skipping to change at line 3970
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
this->setClean(); this->setClean();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
void operator+=(CachedResultBase const &) void operator+=(CachedResultBase const &)
{ {
this->setDirty(); this->setDirty();
} }
void update(U const &) void update(U const &)
{ {
this->setDirty(); this->setDirty();
skipping to change at line 3641 skipping to change at line 3999
// cached Mean and Variance // cached Mean and Variance
/** \brief Modifier. Divide statistic by Count: DivideByCount<TAG> = TAG / Count . /** \brief Modifier. Divide statistic by Count: DivideByCount<TAG> = TAG / Count .
*/ */
template <class TAG> template <class TAG>
class DivideByCount class DivideByCount
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename StandardizeTag<TAG>::type TargetTag;
typedef Select<TargetTag, Count> Dependencies; typedef Select<TargetTag, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("DivideByCount<") + Target return std::string("DivideByCount<") + TargetTag::name() + " >";
Tag::name() + " >"; // static const std::string n = std::string("DivideByCount<") + Tar
return n; getTag::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public CachedResultBase<BASE, typename LookupDependency<TargetTag, BA SE>::value_type, U> : public CachedResultBase<BASE, typename LookupDependency<TargetTag, BA SE>::value_type, U>
{ {
typedef typename CachedResultBase<BASE, typename LookupDependency<T argetTag, BASE>::value_type, U>::result_type result_type; typedef typename CachedResultBase<BASE, typename LookupDependency<T argetTag, BASE>::value_type, U>::result_type result_type;
result_type operator()() const result_type operator()() const
{ {
skipping to change at line 3676 skipping to change at line 4035
// UnbiasedVariance // UnbiasedVariance
/** \brief Modifier. Divide statistics by Count-1: DivideUnbiased<TAG> = T AG / (Count-1) /** \brief Modifier. Divide statistics by Count-1: DivideUnbiased<TAG> = T AG / (Count-1)
*/ */
template <class TAG> template <class TAG>
class DivideUnbiased class DivideUnbiased
{ {
public: public:
typedef typename StandardizeTag<TAG>::type TargetTag; typedef typename StandardizeTag<TAG>::type TargetTag;
typedef Select<TargetTag, Count> Dependencies; typedef Select<TargetTag, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("DivideUnbiased<") + Targe return std::string("DivideUnbiased<") + TargetTag::name() + " >";
tTag::name() + " >"; // static const std::string n = std::string("DivideUnbiased<") + Ta
return n; rgetTag::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename LookupDependency<TargetTag, BASE>::value_type val ue_type; typedef typename LookupDependency<TargetTag, BASE>::value_type val ue_type;
typedef value_type result_typ e; typedef value_type result_typ e;
result_type operator()() const result_type operator()() const
skipping to change at line 3707 skipping to change at line 4067
// RootMeanSquares and StdDev // RootMeanSquares and StdDev
/** \brief Modifier. RootDivideByCount<TAG> = sqrt( TAG/Count ) /** \brief Modifier. RootDivideByCount<TAG> = sqrt( TAG/Count )
*/ */
template <class TAG> template <class TAG>
class RootDivideByCount class RootDivideByCount
{ {
public: public:
typedef typename StandardizeTag<DivideByCount<TAG> >::type TargetTag; typedef typename StandardizeTag<DivideByCount<TAG> >::type TargetTag;
typedef Select<TargetTag> Dependencies; typedef Select<TargetTag> Dependencies;
static std::string const & name() static std::string name()
{ {
typedef typename StandardizeTag<TAG>::type InnerTag; typedef typename StandardizeTag<TAG>::type InnerTag;
static const std::string n = std::string("RootDivideByCount<") + In return std::string("RootDivideByCount<") + InnerTag::name() + " >";
nerTag::name() + " >"; // static const std::string n = std::string("RootDivideByCount<") +
return n; InnerTag::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename LookupDependency<TargetTag, BASE>::value_type val ue_type; typedef typename LookupDependency<TargetTag, BASE>::value_type val ue_type;
typedef value_type result_typ e; typedef value_type result_typ e;
result_type operator()() const result_type operator()() const
skipping to change at line 3739 skipping to change at line 4100
// UnbiasedStdDev // UnbiasedStdDev
/** \brief Modifier. RootDivideUnbiased<TAG> = sqrt( TAG / (Count-1) ) /** \brief Modifier. RootDivideUnbiased<TAG> = sqrt( TAG / (Count-1) )
*/ */
template <class TAG> template <class TAG>
class RootDivideUnbiased class RootDivideUnbiased
{ {
public: public:
typedef typename StandardizeTag<DivideUnbiased<TAG> >::type TargetTag; typedef typename StandardizeTag<DivideUnbiased<TAG> >::type TargetTag;
typedef Select<TargetTag> Dependencies; typedef Select<TargetTag> Dependencies;
static std::string const & name() static std::string name()
{ {
typedef typename StandardizeTag<TAG>::type InnerTag; typedef typename StandardizeTag<TAG>::type InnerTag;
static const std::string n = std::string("RootDivideUnbiased<") + I return std::string("RootDivideUnbiased<") + InnerTag::name() + " >"
nnerTag::name() + " >"; ;
return n; // static const std::string n = std::string("RootDivideUnbiased<")
+ InnerTag::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename LookupDependency<TargetTag, BASE>::value_type val ue_type; typedef typename LookupDependency<TargetTag, BASE>::value_type val ue_type;
typedef value_type result_typ e; typedef value_type result_typ e;
result_type operator()() const result_type operator()() const
skipping to change at line 3769 skipping to change at line 4131
}; };
/** \brief Spezialization: works in pass 1, %operator+=() supported (mergin g supported). /** \brief Spezialization: works in pass 1, %operator+=() supported (mergin g supported).
*/ */
template <> template <>
class Central<PowerSum<2> > class Central<PowerSum<2> >
{ {
public: public:
typedef Select<Mean, Count> Dependencies; typedef Select<Mean, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Central<PowerSum<2> >"); return "Central<PowerSum<2> >";
return n; // static const std::string n("Central<PowerSum<2> >");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
void operator+=(Impl const & o) void operator+=(Impl const & o)
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
double n1 = getDependency<Count>(*this), n2 = getDependency<Cou nt>(o); double n1 = getDependency<Count>(*this), n2 = getDependency<Cou nt>(o);
skipping to change at line 3823 skipping to change at line 4186
}; };
/** \brief Specialization: works in pass 2, %operator+=() supported (mergin g supported). /** \brief Specialization: works in pass 2, %operator+=() supported (mergin g supported).
*/ */
template <> template <>
class Central<PowerSum<3> > class Central<PowerSum<3> >
{ {
public: public:
typedef Select<Centralize, Count, Mean, Central<PowerSum<2> > > Depende ncies; typedef Select<Centralize, Count, Mean, Central<PowerSum<2> > > Depende ncies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Central<PowerSum<3> >"); return "Central<PowerSum<3> >";
return n; // static const std::string n("Central<PowerSum<3> >");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
typedef typename SumBaseImpl<BASE, U>::value_type value_type; typedef typename SumBaseImpl<BASE, U>::value_type value_type;
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
skipping to change at line 3878 skipping to change at line 4242
}; };
}; };
/** \brief Specialization: works in pass 2, %operator+=() supported (mergin g supported). /** \brief Specialization: works in pass 2, %operator+=() supported (mergin g supported).
*/ */
template <> template <>
class Central<PowerSum<4> > class Central<PowerSum<4> >
{ {
public: public:
typedef Select<Centralize, Central<PowerSum<3> > > Dependencies; typedef Select<Centralize, Central<PowerSum<3> > > Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Central<PowerSum<4> >"); return "Central<PowerSum<4> >";
return n; // static const std::string n("Central<PowerSum<4> >");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public SumBaseImpl<BASE, U> : public SumBaseImpl<BASE, U>
{ {
typedef typename SumBaseImpl<BASE, U>::value_type value_type; typedef typename SumBaseImpl<BASE, U>::value_type value_type;
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
skipping to change at line 3941 skipping to change at line 4306
/** \brief Basic statistic. Skewness. /** \brief Basic statistic. Skewness.
%Skewness =@f$ \frac{ \frac{1}{n}\sum_i (x_i-\hat{x})^3 }{ (\frac{1}{n} \sum_i (x_i-\hat{x})^2)^{3/2} } @f$ . %Skewness =@f$ \frac{ \frac{1}{n}\sum_i (x_i-\hat{x})^3 }{ (\frac{1}{n} \sum_i (x_i-\hat{x})^2)^{3/2} } @f$ .
Works in pass 2, %operator+=() supported (merging supported). Works in pass 2, %operator+=() supported (merging supported).
*/ */
class Skewness class Skewness
{ {
public: public:
typedef Select<Central<PowerSum<2> >, Central<PowerSum<3> > > Dependenc ies; typedef Select<Central<PowerSum<2> >, Central<PowerSum<3> > > Dependenc ies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Skewness"); return "Skewness";
return n; // static const std::string n("Skewness");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::val ue_type value_type; typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::val ue_type value_type;
typedef value_type result_type; typedef value_type result_type;
result_type operator()() const result_type operator()() const
{ {
typedef Central<PowerSum<3> > Sum3; typedef Central<PowerSum<3> > Sum3;
typedef Central<PowerSum<2> > Sum2; typedef Central<PowerSum<2> > Sum2;
using namespace multi_math; using namespace multi_math;
return sqrt(getDependency<Count>(*this)) * getDependency<Sum3>( *this) / pow(getDependency<Sum2>(*this), 1.5); return sqrt(getDependency<Count>(*this)) * getDependency<Sum3>( *this) / pow(getDependency<Sum2>(*this), 1.5);
} }
}; };
}; };
/** \brief Basic statistic. Unbiased Skewness. /** \brief Basic statistic. Unbiased Skewness.
Works in pass 2, %operator+=() supported (merging supported). Works in pass 2, %operator+=() supported (merging supported).
*/ */
class UnbiasedSkewness class UnbiasedSkewness
{ {
public: public:
typedef Select<Skewness> Dependencies; typedef Select<Skewness> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("UnbiasedSkewness"); return "UnbiasedSkewness";
return n; // static const std::string n("UnbiasedSkewness");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::val ue_type value_type; typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::val ue_type value_type;
typedef value_type result_type; typedef value_type result_type;
result_type operator()() const result_type operator()() const
{ {
using namespace multi_math; using namespace multi_math;
double n = getDependency<Count>(*this); double n = getDependency<Count>(*this);
return sqrt(n*(n-1.0)) / (n - 2.0) * getDependency<Skewness>(*t his); return sqrt(n*(n-1.0)) / (n - 2.0) * getDependency<Skewness>(*t his);
} }
}; };
}; };
/** \brief Basic statistic. Kurtosis. /** \brief Basic statistic. Kurtosis.
%Kurtosis = @f$ \frac{ \frac{1}{n}\sum_i (x_i-\bar{x})^4 }{ %Kurtosis = @f$ \frac{ \frac{1}{n}\sum_i (x_i-\bar{x})^4 }{
(\frac{1}{n} \sum_i(x_i-\bar{x})^2)^2 } - 3 @f$ . (\frac{1}{n} \sum_i(x_i-\bar{x})^2)^2 } - 3 @f$ .
Works in pass 2, %operator+=() supported (merging supported). Works in pass 2, %operator+=() supported (merging supported).
*/ */
class Kurtosis class Kurtosis
{ {
public: public:
typedef Select<Central<PowerSum<2> >, Central<PowerSum<4> > > Dependenc ies; typedef Select<Central<PowerSum<2> >, Central<PowerSum<4> > > Dependenc ies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Kurtosis"); return "Kurtosis";
return n; // static const std::string n("Kurtosis");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::val typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::val
ue_type value_type; ue_type value_type;
typedef value_type typedef value_type
result_type; result_type;
result_type operator()() const result_type operator()() const
{ {
typedef Central<PowerSum<4> > Sum4; typedef Central<PowerSum<4> > Sum4;
typedef Central<PowerSum<2> > Sum2; typedef Central<PowerSum<2> > Sum2;
using namespace multi_math; using namespace multi_math;
return getDependency<Count>(*this) * getDependency<Sum4>(*this) return getDependency<Count>(*this) * getDependency<Sum4>(*this)
/ sq(getDependency<Sum2>(*this)) - value_type(3.0); / sq(getDependency<Sum2>(*this)) - 3.0;
} }
}; };
}; };
/** \brief Basic statistic. Unbiased Kurtosis. /** \brief Basic statistic. Unbiased Kurtosis.
Works in pass 2, %operator+=() supported (merging supported). Works in pass 2, %operator+=() supported (merging supported).
*/ */
class UnbiasedKurtosis class UnbiasedKurtosis
{ {
public: public:
typedef Select<Kurtosis> Dependencies; typedef Select<Kurtosis> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("UnbiasedKurtosis"); return "UnbiasedKurtosis";
return n; // static const std::string n("UnbiasedKurtosis");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
static const unsigned int workInPass = 2; static const unsigned int workInPass = 2;
typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::val ue_type value_type; typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::val ue_type value_type;
typedef value_type result_type; typedef value_type result_type;
result_type operator()() const result_type operator()() const
{ {
using namespace multi_math; using namespace multi_math;
double n = getDependency<Count>(*this); double n = getDependency<Count>(*this);
return (n-1.0)/((n-2.0)*(n-3.0))*((n+1.0)*getDependency<Kurtosi s>(*this) + value_type(6.0)); return (n-1.0)/((n-2.0)*(n-3.0))*((n+1.0)*getDependency<Kurtosi s>(*this) + value_type(6.0));
} }
}; };
}; };
namespace detail { namespace acc_detail {
template <class Scatter, class Sum> template <class Scatter, class Sum>
void updateFlatScatterMatrix(Scatter & sc, Sum const & s, double w) void updateFlatScatterMatrix(Scatter & sc, Sum const & s, double w)
{ {
int size = s.size(); int size = s.size();
for(MultiArrayIndex j=0, k=0; j<size; ++j) for(MultiArrayIndex j=0, k=0; j<size; ++j)
for(MultiArrayIndex i=j; i<size; ++i, ++k) for(MultiArrayIndex i=j; i<size; ++i, ++k)
sc[k] += w*s[i]*s[j]; sc[k] += w*s[i]*s[j];
} }
skipping to change at line 4129 skipping to change at line 4498
} }
} }
} }
template <class Scatter> template <class Scatter>
void flatScatterMatrixToCovariance(double & cov, Scatter const & sc, double n) void flatScatterMatrixToCovariance(double & cov, Scatter const & sc, double n)
{ {
cov = sc / n; cov = sc / n;
} }
} // namespace detail } // namespace acc_detail
// we only store the flattened upper triangular part of the scatter matrix // we only store the flattened upper triangular part of the scatter matrix
/** \brief Basic statistic. Flattened uppter-triangular part of scatter mat rix. /** \brief Basic statistic. Flattened uppter-triangular part of scatter mat rix.
Works in pass 1, %operator+=() supported (merging supported). Works in pass 1, %operator+=() supported (merging supported).
*/ */
class FlatScatterMatrix class FlatScatterMatrix
{ {
public: public:
typedef Select<Mean, Count> Dependencies; typedef Select<Mean, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("FlatScatterMatrix"); return "FlatScatterMatrix";
return n; // static const std::string n("FlatScatterMatrix");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename AccumulatorResultTraits<U>::element_promote_type element_type; typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
typedef typename AccumulatorResultTraits<U>::FlatCovarianceType value_type; typedef typename AccumulatorResultTraits<U>::FlatCovarianceType value_type;
typedef value_type const & result _type; typedef value_type const & result _type;
skipping to change at line 4174 skipping to change at line 4544
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
int size = prod(s); int size = prod(s);
detail::reshapeImpl(value_, Shape1(size*(size+1)/2)); acc_detail::reshapeImpl(value_, Shape1(size*(size+1)/2));
detail::reshapeImpl(diff_, s); acc_detail::reshapeImpl(diff_, s);
} }
void operator+=(Impl const & o) void operator+=(Impl const & o)
{ {
double n1 = getDependency<Count>(*this), n2 = getDependency<Cou nt>(o); double n1 = getDependency<Count>(*this), n2 = getDependency<Cou nt>(o);
if(n1 == 0.0) if(n1 == 0.0)
{ {
value_ = o.value_; value_ = o.value_;
} }
else if(n2 != 0.0) else if(n2 != 0.0)
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
diff_ = getDependency<Mean>(*this) - getDependency<Mean>(o) ; diff_ = getDependency<Mean>(*this) - getDependency<Mean>(o) ;
detail::updateFlatScatterMatrix(value_, diff_, n1 * n2 / (n 1 + n2)); acc_detail::updateFlatScatterMatrix(value_, diff_, n1 * n2 / (n1 + n2));
value_ += o.value_; value_ += o.value_;
} }
} }
void update(U const & t) void update(U const & t)
{ {
compute(t); compute(t);
} }
void update(U const & t, double weight) void update(U const & t, double weight)
skipping to change at line 4217 skipping to change at line 4587
} }
private: private:
void compute(U const & t, double weight = 1.0) void compute(U const & t, double weight = 1.0)
{ {
double n = getDependency<Count>(*this); double n = getDependency<Count>(*this);
if(n > weight) if(n > weight)
{ {
using namespace vigra::multi_math; using namespace vigra::multi_math;
diff_ = getDependency<Mean>(*this) - t; diff_ = getDependency<Mean>(*this) - t;
detail::updateFlatScatterMatrix(value_, diff_, n * weight / (n - weight)); acc_detail::updateFlatScatterMatrix(value_, diff_, n * weig ht / (n - weight));
} }
} }
}; };
}; };
// Covariance // Covariance
template <> template <>
class DivideByCount<FlatScatterMatrix> class DivideByCount<FlatScatterMatrix>
{ {
public: public:
typedef Select<FlatScatterMatrix, Count> Dependencies; typedef Select<FlatScatterMatrix, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("DivideByCount<FlatScatterMatrix>"); return "DivideByCount<FlatScatterMatrix>";
return n; // static const std::string n("DivideByCount<FlatScatterMatrix>");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::Co varianceType, U> : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::Co varianceType, U>
{ {
typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>: :CovarianceType, U> BaseType; typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>: :CovarianceType, U> BaseType;
typedef typename BaseType::result_type result_type; typedef typename BaseType::result_type result_type;
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
int size = prod(s); int size = prod(s);
detail::reshapeImpl(this->value_, Shape2(size,size)); acc_detail::reshapeImpl(this->value_, Shape2(size,size));
} }
result_type operator()() const result_type operator()() const
{ {
if(this->isDirty()) if(this->isDirty())
{ {
detail::flatScatterMatrixToCovariance(this->value_, getDepe ndency<FlatScatterMatrix>(*this), getDependency<Count>(*this)); acc_detail::flatScatterMatrixToCovariance(this->value_, get Dependency<FlatScatterMatrix>(*this), getDependency<Count>(*this));
this->setClean(); this->setClean();
} }
return this->value_; return this->value_;
} }
}; };
}; };
// UnbiasedCovariance // UnbiasedCovariance
template <> template <>
class DivideUnbiased<FlatScatterMatrix> class DivideUnbiased<FlatScatterMatrix>
{ {
public: public:
typedef Select<FlatScatterMatrix, Count> Dependencies; typedef Select<FlatScatterMatrix, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("DivideUnbiased<FlatScatterMatrix>"); return "DivideUnbiased<FlatScatterMatrix>";
return n; // static const std::string n("DivideUnbiased<FlatScatterMatrix>");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::Co varianceType, U> : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::Co varianceType, U>
{ {
typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>: :CovarianceType, U> BaseType; typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>: :CovarianceType, U> BaseType;
typedef typename BaseType::result_type result_type; typedef typename BaseType::result_type result_type;
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
int size = prod(s); int size = prod(s);
detail::reshapeImpl(this->value_, Shape2(size,size)); acc_detail::reshapeImpl(this->value_, Shape2(size,size));
} }
result_type operator()() const result_type operator()() const
{ {
if(this->isDirty()) if(this->isDirty())
{ {
detail::flatScatterMatrixToCovariance(this->value_, getDepe ndency<FlatScatterMatrix>(*this), getDependency<Count>(*this) - 1.0); acc_detail::flatScatterMatrixToCovariance(this->value_, get Dependency<FlatScatterMatrix>(*this), getDependency<Count>(*this) - 1.0);
this->setClean(); this->setClean();
} }
return this->value_; return this->value_;
} }
}; };
}; };
/** Basic statistic. ScatterMatrixEigensystem (?) /** Basic statistic. ScatterMatrixEigensystem (?)
*/ */
class ScatterMatrixEigensystem class ScatterMatrixEigensystem
{ {
public: public:
typedef Select<FlatScatterMatrix> Dependencies; typedef Select<FlatScatterMatrix> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("ScatterMatrixEigensystem"); return "ScatterMatrixEigensystem";
return n; // static const std::string n("ScatterMatrixEigensystem");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename AccumulatorResultTraits<U>::element_promote_type element_type; typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
typedef typename AccumulatorResultTraits<U>::SumType EigenvalueType; typedef typename AccumulatorResultTraits<U>::SumType EigenvalueType;
typedef typename AccumulatorResultTraits<U>::CovarianceType EigenvectorType; typedef typename AccumulatorResultTraits<U>::CovarianceType EigenvectorType;
typedef std::pair<EigenvalueType, EigenvectorType> value_type; typedef std::pair<EigenvalueType, EigenvectorType> value_type;
typedef value_type const & result_type; typedef value_type const & result_type;
mutable value_type value_; mutable value_type value_;
Impl() Impl()
: value_() : value_()
{} {}
void operator+=(Impl const &) void operator+=(Impl const & o)
{ {
if(!acc_detail::hasDataImpl(value_.second))
{
acc_detail::copyShapeImpl(o.value_.first, value_.first);
acc_detail::copyShapeImpl(o.value_.second, value_.second);
}
this->setDirty(); this->setDirty();
} }
void update(U const &) void update(U const &)
{ {
this->setDirty(); this->setDirty();
} }
void update(U const &, double) void update(U const &, double)
{ {
skipping to change at line 4356 skipping to change at line 4734
{ {
value_.first = element_type(); value_.first = element_type();
value_.second = element_type(); value_.second = element_type();
this->setClean(); this->setClean();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
int size = prod(s); int size = prod(s);
detail::reshapeImpl(value_.first, Shape1(size)); acc_detail::reshapeImpl(value_.first, Shape1(size));
detail::reshapeImpl(value_.second, Shape2(size,size)); acc_detail::reshapeImpl(value_.second, Shape2(size,size));
} }
result_type operator()() const result_type operator()() const
{ {
if(this->isDirty()) if(this->isDirty())
{ {
compute(getDependency<FlatScatterMatrix>(*this), value_.fir st, value_.second); compute(getDependency<FlatScatterMatrix>(*this), value_.fir st, value_.second);
this->setClean(); this->setClean();
} }
return value_; return value_;
} }
private: private:
template <class Flat, class EW, class EV> template <class Flat, class EW, class EV>
static void compute(Flat const & flatScatter, EW & ew, EV & ev) static void compute(Flat const & flatScatter, EW & ew, EV & ev)
{ {
EigenvectorType scatter(ev.shape()); EigenvectorType scatter(ev.shape());
detail::flatScatterMatrixToScatterMatrix(scatter, flatScatter); acc_detail::flatScatterMatrixToScatterMatrix(scatter, flatScatt er);
// create a view because EW could be a TinyVector // create a view because EW could be a TinyVector
MultiArrayView<2, element_type> ewview(Shape2(ev.shape(0), 1), &ew[0]); MultiArrayView<2, element_type> ewview(Shape2(ev.shape(0), 1), &ew[0]);
symmetricEigensystem(scatter, ewview, ev); symmetricEigensystem(scatter, ewview, ev);
} }
static void compute(double v, double & ew, double & ev) static void compute(double v, double & ew, double & ev)
{ {
ew = v; ew = v;
ev = 1.0; ev = 1.0;
} }
}; };
}; };
// CovarianceEigensystem // CovarianceEigensystem
template <> template <>
class DivideByCount<ScatterMatrixEigensystem> class DivideByCount<ScatterMatrixEigensystem>
{ {
public: public:
typedef Select<ScatterMatrixEigensystem, Count> Dependencies; typedef Select<ScatterMatrixEigensystem, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("DivideByCount<ScatterMatrixEigensystem> return "DivideByCount<ScatterMatrixEigensystem>";
"); // static const std::string n("DivideByCount<ScatterMatrixEigensyst
return n; em>");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>:: type SMImpl; typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>:: type SMImpl;
typedef typename SMImpl::element_type e lement_type; typedef typename SMImpl::element_type e lement_type;
typedef typename SMImpl::EigenvalueType E igenvalueType; typedef typename SMImpl::EigenvalueType E igenvalueType;
typedef typename SMImpl::EigenvectorType E igenvectorType; typedef typename SMImpl::EigenvectorType E igenvectorType;
skipping to change at line 4444 skipping to change at line 4823
void reset() void reset()
{ {
value_.first = element_type(); value_.first = element_type();
this->setClean(); this->setClean();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
int size = prod(s); int size = prod(s);
detail::reshapeImpl(value_.first, Shape2(size,1)); acc_detail::reshapeImpl(value_.first, Shape2(size,1));
} }
result_type operator()() const result_type operator()() const
{ {
if(this->isDirty()) if(this->isDirty())
{ {
value_.first = getDependency<ScatterMatrixEigensystem>(*thi s).first / getDependency<Count>(*this); value_.first = getDependency<ScatterMatrixEigensystem>(*thi s).first / getDependency<Count>(*this);
this->setClean(); this->setClean();
} }
return value_; return value_;
skipping to change at line 4509 skipping to change at line 4888
// { // {
// value_.first = element_type(); // value_.first = element_type();
// value_.second = element_type(); // value_.second = element_type();
// this->setClean(); // this->setClean();
// } // }
// template <class Shape> // template <class Shape>
// void reshape(Shape const & s) // void reshape(Shape const & s)
// { // {
// int size = prod(s); // int size = prod(s);
// detail::reshapeImpl(value_.first, Shape2(size,1)); // acc_detail::reshapeImpl(value_.first, Shape2(size,1));
// detail::reshapeImpl(value_.second, Shape2(size,size)); // acc_detail::reshapeImpl(value_.second, Shape2(size,size));
// } // }
// result_type operator()() const // result_type operator()() const
// { // {
// if(this->isDirty()) // if(this->isDirty())
// { // {
// compute(getDependency<Covariance>(*this), value_.first, value_.second); // compute(getDependency<Covariance>(*this), value_.first, value_.second);
// this->setClean(); // this->setClean();
// } // }
// return value_; // return value_;
skipping to change at line 4549 skipping to change at line 4928
// covariance eigenvalues // covariance eigenvalues
/** \brief Specialization (covariance eigenvalues): works in pass 1, %opera tor+=() supported (merging). /** \brief Specialization (covariance eigenvalues): works in pass 1, %opera tor+=() supported (merging).
*/ */
template <> template <>
class Principal<PowerSum<2> > class Principal<PowerSum<2> >
{ {
public: public:
typedef Select<ScatterMatrixEigensystem> Dependencies; typedef Select<ScatterMatrixEigensystem> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Principal<PowerSum<2> >"); return "Principal<PowerSum<2> >";
return n; // static const std::string n("Principal<PowerSum<2> >");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>:: type::EigenvalueType value_type; typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>:: type::EigenvalueType value_type;
typedef value_type const & result_type; typedef value_type const & result_type;
result_type operator()() const result_type operator()() const
skipping to change at line 4578 skipping to change at line 4958
// Principal<CoordinateSystem> == covariance eigenvectors // Principal<CoordinateSystem> == covariance eigenvectors
/** \brief Specialization (covariance eigenvectors): works in pass 1, %oper ator+=() supported (merging). /** \brief Specialization (covariance eigenvectors): works in pass 1, %oper ator+=() supported (merging).
*/ */
template <> template <>
class Principal<CoordinateSystem> class Principal<CoordinateSystem>
{ {
public: public:
typedef Select<ScatterMatrixEigensystem> Dependencies; typedef Select<ScatterMatrixEigensystem> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Principal<CoordinateSystem>"); return "Principal<CoordinateSystem>";
return n; // static const std::string n("Principal<CoordinateSystem>");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>:: type::EigenvectorType value_type; typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>:: type::EigenvectorType value_type;
typedef value_type const & result_type; typedef value_type const & result_type;
result_type operator()() const result_type operator()() const
skipping to change at line 4607 skipping to change at line 4988
/** \brief Basic statistic. %Minimum value. /** \brief Basic statistic. %Minimum value.
Works in pass 1, %operator+=() supported (merging supported). Works in pass 1, %operator+=() supported (merging supported).
*/ */
class Minimum class Minimum
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Minimum"); return "Minimum";
return n; // static const std::string n("Minimum");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename AccumulatorResultTraits<U>::element_type element_t ype; typedef typename AccumulatorResultTraits<U>::element_type element_t ype;
typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e; typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e;
typedef value_type const & result_ty pe; typedef value_type const & result_ty pe;
skipping to change at line 4636 skipping to change at line 5018
} }
void reset() void reset()
{ {
value_ = NumericTraits<element_type>::max(); value_ = NumericTraits<element_type>::max();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s, NumericTraits<element_type>::max ()); acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>: :max());
} }
void operator+=(Impl const & o) void operator+=(Impl const & o)
{ {
updateImpl(o.value_); // necessary because std::min causes ambi guous overload updateImpl(o.value_); // necessary because std::min causes ambi guous overload
} }
void update(U const & t) void update(U const & t)
{ {
updateImpl(t); updateImpl(t);
skipping to change at line 4684 skipping to change at line 5066
/** \brief Basic statistic. %Maximum value. /** \brief Basic statistic. %Maximum value.
Works in pass 1, %operator+=() supported (merging supported). Works in pass 1, %operator+=() supported (merging supported).
*/ */
class Maximum class Maximum
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("Maximum"); return "Maximum";
return n; // static const std::string n("Maximum");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename AccumulatorResultTraits<U>::element_type element_t ype; typedef typename AccumulatorResultTraits<U>::element_type element_t ype;
typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e; typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e;
typedef value_type const & result_ty pe; typedef value_type const & result_ty pe;
skipping to change at line 4713 skipping to change at line 5096
} }
void reset() void reset()
{ {
value_ = NumericTraits<element_type>::min(); value_ = NumericTraits<element_type>::min();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s, NumericTraits<element_type>::min ()); acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>: :min());
} }
void operator+=(Impl const & o) void operator+=(Impl const & o)
{ {
updateImpl(o.value_); // necessary because std::max causes ambi guous overload updateImpl(o.value_); // necessary because std::max causes ambi guous overload
} }
void update(U const & t) void update(U const & t)
{ {
updateImpl(t); updateImpl(t);
skipping to change at line 4752 skipping to change at line 5135
} }
template <class T, class Alloc> template <class T, class Alloc>
void updateImpl(MultiArray<1, T, Alloc> const & o) void updateImpl(MultiArray<1, T, Alloc> const & o)
{ {
value_ = multi_math::max(value_, o); value_ = multi_math::max(value_, o);
} }
}; };
}; };
/** \brief Basic statistic. First data value seen of the object.
Usually used as <tt>Coord<FirstSeen></tt> (alias <tt>RegionAnchor</tt>)
which provides a well-defined anchor point for the region.
*/
class FirstSeen
{
public:
typedef Select<Count> Dependencies;
static std::string name()
{
return "FirstSeen";
// static const std::string n("FirstSeen");
// return n;
}
template <class U, class BASE>
struct Impl
: public BASE
{
typedef typename AccumulatorResultTraits<U>::element_type element_t
ype;
typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ
e;
typedef value_type const & result_ty
pe;
value_type value_;
Impl()
: value_()
{}
void reset()
{
value_ = element_type();
}
template <class Shape>
void reshape(Shape const & s)
{
acc_detail::reshapeImpl(value_, s);
}
void operator+=(Impl const & o)
{
// FIXME: only works for Coord<FirstSeen>
if(reverse(o.value_) < reverse(value_))
value_ = o.value_;
}
void update(U const & t)
{
if(getDependency<Count>(*this) == 1)
value_ = t;
}
void update(U const & t, double weight)
{
update(t);
}
result_type operator()() const
{
return value_;
}
};
};
/** \brief Return both the minimum and maximum in <tt>std::pair</tt>.
Usually used as <tt>Coord<Range></tt> (alias <tt>BoundingBox</tt>).
Note that <tt>Range</tt> returns a closed interval, i.e. the upper
limit is part of the range.
*/
class Range
{
public:
typedef Select<Minimum, Maximum> Dependencies;
static std::string name()
{
return "Range";
// static const std::string n("Range");
// return n;
}
template <class U, class BASE>
struct Impl
: public BASE
{
typedef typename AccumulatorResultTraits<U>::MinmaxType minmax_ty
pe;
typedef std::pair<minmax_type, minmax_type> value_typ
e;
typedef value_type result_ty
pe;
result_type operator()() const
{
return value_type(getDependency<Minimum>(*this), getDependency<
Maximum>(*this));
}
};
};
/** \brief Basic statistic. Data value where weight assumes its minimal val ue. /** \brief Basic statistic. Data value where weight assumes its minimal val ue.
Weights must be given. Coord<ArgMinWeight> gives coordinate where weigh t assumes its minimal value. Works in pass 1, %operator+=() supported (merg ing supported). Weights must be given. Coord<ArgMinWeight> gives coordinate where weigh t assumes its minimal value. Works in pass 1, %operator+=() supported (merg ing supported).
*/ */
class ArgMinWeight class ArgMinWeight
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("ArgMinWeight"); return "ArgMinWeight";
return n; // static const std::string n("ArgMinWeight");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename AccumulatorResultTraits<U>::element_type element_t ype; typedef typename AccumulatorResultTraits<U>::element_type element_t ype;
typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e; typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e;
typedef value_type const & result_ty pe; typedef value_type const & result_ty pe;
skipping to change at line 4792 skipping to change at line 5276
void reset() void reset()
{ {
min_weight_ = NumericTraits<double>::max(); min_weight_ = NumericTraits<double>::max();
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
void operator+=(Impl const & o) void operator+=(Impl const & o)
{ {
using namespace multi_math; using namespace multi_math;
if(o.min_weight_ < min_weight_) if(o.min_weight_ < min_weight_)
{ {
min_weight_ = o.min_weight_; min_weight_ = o.min_weight_;
value_ = o.value_; value_ = o.value_;
} }
skipping to change at line 4835 skipping to change at line 5319
/** \brief Basic statistic. Data where weight assumes its maximal value. /** \brief Basic statistic. Data where weight assumes its maximal value.
Weights must be given. Coord<ArgMinWeight> gives coordinate where weigh t assumes its maximal value. Works in pass 1, %operator+=() supported (merg ing supported). Weights must be given. Coord<ArgMinWeight> gives coordinate where weigh t assumes its maximal value. Works in pass 1, %operator+=() supported (merg ing supported).
*/ */
class ArgMaxWeight class ArgMaxWeight
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n("ArgMaxWeight"); return "ArgMaxWeight";
return n; // static const std::string n("ArgMaxWeight");
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public BASE : public BASE
{ {
typedef typename AccumulatorResultTraits<U>::element_type element_t ype; typedef typename AccumulatorResultTraits<U>::element_type element_t ype;
typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e; typedef typename AccumulatorResultTraits<U>::MinmaxType value_typ e;
typedef value_type const & result_ty pe; typedef value_type const & result_ty pe;
skipping to change at line 4866 skipping to change at line 5351
void reset() void reset()
{ {
max_weight_ = NumericTraits<double>::min(); max_weight_ = NumericTraits<double>::min();
value_ = element_type(); value_ = element_type();
} }
template <class Shape> template <class Shape>
void reshape(Shape const & s) void reshape(Shape const & s)
{ {
detail::reshapeImpl(value_, s); acc_detail::reshapeImpl(value_, s);
} }
void operator+=(Impl const & o) void operator+=(Impl const & o)
{ {
using namespace multi_math; using namespace multi_math;
if(o.max_weight_ > max_weight_) if(o.max_weight_ > max_weight_)
{ {
max_weight_ = o.max_weight_; max_weight_ = o.max_weight_;
value_ = o.value_; value_ = o.value_;
} }
skipping to change at line 4967 skipping to change at line 5452
void reset() void reset()
{ {
value_ = element_type(); value_ = element_type();
left_outliers = 0.0; left_outliers = 0.0;
right_outliers = 0.0; right_outliers = 0.0;
} }
void operator+=(HistogramBase const & o) void operator+=(HistogramBase const & o)
{ {
value_ += o.value_; if(value_.size() == 0)
{
value_ = o.value_;
}
else if(o.value_.size() > 0)
{
vigra_precondition(value_.size() == o.value_.size(),
"HistogramBase::operator+=(): bin counts must be equal.");
value_ += o.value_;
}
left_outliers += o.left_outliers; left_outliers += o.left_outliers;
right_outliers += o.right_outliers; right_outliers += o.right_outliers;
} }
void setBinCount(int binCount) void setBinCount(int binCount)
{ {
vigra_precondition(binCount > 0, vigra_precondition(binCount > 0,
"HistogramBase:.setBinCount(): binCount > 0 required."); "HistogramBase:.setBinCount(): binCount > 0 required.");
value_type(Shape1(binCount)).swap(value_); value_type(Shape1(binCount)).swap(value_);
} }
skipping to change at line 5043 skipping to change at line 5537
else if(index >= (int)this->value_.size()) else if(index >= (int)this->value_.size())
this->right_outliers += weight; this->right_outliers += weight;
else else
this->value_[index] += weight; this->value_[index] += weight;
} }
void setMinMax(double mi, double ma) void setMinMax(double mi, double ma)
{ {
vigra_precondition(this->value_.size() > 0, vigra_precondition(this->value_.size() > 0,
"RangeHistogramBase::setMinMax(...): setBinCount(...) has not b een called."); "RangeHistogramBase::setMinMax(...): setBinCount(...) has not b een called.");
vigra_precondition(mi < ma, vigra_precondition(mi <= ma,
"RangeHistogramBase::setMinMax(...): min < max required."); "RangeHistogramBase::setMinMax(...): min <= max required.");
if(mi == ma)
ma += this->value_.size() * NumericTraits<double>::epsilon();
offset_ = mi; offset_ = mi;
scale_ = (double)this->value_.size() / (ma - mi); scale_ = (double)this->value_.size() / (ma - mi);
inverse_scale_ = 1.0 / scale_; inverse_scale_ = 1.0 / scale_;
} }
double mapItem(double t) const double mapItem(double t) const
{ {
return scale_ * (t - offset_); return scale_ * (t - offset_);
} }
double mapItemInverse(double t) const double mapItemInverse(double t) const
{ {
return inverse_scale_ * t + offset_; return inverse_scale_ * t + offset_;
} }
template <class ArrayLike> template <class ArrayLike>
void computeStandardQuantiles(double minimum, double maximum, double co unt, void computeStandardQuantiles(double minimum, double maximum, double co unt,
ArrayLike const & desiredQuantiles, Array Like & res) const ArrayLike const & desiredQuantiles, Array Like & res) const
{ {
if(count == 0.0) {
return;
}
ArrayVector<double> keypoints, cumhist; ArrayVector<double> keypoints, cumhist;
double mappedMinimum = mapItem(minimum); double mappedMinimum = mapItem(minimum);
double mappedMaximum = mapItem(maximum); double mappedMaximum = mapItem(maximum);
keypoints.push_back(mappedMinimum); keypoints.push_back(mappedMinimum);
cumhist.push_back(0.0); cumhist.push_back(0.0);
if(this->left_outliers > 0.0) if(this->left_outliers > 0.0)
{ {
keypoints.push_back(0.0); keypoints.push_back(0.0);
skipping to change at line 5157 skipping to change at line 5657
- Note that histogram options (for all histograms in the accumulator ch ain) can also be set by passing an instance of HistogramOptions to the accu mulator chain via acc_chain.setHistogramOptions(). - Note that histogram options (for all histograms in the accumulator ch ain) can also be set by passing an instance of HistogramOptions to the accu mulator chain via acc_chain.setHistogramOptions().
Works in pass 1, %operator+=() supported (merging supported). Works in pass 1, %operator+=() supported (merging supported).
*/ */
template <int BinCount> template <int BinCount>
class IntegerHistogram class IntegerHistogram
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("IntegerHistogram<") + asS return std::string("IntegerHistogram<") + asString(BinCount) + ">";
tring(BinCount) + ">"; // static const std::string n = std::string("IntegerHistogram<") +
return n; asString(BinCount) + ">";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public HistogramBase<BASE, BinCount> : public HistogramBase<BASE, BinCount>
{ {
void update(int index) void update(int index)
{ {
if(index < 0) if(index < 0)
++this->left_outliers; ++this->left_outliers;
skipping to change at line 5269 skipping to change at line 5770
- Outliers can be accessed via getAccumulator<...>(a).left_outliers and getAccumulator<...>(a).right_outliers. - Outliers can be accessed via getAccumulator<...>(a).left_outliers and getAccumulator<...>(a).right_outliers.
- Note that histogram options (for all histograms in the accumulator ch ain) can also be set by passing an instance of HistogramOptions to the accu mulator chain via acc_chain.setHistogramOptions(). - Note that histogram options (for all histograms in the accumulator ch ain) can also be set by passing an instance of HistogramOptions to the accu mulator chain via acc_chain.setHistogramOptions().
*/ */
template <int BinCount> template <int BinCount>
class UserRangeHistogram class UserRangeHistogram
{ {
public: public:
typedef Select<> Dependencies; typedef Select<> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("UserRangeHistogram<") + a return std::string("UserRangeHistogram<") + asString(BinCount) + ">
sString(BinCount) + ">"; ";
return n; // static const std::string n = std::string("UserRangeHistogram<")
+ asString(BinCount) + ">";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public RangeHistogramBase<BASE, BinCount, U> : public RangeHistogramBase<BASE, BinCount, U>
{ {
void update(U const & t) void update(U const & t)
{ {
update(t, 1.0); update(t, 1.0);
} }
skipping to change at line 5310 skipping to change at line 5812
- Outliers can be accessed via getAccumulator<...>(acc_chain).left_outl iers and getAccumulator<...>(acc_chain).right_outliers . - Outliers can be accessed via getAccumulator<...>(acc_chain).left_outl iers and getAccumulator<...>(acc_chain).right_outliers .
- Note that histogram options (for all histograms in the accumulator ch ain) can also be set by passing an instance of HistogramOptions to the accu mulator chain via acc_chain.setHistogramOptions(). - Note that histogram options (for all histograms in the accumulator ch ain) can also be set by passing an instance of HistogramOptions to the accu mulator chain via acc_chain.setHistogramOptions().
*/ */
template <int BinCount> template <int BinCount>
class AutoRangeHistogram class AutoRangeHistogram
{ {
public: public:
typedef Select<Minimum, Maximum> Dependencies; typedef Select<Minimum, Maximum> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("AutoRangeHistogram<") + a return std::string("AutoRangeHistogram<") + asString(BinCount) + ">
sString(BinCount) + ">"; ";
return n; // static const std::string n = std::string("AutoRangeHistogram<")
+ asString(BinCount) + ">";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public RangeHistogramBase<BASE, BinCount, U> : public RangeHistogramBase<BASE, BinCount, U>
{ {
static const unsigned int workInPass = LookupDependency<Minimum, BA SE>::type::workInPass + 1; static const unsigned int workInPass = LookupDependency<Minimum, BA SE>::type::workInPass + 1;
void update(U const & t) void update(U const & t)
{ {
skipping to change at line 5353 skipping to change at line 5856
- Outliers can be accessed via getAccumulator<GlobalRangeHistogram<Binc ount>>(acc_chain).left_outliers and getAccumulator<...>(acc_chain).right_ou tliers . - Outliers can be accessed via getAccumulator<GlobalRangeHistogram<Binc ount>>(acc_chain).left_outliers and getAccumulator<...>(acc_chain).right_ou tliers .
- Histogram options (for all histograms in the accumulator chain) can a lso be set by passing an instance of HistogramOptions to the accumulator ch ain via acc_chain.setHistogramOptions(). - Histogram options (for all histograms in the accumulator chain) can a lso be set by passing an instance of HistogramOptions to the accumulator ch ain via acc_chain.setHistogramOptions().
*/ */
template <int BinCount> template <int BinCount>
class GlobalRangeHistogram class GlobalRangeHistogram
{ {
public: public:
typedef Select<Global<Minimum>, Global<Maximum>, Minimum, Maximum> Depe ndencies; typedef Select<Global<Minimum>, Global<Maximum>, Minimum, Maximum> Depe ndencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("GlobalRangeHistogram<") + return std::string("GlobalRangeHistogram<") + asString(BinCount) +
asString(BinCount) + ">"; ">";
return n; // static const std::string n = std::string("GlobalRangeHistogram<"
) + asString(BinCount) + ">";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public RangeHistogramBase<BASE, BinCount, U> : public RangeHistogramBase<BASE, BinCount, U>
{ {
static const unsigned int workInPass = LookupDependency<Minimum, BA SE>::type::workInPass + 1; static const unsigned int workInPass = LookupDependency<Minimum, BA SE>::type::workInPass + 1;
bool useLocalMinimax_; bool useLocalMinimax_;
skipping to change at line 5409 skipping to change at line 5913
Return type is TinyVector<double, 7> . Return type is TinyVector<double, 7> .
*/ */
template <class HistogramAccumulator> template <class HistogramAccumulator>
class StandardQuantiles class StandardQuantiles
{ {
public: public:
typedef typename StandardizeTag<HistogramAccumulator>::type HistogramTa g; typedef typename StandardizeTag<HistogramAccumulator>::type HistogramTa g;
typedef Select<HistogramTag, Minimum, Maximum, Count> Dependencies; typedef Select<HistogramTag, Minimum, Maximum, Count> Dependencies;
static std::string const & name() static std::string name()
{ {
static const std::string n = std::string("StandardQuantiles<") + Hi return std::string("StandardQuantiles<") + HistogramTag::name() + "
stogramTag::name() + " >"; >";
return n; // static const std::string n = std::string("StandardQuantiles<") +
HistogramTag::name() + " >";
// return n;
} }
template <class U, class BASE> template <class U, class BASE>
struct Impl struct Impl
: public CachedResultBase<BASE, TinyVector<double, 7>, U> : public CachedResultBase<BASE, TinyVector<double, 7>, U>
{ {
typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>:: result_type result_type; typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>:: result_type result_type;
typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>:: value_type value_type; typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>:: value_type value_type;
static const unsigned int workInPass = LookupDependency<HistogramTa g, BASE>::type::workInPass; static const unsigned int workInPass = LookupDependency<HistogramTa g, BASE>::type::workInPass;
result_type operator()() const result_type operator()() const
{ {
if(this->isDirty()) if(this->isDirty())
{ {
static const double desiredQuantiles[] = {0.0, 0.1, 0.25, 0 .5, 0.75, 0.9, 1.0 }; double desiredQuantiles[] = {0.0, 0.1, 0.25, 0.5, 0.75, 0.9 , 1.0 };
getAccumulator<HistogramTag>(*this).computeStandardQuantile s(getDependency<Minimum>(*this), getDependency<Maximum>(*this), getAccumulator<HistogramTag>(*this).computeStandardQuantile s(getDependency<Minimum>(*this), getDependency<Maximum>(*this),
getDependency<Count>(*this), value_type(desiredQuantiles), getDependency<Count>(*this), value_type(desiredQuantiles),
this->value_); this->value_);
this->setClean(); this->setClean();
} }
return this->value_; return this->value_;
} }
}; };
}; };
template <int N>
struct feature_RegionContour_can_only_be_computed_for_2D_arrays
: vigra::staticAssert::AssertBool<N==2>
{};
/** \brief Compute the contour of a 2D region.
AccumulatorChain must be used with CoupledIterator in order to have acc
ess to pixel coordinates.
*/
class RegionContour
{
public:
typedef Select<Count> Dependencies;
static std::string name()
{
return std::string("RegionContour");
// static const std::string n = std::string("RegionContour");
// return n;
}
template <class T, class BASE>
struct Impl
: public BASE
{
typedef HandleArgSelector<T, LabelArgTag, BASE> Label
Handle;
typedef TinyVector<double, 2> point
_type;
typedef Polygon<point_type> value
_type;
typedef value_type const & resul
t_type;
point_type offset_;
value_type contour_;
Impl()
: offset_()
, contour_()
{}
void setCoordinateOffset(point_type const & offset)
{
offset_ = offset;
}
template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t)
{
VIGRA_STATIC_ASSERT((feature_RegionContour_can_only_be_computed
_for_2D_arrays<
CoupledHandle<U, NEXT>::dimensions>));
if(getDependency<Count>(*this) == 1)
{
contour_.clear();
extractContour(LabelHandle::getHandle(t).arrayView(), t.poi
nt(), contour_);
contour_ += offset_;
}
}
template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t, double weight)
{
update(t);
}
void operator+=(Impl const & o)
{
vigra_precondition(false,
"RegionContour::operator+=(): RegionContour cannot be merge
d.");
}
result_type operator()() const
{
return contour_;
}
};
};
/** \brief Compute the perimeter of a 2D region.
This is the length of the polygon returned by RegionContour.
AccumulatorChain must be used with CoupledIterator in order to have acc
ess to pixel coordinates.
*/
class RegionPerimeter
{
public:
typedef Select<RegionContour> Dependencies;
static std::string name()
{
return std::string("RegionPerimeter");
// static const std::string n = std::string("RegionPerimeter");
// return n;
}
template <class T, class BASE>
struct Impl
: public BASE
{
typedef double value_type;
typedef value_type result_type;
result_type operator()() const
{
return getDependency<RegionContour>(*this).length();
}
};
};
/** \brief Compute the circularity of a 2D region.
The is the ratio between the perimeter of a circle with the same area a
s the
present region and the perimeter of the region, i.e. \f[c = \frac{2 \sq
rt{\pi a}}{p} \f], where a and p are the area and length of the polygon ret
urned by RegionContour.
AccumulatorChain must be used with CoupledIterator in order to have acc
ess to pixel coordinates.
*/
class RegionCircularity
{
public:
typedef Select<Count, RegionContour> Dependencies;
static std::string name()
{
return std::string("RegionCircularity");
// static const std::string n = std::string("RegionCircularity");
// return n;
}
template <class T, class BASE>
struct Impl
: public BASE
{
typedef double value_type;
typedef value_type result_type;
result_type operator()() const
{
return 2.0*sqrt(M_PI*getDependency<RegionContour>(*this).area()
) / getDependency<RegionContour>(*this).length();
}
};
};
/** \brief Compute the eccentricity of a 2D region in terms of its prinipal
radii.
Formula: \f[ e = \sqrt{1 - m^2 / M^2 } \f], where m and M are the minor
and major principal radius.
AccumulatorChain must be used with CoupledIterator in order to have acc
ess to pixel coordinates.
*/
class RegionEccentricity
{
public:
typedef Select<RegionRadii> Dependencies;
static std::string name()
{
return std::string("RegionEccentricity");
// static const std::string n = std::string("RegionEccentricity");
// return n;
}
template <class T, class BASE>
struct Impl
: public BASE
{
typedef double value_type;
typedef value_type result_type;
result_type operator()() const
{
double M = getDependency<RegionRadii>(*this).front(),
m = getDependency<RegionRadii>(*this).back();
return sqrt(1.0 - sq(m/M));
}
};
};
template <int N>
struct feature_ConvexHull_can_only_be_computed_for_2D_arrays
: vigra::staticAssert::AssertBool<N==2>
{};
/** \brief Compute the contour of a 2D region.
AccumulatorChain must be used with CoupledIterator in order to have acc
ess to pixel coordinates.
*/
class ConvexHull
{
public:
typedef Select<BoundingBox, RegionContour, RegionCenter> Dependencies;
static std::string name()
{
return std::string("ConvexHull");
// static const std::string n = std::string("ConvexHull");
// return n;
}
template <class T, class BASE>
struct Impl
: public BASE
{
static const unsigned int workInPass = 2;
typedef HandleArgSelector<T, LabelArgTag, BASE> Label
Handle;
typedef TinyVector<double, 2> point
_type;
typedef Polygon<point_type> polyg
on_type;
typedef Impl value
_type;
typedef value_type const & resul
t_type;
polygon_type convex_hull_;
point_type input_center_, convex_hull_center_, defect_center_;
double convexity_, rugosity_, mean_defect_displacement_,
defect_area_mean_, defect_area_variance_, defect_area_skewne
ss_, defect_area_kurtosis_;
int convexity_defect_count_;
ArrayVector<MultiArrayIndex> convexity_defect_area_;
bool features_computed_;
Impl()
: convex_hull_()
, input_center_()
, convex_hull_center_()
, defect_center_()
, convexity_()
, rugosity_()
, mean_defect_displacement_()
, defect_area_mean_()
, defect_area_variance_()
, defect_area_skewness_()
, defect_area_kurtosis_()
, convexity_defect_count_()
, convexity_defect_area_()
, features_computed_(false)
{}
template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t)
{
VIGRA_STATIC_ASSERT((feature_ConvexHull_can_only_be_computed_fo
r_2D_arrays<
CoupledHandle<U, NEXT>::dimensions>));
if(!features_computed_)
{
using namespace functor;
Shape2 start = getDependency<Coord<Minimum> >(*this),
stop = getDependency<Coord<Maximum> >(*this) + Shap
e2(1);
point_type offset(start);
input_center_ = getDependency<RegionCenter>(*this);
MultiArrayIndex label = LabelHandle::getValue(t);
convex_hull_.clear();
convexHull(getDependency<RegionContour>(*this), convex_hull
_);
convex_hull_center_ = centroid(convex_hull_);
convexity_ = getDependency<RegionContour>(*this).area() / c
onvex_hull_.area();
rugosity_ = getDependency<RegionContour>(*this).length() /
convex_hull_.length();
MultiArray<2, UInt8> convex_hull_difference(stop-start);
fillPolygon(convex_hull_ - offset, convex_hull_difference,
1);
combineTwoMultiArrays(convex_hull_difference,
LabelHandle::getHandle(t).arrayView()
.subarray(start, stop),
convex_hull_difference,
ifThenElse(Arg2() == Param(label), Pa
ram(0), Arg1()));
MultiArray<2, UInt32> convexity_defects(stop-start);
convexity_defect_count_ =
labelImageWithBackground(convex_hull_difference, convexi
ty_defects, false, 0);
if (convexity_defect_count_ != 0)
{
AccumulatorChainArray<CoupledArrays<2, UInt32>,
Select<LabelArg<1>, Count, Region
Center> > convexity_defects_stats;
convexity_defects_stats.ignoreLabel(0);
extractFeatures(convexity_defects, convexity_defects_st
ats);
double total_defect_area = 0.0;
mean_defect_displacement_ = 0.0;
defect_center_ = point_type();
for (int k = 1; k <= convexity_defect_count_; ++k)
{
double area = get<Count>(convexity_defects_stats, k
);
point_type center = get<RegionCenter>(convexity_def
ects_stats, k) + offset;
convexity_defect_area_.push_back(area);
total_defect_area += area;
defect_center_ += area*center;
mean_defect_displacement_ += area*norm(input_center
_ - center);
}
sort(convexity_defect_area_.begin(), convexity_defect_a
rea_.end(),
std::greater<MultiArrayIndex>());
mean_defect_displacement_ /= total_defect_area;
defect_center_ /= total_defect_area;
AccumulatorChain<MultiArrayIndex,
Select<Mean, UnbiasedVariance, Unbiase
dSkewness, UnbiasedKurtosis> > defect_area_stats;
extractFeatures(convexity_defect_area_.begin(),
convexity_defect_area_.end(), defect_ar
ea_stats);
defect_area_mean_ = convexity_defect_count_ > 0
? get<Mean>(defect_area_stats)
: 0.0;
defect_area_variance_ = convexity_defect_count_ > 1
? get<UnbiasedVariance>(defect_area_stats)
: 0.0;
defect_area_skewness_ = convexity_defect_count_ > 2
? get<UnbiasedSkewness>(defect_area_stats)
: 0.0;
defect_area_kurtosis_ = convexity_defect_count_ > 3
? get<UnbiasedKurtosis>(defect_area_stats)
: 0.0;
}
/**********************************************/
features_computed_ = true;
}
}
template <class U, class NEXT>
void update(CoupledHandle<U, NEXT> const & t, double weight)
{
update(t);
}
void operator+=(Impl const & o)
{
vigra_precondition(false,
"ConvexHull::operator+=(): ConvexHull features cannot be me
rged.");
}
result_type operator()() const
{
return *this;
}
/*
* Returns the convex hull polygon.
*/
polygon_type const & hull() const
{
return convex_hull_;
}
/*
* Returns the area enclosed by the input polygon.
*/
double inputArea() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return getDependency<RegionContour>(*this).area();
}
/*
* Returns the area enclosed by the convex hull polygon.
*/
double hullArea() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return convex_hull_.area();
}
/*
* Returns the perimeter of the input polygon.
*/
double inputPerimeter() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return getDependency<RegionContour>(*this).length();
}
/*
* Returns the perimeter of the convex hull polygon.
*/
double hullPerimeter() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return convex_hull_.length();
}
/*
* Center of the original region.
*/
point_type const & inputCenter() const
{
return input_center_;
}
/*
* Center of the region enclosed by the convex hull.
*/
point_type const & hullCenter() const
{
return convex_hull_center_;
}
/*
* Center of difference between the convex hull and the original re
gion.
*/
point_type const & convexityDefectCenter() const
{
return defect_center_;
}
/*
* Returns the ratio between the input area and the convex hull are
a.
* This is always <tt><= 1</tt>, and the smaller the value is,
* the less convex is the input polygon.
*/
double convexity() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return convexity_;
}
/*
* Returns the ratio between the input perimeter and the convex per
imeter.
* This is always <tt>>= 1</tt>, and the higher the value is, the l
ess
* convex is the input polygon.
*/
double rugosity() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return rugosity_;
}
/*
* Returns the number of convexity defects (i.e. number of connecte
d components
* of the difference between convex hull and input region).
*/
int convexityDefectCount() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return convexity_defect_count_;
}
/*
* Returns the mean area of the convexity defects.
*/
double convexityDefectAreaMean() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return defect_area_mean_;
}
/*
* Returns the variance of the convexity defect areas.
*/
double convexityDefectAreaVariance() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return defect_area_variance_;
}
/*
* Returns the skewness of the convexity defect areas.
*/
double convexityDefectAreaSkewness() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return defect_area_skewness_;
}
/*
* Returns the kurtosis of the convexity defect areas.
*/
double convexityDefectAreaKurtosis() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return defect_area_kurtosis_;
}
/*
* Returns the mean distance between the defect areas and the cente
r of
* the input region, weighted by the area of each defect region.
*/
double meanDefectDisplacement() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return mean_defect_displacement_;
}
/*
* Returns the areas of the convexity defect regions (ordered desce
nding).
*/
ArrayVector<MultiArrayIndex> const & defectAreaList() const
{
vigra_precondition(features_computed_,
"ConvexHull: features must be calculated first.");
return convexity_defect_area_;
}
};
};
}} // namespace vigra::acc }} // namespace vigra::acc
#endif // VIGRA_ACCUMULATOR_HXX #endif // VIGRA_ACCUMULATOR_HXX
 End of changes. 272 change blocks. 
474 lines changed or deleted 1621 lines changed or added


 affine_registration.hxx   affine_registration.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_AFFINE_REGISTRATION_HXX #ifndef VIGRA_AFFINE_REGISTRATION_HXX
#define VIGRA_AFFINE_REGISTRATION_HXX #define VIGRA_AFFINE_REGISTRATION_HXX
#include "mathutil.hxx" #include "mathutil.hxx"
#include "matrix.hxx" #include "matrix.hxx"
#include "linear_solve.hxx" #include "linear_solve.hxx"
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "splineimageview.hxx" #include "splineimageview.hxx"
#include "imagecontainer.hxx" #include "imagecontainer.hxx"
#include "multi_shape.hxx"
#include <cmath> #include <cmath>
namespace vigra { namespace vigra {
/** \addtogroup Registration Image Registration /** \addtogroup Registration Image Registration
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* affineMatrix2DFromCorrespondingPoints */ /* affineMatrix2DFromCorrespondingPoints */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Create homogeneous matrix that maps corresponding points onto ea ch other. /** \brief Create homogeneous matrix that maps corresponding points onto ea ch other.
For use with \ref affineWarpImage(). Since only two corresponding point For use with \ref affineWarpImage(). When only two corresponding points
s are given, are given,
the matrix will not use a full affine transform, but only a similarity the matrix will only represent a similarity transform
transform (translation, rotation, and uniform scaling). When only one point pair
(translation, rotation, and uniform scaling). See \ is given,
the result will be a pure translation.
*/ */
template <class SrcIterator, class DestIterator> template <class SrcIterator, class DestIterator>
linalg::TemporaryMatrix<double> linalg::TemporaryMatrix<double>
affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, Dest Iterator d) affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, Dest Iterator d)
{ {
int size = send - s; int size = send - s;
linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3)); linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
if(size == 1) if(size == 1)
skipping to change at line 403 skipping to change at line 406
/** \brief Estimate the optical flow between two images according to a tran slation model. /** \brief Estimate the optical flow between two images according to a tran slation model.
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/affine_registration.hxx\><br> <b>\#include</b> \<vigra/affine_registration.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
int SPLINEORDER>
void
estimateTranslation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons
t & options = AffineMotionEstimationOptions<SPLINEORDER>());
}
\endcode
\deprecatedAPI{estimateTranslation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER = 2> int SPLINEORDER = 2>
void void
estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor s rc, estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor s rc,
DestIterator dul, DestIterator dlr, DestAccesso r dest, DestIterator dul, DestIterator dlr, DestAccesso r dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons t & options = AffineMotionEstimationOptions<SPLINEORDER> cons t & options =
AffineMotionEstimat ionOptions<>()) AffineMotionEstimat ionOptions<>())
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER = 2> int SPLINEORDER = 2>
void void
estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
triple<DestIterator, DestIterator, DestAccessor > dest, triple<DestIterator, DestIterator, DestAccessor > dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons t & options = AffineMotionEstimationOptions<SPLINEORDER> cons t & options =
AffineMotionEstimat ionOptions<>()) AffineMotionEstimat ionOptions<>())
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void estimateTranslation) doxygen_overloaded_function(template <...> void estimateTranslation)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER> int SPLINEORDER>
inline void inline void
estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src, estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestIterator dlr, DestAccessor dest, DestIterator dul, DestIterator dlr, DestAccessor dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
skipping to change at line 483 skipping to change at line 501
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src, estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<DestIterator, DestIterator, DestAccessor> dest, triple<DestIterator, DestIterator, DestAccessor> dest,
Matrix<double> & affineMatrix) Matrix<double> & affineMatrix)
{ {
estimateTranslation(src.first, src.second, src.third, dest.first, dest. second, dest.third, estimateTranslation(src.first, src.second, src.third, dest.first, dest. second, dest.third,
affineMatrix, AffineMotionEstimationOptions<>()); affineMatrix, AffineMotionEstimationOptions<>());
} }
template <class T1, class S1,
class T2, class S2,
int SPLINEORDER>
inline void
estimateTranslation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> const & opti
ons)
{
estimateTranslation(srcImageRange(src), destImageRange(dest),
affineMatrix, options);
}
template <class T1, class S1,
class T2, class S2>
inline void
estimateTranslation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix)
{
estimateTranslation(srcImageRange(src), destImageRange(dest),
affineMatrix, AffineMotionEstimationOptions<>());
}
/********************************************************/ /********************************************************/
/* */ /* */
/* estimateSimilarityTransform */ /* estimateSimilarityTransform */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Estimate the optical flow between two images according to a simi larity transform model /** \brief Estimate the optical flow between two images according to a simi larity transform model
(e.g. translation, rotation, and uniform scaling). (e.g. translation, rotation, and uniform scaling).
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/affine_registration.hxx\><br> <b>\#include</b> \<vigra/affine_registration.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
int SPLINEORDER>
void
estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORD
ER> const & options =
AffineMotionEstimat
ionOptions<SPLINEORDER>());
}
\endcode
\deprecatedAPI{estimateSimilarityTransform}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER = 2> int SPLINEORDER = 2>
void void
estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAc cessor src, estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAc cessor src,
DestIterator dul, DestIterator dlr, DestAccesso r dest, DestIterator dul, DestIterator dlr, DestAccesso r dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons t & options = AffineMotionEstimationOptions<SPLINEORDER> cons t & options =
AffineMotionEstimat ionOptions<>()) AffineMotionEstimat ionOptions<>())
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER = 2> int SPLINEORDER = 2>
void void
estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAcc essor> src, estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAcc essor> src,
triple<DestIterator, DestIterator, DestAccessor > dest, triple<DestIterator, DestIterator, DestAccessor > dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons t & options = AffineMotionEstimationOptions<SPLINEORDER> cons t & options =
AffineMotionEstimat ionOptions<>()) AffineMotionEstimat ionOptions<>())
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void estimateSimilarityTransform ) doxygen_overloaded_function(template <...> void estimateSimilarityTransform )
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER> int SPLINEORDER>
inline void inline void
estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAccessor s rc, estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAccessor s rc,
DestIterator dul, DestIterator dlr, DestAccesso r dest, DestIterator dul, DestIterator dlr, DestAccesso r dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
skipping to change at line 579 skipping to change at line 637
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
triple<DestIterator, DestIterator, DestAccessor > dest, triple<DestIterator, DestIterator, DestAccessor > dest,
Matrix<double> & affineMatrix) Matrix<double> & affineMatrix)
{ {
estimateSimilarityTransform(src.first, src.second, src.third, dest.firs t, dest.second, dest.third, estimateSimilarityTransform(src.first, src.second, src.third, dest.firs t, dest.second, dest.third,
affineMatrix, AffineMotionEstimationOptions <>()); affineMatrix, AffineMotionEstimationOptions <>());
} }
template <class T1, class S1,
class T2, class S2,
int SPLINEORDER>
inline void
estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons
t & options)
{
estimateSimilarityTransform(srcImageRange(src), destImageRange(dest),
affineMatrix, options);
}
template <class T1, class S1,
class T2, class S2>
inline void
estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix)
{
estimateSimilarityTransform(srcImageRange(src), destImageRange(dest),
affineMatrix, AffineMotionEstimationOptions
<>());
}
/********************************************************/ /********************************************************/
/* */ /* */
/* estimateAffineTransform */ /* estimateAffineTransform */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Estimate the optical flow between two images according to an aff ine transform model /** \brief Estimate the optical flow between two images according to an aff ine transform model
(e.g. translation, rotation, non-uniform scaling, and shearing). (e.g. translation, rotation, non-uniform scaling, and shearing).
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/affine_registration.hxx\><br> <b>\#include</b> \<vigra/affine_registration.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
int SPLINEORDER>
void
estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER>
const & options =
AffineMotionEstimationOp
tions<SPLINEORDER>());
}
\endcode
\deprecatedAPI{estimateAffineTransform}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER = 2> int SPLINEORDER = 2>
void void
estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccess or src, estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccess or src,
DestIterator dul, DestIterator dlr, DestAccesso r dest, DestIterator dul, DestIterator dlr, DestAccesso r dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons t & options = AffineMotionEstimationOptions<SPLINEORDER> cons t & options =
AffineMotionEstimat ionOptions<>()) AffineMotionEstimat ionOptions<>())
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER = 2> int SPLINEORDER = 2>
void void
estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccesso r> src, estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
triple<DestIterator, DestIterator, DestAccessor > dest, triple<DestIterator, DestIterator, DestAccessor > dest,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> cons t & options = AffineMotionEstimationOptions<SPLINEORDER> cons t & options =
AffineMotionEstimat ionOptions<>()) AffineMotionEstimat ionOptions<>())
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void estimateAffineTransform) doxygen_overloaded_function(template <...> void estimateAffineTransform)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
int SPLINEORDER> int SPLINEORDER>
inline void inline void
estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src, estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestIterator dlr, DestAccessor de st, DestIterator dul, DestIterator dlr, DestAccessor de st,
Matrix<double> & affineMatrix, Matrix<double> & affineMatrix,
skipping to change at line 675 skipping to change at line 773
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src, estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<DestIterator, DestIterator, DestAccessor> de st, triple<DestIterator, DestIterator, DestAccessor> de st,
Matrix<double> & affineMatrix) Matrix<double> & affineMatrix)
{ {
estimateAffineTransform(src.first, src.second, src.third, dest.first, d est.second, dest.third, estimateAffineTransform(src.first, src.second, src.third, dest.first, d est.second, dest.third,
affineMatrix, AffineMotionEstimationOptions<>() ); affineMatrix, AffineMotionEstimationOptions<>() );
} }
template <class T1, class S1,
class T2, class S2,
int SPLINEORDER>
inline void
estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix,
AffineMotionEstimationOptions<SPLINEORDER> const &
options)
{
vigra_precondition(src.shape() == dest.shape(),
"estimateAffineTransform(): shape mismatch between input and output
.");
estimateAffineTransform(srcImageRange(src), destImageRange(dest),
affineMatrix, options);
}
template <class T1, class S1,
class T2, class S2>
inline void
estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Matrix<double> & affineMatrix)
{
vigra_precondition(src.shape() == dest.shape(),
"estimateAffineTransform(): shape mismatch between input and output
.");
estimateAffineTransform(srcImageRange(src), destImageRange(dest),
affineMatrix, AffineMotionEstimationOptions<>()
);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_AFFINE_REGISTRATION_HXX */ #endif /* VIGRA_AFFINE_REGISTRATION_HXX */
 End of changes. 14 change blocks. 
11 lines changed or deleted 149 lines changed or added


 affinegeometry.hxx   affinegeometry.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_AFFINEGEOMETRY_HXX #ifndef VIGRA_AFFINEGEOMETRY_HXX
#define VIGRA_AFFINEGEOMETRY_HXX #define VIGRA_AFFINEGEOMETRY_HXX
#include "mathutil.hxx" #include "mathutil.hxx"
#include "matrix.hxx" #include "matrix.hxx"
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "splineimageview.hxx" #include "splineimageview.hxx"
#include "multi_shape.hxx"
#include <cmath> #include <cmath>
namespace vigra { namespace vigra {
/** \addtogroup GeometricTransformations Geometric Transformations /** \addtogroup GeometricTransformations Geometric Transformations
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
skipping to change at line 162 skipping to change at line 164
{ {
return rotationMatrix2DRadians(angle*M_PI/180.0, center); return rotationMatrix2DRadians(angle*M_PI/180.0, center);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* rotateImage */ /* rotateImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Rotate image by an arbitrary angle. // documentation is in basicgeometry.hxx
The algorithm performs a rotation about the given center point (the ima
ge center by default)
using the given SplineImageView for interpolation. The destination imag
e must have the same size
as the source SplineImageView. The rotation is counter-clockwise, and t
he angle must be given in degrees.
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
// rotate about given center point
template <int ORDER, class T,
class DestIterator, class DestAccessor>
void rotateImage(SplineImageView<ORDER, T> const & src,
DestIterator id, DestAccessor dest,
double angleInDegree, TinyVector<double, 2> const
& center);
// rotate about image center
template <int ORDER, class T,
class DestIterator, class DestAccessor>
void
rotateImage(SplineImageView<ORDER, T> const & src,
DestIterator id, DestAccessor dest,
double angleInDegree)
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
// rotate about given center point
template <int ORDER, class T,
class DestIterator, class DestAccessor>
void
rotateImage(SplineImageView<ORDER, T> const & src,
pair<DestImageIterator, DestAccessor> dest,
double angleInDegree, TinyVector<double, 2> const & cen
ter);
// rotate about image center
template <int ORDER, class T,
class DestIterator, class DestAccessor>
void
rotateImage(SplineImageView<ORDER, T> const & src,
pair<DestImageIterator, DestAccessor> dest,
double angleInDegree);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/affinegeometry.hxx\><br>
Namespace: vigra
\code
Image src(width, height);
vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src))
;
Image dest(width, height);
vigra::rotateImage(spline, destImage(dest), 38.5);
\endcode
<b> Required Interface:</b>
\code
DestImageIterator dest_upperleft;
double x = ..., y = ...;
if (spline.isInside(x,y))
dest_accessor.set(spline(x, y), dest_upperleft);
\endcode
*/
doxygen_overloaded_function(template <...> void rotateImage)
template <int ORDER, class T, template <int ORDER, class T,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void rotateImage(SplineImageView<ORDER, T> const & src, void rotateImage(SplineImageView<ORDER, T> const & src,
DestIterator id, DestAccessor dest, DestIterator id, DestAccessor dest,
double angleInDegree, TinyVector<double, 2> const & center ) double angleInDegree, TinyVector<double, 2> const & center )
{ {
int w = src.width(); int w = src.width();
int h = src.height(); int h = src.height();
double angle = angleInDegree*M_PI/180.0; double angle = angleInDegree/180.0;
double c = std::cos(angle); double c = cos_pi(angle); // avoid round-off errors for simple rotation
double s = std::sin(angle); s
double s = sin_pi(angle);
// avoid round-off errors for simple rotations
if(closeAtTolerance(std::fmod(angleInDegree, 45.0), 0.0))
{
// convert angle into a multiple of pi/4
int ai = roundi(angleInDegree / 45.0) % 8;
if(ai < 0)
ai += 8;
static double sqrt2_2 = 0.5*M_SQRT2;
static double ss[8] = {0.0, sqrt2_2, 1.0, sqrt2_2, 0.0, -sqrt2_2,
-1.0, -sqrt2_2};
static double cc[8] = {1.0, sqrt2_2, 0.0, -sqrt2_2, -1.0, -sqrt2_2,
0.0, sqrt2_2};
s = ss[ai];
c = cc[ai];
}
for(int y = 0; y < h; ++y, ++id.y) for(int y = 0; y < h; ++y, ++id.y)
{ {
typename DestIterator::row_iterator rd = id.rowIterator(); typename DestIterator::row_iterator rd = id.rowIterator();
double sy = (y - center[1])*c - center[0]*s + center[1]; double sy = (y - center[1])*c - center[0]*s + center[1];
double sx = -(y - center[1])*s - center[0]*c + center[0]; double sx = -(y - center[1])*s - center[0]*c + center[0];
for(int x=0; x < w; ++x, ++rd, sx += c, sy += s) for(int x=0; x < w; ++x, ++rd, sx += c, sy += s)
{ {
if(src.isInside(sx, sy)) if(src.isInside(sx, sy))
dest.set(src(sx, sy), rd); dest.set(src(sx, sy), rd);
skipping to change at line 315 skipping to change at line 223
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
rotateImage(SplineImageView<ORDER, T> const & src, rotateImage(SplineImageView<ORDER, T> const & src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double angleInDegree) double angleInDegree)
{ {
TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0 ) / 2.0); TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0 ) / 2.0);
rotateImage(src, dest.first, dest.second, angleInDegree, center); rotateImage(src, dest.first, dest.second, angleInDegree, center);
} }
template <int ORDER, class T,
class T2, class S2>
inline void
rotateImage(SplineImageView<ORDER, T> const & src,
MultiArrayView<2, T2, S2> dest,
double angleInDegree, TinyVector<double, 2> const & center)
{
rotateImage(src, destImage(dest), angleInDegree, center);
}
template <int ORDER, class T,
class T2, class S2>
inline void
rotateImage(SplineImageView<ORDER, T> const & src,
MultiArrayView<2, T2, S2> dest,
double angleInDegree)
{
TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0
) / 2.0);
rotateImage(src, destImage(dest), angleInDegree, center);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* affineWarpImage */ /* affineWarpImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Warp an image according to an affine transformation. /** \brief Warp an image according to an affine transformation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <int ORDER, class T,
class T2, class S2,
class C>
void
affineWarpImage(SplineImageView<ORDER, T> const & src,
MultiArrayView<2, T2, S2> dest,
MultiArrayView<2, double, C> const & affineMatrix);
}
\endcode
\deprecatedAPI{affineWarpImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <int ORDER, class T, template <int ORDER, class T,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class C> class C>
void affineWarpImage(SplineImageView<ORDER, T> const & src, void affineWarpImage(SplineImageView<ORDER, T> const & src,
DestIterator dul, DestIterator dlr, DestAccesso r dest, DestIterator dul, DestIterator dlr, DestAccesso r dest,
MultiArrayView<2, double, C> const & affineMatr ix); MultiArrayView<2, double, C> const & affineMatr ix);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <int ORDER, class T, template <int ORDER, class T,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class C> class C>
void affineWarpImage(SplineImageView<ORDER, T> const & src, void affineWarpImage(SplineImageView<ORDER, T> const & src,
triple<DestIterator, DestIterator, DestAccessor > dest, triple<DestIterator, DestIterator, DestAccessor > dest,
MultiArrayView<2, double, C> const & affineMatr ix); MultiArrayView<2, double, C> const & affineMatr ix);
} }
\endcode \endcode
\deprecatedEnd
The algorithm applies the given \a affineMatrix to the <i>destination c oordinates</i> and copies The algorithm applies the given \a affineMatrix to the <i>destination c oordinates</i> and copies
the image value from the resulting source coordinates, using the given SplineImageView \a src for interpolation. the image value from the resulting source coordinates, using the given SplineImageView \a src for interpolation.
If the resulting coordinate is outside the source image, nothing will b e written at that destination point. If the resulting coordinate is outside the source image, nothing will b e written at that destination point.
\code \code
for all dest pixels: for all dest pixels:
currentSrcCoordinate = affineMatrix * currentDestCoordinate; currentSrcCoordinate = affineMatrix * currentDestCoordinate;
if src.isInside(currentSrcCoordinate): if src.isInside(currentSrcCoordinate):
dest[currentDestCoordinate] = src[currentSrcCoordinate]; // copy an interpolated value dest[currentDestCoordinate] = src[currentSrcCoordinate]; // copy an interpolated value
\endcode \endcode
The matrix represent a 2-dimensional affine transform by means of homog eneous coordinates, The matrix represents a 2-dimensional affine transform by means of homo geneous coordinates,
i.e. it must be a 3x3 matrix whose last row is (0,0,1). i.e. it must be a 3x3 matrix whose last row is (0,0,1).
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/affinegeometry.hxx\><br> <b>\#include</b> \<vigra/affinegeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(width, height);
SplineImageView<3, float> spline(src);
MultiArray<2, float> dest1(src.shape());
// equivalent (up to round-off errors) to
// rotateImage(spline, dest1, 45.0);
TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0);
affineWarpImage(spline, dest1, rotationMatrix2DDegrees(45.0, center));
MultiArray<2, float> dest2(2*width-1, 2*height-1);
Image src(width, height); // equivalent (up to round-off errors) to
vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)) // resizeImageSplineInterpolation(img, dest2);
; // note that scaleFactor = 0.5, because we must pass the transformation
from destination to source
affineWarpImage(spline, dest2, scalingMatrix2D(0.5));
\endcode
\deprecatedUsage{affineWarpImage}
\code
FImage src(width, height);
SplineImageView<3, Image::value_type> spline(srcImageRange(src));
Image dest1(width, height); FImage dest1(width, height);
// equivalent (up to round-off errors) with // equivalent (up to round-off errors) with
// rotateImage(spline, destImage(dest1), 45.0); // rotateImage(spline, destImage(dest1), 45.0);
TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0); TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0);
affineWarpImage(spline, destImageRange(dest1), rotationMatrix2DDegrees( 45.0, center)); affineWarpImage(spline, destImageRange(dest1), rotationMatrix2DDegrees( 45.0, center));
Image dest2(2*width-1, 2*height-1); FImage dest2(2*width-1, 2*height-1);
// equivalent (up to round-off errors) with // equivalent (up to round-off errors) with
// resizeImageSplineInterpolation(srcImageRange(img), destImageRang e(dest2)); // resizeImageSplineInterpolation(srcImageRange(img), destImageRang e(dest2));
// note that scaleFactor = 0.5, because we must pass the transformation from destination to source // note that scaleFactor = 0.5, because we must pass the transformation from destination to source
affineWarpImage(spline, destImageRange(dest2), scalingMatrix2D(0.5)); affineWarpImage(spline, destImageRange(dest2), scalingMatrix2D(0.5));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
double x = ..., y = ...; double x = ..., y = ...;
if (spline.isInside(x,y)) if (spline.isInside(x,y))
dest_accessor.set(spline(x, y), dest_upperleft); dest_accessor.set(spline(x, y), dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b>See also:</b> Functions to specify affine transformation: \ref trans lationMatrix2D(), \ref scalingMatrix2D(), <b>See also:</b> Functions to specify affine transformation: \ref trans lationMatrix2D(), \ref scalingMatrix2D(),
\ref shearMatrix2D(), \ref rotationMatrix2DRadians(), \ ref rotationMatrix2DDegrees() \ref shearMatrix2D(), \ref rotationMatrix2DRadians(), \ ref rotationMatrix2DDegrees()
*/ */
doxygen_overloaded_function(template <...> void affineWarpImage) doxygen_overloaded_function(template <...> void affineWarpImage)
template <int ORDER, class T, template <int ORDER, class T,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class C> class C>
void affineWarpImage(SplineImageView<ORDER, T> const & src, void affineWarpImage(SplineImageView<ORDER, T> const & src,
skipping to change at line 436 skipping to change at line 395
double sy = x*affineMatrix(1,0) + y*affineMatrix(1,1) + affineM atrix(1,2); double sy = x*affineMatrix(1,0) + y*affineMatrix(1,1) + affineM atrix(1,2);
if(src.isInside(sx, sy)) if(src.isInside(sx, sy))
dest.set(src(sx, sy), rd); dest.set(src(sx, sy), rd);
} }
} }
} }
template <int ORDER, class T, template <int ORDER, class T,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class C> class C>
inline inline void
void affineWarpImage(SplineImageView<ORDER, T> const & src, affineWarpImage(SplineImageView<ORDER, T> const & src,
triple<DestIterator, DestIterator, DestAccessor> dest, triple<DestIterator, DestIterator, DestAccessor> dest,
MultiArrayView<2, double, C> const & affineMatrix) MultiArrayView<2, double, C> const & affineMatrix)
{ {
affineWarpImage(src, dest.first, dest.second, dest.third, affineMatrix) ; affineWarpImage(src, dest.first, dest.second, dest.third, affineMatrix) ;
} }
template <int ORDER, class T,
class T2, class S2,
class C>
inline void
affineWarpImage(SplineImageView<ORDER, T> const & src,
MultiArrayView<2, T2, S2> dest,
MultiArrayView<2, double, C> const & affineMatrix)
{
affineWarpImage(src, destImageRange(dest), affineMatrix);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_AFFINEGEOMETRY_HXX */ #endif /* VIGRA_AFFINEGEOMETRY_HXX */
 End of changes. 20 change blocks. 
124 lines changed or deleted 88 lines changed or added


 algorithm.hxx   algorithm.hxx 
skipping to change at line 51 skipping to change at line 51
#include "inspector_passes.hxx" #include "inspector_passes.hxx"
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <iterator> #include <iterator>
namespace vigra { namespace vigra {
/** \addtogroup MathFunctions /** \addtogroup MathFunctions
*/ */
//@{ //@{
/*! Find the minimum element in a sequence. /** \brief Find the minimum element in a sequence.
The function returns the iterator referring to the minimum element. The function returns the iterator referring to the minimum element.
This is identical to the function <tt>std::min_element()</tt>. This is identical to the function <tt>std::min_element()</tt>.
<b>Required Interface:</b> <b>Required Interface:</b>
\code \code
Iterator is a standard forward iterator. Iterator is a standard forward iterator.
bool f = *first < NumericTraits<typename std::iterator_traits<Itera tor>::value_type>::max(); bool f = *first < NumericTraits<typename std::iterator_traits<Itera tor>::value_type>::max();
skipping to change at line 79 skipping to change at line 79
{ {
if(first == last) if(first == last)
return last; return last;
Iterator best = first; Iterator best = first;
for(++first; first != last; ++first) for(++first; first != last; ++first)
if(*first < *best) if(*first < *best)
best = first; best = first;
return best; return best;
} }
/*! Find the maximum element in a sequence. /** \brief Find the maximum element in a sequence.
The function returns the iterator referring to the maximum element. The function returns the iterator referring to the maximum element.
This is identical to the function <tt>std::max_element()</tt>. This is identical to the function <tt>std::max_element()</tt>.
<b>Required Interface:</b> <b>Required Interface:</b>
\code \code
Iterator is a standard forward iterator. Iterator is a standard forward iterator.
bool f = NumericTraits<typename std::iterator_traits<Iterator>::val ue_type>::min() < *first; bool f = NumericTraits<typename std::iterator_traits<Iterator>::val ue_type>::min() < *first;
skipping to change at line 107 skipping to change at line 107
{ {
if(first == last) if(first == last)
return last; return last;
Iterator best = first; Iterator best = first;
for(++first; first != last; ++first) for(++first; first != last; ++first)
if(*best < *first) if(*best < *first)
best = first; best = first;
return best; return best;
} }
/*! Find the minimum element in a sequence conforming to a condition. /** \brief Find the minimum element in a sequence conforming to a condi tion.
The function returns the iterator referring to the minimum element, The function returns the iterator referring to the minimum element,
where only elements conforming to the condition (i.e. where where only elements conforming to the condition (i.e. where
<tt>condition(*iterator)</tt> evaluates to <tt>true</tt>) are consi dered. <tt>condition(*iterator)</tt> evaluates to <tt>true</tt>) are consi dered.
If no element conforms to the condition, or the sequence is empty, If no element conforms to the condition, or the sequence is empty,
the end iterator \a last is returned. the end iterator \a last is returned.
<b>Required Interface:</b> <b>Required Interface:</b>
\code \code
skipping to change at line 143 skipping to change at line 143
break; break;
if(first == last) if(first == last)
return last; return last;
Iterator best = first; Iterator best = first;
for(++first; first != last; ++first) for(++first; first != last; ++first)
if(condition(*first) && *first < *best) if(condition(*first) && *first < *best)
best = first; best = first;
return best; return best;
} }
/*! Find the maximum element in a sequence conforming to a condition. /** \brief Find the maximum element in a sequence conforming to a condi tion.
The function returns the iterator referring to the maximum element, The function returns the iterator referring to the maximum element,
where only elements conforming to the condition (i.e. where where only elements conforming to the condition (i.e. where
<tt>condition(*iterator)</tt> evaluates to <tt>true</tt>) are consi dered. <tt>condition(*iterator)</tt> evaluates to <tt>true</tt>) are consi dered.
If no element conforms to the condition, or the sequence is empty, If no element conforms to the condition, or the sequence is empty,
the end iterator \a last is returned. the end iterator \a last is returned.
<b>Required Interface:</b> <b>Required Interface:</b>
\code \code
skipping to change at line 179 skipping to change at line 179
break; break;
if(first == last) if(first == last)
return last; return last;
Iterator best = first; Iterator best = first;
for(++first; first != last; ++first) for(++first; first != last; ++first)
if(condition(*first) && *best < *first) if(condition(*first) && *best < *first)
best = first; best = first;
return best; return best;
} }
/*! Fill an array with a sequence of numbers. /** \brief Fill an array with a sequence of numbers.
The sequence starts at \a start and is incremented with \a step. De fault start The sequence starts at \a start and is incremented with \a step. De fault start
and stepsize are 0 and 1 respectively. and stepsize are 0 and 1 respectively. This is a generalization of
function
<tt>std::iota()</tt> in C++11.
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Value> template <class Iterator, class Value>
void linearSequence(Iterator first, Iterator last, void linearSequence(Iterator first, Iterator last,
Value const & start = 0, Value const & step = 1); Value const & start = 0, Value const & step = 1);
} }
\endcode \endcode
skipping to change at line 216 skipping to change at line 217
template <class Iterator, class Value> template <class Iterator, class Value>
void linearSequence(Iterator first, Iterator last, Value start, Value step) void linearSequence(Iterator first, Iterator last, Value start, Value step)
{ {
for(; first != last; ++first, start += step) for(; first != last; ++first, start += step)
*first = start; *first = start;
} }
template <class Iterator, class Value> template <class Iterator, class Value>
void linearSequence(Iterator first, Iterator last, Value start) void linearSequence(Iterator first, Iterator last, Value start)
{ {
for(; first != last; ++first, ++start) linearSequence(first, last, start, NumericTraits<Value>::one());
*first = start;
} }
template <class Iterator> template <class Iterator>
void linearSequence(Iterator first, Iterator last) void linearSequence(Iterator first, Iterator last)
{ {
typedef typename std::iterator_traits<Iterator>::value_type Value; typedef typename std::iterator_traits<Iterator>::value_type Value;
linearSequence(first, last, NumericTraits<Value>::zero()); linearSequence(first, last, NumericTraits<Value>::zero());
} }
skipping to change at line 294 skipping to change at line 294
template <class InputIterator, class Functor> template <class InputIterator, class Functor>
inline void inline void
inspectSequence(InputIterator first, InputIterator last, Functor & f) inspectSequence(InputIterator first, InputIterator last, Functor & f)
{ {
detail::inspectSequence_binder<InputIterator> g(first, last); detail::inspectSequence_binder<InputIterator> g(first, last);
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
namespace detail { namespace detail {
template <class Iterator, class Compare> template <class ArrayLike, class Compare>
struct IndexCompare struct IndexCompare
{ {
Iterator i_; ArrayLike i_;
Compare c_; Compare c_;
IndexCompare(Iterator i, Compare c) IndexCompare(ArrayLike i, Compare c)
: i_(i), : i_(i),
c_(c) c_(c)
{} {}
template <class Index> template <class Index>
bool operator()(Index const & l, Index const & r) const bool operator()(Index const & l, Index const & r) const
{ {
return c_(i_[l], i_[r]); return c_(i_[l], i_[r]);
} }
}; };
} // namespace detail } // namespace detail
/*! Return the index permutation that would sort the input array. /** \brief Create a compare functor for indirect sort.
Indirect sorting refers to the situation where you have an array ho
lding
data and another array holding indices referencing the first array,
and you want to sort the index array according to some property of
the data array without changing the data array itself. The factory
function <tt>makeIndexComparator()</tt> creates a sorting predicate
for this task, given a sorting predicate for the data array.
\see vigra::indexSort(), vigra::applyPermutation()
<b>Usage:</b>
<b>\#include</b> \<vigra/algorithm.hxx\><br>
Namespace: vigra
\code
const std:vector<double> data(...); // data is immutable
std::vector<int> index(data.size());
std::iota(index.begin(), index.end());
// sort the indices such that data[index[k]] is an ascending sequen
ce in k
std::sort(index.begin(), index.end(), makeIndexComparator(data));
\endcode
<b>Declarations:</b>
\code
namespace vigra {
// compare using std::less
template <class ArrayLike>
auto makeIndexComparator(ArrayLike a);
// compare using functor Compare
template <class ArrayLike, class Compare>
auto makeIndexComparator(ArrayLike a, Compare c);
}
\endcode
*/
template <class ArrayLike, class Compare>
inline detail::IndexCompare<ArrayLike, Compare>
makeIndexComparator(ArrayLike a, Compare c)
{
return detail::IndexCompare<ArrayLike, Compare>(a, c);
}
template <class ArrayLike>
inline detail::IndexCompare<ArrayLike, std::less<typename ArrayLike::value_
type> >
makeIndexComparator(ArrayLike a)
{
typedef std::less<typename ArrayLike::value_type> Compare;
return detail::IndexCompare<ArrayLike, Compare>(a, Compare());
}
/** \brief Return the index permutation that would sort the input array
.
To actually sort an array according to the ordering thus determined , use To actually sort an array according to the ordering thus determined , use
\ref applyPermutation(). \ref applyPermutation().
<b>Usage:</b>
<b>\#include</b> \<vigra/algorithm.hxx\><br>
Namespace: vigra
\code
const std:vector<double> data(...); // data is immutable
std::vector<int> index(data.size());
// arrange indices such that data[index[k]] is an ascending sequenc
e in k
indexSort(data.begin(), data.end(), index.begin());
\endcode
<b> Declarations:</b> <b> Declarations:</b>
\code \code
namespace vigra { namespace vigra {
// compare using std::less // compare using std::less
template <class Iterator, class IndexIterator> template <class Iterator, class IndexIterator>
void indexSort(Iterator first, Iterator last, IndexIterator ind ex_first); void indexSort(Iterator first, Iterator last, IndexIterator ind ex_first);
// compare using functor Compare // compare using functor Compare
template <class Iterator, class IndexIterator, class Compare> template <class Iterator, class IndexIterator, class Compare>
skipping to change at line 349 skipping to change at line 418
\endcode \endcode
<b>\#include</b> \<vigra/algorithm.hxx\><br> <b>\#include</b> \<vigra/algorithm.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class Iterator, class IndexIterator, class Compare> template <class Iterator, class IndexIterator, class Compare>
void indexSort(Iterator first, Iterator last, IndexIterator index_first, Co mpare c) void indexSort(Iterator first, Iterator last, IndexIterator index_first, Co mpare c)
{ {
int size = last - first; int size = last - first;
linearSequence(index_first, index_first+size); linearSequence(index_first, index_first+size);
std::sort(index_first, index_first+size, std::sort(index_first, index_first+size, makeIndexComparator(first, c))
detail::IndexCompare<Iterator, Compare>(first, c)); ;
} }
template <class Iterator, class IndexIterator> template <class Iterator, class IndexIterator>
void indexSort(Iterator first, Iterator last, IndexIterator index_first) void indexSort(Iterator first, Iterator last, IndexIterator index_first)
{ {
typedef typename std::iterator_traits<Iterator>::value_type Value; typedef typename std::iterator_traits<Iterator>::value_type Value;
indexSort(first, last, index_first, std::less<Value>()); indexSort(first, last, index_first, std::less<Value>());
} }
/*! Sort an array according to the given index permutation. /** \brief Sort an array according to the given index permutation.
The iterators \a in and \a out may not refer to the same array, as The iterators \a in and \a out may not refer to the same array, as
this would overwrite the input prematurely. this would overwrite the input prematurely.
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template <class IndexIterator, class InIterator, class OutItera tor> template <class IndexIterator, class InIterator, class OutItera tor>
void applyPermutation(IndexIterator index_first, IndexIterator index_last, void applyPermutation(IndexIterator index_first, IndexIterator index_last,
skipping to change at line 395 skipping to change at line 463
Namespace: vigra Namespace: vigra
*/ */
template <class IndexIterator, class InIterator, class OutIterator> template <class IndexIterator, class InIterator, class OutIterator>
void applyPermutation(IndexIterator index_first, IndexIterator index_last, void applyPermutation(IndexIterator index_first, IndexIterator index_last,
InIterator in, OutIterator out) InIterator in, OutIterator out)
{ {
for(; index_first != index_last; ++index_first, ++out) for(; index_first != index_last; ++index_first, ++out)
*out = in[*index_first]; *out = in[*index_first];
} }
/*! Compute the inverse of a given permutation. /** \brief Compute the inverse of a given permutation.
This is just another name for \ref indexSort(), referring to This is just another name for \ref indexSort(), referring to
another semantics. another semantics.
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template <class InIterator, class OutIterator> template <class InIterator, class OutIterator>
void inversePermutation(InIterator first, InIterator last, void inversePermutation(InIterator first, InIterator last,
skipping to change at line 436 skipping to change at line 504
} }
namespace detail { namespace detail {
static bool isLittleEndian() static bool isLittleEndian()
{ {
static const UIntBiggest testint = 0x01; static const UIntBiggest testint = 0x01;
return ((UInt8 *)&testint)[0] == 0x01; return ((UInt8 *)&testint)[0] == 0x01;
} }
template <class InIterator> template <class INT>
UInt32 checksumImpl(InIterator i, unsigned int size, UInt32 crc = 0xFFFFFFF struct ChecksumImpl
F)
{ {
static const UInt32 table[256] = { static UInt32 table0[256];
0x0U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x76dc419U, 0x706af48f static UInt32 table1[256];
U, static UInt32 table2[256];
0xe963a535U, 0x9e6495a3U, 0xedb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x9 static UInt32 table3[256];
7d2d988U,
0x9b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 0x90bf1d91U, 0x1db71064U, 0x6
ab020f2U,
0xf3b97148U, 0x84be41deU, 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x
83d385c7U,
0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x
63066cd9U,
0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 0x
a2677172U,
0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 0x35b5a8faU, 0x
42b2986cU,
0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0x
abd13d59U,
0x26d930acU, 0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x
56b3c423U,
0xcfba9599U, 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0x
b10be924U,
0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, 0x
1db7106U,
0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x6b6b51fU, 0x9fbfe4a5U, 0xe
8b8d433U,
0x7807c9a2U, 0xf00f934U, 0x9609a88eU, 0xe10e9818U, 0x7f6a0dbbU, 0x8
6d3d2dU,
0x91646c97U, 0xe6635c01U, 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0x
f262004eU,
0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x
12b7e950U,
0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0x
fbd44c65U,
0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 0x4adfa541U, 0x
3dd895d7U,
0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, 0x346ed9fcU, 0xad678846U, 0x
da60b8d0U,
0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x
270241aaU,
0xbe0b1010U, 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0x
ce61e49fU,
0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 0x
2eb40d81U,
0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 0x3b6e20cU, 0x7
4b1d29aU,
0xead54739U, 0x9dd277afU, 0x4db2615U, 0x73dc1683U, 0xe3630b12U, 0x9
4643b84U,
0xd6d6a3eU, 0x7a6a5aa8U, 0xe40ecf0bU, 0x9309ff9dU, 0xa00ae27U, 0x7d
079eb1U,
0xf00f9344U, 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x
806567cbU,
0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 0x
67dd4accU,
0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, 0xd6d6a3e8U, 0x
a1d1937eU,
0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 0xa6bc5767U, 0x3fb506ddU, 0x
48b2364bU,
0xd80d2bdaU, 0xaf0a1b4cU, 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0x
a867df55U,
0x316e8eefU, 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x
5268e236U,
0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, 0x
b2bd0b28U,
0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, 0x2cd99e8bU, 0x
5bdeae1dU,
0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 0x26d930aU, 0x9c0906a9U, 0xe
b0e363fU,
0x72076785U, 0x5005713U, 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0xc
b61b38U,
0x92d28e9bU, 0xe5d5be0dU, 0x7cdcefb7U, 0xbdbdf21U, 0x86d3d2d4U, 0xf
1d4e242U,
0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 0x
18b74777U,
0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 0x8f659effU, 0x
f862ae69U,
0x616bffd3U, 0x166ccf45U, 0xa00ae278U, 0xd70dd2eeU, 0x4e048354U, 0x
3903b3c2U,
0xa7672661U, 0xd06016f7U, 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0x
d9d65adcU,
0x40df0b66U, 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x
30b5ffe9U,
0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, 0x
cdd70693U,
0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, 0x5d681b02U, 0x
2a6f2b94U,
0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU };
static const UInt32 table1[256] = {
0x00000000U, 0x191b3141U, 0x32366282U, 0x2b2d53c3U, 0x646cc504U,
0x7d77f445U, 0x565aa786U, 0x4f4196c7U, 0xc8d98a08U, 0xd1c2bb49U,
0xfaefe88aU, 0xe3f4d9cbU, 0xacb54f0cU, 0xb5ae7e4dU, 0x9e832d8eU,
0x87981ccfU, 0x4ac21251U, 0x53d92310U, 0x78f470d3U, 0x61ef4192U,
0x2eaed755U, 0x37b5e614U, 0x1c98b5d7U, 0x05838496U, 0x821b9859U,
0x9b00a918U, 0xb02dfadbU, 0xa936cb9aU, 0xe6775d5dU, 0xff6c6c1cU,
0xd4413fdfU, 0xcd5a0e9eU, 0x958424a2U, 0x8c9f15e3U, 0xa7b24620U,
0xbea97761U, 0xf1e8e1a6U, 0xe8f3d0e7U, 0xc3de8324U, 0xdac5b265U,
0x5d5daeaaU, 0x44469febU, 0x6f6bcc28U, 0x7670fd69U, 0x39316baeU,
0x202a5aefU, 0x0b07092cU, 0x121c386dU, 0xdf4636f3U, 0xc65d07b2U,
0xed705471U, 0xf46b6530U, 0xbb2af3f7U, 0xa231c2b6U, 0x891c9175U,
0x9007a034U, 0x179fbcfbU, 0x0e848dbaU, 0x25a9de79U, 0x3cb2ef38U,
0x73f379ffU, 0x6ae848beU, 0x41c51b7dU, 0x58de2a3cU, 0xf0794f05U,
0xe9627e44U, 0xc24f2d87U, 0xdb541cc6U, 0x94158a01U, 0x8d0ebb40U,
0xa623e883U, 0xbf38d9c2U, 0x38a0c50dU, 0x21bbf44cU, 0x0a96a78fU,
0x138d96ceU, 0x5ccc0009U, 0x45d73148U, 0x6efa628bU, 0x77e153caU,
0xbabb5d54U, 0xa3a06c15U, 0x888d3fd6U, 0x91960e97U, 0xded79850U,
0xc7cca911U, 0xece1fad2U, 0xf5facb93U, 0x7262d75cU, 0x6b79e61dU,
0x4054b5deU, 0x594f849fU, 0x160e1258U, 0x0f152319U, 0x243870daU,
0x3d23419bU, 0x65fd6ba7U, 0x7ce65ae6U, 0x57cb0925U, 0x4ed03864U,
0x0191aea3U, 0x188a9fe2U, 0x33a7cc21U, 0x2abcfd60U, 0xad24e1afU,
0xb43fd0eeU, 0x9f12832dU, 0x8609b26cU, 0xc94824abU, 0xd05315eaU,
0xfb7e4629U, 0xe2657768U, 0x2f3f79f6U, 0x362448b7U, 0x1d091b74U,
0x04122a35U, 0x4b53bcf2U, 0x52488db3U, 0x7965de70U, 0x607eef31U,
0xe7e6f3feU, 0xfefdc2bfU, 0xd5d0917cU, 0xcccba03dU, 0x838a36faU,
0x9a9107bbU, 0xb1bc5478U, 0xa8a76539U, 0x3b83984bU, 0x2298a90aU,
0x09b5fac9U, 0x10aecb88U, 0x5fef5d4fU, 0x46f46c0eU, 0x6dd93fcdU,
0x74c20e8cU, 0xf35a1243U, 0xea412302U, 0xc16c70c1U, 0xd8774180U,
0x9736d747U, 0x8e2de606U, 0xa500b5c5U, 0xbc1b8484U, 0x71418a1aU,
0x685abb5bU, 0x4377e898U, 0x5a6cd9d9U, 0x152d4f1eU, 0x0c367e5fU,
0x271b2d9cU, 0x3e001cddU, 0xb9980012U, 0xa0833153U, 0x8bae6290U,
0x92b553d1U, 0xddf4c516U, 0xc4eff457U, 0xefc2a794U, 0xf6d996d5U,
0xae07bce9U, 0xb71c8da8U, 0x9c31de6bU, 0x852aef2aU, 0xca6b79edU,
0xd37048acU, 0xf85d1b6fU, 0xe1462a2eU, 0x66de36e1U, 0x7fc507a0U,
0x54e85463U, 0x4df36522U, 0x02b2f3e5U, 0x1ba9c2a4U, 0x30849167U,
0x299fa026U, 0xe4c5aeb8U, 0xfdde9ff9U, 0xd6f3cc3aU, 0xcfe8fd7bU,
0x80a96bbcU, 0x99b25afdU, 0xb29f093eU, 0xab84387fU, 0x2c1c24b0U,
0x350715f1U, 0x1e2a4632U, 0x07317773U, 0x4870e1b4U, 0x516bd0f5U,
0x7a468336U, 0x635db277U, 0xcbfad74eU, 0xd2e1e60fU, 0xf9ccb5ccU,
0xe0d7848dU, 0xaf96124aU, 0xb68d230bU, 0x9da070c8U, 0x84bb4189U,
0x03235d46U, 0x1a386c07U, 0x31153fc4U, 0x280e0e85U, 0x674f9842U,
0x7e54a903U, 0x5579fac0U, 0x4c62cb81U, 0x8138c51fU, 0x9823f45eU,
0xb30ea79dU, 0xaa1596dcU, 0xe554001bU, 0xfc4f315aU, 0xd7626299U,
0xce7953d8U, 0x49e14f17U, 0x50fa7e56U, 0x7bd72d95U, 0x62cc1cd4U,
0x2d8d8a13U, 0x3496bb52U, 0x1fbbe891U, 0x06a0d9d0U, 0x5e7ef3ecU,
0x4765c2adU, 0x6c48916eU, 0x7553a02fU, 0x3a1236e8U, 0x230907a9U,
0x0824546aU, 0x113f652bU, 0x96a779e4U, 0x8fbc48a5U, 0xa4911b66U,
0xbd8a2a27U, 0xf2cbbce0U, 0xebd08da1U, 0xc0fdde62U, 0xd9e6ef23U,
0x14bce1bdU, 0x0da7d0fcU, 0x268a833fU, 0x3f91b27eU, 0x70d024b9U,
0x69cb15f8U, 0x42e6463bU, 0x5bfd777aU, 0xdc656bb5U, 0xc57e5af4U,
0xee530937U, 0xf7483876U, 0xb809aeb1U, 0xa1129ff0U, 0x8a3fcc33U,
0x9324fd72U };
static const UInt32 table2[256] = {
0x00000000U, 0x01c26a37U, 0x0384d46eU, 0x0246be59U, 0x0709a8dcU,
0x06cbc2ebU, 0x048d7cb2U, 0x054f1685U, 0x0e1351b8U, 0x0fd13b8fU,
0x0d9785d6U, 0x0c55efe1U, 0x091af964U, 0x08d89353U, 0x0a9e2d0aU,
0x0b5c473dU, 0x1c26a370U, 0x1de4c947U, 0x1fa2771eU, 0x1e601d29U,
0x1b2f0bacU, 0x1aed619bU, 0x18abdfc2U, 0x1969b5f5U, 0x1235f2c8U,
0x13f798ffU, 0x11b126a6U, 0x10734c91U, 0x153c5a14U, 0x14fe3023U,
0x16b88e7aU, 0x177ae44dU, 0x384d46e0U, 0x398f2cd7U, 0x3bc9928eU,
0x3a0bf8b9U, 0x3f44ee3cU, 0x3e86840bU, 0x3cc03a52U, 0x3d025065U,
0x365e1758U, 0x379c7d6fU, 0x35dac336U, 0x3418a901U, 0x3157bf84U,
0x3095d5b3U, 0x32d36beaU, 0x331101ddU, 0x246be590U, 0x25a98fa7U,
0x27ef31feU, 0x262d5bc9U, 0x23624d4cU, 0x22a0277bU, 0x20e69922U,
0x2124f315U, 0x2a78b428U, 0x2bbade1fU, 0x29fc6046U, 0x283e0a71U,
0x2d711cf4U, 0x2cb376c3U, 0x2ef5c89aU, 0x2f37a2adU, 0x709a8dc0U,
0x7158e7f7U, 0x731e59aeU, 0x72dc3399U, 0x7793251cU, 0x76514f2bU,
0x7417f172U, 0x75d59b45U, 0x7e89dc78U, 0x7f4bb64fU, 0x7d0d0816U,
0x7ccf6221U, 0x798074a4U, 0x78421e93U, 0x7a04a0caU, 0x7bc6cafdU,
0x6cbc2eb0U, 0x6d7e4487U, 0x6f38fadeU, 0x6efa90e9U, 0x6bb5866cU,
0x6a77ec5bU, 0x68315202U, 0x69f33835U, 0x62af7f08U, 0x636d153fU,
0x612bab66U, 0x60e9c151U, 0x65a6d7d4U, 0x6464bde3U, 0x662203baU,
0x67e0698dU, 0x48d7cb20U, 0x4915a117U, 0x4b531f4eU, 0x4a917579U,
0x4fde63fcU, 0x4e1c09cbU, 0x4c5ab792U, 0x4d98dda5U, 0x46c49a98U,
0x4706f0afU, 0x45404ef6U, 0x448224c1U, 0x41cd3244U, 0x400f5873U,
0x4249e62aU, 0x438b8c1dU, 0x54f16850U, 0x55330267U, 0x5775bc3eU,
0x56b7d609U, 0x53f8c08cU, 0x523aaabbU, 0x507c14e2U, 0x51be7ed5U,
0x5ae239e8U, 0x5b2053dfU, 0x5966ed86U, 0x58a487b1U, 0x5deb9134U,
0x5c29fb03U, 0x5e6f455aU, 0x5fad2f6dU, 0xe1351b80U, 0xe0f771b7U,
0xe2b1cfeeU, 0xe373a5d9U, 0xe63cb35cU, 0xe7fed96bU, 0xe5b86732U,
0xe47a0d05U, 0xef264a38U, 0xeee4200fU, 0xeca29e56U, 0xed60f461U,
0xe82fe2e4U, 0xe9ed88d3U, 0xebab368aU, 0xea695cbdU, 0xfd13b8f0U,
0xfcd1d2c7U, 0xfe976c9eU, 0xff5506a9U, 0xfa1a102cU, 0xfbd87a1bU,
0xf99ec442U, 0xf85cae75U, 0xf300e948U, 0xf2c2837fU, 0xf0843d26U,
0xf1465711U, 0xf4094194U, 0xf5cb2ba3U, 0xf78d95faU, 0xf64fffcdU,
0xd9785d60U, 0xd8ba3757U, 0xdafc890eU, 0xdb3ee339U, 0xde71f5bcU,
0xdfb39f8bU, 0xddf521d2U, 0xdc374be5U, 0xd76b0cd8U, 0xd6a966efU,
0xd4efd8b6U, 0xd52db281U, 0xd062a404U, 0xd1a0ce33U, 0xd3e6706aU,
0xd2241a5dU, 0xc55efe10U, 0xc49c9427U, 0xc6da2a7eU, 0xc7184049U,
0xc25756ccU, 0xc3953cfbU, 0xc1d382a2U, 0xc011e895U, 0xcb4dafa8U,
0xca8fc59fU, 0xc8c97bc6U, 0xc90b11f1U, 0xcc440774U, 0xcd866d43U,
0xcfc0d31aU, 0xce02b92dU, 0x91af9640U, 0x906dfc77U, 0x922b422eU,
0x93e92819U, 0x96a63e9cU, 0x976454abU, 0x9522eaf2U, 0x94e080c5U,
0x9fbcc7f8U, 0x9e7eadcfU, 0x9c381396U, 0x9dfa79a1U, 0x98b56f24U,
0x99770513U, 0x9b31bb4aU, 0x9af3d17dU, 0x8d893530U, 0x8c4b5f07U,
0x8e0de15eU, 0x8fcf8b69U, 0x8a809decU, 0x8b42f7dbU, 0x89044982U,
0x88c623b5U, 0x839a6488U, 0x82580ebfU, 0x801eb0e6U, 0x81dcdad1U,
0x8493cc54U, 0x8551a663U, 0x8717183aU, 0x86d5720dU, 0xa9e2d0a0U,
0xa820ba97U, 0xaa6604ceU, 0xaba46ef9U, 0xaeeb787cU, 0xaf29124bU,
0xad6fac12U, 0xacadc625U, 0xa7f18118U, 0xa633eb2fU, 0xa4755576U,
0xa5b73f41U, 0xa0f829c4U, 0xa13a43f3U, 0xa37cfdaaU, 0xa2be979dU,
0xb5c473d0U, 0xb40619e7U, 0xb640a7beU, 0xb782cd89U, 0xb2cddb0cU,
0xb30fb13bU, 0xb1490f62U, 0xb08b6555U, 0xbbd72268U, 0xba15485fU,
0xb853f606U, 0xb9919c31U, 0xbcde8ab4U, 0xbd1ce083U, 0xbf5a5edaU,
0xbe9834edU };
static const UInt32 table3[256] = {
0x00000000U, 0xb8bc6765U, 0xaa09c88bU, 0x12b5afeeU, 0x8f629757U,
0x37def032U, 0x256b5fdcU, 0x9dd738b9U, 0xc5b428efU, 0x7d084f8aU,
0x6fbde064U, 0xd7018701U, 0x4ad6bfb8U, 0xf26ad8ddU, 0xe0df7733U,
0x58631056U, 0x5019579fU, 0xe8a530faU, 0xfa109f14U, 0x42acf871U,
0xdf7bc0c8U, 0x67c7a7adU, 0x75720843U, 0xcdce6f26U, 0x95ad7f70U,
0x2d111815U, 0x3fa4b7fbU, 0x8718d09eU, 0x1acfe827U, 0xa2738f42U,
0xb0c620acU, 0x087a47c9U, 0xa032af3eU, 0x188ec85bU, 0x0a3b67b5U,
0xb28700d0U, 0x2f503869U, 0x97ec5f0cU, 0x8559f0e2U, 0x3de59787U,
0x658687d1U, 0xdd3ae0b4U, 0xcf8f4f5aU, 0x7733283fU, 0xeae41086U,
0x525877e3U, 0x40edd80dU, 0xf851bf68U, 0xf02bf8a1U, 0x48979fc4U,
0x5a22302aU, 0xe29e574fU, 0x7f496ff6U, 0xc7f50893U, 0xd540a77dU,
0x6dfcc018U, 0x359fd04eU, 0x8d23b72bU, 0x9f9618c5U, 0x272a7fa0U,
0xbafd4719U, 0x0241207cU, 0x10f48f92U, 0xa848e8f7U, 0x9b14583dU,
0x23a83f58U, 0x311d90b6U, 0x89a1f7d3U, 0x1476cf6aU, 0xaccaa80fU,
0xbe7f07e1U, 0x06c36084U, 0x5ea070d2U, 0xe61c17b7U, 0xf4a9b859U,
0x4c15df3cU, 0xd1c2e785U, 0x697e80e0U, 0x7bcb2f0eU, 0xc377486bU,
0xcb0d0fa2U, 0x73b168c7U, 0x6104c729U, 0xd9b8a04cU, 0x446f98f5U,
0xfcd3ff90U, 0xee66507eU, 0x56da371bU, 0x0eb9274dU, 0xb6054028U,
0xa4b0efc6U, 0x1c0c88a3U, 0x81dbb01aU, 0x3967d77fU, 0x2bd27891U,
0x936e1ff4U, 0x3b26f703U, 0x839a9066U, 0x912f3f88U, 0x299358edU,
0xb4446054U, 0x0cf80731U, 0x1e4da8dfU, 0xa6f1cfbaU, 0xfe92dfecU,
0x462eb889U, 0x549b1767U, 0xec277002U, 0x71f048bbU, 0xc94c2fdeU,
0xdbf98030U, 0x6345e755U, 0x6b3fa09cU, 0xd383c7f9U, 0xc1366817U,
0x798a0f72U, 0xe45d37cbU, 0x5ce150aeU, 0x4e54ff40U, 0xf6e89825U,
0xae8b8873U, 0x1637ef16U, 0x048240f8U, 0xbc3e279dU, 0x21e91f24U,
0x99557841U, 0x8be0d7afU, 0x335cb0caU, 0xed59b63bU, 0x55e5d15eU,
0x47507eb0U, 0xffec19d5U, 0x623b216cU, 0xda874609U, 0xc832e9e7U,
0x708e8e82U, 0x28ed9ed4U, 0x9051f9b1U, 0x82e4565fU, 0x3a58313aU,
0xa78f0983U, 0x1f336ee6U, 0x0d86c108U, 0xb53aa66dU, 0xbd40e1a4U,
0x05fc86c1U, 0x1749292fU, 0xaff54e4aU, 0x322276f3U, 0x8a9e1196U,
0x982bbe78U, 0x2097d91dU, 0x78f4c94bU, 0xc048ae2eU, 0xd2fd01c0U,
0x6a4166a5U, 0xf7965e1cU, 0x4f2a3979U, 0x5d9f9697U, 0xe523f1f2U,
0x4d6b1905U, 0xf5d77e60U, 0xe762d18eU, 0x5fdeb6ebU, 0xc2098e52U,
0x7ab5e937U, 0x680046d9U, 0xd0bc21bcU, 0x88df31eaU, 0x3063568fU,
0x22d6f961U, 0x9a6a9e04U, 0x07bda6bdU, 0xbf01c1d8U, 0xadb46e36U,
0x15080953U, 0x1d724e9aU, 0xa5ce29ffU, 0xb77b8611U, 0x0fc7e174U,
0x9210d9cdU, 0x2aacbea8U, 0x38191146U, 0x80a57623U, 0xd8c66675U,
0x607a0110U, 0x72cfaefeU, 0xca73c99bU, 0x57a4f122U, 0xef189647U,
0xfdad39a9U, 0x45115eccU, 0x764dee06U, 0xcef18963U, 0xdc44268dU,
0x64f841e8U, 0xf92f7951U, 0x41931e34U, 0x5326b1daU, 0xeb9ad6bfU,
0xb3f9c6e9U, 0x0b45a18cU, 0x19f00e62U, 0xa14c6907U, 0x3c9b51beU,
0x842736dbU, 0x96929935U, 0x2e2efe50U, 0x2654b999U, 0x9ee8defcU,
0x8c5d7112U, 0x34e11677U, 0xa9362eceU, 0x118a49abU, 0x033fe645U,
0xbb838120U, 0xe3e09176U, 0x5b5cf613U, 0x49e959fdU, 0xf1553e98U,
0x6c820621U, 0xd43e6144U, 0xc68bceaaU, 0x7e37a9cfU, 0xd67f4138U,
0x6ec3265dU, 0x7c7689b3U, 0xc4caeed6U, 0x591dd66fU, 0xe1a1b10aU,
0xf3141ee4U, 0x4ba87981U, 0x13cb69d7U, 0xab770eb2U, 0xb9c2a15cU,
0x017ec639U, 0x9ca9fe80U, 0x241599e5U, 0x36a0360bU, 0x8e1c516eU,
0x866616a7U, 0x3eda71c2U, 0x2c6fde2cU, 0x94d3b949U, 0x090481f0U,
0xb1b8e695U, 0xa30d497bU, 0x1bb12e1eU, 0x43d23e48U, 0xfb6e592dU,
0xe9dbf6c3U, 0x516791a6U, 0xccb0a91fU, 0x740cce7aU, 0x66b96194U,
0xde0506f1U };
template <class InIterator>
static UInt32 exec(InIterator i, unsigned int size, UInt32 crc = 0xFFFF
FFFF);
};
template <class INT>
UInt32 ChecksumImpl<INT>::table0[256] = {
0x0U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x76dc419U, 0x706af48fU,
0xe963a535U, 0x9e6495a3U, 0xedb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d
988U,
0x9b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 0x90bf1d91U, 0x1db71064U, 0x6ab02
0f2U,
0xf3b97148U, 0x84be41deU, 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d3
85c7U,
0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x6306
6cd9U,
0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 0xa267
7172U,
0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 0x35b5a8faU, 0x42b2
986cU,
0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd1
3d59U,
0x26d930acU, 0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3
c423U,
0xcfba9599U, 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10b
e924U,
0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, 0x1db7
106U,
0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x6b6b51fU, 0x9fbfe4a5U, 0xe8b8d
433U,
0x7807c9a2U, 0xf00f934U, 0x9609a88eU, 0xe10e9818U, 0x7f6a0dbbU, 0x86d3d
2dU,
0x91646c97U, 0xe6635c01U, 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262
004eU,
0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7
e950U,
0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd4
4c65U,
0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 0x4adfa541U, 0x3dd8
95d7U,
0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, 0x346ed9fcU, 0xad678846U, 0xda60
b8d0U,
0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x2702
41aaU,
0xbe0b1010U, 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61
e49fU,
0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 0x2eb4
0d81U,
0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 0x3b6e20cU, 0x74b1d
29aU,
0xead54739U, 0x9dd277afU, 0x4db2615U, 0x73dc1683U, 0xe3630b12U, 0x94643
b84U,
0xd6d6a3eU, 0x7a6a5aa8U, 0xe40ecf0bU, 0x9309ff9dU, 0xa00ae27U, 0x7d079e
b1U,
0xf00f9344U, 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x8065
67cbU,
0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 0x67dd
4accU,
0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, 0xd6d6a3e8U, 0xa1d1
937eU,
0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 0xa6bc5767U, 0x3fb506ddU, 0x48b2
364bU,
0xd80d2bdaU, 0xaf0a1b4cU, 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867
df55U,
0x316e8eefU, 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268
e236U,
0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, 0xb2bd
0b28U,
0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, 0x2cd99e8bU, 0x5bde
ae1dU,
0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 0x26d930aU, 0x9c0906a9U, 0xeb0e3
63fU,
0x72076785U, 0x5005713U, 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0xcb61b
38U,
0x92d28e9bU, 0xe5d5be0dU, 0x7cdcefb7U, 0xbdbdf21U, 0x86d3d2d4U, 0xf1d4e
242U,
0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 0x18b7
4777U,
0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 0x8f659effU, 0xf862
ae69U,
0x616bffd3U, 0x166ccf45U, 0xa00ae278U, 0xd70dd2eeU, 0x4e048354U, 0x3903
b3c2U,
0xa7672661U, 0xd06016f7U, 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d6
5adcU,
0x40df0b66U, 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5
ffe9U,
0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, 0xcdd7
0693U,
0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, 0x5d681b02U, 0x2a6f
2b94U,
0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU };
template <class INT>
UInt32 ChecksumImpl<INT>::table1[256] = {
0x00000000U, 0x191b3141U, 0x32366282U, 0x2b2d53c3U, 0x646cc504U,
0x7d77f445U, 0x565aa786U, 0x4f4196c7U, 0xc8d98a08U, 0xd1c2bb49U,
0xfaefe88aU, 0xe3f4d9cbU, 0xacb54f0cU, 0xb5ae7e4dU, 0x9e832d8eU,
0x87981ccfU, 0x4ac21251U, 0x53d92310U, 0x78f470d3U, 0x61ef4192U,
0x2eaed755U, 0x37b5e614U, 0x1c98b5d7U, 0x05838496U, 0x821b9859U,
0x9b00a918U, 0xb02dfadbU, 0xa936cb9aU, 0xe6775d5dU, 0xff6c6c1cU,
0xd4413fdfU, 0xcd5a0e9eU, 0x958424a2U, 0x8c9f15e3U, 0xa7b24620U,
0xbea97761U, 0xf1e8e1a6U, 0xe8f3d0e7U, 0xc3de8324U, 0xdac5b265U,
0x5d5daeaaU, 0x44469febU, 0x6f6bcc28U, 0x7670fd69U, 0x39316baeU,
0x202a5aefU, 0x0b07092cU, 0x121c386dU, 0xdf4636f3U, 0xc65d07b2U,
0xed705471U, 0xf46b6530U, 0xbb2af3f7U, 0xa231c2b6U, 0x891c9175U,
0x9007a034U, 0x179fbcfbU, 0x0e848dbaU, 0x25a9de79U, 0x3cb2ef38U,
0x73f379ffU, 0x6ae848beU, 0x41c51b7dU, 0x58de2a3cU, 0xf0794f05U,
0xe9627e44U, 0xc24f2d87U, 0xdb541cc6U, 0x94158a01U, 0x8d0ebb40U,
0xa623e883U, 0xbf38d9c2U, 0x38a0c50dU, 0x21bbf44cU, 0x0a96a78fU,
0x138d96ceU, 0x5ccc0009U, 0x45d73148U, 0x6efa628bU, 0x77e153caU,
0xbabb5d54U, 0xa3a06c15U, 0x888d3fd6U, 0x91960e97U, 0xded79850U,
0xc7cca911U, 0xece1fad2U, 0xf5facb93U, 0x7262d75cU, 0x6b79e61dU,
0x4054b5deU, 0x594f849fU, 0x160e1258U, 0x0f152319U, 0x243870daU,
0x3d23419bU, 0x65fd6ba7U, 0x7ce65ae6U, 0x57cb0925U, 0x4ed03864U,
0x0191aea3U, 0x188a9fe2U, 0x33a7cc21U, 0x2abcfd60U, 0xad24e1afU,
0xb43fd0eeU, 0x9f12832dU, 0x8609b26cU, 0xc94824abU, 0xd05315eaU,
0xfb7e4629U, 0xe2657768U, 0x2f3f79f6U, 0x362448b7U, 0x1d091b74U,
0x04122a35U, 0x4b53bcf2U, 0x52488db3U, 0x7965de70U, 0x607eef31U,
0xe7e6f3feU, 0xfefdc2bfU, 0xd5d0917cU, 0xcccba03dU, 0x838a36faU,
0x9a9107bbU, 0xb1bc5478U, 0xa8a76539U, 0x3b83984bU, 0x2298a90aU,
0x09b5fac9U, 0x10aecb88U, 0x5fef5d4fU, 0x46f46c0eU, 0x6dd93fcdU,
0x74c20e8cU, 0xf35a1243U, 0xea412302U, 0xc16c70c1U, 0xd8774180U,
0x9736d747U, 0x8e2de606U, 0xa500b5c5U, 0xbc1b8484U, 0x71418a1aU,
0x685abb5bU, 0x4377e898U, 0x5a6cd9d9U, 0x152d4f1eU, 0x0c367e5fU,
0x271b2d9cU, 0x3e001cddU, 0xb9980012U, 0xa0833153U, 0x8bae6290U,
0x92b553d1U, 0xddf4c516U, 0xc4eff457U, 0xefc2a794U, 0xf6d996d5U,
0xae07bce9U, 0xb71c8da8U, 0x9c31de6bU, 0x852aef2aU, 0xca6b79edU,
0xd37048acU, 0xf85d1b6fU, 0xe1462a2eU, 0x66de36e1U, 0x7fc507a0U,
0x54e85463U, 0x4df36522U, 0x02b2f3e5U, 0x1ba9c2a4U, 0x30849167U,
0x299fa026U, 0xe4c5aeb8U, 0xfdde9ff9U, 0xd6f3cc3aU, 0xcfe8fd7bU,
0x80a96bbcU, 0x99b25afdU, 0xb29f093eU, 0xab84387fU, 0x2c1c24b0U,
0x350715f1U, 0x1e2a4632U, 0x07317773U, 0x4870e1b4U, 0x516bd0f5U,
0x7a468336U, 0x635db277U, 0xcbfad74eU, 0xd2e1e60fU, 0xf9ccb5ccU,
0xe0d7848dU, 0xaf96124aU, 0xb68d230bU, 0x9da070c8U, 0x84bb4189U,
0x03235d46U, 0x1a386c07U, 0x31153fc4U, 0x280e0e85U, 0x674f9842U,
0x7e54a903U, 0x5579fac0U, 0x4c62cb81U, 0x8138c51fU, 0x9823f45eU,
0xb30ea79dU, 0xaa1596dcU, 0xe554001bU, 0xfc4f315aU, 0xd7626299U,
0xce7953d8U, 0x49e14f17U, 0x50fa7e56U, 0x7bd72d95U, 0x62cc1cd4U,
0x2d8d8a13U, 0x3496bb52U, 0x1fbbe891U, 0x06a0d9d0U, 0x5e7ef3ecU,
0x4765c2adU, 0x6c48916eU, 0x7553a02fU, 0x3a1236e8U, 0x230907a9U,
0x0824546aU, 0x113f652bU, 0x96a779e4U, 0x8fbc48a5U, 0xa4911b66U,
0xbd8a2a27U, 0xf2cbbce0U, 0xebd08da1U, 0xc0fdde62U, 0xd9e6ef23U,
0x14bce1bdU, 0x0da7d0fcU, 0x268a833fU, 0x3f91b27eU, 0x70d024b9U,
0x69cb15f8U, 0x42e6463bU, 0x5bfd777aU, 0xdc656bb5U, 0xc57e5af4U,
0xee530937U, 0xf7483876U, 0xb809aeb1U, 0xa1129ff0U, 0x8a3fcc33U,
0x9324fd72U };
template <class INT>
UInt32 ChecksumImpl<INT>::table2[256] = {
0x00000000U, 0x01c26a37U, 0x0384d46eU, 0x0246be59U, 0x0709a8dcU,
0x06cbc2ebU, 0x048d7cb2U, 0x054f1685U, 0x0e1351b8U, 0x0fd13b8fU,
0x0d9785d6U, 0x0c55efe1U, 0x091af964U, 0x08d89353U, 0x0a9e2d0aU,
0x0b5c473dU, 0x1c26a370U, 0x1de4c947U, 0x1fa2771eU, 0x1e601d29U,
0x1b2f0bacU, 0x1aed619bU, 0x18abdfc2U, 0x1969b5f5U, 0x1235f2c8U,
0x13f798ffU, 0x11b126a6U, 0x10734c91U, 0x153c5a14U, 0x14fe3023U,
0x16b88e7aU, 0x177ae44dU, 0x384d46e0U, 0x398f2cd7U, 0x3bc9928eU,
0x3a0bf8b9U, 0x3f44ee3cU, 0x3e86840bU, 0x3cc03a52U, 0x3d025065U,
0x365e1758U, 0x379c7d6fU, 0x35dac336U, 0x3418a901U, 0x3157bf84U,
0x3095d5b3U, 0x32d36beaU, 0x331101ddU, 0x246be590U, 0x25a98fa7U,
0x27ef31feU, 0x262d5bc9U, 0x23624d4cU, 0x22a0277bU, 0x20e69922U,
0x2124f315U, 0x2a78b428U, 0x2bbade1fU, 0x29fc6046U, 0x283e0a71U,
0x2d711cf4U, 0x2cb376c3U, 0x2ef5c89aU, 0x2f37a2adU, 0x709a8dc0U,
0x7158e7f7U, 0x731e59aeU, 0x72dc3399U, 0x7793251cU, 0x76514f2bU,
0x7417f172U, 0x75d59b45U, 0x7e89dc78U, 0x7f4bb64fU, 0x7d0d0816U,
0x7ccf6221U, 0x798074a4U, 0x78421e93U, 0x7a04a0caU, 0x7bc6cafdU,
0x6cbc2eb0U, 0x6d7e4487U, 0x6f38fadeU, 0x6efa90e9U, 0x6bb5866cU,
0x6a77ec5bU, 0x68315202U, 0x69f33835U, 0x62af7f08U, 0x636d153fU,
0x612bab66U, 0x60e9c151U, 0x65a6d7d4U, 0x6464bde3U, 0x662203baU,
0x67e0698dU, 0x48d7cb20U, 0x4915a117U, 0x4b531f4eU, 0x4a917579U,
0x4fde63fcU, 0x4e1c09cbU, 0x4c5ab792U, 0x4d98dda5U, 0x46c49a98U,
0x4706f0afU, 0x45404ef6U, 0x448224c1U, 0x41cd3244U, 0x400f5873U,
0x4249e62aU, 0x438b8c1dU, 0x54f16850U, 0x55330267U, 0x5775bc3eU,
0x56b7d609U, 0x53f8c08cU, 0x523aaabbU, 0x507c14e2U, 0x51be7ed5U,
0x5ae239e8U, 0x5b2053dfU, 0x5966ed86U, 0x58a487b1U, 0x5deb9134U,
0x5c29fb03U, 0x5e6f455aU, 0x5fad2f6dU, 0xe1351b80U, 0xe0f771b7U,
0xe2b1cfeeU, 0xe373a5d9U, 0xe63cb35cU, 0xe7fed96bU, 0xe5b86732U,
0xe47a0d05U, 0xef264a38U, 0xeee4200fU, 0xeca29e56U, 0xed60f461U,
0xe82fe2e4U, 0xe9ed88d3U, 0xebab368aU, 0xea695cbdU, 0xfd13b8f0U,
0xfcd1d2c7U, 0xfe976c9eU, 0xff5506a9U, 0xfa1a102cU, 0xfbd87a1bU,
0xf99ec442U, 0xf85cae75U, 0xf300e948U, 0xf2c2837fU, 0xf0843d26U,
0xf1465711U, 0xf4094194U, 0xf5cb2ba3U, 0xf78d95faU, 0xf64fffcdU,
0xd9785d60U, 0xd8ba3757U, 0xdafc890eU, 0xdb3ee339U, 0xde71f5bcU,
0xdfb39f8bU, 0xddf521d2U, 0xdc374be5U, 0xd76b0cd8U, 0xd6a966efU,
0xd4efd8b6U, 0xd52db281U, 0xd062a404U, 0xd1a0ce33U, 0xd3e6706aU,
0xd2241a5dU, 0xc55efe10U, 0xc49c9427U, 0xc6da2a7eU, 0xc7184049U,
0xc25756ccU, 0xc3953cfbU, 0xc1d382a2U, 0xc011e895U, 0xcb4dafa8U,
0xca8fc59fU, 0xc8c97bc6U, 0xc90b11f1U, 0xcc440774U, 0xcd866d43U,
0xcfc0d31aU, 0xce02b92dU, 0x91af9640U, 0x906dfc77U, 0x922b422eU,
0x93e92819U, 0x96a63e9cU, 0x976454abU, 0x9522eaf2U, 0x94e080c5U,
0x9fbcc7f8U, 0x9e7eadcfU, 0x9c381396U, 0x9dfa79a1U, 0x98b56f24U,
0x99770513U, 0x9b31bb4aU, 0x9af3d17dU, 0x8d893530U, 0x8c4b5f07U,
0x8e0de15eU, 0x8fcf8b69U, 0x8a809decU, 0x8b42f7dbU, 0x89044982U,
0x88c623b5U, 0x839a6488U, 0x82580ebfU, 0x801eb0e6U, 0x81dcdad1U,
0x8493cc54U, 0x8551a663U, 0x8717183aU, 0x86d5720dU, 0xa9e2d0a0U,
0xa820ba97U, 0xaa6604ceU, 0xaba46ef9U, 0xaeeb787cU, 0xaf29124bU,
0xad6fac12U, 0xacadc625U, 0xa7f18118U, 0xa633eb2fU, 0xa4755576U,
0xa5b73f41U, 0xa0f829c4U, 0xa13a43f3U, 0xa37cfdaaU, 0xa2be979dU,
0xb5c473d0U, 0xb40619e7U, 0xb640a7beU, 0xb782cd89U, 0xb2cddb0cU,
0xb30fb13bU, 0xb1490f62U, 0xb08b6555U, 0xbbd72268U, 0xba15485fU,
0xb853f606U, 0xb9919c31U, 0xbcde8ab4U, 0xbd1ce083U, 0xbf5a5edaU,
0xbe9834edU };
template <class INT>
UInt32 ChecksumImpl<INT>::table3[256] = {
0x00000000U, 0xb8bc6765U, 0xaa09c88bU, 0x12b5afeeU, 0x8f629757U,
0x37def032U, 0x256b5fdcU, 0x9dd738b9U, 0xc5b428efU, 0x7d084f8aU,
0x6fbde064U, 0xd7018701U, 0x4ad6bfb8U, 0xf26ad8ddU, 0xe0df7733U,
0x58631056U, 0x5019579fU, 0xe8a530faU, 0xfa109f14U, 0x42acf871U,
0xdf7bc0c8U, 0x67c7a7adU, 0x75720843U, 0xcdce6f26U, 0x95ad7f70U,
0x2d111815U, 0x3fa4b7fbU, 0x8718d09eU, 0x1acfe827U, 0xa2738f42U,
0xb0c620acU, 0x087a47c9U, 0xa032af3eU, 0x188ec85bU, 0x0a3b67b5U,
0xb28700d0U, 0x2f503869U, 0x97ec5f0cU, 0x8559f0e2U, 0x3de59787U,
0x658687d1U, 0xdd3ae0b4U, 0xcf8f4f5aU, 0x7733283fU, 0xeae41086U,
0x525877e3U, 0x40edd80dU, 0xf851bf68U, 0xf02bf8a1U, 0x48979fc4U,
0x5a22302aU, 0xe29e574fU, 0x7f496ff6U, 0xc7f50893U, 0xd540a77dU,
0x6dfcc018U, 0x359fd04eU, 0x8d23b72bU, 0x9f9618c5U, 0x272a7fa0U,
0xbafd4719U, 0x0241207cU, 0x10f48f92U, 0xa848e8f7U, 0x9b14583dU,
0x23a83f58U, 0x311d90b6U, 0x89a1f7d3U, 0x1476cf6aU, 0xaccaa80fU,
0xbe7f07e1U, 0x06c36084U, 0x5ea070d2U, 0xe61c17b7U, 0xf4a9b859U,
0x4c15df3cU, 0xd1c2e785U, 0x697e80e0U, 0x7bcb2f0eU, 0xc377486bU,
0xcb0d0fa2U, 0x73b168c7U, 0x6104c729U, 0xd9b8a04cU, 0x446f98f5U,
0xfcd3ff90U, 0xee66507eU, 0x56da371bU, 0x0eb9274dU, 0xb6054028U,
0xa4b0efc6U, 0x1c0c88a3U, 0x81dbb01aU, 0x3967d77fU, 0x2bd27891U,
0x936e1ff4U, 0x3b26f703U, 0x839a9066U, 0x912f3f88U, 0x299358edU,
0xb4446054U, 0x0cf80731U, 0x1e4da8dfU, 0xa6f1cfbaU, 0xfe92dfecU,
0x462eb889U, 0x549b1767U, 0xec277002U, 0x71f048bbU, 0xc94c2fdeU,
0xdbf98030U, 0x6345e755U, 0x6b3fa09cU, 0xd383c7f9U, 0xc1366817U,
0x798a0f72U, 0xe45d37cbU, 0x5ce150aeU, 0x4e54ff40U, 0xf6e89825U,
0xae8b8873U, 0x1637ef16U, 0x048240f8U, 0xbc3e279dU, 0x21e91f24U,
0x99557841U, 0x8be0d7afU, 0x335cb0caU, 0xed59b63bU, 0x55e5d15eU,
0x47507eb0U, 0xffec19d5U, 0x623b216cU, 0xda874609U, 0xc832e9e7U,
0x708e8e82U, 0x28ed9ed4U, 0x9051f9b1U, 0x82e4565fU, 0x3a58313aU,
0xa78f0983U, 0x1f336ee6U, 0x0d86c108U, 0xb53aa66dU, 0xbd40e1a4U,
0x05fc86c1U, 0x1749292fU, 0xaff54e4aU, 0x322276f3U, 0x8a9e1196U,
0x982bbe78U, 0x2097d91dU, 0x78f4c94bU, 0xc048ae2eU, 0xd2fd01c0U,
0x6a4166a5U, 0xf7965e1cU, 0x4f2a3979U, 0x5d9f9697U, 0xe523f1f2U,
0x4d6b1905U, 0xf5d77e60U, 0xe762d18eU, 0x5fdeb6ebU, 0xc2098e52U,
0x7ab5e937U, 0x680046d9U, 0xd0bc21bcU, 0x88df31eaU, 0x3063568fU,
0x22d6f961U, 0x9a6a9e04U, 0x07bda6bdU, 0xbf01c1d8U, 0xadb46e36U,
0x15080953U, 0x1d724e9aU, 0xa5ce29ffU, 0xb77b8611U, 0x0fc7e174U,
0x9210d9cdU, 0x2aacbea8U, 0x38191146U, 0x80a57623U, 0xd8c66675U,
0x607a0110U, 0x72cfaefeU, 0xca73c99bU, 0x57a4f122U, 0xef189647U,
0xfdad39a9U, 0x45115eccU, 0x764dee06U, 0xcef18963U, 0xdc44268dU,
0x64f841e8U, 0xf92f7951U, 0x41931e34U, 0x5326b1daU, 0xeb9ad6bfU,
0xb3f9c6e9U, 0x0b45a18cU, 0x19f00e62U, 0xa14c6907U, 0x3c9b51beU,
0x842736dbU, 0x96929935U, 0x2e2efe50U, 0x2654b999U, 0x9ee8defcU,
0x8c5d7112U, 0x34e11677U, 0xa9362eceU, 0x118a49abU, 0x033fe645U,
0xbb838120U, 0xe3e09176U, 0x5b5cf613U, 0x49e959fdU, 0xf1553e98U,
0x6c820621U, 0xd43e6144U, 0xc68bceaaU, 0x7e37a9cfU, 0xd67f4138U,
0x6ec3265dU, 0x7c7689b3U, 0xc4caeed6U, 0x591dd66fU, 0xe1a1b10aU,
0xf3141ee4U, 0x4ba87981U, 0x13cb69d7U, 0xab770eb2U, 0xb9c2a15cU,
0x017ec639U, 0x9ca9fe80U, 0x241599e5U, 0x36a0360bU, 0x8e1c516eU,
0x866616a7U, 0x3eda71c2U, 0x2c6fde2cU, 0x94d3b949U, 0x090481f0U,
0xb1b8e695U, 0xa30d497bU, 0x1bb12e1eU, 0x43d23e48U, 0xfb6e592dU,
0xe9dbf6c3U, 0x516791a6U, 0xccb0a91fU, 0x740cce7aU, 0x66b96194U,
0xde0506f1U };
template <class INT>
template <class InIterator>
UInt32 ChecksumImpl<INT>::exec(InIterator i, unsigned int size, UInt32 crc)
{
InIterator end = i + size; InIterator end = i + size;
if(isLittleEndian() && size > 3) if(isLittleEndian() && size > 3)
{ {
// take care of alignment // take care of alignment
for(; (std::size_t)i % 4 != 0; ++i) for(; (std::size_t)i % 4 != 0; ++i)
{ {
crc = (crc >> 8) ^ table[(crc ^ *i) & 0xFF]; crc = (crc >> 8) ^ table0[(crc ^ *i) & 0xFF];
} }
for(; i < end-3; i+=4) for(; i < end-3; i+=4)
{ {
crc ^= *((UInt32 *)i); crc ^= *((UInt32 *)i);
crc = table3[crc & 0xFF] ^ crc = table3[crc & 0xFF] ^
table2[(crc >> 8) & 0xFF] ^ table2[(crc >> 8) & 0xFF] ^
table1[(crc >> 16) & 0xFF] ^ table1[(crc >> 16) & 0xFF] ^
table[crc >> 24]; table0[crc >> 24];
} }
} }
for(; i < end; ++i) for(; i < end; ++i)
{ {
crc = (crc >> 8) ^ table[(crc ^ *i) & 0xFF]; crc = (crc >> 8) ^ table0[(crc ^ *i) & 0xFF];
} }
return ~crc; return ~crc;
} }
} // namespace detail } // namespace detail
/*! Compute the CRC-32 checksum of a byte array. /** \brief Compute the CRC-32 checksum of a byte array.
Implementation note: This function is slower on big-endian machines Implementation note: This function is slower on big-endian machines
because the "4 bytes at a time" optimization is only implemented fo r because the "4 bytes at a time" optimization is only implemented fo r
little-endian. little-endian.
*/ */
inline UInt32 checksum(const char * data, unsigned int size) inline UInt32 checksum(const char * data, unsigned int size)
{ {
return detail::checksumImpl(data, size); return detail::ChecksumImpl<UInt32>::exec(data, size);
} }
/*! Concatenate a byte array to an existing CRC-32 checksum. /** Concatenate a byte array to an existing CRC-32 checksum.
*/ */
inline UInt32 concatenateChecksum(UInt32 checksum, const char * data, unsig ned int size) inline UInt32 concatenateChecksum(UInt32 checksum, const char * data, unsig ned int size)
{ {
return detail::checksumImpl(data, size, ~checksum); return detail::ChecksumImpl<UInt32>::exec(data, size, ~checksum);
} }
template <class T> template <class T>
void updateMin(T & x, const T & y) void updateMin(T & x, const T & y)
{ {
using std::min; using std::min;
x = min(x, y); x = min(x, y);
} }
template <class T> template <class T>
 End of changes. 25 change blocks. 
274 lines changed or deleted 365 lines changed or added


 array_vector.hxx   array_vector.hxx 
skipping to change at line 49 skipping to change at line 49
#include "error.hxx" #include "error.hxx"
#include "memory.hxx" #include "memory.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include <iosfwd> #include <iosfwd>
#ifdef VIGRA_CHECK_BOUNDS #ifdef VIGRA_CHECK_BOUNDS
#define VIGRA_ASSERT_INSIDE(diff) \ #define VIGRA_ASSERT_INSIDE(diff) \
vigra_precondition(diff >= 0, "Index out of bounds");\ vigra_precondition(diff >= 0, "Index out of bounds");\
vigra_precondition((unsigned int)diff < size_, "Index out of bounds"); vigra_precondition(diff < (difference_type)size_, "Index out of bounds");
#else #else
#define VIGRA_ASSERT_INSIDE(diff) #define VIGRA_ASSERT_INSIDE(diff)
#endif #endif
namespace vigra namespace vigra
{ {
template <class T, class Alloc = std::allocator<T> > template <class T, class Alloc = std::allocator<T> >
class ArrayVector; class ArrayVector;
/** Provide STL conforming interface for C-arrays. /** Provide STL conforming interface for C-arrays.
This template implements much of the functionality of <tt><a href="http ://www.sgi.com/tech/stl/Vector.html">std::vector</a></tt> This template implements much of the functionality of <a href="http://w ww.sgi.com/tech/stl/Vector.html">std::vector</a>
on top of a C-array. <tt>ArrayVectorView</tt> does not manage the memor y on top of a C-array. <tt>ArrayVectorView</tt> does not manage the memor y
it refers to (i.e. it does not allocate or deallocate any memory). it refers to (i.e. it does not allocate or deallocate any memory).
Thus, if the underlying memory changes, all dependent <tt>ArrayVectorVi ew</tt> Thus, if the underlying memory changes, all dependent <tt>ArrayVectorVi ew</tt>
objects are invalidated. This is especially important when <tt>ArrayVec torView</tt> objects are invalidated. This is especially important when <tt>ArrayVec torView</tt>
is used as a base class for <tt>ArrayVector</tt>, where several functio ns is used as a base class for <tt>ArrayVector</tt>, where several functio ns
(e.g. resize(), insert()) can allocate new memory and thus invalidate t he (e.g. resize(), insert()) can allocate new memory and thus invalidate t he
dependent views. The rules what operations invalidate view objects are the dependent views. The rules what operations invalidate view objects are the
same as the rules concerning standard iterators. same as the rules concerning standard iterators.
<b>\#include</b> \<vigra/array_vector.hxx\><br> <b>\#include</b> \<vigra/array_vector.hxx\><br>
skipping to change at line 249 skipping to change at line 249
return data() + size(); return data() + size();
} }
/** Get iterator pointing beyond the last array element. /** Get iterator pointing beyond the last array element.
*/ */
inline iterator end() inline iterator end()
{ {
return data() + size(); return data() + size();
} }
/** Get const iterator referring to the first array element.
*/
inline const_iterator cbegin() const
{
return data();
}
/** Get const iterator pointing beyond the last array element.
*/
inline const_iterator cend() const
{
return data() + size();
}
/** Get reverse iterator referring to the last array element. /** Get reverse iterator referring to the last array element.
*/ */
inline reverse_iterator rbegin() inline reverse_iterator rbegin()
{ {
return (reverse_iterator(end())); return (reverse_iterator(end()));
} }
/** Get const reverse iterator referring to the last array element. /** Get const reverse iterator referring to the last array element.
*/ */
inline const_reverse_iterator rbegin() const inline const_reverse_iterator rbegin() const
skipping to change at line 277 skipping to change at line 291
return (reverse_iterator(begin())); return (reverse_iterator(begin()));
} }
/** Get const reverse iterator pointing before the first array elem ent. /** Get const reverse iterator pointing before the first array elem ent.
*/ */
inline const_reverse_iterator rend() const inline const_reverse_iterator rend() const
{ {
return (const_reverse_iterator(begin())); return (const_reverse_iterator(begin()));
} }
/** Get const reverse iterator referring to the last array element.
*/
inline const_reverse_iterator crbegin() const
{
return (const_reverse_iterator(end()));
}
/** Get const reverse iterator pointing before the first array elem
ent.
*/
inline const_reverse_iterator crend() const
{
return (const_reverse_iterator(begin()));
}
/** Access first array element. /** Access first array element.
*/ */
reference front() reference front()
{ {
return *data_; return *data_;
} }
/** Read first array element. /** Read first array element.
*/ */
const_reference front() const const_reference front() const
skipping to change at line 390 skipping to change at line 418
copyImpl(rhs); copyImpl(rhs);
return *this; return *this;
} }
template <class T> template <class T>
template <class U> template <class U>
bool ArrayVectorView<T>::operator==(ArrayVectorView<U> const & rhs) const bool ArrayVectorView<T>::operator==(ArrayVectorView<U> const & rhs) const
{ {
if(size() != rhs.size()) if(size() != rhs.size())
return false; return false;
for(unsigned int k=0; k<size(); ++k) for(size_type k=0; k<size(); ++k)
if(data_[k] != rhs[k]) if(data_[k] != rhs[k])
return false; return false;
return true; return true;
} }
template <class T> template <class T>
void void
ArrayVectorView <T>::copyImpl(const ArrayVectorView & rhs) ArrayVectorView <T>::copyImpl(const ArrayVectorView & rhs)
{ {
vigra_precondition (size() == rhs.size(), vigra_precondition (size() == rhs.size(),
"ArrayVectorView::copy(): shape mismatch."); "ArrayVectorView::copy(): shape mismatch.");
if(size() == 0) // needed because MSVC debug assertions in std::copy()
may fire
return; // "invalid address: data_ == NULL" even when nothing
is to be copied
// use copy() or copy_backward() according to possible overlap of this and rhs // use copy() or copy_backward() according to possible overlap of this and rhs
if(data_ <= rhs.data()) if(data_ <= rhs.data())
{ {
std::copy(rhs.begin(), rhs.end(), begin()); std::copy(rhs.begin(), rhs.end(), begin());
} }
else else
{ {
std::copy_backward(rhs.begin(), rhs.end(), end()); std::copy_backward(rhs.begin(), rhs.end(), end());
} }
} }
skipping to change at line 434 skipping to change at line 464
template <class U> template <class U>
void void
ArrayVectorView <T>::swapDataImpl(const ArrayVectorView <U>& rhs) ArrayVectorView <T>::swapDataImpl(const ArrayVectorView <U>& rhs)
{ {
vigra_precondition (size () == rhs.size() (), vigra_precondition (size () == rhs.size() (),
"ArrayVectorView::swapData(): size mismatch."); "ArrayVectorView::swapData(): size mismatch.");
// check for overlap // check for overlap
if(data_ + size_ <= rhs.data_ || rhs.data_ + size_ <= data_) if(data_ + size_ <= rhs.data_ || rhs.data_ + size_ <= data_)
{ {
for(unsigned int k=0; k<size_; ++k) for(size_type k=0; k<size_; ++k)
std::swap(data_[k], rhs.data_[k]); std::swap(data_[k], rhs.data_[k]);
} }
else else
{ {
ArrayVector<T> t(*this); ArrayVector<T> t(*this);
copyImpl(rhs); copyImpl(rhs);
rhs.copyImpl(*this); rhs.copyImpl(*this);
} }
} }
skipping to change at line 600 skipping to change at line 630
template <class InputIterator> template <class InputIterator>
iterator insert(iterator p, InputIterator i, InputIterator iend); iterator insert(iterator p, InputIterator i, InputIterator iend);
iterator erase(iterator p); iterator erase(iterator p);
iterator erase(iterator p, iterator q); iterator erase(iterator p, iterator q);
void clear(); void clear();
void reserve( size_type new_capacity ); pointer reserveImpl( bool dealloc, size_type new_capacity );
void reserve(); pointer reserveImpl( bool dealloc);
void reserve()
{
reserveImpl(true);
}
void reserve( size_type new_capacity )
{
reserveImpl(true, new_capacity);
}
void resize( size_type new_size, value_type const & initial ); void resize( size_type new_size, value_type const & initial );
void resize( size_type new_size ) void resize( size_type new_size )
{ {
resize(new_size, value_type()); resize(new_size, value_type());
} }
size_type capacity() const size_type capacity() const
{ {
skipping to change at line 663 skipping to change at line 703
template <class T, class Alloc> template <class T, class Alloc>
inline void ArrayVector<T, Alloc>::pop_back() inline void ArrayVector<T, Alloc>::pop_back()
{ {
--this->size_; --this->size_;
alloc_.destroy(this->data_ + this->size_); alloc_.destroy(this->data_ + this->size_);
} }
template <class T, class Alloc> template <class T, class Alloc>
inline void ArrayVector<T, Alloc>::push_back( value_type const & t ) inline void ArrayVector<T, Alloc>::push_back( value_type const & t )
{ {
reserve(); pointer old_data = reserveImpl(false);
alloc_.construct(this->data_ + this->size_, t); alloc_.construct(this->data_ + this->size_, t);
// deallocate old data _after_ construction of new element, so that
// 't' can refer to the old data as in 'push_back(front())'
deallocate(old_data, this->size_);
++this->size_; ++this->size_;
} }
template <class T, class Alloc> template <class T, class Alloc>
inline void ArrayVector<T, Alloc>::clear() inline void ArrayVector<T, Alloc>::clear()
{ {
detail::destroy_n(this->data_, (int)this->size_); detail::destroy_n(this->data_, this->size_);
this->size_ = 0; this->size_ = 0;
} }
template <class T, class Alloc> template <class T, class Alloc>
typename ArrayVector<T, Alloc>::iterator typename ArrayVector<T, Alloc>::iterator
ArrayVector<T, Alloc>::insert(iterator p, value_type const & v) ArrayVector<T, Alloc>::insert(iterator p, value_type const & v)
{ {
difference_type pos = p - this->begin(); difference_type pos = p - this->begin();
if(p == this->end()) if(p == this->end())
{ {
push_back(v); push_back(v);
p = this->begin() + pos; p = this->begin() + pos;
} }
else else
{ {
push_back(this->back()); T lastElement = this->back();
push_back(lastElement);
p = this->begin() + pos; p = this->begin() + pos;
std::copy_backward(p, this->end() - 2, this->end() - 1); std::copy_backward(p, this->end() - 2, this->end() - 1);
*p = v; *p = v;
} }
return p; return p;
} }
template <class T, class Alloc> template <class T, class Alloc>
typename ArrayVector<T, Alloc>::iterator typename ArrayVector<T, Alloc>::iterator
ArrayVector<T, Alloc>::insert(iterator p, size_type n, value_type const & v ) ArrayVector<T, Alloc>::insert(iterator p, size_type n, value_type const & v )
skipping to change at line 806 skipping to change at line 850
ArrayVector<T, Alloc>::erase(iterator p, iterator q) ArrayVector<T, Alloc>::erase(iterator p, iterator q)
{ {
std::copy(q, this->end(), p); std::copy(q, this->end(), p);
difference_type eraseCount = q - p; difference_type eraseCount = q - p;
detail::destroy_n(this->end() - eraseCount, eraseCount); detail::destroy_n(this->end() - eraseCount, eraseCount);
this->size_ -= eraseCount; this->size_ -= eraseCount;
return p; return p;
} }
template <class T, class Alloc> template <class T, class Alloc>
inline void typename ArrayVector<T, Alloc>::pointer
ArrayVector<T, Alloc>::reserve( size_type new_capacity ) ArrayVector<T, Alloc>::reserveImpl( bool dealloc, size_type new_capacity)
{ {
if(new_capacity <= capacity_) if(new_capacity <= capacity_)
return; return 0;
pointer new_data = reserve_raw(new_capacity); pointer new_data = reserve_raw(new_capacity),
old_data = this->data_;
if(this->size_ > 0) if(this->size_ > 0)
std::uninitialized_copy(this->data_, this->data_+this->size_, new_d std::uninitialized_copy(old_data, old_data+this->size_, new_data);
ata);
deallocate(this->data_, this->size_);
this->data_ = new_data; this->data_ = new_data;
capacity_ = new_capacity; capacity_ = new_capacity;
if(!dealloc)
return old_data;
deallocate(old_data, this->size_);
return 0;
} }
template <class T, class Alloc> template <class T, class Alloc>
inline void inline typename ArrayVector<T, Alloc>::pointer
ArrayVector<T, Alloc>::reserve() ArrayVector<T, Alloc>::reserveImpl(bool dealloc)
{ {
if(capacity_ == 0) if(capacity_ == 0)
reserve(minimumCapacity); return reserveImpl(dealloc, minimumCapacity);
else if(this->size_ == capacity_) else if(this->size_ == capacity_)
reserve(resizeFactor*capacity_); return reserveImpl(dealloc, resizeFactor*capacity_);
else
return 0;
} }
template <class T, class Alloc> template <class T, class Alloc>
inline void inline void
ArrayVector<T, Alloc>::resize( size_type new_size, value_type const & initi al) ArrayVector<T, Alloc>::resize( size_type new_size, value_type const & initi al)
{ {
if(new_size < this->size_) if(new_size < this->size_)
erase(this->begin() + new_size, this->end()); erase(this->begin() + new_size, this->end());
else if(this->size_ < new_size) else if(this->size_ < new_size)
{ {
skipping to change at line 879 skipping to change at line 929
std::swap(capacity_, rhs.capacity_); std::swap(capacity_, rhs.capacity_);
std::swap(this->data_, rhs.data_); std::swap(this->data_, rhs.data_);
} }
template <class T, class Alloc> template <class T, class Alloc>
inline void inline void
ArrayVector<T, Alloc>::deallocate(pointer data, size_type size) ArrayVector<T, Alloc>::deallocate(pointer data, size_type size)
{ {
if(data) if(data)
{ {
detail::destroy_n(data, (int)size); detail::destroy_n(data, size);
alloc_.deallocate(data, size); alloc_.deallocate(data, size);
} }
} }
template <class T, class Alloc> template <class T, class Alloc>
inline typename ArrayVector<T, Alloc>::pointer inline typename ArrayVector<T, Alloc>::pointer
ArrayVector<T, Alloc>::reserve_raw(size_type capacity) ArrayVector<T, Alloc>::reserve_raw(size_type capacity)
{ {
pointer data = 0; pointer data = 0;
if(capacity) if(capacity)
skipping to change at line 903 skipping to change at line 953
return data; return data;
} }
} // namespace vigra } // namespace vigra
namespace std { namespace std {
template <class T> template <class T>
ostream & operator<<(ostream & s, vigra::ArrayVectorView<T> const & a) ostream & operator<<(ostream & s, vigra::ArrayVectorView<T> const & a)
{ {
for(int k=0; k<(int)a.size()-1; ++k) for(std::size_t k=0; k<a.size()-1; ++k)
s << a[k] << ", "; s << a[k] << ", ";
if(a.size()) if(a.size())
s << a.back(); s << a.back();
return s; return s;
} }
} // namespace std } // namespace std
#undef VIGRA_ASSERT_INSIDE #undef VIGRA_ASSERT_INSIDE
#endif /* VIGRA_ARRAY_VECTOR_HXX */ #endif /* VIGRA_ARRAY_VECTOR_HXX */
 End of changes. 22 change blocks. 
22 lines changed or deleted 74 lines changed or added


 axistags.hxx   axistags.hxx 
skipping to change at line 61 skipping to change at line 61
{ {
public: public:
// this particular assignment of bits to types is crucial for // this particular assignment of bits to types is crucial for
// canonical axis ordering // canonical axis ordering
enum AxisType { Channels = 1, enum AxisType { Channels = 1,
Space = 2, Space = 2,
Angle = 4, Angle = 4,
Time = 8, Time = 8,
Frequency = 16, Frequency = 16,
UnknownAxisType = 32, Edge = 32,
UnknownAxisType = 64,
NonChannel = Space | Angle | Time | Frequency | Unknown AxisType, NonChannel = Space | Angle | Time | Frequency | Unknown AxisType,
AllAxes = 2*UnknownAxisType-1 }; AllAxes = 2*UnknownAxisType-1 };
AxisInfo(std::string key = "?", AxisType typeFlags = UnknownAxisType, AxisInfo(std::string key = "?", AxisType typeFlags = UnknownAxisType,
double resolution = 0.0, std::string description = "") double resolution = 0.0, std::string description = "")
: key_(key), : key_(key),
description_(description), description_(description),
resolution_(resolution), resolution_(resolution),
flags_(typeFlags) flags_(typeFlags)
{} {}
skipping to change at line 130 skipping to change at line 131
bool isChannel() const bool isChannel() const
{ {
return isType(Channels); return isType(Channels);
} }
bool isFrequency() const bool isFrequency() const
{ {
return isType(Frequency); return isType(Frequency);
} }
bool isEdge() const
{
return isType(Edge);
}
bool isAngular() const bool isAngular() const
{ {
return isType(Angle); return isType(Angle);
} }
bool isType(AxisType type) const bool isType(AxisType type) const
{ {
return (typeFlags() & type) != 0; return (typeFlags() & type) != 0;
} }
skipping to change at line 259 skipping to change at line 265
static AxisInfo y(double resolution = 0.0, std::string const & descript ion = "") static AxisInfo y(double resolution = 0.0, std::string const & descript ion = "")
{ {
return AxisInfo("y", Space, resolution, description); return AxisInfo("y", Space, resolution, description);
} }
static AxisInfo z(double resolution = 0.0, std::string const & descript ion = "") static AxisInfo z(double resolution = 0.0, std::string const & descript ion = "")
{ {
return AxisInfo("z", Space, resolution, description); return AxisInfo("z", Space, resolution, description);
} }
static AxisInfo n(double resolution = 0.0, std::string const & descript
ion = "")
{
return AxisInfo("n", Space, resolution, description);
}
static AxisInfo e(double resolution = 0.0, std::string const & descript
ion = "")
{
return AxisInfo("e", Edge, resolution, description);
}
static AxisInfo t(double resolution = 0.0, std::string const & descript ion = "") static AxisInfo t(double resolution = 0.0, std::string const & descript ion = "")
{ {
return AxisInfo("t", Time, resolution, description); return AxisInfo("t", Time, resolution, description);
} }
static AxisInfo fx(double resolution = 0.0, std::string const & descrip tion = "") static AxisInfo fx(double resolution = 0.0, std::string const & descrip tion = "")
{ {
return AxisInfo("x", AxisType(Space | Frequency), resolution, descr iption); return AxisInfo("x", AxisType(Space | Frequency), resolution, descr iption);
} }
skipping to change at line 342 skipping to change at line 358
AxisTags(AxisInfo const & i1, AxisInfo const & i2, AxisTags(AxisInfo const & i1, AxisInfo const & i2,
AxisInfo const & i3, AxisInfo const & i4, AxisInfo const & i5) AxisInfo const & i3, AxisInfo const & i4, AxisInfo const & i5)
{ {
push_back(i1); push_back(i1);
push_back(i2); push_back(i2);
push_back(i3); push_back(i3);
push_back(i4); push_back(i4);
push_back(i5); push_back(i5);
} }
AxisTags(std::string const & tags)
{
for(int k=0; k<tags.size(); ++k)
{
switch(tags[k])
{
case 'x':
push_back(AxisInfo::x());
break;
case 'y':
push_back(AxisInfo::y());
break;
case 'z':
push_back(AxisInfo::z());
break;
case 't':
push_back(AxisInfo::t());
break;
case 'c':
push_back(AxisInfo::c());
break;
case 'f':
++k;
vigra_precondition(k < tags.size(),
"AxisTags(string): invalid input");
switch(tags[k])
{
case 'x':
push_back(AxisInfo::fx());
break;
case 'y':
push_back(AxisInfo::fy());
break;
case 'z':
push_back(AxisInfo::fz());
break;
case 't':
push_back(AxisInfo::ft());
break;
default:
vigra_precondition(false,
"AxisTags(string): invalid input");
}
break;
default:
vigra_precondition(false,
"AxisTags(string): invalid input");
}
}
}
// static AxisTags fromJSON(std::string const & repr); // static AxisTags fromJSON(std::string const & repr);
std::string toJSON() const std::string toJSON() const
{ {
std::stringstream s; std::stringstream s;
s << "{\n \"axes\": ["; s << "{\n \"axes\": [";
for(unsigned int k=0; k<size(); ++k) for(unsigned int k=0; k<size(); ++k)
{ {
if(k > 0) if(k > 0)
s << ","; s << ",";
skipping to change at line 391 skipping to change at line 458
if(size() > 0) if(size() > 0)
res += axes_[0].key(); res += axes_[0].key();
for(unsigned int k=1; k<size(); ++k) for(unsigned int k=1; k<size(); ++k)
{ {
res += " "; res += " ";
res += axes_[k].key(); res += axes_[k].key();
} }
return res; return res;
} }
bool contains(std::string const & key) const
{
return index(key) < (int)size();
}
AxisInfo & get(int k) AxisInfo & get(int k)
{ {
checkIndex(k); checkIndex(k);
if(k < 0) if(k < 0)
k += size(); k += size();
return axes_[k]; return axes_[k];
} }
AxisInfo & get(std::string const & key) AxisInfo & get(std::string const & key)
{ {
 End of changes. 5 change blocks. 
1 lines changed or deleted 75 lines changed or added


 basicgeometry.hxx   basicgeometry.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_BASICGEOMETRY_HXX #ifndef VIGRA_BASICGEOMETRY_HXX
#define VIGRA_BASICGEOMETRY_HXX #define VIGRA_BASICGEOMETRY_HXX
#include "error.hxx" #include "error.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "copyimage.hxx" #include "copyimage.hxx"
#include "multi_shape.hxx"
#include <cmath> #include <cmath>
namespace vigra { namespace vigra {
/** \addtogroup GeometricTransformations Geometric Transformations /** \addtogroup GeometricTransformations Geometric Transformations
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* rotateImage */ /* rotateImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Rotate image by a multiple of 90 degrees. /** \brief Rotate an image by a multiple of 90 degrees or by an arbitrary a
ngle.
If you specify the angle as an integer which is a multiple of 90 degree
s, rotateImage()
just copies the pixels in the appropriate new order. It expects the des
tination image to
have the correct shape for the desired rotation. That is, when the rota
tion is a multiple
of 180 degrees, source and destination must have the same shape, otherw
ise destination
must have the transposed shape of the source.
If you want to rotate by an arbitrary angle and around an arbitrary cen
ter point,
you must specify the source image as a \ref vigra::SplineImageView, whi
ch is used for
interpolation at the required subpixel positions. If no center point is
provided, the image
center is used by default. The destination image must have the same siz
e
as the source SplineImageView.
This algorithm just copies the pixels in the appropriate new order. It Positive angles refer to counter-clockwise rotation, negative ones to c
expects the lockwise rotation.
destination image to have the correct shape for the desired rotation. All angles must be given in degrees.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// rotate by a multiple of 90 degrees
template <class T1, class S1,
class T2, class S2>
void
rotateImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int rotation);
// rotate by an arbitrary angle around the given center point
template <int ORDER, class T,
class T2, class S2>
void
rotateImage(SplineImageView<ORDER, T> const & src,
MultiArrayView<2, T2, S2> dest,
double angleInDegree,
TinyVector<double, 2> const & center = (src.shape() - S
hape2(1)) / 2.0);
}
\endcode
\deprecatedAPI{rotateImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// rotate by a multiple of 90 degrees
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
rotateImage(SrcIterator is, SrcIterator end, SrcAccessor as, rotateImage(SrcIterator is, SrcIterator end, SrcAccessor as,
DestIterator id, DestAccessor ad, int rotation); DestIterator id, DestAccessor ad, int rotation);
// rotate by an arbitrary angle around the given center point
template <int ORDER, class T,
class DestIterator, class DestAccessor>
void rotateImage(SplineImageView<ORDER, T> const & src,
DestIterator id, DestAccessor dest,
double angleInDegree, TinyVector<double, 2> const
& center = (src.shape() - Shape2(1)) / 2.0);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// rotate by a multiple of 90 degrees
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void void
rotateImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, rotateImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, int rotatio n); pair<DestImageIterator, DestAccessor> dest, int rotatio n);
// rotate by an arbitrary angle around the given center point
template <int ORDER, class T,
class DestIterator, class DestAccessor>
void
rotateImage(SplineImageView<ORDER, T> const & src,
pair<DestImageIterator, DestAccessor> dest,
double angleInDegree, TinyVector<double, 2> const & cen
ter = (src.shape() - Shape2(1)) / 2.0);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/basicgeometry.hxx\><br> <b>\#include</b> \<vigra/basicgeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image dest(src.height(), src.width()); // note that width and height ar // rotate counter-clockwise by 90 degrees (no interpolation required)
e exchanged MultiArray<2, float> src(width, height),
dest(height, width); // note that width and height
are exchanged
... // fill src
rotateImage(src, dest, 90);
vigra::rotateImage(srcImageRange(src), destImage(dest), 90); // rotate clockwise by 38.5 degrees, using a SplieImageView for cubic i
nterpolation
SplineImageView<3, float> spline(srcImageRange(src));
MultiArray<2, float> dest2(src.shape());
vigra::rotateImage(spline, dest2, -38.5);
\endcode \endcode
<b> Required Interface:</b> \deprecatedUsage{rotateImage}
\code
// rotate counter-clockwise by 90 degrees (no interpolation required)
BImage src(width, height),
dest(height, width); // note that width and height are exchan
ged
... // fill src
rotateImage(srcImageRange(src), destImage(dest), 90);
// rotate clockwise by 38.5 degrees, using a SplieImageView for cubic i
nterpolation
SplineImageView<3, float> spline(srcImageRange(src));
FImage dest2(width, height);
rotateImage(spline, destImage(dest), -38.5);
\endcode
<b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
dest_accessor.set(src_accessor(src_upperleft), dest_upperleft); dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
src_lowerright.x - src_upperleft.x > 1 src.shape(0) > 1 && src.shape(1) > 1
src_lowerright.y - src_upperleft.y > 1
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void rotateImage) doxygen_overloaded_function(template <...> void rotateImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void rotateImage(SrcIterator is, SrcIterator end, SrcAccessor as, void rotateImage(SrcIterator is, SrcIterator end, SrcAccessor as,
DestIterator id, DestAccessor ad, int rotation) DestIterator id, DestAccessor ad, int rotation)
{ {
int x, y; int x, y;
int ws = end.x - is.x; int ws = end.x - is.x;
skipping to change at line 197 skipping to change at line 269
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void inline void
rotateImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, rotateImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, int rotation) pair<DestImageIterator, DestAccessor> dest, int rotation)
{ {
rotateImage(src.first, src.second, src.third, dest.first, dest.second, rotation); rotateImage(src.first, src.second, src.third, dest.first, dest.second, rotation);
} }
template <class T1, class S1,
class T2, class S2>
inline void
rotateImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int rotation)
{
if(rotation % 180 == 0)
vigra_precondition(src.shape() == dest.shape(),
"rotateImage(): shape mismatch between input and output.");
else
vigra_precondition(src.shape() == reverse(dest.shape()),
"rotateImage(): shape mismatch between input and output.");
rotateImage(srcImageRange(src), destImage(dest), rotation);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* reflectImage */ /* reflectImage */
/* */ /* */
/********************************************************/ /********************************************************/
enum Reflect {horizontal = 1, vertical = 2}; enum Reflect {horizontal = 1, vertical = 2};
inline inline
Reflect operator|(Reflect l, Reflect r) Reflect operator|(Reflect l, Reflect r)
skipping to change at line 222 skipping to change at line 310
The reflection direction refers to the reflection axis, i.e. The reflection direction refers to the reflection axis, i.e.
horizontal reflection turns the image upside down, vertical reflection horizontal reflection turns the image upside down, vertical reflection
changes left for right. The directions are selected by the enum values changes left for right. The directions are selected by the enum values
<tt>vigra::horizontal</tt> and <tt>vigra::vertical</tt>. The two direct ions <tt>vigra::horizontal</tt> and <tt>vigra::vertical</tt>. The two direct ions
can also be "or"ed together to perform both reflections simultaneously can also be "or"ed together to perform both reflections simultaneously
(see example below) -- this is the same as a 180 degree rotation. (see example below) -- this is the same as a 180 degree rotation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
reflectImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, Reflect reflect);
}
\endcode
\deprecatedAPI{reflectImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
reflectImage(SrcIterator is, SrcIterator end, SrcAccessor as, reflectImage(SrcIterator is, SrcIterator end, SrcAccessor as,
DestIterator id, DestAccessor ad, Reflect axis); DestIterator id, DestAccessor ad, Reflect axis);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void void
reflectImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor > src, reflectImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor > src,
pair<DestImageIterator, DestAccessor> dest, Reflect ax is); pair<DestImageIterator, DestAccessor> dest, Reflect ax is);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/basicgeometry.hxx\><br> <b>\#include</b> \<vigra/basicgeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image dest(src.width(), src.height()); MultiArray<2, float> src(width, height),
dest(width, height);
vigra::reflectImage(srcImageRange(src), destImage(dest), vigra::horizon ... // fill src
tal | vigra::vertical); // reflect about both dimensions
vigra::reflectImage(src, dest, vigra::horizontal | vigra::vertical);
\endcode \endcode
<b> Required Interface:</b> \deprecatedUsage{reflectImage}
\code
BImage src(width, height),
dest(width, height);
... // fill src
vigra::reflectImage(srcImageRange(src), destImage(dest), vigra::horizon
tal | vigra::vertical);
\endcode
<b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
dest_accessor.set(src_accessor(src_upperleft), dest_upperleft); dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
src_lowerright.x - src_upperleft.x > 1 src.shape(0) > 1 && src.shape(1) > 1
src_lowerright.y - src_upperleft.y > 1
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void reflectImage) doxygen_overloaded_function(template <...> void reflectImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void reflectImage(SrcIterator is, SrcIterator end, SrcAccessor as, void reflectImage(SrcIterator is, SrcIterator end, SrcAccessor as,
DestIterator id, DestAccessor ad, Reflect reflect) DestIterator id, DestAccessor ad, Reflect reflect)
{ {
int ws = end.x - is.x; int ws = end.x - is.x;
skipping to change at line 345 skipping to change at line 451
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void inline void
reflectImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, reflectImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, Reflect reflect) pair<DestImageIterator, DestAccessor> dest, Reflect reflect)
{ {
reflectImage(src.first, src.second, src.third, dest.first, dest.second, reflect); reflectImage(src.first, src.second, src.third, dest.first, dest.second, reflect);
} }
template <class T1, class S1,
class T2, class S2>
inline void
reflectImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, Reflect reflect)
{
vigra_precondition(src.shape() == dest.shape(),
"reflectImage(): shape mismatch between input and output.");
reflectImage(srcImageRange(src), destImage(dest), reflect);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* transposeImage */ /* transposeImage */
/* */ /* */
/********************************************************/ /********************************************************/
// names clash with sys/types.h on Mac OS / Darwin, see docs below // names clash with sys/types.h on Mac OS / Darwin, see docs below
enum Transpose{major = 1, minor = 2}; enum Transpose{major = 1, minor = 2};
/** \brief Transpose an image over the major or minor diagonal. /** \brief Transpose an image over the major or minor diagonal.
skipping to change at line 367 skipping to change at line 484
major transposition turns the upper right corner into the lower left on e, major transposition turns the upper right corner into the lower left on e,
whereas minor transposition changes the upper left corner into the lowe r right one. whereas minor transposition changes the upper left corner into the lowe r right one.
The directions are selected by the enum values The directions are selected by the enum values
<tt>vigra::major</tt> and <tt>vigra::minor</tt>. The two directions <tt>vigra::major</tt> and <tt>vigra::minor</tt>. The two directions
can also be "or"ed together to perform both reflections simultaneously can also be "or"ed together to perform both reflections simultaneously
(see example below) -- this is the same as a 180 degree rotation. (see example below) -- this is the same as a 180 degree rotation.
(Caution: When doing multi-platform development, you should be (Caution: When doing multi-platform development, you should be
aware that some <sys/types.h> define major/minor, too. Do not omit aware that some <sys/types.h> define major/minor, too. Do not omit
the vigra namespace prefix.) the vigra namespace prefix.)
Note that a similar effect can be chieved by MultiArrayView::transpose(
). However,
the latter can only transpose about the major diagonal, and it doesn't
rearrange the data
- it just creates a view with transposed axis ordering. It depends on
the context
which function is more appropriate.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
transposeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, Transpose axis);
}
\endcode
\deprecatedAPI{transposeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
transposeImage(SrcIterator is, SrcIterator end, SrcAccessor as, transposeImage(SrcIterator is, SrcIterator end, SrcAccessor as,
DestIterator id, DestAccessor ad, Transpose axis); DestIterator id, DestAccessor ad, Transpose axis);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void void
transposeImage(triple<SrcImageIterator, SrcImageIterator, SrcAccess or> src, transposeImage(triple<SrcImageIterator, SrcImageIterator, SrcAccess or> src,
pair<DestImageIterator, DestAccessor> dest, Transpos e axis); pair<DestImageIterator, DestAccessor> dest, Transpos e axis);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/basicgeometry.hxx\><br> <b>\#include</b> \<vigra/basicgeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image dest(src.width(), src.height()); MultiArray<2, float> src(width, height),
dest(height, width); // note that dimensions are
transposed
... // fill src
vigra::transposeImage(srcImageRange(src), destImage(dest), vigra::major // transpose about the major diagonal
| vigra::minor); vigra::transposeImage(src, dest, vigra::major);
// this produces the same data as transposing the view
assert(dest == src.transpose());
// transposition about the minor diagonal has no correspondence in Mult
iArrayView
vigra::transposeImage(src, dest, vigra::minor);
\endcode \endcode
<b> Required Interface:</b> \deprecatedUsage{transposeImage}
\code
BImage src(width, height),
dest(width, height);
... // fill src
// transpose about both diagonals simultaneously
vigra::transposeImage(srcImageRange(src), destImage(dest), vigra::major
| vigra::minor);
\endcode
<b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
dest_accessor.set(src_accessor(src_upperleft), dest_upperleft); dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
src_lowerright.x - src_upperleft.x > 1 src.shape(0) > 1 && src.shape(1) > 1
src_lowerright.y - src_upperleft.y > 1
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void transposeImage) doxygen_overloaded_function(template <...> void transposeImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void transposeImage(SrcIterator is, SrcIterator end, SrcAccessor as, void transposeImage(SrcIterator is, SrcIterator end, SrcAccessor as,
DestIterator id, DestAccessor ad, Transpose transpose) DestIterator id, DestAccessor ad, Transpose transpose)
{ {
int ws = end.x - is.x; int ws = end.x - is.x;
int hs = end.y - is.y; int hs = end.y - is.y;
skipping to change at line 489 skipping to change at line 636
vigra_fail("transposeImage(): " vigra_fail("transposeImage(): "
"This function transposes major or minor," "This function transposes major or minor,"
" 'and' is included"); " 'and' is included");
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void inline void
transposeImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, transposeImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, Transpose transpo se) pair<DestImageIterator, DestAccessor> dest, Transpose transp ose)
{ {
transposeImage(src.first, src.second, src.third, dest.first, dest.secon d, transpose); transposeImage(src.first, src.second, src.third, dest.first, dest.secon d, transpose);
} }
template <class T1, class S1,
class T2, class S2>
inline void
transposeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, Transpose transpose)
{
vigra_precondition(src.shape() == reverse(dest.shape()),
"transposeImage(): shape mismatch between input and output.");
transposeImage(srcImageRange(src), destImage(dest), transpose);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* resampleLine */ /* resampleLine */
/* */ /* */
/********************************************************/ /********************************************************/
/* /*
* Vergroessert eine Linie um einen Faktor. * Vergroessert eine Linie um einen Faktor.
* Ist z.B. der Faktor = 4 so werden in der * Ist z.B. der Faktor = 4 so werden in der
* neuen Linie(Destination) jedes Pixel genau 4 mal * neuen Linie(Destination) jedes Pixel genau 4 mal
skipping to change at line 593 skipping to change at line 751
This algorithm is very fast and does not require any arithmetic on the pixel types. This algorithm is very fast and does not require any arithmetic on the pixel types.
The input image must have a size of at The input image must have a size of at
least 2x2. Destiniation pixels are directly copied from the appropriate least 2x2. Destiniation pixels are directly copied from the appropriate
source pixels. The size of the result image is the product of <tt>facto r</tt> source pixels. The size of the result image is the product of <tt>facto r</tt>
and the original size, where we round up if <tt>factor < 1.0</tt> and d own otherwise. and the original size, where we round up if <tt>factor < 1.0</tt> and d own otherwise.
This size calculation is the main difference to the convention used in the similar This size calculation is the main difference to the convention used in the similar
function \ref resizeImageNoInterpolation(): function \ref resizeImageNoInterpolation():
there, the result size is calculated as <tt>n*(old_width-1)+1</tt> and there, the result size is calculated as <tt>n*(old_width-1)+1</tt> and
<tt>n*(old_height-1)+1</tt>. This is because \ref resizeImageNoInterpol ation() <tt>n*(old_height-1)+1</tt>. This is because \ref resizeImageNoInterpol ation()
does not replicate the last pixel in every row/column in order to make it compatible does not replicate the last pixel of every row/column in order to make it compatible
with the other functions of the <tt>resizeImage...</tt> family. with the other functions of the <tt>resizeImage...</tt> family.
The function can be called with different resampling factors for x and y, or The function can be called with different resampling factors for x and y, or
with a single factor to be used for both directions. with a single factor to be used for both directions.
It should also be noted that resampleImage() is implemented so that an enlargement followed It should also be noted that resampleImage() is implemented so that an enlargement followed
by the corresponding shrinking reproduces the original image. The funct ion uses accessors. by the corresponding shrinking reproduces the original image.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
resampleImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, double factor);
template <class T1, class S1,
class T2, class S2>
void
resampleImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, double xfactor, doubl
e yfactor);
}
\endcode
\deprecatedAPI{resampleImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa, resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor ad, double factor); DestIterator id, DestAccessor ad, double factor);
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa, resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor ad, double xfactor, dou ble yfactor); DestIterator id, DestAccessor ad, double xfactor, dou ble yfactor);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void void
resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccesso r> src, resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccesso r> src,
pair<DestImageIterator, DestAccessor> dest, double fa ctor); pair<DestImageIterator, DestAccessor> dest, double fa ctor);
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void void
resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccesso r> src, resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccesso r> src,
pair<DestImageIterator, DestAccessor> dest, double xf actor, double yfactor); pair<DestImageIterator, DestAccessor> dest, double xf actor, double yfactor);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/basicgeometry.hxx\><br> <b>\#include</b> \<vigra/basicgeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
double factor = 2.0; double factor = 2.0;
Image dest((int)(factor*src.width()), (int)(factor*src.height())); MultiArray<2, float> src(width, height),
dest((int)(factor*width), (int)(factor*height));
vigra::resampleImage(srcImageRange(src), destImage(dest), factor); // enlarge image by factor
... // fill src
resampleImage(src, dest, factor);
\endcode \endcode
\deprecatedUsage{resampleImage}
\code
// use old API
vigra::resampleImage(srcImageRange(src), destImage(dest), factor);
\endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
dest_accessor.set(src_accessor(src_upperleft), dest_upperleft); dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
src_lowerright.x - src_upperleft.x > 1 src.shape(0) > 1 && src.shape(1) > 1
src_lowerright.y - src_upperleft.y > 1
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void resampleImage) doxygen_overloaded_function(template <...> void resampleImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa, resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor ad, double xfactor, double yfac tor) DestIterator id, DestAccessor ad, double xfactor, double yfac tor)
{ {
int width_old = iend.x - is.x; int width_old = iend.x - is.x;
skipping to change at line 751 skipping to change at line 929
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void inline void
resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, double xfactor, d ouble yfactor) pair<DestImageIterator, DestAccessor> dest, double xfactor, d ouble yfactor)
{ {
resampleImage(src.first, src.second, src.third, dest.first, dest.second, xfactor, yfactor); resampleImage(src.first, src.second, src.third, dest.first, dest.second, xfactor, yfactor);
} }
template <class T1, class S1,
class T2, class S2>
inline void
resampleImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, double factor)
{
if(factor > 1.0)
vigra_precondition(floor(factor*src.shape()) == dest.shape(),
"resampleImage(): shape mismatch between input and output.");
else
vigra_precondition(ceil(factor*src.shape()) == dest.shape(),
"resampleImage(): shape mismatch between input and output.");
resampleImage(srcImageRange(src), destImage(dest), factor);
}
template <class T1, class S1,
class T2, class S2>
inline void
resampleImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, double xfactor, double yfacto
r)
{
if(xfactor > 1.0)
vigra_precondition(floor(xfactor*src.shape(0)) == dest.shape(0),
"resampleImage(): shape mismatch between input and output.");
else
vigra_precondition(ceil(xfactor*src.shape(0)) == dest.shape(0),
"resampleImage(): shape mismatch between input and output.");
if(yfactor > 1.0)
vigra_precondition(floor(yfactor*src.shape(1)) == dest.shape(1),
"resampleImage(): shape mismatch between input and output.");
else
vigra_precondition(ceil(yfactor*src.shape(1)) == dest.shape(1),
"resampleImage(): shape mismatch between input and output.");
resampleImage(srcImageRange(src), destImage(dest), xfactor, yfactor);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_BASICGEOMETRY_HXX */ #endif /* VIGRA_BASICGEOMETRY_HXX */
 End of changes. 73 change blocks. 
65 lines changed or deleted 304 lines changed or added


 basicimage.hxx   basicimage.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_BASICIMAGE_HXX #ifndef VIGRA_BASICIMAGE_HXX
#define VIGRA_BASICIMAGE_HXX #define VIGRA_BASICIMAGE_HXX
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include "utilities.hxx" #include "utilities.hxx"
#include "iteratortraits.hxx" #include "iteratortraits.hxx"
#include "accessor.hxx" #include "accessor.hxx"
#include "memory.hxx" #include "memory.hxx"
#include "basicimageview.hxx"
// Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined. // Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
#ifdef VIGRA_CHECK_BOUNDS #ifdef VIGRA_CHECK_BOUNDS
#define VIGRA_ASSERT_INSIDE(diff) \ #define VIGRA_ASSERT_INSIDE(diff) \
vigra_precondition(this->isInside(diff), "Index out of bounds") vigra_precondition(this->isInside(diff), "Index out of bounds")
#else #else
#define VIGRA_ASSERT_INSIDE(diff) #define VIGRA_ASSERT_INSIDE(diff)
#endif #endif
namespace vigra { namespace vigra {
skipping to change at line 119 skipping to change at line 120
/********************************************************/ /********************************************************/
/* */ /* */
/* BasicImageIterator */ /* BasicImageIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** Implementation of the standard image iterator for \ref vigra::BasicImag e. /** Implementation of the standard image iterator for \ref vigra::BasicImag e.
See \ref vigra::ImageIterator for documentation. See \ref vigra::ImageIterator for documentation.
<b>\#include</b> \<vigra/basicimage.hxx\> <b>\#include</b> \<vigra/basicimage.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class IMAGEITERATOR, class PIXELTYPE, template <class IMAGEITERATOR, class PIXELTYPE,
class REFERENCE, class POINTER, class LINESTARTITERATOR> class REFERENCE, class POINTER, class LINESTARTITERATOR>
class BasicImageIteratorBase class BasicImageIteratorBase
{ {
public: public:
typedef BasicImageIteratorBase<IMAGEITERATOR, typedef BasicImageIteratorBase<IMAGEITERATOR,
PIXELTYPE, REFERENCE, POINTER, LINESTARTITERATOR> self_type; PIXELTYPE, REFERENCE, POINTER, LINESTARTITERATOR> self_type;
skipping to change at line 142 skipping to change at line 143
typedef PIXELTYPE PixelType; typedef PIXELTYPE PixelType;
typedef REFERENCE reference; typedef REFERENCE reference;
typedef REFERENCE index_reference; typedef REFERENCE index_reference;
typedef POINTER pointer; typedef POINTER pointer;
typedef Diff2D difference_type; typedef Diff2D difference_type;
typedef image_traverser_tag iterator_category; typedef image_traverser_tag iterator_category;
typedef POINTER row_iterator; typedef POINTER row_iterator;
typedef IteratorAdaptor<LineBasedColumnIteratorPolicy<IMAGEITERATOR> > typedef IteratorAdaptor<LineBasedColumnIteratorPolicy<IMAGEITERATOR> >
column_iterator; column_iterator;
typedef int MoveX; typedef std::ptrdiff_t MoveX;
typedef LINESTARTITERATOR MoveY; typedef LINESTARTITERATOR MoveY;
MoveX x; MoveX x;
MoveY y; MoveY y;
IMAGEITERATOR & operator+=(difference_type const & s) IMAGEITERATOR & operator+=(difference_type const & s)
{ {
x += s.x; x += s.x;
y += s.y; y += s.y;
return static_cast<IMAGEITERATOR &>(*this); return static_cast<IMAGEITERATOR &>(*this);
skipping to change at line 211 skipping to change at line 212
pointer operator->() const pointer operator->() const
{ {
return *y + x; return *y + x;
} }
index_reference operator[](difference_type const & d) const index_reference operator[](difference_type const & d) const
{ {
return *(*(y + d.y) + x + d.x); return *(*(y + d.y) + x + d.x);
} }
index_reference operator()(int dx, int dy) const index_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
{ {
return *(*(y + dy) + x + dx); return *(*(y + dy) + x + dx);
} }
pointer operator[](int dy) const pointer operator[](std::ptrdiff_t dy) const
{ {
return y[dy] + x; return y[dy] + x;
} }
row_iterator rowIterator() const row_iterator rowIterator() const
{ return *y + x; } { return *y + x; }
column_iterator columnIterator() const column_iterator columnIterator() const
{ {
typedef typename column_iterator::BaseType Iter; typedef typename column_iterator::BaseType Iter;
return column_iterator(Iter(y, x)); return column_iterator(Iter(y, x));
} }
protected: protected:
BasicImageIteratorBase(LINESTARTITERATOR const & line) BasicImageIteratorBase(LINESTARTITERATOR const & line)
: x(0), : x(0),
y(line) y(line)
{} {}
BasicImageIteratorBase(int ix, LINESTARTITERATOR const & line) BasicImageIteratorBase(std::ptrdiff_t ix, LINESTARTITERATOR const & lin e)
: x(ix), : x(ix),
y(line) y(line)
{} {}
BasicImageIteratorBase() BasicImageIteratorBase()
: x(0), : x(0),
y(0) y(0)
{} {}
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* BasicImageIterator */ /* BasicImageIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** Implementation of the standard image iterator for \ref vigra::BasicImag e. /** Implementation of the standard image iterator for \ref vigra::BasicImag e.
See \ref vigra::ImageIterator for documentation. See \ref vigra::ImageIterator for documentation.
<b>\#include</b> \<vigra/basicimage.hxx\> <b>\#include</b> \<vigra/basicimage.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE, class ITERATOR> template <class PIXELTYPE, class ITERATOR>
class BasicImageIterator class BasicImageIterator
: public BasicImageIteratorBase<BasicImageIterator<PIXELTYPE, ITERATOR>, : public BasicImageIteratorBase<BasicImageIterator<PIXELTYPE, ITERATOR>,
PIXELTYPE, PIXELTYPE &, PIXELTYPE *, ITERATOR> PIXELTYPE, PIXELTYPE &, PIXELTYPE *, ITERATOR>
{ {
public: public:
typedef BasicImageIteratorBase<BasicImageIterator, PIXELTYPE, typedef BasicImageIteratorBase<BasicImageIterator, PIXELTYPE,
skipping to change at line 287 skipping to change at line 288
/********************************************************/ /********************************************************/
/* */ /* */
/* ConstBasicImageIterator */ /* ConstBasicImageIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** Implementation of the standard const image iterator for \ref vigra::Bas icImage. /** Implementation of the standard const image iterator for \ref vigra::Bas icImage.
See \ref vigra::ConstImageIterator for documentation. See \ref vigra::ConstImageIterator for documentation.
<b>\#include</b> \<vigra/basicimage.hxx\> <b>\#include</b> \<vigra/basicimage.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE, class ITERATOR> template <class PIXELTYPE, class ITERATOR>
class ConstBasicImageIterator class ConstBasicImageIterator
: public BasicImageIteratorBase<ConstBasicImageIterator<PIXELTYPE, ITERATOR >, : public BasicImageIteratorBase<ConstBasicImageIterator<PIXELTYPE, ITERATOR >,
PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *, ITERAT OR> PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *, ITERAT OR>
{ {
public: public:
typedef BasicImageIteratorBase<ConstBasicImageIterator, typedef BasicImageIteratorBase<ConstBasicImageIterator,
skipping to change at line 464 skipping to change at line 465
/* */ /* */
/* BasicImage */ /* BasicImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Fundamental class template for images. /** \brief Fundamental class template for images.
A customized memory allocator can be specified as a templated argument A customized memory allocator can be specified as a templated argument
and passed in the constructor. and passed in the constructor.
<b>\#include</b> \<vigra/basicimage.hxx\> <b>\#include</b> \<vigra/basicimage.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE, class Alloc = std::allocator<PIXELTYPE> > template <class PIXELTYPE, class Alloc = std::allocator<PIXELTYPE> >
class BasicImage class BasicImage
{ {
public: public:
/** the BasicImage's pixel type /** the BasicImage's pixel type
*/ */
typedef PIXELTYPE value_type; typedef PIXELTYPE value_type;
skipping to change at line 601 skipping to change at line 601
explicit BasicImage(Alloc const & alloc) explicit BasicImage(Alloc const & alloc)
: data_(0), : data_(0),
width_(0), width_(0),
height_(0), height_(0),
allocator_(alloc), allocator_(alloc),
pallocator_(alloc) pallocator_(alloc)
{} {}
/** construct image of size width x height, use the specified alloc ator. /** construct image of size width x height, use the specified alloc ator.
*/ */
BasicImage(int width, int height, Alloc const & alloc = Alloc()) BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, Alloc const & a lloc = Alloc())
: data_(0), : data_(0),
width_(0), width_(0),
height_(0), height_(0),
allocator_(alloc), allocator_(alloc),
pallocator_(alloc) pallocator_(alloc)
{ {
vigra_precondition((width >= 0) && (height >= 0), vigra_precondition((width >= 0) && (height >= 0),
"BasicImage::BasicImage(int width, int height): " "BasicImage::BasicImage(int width, int height): "
"width and height must be >= 0.\n"); "width and height must be >= 0.\n");
skipping to change at line 636 skipping to change at line 636
"size.x and size.y must be >= 0.\n"); "size.x and size.y must be >= 0.\n");
resize(size.x, size.y, value_type()); resize(size.x, size.y, value_type());
} }
/** construct image of size width*height and initialize every /** construct image of size width*height and initialize every
pixel with the value \a d (use this constructor, if pixel with the value \a d (use this constructor, if
value_type doesn't have a default constructor). value_type doesn't have a default constructor).
Use the specified allocator. Use the specified allocator.
*/ */
BasicImage(int width, int height, value_type const & d, Alloc const & a lloc = Alloc()) BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, value_type cons t & d, Alloc const & alloc = Alloc())
: data_(0), : data_(0),
width_(0), width_(0),
height_(0), height_(0),
allocator_(alloc), allocator_(alloc),
pallocator_(alloc) pallocator_(alloc)
{ {
vigra_precondition((width >= 0) && (height >= 0), vigra_precondition((width >= 0) && (height >= 0),
"BasicImage::BasicImage(int width, int height, value_type cons t & ): " "BasicImage::BasicImage(int width, int height, value_type cons t & ): "
"width and height must be >= 0.\n"); "width and height must be >= 0.\n");
resize(width, height, d); resize(width, height, d);
} }
/** construct image of size width*height and try to skip initializa tion /** construct image of size width*height and try to skip initializa tion
of the memory (see BasicImage::resize for details). of the memory (see BasicImage::resize for details).
Use the specified allocator. Use the specified allocator.
*/ */
BasicImage(int width, int height, SkipInitializationTag, Alloc const & alloc = Alloc()) BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, SkipInitializat ionTag, Alloc const & alloc = Alloc())
: data_(0), : data_(0),
width_(0), width_(0),
height_(0), height_(0),
allocator_(alloc), allocator_(alloc),
pallocator_(alloc) pallocator_(alloc)
{ {
vigra_precondition((width >= 0) && (height >= 0), vigra_precondition((width >= 0) && (height >= 0),
"BasicImage::BasicImage(int width, int height, value_type cons t & ): " "BasicImage::BasicImage(int width, int height, value_type cons t & ): "
"width and height must be >= 0.\n"); "width and height must be >= 0.\n");
skipping to change at line 706 skipping to change at line 706
vigra_precondition((size.x >= 0) && (size.y >= 0), vigra_precondition((size.x >= 0) && (size.y >= 0),
"BasicImage::BasicImage(Diff2D const & size, value_type const & v): " "BasicImage::BasicImage(Diff2D const & size, value_type const & v): "
"size.x and size.y must be >= 0.\n"); "size.x and size.y must be >= 0.\n");
resize(size.x, size.y, SkipInitialization); resize(size.x, size.y, SkipInitialization);
} }
/** construct image of size width*height and copy the data from the /** construct image of size width*height and copy the data from the
given C-style array \a d. Use the specified allocator. given C-style array \a d. Use the specified allocator.
*/ */
BasicImage(int width, int height, const_pointer d, Alloc const & alloc = Alloc()) BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, const_pointer d , Alloc const & alloc = Alloc())
: data_(0), : data_(0),
width_(0), width_(0),
height_(0), height_(0),
allocator_(alloc), allocator_(alloc),
pallocator_(alloc) pallocator_(alloc)
{ {
vigra_precondition((width >= 0) && (height >= 0), vigra_precondition((width >= 0) && (height >= 0),
"BasicImage::BasicImage(int width, int height, const_pointer ) : " "BasicImage::BasicImage(int width, int height, const_pointer ) : "
"width and height must be >= 0.\n"); "width and height must be >= 0.\n");
skipping to change at line 771 skipping to change at line 771
*/ */
BasicImage & operator=(value_type pixel); BasicImage & operator=(value_type pixel);
/** set Image with const value /** set Image with const value
*/ */
BasicImage & init(value_type const & pixel); BasicImage & init(value_type const & pixel);
/** reset image to specified size (dimensions must not be negative) /** reset image to specified size (dimensions must not be negative)
(old data are kept if new size matches old size) (old data are kept if new size matches old size)
*/ */
void resize(int width, int height) void resize(std::ptrdiff_t width, std::ptrdiff_t height)
{ {
if(width != width_ || height != height_) if(width != width_ || height != height_)
resize(width, height, value_type()); resize(width, height, value_type());
} }
/** reset image to specified size (dimensions must not be negative) /** reset image to specified size (dimensions must not be negative)
(old data are kept if new size matches old size) (old data are kept if new size matches old size)
*/ */
void resize(difference_type const & size) void resize(difference_type const & size)
{ {
skipping to change at line 793 skipping to change at line 793
{ {
resize(size.x, size.y, value_type()); resize(size.x, size.y, value_type());
} }
} }
/** reset image to specified size and initialize it with /** reset image to specified size and initialize it with
given data (use this if value_type doesn't have a default given data (use this if value_type doesn't have a default
constructor, dimensions must not be negative, constructor, dimensions must not be negative,
old data are kept if new size matches old size) old data are kept if new size matches old size)
*/ */
void resize(int width, int height, value_type const & d) void resize(std::ptrdiff_t width, std::ptrdiff_t height, value_type con st & d)
{ {
resizeImpl(width, height, d, false); resizeImpl(width, height, d, false);
} }
/** reset image to specified size and skip initialization /** reset image to specified size and skip initialization
if possible (use this if <tt>value_type</tt> is a built-in type if possible (use this if <tt>value_type</tt> is a built-in type
or <tt>TinyVector&lt;builtin&gt&</tt> and the data is or <tt>TinyVector&lt;builtin&gt&</tt> and the data is
immediately overridden afterwards). If <tt>value_type</tt> requ ires immediately overridden afterwards). If <tt>value_type</tt> requ ires
initialization, <tt>SkipInitialization</tt> is ignored. initialization, <tt>SkipInitialization</tt> is ignored.
Usage: Usage:
\code \code
image.resize(new_width, new_height, SkipInitialization); image.resize(new_width, new_height, SkipInitialization);
\endcode \endcode
*/ */
void resize(int width, int height, SkipInitializationTag) void resize(std::ptrdiff_t width, std::ptrdiff_t height, SkipInitializa tionTag)
{ {
resizeImpl(width, height, NumericTraits<value_type>::zero(), resizeImpl(width, height, NumericTraits<value_type>::zero(),
CanSkipInitialization<value_type>::value); CanSkipInitialization<value_type>::value);
} }
/** resize image to given size and initialize by copying data /** resize image to given size and initialize by copying data
from the C-style array \a data. from the C-style array \a data.
*/ */
void resizeCopy(int width, int height, const_pointer data); void resizeCopy(std::ptrdiff_t width, std::ptrdiff_t height, const_poin ter data);
/** resize image to size of other image and copy its data /** resize image to size of other image and copy its data
*/ */
void resizeCopy(const BasicImage & rhs) void resizeCopy(const BasicImage & rhs)
{ {
resizeCopy(rhs.width(), rhs.height(), rhs.data_); resizeCopy(rhs.width(), rhs.height(), rhs.data_);
} }
/** swap the internal data with the rhs image in constant time /** swap the internal data with the rhs image in constant time
*/ */
void swap( BasicImage & rhs ); void swap( BasicImage & rhs );
/** width of Image /** width of Image
*/ */
int width() const std::ptrdiff_t width() const
{ {
return width_; return width_;
} }
/** height of Image /** height of Image
*/ */
int height() const std::ptrdiff_t height() const
{ {
return height_; return height_;
} }
/** size of Image /** size of Image
*/ */
size_type size() const size_type size() const
{ {
return size_type(width(), height()); return size_type(width(), height());
} }
skipping to change at line 881 skipping to change at line 881
*/ */
const_reference operator[](difference_type const & d) const const_reference operator[](difference_type const & d) const
{ {
VIGRA_ASSERT_INSIDE(d); VIGRA_ASSERT_INSIDE(d);
return lines_[d.y][d.x]; return lines_[d.y][d.x];
} }
/** access pixel at given location. <br> /** access pixel at given location. <br>
usage: <TT> value_type value = image(1,2) </TT> usage: <TT> value_type value = image(1,2) </TT>
*/ */
reference operator()(int dx, int dy) reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy)
{ {
VIGRA_ASSERT_INSIDE(difference_type(dx,dy)); VIGRA_ASSERT_INSIDE(difference_type(dx,dy));
return lines_[dy][dx]; return lines_[dy][dx];
} }
/** read pixel at given location. <br> /** read pixel at given location. <br>
usage: <TT> value_type value = image(1,2) </TT> usage: <TT> value_type value = image(1,2) </TT>
*/ */
const_reference operator()(int dx, int dy) const const_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(dx,dy)); VIGRA_ASSERT_INSIDE(difference_type(dx,dy));
return lines_[dy][dx]; return lines_[dy][dx];
} }
/** access pixel at given location. /** access pixel at given location.
Note that the 'x' index is the trailing index. <br> Note that the 'x' index is the trailing index. <br>
usage: <TT> value_type value = image[2][1] </TT> usage: <TT> value_type value = image[2][1] </TT>
*/ */
pointer operator[](int dy) pointer operator[](std::ptrdiff_t dy)
{ {
VIGRA_ASSERT_INSIDE(difference_type(0,dy)); VIGRA_ASSERT_INSIDE(difference_type(0,dy));
return lines_[dy]; return lines_[dy];
} }
/** read pixel at given location. /** read pixel at given location.
Note that the 'x' index is the trailing index. <br> Note that the 'x' index is the trailing index. <br>
usage: <TT> value_type value = image[2][1] </TT> usage: <TT> value_type value = image[2][1] </TT>
*/ */
const_pointer operator[](int dy) const const_pointer operator[](std::ptrdiff_t dy) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(0,dy)); VIGRA_ASSERT_INSIDE(difference_type(0,dy));
return lines_[dy]; return lines_[dy];
} }
/** init 2D random access iterator pointing to upper left pixel /** init 2D random access iterator pointing to upper left pixel
*/ */
traverser upperLeft() traverser upperLeft()
{ {
vigra_precondition(data_ != 0, vigra_precondition(data_ != 0,
skipping to change at line 994 skipping to change at line 994
*/ */
const_iterator end() const const_iterator end() const
{ {
vigra_precondition(data_ != 0, vigra_precondition(data_ != 0,
"BasicImage::end(): image must have non-zero size."); "BasicImage::end(): image must have non-zero size.");
return data_ + width() * height(); return data_ + width() * height();
} }
/** init 1D random access iterator pointing to first pixel of row \ a y /** init 1D random access iterator pointing to first pixel of row \ a y
*/ */
row_iterator rowBegin(int y) row_iterator rowBegin(std::ptrdiff_t y)
{ {
return lines_[y]; return lines_[y];
} }
/** init 1D random access iterator pointing past the end of row \a y /** init 1D random access iterator pointing past the end of row \a y
*/ */
row_iterator rowEnd(int y) row_iterator rowEnd(std::ptrdiff_t y)
{ {
return rowBegin(y) + width(); return rowBegin(y) + width();
} }
/** init 1D random access const iterator pointing to first pixel of row \a y /** init 1D random access const iterator pointing to first pixel of row \a y
*/ */
const_row_iterator rowBegin(int y) const const_row_iterator rowBegin(std::ptrdiff_t y) const
{ {
return lines_[y]; return lines_[y];
} }
/** init 1D random access const iterator pointing past the end of r ow \a y /** init 1D random access const iterator pointing past the end of r ow \a y
*/ */
const_row_iterator rowEnd(int y) const const_row_iterator rowEnd(std::ptrdiff_t y) const
{ {
return rowBegin(y) + width(); return rowBegin(y) + width();
} }
/** init 1D random access iterator pointing to first pixel of colum n \a x /** init 1D random access iterator pointing to first pixel of colum n \a x
*/ */
column_iterator columnBegin(int x) column_iterator columnBegin(std::ptrdiff_t x)
{ {
typedef typename column_iterator::BaseType Iter; typedef typename column_iterator::BaseType Iter;
return column_iterator(Iter(lines_, x)); return column_iterator(Iter(lines_, x));
} }
/** init 1D random access iterator pointing past the end of column \a x /** init 1D random access iterator pointing past the end of column \a x
*/ */
column_iterator columnEnd(int x) column_iterator columnEnd(std::ptrdiff_t x)
{ {
return columnBegin(x) + height(); return columnBegin(x) + height();
} }
/** init 1D random access const iterator pointing to first pixel of column \a x /** init 1D random access const iterator pointing to first pixel of column \a x
*/ */
const_column_iterator columnBegin(int x) const const_column_iterator columnBegin(std::ptrdiff_t x) const
{ {
typedef typename const_column_iterator::BaseType Iter; typedef typename const_column_iterator::BaseType Iter;
return const_column_iterator(Iter(lines_, x)); return const_column_iterator(Iter(lines_, x));
} }
/** init 1D random access const iterator pointing past the end of c olumn \a x /** init 1D random access const iterator pointing past the end of c olumn \a x
*/ */
const_column_iterator columnEnd(int x) const const_column_iterator columnEnd(std::ptrdiff_t x) const
{ {
return columnBegin(x) + height(); return columnBegin(x) + height();
} }
/** get a pointer to the internal data /** get a pointer to the internal data
*/ */
const_pointer data() const const_pointer data() const
{ {
return data_; return data_;
} }
skipping to change at line 1074 skipping to change at line 1074
/** return default const accessor /** return default const accessor
*/ */
ConstAccessor accessor() const ConstAccessor accessor() const
{ {
return ConstAccessor(); return ConstAccessor();
} }
private: private:
void deallocate(); void deallocate();
void resizeImpl(int width, int height, value_type const & d, bool skipI nit); void resizeImpl(std::ptrdiff_t width, std::ptrdiff_t height, value_type const & d, bool skipInit);
value_type ** initLineStartArray(value_type * data, int width, int heig ht); value_type ** initLineStartArray(value_type * data, std::ptrdiff_t widt h, std::ptrdiff_t height);
PIXELTYPE * data_; PIXELTYPE * data_;
PIXELTYPE ** lines_; PIXELTYPE ** lines_;
int width_, height_; std::ptrdiff_t width_, height_;
Alloc allocator_; Alloc allocator_;
LineAllocator pallocator_; LineAllocator pallocator_;
}; };
template <class PIXELTYPE, class Alloc> template <class PIXELTYPE, class Alloc>
BasicImage<PIXELTYPE, Alloc> & BasicImage<PIXELTYPE, Alloc> &
BasicImage<PIXELTYPE, Alloc>::operator=(const BasicImage & rhs) BasicImage<PIXELTYPE, Alloc>::operator=(const BasicImage & rhs)
{ {
if(this != &rhs) if(this != &rhs)
{ {
skipping to change at line 1134 skipping to change at line 1134
ScanOrderIterator i = begin(); ScanOrderIterator i = begin();
ScanOrderIterator iend = end(); ScanOrderIterator iend = end();
for(; i != iend; ++i) *i = pixel; for(; i != iend; ++i) *i = pixel;
return *this; return *this;
} }
template <class PIXELTYPE, class Alloc> template <class PIXELTYPE, class Alloc>
void void
BasicImage<PIXELTYPE, Alloc>::resizeImpl(int width, int height, value_type const & d, bool skipInit) BasicImage<PIXELTYPE, Alloc>::resizeImpl(std::ptrdiff_t width, std::ptrdiff _t height, value_type const & d, bool skipInit)
{ {
vigra_precondition((width >= 0) && (height >= 0), vigra_precondition((width >= 0) && (height >= 0),
"BasicImage::resize(int width, int height, value_type const &): " "BasicImage::resize(int width, int height, value_type const &): "
"width and height must be >= 0.\n"); "width and height must be >= 0.\n");
vigra_precondition(width * height >= 0, vigra_precondition(width * height >= 0,
"BasicImage::resize(int width, int height, value_type const &): " "BasicImage::resize(int width, int height, value_type const &): "
"width * height too large (integer overflow -> negative).\n"); "width * height too large (integer overflow -> negative).\n");
if (width_ != width || height_ != height) // change size? if (width_ != width || height_ != height) // change size?
{ {
skipping to change at line 1184 skipping to change at line 1184
height_ = height; height_ = height;
} }
else if(width*height > 0 && !skipInit) // keep size, re-init data else if(width*height > 0 && !skipInit) // keep size, re-init data
{ {
std::fill_n(data_, width*height, d); std::fill_n(data_, width*height, d);
} }
} }
template <class PIXELTYPE, class Alloc> template <class PIXELTYPE, class Alloc>
void void
BasicImage<PIXELTYPE, Alloc>::resizeCopy(int width, int height, const_point er data) BasicImage<PIXELTYPE, Alloc>::resizeCopy(std::ptrdiff_t width, std::ptrdiff _t height, const_pointer data)
{ {
int newsize = width*height; std::ptrdiff_t newsize = width*height;
if (width_ != width || height_ != height) // change size? if (width_ != width || height_ != height) // change size?
{ {
value_type * newdata = 0; value_type * newdata = 0;
value_type ** newlines = 0; value_type ** newlines = 0;
if(newsize > 0) if(newsize > 0)
{ {
if (newsize != width_*height_) // different sizes, must realloc ate if (newsize != width_*height_) // different sizes, must realloc ate
{ {
newdata = allocator_.allocate(typename Alloc::size_type(new size)); newdata = allocator_.allocate(typename Alloc::size_type(new size));
std::uninitialized_copy(data, data + newsize, newdata); std::uninitialized_copy(data, data + newsize, newdata);
skipping to change at line 1255 skipping to change at line 1255
for(; i != iend; ++i) (*i).~PIXELTYPE(); for(; i != iend; ++i) (*i).~PIXELTYPE();
allocator_.deallocate(data_, typename Alloc::size_type(width()*heig ht())); allocator_.deallocate(data_, typename Alloc::size_type(width()*heig ht()));
pallocator_.deallocate(lines_, typename Alloc::size_type(height_)); pallocator_.deallocate(lines_, typename Alloc::size_type(height_));
} }
} }
template <class PIXELTYPE, class Alloc> template <class PIXELTYPE, class Alloc>
PIXELTYPE ** PIXELTYPE **
BasicImage<PIXELTYPE, Alloc>::initLineStartArray(value_type * data, int wid th, int height) BasicImage<PIXELTYPE, Alloc>::initLineStartArray(value_type * data, std::pt rdiff_t width, std::ptrdiff_t height)
{ {
value_type ** lines = pallocator_.allocate(typename Alloc::size_type(he ight)); value_type ** lines = pallocator_.allocate(typename Alloc::size_type(he ight));
for(int y=0; y<height; ++y) for(std::ptrdiff_t y=0; y<height; ++y)
lines[y] = data + y*width; lines[y] = data + y*width;
return lines; return lines;
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* argument object factories */ /* argument object factories */
/* */ /* */
/********************************************************/ /********************************************************/
 End of changes. 39 change blocks. 
39 lines changed or deleted 39 lines changed or added


 basicimageview.hxx   basicimageview.hxx 
skipping to change at line 68 skipping to change at line 68
/** \brief BasicImage using foreign memory. /** \brief BasicImage using foreign memory.
This class provides the same interface as \ref vigra::BasicImage This class provides the same interface as \ref vigra::BasicImage
(with the exception of <tt>resize()</tt>) but the image's (with the exception of <tt>resize()</tt>) but the image's
memory is provided from the outside instead of allocated internally. memory is provided from the outside instead of allocated internally.
A <tt>BasicImageView</tt> can also be created from a A <tt>BasicImageView</tt> can also be created from a
\ref vigra::MultiArrayView with the appropriate shape -- see \ref vigra::MultiArrayView with the appropriate shape -- see
\ref MultiArrayToImage. \ref MultiArrayToImage.
<b>\#include</b> \<vigra/basicimageview.hxx\> <b>\#include</b> \<vigra/basicimageview.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE> template <class PIXELTYPE>
class BasicImageView class BasicImageView
{ {
public: public:
/** the BasicImageView's pixel type /** the BasicImageView's pixel type
*/ */
typedef PIXELTYPE value_type; typedef PIXELTYPE value_type;
skipping to change at line 184 skipping to change at line 183
*/ */
BasicImageView() BasicImageView()
: data_(0), : data_(0),
width_(0), width_(0),
height_(0), height_(0),
stride_(0) stride_(0)
{} {}
/** construct view of size w x h /** construct view of size w x h
*/ */
BasicImageView(const_pointer data, int w, int h, int stride = 0) BasicImageView(const_pointer data, std::ptrdiff_t w, std::ptrdiff_t h, std::ptrdiff_t stride = 0)
: data_(const_cast<pointer>(data)), : data_(const_cast<pointer>(data)),
width_(w), width_(w),
height_(h), height_(h),
stride_(stride == 0 ? w : stride) stride_(stride == 0 ? w : stride)
{} {}
/** construct view of size size.x x size.y /** construct view of size size.x x size.y
*/ */
BasicImageView(const_pointer data, difference_type const & size, int st ride = 0) BasicImageView(const_pointer data, difference_type const & size, std::p trdiff_t stride = 0)
: data_(const_cast<pointer>(data)), : data_(const_cast<pointer>(data)),
width_(size.x), width_(size.x),
height_(size.y), height_(size.y),
stride_(stride == 0 ? size.x : stride) stride_(stride == 0 ? size.x : stride)
{} {}
/** set Image with const value /** set Image with const value
*/ */
BasicImageView & init(value_type const & pixel) BasicImageView & init(value_type const & pixel)
{ {
initImage(upperLeft(), lowerRight(), accessor(), pixel); initImage(upperLeft(), lowerRight(), accessor(), pixel);
return *this; return *this;
} }
/** width of Image /** width of Image
*/ */
int width() const std::ptrdiff_t width() const
{ {
return width_; return width_;
} }
/** height of Image /** height of Image
*/ */
int height() const std::ptrdiff_t height() const
{ {
return height_; return height_;
} }
/** stride of Image. /** stride of Image.
Memory offset between the start of two successive rows. Memory offset between the start of two successive rows.
*/ */
int stride() const std::ptrdiff_t stride() const
{ {
return stride_; return stride_;
} }
/** size of Image /** size of Image
*/ */
size_type size() const size_type size() const
{ {
return size_type(width(), height()); return size_type(width(), height());
} }
skipping to change at line 267 skipping to change at line 266
*/ */
const_reference operator[](difference_type const & d) const const_reference operator[](difference_type const & d) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(d)); VIGRA_ASSERT_INSIDE(difference_type(d));
return data_[d.y*stride_ + d.x]; return data_[d.y*stride_ + d.x];
} }
/** access pixel at given location. <br> /** access pixel at given location. <br>
usage: <TT> value_type value = image(1,2) </TT> usage: <TT> value_type value = image(1,2) </TT>
*/ */
reference operator()(int dx, int dy) reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy)
{ {
VIGRA_ASSERT_INSIDE(difference_type(dx,dy)); VIGRA_ASSERT_INSIDE(difference_type(dx,dy));
return data_[dy*stride_ + dx]; return data_[dy*stride_ + dx];
} }
/** read pixel at given location. <br> /** read pixel at given location. <br>
usage: <TT> value_type value = image(1,2) </TT> usage: <TT> value_type value = image(1,2) </TT>
*/ */
const_reference operator()(int dx, int dy) const const_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(dx, dy)); VIGRA_ASSERT_INSIDE(difference_type(dx, dy));
return data_[dy*stride_ + dx]; return data_[dy*stride_ + dx];
} }
/** access pixel at given location. /** access pixel at given location.
Note that the 'x' index is the trailing index. <br> Note that the 'x' index is the trailing index. <br>
usage: <TT> value_type value = image[2][1] </TT> usage: <TT> value_type value = image[2][1] </TT>
*/ */
pointer operator[](int dy) pointer operator[](std::ptrdiff_t dy)
{ {
VIGRA_ASSERT_INSIDE(difference_type(0, dy)); VIGRA_ASSERT_INSIDE(difference_type(0, dy));
return data_ + dy*stride_; return data_ + dy*stride_;
} }
/** read pixel at given location. /** read pixel at given location.
Note that the 'x' index is the trailing index. <br> Note that the 'x' index is the trailing index. <br>
usage: <TT> value_type value = image[2][1] </TT> usage: <TT> value_type value = image[2][1] </TT>
*/ */
const_pointer operator[](int dy) const const_pointer operator[](std::ptrdiff_t dy) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(0,dy)); VIGRA_ASSERT_INSIDE(difference_type(0,dy));
return data_ + dy*stride_; return data_ + dy*stride_;
} }
/** init 2D random access iterator pointing to upper left pixel /** init 2D random access iterator pointing to upper left pixel
*/ */
traverser upperLeft() traverser upperLeft()
{ {
return traverser(data_, stride_); return traverser(data_, stride_);
skipping to change at line 380 skipping to change at line 379
const_iterator end() const const_iterator end() const
{ {
vigra_precondition(stride_ == width_, vigra_precondition(stride_ == width_,
"BasicImageView::end(): " "BasicImageView::end(): "
"can only create scan order iterator if width() == stride()."); "can only create scan order iterator if width() == stride().");
return data_ + width() * height(); return data_ + width() * height();
} }
/** init 1D random access iterator pointing to first pixel of row \ a y /** init 1D random access iterator pointing to first pixel of row \ a y
*/ */
row_iterator rowBegin(int y) row_iterator rowBegin(std::ptrdiff_t y)
{ {
return data_ + stride_ * y; return data_ + stride_ * y;
} }
/** init 1D random access iterator pointing past the end of row \a y /** init 1D random access iterator pointing past the end of row \a y
*/ */
row_iterator rowEnd(int y) row_iterator rowEnd(std::ptrdiff_t y)
{ {
return rowBegin(y) + width(); return rowBegin(y) + width();
} }
/** init 1D random access const iterator pointing to first pixel of row \a y /** init 1D random access const iterator pointing to first pixel of row \a y
*/ */
const_row_iterator rowBegin(int y) const const_row_iterator rowBegin(std::ptrdiff_t y) const
{ {
return data_ + stride_ * y; return data_ + stride_ * y;
} }
/** init 1D random access const iterator pointing past the end of r ow \a y /** init 1D random access const iterator pointing past the end of r ow \a y
*/ */
const_row_iterator rowEnd(int y) const const_row_iterator rowEnd(std::ptrdiff_t y) const
{ {
return rowBegin(y) + width(); return rowBegin(y) + width();
} }
/** init 1D random access iterator pointing to first pixel of colum n \a x /** init 1D random access iterator pointing to first pixel of colum n \a x
*/ */
column_iterator columnBegin(int x) column_iterator columnBegin(std::ptrdiff_t x)
{ {
typedef typename column_iterator::BaseType Iter; typedef typename column_iterator::BaseType Iter;
return column_iterator(Iter(data_ + x, stride_)); return column_iterator(Iter(data_ + x, stride_));
} }
/** init 1D random access iterator pointing past the end of column \a x /** init 1D random access iterator pointing past the end of column \a x
*/ */
column_iterator columnEnd(int x) column_iterator columnEnd(std::ptrdiff_t x)
{ {
return columnBegin(x) + height(); return columnBegin(x) + height();
} }
/** init 1D random access const iterator pointing to first pixel of column \a x /** init 1D random access const iterator pointing to first pixel of column \a x
*/ */
const_column_iterator columnBegin(int x) const const_column_iterator columnBegin(std::ptrdiff_t x) const
{ {
typedef typename const_column_iterator::BaseType Iter; typedef typename const_column_iterator::BaseType Iter;
return const_column_iterator(Iter(data_ + x, stride_)); return const_column_iterator(Iter(data_ + x, stride_));
} }
/** init 1D random access const iterator pointing past the end of c olumn \a x /** init 1D random access const iterator pointing past the end of c olumn \a x
*/ */
const_column_iterator columnEnd(int x) const const_column_iterator columnEnd(std::ptrdiff_t x) const
{ {
return columnBegin(x) + height(); return columnBegin(x) + height();
} }
/** get a pointer to the internal data /** get a pointer to the internal data
*/ */
const_pointer data() const const_pointer data() const
{ {
return data_; return data_;
} }
skipping to change at line 460 skipping to change at line 459
/** return default const accessor /** return default const accessor
*/ */
ConstAccessor accessor() const ConstAccessor accessor() const
{ {
return ConstAccessor(); return ConstAccessor();
} }
private: private:
pointer data_; pointer data_;
int width_, height_, stride_; std::ptrdiff_t width_, height_, stride_;
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* argument object factories */ /* argument object factories */
/* */ /* */
/********************************************************/ /********************************************************/
template <class PixelType, class Accessor> template <class PixelType, class Accessor>
inline triple<typename BasicImageView<PixelType>::const_traverser, inline triple<typename BasicImageView<PixelType>::const_traverser,
 End of changes. 19 change blocks. 
20 lines changed or deleted 19 lines changed or added


 bessel.hxx   bessel.hxx 
skipping to change at line 138 skipping to change at line 138
// relations. If 'nm' < 'n' only 'nm' orders are returned. // relations. If 'nm' < 'n' only 'nm' orders are returned.
// //
// code has been adapted from C.R. Bond's implementation // code has been adapted from C.R. Bond's implementation
// see http://www.crbond.com/math.htm // see http://www.crbond.com/math.htm
// //
template <class REAL> template <class REAL>
void bessjyn(int n, REAL x,int &nm, double *jn, double *yn) void bessjyn(int n, REAL x,int &nm, double *jn, double *yn)
{ {
double t1,t2,f,f1,f2,bj0,bj1,bjk,by0,by1,cu,s0,su,sv; double t1,t2,f,f1,f2,bj0,bj1,bjk,by0,by1,cu,s0,su,sv;
double ec,bs,byk,p0,p1,q0,q1; double ec,bs,byk,p0,p1,q0,q1;
static double a[] = { double a[] = {
-0.7031250000000000e-1, -0.7031250000000000e-1,
0.1121520996093750, 0.1121520996093750,
-0.5725014209747314, -0.5725014209747314,
6.074042001273483}; 6.074042001273483};
static double b[] = { double b[] = {
0.7324218750000000e-1, 0.7324218750000000e-1,
-0.2271080017089844, -0.2271080017089844,
1.727727502584457, 1.727727502584457,
-2.438052969955606e1}; -2.438052969955606e1};
static double a1[] = { double a1[] = {
0.1171875, 0.1171875,
-0.1441955566406250, -0.1441955566406250,
0.6765925884246826, 0.6765925884246826,
-6.883914268109947}; -6.883914268109947};
static double b1[] = { double b1[] = {
-0.1025390625, -0.1025390625,
0.2775764465332031, 0.2775764465332031,
-1.993531733751297, -1.993531733751297,
2.724882731126854e1}; 2.724882731126854e1};
int i,k,m; int i,k,m;
nm = n; nm = n;
if (x < 1e-15) if (x < 1e-15)
{ {
for (i=0;i<=n;i++) for (i=0;i<=n;i++)
skipping to change at line 259 skipping to change at line 259
{ {
byk = 2.0*(k-1.0)*by1/x-by0; byk = 2.0*(k-1.0)*by1/x-by0;
yn[k] = byk; yn[k] = byk;
by0 = by1; by0 = by1;
by1 = byk; by1 = byk;
} }
} }
} // namespace detail } // namespace detail
/*! Bessel function of the first kind. /** \brief Bessel function of the first kind.
Computes the value of BesselJ of integer order <tt>n</tt> and argum ent <tt>x</tt>. Computes the value of BesselJ of integer order <tt>n</tt> and argum ent <tt>x</tt>.
Negative <tt>x</tt> are unsupported and will result in a <tt>std::d omain_error</tt>. Negative <tt>x</tt> are unsupported and will result in a <tt>std::d omain_error</tt>.
This function wraps a number of existing implementations and falls back to This function wraps a number of existing implementations and falls back to
a rather slow algorithm if none of them is available. In particular , a rather slow algorithm if none of them is available. In particular ,
it uses boost::math when <tt>HasBoostMath</tt> is \#defined, or nat ive it uses boost::math when <tt>HasBoostMath</tt> is \#defined, or nat ive
implementations on gcc and MSVC otherwise. implementations on gcc and MSVC otherwise.
<b>\#include</b> \<vigra/bessel.hxx\><br> <b>\#include</b> \<vigra/bessel.hxx\><br>
skipping to change at line 295 skipping to change at line 295
int an = abs(n), nr = n, s = an+2; int an = abs(n), nr = n, s = an+2;
ArrayVector<double> t(2*s); ArrayVector<double> t(2*s);
detail::bessjyn(an, x, nr, &t[0], &t[s]); detail::bessjyn(an, x, nr, &t[0], &t[s]);
if(n < 0 && odd(an)) if(n < 0 && odd(an))
return -t[an]; return -t[an];
else else
return t[an]; return t[an];
#endif #endif
} }
/*! Bessel function of the second kind. /** \brief Bessel function of the second kind.
Computes the value of BesselY of integer order <tt>n</tt> and argum ent <tt>x</tt>. Computes the value of BesselY of integer order <tt>n</tt> and argum ent <tt>x</tt>.
Negative <tt>x</tt> are unsupported and will result in a <tt>std::d omain_error</tt>. Negative <tt>x</tt> are unsupported and will result in a <tt>std::d omain_error</tt>.
This function wraps a number of existing implementations and falls back to This function wraps a number of existing implementations and falls back to
a rather slow algorithm if none of them is available. In particular , a rather slow algorithm if none of them is available. In particular ,
it uses boost::math when <tt>HasBoostMath</tt> is \#defined, or nat ive it uses boost::math when <tt>HasBoostMath</tt> is \#defined, or nat ive
implementations on gcc and MSVC otherwise. implementations on gcc and MSVC otherwise.
<b>\#include</b> \<vigra/bessel.hxx\><br> <b>\#include</b> \<vigra/bessel.hxx\><br>
 End of changes. 6 change blocks. 
6 lines changed or deleted 6 lines changed or added


 bordertreatment.hxx   bordertreatment.hxx 
skipping to change at line 41 skipping to change at line 41
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_BORDERTREATMENT_HXX #ifndef VIGRA_BORDERTREATMENT_HXX
#define VIGRA_BORDERTREATMENT_HXX #define VIGRA_BORDERTREATMENT_HXX
namespace vigra { namespace vigra {
/*! \page BorderTreatmentMode BorderTreatmentMode /** \page BorderTreatmentMode BorderTreatmentMode
Choose between different border treatment modes. In the convolution Choose between different border treatment modes. In the convolution
algorithms, these modes apply to algorithms, these modes apply to
all image pixels where the kernel does not completely fit inside all image pixels where the kernel does not completely fit inside
the image. the image.
<b>\#include</b> \<vigra/bordertreatment.hxx\><br> <b>\#include</b> \<vigra/bordertreatment.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 boundarytensor.hxx   boundarytensor.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_BOUNDARYTENSOR_HXX #define VIGRA_BOUNDARYTENSOR_HXX
#include <cmath> #include <cmath>
#include <functional> #include <functional>
#include "utilities.hxx" #include "utilities.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "basicimage.hxx" #include "basicimage.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "convolution.hxx" #include "convolution.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
/***********************************************************************/ /***********************************************************************/
typedef ArrayVector<Kernel1D<double> > KernelArray; typedef ArrayVector<Kernel1D<double> > KernelArray;
template <class KernelArray> template <class KernelArray>
skipping to change at line 383 skipping to change at line 384
\f] \f]
where <i>n</i> = <tt>xorder</tt> and <i>m</i> = <tt>yorder</tt> determi ne th e where <i>n</i> = <tt>xorder</tt> and <i>m</i> = <tt>yorder</tt> determi ne th e
order of the transform, and <tt>sigma > 0</tt> is the scale of the Lapl acian order of the transform, and <tt>sigma > 0</tt> is the scale of the Lapl acian
of Gaussian. This function computes a good spatial domain approximation of of Gaussian. This function computes a good spatial domain approximation of
these transforms for <tt>xorder + yorder <= 2</tt>. The filter response s may be used these transforms for <tt>xorder + yorder <= 2</tt>. The filter response s may be used
to calculate the monogenic signal or the boundary tensor. to calculate the monogenic signal or the boundary tensor.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
rieszTransformOfLOG(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale, unsigned int xorder, unsigned int
yorder);
}
\endcode
\deprecatedAPI{rieszTransformOfLOG}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void rieszTransformOfLOG(SrcIterator supperleft, SrcIterator slower right, SrcAccessor src, void rieszTransformOfLOG(SrcIterator supperleft, SrcIterator slower right, SrcAccessor src,
DestIterator dupperleft, DestAccessor dest , DestIterator dupperleft, DestAccessor dest ,
double scale, unsigned int xorder, unsigne d int yorder); double scale, unsigned int xorder, unsigne d int yorder);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void rieszTransformOfLOG(triple<SrcIterator, SrcIterator, SrcAccess or> src, void rieszTransformOfLOG(triple<SrcIterator, SrcIterator, SrcAccess or> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, unsigned int xorder, unsigne d int yorder); double scale, unsigned int xorder, unsigne d int yorder);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/boundarytensor.hxx\> <b>\#include</b> \<vigra/boundarytensor.hxx\><br>
Namespace: vigra
\code \code
FImage impulse(17,17), res(17, 17); MultiArrayView<2, double> impulse(17,17), res(17, 17);
impulse(8,8) = 1.0; impulse(8,8) = 1.0;
// calculate the impulse response of the first order Riesz transform in x-direction // calculate the impulse response of the first order Riesz transform in x-direction
rieszTransformOfLOG(srcImageRange(impulse), destImage(res), 2.0, 1, 0); rieszTransformOfLOG(impulse, res, 2.0, 1, 0);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void rieszTransformOfLOG) doxygen_overloaded_function(template <...> void rieszTransformOfLOG)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void rieszTransformOfLOG(SrcIterator supperleft, SrcIterator slowerright, S rcAccessor src, void rieszTransformOfLOG(SrcIterator supperleft, SrcIterator slowerright, S rcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale, unsigned int xorder, unsigned int yo rder) double scale, unsigned int xorder, unsigned int yo rder)
{ {
unsigned int order = xorder + yorder; unsigned int order = xorder + yorder;
skipping to change at line 529 skipping to change at line 543
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void rieszTransformOfLOG(triple<SrcIterator, SrcIterator, SrcAccessor> src, void rieszTransformOfLOG(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, unsigned int xorder, unsigned int yo rder) double scale, unsigned int xorder, unsigned int yo rder)
{ {
rieszTransformOfLOG(src.first, src.second, src.third, dest.first, dest. second, rieszTransformOfLOG(src.first, src.second, src.third, dest.first, dest. second,
scale, xorder, yorder); scale, xorder, yorder);
} }
template <class T1, class S1,
class T2, class S2>
inline void
rieszTransformOfLOG(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale, unsigned int xorder, unsigned int yorder)
{
vigra_precondition(src.shape() == dest.shape(),
"rieszTransformOfLOG(): shape mismatch between input and output.");
rieszTransformOfLOG(srcImageRange(src), destImage(dest),
scale, xorder, yorder);
}
//@} //@}
/** \addtogroup TensorImaging Tensor Image Processing /** \addtogroup TensorImaging Tensor Image Processing
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* boundaryTensor */ /* boundaryTensor */
/* */ /* */
skipping to change at line 560 skipping to change at line 588
with the Laplacian of Gaussian as the underlying bandpass filter (see with the Laplacian of Gaussian as the underlying bandpass filter (see
\ref rieszTransformOfLOG()). The output image must have 3 bands which w ill hold the \ref rieszTransformOfLOG()). The output image must have 3 bands which w ill hold the
tensor components in the order t11, t12 (== t21), t22. The function tensor components in the order t11, t12 (== t21), t22. The function
\ref boundaryTensor1() with the same interface implements a variant of the \ref boundaryTensor1() with the same interface implements a variant of the
boundary tensor where the 0th-order Riesz transform has been dropped, s o that the boundary tensor where the 0th-order Riesz transform has been dropped, s o that the
tensor is no longer sensitive to blobs. tensor is no longer sensitive to blobs.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
boundaryTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{boundaryTensor}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void boundaryTensor(SrcIterator supperleft, SrcIterator slowerright , SrcAccessor src, void boundaryTensor(SrcIterator supperleft, SrcIterator slowerright , SrcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale); double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void boundaryTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, void boundaryTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale); double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/boundarytensor.hxx\> <b>\#include</b> \<vigra/boundarytensor.hxx\><br/>
Namespace: vigra
\code \code
FImage img(w,h); MultiArray<2, float> img(w,h);
FVector3Image bt(w,h); MultiArray<2, TinyVector<float, 3> bt(w,h);
... ...
boundaryTensor(srcImageRange(img), destImage(bt), 2.0); boundaryTensor(img, bt, 2.0);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void boundaryTensor) doxygen_overloaded_function(template <...> void boundaryTensor)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void boundaryTensor(SrcIterator supperleft, SrcIterator slowerright, SrcAcc essor src, void boundaryTensor(SrcIterator supperleft, SrcIterator slowerright, SrcAcc essor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale) double scale)
{ {
vigra_precondition(dest.size(dupperleft) == 3, vigra_precondition(dest.size(dupperleft) == 3,
skipping to change at line 624 skipping to change at line 665
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void boundaryTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src, void boundaryTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
{ {
boundaryTensor(src.first, src.second, src.third, boundaryTensor(src.first, src.second, src.third,
dest.first, dest.second, scale); dest.first, dest.second, scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
boundaryTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"boundaryTensor(): shape mismatch between input and output.");
boundaryTensor(srcImageRange(src),
destImage(dest), scale);
}
/** \brief Boundary tensor variant. /** \brief Boundary tensor variant.
This function implements a variant of the boundary tensor where the This function implements a variant of the boundary tensor where the
0th-order Riesz transform has been dropped, so that the tensor is no 0th-order Riesz transform has been dropped, so that the tensor is no
longer sensitive to blobs. See \ref boundaryTensor() for more detailed longer sensitive to blobs. See \ref boundaryTensor() for more detailed
documentation. documentation.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/boundarytensor.hxx\> <b>\#include</b> \<vigra/boundarytensor.hxx\><br/>
Namespace: vigra
pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
boundaryTensor1(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
pass arguments explicitly: \deprecatedAPI{boundaryTensor1}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void boundaryTensor1(SrcIterator supperleft, SrcIterator slowerrigh t, SrcAccessor src, void boundaryTensor1(SrcIterator supperleft, SrcIterator slowerrigh t, SrcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale); double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void boundaryTensor1(triple<SrcIterator, SrcIterator, SrcAccessor> src, void boundaryTensor1(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale); double scale);
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void boundaryTensor1) doxygen_overloaded_function(template <...> void boundaryTensor1)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void boundaryTensor1(SrcIterator supperleft, SrcIterator slowerright, SrcAc cessor src, void boundaryTensor1(SrcIterator supperleft, SrcIterator slowerright, SrcAc cessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale) double scale)
{ {
vigra_precondition(dest.size(dupperleft) == 3, vigra_precondition(dest.size(dupperleft) == 3,
skipping to change at line 687 skipping to change at line 755
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void boundaryTensor1(triple<SrcIterator, SrcIterator, SrcAccessor> src, void boundaryTensor1(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
{ {
boundaryTensor1(src.first, src.second, src.third, boundaryTensor1(src.first, src.second, src.third,
dest.first, dest.second, scale); dest.first, dest.second, scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
boundaryTensor1(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"boundaryTensor1(): shape mismatch between input and output.");
boundaryTensor1(srcImageRange(src),
destImage(dest), scale);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* boundaryTensor3 */ /* boundaryTensor3 */
/* */ /* */
/********************************************************/ /********************************************************/
/* Add 3rd order Riesz transform to boundary tensor /* Add 3rd order Riesz transform to boundary tensor
??? Does not work -- bug or too coarse approximation for 3rd order ??? ??? Does not work -- bug or too coarse approximation for 3rd order ???
*/ */
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
skipping to change at line 795 skipping to change at line 876
inline inline
void boundaryTensor3(triple<SrcIterator, SrcIterator, SrcAccessor> src, void boundaryTensor3(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIteratorEven, DestAccessorEven> even, pair<DestIteratorEven, DestAccessorEven> even,
pair<DestIteratorOdd, DestAccessorOdd> odd, pair<DestIteratorOdd, DestAccessorOdd> odd,
double scale) double scale)
{ {
boundaryTensor3(src.first, src.second, src.third, boundaryTensor3(src.first, src.second, src.third,
even.first, even.second, odd.first, odd.second, scale); even.first, even.second, odd.first, odd.second, scale);
} }
template <class T1, class S1,
class T2E, class S2Even,
class T2O, class S2Odd>
inline
void boundaryTensor3(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2E, S2Even> even,
MultiArrayView<2, T2O, S2Odd> odd,
double scale)
{
vigra_precondition(src.shape() == even.shape() && src.shape() == odd.sh
ape(),
"boundaryTensor3(): shape mismatch between input and output.");
boundaryTensor3(srcImageRange(src),
destImage(even), destImage(odd), scale);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_BOUNDARYTENSOR_HXX #endif // VIGRA_BOUNDARYTENSOR_HXX
 End of changes. 23 change blocks. 
16 lines changed or deleted 114 lines changed or added


 box.hxx   box.hxx 
skipping to change at line 269 skipping to change at line 269
*/ */
void addBorder(VALUETYPE borderWidth) void addBorder(VALUETYPE borderWidth)
{ {
for(unsigned int i = 0; i < DIMENSION; ++i) for(unsigned int i = 0; i < DIMENSION; ++i)
{ {
begin_[i] -= borderWidth; begin_[i] -= borderWidth;
end_[i] += borderWidth; end_[i] += borderWidth;
} }
} }
/** Adds a border of the given width around the box. That
* means, begin()'s components are moved by -borderWidth
* and end()'s by borderWidth. (If borderWidth is
* negative, the box will get smaller accordingly.)
*/
void addBorder(const Vector & borderWidth)
{
begin_ -= borderWidth;
end_ += borderWidth;
}
/// equality check /// equality check
bool operator==(Box const &r) const bool operator==(Box const &r) const
{ {
return (begin_ == r.begin_) && (end_ == r.end_); return (begin_ == r.begin_) && (end_ == r.end_);
} }
/// inequality check /// inequality check
bool operator!=(Box const &r) const bool operator!=(Box const &r) const
{ {
return (begin_ != r.begin_) || (end_ != r.end_); return (begin_ != r.begin_) || (end_ != r.end_);
skipping to change at line 464 skipping to change at line 475
{ {
begin_ *= scale; begin_ *= scale;
end_ *= scale; end_ *= scale;
return *this; return *this;
} }
/** /**
* Return box scaled by given factor. The same scalar * Return box scaled by given factor. The same scalar
* multiplication will be performed on both begin() and end(). * multiplication will be performed on both begin() and end().
*/ */
Box operator*(double scale) Box operator*(double scale)const
{ {
Box result(*this); Box result(*this);
result *= scale; result *= scale;
return result; return result;
} }
/** /**
* Scale box by scalar divide-assignment. The same scalar * Scale box by scalar divide-assignment. The same scalar
* divide-assignment operation will be performed on both * divide-assignment operation will be performed on both
* begin() and end(). * begin() and end().
skipping to change at line 487 skipping to change at line 498
{ {
begin_ /= scale; begin_ /= scale;
end_ /= scale; end_ /= scale;
return *this; return *this;
} }
/** /**
* Return box scaled by inverse of given factor. The same scalar * Return box scaled by inverse of given factor. The same scalar
* division will be performed on both begin() and end(). * division will be performed on both begin() and end().
*/ */
Box operator/(double scale) Box operator/(double scale)const
{ {
Box result(*this); Box result(*this);
result /= scale; result /= scale;
return result; return result;
} }
/** /**
* Translate box by vector addition-assignment. The same vector * Translate box by vector addition-assignment. The same vector
* addition-assignment operation will be performed on both * addition-assignment operation will be performed on both
* begin() and end(). * begin() and end().
skipping to change at line 510 skipping to change at line 521
{ {
begin_ += offset; begin_ += offset;
end_ += offset; end_ += offset;
return *this; return *this;
} }
/** /**
* Translate box by vector addition. The same vector addition * Translate box by vector addition. The same vector addition
* operation will be performed on both begin() and end(). * operation will be performed on both begin() and end().
*/ */
Box operator+(const Vector &offset) Box operator+(const Vector &offset)const
{ {
Box result(*this); Box result(*this);
result += offset; result += offset;
return result; return result;
} }
/** /**
* Translate box by vector subtract-assignment. The same vector * Translate box by vector subtract-assignment. The same vector
* subtract-assignment operation will be performed on both * subtract-assignment operation will be performed on both
* begin() and end(). * begin() and end().
skipping to change at line 533 skipping to change at line 544
{ {
begin_ -= offset; begin_ -= offset;
end_ -= offset; end_ -= offset;
return *this; return *this;
} }
/** /**
* Translate box by vector subtract. The same vector subtract * Translate box by vector subtract. The same vector subtract
* operation will be performed on both begin() and end(). * operation will be performed on both begin() and end().
*/ */
Box operator-(const Vector &offset) Box operator-(const Vector &offset)const
{ {
Box result(*this); Box result(*this);
result -= offset; result -= offset;
return result; return result;
} }
}; };
template<class VALUETYPE, unsigned int DIMENSION>
std::ostream& operator<< (std::ostream& stream, const Box<VALUETYPE, DIMENS
ION> & box) {
stream<<"["<<box.begin()<<", "<<box.end()<<" ]";
return stream;
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_BOX_HXX #endif // VIGRA_BOX_HXX
 End of changes. 6 change blocks. 
4 lines changed or deleted 22 lines changed or added


 bucket_queue.hxx   bucket_queue.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_BUCKET_QUEUE_HXX #ifndef VIGRA_BUCKET_QUEUE_HXX
#define VIGRA_BUCKET_QUEUE_HXX #define VIGRA_BUCKET_QUEUE_HXX
#include "config.hxx" #include "priority_queue.hxx"
#include "error.hxx"
#include "array_vector.hxx"
#include <queue>
namespace vigra {
/** \brief Priority queue implemented using bucket sort.
This template implements functionality similar to <tt><a href="http://w
ww.sgi.com/tech/stl/priority_queue.html">std::priority_queue</a></tt>,
but uses a more efficient algorithm based on bucket sort. It can be use
d
when all priorities are positive integers in a given range (typically,
0...255).
By default, <tt>BucketQueue\<ValueType\></tt> sorts the elements in des
cending order,
i.e. like in <tt>std::priority_queue</tt> the largest element has highe
st priority.
An ascending queue can be specified as <tt>BucketQueue\<ValueType, true
\></tt>.
Elements with equal priorities are returned in a first-in first-out fas
hion.
The main difference to <tt>std::priority_queue</tt> is the function <tt
>push</tt>
which explicitly takes the priority of the element to be added as a sec
ond argument.
This allows optimization of <tt>ValueType</tt>: since the bucket unique
ly
determines an element's priority, there is no need for <tt>ValueType</t
t> to
store redundant priority information. If compatibility to <tt>std::prio
rity_queue</tt>
is more important, use \ref vigra::MappedBucketQueue.
<b>\#include</b> \<vigra/bucket_queue.hxx\><br>
Namespace: vigra
*/
template <class ValueType,
bool Ascending = false> // std::priority_queue is descending
class BucketQueue
{
ArrayVector<std::queue<ValueType> > buckets_;
std::size_t size_;
std::ptrdiff_t top_;
public:
typedef ValueType value_type;
typedef ValueType & reference;
typedef ValueType const & const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t priority_type;
/** \brief Create bucket queue with \arg bucket_count entries.
Priorities must be integers in the range <tt>[0, ..., bucket_co
unt-1]</tt>.
*/
BucketQueue(size_type bucket_count = 256)
: buckets_(bucket_count),
size_(0), top_(0)
{}
/** \brief Number of elements in this queue.
*/
size_type size() const
{
return size_;
}
/** \brief Queue contains no elements.
Equivalent to <tt>size() == 0</tt>.
*/
bool empty() const
{
return size() == 0;
}
/** \brief Maximum index (i.e. priority) allowed in this queue.
Equivalent to <tt>bucket_count - 1</tt>.
*/
priority_type maxIndex() const
{
return (priority_type)buckets_.size() - 1;
}
/** \brief Priority of the current top element.
*/
priority_type topPriority() const
{
return top_;
}
/** \brief The current top element.
*/
const_reference top() const
{
return buckets_[top_].front();
}
/** \brief Remove the current top element.
*/
void pop()
{
--size_;
buckets_[top_].pop();
while(top_ > 0 && buckets_[top_].size() == 0)
--top_;
}
/** \brief Insert new element \arg v with given \arg priority.
*/
void push(value_type const & v, priority_type priority)
{
++size_;
buckets_[priority].push(v);
if(priority > top_)
top_ = priority;
}
};
template <class ValueType>
class BucketQueue<ValueType, true> // ascending queue
{
ArrayVector<std::queue<ValueType> > buckets_;
std::size_t size_;
std::ptrdiff_t top_;
public:
typedef ValueType value_type;
typedef ValueType & reference;
typedef ValueType const & const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t priority_type;
BucketQueue(size_type bucket_count = 256)
: buckets_(bucket_count),
size_(0), top_((priority_type)bucket_count)
{}
size_type size() const
{
return size_;
}
bool empty() const
{
return size() == 0;
}
priority_type maxIndex() const
{
return (priority_type)buckets_.size() - 1;
}
priority_type topPriority() const
{
return top_;
}
const_reference top() const
{
return buckets_[top_].front();
}
void pop()
{
--size_;
buckets_[top_].pop();
while(top_ < (priority_type)buckets_.size() && buckets_[top_].size(
) == 0)
++top_;
}
void push(value_type const & v, priority_type priority)
{
++size_;
buckets_[priority].push(v);
if(priority < top_)
top_ = priority;
}
};
/** \brief Priority queue implemented using bucket sort (STL compatible).
This template is compatible to <tt><a href="http://www.sgi.com/tech/stl
/priority_queue.html">std::priority_queue</a></tt>,
but uses a more efficient algorithm based on bucket sort. It us used
like \ref vigra::BucketQueue, but has an additional <tt>PriorityFunctor
</tt>
which extracts the priority value of an element of type <tt>ValueType</
tt>.
Thus functor is called within <tt>push</tt> so that it does not need an
extra argument.
<b>\#include</b> \<vigra/bucket_queue.hxx\><br>
Namespace: vigra
*/
template <class ValueType,
class PriorityFunctor,
bool Ascending = false>
class MappedBucketQueue
: public BucketQueue<ValueType, Ascending>
{
PriorityFunctor get_priority_;
public:
typedef BucketQueue<ValueType, Ascending> BaseType;
typedef typename BaseType::value_type value_type;
typedef typename BaseType::reference reference;
typedef typename BaseType::const_reference const_reference;
typedef typename BaseType::size_type size_type;
typedef typename BaseType::priority_type priority_type;
/** \brief Create a queue with \arg bucket_count entries.
Priorities will be computed by the <tt>PriorityFunctor</tt>
given in \arg priority (i.e. <tt>priority(v)</tt> must result i
n an integer,
where <tt>v</tt> is an instance of <tt>ValueType</tt>).
*/
MappedBucketQueue(unsigned int bucket_count = 256,
PriorityFunctor const & priority = PriorityFunctor())
: BaseType(bucket_count),
get_priority_(priority)
{}
/** \brief Insert new element \arg v.
Its priority is calculated by <tt>priority(v)</tt>,
where <tt>priority</tt> is an instance of the
<tt>PriorityFunctor</tt> passed in the constructor.
If the priority is outside the range <tt>[0, ..., bucket_count-
1]</tt>,
it is clamped to the range borders.
*/
void push(value_type const & v)
{
priority_type index = get_priority_(v);
// clamp index to the allowed range
if(index > BaseType::maxIndex())
index = BaseType::maxIndex();
else if (index < 0)
index = 0;
BaseType::push(v, index);
}
};
/** \brief Heap-based priority queue compatible to BucketQueue.
This template is compatible to \ref vigra::BucketQueue, but except arbi
trary priority
types. Internally, it uses a <tt>std::priority_queue</tt>, but implemen
ts an
API where priorities and payload data are separate, like in \ref vigra:
:BucketQueue.
<b>\#include</b> \<vigra/bucket_queue.hxx\><br>
Namespace: vigra
*/
template <class ValueType,
class PriorityType,
bool Ascending = false> // std::priority_queue is descending
class PriorityQueue
{
typedef std::pair<ValueType, PriorityType> ElementType;
struct Compare
{
typename IfBool<Ascending, std::greater<PriorityType>,
std::less<PriorityType> >::type cmp;
bool operator()(ElementType const & l, ElementType const & r) const
{
return cmp(l.second, r.second);
}
};
typedef std::priority_queue<ElementType, std::vector<ElementType>, Comp
are> Heap;
Heap heap_;
public:
typedef ValueType value_type;
typedef ValueType & reference;
typedef ValueType const & const_reference;
typedef typename Heap::size_type size_type;
typedef PriorityType priority_type;
/** \brief Create empty priority queue.
*/
PriorityQueue()
: heap_()
{}
/** \brief Number of elements in this queue.
*/
size_type size() const
{
return heap_.size();
}
/** \brief Queue contains no elements.
Equivalent to <tt>size() == 0</tt>.
*/
bool empty() const
{
return size() == 0;
}
/** \brief Maximum index (i.e. priority) allowed in this queue.
Equivalent to <tt>bucket_count - 1</tt>.
*/
priority_type maxIndex() const
{
return NumericTraits<priority_type>::max();
}
/** \brief Priority of the current top element.
*/
priority_type topPriority() const
{
return heap_.top().second;
}
/** \brief The current top element.
*/
const_reference top() const
{
return heap_.top().first;
}
/** \brief Remove the current top element.
*/
void pop()
{
heap_.pop();
}
/** \brief Insert new element \arg v with given \arg priority.
*/
void push(value_type const & v, priority_type priority)
{
heap_.push(ElementType(v, priority));
}
};
} // namespace vigra
#endif // VIGRA_BUCKET_QUEUE_HXX #endif // VIGRA_BUCKET_QUEUE_HXX
 End of changes. 1 change blocks. 
360 lines changed or deleted 1 lines changed or added


 clebsch-gordan.hxx   clebsch-gordan.hxx 
skipping to change at line 374 skipping to change at line 374
} }
} }
} // anonymous namespace } // anonymous namespace
inline inline
double clebschGordan (double l1, double m1, double l2, double m2, double l3 , double m3) double clebschGordan (double l1, double m1, double l2, double m2, double l3 , double m3)
{ {
const double err = 0.01; const double err = 0.01;
double CG = 0.0, m2min, m2max, *cofp; double CG = 0.0, m2min, m2max, *cofp;
// static array for calculation of 3-j symbols // array for calculation of 3-j symbols
const int ncof = 100; const int ncof = 100;
double cof[ncof]; double cof[ncof];
// reset error flag // reset error flag
int errflag = 0; int errflag = 0;
ContractViolation Err; ContractViolation Err;
// Check for physical restriction. // Check for physical restriction.
// All other restrictions are checked by the 3-j symbol routine. // All other restrictions are checked by the 3-j symbol routine.
if ( abs(m1 + m2 - m3) > err) if ( abs(m1 + m2 - m3) > err)
{ {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 colorconversions.hxx   colorconversions.hxx 
skipping to change at line 78 skipping to change at line 78
? -norm*std::pow(-value/norm, gamma) ? -norm*std::pow(-value/norm, gamma)
: norm*std::pow(value/norm, gamma))); : norm*std::pow(value/norm, gamma)));
} }
template<class ValueType> template<class ValueType>
inline ValueType sRGBCorrection(double value, double norm) inline ValueType sRGBCorrection(double value, double norm)
{ {
value /= norm; value /= norm;
typedef typename NumericTraits<ValueType>::RealPromote Promote; typedef typename NumericTraits<ValueType>::RealPromote Promote;
return NumericTraits<ValueType>::fromRealPromote( return NumericTraits<ValueType>::fromRealPromote(
RequiresExplicitCast<ValueType>::cast( RequiresExplicitCast<Promote>::cast(
(value <= 0.0031308) (value <= 0.0031308)
? norm*12.92*value ? norm*12.92*value
: norm*(1.055*std::pow(value, 0.41666666666666667) - 0. 055))); : norm*(1.055*std::pow(value, 0.41666666666666667) - 0. 055)));
} }
template<class ValueType> template<class ValueType>
inline ValueType inverse_sRGBCorrection(double value, double norm) inline ValueType inverse_sRGBCorrection(double value, double norm)
{ {
value /= norm; value /= norm;
typedef typename NumericTraits<ValueType>::RealPromote Promote; typedef typename NumericTraits<ValueType>::RealPromote Promote;
return NumericTraits<ValueType>::fromRealPromote( return NumericTraits<ValueType>::fromRealPromote(
RequiresExplicitCast<ValueType>::cast( RequiresExplicitCast<Promote>::cast(
(value <= 0.04045) (value <= 0.04045)
? norm*value / 12.92 ? norm*value / 12.92
: norm*VIGRA_CSTD::pow((value + 0.055)/1.055, 2.4))); : norm*VIGRA_CSTD::pow((value + 0.055)/1.055, 2.4)));
} }
} // namespace detail } // namespace detail
/** \defgroup ColorConversions Color Space Conversions /** \defgroup ColorConversions Color Space Conversions
Convert between RGB, sRGB, R'G'B', XYZ, L*a*b*, L*u*v*, Y'PbPr, Y'CbCr, Y'IQ, and Y'UV color spaces. Convert between RGB, sRGB, R'G'B', XYZ, L*a*b*, L*u*v*, Y'PbPr, Y'CbCr, Y'IQ, and Y'UV color spaces.
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 combineimages.hxx   combineimages.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_COMBINEIMAGES_HXX #ifndef VIGRA_COMBINEIMAGES_HXX
#define VIGRA_COMBINEIMAGES_HXX #define VIGRA_COMBINEIMAGES_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "multi_shape.hxx"
#include <cmath> #include <cmath>
namespace vigra { namespace vigra {
/** \addtogroup CombineAlgo Algorithms to Combine Images /** \addtogroup CombineAlgo Algorithms to Combine Images
Apply functor to calculate a pixelwise transformation depending on mult iple images. Apply functor to calculate a pixelwise transformation depending on mult iple images.
Note that the binary functors of the STL may be used with these functio ns. Note that the binary functors of the STL may be used with these functio ns.
*/ */
//@{ //@{
skipping to change at line 114 skipping to change at line 116
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* combineTwoImages */ /* combineTwoImages */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Combine two source images into destination image. /** \brief Combine two source images into destination image.
After the introduction of arithmetic and algebraic \ref MultiMathModule
"array experessions",
this function is rarely needed. Moreover, \ref combineTwoMultiArrays()
provides the
same functionality for arbitrary dimensional arrays.
The transformation given by the functor is applied to the source The transformation given by the functor is applied to the source
pixels and the result written into the corresponding destination pixel. pixels and the result written into the corresponding destination pixel.
This is typically used for operations like add and subtract. This is typically used for operations like add and subtract.
The function uses accessors to access the pixel data.
Note that the binary functors of the STL can be used in addition to Note that the binary functors of the STL can be used in addition to
the functors specifically defined in \ref CombineFunctor. the functors specifically defined in \ref CombineFunctor.
Creation of new functors is easiest by using \ref FunctorExpressions. Creation of new functors is easiest by using \ref FunctorExpressions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T11, class S11,
class T12, class S12,
class T2, class S2,
class Functor>
void
combineTwoImages(MultiArrayView<2, T11, S11> const & src1,
MultiArrayView<2, T12, S12> const & src2,
MultiArrayView<2, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{combineTwoImages}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineTwoImages(SrcImageIterator1 src1_upperleft, combineTwoImages(SrcImageIterator1 src1_upperleft,
SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1, SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1,
SrcImageIterator2 src2_upperleft, SrcAccessor2 sa2, SrcImageIterator2 src2_upperleft, SrcAccessor2 sa2,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
Functor const & f) Functor const & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineTwoImages(triple<SrcImageIterator1, SrcImageIterator1, SrcAc cessor1> src1, combineTwoImages(triple<SrcImageIterator1, SrcImageIterator1, SrcAc cessor1> src1,
pair<SrcImageIterator2, SrcAccessor2> src2, pair<SrcImageIterator2, SrcAccessor2> src2,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/combineimages.hxx\><br> <b>\#include</b> \<vigra/combineimages.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <functional> // for plus #include <functional> // for plus
MultiArray<2, float> src1(width, height), src2(width, height),
dest(width, height);
... // fill source images
combineTwoImages(src1, src2, dest,
std::plus<float>());
\endcode
\deprecatedUsage{combineTwoImages}
\code
#include <functional> // for plus
FImage src1(width, height), src2(width, height),
dest(width, height);
... // fill source images
vigra::combineTwoImages( vigra::combineTwoImages(
srcIterRange(src1.upperLeft(), src1.lowerRight()), srcIterRange(src1.upperLeft(), src1.lowerRight()),
srcIter(src2.upperLeft()), srcIter(src2.upperLeft()),
destIter(dest.upperLeft()), destIter(dest.upperLeft()),
std::plus<SrcValueType>()); std::plus<float>());
\endcode \endcode
Note that <TT>SrcValueType</TT> must be replaced with the appropriate t
ype (e.g.
the promote type of the input images' pixel type, see also
\ref NumericPromotionTraits)
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator1 src1_upperleft, src1_lowerright; SrcImageIterator1 src1_upperleft, src1_lowerright;
SrcImageIterator2 src2_upperleft; SrcImageIterator2 src2_upperleft;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcImageIterator1::row_iterator sx1 = src1_upperleft.rowIterator(); SrcImageIterator1::row_iterator sx1 = src1_upperleft.rowIterator();
SrcImageIterator2::row_iterator sx2 = src2_upperleft.rowIterator(); SrcImageIterator2::row_iterator sx2 = src2_upperleft.rowIterator();
DestImageIterator::row_iterator dx = dest_upperleft.rowIterator(); DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
SrcAccessor1 src1_accessor; SrcAccessor1 src1_accessor;
SrcAccessor2 src2_accessor; SrcAccessor2 src2_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
Functor functor; Functor functor;
dest_accessor.set( dest_accessor.set(
functor(src1_accessor(sx1), src2_accessor(sx2)), functor(src1_accessor(sx1), src2_accessor(sx2)),
dx); dx);
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void combineTwoImages) doxygen_overloaded_function(template <...> void combineTwoImages)
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineTwoImages(SrcImageIterator1 src1_upperleft, combineTwoImages(SrcImageIterator1 src1_upperleft,
SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1, SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1,
skipping to change at line 230 skipping to change at line 260
} }
} }
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
inline inline
void void
combineTwoImages(triple<SrcImageIterator1, SrcImageIterator1, SrcAccessor1> src1, combineTwoImages(triple<SrcImageIterator1, SrcImageIterator1, SrcAccessor1> src1,
pair<SrcImageIterator2, SrcAccessor2> src2, pair<SrcImageIterator2, SrcAccessor2> src2,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
{ {
combineTwoImages(src1.first, src1.second, src1.third, combineTwoImages(src1.first, src1.second, src1.third,
src2.first, src2.second, src2.first, src2.second,
dest.first, dest.second, f); dest.first, dest.second, f);
}
template <class T11, class S11,
class T12, class S12,
class T2, class S2,
class Functor>
inline void
combineTwoImages(MultiArrayView<2, T11, S11> const & src1,
MultiArrayView<2, T12, S12> const & src2,
MultiArrayView<2, T2, S2> dest,
Functor const & f)
{
vigra_precondition(src1.shape() == src2.shape() && src1.shape() == dest
.shape(),
"combineTwoImages(): shape mismatch between inputs and/or output.")
;
combineTwoImages(srcImageRange(src1),
srcImage(src2),
destImage(dest), f);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* combineTwoImagesIf */ /* combineTwoImagesIf */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Combine ROI of two source images into destination image. /** \brief Combine ROI of two source images into destination image.
The transformation given by the functor is applied to all source The transformation given by the functor is applied to all source
pixels in the ROI (i.e. whenever the return value of the mask's accesso pixels in the ROI (i.e. whenever the corresponding value of the mask ar
r ray
is not zero) is non-zero)
and the result written into the corresponding destination pixel. and the result written into the corresponding destination pixel.
This is typically used for operations like add and subtract. This is typically used for operations like add and subtract.
The function uses accessors to access the pixel data.
Note that the binary functors of the STL can be used in addition to Note that the binary functors of the STL can be used in addition to
the functors specifically defined in \ref CombineFunctor. the functors specifically defined in \ref CombineFunctor.
Creation of new functors is easiest by using \ref FunctorExpressions. Creation of new functors is easiest by using \ref FunctorExpressions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T11, class S11,
class T12, class S12,
class TM, class SM,
class T2, class S2,
class Functor>
void
combineTwoImagesIf(MultiArrayView<2, T11, S11> const & src1,
MultiArrayView<2, T12, S12> const & src2,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{combineTwoImagesIf}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, clas DestAccessor, class DestImageIterator, clas DestAccessor,
class Functor> class Functor>
void void
combineTwoImagesIf(SrcImageIterator1 src1_upperleft, combineTwoImagesIf(SrcImageIterator1 src1_upperleft,
SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1, SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1,
SrcImageIterator2 src2_upperleft, SrcAccessor2 sa2, SrcImageIterator2 src2_upperleft, SrcAccessor2 sa2,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
Functor const & f) Functor const & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, clas DestAccessor, class DestImageIterator, clas DestAccessor,
class Functor> class Functor>
void void
combineTwoImagesIf(triple<SrcImageIterator1, SrcImageIterator1, Src Accessor1> src1, combineTwoImagesIf(triple<SrcImageIterator1, SrcImageIterator1, Src Accessor1> src1,
pair<SrcImageIterator2, SrcAccessor2> src2, pair<SrcImageIterator2, SrcAccessor2> src2,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/combineimages.hxx\><br> <b>\#include</b> \<vigra/combineimages.hxx\><br>
Namespace: vigra Namespace: vigra
\code
#include <functional> // for plus
MultiArray<2, float> src1(width, height), src2(width, height), mask(wid
th, height),
dest(width, height);
... // fill source and mask images
combineTwoImagesIf(src1, src2, mask, dest,
std::plus<float>());
\endcode
\deprecatedUsage{combineTwoImagesIf}
\code \code
#include <functional> // for plus #include <functional> // for plus
FImage src1(width, height), src2(width, height), mask(width, height),
dest(width, height);
... // fill source and mask images
vigra::combineTwoImagesIf( vigra::combineTwoImagesIf(
srcIterRange(src1.upperLeft(), src1.lowerRight()), srcIterRange(src1.upperLeft(), src1.lowerRight()),
srcIter(src2.upperLeft()), srcIter(src2.upperLeft()),
maskIter(mask.upperLeft()), maskIter(mask.upperLeft()),
destIter(dest.upperLeft()), destIter(dest.upperLeft()),
std::plus<SrcValueType>()); std::plus<SrcValueType>());
\endcode \endcode
Note that <TT>SrcValueType</TT> must be replaced with the appropriate t
ype (e.g.
the promote type of the input images' pixel type, see also
\ref NumericPromotionTraits)
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator1 src1_upperleft, src1_lowerright; SrcImageIterator1 src1_upperleft, src1_lowerright;
SrcImageIterator2 src2_upperleft; SrcImageIterator2 src2_upperleft;
MaskImageIterator mask_upperleft; MaskImageIterator mask_upperleft;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcImageIterator1::row_iterator sx1 = src1_upperleft.rowIterator(); SrcImageIterator1::row_iterator sx1 = src1_upperleft.rowIterator();
SrcImageIterator2::row_iterator sx2 = src2_upperleft.rowIterator(); SrcImageIterator2::row_iterator sx2 = src2_upperleft.rowIterator();
MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator(); MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
DestImageIterator::row_iterator dx = dest_upperleft.rowIterator(); DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
skipping to change at line 340 skipping to change at line 412
DestAccessor dest_accessor; DestAccessor dest_accessor;
Functor functor; Functor functor;
if(mask_accessor(mx)) if(mask_accessor(mx))
dest_accessor.set( dest_accessor.set(
functor(src1_accessor(sx1), src2_accessor(sx2)), functor(src1_accessor(sx1), src2_accessor(sx2)),
dx); dx);
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void combineTwoImagesIf) doxygen_overloaded_function(template <...> void combineTwoImagesIf)
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineTwoImagesIf(SrcImageIterator1 src1_upperleft, combineTwoImagesIf(SrcImageIterator1 src1_upperleft,
skipping to change at line 379 skipping to change at line 453
} }
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
inline inline
void void
combineTwoImagesIf(triple<SrcImageIterator1, SrcImageIterator1, SrcAccessor 1> src1, combineTwoImagesIf(triple<SrcImageIterator1, SrcImageIterator1, SrcAccessor 1> src1,
pair<SrcImageIterator2, SrcAccessor2> src2, pair<SrcImageIterator2, SrcAccessor2> src2,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
{ {
combineTwoImagesIf(src1.first, src1.second, src1.third, combineTwoImagesIf(src1.first, src1.second, src1.third,
src2.first, src2.second, src2.first, src2.second,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, f); dest.first, dest.second, f);
} }
template <class T11, class S11,
class T12, class S12,
class TM, class SM,
class T2, class S2,
class Functor>
inline void
combineTwoImagesIf(MultiArrayView<2, T11, S11> const & src1,
MultiArrayView<2, T12, S12> const & src2,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
Functor const & f)
{
vigra_precondition(src1.shape() == src2.shape() && src1.shape() == mask
.shape() && src1.shape() == dest.shape(),
"combineTwoImagesIf(): shape mismatch between inputs and/or output.
");
combineTwoImagesIf(srcImageRange(src1),
srcImage(src2),
maskImage(mask),
destImage(dest), f);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* combineThreeImages */ /* combineThreeImages */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Combine three source images into destination image. /** \brief Combine three source images into destination image.
After the introduction of arithmetic and algebraic \ref MultiMathModule
"array experessions",
this function is rarely needed. Moreover, \ref combineThreeMultiArrays(
) provides the
same functionality for arbitrary dimensional arrays.
The transformation given by the functor is applied to the source The transformation given by the functor is applied to the source
pixels and the result written into the corresponding destination pixel. pixels and the result written into the corresponding destination pixel.
The function uses accessors to access the pixel data.
Creation of new functors is easiest by using \ref FunctorExpressions. Creation of new functors is easiest by using \ref FunctorExpressions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T11, class S11,
class T12, class S12,
class T13, class S13,
class T2, class S2,
class Functor>
void
combineThreeImages(MultiArrayView<2, T11, S11> const & src1,
MultiArrayView<2, T12, S12> const & src2,
MultiArrayView<2, T13, S13> const & src3,
MultiArrayView<2, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{combineThreeImages}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class SrcImageIterator3, class SrcAccessor3, class SrcImageIterator3, class SrcAccessor3,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineThreeImages(SrcImageIterator1 src1_upperleft, combineThreeImages(SrcImageIterator1 src1_upperleft,
SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1, SrcImageIterator1 src1_lowerright, SrcAccessor1 sa1,
SrcImageIterator2 src2_upperleft, SrcAccessor2 sa2, SrcImageIterator2 src2_upperleft, SrcAccessor2 sa2,
SrcImageIterator3 src2_upperleft, SrcAccessor3 sa3, SrcImageIterator3 src2_upperleft, SrcAccessor3 sa3,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
Functor const & f) Functor const & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class SrcImageIterator3, class SrcAccessor3, class SrcImageIterator3, class SrcAccessor3,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineThreeImages(triple<SrcImageIterator1, SrcImageIterator1, Src Accessor1> src1, combineThreeImages(triple<SrcImageIterator1, SrcImageIterator1, Src Accessor1> src1,
pair<SrcImageIterator2, SrcAccessor2> src2, pair<SrcImageIterator2, SrcAccessor2> src2,
pair<SrcImageIterator3, SrcAccessor3> src3, pair<SrcImageIterator3, SrcAccessor3> src3,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/combineimages.hxx\><br> <b>\#include</b> \<vigra/combineimages.hxx\><br>
Namespace: vigra Namespace: vigra
\code
#include <vigra/functorexpression.hxx>
MultiArray<2, float> src1(width, height), src2(width, height), src3(wid
th, height),
dest(width, height);
... // fill source images
using namespace vigra::functor; // activate VIGRA's lambda library
combineThreeImages(src1, src2, src3, dest,
Arg1()*exp(-abs(Arg2()-Arg3())));
\endcode
\deprecatedUsage{combineThreeImages}
\code \code
FImage src1(width, height), src2(width, height), src3(width, height),
dest(width, height);
... // fill source images
vigra::combineThreeImages( vigra::combineThreeImages(
srcIterRange(src1.upperLeft(), src1.lowerRight()), srcIterRange(src1.upperLeft(), src1.lowerRight()),
srcIter(src2.upperLeft()), srcIter(src2.upperLeft()),
srcIter(src3.upperLeft()), srcIter(src3.upperLeft()),
destIter(dest.upperLeft()), destIter(dest.upperLeft()),
SomeThreeArgumentFunctor()); SomeThreeArgumentFunctor());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator1 src1_upperleft, src1_lowerright; SrcImageIterator1 src1_upperleft, src1_lowerright;
SrcImageIterator2 src2_upperleft; SrcImageIterator2 src2_upperleft;
SrcImageIterator3 src3_upperleft; SrcImageIterator3 src3_upperleft;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcImageIterator1::row_iterator sx1 = src1_upperleft.rowIterator(); SrcImageIterator1::row_iterator sx1 = src1_upperleft.rowIterator();
SrcImageIterator2::row_iterator sx2 = src2_upperleft.rowIterator(); SrcImageIterator2::row_iterator sx2 = src2_upperleft.rowIterator();
SrcImageIterator3::row_iterator sx3 = src3_upperleft.rowIterator(); SrcImageIterator3::row_iterator sx3 = src3_upperleft.rowIterator();
DestImageIterator::row_iterator dx = dest_upperleft.rowIterator(); DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
skipping to change at line 481 skipping to change at line 612
Functor functor; Functor functor;
dest_accessor.set( dest_accessor.set(
functor(src1_accessor(sx1), functor(src1_accessor(sx1),
src2_accessor(sx2), src2_accessor(sx2),
src3_accessor(sx3)), src3_accessor(sx3)),
dx); dx);
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void combineThreeImages) doxygen_overloaded_function(template <...> void combineThreeImages)
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class SrcImageIterator3, class SrcAccessor3, class SrcImageIterator3, class SrcAccessor3,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
combineThreeImages(SrcImageIterator1 src1_upperleft, combineThreeImages(SrcImageIterator1 src1_upperleft,
skipping to change at line 520 skipping to change at line 653
} }
template <class SrcImageIterator1, class SrcAccessor1, template <class SrcImageIterator1, class SrcAccessor1,
class SrcImageIterator2, class SrcAccessor2, class SrcImageIterator2, class SrcAccessor2,
class SrcImageIterator3, class SrcAccessor3, class SrcImageIterator3, class SrcAccessor3,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
inline inline
void void
combineThreeImages(triple<SrcImageIterator1, SrcImageIterator1, SrcAccessor 1> src1, combineThreeImages(triple<SrcImageIterator1, SrcImageIterator1, SrcAccessor 1> src1,
pair<SrcImageIterator2, SrcAccessor2> src2, pair<SrcImageIterator2, SrcAccessor2> src2,
pair<SrcImageIterator3, SrcAccessor3> src3, pair<SrcImageIterator3, SrcAccessor3> src3,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
{ {
combineThreeImages(src1.first, src1.second, src1.third, combineThreeImages(src1.first, src1.second, src1.third,
src2.first, src2.second, src2.first, src2.second,
src3.first, src3.second, src3.first, src3.second,
dest.first, dest.second, f); dest.first, dest.second, f);
}
template <class T11, class S11,
class T12, class S12,
class T13, class S13,
class T2, class S2,
class Functor>
inline void
combineThreeImages(MultiArrayView<2, T11, S11> const & src1,
MultiArrayView<2, T12, S12> const & src2,
MultiArrayView<2, T13, S13> const & src3,
MultiArrayView<2, T2, S2> dest,
Functor const & f)
{
vigra_precondition(src1.shape() == src2.shape() && src1.shape() == src3
.shape() && src1.shape() == dest.shape(),
"combineThreeImages(): shape mismatch between inputs and/or output.
");
combineThreeImages(srcImageRange(src1),
srcImage(src2),
srcImage(src3),
destImage(dest), f);
} }
//@} //@}
/** \addtogroup CombineFunctor Functors to Combine Images /** \addtogroup CombineFunctor Functors to Combine Images
Common functors with several arguments Common functors with several arguments
*/ */
//@{ //@{
 End of changes. 43 change blocks. 
51 lines changed or deleted 214 lines changed or added


 config.hxx   config.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_CONFIG_HXX #ifndef VIGRA_CONFIG_HXX
#define VIGRA_CONFIG_HXX #define VIGRA_CONFIG_HXX
#include <vigra/configVersion.hxx> #include "config_version.hxx"
#include <stdexcept> #include <stdexcept>
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// // // //
// VisualC++ 5.0 // // VisualC++ //
// // // //
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#ifdef _MSC_VER #ifdef _MSC_VER
// make sure that we use vigra/windows.h so that incompatibilities are
fixed
#include "windows.h"
#if(_MSC_VER < 1100) // before VisualC++ 5.0 #if(_MSC_VER < 1100) // before VisualC++ 5.0
#error "Need VisualC++ 5.0, Service Pack 2, or later" #error "Need VisualC++ 5.0, Service Pack 2, or later"
#endif // _MSC_VER < 1100 #endif // _MSC_VER < 1100
#if (_MSC_VER < 1300) #if (_MSC_VER < 1300)
#define NO_TYPENAME // no 'typename' keyword #define NO_TYPENAME // no 'typename' keyword
#define TEMPLATE_COPY_CONSTRUCTOR_BUG #define TEMPLATE_COPY_CONSTRUCTOR_BUG
#define NO_STL_MEMBER_TEMPLATES #define NO_STL_MEMBER_TEMPLATES
#define NO_INLINE_STATIC_CONST_DEFINITION #define NO_INLINE_STATIC_CONST_DEFINITION
#define CMATH_NOT_IN_STD #define CMATH_NOT_IN_STD
skipping to change at line 106 skipping to change at line 109
#ifndef CMATH_NOT_IN_STD #ifndef CMATH_NOT_IN_STD
} }
#endif // CMATH_NOT_IN_STD #endif // CMATH_NOT_IN_STD
#endif // _MSC_EXTENSIONS #endif // _MSC_EXTENSIONS
#endif // _MSC_VER < 1310 #endif // _MSC_VER < 1310
#if _MSC_VER < 1400 #if _MSC_VER < 1400
#define VIGRA_NO_WORKING_STRINGSTREAM #define VIGRA_NO_WORKING_STRINGSTREAM
#endif #endif
#if _MSC_VER >= 1600 #if _MSC_VER < 1600
#define VIGRA_HAS_UNIQUE_PTR #define VIGRA_NO_UNIQUE_PTR
#endif #endif
#define VIGRA_NEED_BIN_STREAMS #define VIGRA_NEED_BIN_STREAMS
#define VIGRA_NO_THREADSAFE_STATIC_INIT // at least up to _MSC_VER <=
1600, probably higher
// usage:
// static int * p = VIGRA_SAFE_STATIC(p, new int(42));
//
#define VIGRA_SAFE_STATIC(p, v) \
0; while(p == 0) ::vigra::detail::safeStaticInit(&p, v)
namespace vigra { namespace detail {
template <class T>
inline void safeStaticInit(T ** p, T * v)
{
if (InterlockedCompareExchangePointer((PVOID *)p, v, 0) != 0)
delete v;
}
}} // namespace vigra::detail
#ifndef VIGRA_ENABLE_ANNOYING_WARNINGS #ifndef VIGRA_ENABLE_ANNOYING_WARNINGS
#pragma warning ( disable: 4244 4267) // implicit integer conversio n warnings #pragma warning ( disable: 4244 4267) // implicit integer conversio n warnings
#endif #endif
#ifdef VIGRA_DLL #ifdef VIGRA_DLL
#define VIGRA_EXPORT __declspec(dllexport) #define VIGRA_EXPORT __declspec(dllexport)
#elif defined(VIGRA_STATIC_LIB) #elif defined(VIGRA_STATIC_LIB)
#define VIGRA_EXPORT #define VIGRA_EXPORT
#else #else
#define VIGRA_EXPORT __declspec(dllimport) #define VIGRA_EXPORT __declspec(dllimport)
#endif #endif
#endif // _MSC_VER #endif // _MSC_VER
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// // // //
// gcc // // gcc //
// // // //
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#if defined(__GNUC__) #if defined(__GNUC__) && !defined(__clang__)
#if __GNUC__ < 2 || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 8)) #if __GNUC__ < 2 || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 8))
#error "Need at least g++ 2.95" #error "Need at least g++ 2.95"
#endif #endif
#if __GNUC__ < 3 #if __GNUC__ < 3
#define VIGRA_NO_WORKING_STRINGSTREAM #define VIGRA_NO_WORKING_STRINGSTREAM
#endif #endif
#define HAS_HASH_CONTAINERS #define HAS_HASH_CONTAINERS
// these warnings produce too many false positives to be useful // these warnings produce too many false positives to be useful
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wshadow"
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
#define VIGRA_HAS_UNIQUE_PTR #if defined(__APPLE__)
#define VIGRA_NO_UNIQUE_PTR
#endif
#else
// C++98 mode. No native unique_ptr support
#define VIGRA_NO_UNIQUE_PTR
#define VIGRA_SHARED_PTR_IN_TR1
#endif #endif
#endif // __GNUC__ #endif // __GNUC__
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// // // //
// clang //
// //
///////////////////////////////////////////////////////////
#if defined(__clang__)
// In Apple builds of clang, __clang_major__ and __clang_minor__
// have totally different values than in other builds of clang.
#if defined(__apple_build_version__)
// (For Apple builds of clang, __clang_major__ tracks the XCode ver
sion.)
// For Apple builds, C++11 only works well with libc++, not stdlibc
++
#define VIGRA_NO_UNIQUE_PTR
#if __cplusplus >= 201103L
// Must have at least XCode 4 and use libc++ to use std::shared
_ptr, etc.
// Otherwise, use tr1.
#if !((__clang_major__ >= 4) && defined(_LIBCPP_VERSION))
#define VIGRA_SHARED_PTR_IN_TR1
#endif
#else
// C++98 mode. No native unique_ptr support
#define VIGRA_NO_UNIQUE_PTR
#if !defined(_LIBCPP_VERSION)
#define VIGRA_SHARED_PTR_IN_TR1
#endif
#endif
#else
// This is a conservative constraint:
// Full C++11 support was achieved in clang-3.3,
// but most support was available in 3.1 and 3.2
#if __cplusplus >= 201103L
#if (__clang_major__ < 3) || ((__clang_major__ == 3) && (__clan
g_minor__ < 3))
#define VIGRA_SHARED_PTR_IN_TR1
#define VIGRA_NO_UNIQUE_PTR
#endif
#else
// C++98 mode. No native shared_ptr/unique_ptr support
#define VIGRA_NO_UNIQUE_PTR
#define VIGRA_SHARED_PTR_IN_TR1
#endif
#endif
#endif // __clang__
///////////////////////////////////////////////////////////
// //
// MingW // // MingW //
// // // //
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#if defined(__MINGW32__) #if defined(__MINGW32__)
#define VIGRA_NEED_BIN_STREAMS #define VIGRA_NEED_BIN_STREAMS
#ifdef VIGRA_DLL #ifdef VIGRA_DLL
#define VIGRA_EXPORT __declspec(dllexport) #define VIGRA_EXPORT __declspec(dllexport)
#elif defined(VIGRA_STATIC_LIB) #elif defined(VIGRA_STATIC_LIB)
skipping to change at line 224 skipping to change at line 290
#endif #endif
#ifdef NO_EXPLICIT #ifdef NO_EXPLICIT
#define explicit #define explicit
#endif #endif
#ifndef VIGRA_EXPORT #ifndef VIGRA_EXPORT
#define VIGRA_EXPORT #define VIGRA_EXPORT
#endif #endif
#ifdef VIGRA_HAS_UNIQUE_PTR #ifdef VIGRA_NO_UNIQUE_PTR
# define VIGRA_UNIQUE_PTR std::unique_ptr
#else
# define VIGRA_UNIQUE_PTR std::auto_ptr # define VIGRA_UNIQUE_PTR std::auto_ptr
#else
# ifdef _GLIBCXX_INCLUDE_AS_TR1
# define VIGRA_UNIQUE_PTR std::tr1::unique_ptr
# else
# define VIGRA_UNIQUE_PTR std::unique_ptr
# endif
#endif
#ifdef VIGRA_SHARED_PTR_IN_TR1
# define VIGRA_SHARED_PTR std::tr1::shared_ptr
#else
# define VIGRA_SHARED_PTR std::shared_ptr
#endif
#ifndef VIGRA_NO_THREADSAFE_STATIC_INIT
// usage:
// static int * p = VIGRA_SAFE_STATIC(p, new int(42));
//
#define VIGRA_SAFE_STATIC(p, v) v
#endif #endif
namespace vigra { namespace vigra {
#ifndef SPECIAL_STDEXCEPTION_DEFINITION_NEEDED #ifndef SPECIAL_STDEXCEPTION_DEFINITION_NEEDED
typedef std::exception StdException; typedef std::exception StdException;
#endif #endif
} // namespace vigra } // namespace vigra
 End of changes. 12 change blocks. 
11 lines changed or deleted 100 lines changed or added


 convolution.hxx   convolution.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_CONVOLUTION_HXX #ifndef VIGRA_CONVOLUTION_HXX
#define VIGRA_CONVOLUTION_HXX #define VIGRA_CONVOLUTION_HXX
#include <functional> #include <functional>
#include "stdconvolution.hxx" #include "stdconvolution.hxx"
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "recursiveconvolution.hxx" #include "recursiveconvolution.hxx"
#include "nonlineardiffusion.hxx" #include "nonlineardiffusion.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
#include "multi_shape.hxx"
/** \page Convolution Functions to Convolve Images and Signals /** \page Convolution Functions to Convolve Images and Signals
1D and 2D filters, including separable and recursive convolution, and n on-linear diffusion 1D and 2D filters, including separable and recursive convolution, and n on-linear diffusion
<b>\#include</b> \<vigra/convolution.hxx\><br> <b>\#include</b> \<vigra/convolution.hxx\><br>
Namespace: vigra Namespace: vigra
<UL style="list-style-image:url(documents/bullet.gif)"> <UL style="list-style-image:url(documents/bullet.gif)">
<LI> \ref CommonConvolutionFilters <LI> \ref CommonConvolutionFilters
<BR>&nbsp;&nbsp;&nbsp;<em>Short-hands for the most common 2D convo lution filters</em> <BR>&nbsp;&nbsp;&nbsp;<em>Short-hands for many common 2D convoluti on filters (including normalized convolution)</em>
<LI> \ref MultiArrayConvolutionFilters <LI> \ref MultiArrayConvolutionFilters
<BR>&nbsp;&nbsp;&nbsp;<em>Convolution filters for arbitrary dimens ional arrays (MultiArray etc.)</em> <BR>&nbsp;&nbsp;&nbsp;<em>Convolution filters for arbitrary dimens ional arrays (MultiArray etc.)</em>
<LI> \ref ResamplingConvolutionFilters <LI> \ref ResamplingConvolutionFilters
<BR>&nbsp;&nbsp;&nbsp;<em>Resampling convolution filters</em> <BR>&nbsp;&nbsp;&nbsp;<em>Resampling convolution filters</em>
<LI> \ref StandardConvolution
<BR>&nbsp;&nbsp;&nbsp;<em>2D non-separable convolution, with and w
ithout ROI mask </em>
<LI> \ref vigra::Kernel2D <LI> \ref vigra::Kernel2D
<BR>&nbsp;&nbsp;&nbsp;<em>Generic 2-dimensional discrete convoluti on kernel </em> <BR>&nbsp;&nbsp;&nbsp;<em>Generic 2-dimensional discrete convoluti on kernel </em>
<LI> \ref SeparableConvolution <LI> \ref SeparableConvolution
<BR>&nbsp;&nbsp;&nbsp;<em>1D convolution and separable filters in 2 dimensions </em> <BR>&nbsp;&nbsp;&nbsp;<em>1D convolution and separable filters in 2 dimensions </em>
<LI> \ref vigra::Kernel1D <LI> \ref vigra::Kernel1D
<BR>&nbsp;&nbsp;&nbsp;<em>Generic 1-dimensional discrete convoluti on kernel </em> <BR>&nbsp;&nbsp;&nbsp;<em>Generic 1-dimensional discrete convoluti on kernel </em>
<LI> \ref RecursiveConvolution <LI> \ref RecursiveConvolution
<BR>&nbsp;&nbsp;&nbsp;<em>Recursive filters (1st and 2nd order)</e m> <BR>&nbsp;&nbsp;&nbsp;<em>Recursive filters (1st and 2nd order)</e m>
<LI> \ref NonLinearDiffusion <LI> \ref NonLinearDiffusion
<BR>&nbsp;&nbsp;&nbsp;<em>Edge-preserving smoothing </em> <BR>&nbsp;&nbsp;&nbsp;<em>Edge-preserving smoothing </em>
skipping to change at line 127 skipping to change at line 126
<TT>kernel1d(kerneliterator, kernelaccessor,</TT><br> <TT>kernel1d(kerneliterator, kernelaccessor,</TT><br>
<TT> kernelleft, kernelright,</TT><br> <TT> kernelleft, kernelright,</TT><br>
<TT> vigra::BORDER_TREATMENT_CLIP)</TT> <TT> vigra::BORDER_TREATMENT_CLIP)</TT>
</td><td> </td><td>
create argument object from explicitly given iterator create argument object from explicitly given iterator
(pointing to the center of th kernel), accessor, (pointing to the center of th kernel), accessor,
left and right boundaries, and border treatment mode left and right boundaries, and border treatment mode
</table> </table>
For usage examples see For usage examples see \ref convolveImage().
\ref SeparableConvolution "one-dimensional and separable convolutio
n functions".
\section Kernel2dFactory kernel2d() \section Kernel2dFactory kernel2d()
Pass a \ref vigra::Kernel2D to a 2D (non-separable) convolution alg orithm. Pass a \ref vigra::Kernel2D to a 2D (non-separable) convolution alg orithm.
These factories can be used to create argument objects when we These factories can be used to create argument objects when we
are given instances or subclasses of \ref vigra::Kernel2D are given instances or subclasses of \ref vigra::Kernel2D
(analogous to the \ref ArgumentObjectFactories for images). (analogous to the \ref ArgumentObjectFactories for images).
These factory functions access <TT>kernel.center()</TT>, These factory functions access <TT>kernel.center()</TT>,
<TT>kernel.upperLeft()</TT>, <TT>kernel.lowerRight()</TT>, <TT>kern el.accessor()</TT>, <TT>kernel.upperLeft()</TT>, <TT>kernel.lowerRight()</TT>, <TT>kern el.accessor()</TT>,
skipping to change at line 172 skipping to change at line 170
<TT>kernel2d(kerneliterator, kernelaccessor,</TT> <TT>kernel2d(kerneliterator, kernelaccessor,</TT>
<TT> upperleft, lowerright,</TT> <TT> upperleft, lowerright,</TT>
<TT> vigra::BORDER_TREATMENT_CLIP)</TT> <TT> vigra::BORDER_TREATMENT_CLIP)</TT>
</td><td> </td><td>
create argument object from explicitly given iterator create argument object from explicitly given iterator
(pointing to the center of th kernel), accessor, (pointing to the center of th kernel), accessor,
upper left and lower right corners, and border treatment mode upper left and lower right corners, and border treatment mode
</table> </table>
For usage examples see \ref StandardConvolution "two-dimensional co nvolution functions". For usage examples see \ref convolveImage().
*/ */
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* Common convolution filters */ /* Common convolution filters */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup CommonConvolutionFilters Common Filters /** \addtogroup CommonConvolutionFilters Common Filters
These functions calculate common filters by appropriate sequences of ca lls These functions calculate common filters by appropriate sequences of ca lls
to \ref separableConvolveX() and \ref separableConvolveY(). to \ref separableConvolveX() and \ref separableConvolveY() or explicit
2-dimensional
convolution.
*/ */
//@{ //@{
/********************************************************/ /** \brief Convolve an image with the given kernel(s).
/* */
/* convolveImage */
/* */
/********************************************************/
/** \brief Apply two separable filters successively, the first in x-directi If you pass \ref vigra::Kernel2D to this function, it will perform an e
on, xplicit 2-dimensional
the second in y-direction. convolution. If you pass a single \ref vigra::Kernel1D, it performs a s
eparable convolution,
This function is a shorthand for the concatenation of a call to i.e. it concatenates two 1D convolutions (along the x-axis and along th
\ref separableConvolveX() and \ref separableConvolveY() e y-axis) with the same
with the given kernels. kernel via internal calls to \ref separableConvolveX() and \ref separab
leConvolveY(). If two
1D kernels are specified, separable convolution uses different kernels
for the x- and y-axis.
All \ref BorderTreatmentMode "border treatment modes" are supported.
The unput pixel type <tt>T1</tt> must be a \ref LinearSpace "linear spa
ce" over
the kernel's value_type <tt>T</tt>, i.e. addition of source values, mul
tiplication with kernel values,
and NumericTraits must be defined. The kernel's value_type must be an \
ref AlgebraicField "algebraic field",
i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be d
efined. Typically, you will use
<tt>double</tt> for the kernel type.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// use the same 1D kernel for all axes
template <class T1, class S1,
class T2, class S2,
class T>
void
convolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T> const & k);
// use a different kernel for each axis
template <class T1, class S1,
class T2, class S2,
class T>
void
convolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T> const & kx, Kernel1D<T> const & ky);
// use a non-separable 2D kernel
template <class T1, class S1,
class T2, class S2,
class T3>
void
convolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel2D<T3> const & kernel);
}
\endcode
\deprecatedAPI{convolveImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// use a different kernel for each axis
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class T> class T>
void convolveImage(SrcIterator supperleft, void convolveImage(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
Kernel1D<T> const & kx, Kernel1D<T> const & ky); Kernel1D<T> const & kx, Kernel1D<T> const & ky);
// use a non-separable 2D kernel
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor>
void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAcces
sor src_acc,
DestIterator dest_ul, DestAccessor dest_acc,
KernelIterator ki, KernelAccessor ak,
Diff2D kul, Diff2D klr, BorderTreatmentMode bord
er);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// use a different kernel for each axis
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class T> class T>
inline void void
convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Kernel1D<T> const & kx, Kernel1D<T> const & ky); Kernel1D<T> const & kx, Kernel1D<T> const & ky);
// use a non-separable 2D kernel
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor>
void convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> sr
c,
pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, Diff2D, D
iff2D,
BorderTreatmentMode> kernel);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), dest1(w,h), dest2(w,h);
...
// create horizontal sobel filter (symmetric difference in x-direction,
smoothing in y direction)
Kernel1D<double> kx, ky;
kx.initSymmetricDifference();
ky.initBinomial(1);
// calls separable convolution with the two 1D kernels
convolveImage(src, dest1, kx, ky);
// create a 3x3 Laplacian filter
Kernel2D<double> laplace;
laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
0.375, 0.25, 0.375,
0.25, -2.5, 0.25,
0.375, 0.25, 0.375;
// calls 2D convolution
convolveImage(src, dest2, laplace);
\endcode
\deprecatedUsage{convolveImage}
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// implement sobel filter in x-direction // create horizontal sobel filter (symmetric difference in x-direction, smoothing in y direction)
Kernel1D<double> kx, ky; Kernel1D<double> kx, ky;
kx.initSymmetricGradient(); kx.initSymmetricDifference();
ky.initBinomial(1); ky.initBinomial(1);
// calls separable convolution with the two 1D kernels
vigra::convolveImage(srcImageRange(src), destImage(dest), kx, ky); vigra::convolveImage(srcImageRange(src), destImage(dest), kx, ky);
// create a 3x3 Laplacian filter
Kernel2D<double> laplace;
laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
0.375, 0.25, 0.375,
0.25, -2.5, 0.25,
0.375, 0.25, 0.375;
// calls 2D convolution
vigra::convolveImage(srcImageRange(src), destImage(dest), kernel2d(lapl
ace));
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b>
The image must be larger than the kernel radius.
<ul>
<li>For 1D kernels, <tt>w > std::max(xkernel.right(), -xkernel.keft())<
/tt> and
<tt>h > std::max(ykernel.right(), -ykernel.left())</tt> are requir
ed.
<li>For 2D kernels, <tt>w > std::max(kernel.lowerRight().x, -kernel.upp
erLeft().x)</tt> and
<tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt
> are required.
</ul>
If <tt>BORDER_TREATMENT_CLIP</tt> is requested: the sum of kernel eleme
nts must be != 0.
*/ */
doxygen_overloaded_function(template <...> void convolveImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class T> class T>
void convolveImage(SrcIterator supperleft, void convolveImage(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
Kernel1D<T> const & kx, Kernel1D<T> const & ky) Kernel1D<T> const & kx, Kernel1D<T> const & ky)
{ {
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote NumericTraits<typename SrcAccessor::value_type>::RealPromote
skipping to change at line 280 skipping to change at line 383
class T> class T>
inline void inline void
convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Kernel1D<T> const & kx, Kernel1D<T> const & ky) Kernel1D<T> const & kx, Kernel1D<T> const & ky)
{ {
convolveImage(src.first, src.second, src.third, convolveImage(src.first, src.second, src.third,
dest.first, dest.second, kx, ky); dest.first, dest.second, kx, ky);
} }
template <class T1, class S1,
class T2, class S2,
class T>
inline void
convolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T> const & k)
{
vigra_precondition(src.shape() == dest.shape(),
"convolveImage(): shape mismatch between input and output.");
convolveImage(srcImageRange(src),
destImage(dest), k, k);
}
template <class T1, class S1,
class T2, class S2,
class T>
inline void
convolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T> const & kx, Kernel1D<T> const & ky)
{
vigra_precondition(src.shape() == dest.shape(),
"convolveImage(): shape mismatch between input and output.");
convolveImage(srcImageRange(src),
destImage(dest), kx, ky);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* simpleSharpening */ /* simpleSharpening */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Perform simple sharpening function. /** \brief Perform simple sharpening function.
This function uses \ref convolveImage() with the following filter: This function uses \ref convolveImage() with the following 3x3 filter:
\code \code
-sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact or/16.0, -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact or/16.0,
-sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_fact or/8.0, -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_fact or/8.0,
-sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact or/16.0; -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact or/16.0;
\endcode \endcode
and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode. and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode.
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
1. sharpening_factor >= 0 1. sharpening_factor >= 0
2. scale >= 0 2. scale >= 0
\endcode \endcode
<b> Declarations:</b> <b> Declarations:</b>
<b> Declarations:</b> pass 2D array views:
pass arguments explicitly:
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class T1, class S1,
class DestIterator, class DestAccessor> class T2, class S2>
void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAcce void
ssor src_acc, simpleSharpening(MultiArrayView<2, T1, S1> const & src,
DestIterator dest_ul, DestAccessor dest_acc, do MultiArrayView<2, T2, S2> dest,
uble sharpening_factor) double sharpening_factor);
} }
\endcode \endcode
\deprecatedAPI{simpleSharpening}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAc
cessor src_acc,
DestIterator dest_ul, DestAccessor dest_acc,
double sharpening_factor);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor>
void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> s src,
rc, pair<DestIterator, DestAccessor> dest, double
pair<DestIterator, DestAccessor> dest, sharpening_factor);
double sharpening_factor)
{
simpleSharpening(src.first, src.second, src.third,
dest.first, dest.second, sharpening_factor);
}
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
// sharpening with sharpening_factor = 0.1
vigra::simpleSharpening(src, dest, 0.1);
\endcode
\deprecatedUsage{simpleSharpening}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// sharpening with sharpening_factor = 0.1 // sharpening with sharpening_factor = 0.1
vigra::simpleSharpening(srcImageRange(src), destImage(dest), 0.1); vigra::simpleSharpening(srcImageRange(src), destImage(dest), 0.1);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void simpleSharpening) doxygen_overloaded_function(template <...> void simpleSharpening)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor s rc_acc, void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor s rc_acc,
DestIterator dest_ul, DestAccessor dest_acc, double sha rpening_factor) DestIterator dest_ul, DestAccessor dest_acc, double sha rpening_factor)
{ {
vigra_precondition(sharpening_factor >= 0.0, vigra_precondition(sharpening_factor >= 0.0,
skipping to change at line 375 skipping to change at line 520
convolveImage(src_ul, src_lr, src_acc, dest_ul, dest_acc, convolveImage(src_ul, src_lr, src_acc, dest_ul, dest_acc,
kernel.center(), kernel.accessor(), kernel.center(), kernel.accessor(),
kernel.upperLeft(), kernel.lowerRight() , BORDER_TREATMEN T_REFLECT ); kernel.upperLeft(), kernel.lowerRight() , BORDER_TREATMEN T_REFLECT );
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src, void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, double sharpenin g_factor) pair<DestIterator, DestAccessor> dest, double sharpen ing_factor)
{ {
simpleSharpening(src.first, src.second, src.third, simpleSharpening(src.first, src.second, src.third,
dest.first, dest.second, sharpening_factor); dest.first, dest.second, sharpening_factor);
} }
template <class T1, class S1,
class T2, class S2>
inline void
simpleSharpening(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sharpening_factor)
{
vigra_precondition(src.shape() == dest.shape(),
"simpleSharpening(): shape mismatch between input and output.");
simpleSharpening(srcImageRange(src),
destImage(dest), sharpening_factor);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* gaussianSharpening */ /* gaussianSharpening */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Perform sharpening function with gaussian filter. /** \brief Perform sharpening function with gaussian filter.
This function uses \ref gaussianSmoothing() at the given scale to creat e a This function uses \ref gaussianSmoothing() at the given scale to creat e a
temporary image 'smooth' and than blends the original and smoothed imag e temporary image 'smooth' and than blends the original and smoothed imag e
skipping to change at line 405 skipping to change at line 563
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
1. sharpening_factor >= 0 1. sharpening_factor >= 0
2. scale >= 0 2. scale >= 0
\endcode \endcode
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sharpening_factor,
double scale);
}
\endcode
\deprecatedAPI{gaussianSharpening}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAc cessor src_acc, void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAc cessor src_acc,
DestIterator dest_ul, DestAccessor dest_acc, DestIterator dest_ul, DestAccessor dest_acc,
double sharpening_factor, double scale) double sharpening_factor, double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src, void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double sharpening_factor, double scale) double sharpening_factor, double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code \code
vigra::FImage src(w,h), dest(w,h); MultiArray<2, float> src(w,h), dest(w,h);
... ...
// sharpening with sharpening_factor = 3.0 // sharpening with sharpening_factor = 3.0
// smoothing with scale = 0.5 // smoothing with scale = 0.5
vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0, 0.5) gaussianSharpening(src, dest, 3.0, 0.5);
;
\endcode \endcode
\deprecatedUsage{gaussianSharpening}
\code
vigra::FImage src(w,h), dest(w,h);
...
// sharpening with sharpening_factor = 3.0
// smoothing with scale = 0.5
vigra::gaussianSharpening(srcImageRange(src), destImage(dest), 3.0, 0.5
);
\endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void gaussianSharpening) doxygen_overloaded_function(template <...> void gaussianSharpening)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc, void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor, DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor,
double scale) double scale)
{ {
vigra_precondition(sharpening_factor >= 0.0, vigra_precondition(sharpening_factor >= 0.0,
skipping to change at line 481 skipping to change at line 663
dest_acc.set((1.0 + sharpening_factor)*src_acc(i_src) - sharpen ing_factor*tmp_acc(i_tmp), i_dest); dest_acc.set((1.0 + sharpening_factor)*src_acc(i_src) - sharpen ing_factor*tmp_acc(i_tmp), i_dest);
} }
i_src.x = src_ul.x; i_src.x = src_ul.x;
i_dest.x = dest_ul.x; i_dest.x = dest_ul.x;
i_tmp.x = tmp_ul.x; i_tmp.x = tmp_ul.x;
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src, inline void
pair<DestIterator, DestAccessor> dest, double sharp gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
ening_factor, pair<DestIterator, DestAccessor> dest, double sharpening
double scale) _factor,
double scale)
{ {
gaussianSharpening(src.first, src.second, src.third, gaussianSharpening(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
sharpening_factor, scale); sharpening_factor, scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sharpening_factor,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"gaussianSharpening(): shape mismatch between input and output.");
gaussianSharpening(srcImageRange(src),
destImage(dest),
sharpening_factor, scale);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* gaussianSmoothing */ /* gaussianSmoothing */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Perform isotropic Gaussian convolution. /** \brief Perform isotropic Gaussian convolution.
This function is a shorthand for the concatenation of a call to This function is a shorthand for the concatenation of a call to
\ref separableConvolveX() and \ref separableConvolveY() with a \ref separableConvolveX() and \ref separableConvolveY() with a
Gaussian kernel of the given scale. If two scales are provided, Gaussian kernel of the given scale. If two scales are provided,
smoothing in x and y direction will have different strength. smoothing in x and y direction will have different strength.
The function uses <TT>BORDER_TREATMENT_REFLECT</TT>. The function uses <TT>BORDER_TREATMENT_REFLECT</TT>.
Function \ref gaussianSmoothMultiArray() performs the same filter opera
tion
on arbitrary dimensional arrays.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale_x, double scale_y = scale_x);
}
\endcode
\deprecatedAPI{gaussianSmoothing}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianSmoothing(SrcIterator supperleft, void gaussianSmoothing(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
double scale_x, double scale_y = scale_x); double scale_x, double scale_y = scale_x);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void void
gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src , gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src ,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale_x, double scale_y = scale_x); double scale_x, double scale_y = scale_x);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), dest(w,h);
...
// smooth with scale = 3.0
gaussianSmoothing(src, dest, 3.0);
\endcode
\deprecatedUsage{gaussianSmoothing}
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// smooth with scale = 3.0 // smooth with scale = 3.0
vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0); vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void gaussianSmoothing) doxygen_overloaded_function(template <...> void gaussianSmoothing)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAcces sor sa, gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAcces sor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
double scale_x, double scale_y) double scale_x, double scale_y)
{ {
skipping to change at line 604 skipping to change at line 827
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src, gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
{ {
gaussianSmoothing(src.first, src.second, src.third, gaussianSmoothing(src.first, src.second, src.third,
dest.first, dest.second, scale, scale); dest.first, dest.second, scale, scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale_x, double scale_y)
{
vigra_precondition(src.shape() == dest.shape(),
"gaussianSmoothing(): shape mismatch between input and output.");
gaussianSmoothing(srcImageRange(src),
destImage(dest), scale_x, scale_y);
}
template <class T1, class S1,
class T2, class S2>
inline void
gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"gaussianSmoothing(): shape mismatch between input and output.");
gaussianSmoothing(srcImageRange(src),
destImage(dest), scale, scale);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* gaussianGradient */ /* gaussianGradient */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the gradient vector by means of a 1st derivatives of /** \brief Calculate the gradient vector by means of a 1st derivatives of
Gaussian filter. Gaussian filter.
This function is a shorthand for the concatenation of a call to This function is a shorthand for the concatenation of a call to
\ref separableConvolveX() and \ref separableConvolveY() with the \ref separableConvolveX() and \ref separableConvolveY() with the
appropriate kernels at the given scale. Note that this function can eit her produce appropriate kernels at the given scale. Note that this function can eit her produce
two separate result images for the x- and y-components of the gradient, or write two separate result images for the x- and y-components of the gradient, or write
into a vector valued image (with at least two components). into a vector valued image (with at least two components).
Function \ref gaussianGradientMultiArray() performs the same filter ope
ration
on arbitrary dimensional arrays.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// write x and y component of the gradient into separate images
template <class T1, class S1,
class T2X, class S2X,
class T2Y, class S2Y>
void
gaussianGradient(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2X, S2X> destx,
MultiArrayView<2, T2Y, S2Y> desty,
double scale);
// write x and y component of the gradient into a vector-valued imag
e
template <class T1, class S1,
class T2, class S2>
void
gaussianGradient(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TinyVector<T2, 2>, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{gaussianGradient}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// write x and y component of the gradient into separate images // write x and y component of the gradient into separate images
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void gaussianGradient(SrcIterator supperleft, void gaussianGradient(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIteratorX dupperleftx, DestAccessorX dax, DestIteratorX dupperleftx, DestAccessorX dax,
DestIteratorY dupperlefty, DestAccessorY day, DestIteratorY dupperlefty, DestAccessorY day,
skipping to change at line 643 skipping to change at line 919
// write x and y component of the gradient into a vector-valued ima ge // write x and y component of the gradient into a vector-valued ima ge
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianGradient(SrcIterator supperleft, void gaussianGradient(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor src, SrcIterator slowerright, SrcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale); double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// write x and y component of the gradient into separate images // write x and y component of the gradient into separate images
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void void
gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src, gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIteratorX, DestAccessorX> destx, pair<DestIteratorX, DestAccessorX> destx,
skipping to change at line 666 skipping to change at line 941
// write x and y component of the gradient into a vector-valued ima ge // write x and y component of the gradient into a vector-valued ima ge
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src, gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale); double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), gradx(w,h), grady(w,h);
...
// calculate gradient vector at scale = 3.0
gaussianGradient(src, gradx, grady, 3.0);
// likewise, but use a vector image to store the gradient
MultiArray<2, TinyVector<float, 2> > dest(w,h);
gaussianGradient(src, dest, 3.0);
\endcode
\deprecatedUsage{gaussianGradient}
\code \code
vigra::FImage src(w,h), gradx(w,h), grady(w,h); vigra::FImage src(w,h), gradx(w,h), grady(w,h);
... ...
// calculate gradient vector at scale = 3.0 // calculate gradient vector at scale = 3.0
vigra::gaussianGradient(srcImageRange(src), vigra::gaussianGradient(srcImageRange(src),
destImage(gradx), destImage(grady), 3.0); destImage(gradx), destImage(grady), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void gaussianGradient) doxygen_overloaded_function(template <...> void gaussianGradient)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void gaussianGradient(SrcIterator supperleft, void gaussianGradient(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIteratorX dupperleftx, DestAccessorX dax, DestIteratorX dupperleftx, DestAccessorX dax,
DestIteratorY dupperlefty, DestAccessorY day, DestIteratorY dupperlefty, DestAccessorY day,
skipping to change at line 748 skipping to change at line 1037
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src, gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
{ {
gaussianGradient(src.first, src.second, src.third, gaussianGradient(src.first, src.second, src.third,
dest.first, dest.second, scale); dest.first, dest.second, scale);
} }
template <class T1, class S1,
class T2X, class S2X,
class T2Y, class S2Y>
inline void
gaussianGradient(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2X, S2X> destx,
MultiArrayView<2, T2Y, S2Y> desty,
double scale)
{
vigra_precondition(src.shape() == destx.shape(),
"gaussianGradient(): shape mismatch between input and output.");
gaussianGradient(srcImageRange(src),
destImage(destx), destImage(desty), scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
gaussianGradient(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TinyVector<T2, 2>, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"gaussianGradient(): shape mismatch between input and output.");
gaussianGradient(srcImageRange(src),
destImage(dest), scale);
}
/** \brief Calculate the gradient magnitude by means of a 1st derivatives o f /** \brief Calculate the gradient magnitude by means of a 1st derivatives o f
Gaussian filter. Gaussian filter.
This function calls gaussianGradient() and returns the pixel-wise magni tude of This function calls gaussianGradient() and returns the pixel-wise magni tude of
the resulting gradient vectors. If the original image has multiple band s, the resulting gradient vectors. If the original image has multiple band s,
the squared gradient magnitude is computed for each band separately, an d the the squared gradient magnitude is computed for each band separately, an d the
return value is the square root of the sum of these squared magnitudes. return value is the square root of the sum of these squared magnitudes.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use arbitrary-dimensional arrays:
\code
namespace vigra {
// pass filter scale explicitly
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOp
tions<N>());
template <unsigned int N, class MT, class S1,
class T2, class S2>
void
gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> co
nst & src,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOp
tions<N>());
// pass filter scale(s) in option object
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> const & opt);
template <unsigned int N, class MT, class S1,
class T2, class S2>
void
gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> co
nst & src,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> const & opt);
}
\endcode
Here, the input element types <tt>T1</tt> and <tt>MT</tt> can be arbitr
ary scalar types, and <tt>T1</tt>
may also be <tt>TinyVector</tt> or <tt>RGBValue</tt>. The output elemen
t type <tt>T2</tt> should
be the corresponding norm type (see \ref NormTraits "NormTraits"). In t
he <tt>Multiband<MT></tt>-version,
the input array's right-most dimension is interpreted as a channel axis
, therefore it must
have one dimension more than the output array.
\deprecatedAPI{gaussianGradientMagnitude}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianGradientMagnitude(SrcIterator sul, void gaussianGradientMagnitude(SrcIterator sul,
SrcIterator slr, SrcAccessor src, SrcIterator slr, SrcAccessor src,
DestIterator dupperleft, DestAccesso r dest, DestIterator dupperleft, DestAccesso r dest,
double scale); double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAcces sor> src, gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAcces sor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale); double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\> (or \<vigra/convolutio
n.hxx\> to use the old API)<br/>
Namespace: vigra
\code
// example 1
{
// use a 3-dimensional float array
MultiArray<3, float> volume(Shape3(w, h, d)), grad(volume.shape());
...
// calculate gradient magnitude at scale = 3.0
gaussianGradientMagnitude(volume, grad, 3.0);
}
// example 2
{
// use a 2-dimensional RGB array
MultiArray<2, RGBValue<float> > rgb(Shape2(w, h));
MultiArray<2, float> grad(rgb.shape());
...
// calculate the color gradient magnitude at scale = 3.0
gaussianGradientMagnitude(rgb, grad, 3.0);
}
// example 3
{
// use a 3-dimensional array whose right-most axis is interpreted a
s
// a multi-spectral axis with arbitrary many channels
MultiArray<3, Multiband<float> > spectral(Shape3(w, h, channelCount
));
MultiArray<2, float> grad(Shape2(w, h));
...
// calculate the multi-channel gradient magnitude at scale = 3.0
// (note that the template parameter N (number of spatial dimension
s)
// must be provided explicitly as gaussianGradientMagnitude<2>(...
) )
MultiArrayView<3, Multiband<float> > view(spectral);
gaussianGradientMagnitude<2>(view, grad, 3.0);
}
\endcode
\deprecatedUsage{gaussianGradientMagnitude}
\code \code
vigra::FImage src(w,h), grad(w,h); // use a traditional float or RGB image
FImage image(w, h), grad(w, h);
FRGBImage rgb(w, h);
... ...
// calculate gradient magnitude at scale = 3.0 // calculate gradient magnitude at scale = 3.0
vigra::gaussianGradientMagnitude(srcImageRange(src), destImage(grad), 3 .0); gaussianGradientMagnitude(srcImageRange(image), destImage(grad), 3.0);
// calculate color gradient magnitude at scale = 3.0
gaussianGradientMagnitude(srcImageRange(rgb), destImage(grad), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void gaussianGradientMagnitude) doxygen_overloaded_function(template <...> void gaussianGradientMagnitude)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gaussianGradientMagnitude(SrcIterator sul, void gaussianGradientMagnitude(SrcIterator sul,
SrcIterator slr, SrcAccessor src, SrcIterator slr, SrcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double scale) double scale)
{ {
skipping to change at line 838 skipping to change at line 1242
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Filter image with the Laplacian of Gaussian operator /** \brief Filter image with the Laplacian of Gaussian operator
at the given scale. at the given scale.
This function calls \ref separableConvolveX() and \ref separableConvolv eY() with the appropriate 2nd derivative This function calls \ref separableConvolveX() and \ref separableConvolv eY() with the appropriate 2nd derivative
of Gaussian kernels in x- and y-direction and then sums the results of Gaussian kernels in x- and y-direction and then sums the results
to get the Laplacian. to get the Laplacian.
Function \ref laplacianOfGaussianMultiArray() performs the same filter
operation
on arbitrary dimensional arrays.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{laplacianOfGaussian}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void laplacianOfGaussian(SrcIterator supperleft, void laplacianOfGaussian(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
double scale); double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void void
laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale); double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), dest(w,h);
...
// calculate Laplacian of Gaussian at scale = 3.0
laplacianOfGaussian(src, dest, 3.0);
\endcode
\deprecatedUsage{laplacianOfGaussian}
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// calculate Laplacian of Gaussian at scale = 3.0 // calculate Laplacian of Gaussian at scale = 3.0
vigra::laplacianOfGaussian(srcImageRange(src), destImage(dest), 3.0); vigra::laplacianOfGaussian(srcImageRange(src), destImage(dest), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void laplacianOfGaussian) doxygen_overloaded_function(template <...> void laplacianOfGaussian)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void laplacianOfGaussian(SrcIterator supperleft, void laplacianOfGaussian(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
double scale) double scale)
{ {
skipping to change at line 914 skipping to change at line 1343
separableConvolveY(srcImageRange(tmp), separableConvolveY(srcImageRange(tmp),
destImage(tmpy), kernel1d(deriv)); destImage(tmpy), kernel1d(deriv));
combineTwoImages(srcImageRange(tmpx), srcImage(tmpy), combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
destIter(dupperleft, da), std::plus<TmpType>()); destIter(dupperleft, da), std::plus<TmpType>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src, laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
{ {
laplacianOfGaussian(src.first, src.second, src.third, laplacianOfGaussian(src.first, src.second, src.third,
dest.first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"laplacianOfGaussian(): shape mismatch between input and output.");
laplacianOfGaussian(srcImageRange(src),
destImage(dest), scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* hessianMatrixOfGaussian */ /* hessianMatrixOfGaussian */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Filter image with the 2nd derivatives of the Gaussian /** \brief Filter image with the 2nd derivatives of the Gaussian
at the given scale to get the Hessian matrix. at the given scale to get the Hessian matrix.
skipping to change at line 950 skipping to change at line 1392
where \f$G_{xx}, G_{xy}, G_{yy}\f$ denote 2nd derivatives of Gaussians where \f$G_{xx}, G_{xy}, G_{yy}\f$ denote 2nd derivatives of Gaussians
at the given scale, and at the given scale, and
\f$\ast\f$ is the convolution symbol. This function calls \f$\ast\f$ is the convolution symbol. This function calls
\ref separableConvolveX() and \ref separableConvolveY() \ref separableConvolveX() and \ref separableConvolveY()
with the appropriate 2nd derivative with the appropriate 2nd derivative
of Gaussian kernels and puts the results in of Gaussian kernels and puts the results in
the three destination images. The first destination image will the three destination images. The first destination image will
contain the second derivative in x-direction, the second one the mixed contain the second derivative in x-direction, the second one the mixed
derivative, and the third one holds the derivative in y-direction. derivative, and the third one holds the derivative in y-direction.
Function \ref hessianOfGaussianMultiArray() performs the same filter op
eration
on arbitrary dimensional arrays.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TinyVector<T2, 3>, S2> de
st,
double scale);
}
\endcode
\deprecatedAPI{hessianMatrixOfGaussian}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void hessianMatrixOfGaussian(SrcIterator supperleft, void hessianMatrixOfGaussian(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIteratorX dupperleftx, DestAccessorX da x, DestIteratorX dupperleftx, DestAccessorX da x,
DestIteratorXY dupperleftxy, DestAccessorXY daxy, DestIteratorXY dupperleftxy, DestAccessorXY daxy,
DestIteratorY dupperlefty, DestAccessorY da y, DestIteratorY dupperlefty, DestAccessorY da y,
double scale); double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
inline void void
hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccesso r> src, hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
pair<DestIteratorX, DestAccessorX> destx, pair<DestIteratorX, DestAccessorX> destx,
pair<DestIteratorXY, DestAccessorXY> destxy, pair<DestIteratorXY, DestAccessorXY> destxy,
pair<DestIteratorY, DestAccessorY> desty, pair<DestIteratorY, DestAccessorY> desty,
double scale); double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code \code
vigra::FImage src(w,h), hxx(w,h), hxy(w,h), hyy(w,h); MultiArray<2, float> src(w,h);
MultiArray<2, TinyVector<float, 3> > hessian(w,h); // will hold the t
hree components of the Hessian
... ...
// calculate Hessian of Gaussian at scale = 3.0 // calculate Hessian of Gaussian at scale = 3.0, use a 3-band output im
vigra::hessianMatrixOfGaussian(srcImageRange(src), age
destImage(hxx), destImage(hxy), destImage(hyy), 3.0); hessianMatrixOfGaussian(src, hessian, 3.0);
\endcode \endcode
\deprecatedUsage{hessianMatrixOfGaussian}
\code
vigra::FImage src(w,h),
hxx(w,h), hxy(w,h), hyy(w,h); // use a separate image for
each component of the Hessian
...
// calculate Hessian of Gaussian at scale = 3.0, use 3 single.band outp
ut images
vigra::hessianMatrixOfGaussian(srcImageRange(src),
destImage(hxx), destImage(hxy), destImag
e(hyy), 3.0);
\endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void hessianMatrixOfGaussian) doxygen_overloaded_function(template <...> void hessianMatrixOfGaussian)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void hessianMatrixOfGaussian(SrcIterator supperleft, void hessianMatrixOfGaussian(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIteratorX dupperleftx, DestAccessorX dax, DestIteratorX dupperleftx, DestAccessorX dax,
skipping to change at line 1042 skipping to change at line 1511
separableConvolveY(srcImageRange(tmp), separableConvolveY(srcImageRange(tmp),
destIter(dupperleftxy, daxy), kernel1d(deriv1)); destIter(dupperleftxy, daxy), kernel1d(deriv1));
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
inline void inline void
hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src, hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIteratorX, DestAccessorX> destx, pair<DestIteratorX, DestAccessorX> destx,
pair<DestIteratorXY, DestAccessorXY> destxy, pair<DestIteratorXY, DestAccessorXY> destxy,
pair<DestIteratorY, DestAccessorY> desty, pair<DestIteratorY, DestAccessorY> desty,
double scale) double scale)
{ {
hessianMatrixOfGaussian(src.first, src.second, src.third, hessianMatrixOfGaussian(src.first, src.second, src.third,
destx.first, destx.second, destx.first, destx.second,
destxy.first, destxy.second, destxy.first, destxy.second,
desty.first, desty.second, desty.first, desty.second,
scale); scale);
}
template <class T1, class S1,
class T2X, class S2X,
class T2XY, class S2XY,
class T2Y, class S2Y>
inline void
hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2X, S2X> destx,
MultiArrayView<2, T2XY, S2XY> destxy,
MultiArrayView<2, T2Y, S2Y> desty,
double scale)
{
vigra_precondition(src.shape() == destx.shape() && src.shape() == destx
y.shape() && src.shape() == desty.shape(),
"hessianMatrixOfGaussian(): shape mismatch between input and output
.");
hessianMatrixOfGaussian(srcImageRange(src),
destImage(destx),
destImage(destxy),
destImage(desty),
scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"hessianMatrixOfGaussian(): shape mismatch between input and output
.");
MultiArrayView<3, T2> expanded(dest.expandElements(0));
hessianMatrixOfGaussian(srcImageRange(src),
destImage(expanded.bind<0>(0)),
destImage(expanded.bind<0>(1)),
destImage(expanded.bind<0>(2)),
scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* structureTensor */ /* structureTensor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the Structure Tensor for each pixel of /** \brief Calculate the Structure Tensor for each pixel of
and image, using Gaussian (derivative) filters. and image, using Gaussian (derivative) filters.
skipping to change at line 1091 skipping to change at line 1599
products of the 1st derivative images. This function calls products of the 1st derivative images. This function calls
\ref separableConvolveX() and \ref separableConvolveY() with the \ref separableConvolveX() and \ref separableConvolveY() with the
appropriate Gaussian kernels and puts the results in appropriate Gaussian kernels and puts the results in
the three separate destination images (where the first one will the three separate destination images (where the first one will
contain \f$G \ast (I_x I_x)\f$, the second one \f$G \ast (I_x I_y)\f$, and the contain \f$G \ast (I_x I_x)\f$, the second one \f$G \ast (I_x I_y)\f$, and the
third one holds \f$G \ast (I_y I_y)\f$), or into a single 3-band image (where the bands third one holds \f$G \ast (I_y I_y)\f$), or into a single 3-band image (where the bands
hold the result in the same order as above). The latter form is also ap plicable when hold the result in the same order as above). The latter form is also ap plicable when
the source image is a multi-band image (e.g. RGB). In this case, tensor s are the source image is a multi-band image (e.g. RGB). In this case, tensor s are
first computed for each band separately, and then summed up to get a si ngle result tensor. first computed for each band separately, and then summed up to get a si ngle result tensor.
Function \ref structureTensorMultiArray() performs the same filter oper
ation
on arbitrary dimensional arrays.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// create three separate destination images
template <class T, class S,
class TX, class SX,
class TXY, class SXY,
class TY, class SY>
void
structureTensor(MultiArrayView<2, S, T> const & src,
MultiArrayView<2, TX, SX> destx,
MultiArrayView<2, TXY, SXY> destxy,
MultiArrayView<2, TY, SY> desty,
double inner_scale, double outer_scale);
// create a single 3-band destination image
template <class T1, class S1,
class T2, class S2>
void
structureTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
double inner_scale, double outer_scale);
}
\endcode
\deprecatedAPI{structureTensor}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// create three separate destination images // create three separate destination images
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void structureTensor(SrcIterator supperleft, void structureTensor(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIteratorX dupperleftx, DestAccessorX da x, DestIteratorX dupperleftx, DestAccessorX da x,
skipping to change at line 1117 skipping to change at line 1654
// create a single 3-band destination image // create a single 3-band destination image
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void structureTensor(SrcIterator supperleft, void structureTensor(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
double inner_scale, double outer_scale); double inner_scale, double outer_scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// create three separate destination images // create three separate destination images
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void void
structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src, structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
skipping to change at line 1142 skipping to change at line 1678
// create a single 3-band destination image // create a single 3-band destination image
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src, structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double nner_scale, double outer_scale); double nner_scale, double outer_scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/convolution.hxx\> <b>\#include</b> \<vigra/convolution.hxx\><br/>
Namespace: vigra
\code \code
vigra::FImage src(w,h), stxx(w,h), stxy(w,h), styy(w,h); MultiArray<2, flost> src(w,h),
vigra::BasicImage<TinyVector<float, 3> > st(w,h); stxx(w,h), stxy(w,h), styy(w,h); // use a separat
e image for each component
... ...
// calculate Structure Tensor at inner scale = 1.0 and outer scale = 3. 0 // calculate Structure Tensor at inner scale = 1.0 and outer scale = 3. 0
structureTensor(src, stxx, stxy, styy, 1.0, 3.0);
// likwise with a single 3-band destination image
MultiArray<2, TinyVector<float, 3> > st(w,h);
structureTensor(src, st, 1.0, 3.0);
\endcode
\deprecatedUsage{structureTensor}
\code
vigra::FImage src(w,h),
stxx(w,h), stxy(w,h), styy(w,h);
vigra::BasicImage<TinyVector<float, 3> > st(w,h);
...
vigra::structureTensor(srcImageRange(src), vigra::structureTensor(srcImageRange(src),
destImage(stxx), destImage(stxy), destImage(styy), 1.0, 3.0); destImage(stxx), destImage(stxy), destImage(styy ), 1.0, 3.0);
// dto. with a single 3-band destination image
vigra::structureTensor(srcImageRange(src), destImage(st), 1.0, 3.0); vigra::structureTensor(srcImageRange(src), destImage(st), 1.0, 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void structureTensor) doxygen_overloaded_function(template <...> void structureTensor)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIteratorX, class DestAccessorX, class DestIteratorX, class DestAccessorX,
class DestIteratorXY, class DestAccessorXY, class DestIteratorXY, class DestAccessorXY,
class DestIteratorY, class DestAccessorY> class DestIteratorY, class DestAccessorY>
void structureTensor(SrcIterator supperleft, void structureTensor(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIteratorX dupperleftx, DestAccessorX dax, DestIteratorX dupperleftx, DestAccessorX dax,
skipping to change at line 1216 skipping to change at line 1766
pair<DestIteratorY, DestAccessorY> desty, pair<DestIteratorY, DestAccessorY> desty,
double inner_scale, double outer_scale) double inner_scale, double outer_scale)
{ {
structureTensor(src.first, src.second, src.third, structureTensor(src.first, src.second, src.third,
destx.first, destx.second, destx.first, destx.second,
destxy.first, destxy.second, destxy.first, destxy.second,
desty.first, desty.second, desty.first, desty.second,
inner_scale, outer_scale); inner_scale, outer_scale);
} }
template <class T, class S,
class TX, class SX,
class TXY, class SXY,
class TY, class SY>
inline void
structureTensor(MultiArrayView<2, S, T> const & src,
MultiArrayView<2, TX, SX> destx,
MultiArrayView<2, TXY, SXY> destxy,
MultiArrayView<2, TY, SY> desty,
double inner_scale, double outer_scale)
{
vigra_precondition(src.shape() == destx.shape(),
"structureTensor(): shape mismatch between input and output.");
structureTensor(srcImageRange(src),
destImage(destx), destImage(destxy), destImage(desty),
inner_scale, outer_scale);
}
namespace detail { namespace detail {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void structureTensor(SrcIterator supperleft, void structureTensor(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor src, SrcIterator slowerright, SrcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
double inner_scale, double outer_scale, double inner_scale, double outer_scale,
VigraTrueType /* isScalar */) VigraTrueType /* isScalar */)
{ {
skipping to change at line 1281 skipping to change at line 1849
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar; NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar;
detail::structureTensor(supperleft, slowerright, src, detail::structureTensor(supperleft, slowerright, src,
dupperleft, dest, inner_scale, outer_scale, isS calar()); dupperleft, dest, inner_scale, outer_scale, isS calar());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src, structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double inner_scale, double outer_scale) double inner_scale, double outer_scale)
{ {
structureTensor(src.first, src.second, src.third, structureTensor(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
inner_scale, outer_scale); inner_scale, outer_scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
structureTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
double inner_scale, double outer_scale)
{
vigra_precondition(src.shape() == dest.shape(),
"structureTensor(): shape mismatch between input and output.");
structureTensor(srcImageRange(src),
destImage(dest),
inner_scale, outer_scale);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_CONVOLUTION_HXX #endif // VIGRA_CONVOLUTION_HXX
 End of changes. 110 change blocks. 
118 lines changed or deleted 747 lines changed or added


 coordinate_iterator.hxx   coordinate_iterator.hxx 
skipping to change at line 124 skipping to change at line 124
} }
MultiArrayIndex & idx0() MultiArrayIndex & idx0()
{ {
return index[0]; return index[0];
} }
const index_type & idx() const const index_type & idx() const
{ {
return index; return index;
} }
double & dim0() double & dim0()
{ {
return coord[0]; return coord[0];
} }
double dim0() const double dim0() const
{ {
return coord[0]; return coord[0];
} }
}; };
skipping to change at line 386 skipping to change at line 387
protected: protected:
double stride_0; double stride_0;
CoordinateStride(void*) {} // used MultiIterator ctor, unused. CoordinateStride(void*) {} // used MultiIterator ctor, unused.
public: public:
CoordinateStride(const S & x, double s0) CoordinateStride(const S & x, double s0)
: S(x), stride_0(s0) {} : S(x), stride_0(s0) {}
#ifndef DOXYGEN
using S::operator*; using S::operator*;
using S::idx0; using S::idx0;
using S::idx; using S::idx;
using S::dim0; using S::dim0;
using S::operator+=; using S::operator+=;
using S::operator-=; using S::operator-=;
#endif
void operator++() void operator++()
{ {
++idx0(); ++idx0();
dim0() += stride_0; dim0() += stride_0;
} }
void operator--() void operator--()
{ {
--idx0(); --idx0();
dim0() -= stride_0; dim0() -= stride_0;
 End of changes. 3 change blocks. 
0 lines changed or deleted 3 lines changed or added


 copyimage.hxx   copyimage.hxx 
skipping to change at line 40 skipping to change at line 40
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_COPYIMAGE_HXX #ifndef VIGRA_COPYIMAGE_HXX
#define VIGRA_COPYIMAGE_HXX #define VIGRA_COPYIMAGE_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup CopyAlgo Algorithms to Copy Images /** \addtogroup CopyAlgo Algorithms to Copy Images
Copy images or regions Copy images or regions
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
skipping to change at line 103 skipping to change at line 104
/********************************************************/ /********************************************************/
/* */ /* */
/* copyImage */ /* copyImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Copy source image into destination image. /** \brief Copy source image into destination image.
If necessary, type conversion takes place. If necessary, type conversion takes place.
The function uses accessors to access the pixel data. Some variants of this function use accessors to access the pixel data.
See \ref copyMultiArray() for a dimension-independent version of this a
lgorithm.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
copyImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest);
}
\endcode
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
copyImage(SrcImageIterator src_upperleft, copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowe
SrcImageIterator src_lowerright, SrcAccessor sa, rright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccessor da) DestImageIterator dest_upperleft, DestAccessor da)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
copyImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> s rc, copyImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> s rc,
pair<DestImageIterator, DestAccessor> dest) pair<DestImageIterator, DestAccessor> dest)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/copyimage.hxx\><br> <b>\#include</b> \<vigra/copyimage.hxx\><br>
Namespace: vigra Namespace: vigra
Use MultiArrayView API:
\code \code
vigra::copyImage(srcImageRange(src), destImage(dest)); MultiArray<2, int> src(Shape2(100, 200)),
dest(Shape2(100, 200));
...
copyImage(src, dest);
// equivalent to
dest = src;
\endcode
Use iterator-based API with accessor:
\code
MultiArray<2, RGBValue<unsigned char> > src(Shape2(100, 200)),
MultiArray<2, float> dest(Shape2(100, 200));
// convert RGB to gray values in the fly
copyImage(srcImageRange(src, RGBToGrayAccessor<RGBValue<unsigned char>
>()),
destImage(dest));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcImageIterator::row_iterator sx = src_upperleft.rowIterator(); SrcImageIterator::row_iterator sx = src_upperleft.rowIterator();
DestImageIterator::row_iterator dx = dest_upperleft.rowIterator(); DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
dest_accessor.set(src_accessor(sx), dx); dest_accessor.set(src_accessor(sx), dx);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void copyImage) doxygen_overloaded_function(template <...> void copyImage)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
copyImage(SrcImageIterator src_upperleft, copyImage(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccessor da) DestImageIterator dest_upperleft, DestAccessor da)
{ {
skipping to change at line 180 skipping to change at line 207
src_upperleft.rowIterator() + w, sa, src_upperleft.rowIterator() + w, sa,
dest_upperleft.rowIterator(), da); dest_upperleft.rowIterator(), da);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline inline
void void
copyImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, copyImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest) pair<DestImageIterator, DestAccessor> dest)
{ {
copyImage(src.first, src.second, src.third, copyImage(src.first, src.second, src.third,
dest.first, dest.second); dest.first, dest.second);
}
template <class T1, class S1,
class T2, class S2>
inline void
copyImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{
vigra_precondition(src.shape() == dest.shape(),
"copyImage(): shape mismatch between input and output.");
copyImage(srcImageRange(src), destImage(dest));
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
swapImageData(SrcImageIterator src_upperleft, swapImageData(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccessor da) DestImageIterator dest_upperleft, DestAccessor da)
{ {
int w = src_lowerright.x - src_upperleft.x; int w = src_lowerright.x - src_upperleft.x;
skipping to change at line 214 skipping to change at line 252
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline inline
void void
swapImageData(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, swapImageData(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest) pair<DestImageIterator, DestAccessor> dest)
{ {
swapImageData(src.first, src.second, src.third, swapImageData(src.first, src.second, src.third,
dest.first, dest.second); dest.first, dest.second);
} }
template <class T1, class S1,
class T2, class S2>
inline
void
swapImageData(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{
vigra_precondition(src.shape() == dest.shape(),
"swapImageData(): shape mismatch between input and output.");
swapImageData(srcImageRange(src), destImage(dest));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* copyImageIf */ /* copyImageIf */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Copy source ROI into destination image. /** \brief Copy source ROI into destination image.
Pixel values are copied whenever the return value of the mask's Pixel values are copied whenever the return value of the mask's
accessor is not zero. accessor is not zero.
If necessary, type conversion takes place. If necessary, type conversion takes place.
The function uses accessors to access the pixel data. Some variants of this function use accessors to access the pixel data.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
void
copyImageIf(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest);
}
\endcode
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, clas DestAccessor> class DestImageIterator, clas DestAccessor>
void void
copyImageIf(SrcImageIterator src_upperleft, copyImageIf(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
DestImageIterator dest_upperleft, DestAccessor da) DestImageIterator dest_upperleft, DestAccessor da)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, clas DestAccessor> class DestImageIterator, clas DestAccessor>
void void
copyImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, copyImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
pair<DestImageIterator, DestAccessor> dest) pair<DestImageIterator, DestAccessor> dest)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/copyimage.hxx\><br> <b>\#include</b> \<vigra/copyimage.hxx\><br>
Namespace: vigra Namespace: vigra
Use MultiArrayView API:
\code \code
vigra::copyImageIf(srcImageRange(src), maskImage(mask), destImage(dest) MultiArray<2, int> src(Shape2(100, 200)),
); mask(Shape2(100, 200)),
dest(Shape2(100, 200));
...
copyImageIf(src, mask, dest);
\endcode
Use iterator-based API with accessor:
\code
MultiArray<2, RGBValue<unsigned char> > src(Shape2(100, 200)),
MultiArray<2, unsigned char> mask(Shape2(100, 200));
MultiArray<2, float> dest(Shape2(100, 200));
// convert RGB to gray values in the fly
copyImageIf(srcImageRange(src, RGBToGrayAccessor<RGBValue<unsigned char
> >()),
maskImage(mask), destImage(dest));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
MaskImageIterator mask_upperleft; MaskImageIterator mask_upperleft;
SrcImageIterator::row_iterator sx = src_upperleft.rowIterator(); SrcImageIterator::row_iterator sx = src_upperleft.rowIterator();
MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator(); MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
skipping to change at line 285 skipping to change at line 363
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
MaskAccessor mask_accessor; MaskAccessor mask_accessor;
Functor functor; Functor functor;
if(mask_accessor(mx)) if(mask_accessor(mx))
dest_accessor.set(src_accessor(sx), dx); dest_accessor.set(src_accessor(sx), dx);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void copyImageIf) doxygen_overloaded_function(template <...> void copyImageIf)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
copyImageIf(SrcImageIterator src_upperleft, copyImageIf(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
skipping to change at line 316 skipping to change at line 393
dest_upperleft.rowIterator(), da); dest_upperleft.rowIterator(), da);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline inline
void void
copyImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, copyImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
pair<DestImageIterator, DestAccessor> dest) pair<DestImageIterator, DestAccessor> dest)
{ {
copyImageIf(src.first, src.second, src.third, copyImageIf(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second); dest.first, dest.second);
}
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
inline void
copyImageIf(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"copyImageIf(): shape mismatch between input and output.");
copyImageIf(srcImageRange(src),
maskImage(mask),
destImage(dest));
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_COPYIMAGE_HXX #endif // VIGRA_COPYIMAGE_HXX
 End of changes. 27 change blocks. 
26 lines changed or deleted 122 lines changed or added


 cornerdetection.hxx   cornerdetection.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_CORNERDETECTION_HXX #ifndef VIGRA_CORNERDETECTION_HXX
#define VIGRA_CORNERDETECTION_HXX #define VIGRA_CORNERDETECTION_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
#include "convolution.hxx" #include "convolution.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
template <class SrcType> template <class SrcType>
struct CornerResponseFunctor struct CornerResponseFunctor
{ {
typedef typename NumericTraits<SrcType>::RealPromote argument_type; typedef typename NumericTraits<SrcType>::RealPromote argument_type;
typedef argument_type result_type; typedef argument_type result_type;
result_type operator()(argument_type a1, result_type operator()(argument_type a1,
skipping to change at line 172 skipping to change at line 173
The local maxima of the corner response denote the corners in the gray level The local maxima of the corner response denote the corners in the gray level
image. image.
The source value type must be a linear algebra, i.e. addition, subtract ion, and The source value type must be a linear algebra, i.e. addition, subtract ion, and
multiplication with itself, multiplication with doubles and multiplication with itself, multiplication with doubles and
\ref NumericTraits "NumericTraits" must \ref NumericTraits "NumericTraits" must
be defined. be defined.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
cornerResponseFunction(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{cornerResponseFunction}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
cornerResponseFunction(SrcIterator sul, SrcIterator slr, SrcAccesso r as, cornerResponseFunction(SrcIterator sul, SrcIterator slr, SrcAccesso r as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline
void cornerResponseFunction( void cornerResponseFunction(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/cornerdetection.hxx\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), corners(w,h);
MultiArray<2, float> corner_response(w,h);
...
// find corner response at scale 1.0
cornerResponseFunction(src, corner_response, 1.0);
// find local maxima of corner response, mark with 1
localMaxima(corner_response, corners);
// threshold corner response to keep only strong corners (above 400.0)
transformImage(corner_response, corner_response,
Threshold<double, double>(400.0, std::numeric_limits<dou
ble>::max(), 0.0, 1.0));
// combine thresholding and local maxima
combineTwoImages(corners, corner_response,
corners, std::multiplies<float>());
\endcode
\deprecatedUsage{cornerResponseFunction}
\code
vigra::BImage src(w,h), corners(w,h); vigra::BImage src(w,h), corners(w,h);
vigra::FImage corner_response(w,h); vigra::FImage corner_response(w,h);
// empty corner image // empty corner image
corners.init(0.0); corners.init(0.0);
... ...
// find corner response at scale 1.0 // find corner response at scale 1.0
vigra::cornerResponseFunction(srcImageRange(src), destImage(corner_resp onse), vigra::cornerResponseFunction(srcImageRange(src), destImage(corner_resp onse),
1.0); 1.0);
skipping to change at line 226 skipping to change at line 260
// threshold corner response to keep only strong corners (above 400.0) // threshold corner response to keep only strong corners (above 400.0)
transformImage(srcImageRange(corner_response), destImage(corner_respons e), transformImage(srcImageRange(corner_response), destImage(corner_respons e),
vigra::Threshold<double, double>( vigra::Threshold<double, double>(
400.0, std::numeric_limits<double>::max(), 0.0, 1.0)); 400.0, std::numeric_limits<double>::max(), 0.0, 1.0));
// combine thresholding and local maxima // combine thresholding and local maxima
vigra::combineTwoImages(srcImageRange(corners), srcImage(corner_respons e), vigra::combineTwoImages(srcImageRange(corners), srcImage(corner_respons e),
destImage(corners), std::multiplies<float>()); destImage(corners), std::multiplies<float>());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
double d; double d;
u = u + u u = u + u
u = u - u u = u - u
u = u * u u = u * u
u = d * u u = d * u
dest_accessor.set(u, dest_upperleft); dest_accessor.set(u, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void cornerResponseFunction) doxygen_overloaded_function(template <...> void cornerResponseFunction)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
cornerResponseFunction(SrcIterator sul, SrcIterator slr, SrcAccessor as, cornerResponseFunction(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 295 skipping to change at line 328
void cornerResponseFunction( void cornerResponseFunction(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
{ {
cornerResponseFunction(src.first, src.second, src.third, cornerResponseFunction(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale); scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
cornerResponseFunction(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"cornerResponseFunction(): shape mismatch between input and output.
");
cornerResponseFunction(srcImageRange(src), destImage(dest), scale);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* foerstnerCornerDetector */ /* foerstnerCornerDetector */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find corners in an image (2). /** \brief Find corners in an image (2).
This algorithm implements the so called 'Foerstner Corner Detector' This algorithm implements the so called 'Foerstner Corner Detector'
to measure the 'cornerness' of each pixel in the image, according to to measure the 'cornerness' of each pixel in the image, according to
[W. F&ouml;rstner: <em> "A feature based correspondence algorithms for image [W. F&ouml;rstner: <em> "A feature based correspondence algorithms for image
matching"</em>, Intl. Arch. Photogrammetry and Remote Sensing, vol. 24, pp 160-166, matching"</em>, Intl. Arch. Photogrammetry and Remote Sensing, vol. 24, pp 160-166,
1986]. It is also known as the "Plessey Detector" by Harris. However, i t should not 1986]. It is also known as the "Plessey Detector" by Harris. However, i t should not
be confused with the be confused with the
"\link cornerResponseFunction Corner Response Function\endlink ", "\link cornerResponseFunction Corner Response Function\endlink ",
another detector invented by Harris. another detector invented by Harris.
The algorithm first determines the structure tensor at each pixel by ca lling The algorithm first determines the structure tensor at each pixel by ca lling
\ref structureTensor(). Then the entries of the structure tensor are co \ref structureTensor(), where the given scale is used for both the inne
mbined as r and outer scales.
Then the entries of the structure tensor are combined as
\f[ \f[
\mbox{\rm FoerstnerCornerStrength} = \frac{\mbox{\rm det(StructureT ensor)}}{\mbox{\rm tr(StructureTensor)}} = \mbox{\rm FoerstnerCornerStrength} = \frac{\mbox{\rm det(StructureT ensor)}}{\mbox{\rm tr(StructureTensor)}} =
\frac{A B - C^2}{A + B} \frac{A B - C^2}{A + B}
\f] \f]
The local maxima of the corner strength denote the corners in the gray level The local maxima of the corner strength denote the corners in the gray level
image. Its performance is similar to the \ref cornerResponseFunction(). image. Its performance is similar to the \ref cornerResponseFunction().
The source value type must be a division algebra, i.e. addition, subtra ction, The source value type must be a division algebra, i.e. addition, subtra ction,
multiplication, and division with itself, multiplication with doubles a nd multiplication, and division with itself, multiplication with doubles a nd
\ref NumericTraits "NumericTraits" must \ref NumericTraits "NumericTraits" must
be defined. be defined.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
foerstnerCornerDetector(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{foerstnerCornerDetector}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
foerstnerCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccess or as, foerstnerCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccess or as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void foerstnerCornerDetector(
void foerstnerCornerDetector(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/cornerdetection.hxx\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), corners(w,h);
MultiArray<2, float> foerstner_corner_strength(w,h);
...
// find corner response at scale 1.0
foerstnerCornerDetector(src, foerstner_corner_strength, 1.0);
// find local maxima of corner response, mark with 1
localMaxima(foerstner_corner_strength, corners);
\endcode
\deprecatedUsage{foerstnerCornerDetector}
\code
vigra::BImage src(w,h), corners(w,h); vigra::BImage src(w,h), corners(w,h);
vigra::FImage foerstner_corner_strength(w,h); vigra::FImage foerstner_corner_strength(w,h);
// empty corner image // empty corner image
corners.init(0.0); corners.init(0.0);
... ...
// find corner response at scale 1.0 // find corner response at scale 1.0
vigra::foerstnerCornerDetector(srcImageRange(src), destImage(foerstner_ corner_strength), vigra::foerstnerCornerDetector(srcImageRange(src), destImage(foerstner_ corner_strength),
1.0); 1.0);
// find local maxima of corner response, mark with 1 // find local maxima of corner response, mark with 1
vigra::localMaxima(srcImageRange(foerstner_corner_strength), destImage( corners)); vigra::localMaxima(srcImageRange(foerstner_corner_strength), destImage( corners));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
double d; double d;
u = u + u u = u + u
u = u - u u = u - u
u = u * u u = u * u
u = u / u u = u / u
u = d * u u = d * u
dest_accessor.set(u, dest_upperleft); dest_accessor.set(u, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void foerstnerCornerDetector) doxygen_overloaded_function(template <...> void foerstnerCornerDetector)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
foerstnerCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as, foerstnerCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 434 skipping to change at line 504
destImage(gx), destImage(gxy), destImage(gy), destImage(gx), destImage(gxy), destImage(gy),
scale, scale); scale, scale);
FoerstnerCornerFunctor<typename SrcAccessor::value_type > cf; FoerstnerCornerFunctor<typename SrcAccessor::value_type > cf;
combineThreeImages(srcImageRange(gx), srcImage(gy), srcImage(gxy), combineThreeImages(srcImageRange(gx), srcImage(gy), srcImage(gxy),
destIter(dul, ad), cf ); destIter(dul, ad), cf );
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void foerstnerCornerDetector( foerstnerCornerDetector(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, double scale)
double scale)
{ {
foerstnerCornerDetector(src.first, src.second, src.third, foerstnerCornerDetector(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale); scale);
} }
template <class T1, class S1,
class T2, class S2>
inline void
foerstnerCornerDetector(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"foerstnerCornerDetector(): shape mismatch between input and output
.");
foerstnerCornerDetector(srcImageRange(src),
destImage(dest),
scale);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* rohrCornerDetector */ /* rohrCornerDetector */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find corners in an image (3). /** \brief Find corners in an image (3).
This algorithm implements yet another structure tensor-based corner det ector, This algorithm implements yet another structure tensor-based corner det ector,
according to [K. Rohr: <em>"Untersuchung von grauwertabh&auml;ngigen according to [K. Rohr: <em>"Untersuchung von grauwertabh&auml;ngigen
Transformationen zur Ermittlung der optischen Flusses in Bildfolgen"</e m>, Transformationen zur Ermittlung der optischen Flusses in Bildfolgen"</e m>,
Diploma thesis, Inst. f&uuml;r Nachrichtensysteme, Univ. Karlsruhe, 198 7, see also Diploma thesis, Inst. f&uuml;r Nachrichtensysteme, Univ. Karlsruhe, 198 7, see also
K. Rohr: <em>"Modelling and Identification of Characteristic Intensity Variations"</em>, K. Rohr: <em>"Modelling and Identification of Characteristic Intensity Variations"</em>,
Image and Vision Computing 10:2 (1992) 66-76 and K. Rohr: <em>"Localiza tion Properties of Image and Vision Computing 10:2 (1992) 66-76 and K. Rohr: <em>"Localiza tion Properties of
Direct Corner Detectors"</em>, J. of Mathematical Imaging and Vision 4: 2 (1994) 139-150]. Direct Corner Detectors"</em>, J. of Mathematical Imaging and Vision 4: 2 (1994) 139-150].
The algorithm first determines the structure tensor at each pixel by ca lling The algorithm first determines the structure tensor at each pixel by ca lling
\ref structureTensor(). Then the entries of the structure tensor are co \ref structureTensor(), where the given scale is used for both the inne
mbined as r and outer scales.
Then the entries of the structure tensor are combined as
\f[ \f[
\mbox{\rm RohrCornerStrength} = \mbox{\rm det(StructureTensor)} = A B - C^2 \mbox{\rm RohrCornerStrength} = \mbox{\rm det(StructureTensor)} = A B - C^2
\f] \f]
The local maxima of the corner strength denote the corners in the gray level The local maxima of the corner strength denote the corners in the gray level
image. Its performance is similar to the \ref cornerResponseFunction(). image. Its performance is similar to the \ref cornerResponseFunction().
The source value type must be a linear algebra, i.e. addition, subtract ion, and The source value type must be a linear algebra, i.e. addition, subtract ion, and
multiplication with itself, multiplication with doubles and multiplication with itself, multiplication with doubles and
\ref NumericTraits "NumericTraits" must \ref NumericTraits "NumericTraits" must be defined.
be defined.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
rohrCornerDetector(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{rohrCornerDetector}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
rohrCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as , rohrCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as ,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline
void rohrCornerDetector( void rohrCornerDetector(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/cornerdetection.hxx\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), corners(w,h);
MultiArray<2, float> rohr_corner_strength(w,h);
...
// find corner response at scale 1.0
rohrCornerDetector(src, rohr_corner_strength, 1.0);
// find local maxima of corner response, mark with 1
localMaxima(rohr_corner_strength, corners);
\endcode
\deprecatedUsage{rohrCornerDetector}
\code
vigra::BImage src(w,h), corners(w,h); vigra::BImage src(w,h), corners(w,h);
vigra::FImage rohr_corner_strength(w,h); vigra::FImage rohr_corner_strength(w,h);
// empty corner image // empty corner image
corners.init(0.0); corners.init(0.0);
... ...
// find corner response at scale 1.0 // find corner response at scale 1.0
vigra::rohrCornerDetector(srcImageRange(src), destImage(rohr_corner_str ength), vigra::rohrCornerDetector(srcImageRange(src), destImage(rohr_corner_str ength),
1.0); 1.0);
// find local maxima of corner response, mark with 1 // find local maxima of corner response, mark with 1
vigra::localMaxima(srcImageRange(rohr_corner_strength), destImage(corne rs)); vigra::localMaxima(srcImageRange(rohr_corner_strength), destImage(corne rs));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
double d; double d;
u = u + u u = u + u
u = u - u u = u - u
u = u * u u = u * u
u = d * u u = d * u
dest_accessor.set(u, dest_upperleft); dest_accessor.set(u, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void rohrCornerDetector) doxygen_overloaded_function(template <...> void rohrCornerDetector)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
rohrCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as, rohrCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 581 skipping to change at line 688
destImage(gx), destImage(gxy), destImage(gy), destImage(gx), destImage(gxy), destImage(gy),
scale, scale); scale, scale);
RohrCornerFunctor<typename SrcAccessor::value_type > cf; RohrCornerFunctor<typename SrcAccessor::value_type > cf;
combineThreeImages(srcImageRange(gx), srcImage(gy), srcImage(gxy), combineThreeImages(srcImageRange(gx), srcImage(gy), srcImage(gxy),
destIter(dul, ad), cf ); destIter(dul, ad), cf );
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void rohrCornerDetector( rohrCornerDetector(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, double scale)
double scale)
{ {
rohrCornerDetector(src.first, src.second, src.third, rohrCornerDetector(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale); scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
rohrCornerDetector(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"rohrCornerDetector(): shape mismatch between input and output.");
rohrCornerDetector(srcImageRange(src),
destImage(dest),
scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* beaudetCornerDetector */ /* beaudetCornerDetector */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find corners in an image (4). /** \brief Find corners in an image (4).
skipping to change at line 616 skipping to change at line 736
The local maxima of the corner strength denote the corners in the gray level The local maxima of the corner strength denote the corners in the gray level
image. image.
The source value type must be a linear algebra, i.e. addition, subtract ion, and The source value type must be a linear algebra, i.e. addition, subtract ion, and
multiplication with itself, multiplication with doubles and multiplication with itself, multiplication with doubles and
\ref NumericTraits "NumericTraits" must \ref NumericTraits "NumericTraits" must
be defined. be defined.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
beaudetCornerDetector(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{beaudetCornerDetector}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
beaudetCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as, beaudetCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline
void beaudetCornerDetector( void beaudetCornerDetector(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/cornerdetection.hxx\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), corners(w,h);
MultiArray<2, float> beaudet_corner_strength(w,h);
...
// find corner response at scale 1.0
beaudetCornerDetector(src, beaudet_corner_strength, 1.0);
// find local maxima of corner response, mark with 1
localMaxima(beaudet_corner_strength, corners);
\endcode
\deprecatedUsage{beaudetCornerDetector}
\code
vigra::BImage src(w,h), corners(w,h); vigra::BImage src(w,h), corners(w,h);
vigra::FImage beaudet_corner_strength(w,h); vigra::FImage beaudet_corner_strength(w,h);
// empty corner image // empty corner image
corners.init(0.0); corners.init(0.0);
... ...
// find corner response at scale 1.0 // find corner response at scale 1.0
vigra::beaudetCornerDetector(srcImageRange(src), destImage(beaudet_corn er_strength), vigra::beaudetCornerDetector(srcImageRange(src), destImage(beaudet_corn er_strength),
1.0); 1.0);
// find local maxima of corner response, mark with 1 // find local maxima of corner response, mark with 1
vigra::localMaxima(srcImageRange(beaudet_corner_strength), destImage(co rners)); vigra::localMaxima(srcImageRange(beaudet_corner_strength), destImage(co rners));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
double d; double d;
u = u + u u = u + u
u = u - u u = u - u
u = u * u u = u * u
u = d * u u = d * u
dest_accessor.set(u, dest_upperleft); dest_accessor.set(u, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void beaudetCornerDetector) doxygen_overloaded_function(template <...> void beaudetCornerDetector)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
beaudetCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as, beaudetCornerDetector(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 719 skipping to change at line 863
destImage(gx), destImage(gxy), destImage(gy), destImage(gx), destImage(gxy), destImage(gy),
scale); scale);
BeaudetCornerFunctor<typename SrcAccessor::value_type > cf; BeaudetCornerFunctor<typename SrcAccessor::value_type > cf;
combineThreeImages(srcImageRange(gx), srcImage(gy), srcImage(gxy), combineThreeImages(srcImageRange(gx), srcImage(gy), srcImage(gxy),
destIter(dul, ad), cf ); destIter(dul, ad), cf );
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void beaudetCornerDetector( beaudetCornerDetector(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, double scale)
double scale)
{ {
beaudetCornerDetector(src.first, src.second, src.third, beaudetCornerDetector(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale); scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
beaudetCornerDetector(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"beaudetCornerDetector(): shape mismatch between input and output."
);
beaudetCornerDetector(srcImageRange(src),
destImage(dest),
scale);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_CORNERDETECTION_HXX #endif // VIGRA_CORNERDETECTION_HXX
 End of changes. 47 change blocks. 
50 lines changed or deleted 211 lines changed or added


 distancetransform.hxx   distancetransform.hxx 
skipping to change at line 41 skipping to change at line 41
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_DISTANCETRANSFORM_HXX #ifndef VIGRA_DISTANCETRANSFORM_HXX
#define VIGRA_DISTANCETRANSFORM_HXX #define VIGRA_DISTANCETRANSFORM_HXX
#include <cmath> #include <cmath>
#include "stdimage.hxx" #include "stdimage.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/* /*
* functors to determine the distance norm * functors to determine the distance norm
* these functors assume that dx and dy are positive * these functors assume that dx and dy are positive
* (this is OK for use in internalDistanceTransform()) * (this is OK for use in internalDistanceTransform())
*/ */
// chessboard metric // chessboard metric
skipping to change at line 103 skipping to change at line 104
SrcImageIterator sy = src_upperleft; SrcImageIterator sy = src_upperleft;
DestImageIterator ry = dest_upperleft; DestImageIterator ry = dest_upperleft;
FImage::Iterator xdy = xdist.upperLeft(); FImage::Iterator xdy = xdist.upperLeft();
FImage::Iterator ydy = ydist.upperLeft(); FImage::Iterator ydy = ydist.upperLeft();
SrcImageIterator sx = sy; SrcImageIterator sx = sy;
DestImageIterator rx = ry; DestImageIterator rx = ry;
FImage::Iterator xdx = xdy; FImage::Iterator xdx = xdy;
FImage::Iterator ydx = ydy; FImage::Iterator ydx = ydy;
static const Diff2D left(-1, 0); const Diff2D left(-1, 0);
static const Diff2D right(1, 0); const Diff2D right(1, 0);
static const Diff2D top(0, -1); const Diff2D top(0, -1);
static const Diff2D bottom(0, 1); const Diff2D bottom(0, 1);
int x,y; int x,y;
if(sa(sx) != background) // first pixel if(sa(sx) != background) // first pixel
{ {
*xdx = 0.0; *xdx = 0.0;
*ydx = 0.0; *ydx = 0.0;
da.set(0.0, rx); da.set(0.0, rx);
} }
else else
{ {
skipping to change at line 303 skipping to change at line 304
<li> norm == 1: use Manhattan distance (L1 norm) <li> norm == 1: use Manhattan distance (L1 norm)
<li> norm == 2: use Euclidean distance (L2 norm) <li> norm == 2: use Euclidean distance (L2 norm)
</ul> </ul>
If you use the L2 norm, the destination pixels must be real valued to g ive If you use the L2 norm, the destination pixels must be real valued to g ive
correct results. correct results.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class ValueType>
void
distanceTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
ValueType background, int norm);
}
\endcode
\deprecatedAPI{distanceTransform}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class ValueType> class ValueType>
void distanceTransform(SrcImageIterator src_upperleft, void distanceTransform(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor
DestImageIterator dest_upperleft, DestAccessor da, sa,
ValueType background, int norm) DestImageIterator dest_upperleft, DestAccess
or da,
ValueType background, int norm);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class ValueType> class ValueType>
void distanceTransform( void distanceTransform(triple<SrcImageIterator, SrcImageIterator, S
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, rcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
ValueType background, int norm) ValueType background, int norm);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/distancetransform.hxx\><br> <b>\#include</b> \<vigra/distancetransform.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(w,h);
MultiArray<2, float> distance(w, h);
...
// detect edges in src image (edges will be marked 1, background 0)
differenceOfExponentialEdgeImage(src, edges, 0.8, 4.0);
// find distance of all pixels from nearest edge
distanceTransform(edges, distance, 0, 2);
// ^ background label ^ norm (Euclide
an)
\endcode
\deprecatedUsage{distanceTransform}
\code
vigra::BImage src(w,h), edges(w,h); vigra::BImage src(w,h), edges(w,h);
vigra::FImage distance(w, h); vigra::FImage distance(w, h);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// detect edges in src image (edges will be marked 1, background 0) // detect edges in src image (edges will be marked 1, background 0)
vigra::differenceOfExponentialEdgeImage(srcImageRange(src), destImage(e dges), vigra::differenceOfExponentialEdgeImage(srcImageRange(src), destImage(e dges),
0.8, 4.0); 0.8, 4.0);
// find distance of all pixels from nearest edge // find distance of all pixels from nearest edge
vigra::distanceTransform(srcImageRange(edges), destImage(distance), vigra::distanceTransform(srcImageRange(edges), destImage(distance),
0, 2); 0, 2);
// ^ background label ^ norm (Euclidean) // ^ background label ^ norm (Euclidean)
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor sa; SrcAccessor sa;
DestAccessor da; DestAccessor da;
ValueType background; ValueType background;
float distance; float distance;
sa(src_upperleft) != background; sa(src_upperleft) != background;
da(dest_upperleft) < distance; da(dest_upperleft) < distance;
da.set(distance, dest_upperleft); da.set(distance, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void distanceTransform) doxygen_overloaded_function(template <...> void distanceTransform)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class ValueType> class ValueType>
inline void inline void
distanceTransform(SrcImageIterator src_upperleft, distanceTransform(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
skipping to change at line 404 skipping to change at line 431
} }
else else
{ {
internalDistanceTransform(src_upperleft, src_lowerright, sa, internalDistanceTransform(src_upperleft, src_lowerright, sa,
dest_upperleft, da, background, dest_upperleft, da, background,
InternalDistanceTransformLInifinityNormFu nctor()); InternalDistanceTransformLInifinityNormFu nctor());
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class ValueType> class ValueType>
inline void inline void
distanceTransform( distanceTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> s
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, rc,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
ValueType background, int norm) ValueType background, int norm)
{ {
distanceTransform(src.first, src.second, src.third, distanceTransform(src.first, src.second, src.third,
dest.first, dest.second, background, norm); dest.first, dest.second, background, norm);
} }
template <class T1, class S1,
class T2, class S2,
class ValueType>
inline void
distanceTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
ValueType background, int norm)
{
vigra_precondition(src.shape() == dest.shape(),
"distanceTransform(): shape mismatch between input and output.");
distanceTransform(srcImageRange(src),
destImage(dest), background, norm);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_DISTANCETRANSFORM_HXX #endif // VIGRA_DISTANCETRANSFORM_HXX
 End of changes. 15 change blocks. 
25 lines changed or deleted 70 lines changed or added


 edgedetection.hxx   edgedetection.hxx 
skipping to change at line 54 skipping to change at line 54
#include "stdimage.hxx" #include "stdimage.hxx"
#include "stdimagefunctions.hxx" #include "stdimagefunctions.hxx"
#include "recursiveconvolution.hxx" #include "recursiveconvolution.hxx"
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "convolution.hxx" #include "convolution.hxx"
#include "labelimage.hxx" #include "labelimage.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "pixelneighborhood.hxx" #include "pixelneighborhood.hxx"
#include "linear_solve.hxx" #include "linear_solve.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup EdgeDetection Edge Detection /** \addtogroup EdgeDetection Edge Detection
Edge detectors based on first and second derivatives, Edge detectors based on first and second derivatives,
and related post-processing. and related post-processing.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
skipping to change at line 101 skipping to change at line 102
The source value type The source value type
(<TT>SrcAccessor::value_type</TT>) must be a linear algebra, i.e. addit ion, (<TT>SrcAccessor::value_type</TT>) must be a linear algebra, i.e. addit ion,
subtraction and multiplication of the type with itself, and multiplicat ion subtraction and multiplication of the type with itself, and multiplicat ion
with double and with double and
\ref NumericTraits "NumericTraits" must \ref NumericTraits "NumericTraits" must
be defined. In addition, this type must be less-comparable. be defined. In addition, this type must be less-comparable.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
void
differenceOfExponentialEdgeImage(MultiArrayView<2, T1, S1> const &
src,
MultiArrayView<2, T2, S2> dest,
double scale,
GradValue gradient_threshold,
DestValue edge_marker = NumericTra
its<DestValue>::one());
}
\endcode
\deprecatedAPI{differenceOfExponentialEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class GradValue,
class DestValue = DestAccessor::value_type> class DestValue = DestAccessor::value_type>
void differenceOfExponentialEdgeImage( void differenceOfExponentialEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker = NumericTraits<DestValue>::one()) DestValue edge_marker = NumericTraits<DestValue>::one())
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class GradValue,
class DestValue = DestAccessor::value_type> class DestValue = DestAccessor::value_type>
void differenceOfExponentialEdgeImage( void differenceOfExponentialEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker = NumericTraits<DestValue>::one()) DestValue edge_marker = NumericTraits<DestValue>::one())
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(w,h);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1
differenceOfExponentialEdgeImage(src, edges,
0.8, 4.0, 1);
\endcode
\deprecatedUsage{differenceOfExponentialEdgeImage}
\code
vigra::BImage src(w,h), edges(w,h); vigra::BImage src(w,h), edges(w,h);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1 // find edges at scale 0.8 with gradient larger than 4.0, mark with 1
vigra::differenceOfExponentialEdgeImage(srcImageRange(src), destImage(e dges), vigra::differenceOfExponentialEdgeImage(srcImageRange(src), destImage(e dges),
0.8, 4.0, 1); 0.8, 4.0, 1);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
double d; double d;
GradValue gradient_threshold; GradValue gradient_threshold;
u = u + u u = u + u
u = u - u u = u - u
u = u * u u = u * u
u = d * u u = d * u
u < gradient_threshold u < gradient_threshold
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft); dest_accessor.set(edge_marker, dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
gradient_threshold > 0 gradient_threshold > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void differenceOfExponentialEdge Image) doxygen_overloaded_function(template <...> void differenceOfExponentialEdge Image)
skipping to change at line 217 skipping to change at line 243
recursiveSmoothX(srcIterRange(sul, slr, sa), destImage(tmp), scale / 2. 0); recursiveSmoothX(srcIterRange(sul, slr, sa), destImage(tmp), scale / 2. 0);
recursiveSmoothY(srcImageRange(tmp), destImage(tmp), scale / 2.0); recursiveSmoothY(srcImageRange(tmp), destImage(tmp), scale / 2.0);
recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale); recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale);
recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale); recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale);
typename TMPIMG::Iterator iy = smooth.upperLeft(); typename TMPIMG::Iterator iy = smooth.upperLeft();
typename TMPIMG::Iterator ty = tmp.upperLeft(); typename TMPIMG::Iterator ty = tmp.upperLeft();
DestIterator dy = dul; DestIterator dy = dul;
static const Diff2D right(1, 0); const Diff2D right(1, 0);
static const Diff2D bottom(0, 1); const Diff2D bottom(0, 1);
TMPTYPE thresh = detail::RequiresExplicitCast<TMPTYPE>::cast((gradient_ threshold * gradient_threshold) * TMPTYPE thresh = detail::RequiresExplicitCast<TMPTYPE>::cast((gradient_ threshold * gradient_threshold) *
NumericTraits<TMPTYPE>::one()); NumericTraits<TMPTYPE>::one());
TMPTYPE zero = NumericTraits<TMPTYPE>::zero(); TMPTYPE zero = NumericTraits<TMPTYPE>::zero();
for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, ++dy.y) for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, ++dy.y)
{ {
typename TMPIMG::Iterator ix = iy; typename TMPIMG::Iterator ix = iy;
typename TMPIMG::Iterator tx = ty; typename TMPIMG::Iterator tx = ty;
DestIterator dx = dy; DestIterator dx = dy;
skipping to change at line 302 skipping to change at line 328
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
double scale, GradValue gradient_threshold) double scale, GradValue gradient_threshold)
{ {
differenceOfExponentialEdgeImage(sul, slr, sa, dul, da, differenceOfExponentialEdgeImage(sul, slr, sa, dul, da,
scale, gradient_threshold, 1); scale, gradient_threshold, 1);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
inline inline void
void differenceOfExponentialEdgeImage( differenceOfExponentialEdgeImage(triple<SrcIterator, SrcIterator, SrcAccess
triple<SrcIterator, SrcIterator, SrcAccessor> src, or> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold
DestValue edge_marker) ,
DestValue edge_marker)
{ {
differenceOfExponentialEdgeImage(src.first, src.second, src.third, differenceOfExponentialEdgeImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale, gradient_threshold, scale, gradient_threshold, edge_marker
edge_marker); );
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue> class GradValue>
inline inline void
void differenceOfExponentialEdgeImage( differenceOfExponentialEdgeImage(triple<SrcIterator, SrcIterator, SrcAccess
triple<SrcIterator, SrcIterator, SrcAccessor> src, or> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold) double scale, GradValue gradient_threshold
)
{ {
differenceOfExponentialEdgeImage(src.first, src.second, src.third, differenceOfExponentialEdgeImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale, gradient_threshold, 1); scale, gradient_threshold, 1);
}
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
inline void
differenceOfExponentialEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale,
GradValue gradient_threshold,
DestValue edge_marker)
{
vigra_precondition(src.shape() == dest.shape(),
"differenceOfExponentialEdgeImage(): shape mismatch between input a
nd output.");
differenceOfExponentialEdgeImage(srcImageRange(src),
destImage(dest),
scale, gradient_threshold, edge_marker
);
}
template <class T1, class S1,
class T2, class S2,
class GradValue>
inline void
differenceOfExponentialEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale, GradValue gradient_threshold
)
{
vigra_precondition(src.shape() == dest.shape(),
"differenceOfExponentialEdgeImage(): shape mismatch between input a
nd output.");
differenceOfExponentialEdgeImage(srcImageRange(src),
destImage(dest),
scale, gradient_threshold, T2(1));
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* differenceOfExponentialCrackEdgeImage */ /* differenceOfExponentialCrackEdgeImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Detect and mark edges in a crack edge image using the Shen/Casta n zero-crossing detector. /** \brief Detect and mark edges in a crack edge image using the Shen/Casta n zero-crossing detector.
skipping to change at line 352 skipping to change at line 407
an edge point is marked (using <TT>edge_marker</TT>) in the destination image an edge point is marked (using <TT>edge_marker</TT>) in the destination image
<i>between</i> the corresponding original pixels. Topologically, this m eans we <i>between</i> the corresponding original pixels. Topologically, this m eans we
must insert additional pixels between the original ones to represent th e must insert additional pixels between the original ones to represent th e
boundaries between the pixels (the so called zero- and one-cells, with the original boundaries between the pixels (the so called zero- and one-cells, with the original
pixels being two-cells). Within VIGRA, such an image is called \ref Cra ckEdgeImage. pixels being two-cells). Within VIGRA, such an image is called \ref Cra ckEdgeImage.
To allow insertion of the zero- and one-cells, the destination image mu st have twice the To allow insertion of the zero- and one-cells, the destination image mu st have twice the
size of the original (precisely, <TT>(2*w-1)</TT> by <TT>(2*h-1)</TT> p ixels). Then the algorithm size of the original (precisely, <TT>(2*w-1)</TT> by <TT>(2*h-1)</TT> p ixels). Then the algorithm
proceeds as follows: proceeds as follows:
\code \code
sign of difference image insert zero- and one-cells resulting edge points (*) sign of difference image insert zero- and one-cells resulting e dge points (*)
+ . - . - . * . . . + . - . - . * .
+ - - . . . . . . * * * . . .
+ + - => + . + . - => . . . * . + - - . . . . . . * *
+ + + . . . . . . . . * * * .
+ . + . + . . . . . + + - => + . + . - => . . .
* .
+ + + . . . . . . . .
* *
+ . + . + . . .
. .
\endcode \endcode
Thus the edge points are marked where they actually are - in between th e pixels. Thus the edge points are marked where they actually are - in between th e pixels.
An important property of the resulting edge image is that it conforms t o the notion An important property of the resulting edge image is that it conforms t o the notion
of well-composedness as defined by Latecki et al., i.e. connected regio ns and edges of well-composedness as defined by Latecki et al., i.e. connected regio ns and edges
obtained by a subsequent \ref Labeling do not depend on obtained by a subsequent \ref Labeling do not depend on
whether 4- or 8-connectivity is used. whether 4- or 8-connectivity is used.
The non-edge pixels (<TT>.</TT>) in the destination image remain unchan ged. The non-edge pixels (<TT>.</TT>) in the destination image remain unchan ged.
The result conforms to the requirements of a \ref CrackEdgeImage. It ca n be further The result conforms to the requirements of a \ref CrackEdgeImage. It ca n be further
improved by the post-processing operations \ref removeShortEdges() and improved by the post-processing operations \ref removeShortEdges() and
\ref closeGapsInCrackEdgeImage(). \ref closeGapsInCrackEdgeImage().
The source value type (<TT>SrcAccessor::value_type</TT>) must be a line ar algebra, i.e. addition, The source value type (<TT>SrcAccessor::value_type</TT>) must be a line ar algebra, i.e. addition,
subtraction and multiplication of the type with itself, and multiplicat ion subtraction and multiplication of the type with itself, and multiplicat ion
with double and with double and
\ref NumericTraits "NumericTraits" must \ref NumericTraits "NumericTraits" must
be defined. In addition, this type must be less-comparable. be defined. In addition, this type must be less-comparable.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
void
differenceOfExponentialCrackEdgeImage(MultiArrayView<2, T1, S1> con
st & src,
MultiArrayView<2, T2, S2> des
t,
double scale,
GradValue gradient_threshold,
DestValue edge_marker = Numer
icTraits<DestValue>::one());
}
\endcode
\deprecatedAPI{differenceOfExponentialCrackEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class GradValue,
class DestValue = DestAccessor::value_type> class DestValue = DestAccessor::value_type>
void differenceOfExponentialCrackEdgeImage( void differenceOfExponentialCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker = NumericTraits<DestValue>::one()) DestValue edge_marker = NumericTraits<DestValue>::one())
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class GradValue,
class DestValue = DestAccessor::value_type> class DestValue = DestAccessor::value_type>
void differenceOfExponentialCrackEdgeImage( void differenceOfExponentialCrackEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker = NumericTraits<DestValue>::one()) DestValue edge_marker = NumericTraits<DestValue>::one())
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(2*w-1,2*h-1);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1
differenceOfExponentialCrackEdgeImage(src, edges,
0.8, 4.0, 1);
\endcode
\deprecatedUsage{differenceOfExponentialCrackEdgeImage}
\code
vigra::BImage src(w,h), edges(2*w-1,2*h-1); vigra::BImage src(w,h), edges(2*w-1,2*h-1);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1 // find edges at scale 0.8 with gradient larger than 4.0, mark with 1
vigra::differenceOfExponentialCrackEdgeImage(srcImageRange(src), destIm age(edges), vigra::differenceOfExponentialCrackEdgeImage(srcImageRange(src), destIm age(edges),
0.8, 4.0, 1); 0.8, 4.0, 1);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
double d; double d;
GradValue gradient_threshold; GradValue gradient_threshold;
u = u + u u = u + u
u = u - u u = u - u
u = u * u u = u * u
u = d * u u = d * u
u < gradient_threshold u < gradient_threshold
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft); dest_accessor.set(edge_marker, dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
gradient_threshold > 0 gradient_threshold > 0
\endcode \endcode
The destination image must have twice the size of the source: The destination image must have twice the size of the source:
\code \code
skipping to change at line 494 skipping to change at line 574
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote NumericTraits<typename SrcAccessor::value_type>::RealPromote
TMPTYPE; TMPTYPE;
typedef BasicImage<TMPTYPE> TMPIMG; typedef BasicImage<TMPTYPE> TMPIMG;
TMPIMG tmp(w,h); TMPIMG tmp(w,h);
TMPIMG smooth(w,h); TMPIMG smooth(w,h);
TMPTYPE zero = NumericTraits<TMPTYPE>::zero(); TMPTYPE zero = NumericTraits<TMPTYPE>::zero();
static const Diff2D right(1,0); const Diff2D right(1,0);
static const Diff2D bottom(0,1); const Diff2D bottom(0,1);
static const Diff2D left(-1,0); const Diff2D left(-1,0);
static const Diff2D top(0,-1); const Diff2D top(0,-1);
recursiveSmoothX(srcIterRange(sul, slr, sa), destImage(tmp), scale / 2. 0); recursiveSmoothX(srcIterRange(sul, slr, sa), destImage(tmp), scale / 2. 0);
recursiveSmoothY(srcImageRange(tmp), destImage(tmp), scale / 2.0); recursiveSmoothY(srcImageRange(tmp), destImage(tmp), scale / 2.0);
recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale); recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale);
recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale); recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale);
typename TMPIMG::Iterator iy = smooth.upperLeft(); typename TMPIMG::Iterator iy = smooth.upperLeft();
typename TMPIMG::Iterator ty = tmp.upperLeft(); typename TMPIMG::Iterator ty = tmp.upperLeft();
DestIterator dy = dul; DestIterator dy = dul;
skipping to change at line 547 skipping to change at line 627
TMPTYPE diff = *tx - *ix; TMPTYPE diff = *tx - *ix;
TMPTYPE gy = tx[bottom] - *tx; TMPTYPE gy = tx[bottom] - *tx;
if((gy * gy > thresh) && if((gy * gy > thresh) &&
(diff * (tx[bottom] - ix[bottom]) < zero)) (diff * (tx[bottom] - ix[bottom]) < zero))
{ {
da.set(edge_marker, dx, bottom); da.set(edge_marker, dx, bottom);
} }
} }
typename TMPIMG::Iterator ix = iy;
typename TMPIMG::Iterator tx = ty;
DestIterator dx = dy;
for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
{ {
TMPTYPE diff = *tx - *ix; typename TMPIMG::Iterator ix = iy;
TMPTYPE gx = tx[right] - *tx; typename TMPIMG::Iterator tx = ty;
DestIterator dx = dy;
if((gx * gx > thresh) && for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
(diff * (tx[right] - ix[right]) < zero))
{ {
da.set(edge_marker, dx, right); TMPTYPE diff = *tx - *ix;
TMPTYPE gx = tx[right] - *tx;
if((gx * gx > thresh) &&
(diff * (tx[right] - ix[right]) < zero))
{
da.set(edge_marker, dx, right);
}
} }
} }
iy = smooth.upperLeft() + Diff2D(0,1); iy = smooth.upperLeft() + Diff2D(0,1);
ty = tmp.upperLeft() + Diff2D(0,1); ty = tmp.upperLeft() + Diff2D(0,1);
dy = dul + Diff2D(1,2); dy = dul + Diff2D(1,2);
static const Diff2D topleft(-1,-1); const Diff2D topleft(-1,-1);
static const Diff2D topright(1,-1); const Diff2D topright(1,-1);
static const Diff2D bottomleft(-1,1); const Diff2D bottomleft(-1,1);
static const Diff2D bottomright(1,1); const Diff2D bottomright(1,1);
// find missing 1-cells below threshold (x-direction) // find missing 1-cells below threshold (x-direction)
for(y=0; y<h-2; ++y, ++iy.y, ++ty.y, dy.y+=2) for(y=0; y<h-2; ++y, ++iy.y, ++ty.y, dy.y+=2)
{ {
typename TMPIMG::Iterator ix = iy; typename TMPIMG::Iterator ix = iy;
typename TMPIMG::Iterator tx = ty; typename TMPIMG::Iterator tx = ty;
DestIterator dx = dy; DestIterator dx = dy;
for(int x=0; x<w-2; ++x, ++ix.x, ++tx.x, dx.x+=2) for(int x=0; x<w-2; ++x, ++ix.x, ++tx.x, dx.x+=2)
{ {
skipping to change at line 635 skipping to change at line 717
dy = dul + Diff2D(1,1); dy = dul + Diff2D(1,1);
// find missing 0-cells // find missing 0-cells
for(y=0; y<h-1; ++y, dy.y+=2) for(y=0; y<h-1; ++y, dy.y+=2)
{ {
DestIterator dx = dy; DestIterator dx = dy;
for(int x=0; x<w-1; ++x, dx.x+=2) for(int x=0; x<w-1; ++x, dx.x+=2)
{ {
static const Diff2D dist[] = {right, top, left, bottom }; const Diff2D dist[] = {right, top, left, bottom };
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
{ {
if(da(dx, dist[i]) == edge_marker) break; if(da(dx, dist[i]) == edge_marker) break;
} }
if(i < 4) da.set(edge_marker, dx); if(i < 4) da.set(edge_marker, dx);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
inline inline void
void differenceOfExponentialCrackEdgeImage( differenceOfExponentialCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcA
triple<SrcIterator, SrcIterator, SrcAccessor> src, ccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest
double scale, GradValue gradient_threshold, ,
DestValue edge_marker) double scale, GradValue gradient_thre
shold,
DestValue edge_marker)
{ {
differenceOfExponentialCrackEdgeImage(src.first, src.second, src.third, differenceOfExponentialCrackEdgeImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale, gradient_threshold, scale, gradient_threshold, edge_m
edge_marker); arker);
}
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
inline void
differenceOfExponentialCrackEdgeImage(MultiArrayView<2, T1, S1> const & src
,
MultiArrayView<2, T2, S2> dest,
double scale,
GradValue gradient_threshold,
DestValue edge_marker)
{
vigra_precondition(2*src.shape() - Shape2(1) == dest.shape(),
"differenceOfExponentialCrackEdgeImage(): shape mismatch between in
put and output.");
differenceOfExponentialCrackEdgeImage(srcImageRange(src),
destImage(dest),
scale, gradient_threshold, edge_m
arker);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* removeShortEdges */ /* removeShortEdges */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Remove short edges from an edge image. /** \brief Remove short edges from an edge image.
skipping to change at line 689 skipping to change at line 786
If the source image fulfills the requirements of a \ref CrackEdgeImage, If the source image fulfills the requirements of a \ref CrackEdgeImage,
it will still do so after application of this algorithm. it will still do so after application of this algorithm.
Note that this algorithm, unlike most other algorithms in VIGRA, operat es in-place, Note that this algorithm, unlike most other algorithms in VIGRA, operat es in-place,
i.e. on only one image. Also, the algorithm assumes that all non-edges pixels are already i.e. on only one image. Also, the algorithm assumes that all non-edges pixels are already
marked with the given <TT>non_edge_marker</TT> value. marked with the given <TT>non_edge_marker</TT> value.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S, class Value>
void
removeShortEdges(MultiArrayView<2, T, S> image,
unsigned int min_edge_length, Value non_edge_marke
r);
}
\endcode
\deprecatedAPI{removeShortEdges}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Accessor, class SrcValue> template <class Iterator, class Accessor, class SrcValue>
void removeShortEdges( void removeShortEdges(
Iterator sul, Iterator slr, Accessor sa, Iterator sul, Iterator slr, Accessor sa,
int min_edge_length, SrcValue non_edge_marker) int min_edge_length, SrcValue non_edge_marker)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Accessor, class SrcValue> template <class Iterator, class Accessor, class SrcValue>
void removeShortEdges( void removeShortEdges(
triple<Iterator, Iterator, Accessor> src, triple<Iterator, Iterator, Accessor> src,
int min_edge_length, SrcValue non_edge_marker) int min_edge_length, SrcValue non_edge_marker)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(w,h);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1
differenceOfExponentialEdgeImage(src, edges,
0.8, 4.0, 1);
// zero edges shorter than 10 pixels
removeShortEdges(edges, 10, 0);
\endcode
\deprecatedUsage{removeShortEdges}
\code
vigra::BImage src(w,h), edges(w,h); vigra::BImage src(w,h), edges(w,h);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1 // find edges at scale 0.8 with gradient larger than 4.0, mark with 1
vigra::differenceOfExponentialEdgeImage(srcImageRange(src), destImage(e dges), vigra::differenceOfExponentialEdgeImage(srcImageRange(src), destImage(e dges),
0.8, 4.0, 1); 0.8, 4.0, 1);
// zero edges shorter than 10 pixels // zero edges shorter than 10 pixels
vigra::removeShortEdges(srcImageRange(edges), 10, 0); vigra::removeShortEdges(srcImageRange(edges), 10, 0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u == u u == u
SrcValue non_edge_marker; SrcValue non_edge_marker;
src_accessor.set(non_edge_marker, src_upperleft); src_accessor.set(non_edge_marker, src_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void removeShortEdges) doxygen_overloaded_function(template <...> void removeShortEdges)
template <class Iterator, class Accessor, class Value> template <class Iterator, class Accessor, class Value>
void removeShortEdges( void removeShortEdges(
Iterator sul, Iterator slr, Accessor sa, Iterator sul, Iterator slr, Accessor sa,
unsigned int min_edge_length, Value non_edge_marker) unsigned int min_edge_length, Value non_edge_marker)
{ {
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
skipping to change at line 789 skipping to change at line 909
if(sa(ox) == non_edge_marker) continue; if(sa(ox) == non_edge_marker) continue;
if((region_stats[*lx].count) < min_edge_length) if((region_stats[*lx].count) < min_edge_length)
{ {
sa.set(non_edge_marker, ox); sa.set(non_edge_marker, ox);
} }
} }
} }
} }
template <class Iterator, class Accessor, class Value> template <class Iterator, class Accessor, class Value>
inline inline void
void removeShortEdges( removeShortEdges(triple<Iterator, Iterator, Accessor> src,
triple<Iterator, Iterator, Accessor> src, unsigned int min_edge_length, Value non_edge_marker)
unsigned int min_edge_length, Value non_edge_marker)
{ {
removeShortEdges(src.first, src.second, src.third, removeShortEdges(src.first, src.second, src.third,
min_edge_length, non_edge_marker); min_edge_length, non_edge_marker);
} }
template <class T, class S, class Value>
inline void
removeShortEdges(MultiArrayView<2, T, S> image,
unsigned int min_edge_length, Value non_edge_marker)
{
removeShortEdges(destImageRange(image),
min_edge_length, non_edge_marker);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* closeGapsInCrackEdgeImage */ /* closeGapsInCrackEdgeImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Close one-pixel wide gaps in a cell grid edge image. /** \brief Close one-pixel wide gaps in a cell grid edge image.
This algorithm is typically applied as a post-processing operation of This algorithm is typically applied as a post-processing operation of
\ref differenceOfExponentialCrackEdgeImage(). The source image must ful fill \ref differenceOfExponentialCrackEdgeImage(). The source image must ful fill
skipping to change at line 822 skipping to change at line 950
Since these gaps are usually caused by zero crossing slightly below the gradient Since these gaps are usually caused by zero crossing slightly below the gradient
threshold used in edge detection, this algorithms acts like a weak hyst eresis threshold used in edge detection, this algorithms acts like a weak hyst eresis
thresholding. The newly found edge pixels are marked with the given <TT >edge_marker</TT>. thresholding. The newly found edge pixels are marked with the given <TT >edge_marker</TT>.
The image's value type must be equality comparable. The image's value type must be equality comparable.
Note that this algorithm, unlike most other algorithms in VIGRA, operat es in-place, Note that this algorithm, unlike most other algorithms in VIGRA, operat es in-place,
i.e. on only one image. i.e. on only one image.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S, class Value>
void
closeGapsInCrackEdgeImage(MultiArrayView<2, T, S> image, Value edge
_marker);
}
\endcode
\deprecatedAPI{closeGapsInCrackEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
void closeGapsInCrackEdgeImage( void closeGapsInCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
SrcValue edge_marker) SrcValue edge_marker)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
void closeGapsInCrackEdgeImage( void closeGapsInCrackEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
SrcValue edge_marker) SrcValue edge_marker)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(2*w-1, 2*h-1);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1
differenceOfExponentialCrackEdgeImage(src, edges,
0.8, 4.0, 1);
// close gaps, mark with 1
closeGapsInCrackEdgeImage(edges, 1);
// zero edges shorter than 20 pixels
removeShortEdges(edges, 10, 0);
\endcode
\deprecatedUsage{closeGapsInCrackEdgeImage}
\code
vigra::BImage src(w,h), edges(2*w-1, 2*h-1); vigra::BImage src(w,h), edges(2*w-1, 2*h-1);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1 // find edges at scale 0.8 with gradient larger than 4.0, mark with 1
vigra::differenceOfExponentialCrackEdgeImage(srcImageRange(src), destIm age(edges), vigra::differenceOfExponentialCrackEdgeImage(srcImageRange(src), destIm age(edges),
0.8, 4.0, 1); 0.8, 4.0, 1);
// close gaps, mark with 1 // close gaps, mark with 1
vigra::closeGapsInCrackEdgeImage(srcImageRange(edges), 1); vigra::closeGapsInCrackEdgeImage(srcImageRange(edges), 1);
// zero edges shorter than 20 pixels // zero edges shorter than 20 pixels
vigra::removeShortEdges(srcImageRange(edges), 10, 0); vigra::removeShortEdges(srcImageRange(edges), 10, 0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u == u u == u
u != u u != u
SrcValue edge_marker; SrcValue edge_marker;
src_accessor.set(edge_marker, src_upperleft); src_accessor.set(edge_marker, src_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void closeGapsInCrackEdgeImage) doxygen_overloaded_function(template <...> void closeGapsInCrackEdgeImage)
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
void closeGapsInCrackEdgeImage( void closeGapsInCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
SrcValue edge_marker) SrcValue edge_marker)
{ {
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
vigra_precondition(w % 2 == 1 && h % 2 == 1, vigra_precondition(w % 2 == 1 && h % 2 == 1,
"closeGapsInCrackEdgeImage(): Input is not a crack edge image (must have odd-numbered shape)."); "closeGapsInCrackEdgeImage(): Input is not a crack edge image (must have odd-numbered shape).");
int w2 = w / 2, h2 = h / 2, x, y; int w2 = w / 2, h2 = h / 2, x, y;
int count1, count2, count3; int count1, count2, count3;
static const Diff2D right(1,0); const Diff2D right(1,0);
static const Diff2D bottom(0,1); const Diff2D bottom(0,1);
static const Diff2D left(-1,0); const Diff2D left(-1,0);
static const Diff2D top(0,-1); const Diff2D top(0,-1);
static const Diff2D leftdist[] = { const Diff2D leftdist[] = { Diff2D(0, 0), Diff2D(-1, 1), Diff2D(-2, 0),
Diff2D(0, 0), Diff2D(-1, 1), Diff2D(-2, 0), Diff2D(-1, -1)}; Diff2D(-1, -1)};
static const Diff2D rightdist[] = { const Diff2D rightdist[] = { Diff2D(2, 0), Diff2D(1, 1), Diff2D(0, 0),
Diff2D(2, 0), Diff2D(1, 1), Diff2D(0, 0), Diff2D(1, -1)}; Diff2D(1, -1)};
static const Diff2D topdist[] = { const Diff2D topdist[] = { Diff2D(1, -1), Diff2D(0, 0), Diff2D(-1, -1),
Diff2D(1, -1), Diff2D(0, 0), Diff2D(-1, -1), Diff2D(0, -2)}; Diff2D(0, -2)};
static const Diff2D bottomdist[] = { const Diff2D bottomdist[] = { Diff2D(1, 1), Diff2D(0, 2), Diff2D(-1, 1)
Diff2D(1, 1), Diff2D(0, 2), Diff2D(-1, 1), Diff2D(0, 0)}; , Diff2D(0, 0)};
int i; int i;
SrcIterator sy = sul + Diff2D(0,1); SrcIterator sy = sul + Diff2D(0,1);
SrcIterator sx; SrcIterator sx;
// close 1-pixel wide gaps (x-direction) // close 1-pixel wide gaps (x-direction)
for(y=0; y<h2; ++y, sy.y+=2) for(y=0; y<h2; ++y, sy.y+=2)
{ {
sx = sy + Diff2D(2,0); sx = sy + Diff2D(2,0);
skipping to change at line 996 skipping to change at line 1145
if(count1 <= 1 || count2 <= 1 || count3 == 15) if(count1 <= 1 || count2 <= 1 || count3 == 15)
{ {
sa.set(edge_marker, sx); sa.set(edge_marker, sx);
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
inline inline void
void closeGapsInCrackEdgeImage( closeGapsInCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src
triple<SrcIterator, SrcIterator, SrcAccessor> src, ,
SrcValue edge_marker) SrcValue edge_marker)
{ {
closeGapsInCrackEdgeImage(src.first, src.second, src.third, closeGapsInCrackEdgeImage(src.first, src.second, src.third,
edge_marker); edge_marker);
}
template <class T, class S, class Value>
inline void
closeGapsInCrackEdgeImage(MultiArrayView<2, T, S> image, Value edge_marker)
{
closeGapsInCrackEdgeImage(destImageRange(image), edge_marker);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* beautifyCrackEdgeImage */ /* beautifyCrackEdgeImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Beautify crack edge image for visualization. /** \brief Beautify crack edge image for visualization.
skipping to change at line 1039 skipping to change at line 1194
Therefore, this algorithm should only be applied as a visualization aid , i.e. Therefore, this algorithm should only be applied as a visualization aid , i.e.
for human inspection. The algorithm assumes that edges are marked with <TT>edge_marker</TT>, for human inspection. The algorithm assumes that edges are marked with <TT>edge_marker</TT>,
and background pixels with <TT>background_marker</TT>. The image's valu e type must be and background pixels with <TT>background_marker</TT>. The image's valu e type must be
equality comparable. equality comparable.
Note that this algorithm, unlike most other algorithms in VIGRA, operat es in-place, Note that this algorithm, unlike most other algorithms in VIGRA, operat es in-place,
i.e. on only one image. i.e. on only one image.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S, class Value>
void
beautifyCrackEdgeImage(MultiArrayView<2, T, S> image,
Value edge_marker, Value background_marker);
}
\endcode
\deprecatedAPI{beautifyCrackEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
void beautifyCrackEdgeImage( void beautifyCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
SrcValue edge_marker, SrcValue background_marker) SrcValue edge_marker, SrcValue background_marker)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
void beautifyCrackEdgeImage( void beautifyCrackEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
SrcValue edge_marker, SrcValue background_marker) SrcValue edge_marker, SrcValue background_marker)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(2*w-1, 2*h-1);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1
differenceOfExponentialCrackEdgeImage(src, edges,
0.8, 4.0, 1);
// beautify edge image for visualization
beautifyCrackEdgeImage(edges, 1, 0);
// show to the user ('window' is an unspecified GUI widget to display V
IGRA images)
window.open(edges);
\endcode
\deprecatedUsage{beautifyCrackEdgeImage}
\code
vigra::BImage src(w,h), edges(2*w-1, 2*h-1); vigra::BImage src(w,h), edges(2*w-1, 2*h-1);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1 // find edges at scale 0.8 with gradient larger than 4.0, mark with 1
vigra::differenceOfExponentialCrackEdgeImage(srcImageRange(src), destIm age(edges), vigra::differenceOfExponentialCrackEdgeImage(srcImageRange(src), destIm age(edges),
0.8, 4.0, 1); 0.8, 4.0, 1);
// beautify edge image for visualization // beautify edge image for visualization
vigra::beautifyCrackEdgeImage(destImageRange(edges), 1, 0); vigra::beautifyCrackEdgeImage(destImageRange(edges), 1, 0);
// show to the user // show to the user
window.open(edges); window.open(edges);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u == u u == u
u != u u != u
SrcValue background_marker; SrcValue background_marker;
src_accessor.set(background_marker, src_upperleft); src_accessor.set(background_marker, src_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void beautifyCrackEdgeImage) doxygen_overloaded_function(template <...> void beautifyCrackEdgeImage)
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
void beautifyCrackEdgeImage( void beautifyCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
SrcValue edge_marker, SrcValue background_marker) SrcValue edge_marker, SrcValue background_marker)
{ {
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
vigra_precondition(w % 2 == 1 && h % 2 == 1, vigra_precondition(w % 2 == 1 && h % 2 == 1,
"beautifyCrackEdgeImage(): Input is not a crack edge image (must ha ve odd-numbered shape)."); "beautifyCrackEdgeImage(): Input is not a crack edge image (must ha ve odd-numbered shape).");
int w2 = w / 2, h2 = h / 2, x, y; int w2 = w / 2, h2 = h / 2, x, y;
SrcIterator sy = sul + Diff2D(1,1); SrcIterator sy = sul + Diff2D(1,1);
SrcIterator sx; SrcIterator sx;
static const Diff2D right(1,0); const Diff2D right(1,0);
static const Diff2D bottom(0,1); const Diff2D bottom(0,1);
static const Diff2D left(-1,0); const Diff2D left(-1,0);
static const Diff2D top(0,-1); const Diff2D top(0,-1);
// delete 0-cells at corners // delete 0-cells at corners
for(y=0; y<h2; ++y, sy.y+=2) for(y=0; y<h2; ++y, sy.y+=2)
{ {
sx = sy; sx = sy;
for(x=0; x<w2; ++x, sx.x+=2) for(x=0; x<w2; ++x, sx.x+=2)
{ {
if(sa(sx) != edge_marker) continue; if(sa(sx) != edge_marker) continue;
if(sa(sx, right) == edge_marker && sa(sx, left) == edge_marker) continue; if(sa(sx, right) == edge_marker && sa(sx, left) == edge_marker) continue;
if(sa(sx, bottom) == edge_marker && sa(sx, top) == edge_marker) continue; if(sa(sx, bottom) == edge_marker && sa(sx, top) == edge_marker) continue;
sa.set(background_marker, sx); sa.set(background_marker, sx);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, class SrcValue> template <class SrcIterator, class SrcAccessor, class SrcValue>
inline inline void
void beautifyCrackEdgeImage( beautifyCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, SrcValue edge_marker, SrcValue background_marker)
SrcValue edge_marker, SrcValue background_marker)
{ {
beautifyCrackEdgeImage(src.first, src.second, src.third, beautifyCrackEdgeImage(src.first, src.second, src.third,
edge_marker, background_marker); edge_marker, background_marker);
}
template <class T, class S, class Value>
inline void
beautifyCrackEdgeImage(MultiArrayView<2, T, S> image,
Value edge_marker, Value background_marker)
{
beautifyCrackEdgeImage(destImageRange(image),
edge_marker, background_marker);
} }
/** Helper class that stores edgel attributes. /** Helper class that stores edgel attributes.
*/ */
class Edgel class Edgel
{ {
public: public:
/** The type of an Edgel's members. /** The type of an Edgel's members.
*/ */
skipping to change at line 1171 skipping to change at line 1360
value_type x; value_type x;
/** The edgel's sub-pixel y coordinate. /** The edgel's sub-pixel y coordinate.
*/ */
value_type y; value_type y;
/** The edgel's strength (magnitude of the gradient vector). /** The edgel's strength (magnitude of the gradient vector).
*/ */
value_type strength; value_type strength;
/** /** \brief The edgel's orientation.
The edgel's orientation. This is the clockwise angle in radians
This is the clockwise angle in radians
between the x-axis and the edge, so that the bright side of the between the x-axis and the edge, so that the bright side of the
edge is on the left when one looks along the orientation vector. edge is on the left when one looks along the orientation vector.
The angle is measured clockwise because the y-axis increases The angle is measured clockwise because the y-axis increases
downwards (left-handed coordinate system): downwards (left-handed coordinate system):
\code \code
edgel axis edgel axis
\ \
(dark \ (bright side) (dark \ (bright side)
side) \ side) \
\ \
+------------> x-axis +------------> x-axis
|\ | |\ |
| \ /_/ orientation angle | \ /_/ orientation angle
| \\ | \\
| \ | \
| |
y-axis V y-axis V
\endcode \endcode
So, for example a vertical edge with its dark side on the left So, for example a vertical edge with its dark side on the left
has orientation PI/2, and a horizontal edge with dark side on top has orientation PI/2, and a horizontal edge with dark side on top
has orientation PI. Obviously, the edge's orientation changes has orientation PI. Obviously, the edge's orientation changes
by PI if the contrast is reversed. by PI if the contrast is reversed.
Note that this convention changed as of VIGRA version 1.7.0. Note that this convention changed as of VIGRA version 1.7.0.
*/ */
skipping to change at line 1295 skipping to change at line 1485
larger gradient magnitude than its two neighbors in gradient direction larger gradient magnitude than its two neighbors in gradient direction
(where the direction is rounded into octants). If this is the case, (where the direction is rounded into octants). If this is the case,
a new \ref Edgel is appended to the given vector of <TT>edgels</TT>. Th e subpixel a new \ref Edgel is appended to the given vector of <TT>edgels</TT>. Th e subpixel
edgel position is determined by fitting a parabola to the three gradien t edgel position is determined by fitting a parabola to the three gradien t
magnitude values mentioned above. The sub-pixel location of the parabol a's tip magnitude values mentioned above. The sub-pixel location of the parabol a's tip
and the gradient magnitude and direction (from the pixel center) and the gradient magnitude and direction (from the pixel center)
are written in the newly created edgel. are written in the newly created edgel.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// compute edgels from a scalar image (determine gradient internall
y at 'scale')
template <class T, class S, class BackInsertable>
void
cannyEdgelList(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels,
double scale);
// compute edgels from a pre-computed gradient image
template <class T, class S, class BackInsertable>
void
cannyEdgelList(MultiArrayView<2, TinyVector<T, 2>, S> const & src,
BackInsertable & edgels);
}
\endcode
\deprecatedAPI{cannyEdgelList}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels); BackInsertable & edgels);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, double scale); BackInsertable & edgels, double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels); BackInsertable & edgels);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale); BackInsertable & edgels, double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
// create empty edgel list
std::vector<vigra::Edgel> edgels;
...
// find edgels at scale 0.8
cannyEdgelList(src, edgels, 0.8);
\endcode
\deprecatedUsage{cannyEdgelList}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
// empty edgel list // empty edgel list
std::vector<vigra::Edgel> edgels; std::vector<vigra::Edgel> edgels;
... ...
// find edgels at scale 0.8 // find edgels at scale 0.8
vigra::cannyEdgelList(srcImageRange(src), edgels, 0.8); vigra::cannyEdgelList(srcImageRange(src), edgels, 0.8);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft; SrcImageIterator src_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
src_accessor(src_upperleft); src_accessor(src_upperleft);
BackInsertable edgels; BackInsertable edgels;
edgels.push_back(Edgel()); edgels.push_back(Edgel());
\endcode \endcode
SrcAccessor::value_type must be a type convertible to float SrcAccessor::value_type must be a type convertible to float
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgelList) doxygen_overloaded_function(template <...> void cannyEdgelList)
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
skipping to change at line 1380 skipping to change at line 1599
BackInsertable & edgels, double scale) BackInsertable & edgels, double scale)
{ {
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale);
cannyEdgelList(srcImageRange(grad), edgels); cannyEdgelList(srcImageRange(grad), edgels);
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void
cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale)
{
cannyEdgelList(src.first, src.second, src.third, edgels, scale);
}
template <class SrcIterator, class SrcAccessor, class BackInsertable>
void void
cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels) BackInsertable & edgels)
{ {
using namespace functor; using namespace functor;
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
typedef typename NumericTraits<typename SrcType::value_type>::RealPromo te TmpType; typedef typename NumericTraits<typename SrcType::value_type>::RealPromo te TmpType;
BasicImage<TmpType> magnitude(lr-ul); BasicImage<TmpType> magnitude(lr-ul);
transformImage(srcIterRange(ul, lr, src), destImage(magnitude), norm(Ar g1())); transformImage(srcIterRange(ul, lr, src), destImage(magnitude), norm(Ar g1()));
// find edgels // find edgels
internalCannyFindEdgels(ul, src, magnitude, edgels, NumericTraits<TmpTy pe>::zero()); internalCannyFindEdgels(ul, src, magnitude, edgels, NumericTraits<TmpTy pe>::zero());
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void inline void
cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale)
{
cannyEdgelList(src.first, src.second, src.third, edgels, scale);
}
template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void
cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels) BackInsertable & edgels)
{ {
cannyEdgelList(src.first, src.second, src.third, edgels); cannyEdgelList(src.first, src.second, src.third, edgels);
} }
template <class T, class S, class BackInsertable>
inline void
cannyEdgelList(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels, double scale)
{
cannyEdgelList(srcImageRange(src), edgels, scale);
}
template <class T, class S, class BackInsertable>
inline void
cannyEdgelList(MultiArrayView<2, TinyVector<T, 2>, S> const & src,
BackInsertable & edgels)
{
cannyEdgelList(srcImageRange(src), edgels);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* cannyEdgelListThreshold */ /* cannyEdgelListThreshold */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Canny's edge detector with thresholding. /** \brief Canny's edge detector with thresholding.
This function works exactly like \ref cannyEdgelList(), but This function works exactly like \ref cannyEdgelList(), but
you also pass a threshold for the minimal gradient magnitude, you also pass a threshold for the minimal gradient magnitude,
so that edgels whose strength is below the threshold are not so that edgels whose strength is below the threshold are not
inserted into the edgel list. inserted into the edgel list.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// compute edgels from a scalar image (determine gradient internall
y at 'scale')
template <class T, class S,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels,
double scale,
GradValue grad_threshold);
// compute edgels from a pre-computed gradient image
template <class T, class S,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(MultiArrayView<2, TinyVector<T, 2>, S> cons
t & src,
BackInsertable & edgels,
GradValue grad_threshold);
}
\endcode
\deprecatedAPI{cannyEdgelListThreshold}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, GradValue grad_thr eshold); BackInsertable & edgels, GradValue grad_thr eshold);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, double scale, Grad Value grad_threshold); BackInsertable & edgels, double scale, Grad Value grad_threshold);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccesso r> src, cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
BackInsertable & edgels, GradValue grad_thr eshold); BackInsertable & edgels, GradValue grad_thr eshold);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccesso r> src, cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
BackInsertable & edgels, double scale, Grad Value grad_threshold); BackInsertable & edgels, double scale, Grad Value grad_threshold);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
// create empty edgel list
std::vector<vigra::Edgel> edgels;
...
// find edgels at scale 0.8, only considering gradient magnitudes above
2.0
cannyEdgelListThreshold(src, edgels, 0.8, 2.0);
\endcode
\deprecatedUsage{cannyEdgelListThreshold}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
// empty edgel list // empty edgel list
std::vector<vigra::Edgel> edgels; std::vector<vigra::Edgel> edgels;
... ...
// find edgels at scale 0.8, only considering gradient above 2.0 // find edgels at scale 0.8, only considering gradient above 2.0
vigra::cannyEdgelListThreshold(srcImageRange(src), edgels, 0.8, 2.0); vigra::cannyEdgelListThreshold(srcImageRange(src), edgels, 0.8, 2.0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft; SrcImageIterator src_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
src_accessor(src_upperleft); src_accessor(src_upperleft);
BackInsertable edgels; BackInsertable edgels;
edgels.push_back(Edgel()); edgels.push_back(Edgel());
\endcode \endcode
SrcAccessor::value_type must be a type convertible to float SrcAccessor::value_type must be a type convertible to float
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgelListThreshold) doxygen_overloaded_function(template <...> void cannyEdgelListThreshold)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
skipping to change at line 1517 skipping to change at line 1785
{ {
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale);
cannyEdgelListThreshold(srcImageRange(grad), edgels, grad_threshold); cannyEdgelListThreshold(srcImageRange(grad), edgels, grad_threshold);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
inline void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale, GradValue gr
ad_threshold)
{
cannyEdgelListThreshold(src.first, src.second, src.third, edgels, scale
, grad_threshold);
}
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void void
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, GradValue grad_threshold) BackInsertable & edgels, GradValue grad_threshold)
{ {
using namespace functor; using namespace functor;
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
typedef typename NumericTraits<typename SrcType::value_type>::RealPromo te TmpType; typedef typename NumericTraits<typename SrcType::value_type>::RealPromo te TmpType;
BasicImage<TmpType> magnitude(lr-ul); BasicImage<TmpType> magnitude(lr-ul);
transformImage(srcIterRange(ul, lr, src), destImage(magnitude), norm(Ar g1())); transformImage(srcIterRange(ul, lr, src), destImage(magnitude), norm(Ar g1()));
// find edgels // find edgels
internalCannyFindEdgels(ul, src, magnitude, edgels, grad_threshold); internalCannyFindEdgels(ul, src, magnitude, edgels, grad_threshold);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
inline void inline void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale, GradValue gr
ad_threshold)
{
cannyEdgelListThreshold(src.first, src.second, src.third, edgels, scale
, grad_threshold);
}
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
inline void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, GradValue grad_threshold) BackInsertable & edgels, GradValue grad_threshold)
{ {
cannyEdgelListThreshold(src.first, src.second, src.third, edgels, grad_ threshold); cannyEdgelListThreshold(src.first, src.second, src.third, edgels, grad_ threshold);
} }
template <class T, class S,
class BackInsertable, class GradValue>
inline void
cannyEdgelListThreshold(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels,
double scale,
GradValue grad_threshold)
{
cannyEdgelListThreshold(srcImageRange(src), edgels, scale, grad_thresho
ld);
}
template <class T, class S,
class BackInsertable, class GradValue>
inline void
cannyEdgelListThreshold(MultiArrayView<2, TinyVector<T, 2>, S> const & src,
BackInsertable & edgels,
GradValue grad_threshold)
{
cannyEdgelListThreshold(srcImageRange(src), edgels, grad_threshold);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* cannyEdgeImage */ /* cannyEdgeImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Detect and mark edges in an edge image using Canny's algorithm. /** \brief Detect and mark edges in an edge image using Canny's algorithm.
This operator first calls \ref cannyEdgelList() to generate an This operator first calls \ref cannyEdgelList() with the given scale to generate an
edgel list for the given image. Then it scans this list and selects edg els edgel list for the given image. Then it scans this list and selects edg els
whose strength is above the given <TT>gradient_threshold</TT>. For each of these whose strength is above the given <TT>gradient_threshold</TT>. For each of these
edgels, the edgel's location is rounded to the nearest pixel, and that edgels, the edgel's location is rounded to the nearest pixel, and that
pixel marked with the given <TT>edge_marker</TT>. pixel marked with the given <TT>edge_marker</TT>.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
void
cannyEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale,
GradValue gradient_threshold,
DestValue edge_marker);
}
\endcode
\deprecatedAPI{cannyEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImage( void cannyEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
double scale, GradValue gradient_threshold, DestValue ed ge_marker); double scale, GradValue gradient_threshold, DestValue ed ge_marker);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImage( void cannyEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, DestValue ed ge_marker); double scale, GradValue gradient_threshold, DestValue ed ge_marker);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(w,h);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1
cannyEdgeImage(src, edges, 0.8, 4.0, 1);
\endcode
\deprecatedUsage{cannyEdgeImage}
\code
vigra::BImage src(w,h), edges(w,h); vigra::BImage src(w,h), edges(w,h);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1 // find edges at scale 0.8 with gradient larger than 4.0, mark with 1
vigra::cannyEdgeImage(srcImageRange(src), destImage(edges), vigra::cannyEdgeImage(srcImageRange(src), destImage(edges),
0.8, 4.0, 1); 0.8, 4.0, 1);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see also: \ref cannyEdgelList(). see also: \ref cannyEdgelList().
\code \code
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
DestAccessor dest_accessor; DestAccessor dest_accessor;
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft, vigra::Diff2D(1,1)); dest_accessor.set(edge_marker, dest_upperleft, vigra::Diff2D(1,1));
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
gradient_threshold > 0 gradient_threshold > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgeImage) doxygen_overloaded_function(template <...> void cannyEdgeImage)
skipping to change at line 1659 skipping to change at line 1971
if(pix.x < 0 || pix.x >= w || pix.y < 0 || pix.y >= h) if(pix.x < 0 || pix.x >= w || pix.y < 0 || pix.y >= h)
continue; continue;
da.set(edge_marker, dul, pix); da.set(edge_marker, dul, pix);
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
inline void cannyEdgeImage( inline void
triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, DestValue edge_marke double scale, GradValue gradient_threshold, DestValue edge_m
r) arker)
{ {
cannyEdgeImage(src.first, src.second, src.third, cannyEdgeImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale, gradient_threshold, edge_marker); scale, gradient_threshold, edge_marker);
} }
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
inline void
cannyEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale, GradValue gradient_threshold, DestValue edge_m
arker)
{
vigra_precondition(src.shape() == dest.shape(),
"cannyEdgeImage(): shape mismatch between input and output.");
cannyEdgeImage(srcImageRange(src),
destImage(dest),
scale, gradient_threshold, edge_marker);
}
/********************************************************/ /********************************************************/
namespace detail { namespace detail {
template <class DestIterator> template <class DestIterator>
int neighborhoodConfiguration(DestIterator dul) int neighborhoodConfiguration(DestIterator dul)
{ {
int v = 0; int v = 0;
NeighborhoodCirculator<DestIterator, EightNeighborCode> c(dul, EightNei ghborCode::SouthEast); NeighborhoodCirculator<DestIterator, EightNeighborCode> c(dul, EightNei ghborCode::SouthEast);
for(int i=0; i<8; ++i, --c) for(int i=0; i<8; ++i, --c)
skipping to change at line 1779 skipping to change at line 2106
da.set(edge_marker, dx); da.set(edge_marker, dx);
} }
} }
} }
} }
} // namespace detail } // namespace detail
/********************************************************/ /********************************************************/
/* */ /* */
/* cannyEdgeImageWithThinning */ /* cannyEdgeImageFromGradWithThinning */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Detect and mark edges in an edge image using Canny's algorithm. /** \brief Detect and mark edges in an edge image using Canny's algorithm.
The input pixels of this algorithms must be vectors of length 2 (see Re quired Interface below). The input pixels of this algorithm must be vectors of length 2 (see Req uired Interface below).
It first searches for all pixels whose gradient magnitude is larger It first searches for all pixels whose gradient magnitude is larger
than the given <tt>gradient_threshold</tt> and larger than the magnitud e of its two neighbors than the given <tt>gradient_threshold</tt> and larger than the magnitud e of its two neighbors
in gradient direction (where these neighbors are determined by nearest neighbor in gradient direction (where these neighbors are determined by nearest neighbor
interpolation, i.e. according to the octant where the gradient points i nto). interpolation, i.e. according to the octant where the gradient points i nto).
The resulting edge pixel candidates are then subjected to topological t hinning The resulting edge pixel candidates are then subjected to topological t hinning
so that the remaining edge pixels can be linked into edgel chains with a provable, so that the remaining edge pixels can be linked into edgel chains with a provable,
non-heuristic algorithm. Thinning is performed so that the pixels with highest gradient non-heuristic algorithm. Thinning is performed so that the pixels with highest gradient
magnitude survive. Optionally, the outermost pixels are marked as edge pixels magnitude survive. Optionally, the outermost pixels are marked as edge pixels
as well when <tt>addBorder</tt> is true. The remaining pixels will be m arked in the destination as well when <tt>addBorder</tt> is true. The remaining pixels will be m arked in the destination
image with the value of <tt>edge_marker</tt> (all non-edge pixels remai n untouched). image with the value of <tt>edge_marker</tt> (all non-edge pixels remai n untouched).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
void
cannyEdgeImageFromGradWithThinning(MultiArrayView<2, TinyVector<T1,
2>, S1> const & src,
MultiArrayView<2, T2, S2> dest,
GradValue gradient_threshold,
DestValue edge_marker,
bool addBorder = true);
}
\endcode
\deprecatedAPI{cannyEdgeImageFromGradWithThinning}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImageFromGradWithThinning( void cannyEdgeImageFromGradWithThinning(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
GradValue gradient_threshold, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder = true); DestValue edge_marker, bool addBorder = true);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImageFromGradWithThinning( void cannyEdgeImageFromGradWithThinning(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
GradValue gradient_threshold, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder = true); DestValue edge_marker, bool addBorder = true);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(w,h);
MultiArray<2, TinyVector<float, 2> > grad(w,h);
// compute the image gradient at scale 0.8
gaussianGradient(src, grad, 0.8);
// find edges with gradient larger than 4.0, mark with 1, and add borde
r
cannyEdgeImageFromGradWithThinning(grad, edges, 4.0, 1, true);
\endcode
\deprecatedUsage{cannyEdgeImageFromGradWithThinning}
\code
vigra::BImage src(w,h), edges(w,h); vigra::BImage src(w,h), edges(w,h);
vigra::FVector2Image grad(w,h); vigra::FVector2Image grad(w,h);
// compute the image gradient at scale 0.8 // compute the image gradient at scale 0.8
vigra::gaussianGradient(srcImageRange(src), destImage(grad), 0.8); vigra::gaussianGradient(srcImageRange(src), destImage(grad), 0.8);
// empty edge image // empty edge image
edges = 0; edges = 0;
// find edges gradient larger than 4.0, mark with 1, and add border // find edges gradient larger than 4.0, mark with 1, and add border
vigra::cannyEdgeImageFromGradWithThinning(srcImageRange(grad), destImag e(edges), vigra::cannyEdgeImageFromGradWithThinning(srcImageRange(grad), destImag e(edges),
4.0, 1, true); 4.0, 1, true);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
// the input pixel type must be a vector with two elements // the input pixel type must be a vector with two elements
SrcImageIterator src_upperleft; SrcImageIterator src_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
typedef SrcAccessor::value_type SrcPixel; typedef SrcAccessor::value_type SrcPixel;
typedef NormTraits<SrcPixel>::SquaredNormType SrcSquaredNormType; typedef NormTraits<SrcPixel>::SquaredNormType SrcSquaredNormType;
SrcPixel g = src_accessor(src_upperleft); SrcPixel g = src_accessor(src_upperleft);
SrcPixel::value_type g0 = g[0]; SrcPixel::value_type g0 = g[0];
SrcSquaredNormType gn = squaredNorm(g); SrcSquaredNormType gn = squaredNorm(g);
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
DestAccessor dest_accessor; DestAccessor dest_accessor;
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft, vigra::Diff2D(1,1)); dest_accessor.set(edge_marker, dest_upperleft, vigra::Diff2D(1,1));
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
gradient_threshold > 0 gradient_threshold > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgeImageFromGradWithT hinning) doxygen_overloaded_function(template <...> void cannyEdgeImageFromGradWithT hinning)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImageFromGradWithThinning( void cannyEdgeImageFromGradWithThinning(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
GradValue gradient_threshold, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder) DestValue edge_marker, bool addBorder = true)
{ {
vigra_precondition(gradient_threshold >= NumericTraits<GradValue>::zero
(),
"cannyEdgeImageFromGradWithThinning(): gradient threshold must not
be negative.");
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
BImage edgeImage(w, h, BImage::value_type(0)); BImage edgeImage(w, h, BImage::value_type(0));
BImage::traverser eul = edgeImage.upperLeft(); BImage::traverser eul = edgeImage.upperLeft();
BImage::Accessor ea = edgeImage.accessor(); BImage::Accessor ea = edgeImage.accessor();
if(addBorder) if(addBorder)
initImageBorder(destImageRange(edgeImage), 1, 1); initImageBorder(destImageRange(edgeImage), 1, 1);
detail::cannyEdgeImageFromGrad(sul, slr, sa, eul, ea, gradient_threshol d, 1); detail::cannyEdgeImageFromGrad(sul, slr, sa, eul, ea, gradient_threshol d, 1);
static bool isSimplePoint[256] = { bool isSimplePoint[256] = {
0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0,
1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
skipping to change at line 1936 skipping to change at line 2293
continue; continue;
int v = detail::neighborhoodConfiguration(e); int v = detail::neighborhoodConfiguration(e);
if(isSimplePoint[v]) if(isSimplePoint[v])
{ {
pqueue.push(SP(p, norm(sa(sul+p)))); pqueue.push(SP(p, norm(sa(sul+p))));
*e = 2; // remember that it is already in queue *e = 2; // remember that it is already in queue
} }
} }
} }
static const Diff2D dist[] = { Diff2D(-1,0), Diff2D(0,-1), const Diff2D dist[] = { Diff2D(-1,0), Diff2D(0,-1), Diff2D(1,0), Diff2
Diff2D(1,0), Diff2D(0,1) }; D(0,1) };
while(pqueue.size()) while(pqueue.size())
{ {
p = pqueue.top().point; p = pqueue.top().point;
pqueue.pop(); pqueue.pop();
BImage::traverser e = eul + p; BImage::traverser e = eul + p;
int v = detail::neighborhoodConfiguration(e); int v = detail::neighborhoodConfiguration(e);
if(!isSimplePoint[v]) if(!isSimplePoint[v])
continue; // point may no longer be simple because its neighbor s changed continue; // point may no longer be simple because its neighbor s changed
skipping to change at line 1960 skipping to change at line 2316
for(int i=0; i<4; ++i) for(int i=0; i<4; ++i)
{ {
Diff2D pneu = p + dist[i]; Diff2D pneu = p + dist[i];
if(pneu.x == -1 || pneu.y == -1 || pneu.x == w2 || pneu.y == h2 ) if(pneu.x == -1 || pneu.y == -1 || pneu.x == w2 || pneu.y == h2 )
continue; // do not remove points at the border continue; // do not remove points at the border
BImage::traverser eneu = eul + pneu; BImage::traverser eneu = eul + pneu;
if(*eneu == 1) // point is boundary and not yet in the queue if(*eneu == 1) // point is boundary and not yet in the queue
{ {
int v = detail::neighborhoodConfiguration(eneu); v = detail::neighborhoodConfiguration(eneu);
if(isSimplePoint[v]) if(isSimplePoint[v])
{ {
pqueue.push(SP(pneu, norm(sa(sul+pneu)))); pqueue.push(SP(pneu, norm(sa(sul+pneu))));
*eneu = 2; // remember that it is already in queue *eneu = 2; // remember that it is already in queue
} }
} }
} }
} }
initImageIf(destIterRange(dul, dul+Diff2D(w,h), da), initImageIf(destIterRange(dul, dul+Diff2D(w,h), da),
maskImage(edgeImage), edge_marker); maskImage(edgeImage), edge_marker);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
inline void cannyEdgeImageFromGradWithThinning( inline void cannyEdgeImageFromGradWithThinning(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
GradValue gradient_threshold, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder) DestValue edge_marker, bool addBorder = true)
{ {
cannyEdgeImageFromGradWithThinning(src.first, src.second, src.third, cannyEdgeImageFromGradWithThinning(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
gradient_threshold, edge_marker, addBorder); gradient_threshold, edge_marker, addBorder);
} }
template <class SrcIterator, class SrcAccessor, template <class T1, class S1,
class DestIterator, class DestAccessor, class T2, class S2,
class GradValue, class DestValue>
inline void cannyEdgeImageFromGradWithThinning(
SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
GradValue gradient_threshold, DestValue edge_marker)
{
cannyEdgeImageFromGradWithThinning(sul, slr, sa,
dul, da,
gradient_threshold, edge_marker, true);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
inline void cannyEdgeImageFromGradWithThinning( inline void
triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgeImageFromGradWithThinning(MultiArrayView<2, TinyVector<T1, 2>, S1>
pair<DestIterator, DestAccessor> dest, const & src,
GradValue gradient_threshold, DestValue edge_marker) MultiArrayView<2, T2, S2> dest,
{ GradValue gradient_threshold,
cannyEdgeImageFromGradWithThinning(src.first, src.second, src.third, DestValue edge_marker, bool addBorder =
dest.first, dest.second, true)
gradient_threshold, edge_marker, true); {
vigra_precondition(src.shape() == dest.shape(),
"cannyEdgeImageFromGradWithThinning(): shape mismatch between input
and output.");
cannyEdgeImageFromGradWithThinning(srcImageRange(src),
destImage(dest),
gradient_threshold, edge_marker, add
Border);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* cannyEdgeImageWithThinning */ /* cannyEdgeImageWithThinning */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Detect and mark edges in an edge image using Canny's algorithm. /** \brief Detect and mark edges in an edge image using Canny's algorithm.
This operator first calls \ref gaussianGradient() to compute the gradie nt of the input This operator first calls \ref gaussianGradient() to compute the gradie nt of the input
image, ad then \ref cannyEdgeImageFromGradWithThinning() to generate an image, ad then \ref cannyEdgeImageFromGradWithThinning() to generate an
edge image. See there for more detailed documentation. edge image. See there for more detailed documentation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class GradValue, class DestValue>
void
cannyEdgeImageWithThinning(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale,
GradValue gradient_threshold,
DestValue edge_marker,
bool addBorder = true);
}
\endcode
\deprecatedAPI{cannyEdgeImageWithThinning}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImageWithThinning( void cannyEdgeImageWithThinning(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder = true); DestValue edge_marker, bool addBorder = true);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImageWithThinning( void cannyEdgeImageWithThinning(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder = true); DestValue edge_marker, bool addBorder = true);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), edges(w,h);
...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1,
and add border
cannyEdgeImageWithThinning(src, edges, 0.8, 4.0, 1, true);
\endcode
\deprecatedUsage{cannyEdgeImageWithThinning}
\code
vigra::BImage src(w,h), edges(w,h); vigra::BImage src(w,h), edges(w,h);
// empty edge image // empty edge image
edges = 0; edges = 0;
... ...
// find edges at scale 0.8 with gradient larger than 4.0, mark with 1, annd add border // find edges at scale 0.8 with gradient larger than 4.0, mark with 1, annd add border
vigra::cannyEdgeImageWithThinning(srcImageRange(src), destImage(edges), vigra::cannyEdgeImageWithThinning(srcImageRange(src), destImage(edges),
0.8, 4.0, 1, true); 0.8, 4.0, 1, true);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see also: \ref cannyEdgelList(). see also: \ref cannyEdgelList().
\code \code
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
DestAccessor dest_accessor; DestAccessor dest_accessor;
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft, vigra::Diff2D(1,1)); dest_accessor.set(edge_marker, dest_upperleft, vigra::Diff2D(1,1));
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
gradient_threshold > 0 gradient_threshold > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgeImageWithThinning) doxygen_overloaded_function(template <...> void cannyEdgeImageWithThinning)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
void cannyEdgeImageWithThinning( void cannyEdgeImageWithThinning(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
double scale, GradValue gradient_threshold, double scale, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder) DestValue edge_marker, bool addBorder = true)
{ {
// mark pixels that are higher than their neighbors in gradient directi on // mark pixels that are higher than their neighbors in gradient directi on
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(slr-sul); BasicImage<TinyVector<TmpType, 2> > grad(slr-sul);
gaussianGradient(srcIterRange(sul, slr, sa), destImage(grad), scale); gaussianGradient(srcIterRange(sul, slr, sa), destImage(grad), scale);
cannyEdgeImageFromGradWithThinning(srcImageRange(grad), destIter(dul, d a), cannyEdgeImageFromGradWithThinning(srcImageRange(grad), destIter(dul, d a),
gradient_threshold, edge_marker, addBorder); gradient_threshold, edge_marker, addBorder);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class GradValue, class DestValue> class GradValue, class DestValue>
inline void cannyEdgeImageWithThinning( inline void
triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgeImageWithThinning(triple<SrcIterator, SrcIterator, SrcAccessor> sr
pair<DestIterator, DestAccessor> dest, c,
double scale, GradValue gradient_threshold, pair<DestIterator, DestAccessor> dest,
DestValue edge_marker, bool addBorder) double scale, GradValue gradient_threshold,
DestValue edge_marker, bool addBorder = true)
{ {
cannyEdgeImageWithThinning(src.first, src.second, src.third, cannyEdgeImageWithThinning(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale, gradient_threshold, edge_marker, addB order); scale, gradient_threshold, edge_marker, addB order);
} }
template <class SrcIterator, class SrcAccessor, template <class T1, class S1,
class DestIterator, class DestAccessor, class T2, class S2,
class GradValue, class DestValue> class GradValue, class DestValue>
inline void cannyEdgeImageWithThinning( inline void
SrcIterator sul, SrcIterator slr, SrcAccessor sa, cannyEdgeImageWithThinning(MultiArrayView<2, T1, S1> const & src,
DestIterator dul, DestAccessor da, MultiArrayView<2, T2, S2> dest,
double scale, GradValue gradient_threshold, DestValue edge_marke double scale, GradValue gradient_threshold,
r) DestValue edge_marker, bool addBorder = true)
{ {
cannyEdgeImageWithThinning(sul, slr, sa, vigra_precondition(src.shape() == dest.shape(),
dul, da, "cannyEdgeImageWithThinning(): shape mismatch between input and out
scale, gradient_threshold, edge_marker, true put.");
); cannyEdgeImageWithThinning(srcImageRange(src),
} destImage(dest),
scale, gradient_threshold, edge_marker, addB
template <class SrcIterator, class SrcAccessor, order);
class DestIterator, class DestAccessor,
class GradValue, class DestValue>
inline void cannyEdgeImageWithThinning(
triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
double scale, GradValue gradient_threshold, DestValue edge_marke
r)
{
cannyEdgeImageWithThinning(src.first, src.second, src.third,
dest.first, dest.second,
scale, gradient_threshold, edge_marker, true
);
} }
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskImage, class BackInsertable, class GradValue> class MaskImage, class BackInsertable, class GradValue>
void internalCannyFindEdgels3x3(SrcIterator ul, SrcAccessor grad, void internalCannyFindEdgels3x3(SrcIterator ul, SrcAccessor grad,
MaskImage const & mask, MaskImage const & mask,
BackInsertable & edgels, BackInsertable & edgels,
GradValue grad_thresh) GradValue grad_thresh)
skipping to change at line 2243 skipping to change at line 2603
is fitted to 9 points rather than 3 points as in cannyEdgelList(), the accuracy is higher. is fitted to 9 points rather than 3 points as in cannyEdgelList(), the accuracy is higher.
The function can be called in two modes: If you pass a 'scale', it is a ssumed that the The function can be called in two modes: If you pass a 'scale', it is a ssumed that the
original image is scalar, and the Gaussian gradient is internally compu ted at the original image is scalar, and the Gaussian gradient is internally compu ted at the
given 'scale'. If the function is called without scale parameter, it is assumed that given 'scale'. If the function is called without scale parameter, it is assumed that
the given image already contains the gradient (i.e. its value_type must be the given image already contains the gradient (i.e. its value_type must be
a vector of length 2). a vector of length 2).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// compute edgels from a scalar image (determine gradient internall
y at 'scale')
template <class T, class S, class BackInsertable>
void
cannyEdgelList3x3(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels,
double scale);
// compute edgels from a pre-computed gradient image
template <class T, class S, class BackInsertable>
void
cannyEdgelList3x3(MultiArrayView<2, TinyVector<T, 2>, S> const & sr
c,
BackInsertable & edgels);
}
\endcode
\deprecatedAPI{cannyEdgelList3x3}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src, void cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels); BackInsertable & edgels);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src, void cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, double scale); BackInsertable & edgels, double scale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src , cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src ,
BackInsertable & edgels); BackInsertable & edgels);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src , cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src ,
BackInsertable & edgels, double scale); BackInsertable & edgels, double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
// create empty edgel list
std::vector<vigra::Edgel> edgels;
...
// find edgels at scale 0.8
cannyEdgelList3x3(src, edgels, 0.8);
\endcode
\deprecatedUsage{cannyEdgelList3x3}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
// empty edgel list // empty edgel list
std::vector<vigra::Edgel> edgels; std::vector<vigra::Edgel> edgels;
... ...
// find edgels at scale 0.8 // find edgels at scale 0.8
vigra::cannyEdgelList3x3(srcImageRange(src), edgels, 0.8); vigra::cannyEdgelList3x3(srcImageRange(src), edgels, 0.8);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft; SrcImageIterator src_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
src_accessor(src_upperleft); src_accessor(src_upperleft);
BackInsertable edgels; BackInsertable edgels;
edgels.push_back(Edgel()); edgels.push_back(Edgel());
\endcode \endcode
SrcAccessor::value_type must be a type convertible to float SrcAccessor::value_type must be a type convertible to float
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgelList3x3) doxygen_overloaded_function(template <...> void cannyEdgelList3x3)
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
skipping to change at line 2326 skipping to change at line 2715
BackInsertable & edgels, double scale) BackInsertable & edgels, double scale)
{ {
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale);
cannyEdgelList3x3(srcImageRange(grad), edgels); cannyEdgelList3x3(srcImageRange(grad), edgels);
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void
cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale)
{
cannyEdgelList3x3(src.first, src.second, src.third, edgels, scale);
}
template <class SrcIterator, class SrcAccessor, class BackInsertable>
void void
cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels) BackInsertable & edgels)
{ {
typedef typename NormTraits<typename SrcAccessor::value_type>::NormType NormType; typedef typename NormTraits<typename SrcAccessor::value_type>::NormType NormType;
UInt8Image edges(lr-ul); UInt8Image edges(lr-ul);
cannyEdgeImageFromGradWithThinning(srcIterRange(ul, lr, src), destImage (edges), cannyEdgeImageFromGradWithThinning(srcIterRange(ul, lr, src), destImage (edges),
0.0, 1, false); 0.0, 1, false);
// find edgels // find edgels
internalCannyFindEdgels3x3(ul, src, edges, edgels, NumericTraits<NormTy pe>::zero()); internalCannyFindEdgels3x3(ul, src, edges, edgels, NumericTraits<NormTy pe>::zero());
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void inline void
cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src, cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, double scale)
{
cannyEdgelList3x3(src.first, src.second, src.third, edgels, scale);
}
template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void
cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels) BackInsertable & edgels)
{ {
cannyEdgelList3x3(src.first, src.second, src.third, edgels); cannyEdgelList3x3(src.first, src.second, src.third, edgels);
} }
template <class T, class S, class BackInsertable>
inline void
cannyEdgelList3x3(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels, double scale)
{
cannyEdgelList3x3(srcImageRange(src), edgels, scale);
}
template <class T, class S, class BackInsertable>
inline void
cannyEdgelList3x3(MultiArrayView<2, TinyVector<T, 2>, S> const & src,
BackInsertable & edgels)
{
cannyEdgelList3x3(srcImageRange(src), edgels);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* cannyEdgelList3x3Threshold */ /* cannyEdgelList3x3Threshold */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Improved implementation of Canny's edge detector with thresholdi ng. /** \brief Improved implementation of Canny's edge detector with thresholdi ng.
This function works exactly like \ref cannyEdgelList3x3(), but This function works exactly like \ref cannyEdgelList3x3(), but
you also pass a threshold for the minimal gradient magnitude, you also pass a threshold for the minimal gradient magnitude,
so that edgels whose strength is below the threshold are not so that edgels whose strength is below the threshold are not
inserted into the edgel list. inserted into the edgel list.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAcces sor src, cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAcces sor src,
BackInsertable & edgels, GradValue grad_ thresh); BackInsertable & edgels, GradValue grad_ thresh);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAcces sor src, cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAcces sor src,
BackInsertable & edgels, double scale, G radValue grad_thresh); BackInsertable & edgels, double scale, G radValue grad_thresh);
} }
\endcode \endcode
\deprecatedAPI{cannyEdgelList3x3Threshold}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
// compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAcces
sor src,
BackInsertable & edgels, GradValue grad_
thresh);
// compute edgels from a scalar image (determine gradient internall
y at 'scale')
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAcces
sor src,
BackInsertable & edgels, double scale, G
radValue grad_thresh);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// compute edgels from a gradient image // compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAcce ssor> src, cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAcce ssor> src,
BackInsertable & edgels, GradValue grad_ thresh); BackInsertable & edgels, GradValue grad_ thresh);
// compute edgels from a scalar image (determine gradient internall y at 'scale') // compute edgels from a scalar image (determine gradient internall y at 'scale')
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
void void
cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAcce ssor> src, cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAcce ssor> src,
BackInsertable & edgels, double scale, G radValue grad_thresh); BackInsertable & edgels, double scale, G radValue grad_thresh);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
// create empty edgel list
std::vector<vigra::Edgel> edgels;
...
// find edgels at scale 0.8 whose gradient is at least 4.0
cannyEdgelList3x3Threshold(src, edgels, 0.8, 4.0);
\endcode
\deprecatedUsage{cannyEdgelList3x3Threshold}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
// empty edgel list // empty edgel list
std::vector<vigra::Edgel> edgels; std::vector<vigra::Edgel> edgels;
... ...
// find edgels at scale 0.8 // find edgels at scale 0.8 whose gradient is at least 4.0
vigra::cannyEdgelList3x3(srcImageRange(src), edgels, 0.8); vigra::cannyEdgelList3x3Threshold(srcImageRange(src), edgels, 0.8, 4.0)
;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft; SrcImageIterator src_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
src_accessor(src_upperleft); src_accessor(src_upperleft);
BackInsertable edgels; BackInsertable edgels;
edgels.push_back(Edgel()); edgels.push_back(Edgel());
\endcode \endcode
SrcAccessor::value_type must be a type convertible to float SrcAccessor::value_type must be a type convertible to float
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void cannyEdgelList3x3Threshold) doxygen_overloaded_function(template <...> void cannyEdgelList3x3Threshold)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
skipping to change at line 2462 skipping to change at line 2897
{ {
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale);
cannyEdgelList3x3Threshold(srcImageRange(grad), edgels, grad_thresh); cannyEdgelList3x3Threshold(srcImageRange(grad), edgels, grad_thresh);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
inline void
cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAccessor> sr
c,
BackInsertable & edgels, double scale, GradValue
grad_thresh)
{
cannyEdgelList3x3Threshold(src.first, src.second, src.third, edgels, sc
ale, grad_thresh);
}
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void void
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAccessor src, cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, GradValue grad_thresh) BackInsertable & edgels, GradValue grad_thresh)
{ {
UInt8Image edges(lr-ul); UInt8Image edges(lr-ul);
cannyEdgeImageFromGradWithThinning(srcIterRange(ul, lr, src), destImage (edges), cannyEdgeImageFromGradWithThinning(srcIterRange(ul, lr, src), destImage (edges),
0.0, 1, false); 0.0, 1, false);
// find edgels // find edgels
internalCannyFindEdgels3x3(ul, src, edges, edgels, grad_thresh); internalCannyFindEdgels3x3(ul, src, edges, edgels, grad_thresh);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue> class BackInsertable, class GradValue>
inline void inline void
cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAccessor> sr c, cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAccessor> sr c,
BackInsertable & edgels, double scale, GradValue
grad_thresh)
{
cannyEdgelList3x3Threshold(src.first, src.second, src.third, edgels, sc
ale, grad_thresh);
}
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
inline void
cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAccessor> sr
c,
BackInsertable & edgels, GradValue grad_thresh) BackInsertable & edgels, GradValue grad_thresh)
{ {
cannyEdgelList3x3Threshold(src.first, src.second, src.third, edgels, gr ad_thresh); cannyEdgelList3x3Threshold(src.first, src.second, src.third, edgels, gr ad_thresh);
} }
template <class T, class S,
class BackInsertable, class GradValue>
inline void
cannyEdgelList3x3Threshold(MultiArrayView<2, T, S> const & src,
BackInsertable & edgels, double scale, GradValue
grad_thresh)
{
cannyEdgelList3x3Threshold(srcImageRange(src), edgels, scale, grad_thre
sh);
}
template <class T, class S,
class BackInsertable, class GradValue>
inline void
cannyEdgelList3x3Threshold(MultiArrayView<2, TinyVector<T, 2>, S> const & s
rc,
BackInsertable & edgels,
GradValue grad_thresh)
{
cannyEdgelList3x3Threshold(srcImageRange(src), edgels, grad_thresh);
}
//@} //@}
/** \page CrackEdgeImage Crack Edge Image /** \page CrackEdgeImage Crack Edge Image
Crack edges are marked <i>between</i> the pixels of an image. Crack edges are marked <i>between</i> the pixels of an image.
A Crack Edge Image is an image that represents these edges. In order A Crack Edge Image is an image that represents these edges. In order
to accommodate the cracks, the Crack Edge Image must be twice as large to accommodate the cracks, the Crack Edge Image must be twice as large
as the original image (precisely (2*w - 1) by (2*h - 1)). A Crack Edge Imag e as the original image (precisely (2*w - 1) by (2*h - 1)). A Crack Edge Imag e
can easily be derived from a binary image or from the signs of the can easily be derived from a binary image or from the signs of the
response of a Laplacian filter. Consider the following sketch, where response of a Laplacian filter. Consider the following sketch, where
 End of changes. 152 change blocks. 
267 lines changed or deleted 781 lines changed or added


 eigensystem.hxx   eigensystem.hxx 
skipping to change at line 998 skipping to change at line 998
/** Compute the eigensystem of a symmetric matrix. /** Compute the eigensystem of a symmetric matrix.
\a a is a real symmetric matrix, \a ew is a single-column matrix \a a is a real symmetric matrix, \a ew is a single-column matrix
holding the eigenvalues, and \a ev is a matrix of the same size as holding the eigenvalues, and \a ev is a matrix of the same size as
\a a whose columns are the corresponding eigenvectors. Eigenvalues \a a whose columns are the corresponding eigenvectors. Eigenvalues
will be sorted from largest to smallest magnitude. will be sorted from largest to smallest magnitude.
The algorithm returns <tt>false</tt> when it doesn't The algorithm returns <tt>false</tt> when it doesn't
converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is al lowed. converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is al lowed.
The code of this function was adapted from JAMA. The code of this function was adapted from JAMA.
<b>\#include</b> \<vigra/eigensystem.hxx\> or<br> <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool bool
symmetricEigensystem(MultiArrayView<2, T, C1> const & a, symmetricEigensystem(MultiArrayView<2, T, C1> const & a,
MultiArrayView<2, T, C2> & ew, MultiArrayView<2, T, C3> & ev) MultiArrayView<2, T, C2> & ew, MultiArrayView<2, T, C3> & ev)
{ {
vigra_precondition(isSymmetric(a), vigra_precondition(isSymmetric(a),
"symmetricEigensystem(): symmetric input matrix required."); "symmetricEigensystem(): symmetric input matrix required.");
const MultiArrayIndex acols = columnCount(a); const MultiArrayIndex acols = columnCount(a);
skipping to change at line 1097 skipping to change at line 1097
not necessarily symmetric matrix. not necessarily symmetric matrix.
\a a is a real square matrix, \a ew is a single-column matrix \a a is a real square matrix, \a ew is a single-column matrix
holding the possibly complex eigenvalues, and \a ev is a matrix of holding the possibly complex eigenvalues, and \a ev is a matrix of
the same size as \a a whose columns are the corresponding eigenvect ors. the same size as \a a whose columns are the corresponding eigenvect ors.
Eigenvalues will be sorted from largest to smallest magnitude. Eigenvalues will be sorted from largest to smallest magnitude.
The algorithm returns <tt>false</tt> when it doesn't The algorithm returns <tt>false</tt> when it doesn't
converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is al lowed. converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is al lowed.
The code of this function was adapted from JAMA. The code of this function was adapted from JAMA.
<b>\#include</b> \<vigra/eigensystem.hxx\> or<br> <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool bool
nonsymmetricEigensystem(MultiArrayView<2, T, C1> const & a, nonsymmetricEigensystem(MultiArrayView<2, T, C1> const & a,
MultiArrayView<2, std::complex<T>, C2> & ew, MultiArrayView<2, T, C3> & ev) MultiArrayView<2, std::complex<T>, C2> & ew, MultiArrayView<2, T, C3> & ev)
{ {
const MultiArrayIndex acols = columnCount(a); const MultiArrayIndex acols = columnCount(a);
vigra_precondition(acols == rowCount(a), vigra_precondition(acols == rowCount(a),
"nonsymmetricEigensystem(): square input matrix required."); "nonsymmetricEigensystem(): square input matrix required.");
 End of changes. 2 change blocks. 
4 lines changed or deleted 4 lines changed or added


 error.hxx   error.hxx 
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_ERROR_HXX #ifndef VIGRA_ERROR_HXX
#define VIGRA_ERROR_HXX #define VIGRA_ERROR_HXX
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include "config.hxx" #include "config.hxx"
/*! \page ErrorReporting Error Reporting /** \page ErrorReporting Error Reporting
Exceptions and assertions provided by VIGRA Exceptions and assertions provided by VIGRA
<b>\#include</b> \<vigra/error.hxx\> <b>\#include</b> \<vigra/error.hxx\>
VIGRA defines the following exception classes: VIGRA defines the following exception classes:
\code \code
namespace vigra { namespace vigra {
class ContractViolation : public std::exception; class ContractViolation : public std::exception;
class PreconditionViolation : public ContractViolation; class PreconditionViolation : public ContractViolation;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 fftw.hxx   fftw.hxx 
skipping to change at line 605 skipping to change at line 605
/// Read magnitude at offset from iterator position. /// Read magnitude at offset from iterator position.
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class DIFFERENCE>
value_type operator()(ITERATOR const & i, DIFFERENCE d) const { value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
return (i[d]).magnitude(); return (i[d]).magnitude();
} }
}; };
/* documentation: see fftw3.hxx /* documentation: see fftw3.hxx
*/ */
class FFTWLogMagnitudeAccessor
{
public:
/// The accessor's value type.
typedef fftw_real value_type;
/// Read natural log of magnitude at iterator position.
template <class ITERATOR>
value_type operator()(ITERATOR const & i) const {
return std::log((*i).magnitude() + 1);
}
/// Read natural log of magnitude at offset from iterator position.
template <class ITERATOR, class DIFFERENCE>
value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
return std::log((i[d]).magnitude() + 1);
}
};
/* documentation: see fftw3.hxx
*/
class FFTWPhaseAccessor class FFTWPhaseAccessor
{ {
public: public:
/// The accessor's value type. /// The accessor's value type.
typedef fftw_real value_type; typedef fftw_real value_type;
/// Read phase at iterator position. /// Read phase at iterator position.
template <class ITERATOR> template <class ITERATOR>
value_type operator()(ITERATOR const & i) const { value_type operator()(ITERATOR const & i) const {
return (*i).phase(); return (*i).phase();
 End of changes. 1 change blocks. 
0 lines changed or deleted 21 lines changed or added


 fftw3.hxx   fftw3.hxx 
skipping to change at line 1396 skipping to change at line 1396
return (*i).magnitude(); return (*i).magnitude();
} }
/// Read magnitude at offset from iterator position. /// Read magnitude at offset from iterator position.
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class DIFFERENCE>
value_type operator()(ITERATOR const & i, DIFFERENCE d) const { value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
return (i[d]).magnitude(); return (i[d]).magnitude();
} }
}; };
/** Calculate natural logarithm of magnitude of complex number on the f
ly.
<b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
<b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
Namespace: vigra
*/
template <class Real = double>
class FFTWLogMagnitudeAccessor
{
public:
/// The accessor's value type.
typedef Real value_type;
/// Read natural log of magnitude at iterator position.
template <class ITERATOR>
value_type operator()(ITERATOR const & i) const {
return std::log((*i).magnitude() + 1);
}
/// Read natural log of magnitude at offset from iterator position.
template <class ITERATOR, class DIFFERENCE>
value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
return std::log((i[d]).magnitude() + 1);
}
};
/** Calculate phase of complex number on the fly. /** Calculate phase of complex number on the fly.
<b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
<b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template <class Real = double> template <class Real = double>
class FFTWPhaseAccessor class FFTWPhaseAccessor
{ {
public: public:
skipping to change at line 2013 skipping to change at line 2039
filter image, or a purely imaginary, odd symmetric one). filter image, or a purely imaginary, odd symmetric one).
The DC entry of the filter must be in the upper left, which is the The DC entry of the filter must be in the upper left, which is the
position where FFTW expects it (see \ref moveDCToUpperLeft()). position where FFTW expects it (see \ref moveDCToUpperLeft()).
See also \ref convolveFFT() for corresponding functionality on the basi s of the See also \ref convolveFFT() for corresponding functionality on the basi s of the
\ref MultiArrayView interface. \ref MultiArrayView interface.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class SrcImageIterator, class SrcAccessor,
class FilterImageIterator, class FilterAccessor,
class DestImageIterator, class DestAccessor>
void applyFourierFilter(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAccessor
sa,
FilterImageIterator filterUpperLeft, Filter
Accessor fa,
DestImageIterator destUpperLeft, DestAccess
or da);
}
\endcode
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class FilterImageIterator, class FilterAccessor, class FilterImageIterator, class FilterAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void applyFourierFilter(SrcImageIterator srcUpperLeft, void applyFourierFilter(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAccessor sa, SrcImageIterator srcLowerRight, SrcAccessor sa,
FilterImageIterator filterUpperLeft, Filter Accessor fa, FilterImageIterator filterUpperLeft, Filter Accessor fa,
DestImageIterator destUpperLeft, DestAccess or da); DestImageIterator destUpperLeft, DestAccess or da);
} }
skipping to change at line 2243 skipping to change at line 2282
This provides the same functionality as \ref applyFourierFilter(), This provides the same functionality as \ref applyFourierFilter(),
but applying several filters at once allows to avoid but applying several filters at once allows to avoid
repeated Fourier transforms of the source image. repeated Fourier transforms of the source image.
Filters and result images must be stored in \ref vigra::ImageArray data Filters and result images must be stored in \ref vigra::ImageArray data
structures. In contrast to \ref applyFourierFilter(), this function adj usts structures. In contrast to \ref applyFourierFilter(), this function adj usts
the size of the result images and the the length of the array. the size of the result images and the the length of the array.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class SrcImageIterator, class SrcAccessor, class FilterTy
pe>
void applyFourierFilterFamily(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAc
cessor sa,
const ImageArray<FilterType> &filters
,
ImageArray<FFTWComplexImage> &results
)
}
\endcode
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, class FilterTy pe> template <class SrcImageIterator, class SrcAccessor, class FilterTy pe>
void applyFourierFilterFamily(SrcImageIterator srcUpperLeft, void applyFourierFilterFamily(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAc cessor sa, SrcImageIterator srcLowerRight, SrcAc cessor sa,
const ImageArray<FilterType> &filters , const ImageArray<FilterType> &filters ,
ImageArray<FFTWComplexImage> &results ) ImageArray<FFTWComplexImage> &results )
} }
\endcode \endcode
skipping to change at line 2461 skipping to change at line 2511
X even, Y even 1.0 4.0 * (w-1) * (h-1) X even, Y even 1.0 4.0 * (w-1) * (h-1)
X even, Y odd -1.0 -4.0 * (w-1) * (h+1) X even, Y odd -1.0 -4.0 * (w-1) * (h+1)
X odd, Y even -1.0 -4.0 * (w+1) * (h-1) X odd, Y even -1.0 -4.0 * (w+1) * (h-1)
X odd, Y odd 1.0 4.0 * (w+1) * (h+1) X odd, Y odd 1.0 4.0 * (w+1) * (h+1)
\endcode \endcode
where <tt>w</tt> and <tt>h</tt> denote the image width and height. where <tt>w</tt> and <tt>h</tt> denote the image width and height.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class SrcTraverser, class SrcAccessor,
class DestTraverser, class DestAccessor>
void
fourierTransformRealEE(SrcTraverser sul, SrcTraverser slr, SrcAcces
sor src,
DestTraverser dul, DestAccessor dest, fftw_r
eal norm);
fourierTransformRealEO, fourierTransformRealOE, fourierTransformRea
lOO likewise
}
\endcode
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcTraverser, class SrcAccessor, template <class SrcTraverser, class SrcAccessor,
class DestTraverser, class DestAccessor> class DestTraverser, class DestAccessor>
void void
fourierTransformRealEE(SrcTraverser sul, SrcTraverser slr, SrcAcces sor src, fourierTransformRealEE(SrcTraverser sul, SrcTraverser slr, SrcAcces sor src,
DestTraverser dul, DestAccessor dest, fftw_r eal norm); DestTraverser dul, DestAccessor dest, fftw_r eal norm);
fourierTransformRealEO, fourierTransformRealOE, fourierTransformRea lOO likewise fourierTransformRealEO, fourierTransformRealOE, fourierTransformRea lOO likewise
} }
skipping to change at line 2489 skipping to change at line 2552
void void
fourierTransformRealEE(triple<SrcTraverser, SrcTraverser, SrcAccess or> src, fourierTransformRealEE(triple<SrcTraverser, SrcTraverser, SrcAccess or> src,
pair<DestTraverser, DestAccessor> dest, fftw _real norm); pair<DestTraverser, DestAccessor> dest, fftw _real norm);
fourierTransformRealEO, fourierTransformRealOE, fourierTransformRea lOO likewise fourierTransformRealEO, fourierTransformRealOE, fourierTransformRea lOO likewise
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/fftw3.hxx\><br> <b>\#include</b> \<vigra/fftw3.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::FImage spatial(width,height), fourier(width,height); vigra::FImage spatial(width,height), fourier(width,height);
... // fill image with data ... // fill image with data
// forward cosine transform == reflective boundary conditions // forward cosine transform == reflective boundary conditions
fourierTransformRealEE(srcImageRange(spatial), destImage(fourier), (fft w_real)1.0); fourierTransformRealEE(srcImageRange(spatial), destImage(fourier), (fft w_real)1.0);
// multiply with a first derivative of Gaussian in x-direction // multiply with a first derivative of Gaussian in x-direction
for(int y = 0; y < height; ++y) for(int y = 0; y < height; ++y)
 End of changes. 5 change blocks. 
5 lines changed or deleted 79 lines changed or added


 fixedpoint.hxx   fixedpoint.hxx 
skipping to change at line 1183 skipping to change at line 1183
static const Int32 TOTAL_BITS = 15; // bit 16 is sign static const Int32 TOTAL_BITS = 15; // bit 16 is sign
static const Int32 INT_BITS = IntBits; static const Int32 INT_BITS = IntBits;
static const Int32 FRACTIONAL_BITS = TOTAL_BITS - INT_BITS; static const Int32 FRACTIONAL_BITS = TOTAL_BITS - INT_BITS;
static const Int32 MAX = (Int32)((1u << TOTAL_BITS) - 1); static const Int32 MAX = (Int32)((1u << TOTAL_BITS) - 1);
static const Int32 MIN = -(Int32)(1u << TOTAL_BITS); static const Int32 MIN = -(Int32)(1u << TOTAL_BITS);
static const Int32 ONE = 1 << FRACTIONAL_BITS; static const Int32 ONE = 1 << FRACTIONAL_BITS;
static const Int32 ONE_HALF = ONE >> 1; static const Int32 ONE_HALF = ONE >> 1;
static const Int32 FRACTIONAL_MASK = (1u << FRACTIONAL_BITS) - 1; static const Int32 FRACTIONAL_MASK = (1u << FRACTIONAL_BITS) - 1;
static const Int32 INT_MASK = 0xffffffffu ^ FRACTIONAL_MASK; static const Int32 INT_MASK = 0xffffffffu ^ FRACTIONAL_MASK;
static const FixedPoint16 zero, pi, pi_2, mpi_2;
Int16 value; Int16 value;
FixedPoint16() FixedPoint16()
: value(0) : value(0)
{ {
VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns upported_semantics<((-1 >> 8) == -1)>)); VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns upported_semantics<((-1 >> 8) == -1)>));
} }
/** Construct from an int (fractional part will become zero). /** Construct from an int (fractional part will become zero).
Possible overflow is handled according to the target type's <tt >OverflowHandling</tt>. Possible overflow is handled according to the target type's <tt >OverflowHandling</tt>.
skipping to change at line 1377 skipping to change at line 1379
handled according to the target type's <tt>OverflowHandling</tt >. handled according to the target type's <tt>OverflowHandling</tt >.
*/ */
template <int IntBits2> template <int IntBits2>
FixedPoint16 & operator/=(const FixedPoint16<IntBits2, OverflowHandling > &other) FixedPoint16 & operator/=(const FixedPoint16<IntBits2, OverflowHandling > &other)
{ {
value = detail::FP16DivImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value); value = detail::FP16DivImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value);
return *this; return *this;
} }
}; };
template <int IntBits, FPOverflowHandling OverflowHandling>
const FixedPoint16<IntBits, OverflowHandling> FixedPoint16<IntBits, Overflo
wHandling>::zero(0);
template <int IntBits, FPOverflowHandling OverflowHandling>
const FixedPoint16<IntBits, OverflowHandling> FixedPoint16<IntBits, Overflo
wHandling>::pi(M_PI);
template <int IntBits, FPOverflowHandling OverflowHandling>
const FixedPoint16<IntBits, OverflowHandling> FixedPoint16<IntBits, Overflo
wHandling>::pi_2(0.5 * M_PI);
template <int IntBits, FPOverflowHandling OverflowHandling>
const FixedPoint16<IntBits, OverflowHandling> FixedPoint16<IntBits, Overflo
wHandling>::mpi_2(-0.5 * M_PI);
namespace detail { namespace detail {
template <class T> template <class T>
struct FixedPoint16Cast; struct FixedPoint16Cast;
#define VIGRA_FIXED_POINT_CAST(type) \ #define VIGRA_FIXED_POINT_CAST(type) \
template <> \ template <> \
struct FixedPoint16Cast<type> \ struct FixedPoint16Cast<type> \
{ \ { \
template <int IntBits, FPOverflowHandling OverflowHandling> \ template <int IntBits, FPOverflowHandling OverflowHandling> \
skipping to change at line 1639 skipping to change at line 1653
using std::atan2; using std::atan2;
/// Arctangent. Accuracy better than 1/3 degree (9 significant bits). /// Arctangent. Accuracy better than 1/3 degree (9 significant bits).
template <int IntBits, FPOverflowHandling OverflowHandling> template <int IntBits, FPOverflowHandling OverflowHandling>
FixedPoint16<2, OverflowHandling> FixedPoint16<2, OverflowHandling>
atan2(FixedPoint16<IntBits, OverflowHandling> y, FixedPoint16<IntBits, Over flowHandling> x) atan2(FixedPoint16<IntBits, OverflowHandling> y, FixedPoint16<IntBits, Over flowHandling> x)
{ {
enum { ResIntBits = 2 }; enum { ResIntBits = 2 };
typedef FixedPoint16<ResIntBits, OverflowHandling> FP; typedef FixedPoint16<ResIntBits, OverflowHandling> FP;
static const FP zero(0), pi(M_PI), pi_2(0.5 * M_PI), mpi_2(-0.5 * M_PI) static const Int32 Pi_4 = 25736, // = roundi(0.25 * M_PI * (1 <<
; 15)), at 15 frac bits
static const Int32 Pi_4 = roundi(0.25 * M_PI * (1 << 15)), // 15 frac Pi3_4 = 77208, // = roundi(0.75 * M_PI * (1 <<
bits 15)),
Pi3_4 = roundi(0.75 * M_PI * (1 << 15)), c1 = 6497, // = roundi(0.19826763260224867
c1 = roundi(0.19826763260224867 * (1 << 15)), * (1 << 15)),
c2 = roundi(-0.9757748231899761 * (1 << 30)); c2 = -1047730238; // = roundi(-0.9757748231899761
* (1 << 30));
// coefficients c1 and c2 minimize // coefficients c1 and c2 minimize
// //
// NIntegrate[(c1 r^3 + c2 r + Pi/4 - a)^4 /. r -> (Cos[a] - Sin[a])/(C os[a] + Sin[a]), {a, 0, Pi/2}] // NIntegrate[(c1 r^3 + c2 r + Pi/4 - a)^4 /. r -> (Cos[a] - Sin[a])/(C os[a] + Sin[a]), {a, 0, Pi/2}]
// //
// Thanks to Jim Shima, http://www.dspguru.com/comp.dsp/tricks/alg/fxda tan2.htm // Thanks to Jim Shima, http://www.dspguru.com/comp.dsp/tricks/alg/fxda tan2.htm
if(x.value == 0) if(x.value == 0)
return (y.value > 0) return (y.value > 0)
? pi_2 ? FP::pi_2
: (y.value < 0) : (y.value < 0)
? mpi_2 ? FP::mpi_2
: zero; : FP::zero;
Int32 abs_y = abs(y.value); Int32 abs_y = abs(y.value);
Int32 r, angle; Int32 r, angle;
if(x.value > 0) if(x.value > 0)
{ {
if(y.value == 0) if(y.value == 0)
return zero; return FP::zero;
r = ((x.value - abs_y) << 15) / (x.value + abs_y); // 15 frac bits r = ((x.value - abs_y) << 15) / (x.value + abs_y); // 15 frac bits
angle = Pi_4; angle = Pi_4;
} }
else else
{ {
if(y.value == 0) if(y.value == 0)
return pi; return FP::pi;
r = ((x.value + abs_y) << 15) / (abs_y - x.value); // 15 frac bits r = ((x.value + abs_y) << 15) / (abs_y - x.value); // 15 frac bits
angle = Pi3_4; angle = Pi3_4;
} }
angle += r*((c2 + c1 * (sq(r) >> 15)) >> 15) >> 15; angle += r*((c2 + c1 * (sq(r) >> 15)) >> 15) >> 15;
return (y.value > 0) return (y.value > 0)
? FP(detail::FP16Align<0, ResIntBits, true>::exec( angle), F PNoShift) ? FP(detail::FP16Align<0, ResIntBits, true>::exec( angle), F PNoShift)
: FP(detail::FP16Align<0, ResIntBits, true>::exec(-angle), F PNoShift); : FP(detail::FP16Align<0, ResIntBits, true>::exec(-angle), F PNoShift);
} }
 End of changes. 7 change blocks. 
12 lines changed or deleted 32 lines changed or added


 flatmorphology.hxx   flatmorphology.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_FLATMORPHOLOGY_HXX #ifndef VIGRA_FLATMORPHOLOGY_HXX
#define VIGRA_FLATMORPHOLOGY_HXX #define VIGRA_FLATMORPHOLOGY_HXX
#include <cmath> #include <cmath>
#include <vector> #include <vector>
#include "utilities.hxx" #include "utilities.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup Morphology Basic Morphological Operations /** \addtogroup Morphology Basic Morphological Operations
Perform erosion, dilation, and median with disc structuring functions Perform erosion, dilation, and median with disc structuring functions
See also: \ref MultiArrayMorphology Separable morphology with parabola structuring functions in arbitrary dimensions See also: \ref MultiArrayMorphology Separable morphology with parabola structuring functions in arbitrary dimensions
*/ */
//@{ //@{
skipping to change at line 68 skipping to change at line 69
/** \brief Apply rank order filter with disc structuring function to the im age. /** \brief Apply rank order filter with disc structuring function to the im age.
The pixel values of the source image <b> must</b> be in the range The pixel values of the source image <b> must</b> be in the range
0...255. Radius must be >= 0. Rank must be in the range 0.0 <= rank 0...255. Radius must be >= 0. Rank must be in the range 0.0 <= rank
<= 1.0. The filter acts as a minimum filter if rank = 0.0, <= 1.0. The filter acts as a minimum filter if rank = 0.0,
as a median if rank = 0.5, and as a maximum filter if rank = 1.0. as a median if rank = 0.5, and as a maximum filter if rank = 1.0.
Accessor are used to access the pixel data. Accessor are used to access the pixel data.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
discRankOrderFilter(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius, float rank);
}
\endcode
\deprecatedAPI{discRankOrderFilter}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discRankOrderFilter(SrcIterator upperleft1, discRankOrderFilter(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius, float rank) int radius, float rank)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius, float rank) int radius, float rank)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/flatmorphology.hxx\><br> <b>\#include</b> \<vigra/flatmorphology.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w, h), dest(w, h);
// do median filtering (because rank=0.5) in a cricle with radius 10
discRankOrderFilter(src, dest, 10, 0.5);
\endcode
\deprecatedUsage{discRankOrderFilter}
\code
vigra::CImage src, dest; vigra::CImage src, dest;
// do median filtering // do median filtering
vigra::discRankOrderFilter(srcImageRange(src), destImage(dest), 10, 0.5 ); vigra::discRankOrderFilter(srcImageRange(src), destImage(dest), 10, 0.5 );
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft; SrcIterator src_upperleft;
DestIterator dest_upperleft; DestIterator dest_upperleft;
int x, y; int x, y;
unsigned char value; unsigned char value;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
// value_type of accessor must be convertible to unsigned char // value_type of accessor must be convertible to unsigned char
value = src_accessor(src_upperleft, x, y); value = src_accessor(src_upperleft, x, y);
dest_accessor.set(value, dest_upperleft, x, y); dest_accessor.set(value, dest_upperleft, x, y);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
for all source pixels: 0 <= value <= 255 for all source pixels: 0 <= value <= 255
(rank >= 0.0) && (rank <= 1.0) (rank >= 0.0) && (rank <= 1.0)
radius >= 0 radius >= 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void discRankOrderFilter) doxygen_overloaded_function(template <...> void discRankOrderFilter)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discRankOrderFilter(SrcIterator upperleft1, discRankOrderFilter(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius, float rank) int radius, float rank)
skipping to change at line 353 skipping to change at line 373
} }
} }
da.set(rankpos, xd); da.set(rankpos, xd);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void inline void
discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src, discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius, float rank) int radius, float rank)
{ {
discRankOrderFilter(src.first, src.second, src.third, discRankOrderFilter(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
radius, rank); radius, rank);
} }
template <class T1, class S1,
class T2, class S2>
inline void
discRankOrderFilter(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius, float rank)
{
vigra_precondition(src.shape() == dest.shape(),
"discRankOrderFilter(): shape mismatch between input and output.");
discRankOrderFilter(srcImageRange(src),
destImage(dest),
radius, rank);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* discErosion */ /* discErosion */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply erosion (minimum) filter with disc of given radius to imag e. /** \brief Apply erosion (minimum) filter with disc of given radius to imag e.
This is an abbreviation vor the rank order filter with rank = 0.0. This is an abbreviation for the rank order filter with rank = 0.0.
See \ref discRankOrderFilter() for more information. See \ref discRankOrderFilter() for more information.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
discErosion(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius);
}
\endcode
\deprecatedAPI{discErosion}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discErosion(SrcIterator upperleft1, discErosion(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discErosion(triple<SrcIterator, SrcIterator, SrcAccessor> src, discErosion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void discErosion) doxygen_overloaded_function(template <...> void discErosion)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discErosion(SrcIterator upperleft1, discErosion(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
skipping to change at line 432 skipping to change at line 478
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discErosion(): Radius must be >= 0."); vigra_precondition(radius >= 0, "discErosion(): Radius must be >= 0.");
discRankOrderFilter(src.first, src.second, src.third, discRankOrderFilter(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
radius, 0.0); radius, 0.0);
} }
template <class T1, class S1,
class T2, class S2>
inline void
discErosion(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius)
{
vigra_precondition(src.shape() == dest.shape(),
"discErosion(): shape mismatch between input and output.");
discErosion(srcImageRange(src), destImage(dest), radius);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* discDilation */ /* discDilation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply dilation (maximum) filter with disc of given radius to ima ge. /** \brief Apply dilation (maximum) filter with disc of given radius to ima ge.
This is an abbreviation vor the rank order filter with rank = 1.0. This is an abbreviation for the rank order filter with rank = 1.0.
See \ref discRankOrderFilter() for more information. See \ref discRankOrderFilter() for more information.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
discDilation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius);
}
\endcode
\deprecatedAPI{discDilation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discDilation(SrcIterator upperleft1, discDilation(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src, discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void discDilation) doxygen_overloaded_function(template <...> void discDilation)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discDilation(SrcIterator upperleft1, discDilation(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
skipping to change at line 491 skipping to change at line 561
vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.") ; vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.") ;
discRankOrderFilter(upperleft1, lowerright1, sa, discRankOrderFilter(upperleft1, lowerright1, sa,
upperleft2, da, radius, 1.0); upperleft2, da, radius, 1.0);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src, discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.") ; vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.") ;
discRankOrderFilter(src.first, src.second, src.third, discRankOrderFilter(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
radius, 1.0); radius, 1.0);
} }
template <class T1, class S1,
class T2, class S2>
inline void
discDilation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius)
{
vigra_precondition(src.shape() == dest.shape(),
"discDilation(): shape mismatch between input and output.");
discDilation(srcImageRange(src), destImage(dest), radius);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* discMedian */ /* discMedian */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply median filter with disc of given radius to image. /** \brief Apply median filter with disc of given radius to image.
This is an abbreviation vor the rank order filter with rank = 0.5. This is an abbreviation for the rank order filter with rank = 0.5.
See \ref discRankOrderFilter() for more information. See \ref discRankOrderFilter() for more information.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
discMedian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius);
}
\endcode
\deprecatedAPI{discMedian}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discMedian(SrcIterator upperleft1, discMedian(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src, discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void discMedian) doxygen_overloaded_function(template <...> void discMedian)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discMedian(SrcIterator upperleft1, discMedian(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
skipping to change at line 560 skipping to change at line 654
vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0."); vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0.");
discRankOrderFilter(upperleft1, lowerright1, sa, discRankOrderFilter(upperleft1, lowerright1, sa,
upperleft2, da, radius, 0.5); upperleft2, da, radius, 0.5);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src, discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0."); vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0.");
discRankOrderFilter(src.first, src.second, src.third, discRankOrderFilter(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
radius, 0.5); radius, 0.5);
} }
template <class T1, class S1,
class T2, class S2>
inline void
discMedian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
int radius)
{
vigra_precondition(src.shape() == dest.shape(),
"discMedian(): shape mismatch between input and output.");
discMedian(srcImageRange(src), destImage(dest), radius);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* discRankOrderFilterWithMask */ /* discRankOrderFilterWithMask */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply rank order filter with disc structuring function to the im age /** \brief Apply rank order filter with disc structuring function to the im age
using a mask. using a mask.
The pixel values of the source image <b> must</b> be in the range The pixel values of the source image <b> must</b> be in the range
skipping to change at line 592 skipping to change at line 698
as a median if rank = 0.5, and as a maximum filter if rank = 1.0. as a median if rank = 0.5, and as a maximum filter if rank = 1.0.
Accessor are used to access the pixel data. Accessor are used to access the pixel data.
The mask is only applied to th input image, i.e. the function The mask is only applied to th input image, i.e. the function
generates an output wherever the current disc contains at least generates an output wherever the current disc contains at least
one pixel with mask value 'true'. Source pixels with mask value one pixel with mask value 'true'. Source pixels with mask value
'false' are ignored during the calculation of the rank order. 'false' are ignored during the calculation of the rank order.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
void
discRankOrderFilterWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius, float rank);
}
\endcode
\deprecatedAPI{discRankOrderFilterWithMask}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discRankOrderFilterWithMask(SrcIterator upperleft1, discRankOrderFilterWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa , SrcIterator lowerright1, SrcAccessor sa ,
MaskIterator upperleftm, MaskAccessor m ask, MaskIterator upperleftm, MaskAccessor m ask,
DestIterator upperleft2, DestAccessor d a, DestIterator upperleft2, DestAccessor d a,
int radius, float rank) int radius, float rank)
} }
\endcode \endcode
group arguments (use in conjunction with \ref ArgumentObjectFactories): group arguments (use in conjunction with \ref ArgumentObjectFactories):
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAcc essor> src, discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAcc essor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius, float rank) int radius, float rank)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/flatmorphology.hxx\><br> <b>\#include</b> \<vigra/flatmorphology.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w, h), dest(w, h), mask(w, h);
...
// do median filtering (since rank=0.5) in a circle with radius 10
// but change only the pixels under the mask
discRankOrderFilterWithMask(src, mask, dest, 10, 0.5);
\endcode
\deprecatedUsage{discRankOrderFilterWithMask}
\code
vigra::CImage src, dest, mask; vigra::CImage src, dest, mask;
// do median filtering // do median filtering
vigra::discRankOrderFilterWithMask(srcImageRange(src), vigra::discRankOrderFilterWithMask(srcImageRange(src),
maskImage(mask), destImage(dest), 10, 0.5); maskImage(mask), destImage(dest), 10, 0.5);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft; SrcIterator src_upperleft;
DestIterator dest_upperleft; DestIterator dest_upperleft;
MaskIterator mask_upperleft; MaskIterator mask_upperleft;
int x, y; int x, y;
unsigned char value; unsigned char value;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
MaskAccessor mask_accessor; MaskAccessor mask_accessor;
mask_accessor(mask_upperleft, x, y) // convertible to bool mask_accessor(mask_upperleft, x, y) // convertible to bool
// value_type of accessor must be convertible to unsigned char // value_type of accessor must be convertible to unsigned char
value = src_accessor(src_upperleft, x, y); value = src_accessor(src_upperleft, x, y);
dest_accessor.set(value, dest_upperleft, x, y); dest_accessor.set(value, dest_upperleft, x, y);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
for all source pixels: 0 <= value <= 255 for all source pixels: 0 <= value <= 255
(rank >= 0.0) && (rank <= 1.0) (rank >= 0.0) && (rank <= 1.0)
radius >= 0 radius >= 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void discRankOrderFilterWithMask ) doxygen_overloaded_function(template <...> void discRankOrderFilterWithMask )
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discRankOrderFilterWithMask(SrcIterator upperleft1, discRankOrderFilterWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
skipping to change at line 927 skipping to change at line 1055
leftsum = 0; leftsum = 0;
rankpos = 0; rankpos = 0;
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void inline void
discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius, float rank) int radius, float rank)
{ {
discRankOrderFilterWithMask(src.first, src.second, src.third, discRankOrderFilterWithMask(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, dest.first, dest.second,
radius, rank); radius, rank);
}
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
inline void
discRankOrderFilterWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius, float rank)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"discRankOrderFilterWithMask(): shape mismatch between input and ou
tput.");
discRankOrderFilterWithMask(srcImageRange(src),
maskImage(mask),
destImage(dest),
radius, rank);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* discErosionWithMask */ /* discErosionWithMask */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply erosion (minimum) filter with disc of given radius to imag e /** \brief Apply erosion (minimum) filter with disc of given radius to imag e
using a mask. using a mask.
This is an abbreviation vor the masked rank order filter with This is an abbreviation for the masked rank order filter with
rank = 0.0. See \ref discRankOrderFilterWithMask() for more information . rank = 0.0. See \ref discRankOrderFilterWithMask() for more information .
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
void
discErosionWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius);
}
\endcode
\deprecatedAPI{discErosionWithMask}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discErosionWithMask(SrcIterator upperleft1, discErosionWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
} }
\endcode \endcode
group arguments (use in conjunction with \ref ArgumentObjectFactories): group arguments (use in conjunction with \ref ArgumentObjectFactories):
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void discErosionWithMask) doxygen_overloaded_function(template <...> void discErosionWithMask)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discErosionWithMask(SrcIterator upperleft1, discErosionWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
skipping to change at line 1015 skipping to change at line 1174
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src, discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discErosionWithMask(): Radius must be >= 0."); vigra_precondition(radius >= 0, "discErosionWithMask(): Radius must be >= 0.");
discRankOrderFilterWithMask(src.first, src.second, src.third, discRankOrderFilterWithMask(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, dest.first, dest.second,
radius, 0.0); radius, 0.0);
}
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
inline void
discErosionWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"discErosionWithMask(): shape mismatch between input and output.");
discErosionWithMask(srcImageRange(src), maskImage(mask), destImage(dest
), radius);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* discDilationWithMask */ /* discDilationWithMask */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply dilation (maximum) filter with disc of given radius to ima ge /** \brief Apply dilation (maximum) filter with disc of given radius to ima ge
using a mask. using a mask.
This is an abbreviation vor the masked rank order filter with This is an abbreviation for the masked rank order filter with
rank = 1.0. See \ref discRankOrderFilterWithMask() for more information . rank = 1.0. See \ref discRankOrderFilterWithMask() for more information .
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
void
discDilationWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius);
}
\endcode
\deprecatedAPI{discDilationWithMask}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discDilationWithMask(SrcIterator upperleft1, discDilationWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
} }
\endcode \endcode
group arguments (use in conjunction with \ref ArgumentObjectFactories): group arguments (use in conjunction with \ref ArgumentObjectFactories):
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src, discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void discDilationWithMask) doxygen_overloaded_function(template <...> void discDilationWithMask)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discDilationWithMask(SrcIterator upperleft1, discDilationWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0."); vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0.");
discRankOrderFilterWithMask(upperleft1, lowerright1, sa, discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
upperleftm, mask, upperleftm, mask,
upperleft2, da, upperleft2, da,
radius, 1.0); radius, 1.0);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src, discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0."); vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0.");
discRankOrderFilterWithMask(src.first, src.second, src.third, discRankOrderFilterWithMask(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, dest.first, dest.second,
radius, 1.0); radius, 1.0);
}
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
inline void
discDilationWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"discDilationWithMask(): shape mismatch between input and output.")
;
discDilationWithMask(srcImageRange(src), maskImage(mask), destImage(des
t), radius);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* discMedianWithMask */ /* discMedianWithMask */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply median filter with disc of given radius to image /** \brief Apply median filter with disc of given radius to image
using a mask. using a mask.
This is an abbreviation vor the masked rank order filter with This is an abbreviation for the masked rank order filter with
rank = 0.5. See \ref discRankOrderFilterWithMask() for more information . rank = 0.5. See \ref discRankOrderFilterWithMask() for more information .
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
void
discMedianWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius);
}
\endcode
\deprecatedAPI{discMedianWithMask}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discMedianWithMask(SrcIterator upperleft1, discMedianWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
DestIterator upperleft2, DestAccessor da, DestIterator upperleft2, DestAccessor da,
int radius) int radius)
} }
\endcode \endcode
group arguments (use in conjunction with \ref ArgumentObjectFactories): group arguments (use in conjunction with \ref ArgumentObjectFactories):
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> sr c, discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> sr c,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void discMedianWithMask) doxygen_overloaded_function(template <...> void discMedianWithMask)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discMedianWithMask(SrcIterator upperleft1, discMedianWithMask(SrcIterator upperleft1,
SrcIterator lowerright1, SrcAccessor sa, SrcIterator lowerright1, SrcAccessor sa,
MaskIterator upperleftm, MaskAccessor mask, MaskIterator upperleftm, MaskAccessor mask,
skipping to change at line 1170 skipping to change at line 1385
upperleftm, mask, upperleftm, mask,
upperleft2, da, upperleft2, da,
radius, 0.5); radius, 0.5);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src, discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
int radius) int radius)
{ {
vigra_precondition(radius >= 0, "discMedianWithMask(): Radius must be > = 0."); vigra_precondition(radius >= 0, "discMedianWithMask(): Radius must be > = 0.");
discRankOrderFilterWithMask(src.first, src.second, src.third, discRankOrderFilterWithMask(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, dest.first, dest.second,
radius, 0.5); radius, 0.5);
} }
template <class T1, class S1,
class TM, class SM,
class T2, class S2>
inline void
discMedianWithMask(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
int radius)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"discMedianWithMask(): shape mismatch between input and output.");
discMedianWithMask(srcImageRange(src), maskImage(mask), destImage(dest)
, radius);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_FLATMORPHOLOGY_HXX #endif // VIGRA_FLATMORPHOLOGY_HXX
 End of changes. 57 change blocks. 
60 lines changed or deleted 298 lines changed or added


 functortraits.hxx   functortraits.hxx 
skipping to change at line 150 skipping to change at line 150
<DT><b>TernaryAnalyser</b> <DT><b>TernaryAnalyser</b>
<DD> <tt>f(a1, a2, a3)</tt> (return type <tt>void</tt>) <DD> <tt>f(a1, a2, a3)</tt> (return type <tt>void</tt>)
</DL> </DL>
It should be noted that the functor's argument and result types are not contained It should be noted that the functor's argument and result types are not contained
in the traits class: Since the function calls are often member template functions in in the traits class: Since the function calls are often member template functions in
VIGRA, many functors do not have fixed argument types. Neither are the result VIGRA, many functors do not have fixed argument types. Neither are the result
types fixed in this case because they are computed (via a template meta -program) types fixed in this case because they are computed (via a template meta -program)
from the argument types. from the argument types.
<b>\#include</b> \<vigra/functortraits.hxx\> <b>\#include</b> \<vigra/functortraits.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
class FunctorTraits class FunctorTraits
: public FunctorTraitsBase<T> : public FunctorTraitsBase<T>
{}; {};
#define VIGRA_DEFINE_STL_FUNCTOR(name, unary, binary) \ #define VIGRA_DEFINE_STL_FUNCTOR(name, unary, binary) \
template <class T> \ template <class T> \
class FunctorTraits<name<T> > \ class FunctorTraits<name<T> > \
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 gaborfilter.hxx   gaborfilter.hxx 
skipping to change at line 46 skipping to change at line 46
#ifndef VIGRA_GABORFILTER_HXX #ifndef VIGRA_GABORFILTER_HXX
#define VIGRA_GABORFILTER_HXX #define VIGRA_GABORFILTER_HXX
#include "imagecontainer.hxx" #include "imagecontainer.hxx"
#include "config.hxx" #include "config.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "copyimage.hxx" #include "copyimage.hxx"
#include "transformimage.hxx" #include "transformimage.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
#include "utilities.hxx" #include "utilities.hxx"
#include "multi_shape.hxx"
#include <functional> #include <functional>
#include <vector> #include <vector>
#include <cmath> #include <cmath>
namespace vigra { namespace vigra {
/** \addtogroup GaborFilter Gabor Filter /** \addtogroup GaborFilter Gabor Filter
Functions to create or apply gabor filter (latter based on FFTW). Functions to create or apply gabor filter (latter based on FFTW).
*/ */
skipping to change at line 75 skipping to change at line 76
The orientation is given in radians, the other parameters are the The orientation is given in radians, the other parameters are the
center frequency (for example 0.375 or smaller) and the two center frequency (for example 0.375 or smaller) and the two
angular and radial sigmas of the gabor filter. (See \ref angular and radial sigmas of the gabor filter. (See \ref
angularGaborSigma() for an explanation of possible values.) angularGaborSigma() for an explanation of possible values.)
The energy of the filter is explicitly normalized to 1.0. The energy of the filter is explicitly normalized to 1.0.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S>
void
createGaborFilter(MultiArrayView<2, T, S> dest,
double orientation, double centerFrequency,
double angularSigma, double radialSigma);
}
\endcode
\deprecatedAPI{createGaborFilter}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class DestImageIterator, class DestAccessor> template <class DestImageIterator, class DestAccessor>
void createGaborFilter(DestImageIterator destUpperLeft, void createGaborFilter(DestImageIterator destUpperLeft,
DestImageIterator destLowerRight, DestImageIterator destLowerRight,
DestAccessor da, DestAccessor da,
double orientation, double centerFrequency, double orientation, double centerFrequency,
double angularSigma, double radialSigma) double angularSigma, double radialSigma)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class DestImageIterator, class DestAccessor> template <class DestImageIterator, class DestAccessor>
void createGaborFilter(triple<DestImageIterator, void createGaborFilter(triple<DestImageIterator,
DestImageIterator, DestImageIterator,
DestAccessor> dest, DestAccessor> dest,
double orientation, double centerFrequency, double orientation, double centerFrequency,
double angularSigma, double radialSigma) double angularSigma, double radialSigma)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/gaborfilter.hxx\><br> <b>\#include</b> \<vigra/gaborfilter.hxx\><br/>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> gabor(w,h);
createGaborFilter(gabor, orient, freq,
angularGaborSigma(directionCount, freq),
radialGaborSigma(freq));
\endcode
\deprecatedUsage{createGaborFilter}
\code
vigra::FImage gabor(w,h); vigra::FImage gabor(w,h);
vigra::createGaborFilter(destImageRange(gabor), orient, freq, vigra::createGaborFilter(destImageRange(gabor), orient, freq,
angularGaborSigma(directionCount, freq) angularGaborSigma(directionCount, freq),
radialGaborSigma(freq)); radialGaborSigma(freq));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void createGaborFilter) doxygen_overloaded_function(template <...> void createGaborFilter)
template <class DestImageIterator, class DestAccessor> template <class DestImageIterator, class DestAccessor>
void createGaborFilter(DestImageIterator destUpperLeft, void createGaborFilter(DestImageIterator destUpperLeft,
DestImageIterator destLowerRight, DestAccessor da, DestImageIterator destLowerRight, DestAccessor da,
double orientation, double centerFrequency, double orientation, double centerFrequency,
double angularSigma, double radialSigma) double angularSigma, double radialSigma)
{ {
int w = int(destLowerRight.x - destUpperLeft.x); int w = int(destLowerRight.x - destUpperLeft.x);
skipping to change at line 180 skipping to change at line 202
typename DestImageIterator::row_iterator dix = destUpperLeft.rowIte rator(); typename DestImageIterator::row_iterator dix = destUpperLeft.rowIte rator();
for ( int x=0; x<w; x++, dix++ ) for ( int x=0; x<w; x++, dix++ )
{ {
da.set( da(dix) / factor, dix ); da.set( da(dix) / factor, dix );
} }
} }
} }
template <class DestImageIterator, class DestAccessor> template <class DestImageIterator, class DestAccessor>
inline inline void
void createGaborFilter(triple<DestImageIterator, DestImageIterator, createGaborFilter(triple<DestImageIterator, DestImageIterator, DestAccessor
DestAccessor> dest, > dest,
double orientation, double centerFrequency, double orientation, double centerFrequency,
double angularSigma, double radialSigma) double angularSigma, double radialSigma)
{ {
createGaborFilter(dest.first, dest.second, dest.third, createGaborFilter(dest.first, dest.second, dest.third,
orientation, centerFrequency, orientation, centerFrequency,
angularSigma, radialSigma); angularSigma, radialSigma);
} }
template <class T, class S>
inline void
createGaborFilter(MultiArrayView<2, T, S> dest,
double orientation, double centerFrequency,
double angularSigma, double radialSigma)
{
createGaborFilter(destImageRange(dest),
orientation, centerFrequency,
angularSigma, radialSigma);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* radialGaborSigma */ /* radialGaborSigma */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate sensible radial sigma for given parameters. /** \brief Calculate sensible radial sigma for given parameters.
For a brief introduction what is meant with "sensible" sigmas, see For a brief introduction what is meant with "sensible" sigmas, see
\ref angularGaborSigma(). \ref angularGaborSigma().
skipping to change at line 213 skipping to change at line 245
\code \code
namespace vigra { namespace vigra {
double radialGaborSigma(double centerFrequency) double radialGaborSigma(double centerFrequency)
} }
\endcode \endcode
*/ */
inline double radialGaborSigma(double centerFrequency) inline double radialGaborSigma(double centerFrequency)
{ {
static double sfactor = 3.0 * VIGRA_CSTD::sqrt(VIGRA_CSTD::log(4.0)); double sfactor = 3.0 * VIGRA_CSTD::sqrt(VIGRA_CSTD::log(4.0));
return centerFrequency / sfactor; return centerFrequency / sfactor;
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* angularGaborSigma */ /* angularGaborSigma */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate sensible angular sigma for given parameters. /** \brief Calculate sensible angular sigma for given parameters.
skipping to change at line 282 skipping to change at line 314
The filter parameters are chosen to make the center frequencies The filter parameters are chosen to make the center frequencies
decrease in octaves with increasing scale indices, and to make the decrease in octaves with increasing scale indices, and to make the
half-peak-magnitude ellipses touch each other to somewhat reduce half-peak-magnitude ellipses touch each other to somewhat reduce
redundancy in the filter answers. This is done by using \ref redundancy in the filter answers. This is done by using \ref
angularGaborSigma() and \ref radialGaborSigma(), you'll find more angularGaborSigma() and \ref radialGaborSigma(), you'll find more
information there. information there.
The template parameter ImageType should be a scalar image type suitable for filling in The template parameter ImageType should be a scalar image type suitable for filling in
<b>\#include</b> \<vigra/gaborfilter.hxx\> <b>\#include</b> \<vigra/gaborfilter.hxx\><br/>
Namespace: vigra Namespace: vigra
*/ */
template <class ImageType, template <class ImageType,
class Alloc = typename ImageType::allocator_type::template rebind<Ima geType>::other > class Alloc = typename ImageType::allocator_type::template rebind <ImageType>::other >
class GaborFilterFamily class GaborFilterFamily
: public ImageArray<ImageType, Alloc> : public ImageArray<ImageType, Alloc>
{ {
typedef ImageArray<ImageType, Alloc> ParentClass; typedef ImageArray<ImageType, Alloc> ParentClass;
int scaleCount_, directionCount_; int scaleCount_, directionCount_;
double maxCenterFrequency_; double maxCenterFrequency_;
protected: protected:
void initFilters() void initFilters()
{ {
 End of changes. 13 change blocks. 
14 lines changed or deleted 46 lines changed or added


 gaussians.hxx   gaussians.hxx 
skipping to change at line 52 skipping to change at line 52
#include "array_vector.hxx" #include "array_vector.hxx"
#include "error.hxx" #include "error.hxx"
namespace vigra { namespace vigra {
#if 0 #if 0
/** \addtogroup MathFunctions Mathematical Functions /** \addtogroup MathFunctions Mathematical Functions
*/ */
//@{ //@{
#endif #endif
/*! The Gaussian function and its derivatives. /** The Gaussian function and its derivatives.
Implemented as a unary functor. Since it supports the <tt>radius()</tt> function Implemented as a unary functor. Since it supports the <tt>radius()</tt> function
it can also be used as a kernel in \ref resamplingConvolveImage(). it can also be used as a kernel in \ref resamplingConvolveImage().
<b>\#include</b> \<vigra/gaussians.hxx\><br> <b>\#include</b> \<vigra/gaussians.hxx\><br>
Namespace: vigra Namespace: vigra
\ingroup MathFunctions \ingroup MathFunctions
*/ */
template <class T = double> template <class T = double>
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 gradient_energy_tensor.hxx   gradient_energy_tensor.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_GRADIENT_ENERGY_TENSOR_HXX #define VIGRA_GRADIENT_ENERGY_TENSOR_HXX
#include <cmath> #include <cmath>
#include <functional> #include <functional>
#include "utilities.hxx" #include "utilities.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "basicimage.hxx" #include "basicimage.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "convolution.hxx" #include "convolution.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup TensorImaging Tensor Image Processing /** \addtogroup TensorImaging Tensor Image Processing
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* gradientEnergyTensor */ /* gradientEnergyTensor */
skipping to change at line 83 skipping to change at line 84
with the given filters: The derivative filter \a derivKernel is applied to the appropriate image dimensions with the given filters: The derivative filter \a derivKernel is applied to the appropriate image dimensions
in turn (see the papers above for details), and the other dimension is smoothed with \a smoothKernel. in turn (see the papers above for details), and the other dimension is smoothed with \a smoothKernel.
The kernels can be as small as 3x1, e.g. [0.5, 0, -0.5] and [3.0/16.0, 10.0/16.0, 3.0/16.0] respectively. The kernels can be as small as 3x1, e.g. [0.5, 0, -0.5] and [3.0/16.0, 10.0/16.0, 3.0/16.0] respectively.
The output image must have 3 bands which will hold the The output image must have 3 bands which will hold the
tensor components in the order t11, t12 (== t21), t22. The signs of the output are adjusted for a right-handed tensor components in the order t11, t12 (== t21), t22. The signs of the output are adjusted for a right-handed
coordinate system. Thus, orientations derived from the tensor will be i n counter-clockwise (mathematically positive) coordinate system. Thus, orientations derived from the tensor will be i n counter-clockwise (mathematically positive)
order, with the x-axis at zero degrees (this is the standard in all VIG RA functions that deal with orientation). order, with the x-axis at zero degrees (this is the standard in all VIG RA functions that deal with orientation).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
gradientEnergyTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<double> const & derivKernel, Kernel1D
<double> const & smoothKernel);
}
\endcode
\deprecatedAPI{gradientEnergyTensor}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gradientEnergyTensor(SrcIterator supperleft, SrcIterator slowe rright, SrcAccessor src, void gradientEnergyTensor(SrcIterator supperleft, SrcIterator slowe rright, SrcAccessor src,
DestIterator dupperleft, DestAccessor des t, DestIterator dupperleft, DestAccessor des t,
Kernel1D<double> const & derivKernel, Ker nel1D<double> const & smoothKernel); Kernel1D<double> const & derivKernel, Ker nel1D<double> const & smoothKernel);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gradientEnergyTensor(triple<SrcIterator, SrcIterator, SrcAcces sor> src, void gradientEnergyTensor(triple<SrcIterator, SrcIterator, SrcAcces sor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Kernel1D<double> const & derivKernel, Ker nel1D<double> const & smoothKernel); Kernel1D<double> const & derivKernel, Ker nel1D<double> const & smoothKernel);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/gradient_energy_tensor.hxx\> <b>\#include</b> \<vigra/gradient_energy_tensor.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> img(w,h);
MultiArray<2, TinyVector<float, 3> > get(w,h);
Kernel1D<double> grad, smooth;
grad.initGaussianDerivative(0.7, 1);
smooth.initGaussian(0.7);
...
gradientEnergyTensor(img, get, grad, smooth);
\endcode
\deprecatedUsage{gradientEnergyTensor}
\code \code
FImage img(w,h); FImage img(w,h);
FVector3Image get(w,h); FVector3Image get(w,h);
Kernel1D<double> grad, smooth; Kernel1D<double> grad, smooth;
grad.initGaussianDerivative(0.7, 1); grad.initGaussianDerivative(0.7, 1);
smooth.initGaussian(0.7); smooth.initGaussian(0.7);
... ...
gradientEnergyTensor(srcImageRange(img), destImage(get), grad, smooth); gradientEnergyTensor(srcImageRange(img), destImage(get), grad, smooth);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void gradientEnergyTensor) doxygen_overloaded_function(template <...> void gradientEnergyTensor)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void gradientEnergyTensor(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor src, void gradientEnergyTensor(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor src,
DestIterator dupperleft, DestAccessor dest, DestIterator dupperleft, DestAccessor dest,
Kernel1D<double> const & derivKernel, Kernel1D<do uble> const & smoothKernel) Kernel1D<double> const & derivKernel, Kernel1D<do uble> const & smoothKernel)
{ {
vigra_precondition(dest.size(dupperleft) == 3, vigra_precondition(dest.size(dupperleft) == 3,
skipping to change at line 178 skipping to change at line 204
{ {
dest.setComponent(sq(*gxxi) + sq(*gxyi) - *gxi * *gx3i, d, 0); dest.setComponent(sq(*gxxi) + sq(*gxyi) - *gxi * *gx3i, d, 0);
dest.setComponent(- *gxyi * (*gxxi + *gyyi) + 0.5 * (*gxi * *gy 3i + *gyi * *gx3i), d, 1); dest.setComponent(- *gxyi * (*gxxi + *gyyi) + 0.5 * (*gxi * *gy 3i + *gyi * *gx3i), d, 1);
dest.setComponent(sq(*gxyi) + sq(*gyyi) - *gyi * *gy3i, d, 2); dest.setComponent(sq(*gxyi) + sq(*gyyi) - *gyi * *gy3i, d, 2);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void gradientEnergyTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src gradientEnergyTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, Kernel1D<double> const & derivKernel, Kernel1D<double>
Kernel1D<double> const & derivKernel, Kernel1D<do const & smoothKernel)
uble> const & smoothKernel)
{ {
gradientEnergyTensor(src.first, src.second, src.third, gradientEnergyTensor(src.first, src.second, src.third,
dest.first, dest.second, derivKernel, smoothKernel ); dest.first, dest.second, derivKernel, smoothKernel );
} }
template <class T1, class S1,
class T2, class S2>
inline void
gradientEnergyTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<double> const & derivKernel, Kernel1D<double>
const & smoothKernel)
{
vigra_precondition(src.shape() == dest.shape(),
"gradientEnergyTensor(): shape mismatch between input and output.")
;
gradientEnergyTensor(srcImageRange(src),
destImage(dest), derivKernel, smoothKernel);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_GRADIENT_ENERGY_TENSOR_HXX #endif // VIGRA_GRADIENT_ENERGY_TENSOR_HXX
 End of changes. 9 change blocks. 
10 lines changed or deleted 51 lines changed or added


 hdf5impex.hxx   hdf5impex.hxx 
skipping to change at line 40 skipping to change at line 40
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_HDF5IMPEX_HXX #ifndef VIGRA_HDF5IMPEX_HXX
#define VIGRA_HDF5IMPEX_HXX #define VIGRA_HDF5IMPEX_HXX
#include <string> #include <string>
#include <algorithm>
#include <utility>
#define H5Gcreate_vers 2 #define H5Gcreate_vers 2
#define H5Gopen_vers 2 #define H5Gopen_vers 2
#define H5Dopen_vers 2 #define H5Dopen_vers 2
#define H5Dcreate_vers 2 #define H5Dcreate_vers 2
#define H5Acreate_vers 2 #define H5Acreate_vers 2
#include <hdf5.h> #include <hdf5.h>
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6) #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
skipping to change at line 75 skipping to change at line 77
# ifndef H5Pset_obj_track_times # ifndef H5Pset_obj_track_times
# define H5Pset_obj_track_times(a, b) do {} while (0) # define H5Pset_obj_track_times(a, b) do {} while (0)
# endif # endif
# include <H5LT.h> # include <H5LT.h>
#else #else
# include <hdf5_hl.h> # include <hdf5_hl.h>
#endif #endif
#include "impex.hxx" #include "impex.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "multi_iterator_coupled.hxx"
#include "multi_impex.hxx" #include "multi_impex.hxx"
#include "utilities.hxx" #include "utilities.hxx"
#include "error.hxx" #include "error.hxx"
#include <algorithm> #if defined(_MSC_VER)
# include <io.h>
#else
# include <unistd.h>
#endif
namespace vigra { namespace vigra {
/** \addtogroup VigraHDF5Impex Import/Export of Images and Arrays in HDF5 F ormat /** \addtogroup VigraHDF5Impex Import/Export of Images and Arrays in HDF5 F ormat
Supports arrays with arbitrary element types and arbitrary many dimensi ons. Supports arrays with arbitrary element types and arbitrary many dimensi ons.
See the <a href="http://www.hdfgroup.org/HDF5/">HDF5 Website</a> for mo re See the <a href="http://www.hdfgroup.org/HDF5/">HDF5 Website</a> for mo re
information on the HDF5 file format. information on the HDF5 file format.
*/ */
//@{ //@{
/** \brief Wrapper for hid_t objects. /** \brief Check if given filename refers to a HDF5 file.
*/
inline bool isHDF5(char const * filename)
{
#ifdef _MSC_VER
return _access(filename, 0) != -1 && H5Fis_hdf5(filename);
#else
return access(filename, F_OK) == 0 && H5Fis_hdf5(filename);
#endif
}
/** \brief Temporarily disable HDF5's native error output.
This should be used when you want to call an HDF5 function
that is known to fail (e.g. during testing), or when you want
to use an alternative error reporting mechanism (e.g. exceptions).
<b>Usage:</b>
<b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra
\code
{
HDF5DisableErrorOutput hdf5DisableErrorOutput;
... // call some HDF5 function
} // restore the original error reporting in the destructor of HDF5
DisableErrorOutput
\endcode
*/
class HDF5DisableErrorOutput
{
H5E_auto2_t old_func_;
void *old_client_data_;
HDF5DisableErrorOutput(HDF5DisableErrorOutput const &);
HDF5DisableErrorOutput & operator=(HDF5DisableErrorOutput const &);
public:
HDF5DisableErrorOutput()
: old_func_(0)
, old_client_data_(0)
{
H5Eget_auto2(H5E_DEFAULT, &old_func_, &old_client_data_);
H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
}
~HDF5DisableErrorOutput()
{
H5Eset_auto2(H5E_DEFAULT, old_func_, old_client_data_);
}
};
/** \brief Wrapper for unique hid_t objects.
This class offers the functionality of <tt>std::unique_ptr</tt> for HDF
5 handles
(type <tt>hid_t</tt>). Unfortunately, <tt>std::unique_ptr</tt> cannot b
e used directly
for this purpose because it only works with pointers, whereas <tt>hid_t
</tt> is an integer type.
Newly created or opened HDF5 handles are usually stored as objects of t ype 'hid_t'. When the handle Newly created or opened HDF5 handles are stored as objects of type <tt> hid_t</tt>. When the handle
is no longer needed, the appropriate close function must be called. How ever, if a function is is no longer needed, the appropriate close function must be called. How ever, if a function is
aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that
solves this problem by calling the close function in the destructor (Th is is analogous to how solves this problem by calling the close function in the destructor (Th is is analogous to how
VIGRA_UNIQUE_PTR calls 'delete' on the contained pointer). A pointer to <tt>std::unique_ptr</tt> calls 'delete' on the contained pointer). A po
the close function must be inter to the close function
passed to the constructor, along with an error message that is raised w must be passed to the constructor, along with an error message that is
hen creation/opening fails. raised when
creation/opening fails.
Since HDF5Handle objects are convertible to hid_t, they can be used in When a <tt>HDF5Handle</tt> is created or assigned from another one, own
the code in place ership passes on to the
of the latter. left-hand-side handle object, and the right-hand-side objects is resest
to a NULL handle.
Since <tt>HDF5Handle</tt> objects are convertible to <tt>hid_t</tt>, th
ey can be used in the code
in place of the latter.
<b>Usage:</b> <b>Usage:</b>
\code \code
HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
&H5Fclose, &H5Fclose,
"Error message."); "Error message when H5Fopen() fails.");
... // use file_id in the same way as a plain hid_t object ... // use file_id in the same way as a plain hid_t object
// pass ownership to a new handle object
HDF5Handle new_handle(file_id);
assert(file_id.get() == 0);
\endcode \endcode
<b>\#include</b> \<vigra/hdf5impex.hxx\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class HDF5Handle class HDF5Handle
{ {
public: public:
typedef herr_t (*Destructor)(hid_t); typedef herr_t (*Destructor)(hid_t);
skipping to change at line 141 skipping to change at line 214
: handle_( 0 ), : handle_( 0 ),
destructor_(0) destructor_(0)
{} {}
/** \brief Create a wrapper for a hid_t object. /** \brief Create a wrapper for a hid_t object.
The hid_t object \a h is assumed to be the return value of an open or create function. The hid_t object \a h is assumed to be the return value of an open or create function.
It will be closed with the given close function \a destructor as so on as this It will be closed with the given close function \a destructor as so on as this
HDF5Handle is destructed, except when \a destructor is a NULL point er (in which HDF5Handle is destructed, except when \a destructor is a NULL point er (in which
case nothing happens at destruction time). If \a h has a value that indicates case nothing happens at destruction time). If \a h has a value that indicates
failed opening or creation (by HDF5 convention, this means if it is a negative number), failed opening or creation (by HDF5 convention, this means that \a h is negative),
an exception is raised by calling <tt>vigra_fail(error_message)</tt >. an exception is raised by calling <tt>vigra_fail(error_message)</tt >.
<b>Usage:</b> <b>Usage:</b>
\code \code
HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
&H5Fclose, &H5Fclose,
"Error message."); "Error message.");
... // use file_id in the same way ... // use file_id in the same way
skipping to change at line 163 skipping to change at line 236
*/ */
HDF5Handle(hid_t h, Destructor destructor, const char * error_message) HDF5Handle(hid_t h, Destructor destructor, const char * error_message)
: handle_( h ), : handle_( h ),
destructor_(destructor) destructor_(destructor)
{ {
if(handle_ < 0) if(handle_ < 0)
vigra_fail(error_message); vigra_fail(error_message);
} }
/** \brief Copy constructor. /** \brief Copy constructor.
Hands over ownership of the RHS handle (analogous to VIGRA_UNIQ
UE_PTR). Hands over ownership of the RHS handle (analogous to <tt>std::u
nique_pt</tt>).
*/ */
HDF5Handle(HDF5Handle const & h) HDF5Handle(HDF5Handle const & h)
: handle_( h.handle_ ), : handle_( h.handle_ ),
destructor_(h.destructor_) destructor_(h.destructor_)
{ {
const_cast<HDF5Handle &>(h).handle_ = 0; const_cast<HDF5Handle &>(h).handle_ = 0;
} }
/** \brief Assignment. /** \brief Assignment.
Calls close() for the LHS handle and hands over ownership of th e Calls close() for the LHS handle and hands over ownership of th e
RHS handle (analogous to VIGRA_UNIQUE_PTR). RHS handle (analogous to <tt>std::unique_pt</tt>).
*/ */
HDF5Handle & operator=(HDF5Handle const & h) HDF5Handle & operator=(HDF5Handle const & h)
{ {
if(h.handle_ != handle_) if(h.handle_ != handle_)
{ {
close(); close();
handle_ = h.handle_; handle_ = h.handle_;
destructor_ = h.destructor_; destructor_ = h.destructor_;
const_cast<HDF5Handle &>(h).handle_ = 0; const_cast<HDF5Handle &>(h).handle_ = 0;
} }
skipping to change at line 196 skipping to change at line 270
} }
/** \brief Destructor. /** \brief Destructor.
Calls close() for the contained handle. Calls close() for the contained handle.
*/ */
~HDF5Handle() ~HDF5Handle()
{ {
close(); close();
} }
/** \brief Explicitly call the stored function (if one has been sto /** \brief Explicitly call the stored destructor (if one has been r
red within egistered in the
this object) for the contained handle and set the handle to NU constructor) for the contained handle and set the wrapper to N
LL. ULL. Returns
a negative value when the destructor call for the handle fails
, and
a non-negative value otherwise.
*/ */
herr_t close() herr_t close()
{ {
herr_t res = 1; herr_t res = 1;
if(handle_ && destructor_) if(handle_ && destructor_)
res = (*destructor_)(handle_); res = (*destructor_)(handle_);
handle_ = 0; handle_ = 0;
destructor_ = 0;
return res;
}
/** \brief Return the contained handle and set the wrapper to NULL
without calling <tt>close()</tt>.
*/
hid_t release()
{
hid_t res = handle_;
handle_ = 0;
destructor_ = 0;
return res; return res;
} }
/** \brief Reset the wrapper to a new handle.
Equivalent to <tt>handle = HDF5Handle(h, destructor, error_mes
sage)</tt>.
*/
void reset(hid_t h, Destructor destructor, const char * error_message)
{
if(h < 0)
vigra_fail(error_message);
if(h != handle_)
{
close();
handle_ = h;
destructor_ = destructor;
}
}
/** \brief Swap the contents of two handle wrappers.
Also available as <tt>std::swap(handle1, handle2)</tt>.
*/
void swap(HDF5Handle & h)
{
std::swap(handle_, h.handle_);
std::swap(destructor_, h.destructor_);
}
/** \brief Get a temporary hid_t object for the contained handle. /** \brief Get a temporary hid_t object for the contained handle.
Do not call a close function on the return value - a crash will be likely Do not call a close function on the return value - a crash will be likely
otherwise. otherwise.
*/ */
hid_t get() const hid_t get() const
{ {
return handle_; return handle_;
} }
/** \brief Convert to a plain hid_t object. /** \brief Convert to a plain hid_t object.
skipping to change at line 257 skipping to change at line 371
} }
/** \brief Inequality comparison of the contained handle. /** \brief Inequality comparison of the contained handle.
*/ */
bool operator!=(hid_t h) const bool operator!=(hid_t h) const
{ {
return handle_ != h; return handle_ != h;
} }
}; };
/** \brief Wrapper for shared hid_t objects.
This class offers the functionality of <tt>std::shared_ptr</tt> for HDF
5 handles
(type <tt>hid_t</tt>). Unfortunately, <tt>std::shared_ptr</tt> cannot b
e used directly
for this purpose because it only works with pointers, whereas <tt>hid_t
</tt> is an integer type.
Newly created or opened HDF5 handles are stored as objects of type <tt>
hid_t</tt>. When the handle
is no longer needed, the appropriate close function must be called. How
ever, if a function is
aborted by an exception, this is difficult to ensure. Class HDF5HandleS
hared is a smart pointer
that solves this problem by calling the close function in the destructo
r of the handle's last
owner (This is analogous to how <tt>std::shared_ptr</tt> calls 'delete'
on the contained
pointer). A pointer to the close function must be passed to the constru
ctor, along with an error
message that is raised when creation/opening fails.
When a <tt>HDF5HandleShared</tt> is created or assigned from another on
e, ownership is shared
between the two handles, and the value returned by <tt>use_count()</tt>
increases by one.
Since <tt>HDF5HandleShared</tt> objects are convertible to <tt>hid_t</t
t>, they can be used in the code
in place of the latter.
<b>Usage:</b>
\code
HDF5HandleShared file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
&H5Fclose,
"Error message when H5Fopen() fails.");
... // use file_id in the same way as a plain hid_t object
// share ownership between same_id and file_id
HDF5HandleShared same_id(file_id);
assert(same_id.use_count() == 2);
assert(same_id.get() == file_id.get());
\endcode
<b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra
*/
class HDF5HandleShared
{
public:
typedef herr_t (*Destructor)(hid_t);
private:
hid_t handle_;
Destructor destructor_;
size_t * refcount_;
public:
/** \brief Default constructor.
Creates a NULL handle.
**/
HDF5HandleShared()
: handle_( 0 ),
destructor_(0),
refcount_(0)
{}
/** \brief Create a shared wrapper for a plain hid_t object.
The hid_t object \a h is assumed to be the return value of an open
or create function.
It will be closed with the given close function \a destructor as so
on as this
HDF5HandleShared is destructed, except when \a destructor is a NULL
pointer (in which
case nothing happens at destruction time). If \a h has a value that
indicates
failed opening or creation (by HDF5 convention, this means that \a
h is negative),
an exception is raised by calling <tt>vigra_fail(error_message)</tt
>.
<b>Usage:</b>
\code
HDF5HandleShared file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAUL
T),
&H5Fclose,
"Error message.");
... // use file_id in the same way
\endcode
*/
HDF5HandleShared(hid_t h, Destructor destructor, const char * error_mes
sage)
: handle_( h ),
destructor_(destructor),
refcount_(0)
{
if(handle_ < 0)
vigra_fail(error_message);
if(handle_ > 0)
refcount_ = new size_t(1);
}
/** \brief Copy constructor.
Shares ownership with the RHS handle (analogous to <tt>std::sha
red_ptr</tt>).
*/
HDF5HandleShared(HDF5HandleShared const & h)
: handle_( h.handle_ ),
destructor_(h.destructor_),
refcount_(h.refcount_)
{
if(refcount_)
++(*refcount_);
}
/** \brief Assignment.
Call close() for the present LHS handle and share ownership wit
h the
RHS handle (analogous to <tt>std::shared_ptr</tt>).
*/
HDF5HandleShared & operator=(HDF5HandleShared const & h)
{
if(h.handle_ != handle_)
{
close();
handle_ = h.handle_;
destructor_ = h.destructor_;
refcount_ = h.refcount_;
if(refcount_)
++(*refcount_);
}
return *this;
}
/** \brief Destructor (calls close())
*/
~HDF5HandleShared()
{
close();
}
/** \brief Close the handle if this is the unique (i.e. last) owner
.
Decrements the reference counter and calls the destructor func
tion of
the handle (if one has been registered in the constructor) whe
n the counter
reaches zero. Sets this wrapper to NULL in any case. Returns
a negative value when the destructor call for the handle fails
, and
a non-negative value otherwise.
*/
herr_t close()
{
herr_t res = 1;
if(refcount_)
{
--(*refcount_);
if(*refcount_ == 0)
{
if(destructor_)
res = (*destructor_)(handle_);
delete refcount_;
}
}
handle_ = 0;
destructor_ = 0;
refcount_ = 0;
return res;
}
/** \brief Reset the handle to a new value.
Equivalent to <tt>handle = HDF5HandleShared(h, destructor, err
or_message)</tt>.
*/
void reset(hid_t h, Destructor destructor, const char * error_message)
{
if(h < 0)
vigra_fail(error_message);
if(h != handle_)
{
close();
handle_ = h;
destructor_ = destructor;
if(handle_ > 0)
refcount_ = new size_t(1);
}
}
/** \brief Get the number of owners of the contained handle.
*/
size_t use_count() const
{
return refcount_
? *refcount_
: 0;
}
/** \brief Check if this is the unique owner of the conatined handl
e.
Equivalent to <tt>handle.use_count() == 1</tt>.
*/
bool unique() const
{
return use_count() == 1;
}
/** \brief Swap the contents of two handle wrappers.
Also available as <tt>std::swap(handle1, handle2)</tt>.
*/
void swap(HDF5HandleShared & h)
{
std::swap(handle_, h.handle_);
std::swap(destructor_, h.destructor_);
std::swap(refcount_, h.refcount_);
}
/** \brief Get a temporary hid_t object for the contained handle.
Do not call a close function on the return value - a crash will
be likely
otherwise.
*/
hid_t get() const
{
return handle_;
}
/** \brief Convert to a plain hid_t object.
This function ensures that hid_t objects can be transparently repla
ced with
HDF5HandleShared objects in user code. Do not call a close function
on the return
value - a crash will be likely otherwise.
*/
operator hid_t() const
{
return handle_;
}
/** \brief Equality comparison of the contained handle.
*/
bool operator==(HDF5HandleShared const & h) const
{
return handle_ == h.handle_;
}
/** \brief Equality comparison of the contained handle.
*/
bool operator==(hid_t h) const
{
return handle_ == h;
}
/** \brief Inequality comparison of the contained handle.
*/
bool operator!=(HDF5HandleShared const & h) const
{
return handle_ != h.handle_;
}
/** \brief Inequality comparison of the contained handle.
*/
bool operator!=(hid_t h) const
{
return handle_ != h;
}
};
//@}
} // namespace vigra
namespace std {
inline void swap(vigra::HDF5Handle & l, vigra::HDF5Handle & r)
{
l.swap(r);
}
inline void swap(vigra::HDF5HandleShared & l, vigra::HDF5HandleShared & r)
{
l.swap(r);
}
} // namespace std
namespace vigra {
/** \addtogroup VigraHDF5Impex
*/
//@{
/********************************************************/ /********************************************************/
/* */ /* */
/* HDF5ImportInfo */ /* HDF5ImportInfo */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Argument object for the function readHDF5(). /** \brief Argument object for the function readHDF5().
See \ref readHDF5() for a usage example. This object must be See \ref readHDF5() for a usage example. This object must be
used to read an image or array from an HDF5 file used to read an image or array from an HDF5 file
skipping to change at line 340 skipping to change at line 727
order relative to the file contents. That is, when the axes in the file are order relative to the file contents. That is, when the axes in the file are
ordered as 'z', 'y', 'x', this function will return the shape i n the order ordered as 'z', 'y', 'x', this function will return the shape i n the order
'x', 'y', 'z'. 'x', 'y', 'z'.
*/ */
VIGRA_EXPORT MultiArrayIndex shapeOfDimension(const int dim) const; VIGRA_EXPORT MultiArrayIndex shapeOfDimension(const int dim) const;
/** Query the pixel type of the dataset. /** Query the pixel type of the dataset.
Possible values are: Possible values are:
<DL> <DL>
<DT>"INT8"<DD> 8-bit signed integer (unsigned char)
<DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
<DT>"INT16"<DD> 16-bit signed integer (short) <DT>"INT16"<DD> 16-bit signed integer (short)
<DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short) <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
<DT>"INT32"<DD> 32-bit signed integer (long) <DT>"INT32"<DD> 32-bit signed integer (long)
<DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long) <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
<DT>"INT64"<DD> 64-bit signed integer (long long)
<DT>"UINT64"<DD> 64-bit unsigned integer (unsigned long long)
<DT>"FLOAT"<DD> 32-bit floating point (float) <DT>"FLOAT"<DD> 32-bit floating point (float)
<DT>"DOUBLE"<DD> 64-bit floating point (double) <DT>"DOUBLE"<DD> 64-bit floating point (double)
</DL> </DL>
*/ */
VIGRA_EXPORT const char * getPixelType() const; VIGRA_EXPORT const char * getPixelType() const;
/** Query the pixel type of the dataset. /** Query the pixel type of the dataset.
Same as getPixelType(), but the result is returned as a Same as getPixelType(), but the result is returned as a
ImageImportInfo::PixelType enum. This is useful to implement ImageImportInfo::PixelType enum. This is useful to implement
skipping to change at line 371 skipping to change at line 761
<DT>UINT16<DD> 16-bit unsigned integer (unsigned short) <DT>UINT16<DD> 16-bit unsigned integer (unsigned short)
<DT>INT32<DD> 32-bit signed integer (long) <DT>INT32<DD> 32-bit signed integer (long)
<DT>UINT32<DD> 32-bit unsigned integer (unsigned long) <DT>UINT32<DD> 32-bit unsigned integer (unsigned long)
<DT>FLOAT<DD> 32-bit floating point (float) <DT>FLOAT<DD> 32-bit floating point (float)
<DT>DOUBLE<DD> 64-bit floating point (double) <DT>DOUBLE<DD> 64-bit floating point (double)
</DL> </DL>
*/ */
VIGRA_EXPORT PixelType pixelType() const; VIGRA_EXPORT PixelType pixelType() const;
private: private:
HDF5Handle m_file_handle, m_dataset_handle; HDF5HandleShared m_file_handle, m_dataset_handle;
std::string m_filename, m_path, m_pixeltype; std::string m_filename, m_path, m_pixeltype;
hssize_t m_dimensions; hssize_t m_dimensions;
ArrayVector<hsize_t> m_dims; ArrayVector<hsize_t> m_dims;
}; };
namespace detail { namespace detail {
template<class type> template <class T>
struct HDF5TypeTraits
{
static hid_t getH5DataType()
{
std::runtime_error("getH5DataType(): invalid type");
return 0;
}
static int numberOfBands()
{
std::runtime_error("numberOfBands(): invalid type");
return 0;
}
};
template<class T>
inline hid_t getH5DataType() inline hid_t getH5DataType()
{ {
std::runtime_error("getH5DataType(): invalid type"); return HDF5TypeTraits<T>::getH5DataType();
return 0;
} }
#define VIGRA_H5_DATATYPE(type, h5type) \ #define VIGRA_H5_DATATYPE(type, h5type) \
template<> \ template <> \
inline hid_t getH5DataType<type>() \ struct HDF5TypeTraits<type> \
{ return h5type;} { \
static hid_t getH5DataType() \
{ \
return h5type; \
} \
static int numberOfBands() \
{ \
return 1; \
} \
typedef type value_type; \
}; \
template <int M> \
struct HDF5TypeTraits<TinyVector<type, M> > \
{ \
static hid_t getH5DataType() \
{ \
return h5type; \
} \
static int numberOfBands() \
{ \
return M; \
} \
typedef type value_type; \
}; \
template <> \
struct HDF5TypeTraits<RGBValue<type> > \
{ \
static hid_t getH5DataType() \
{ \
return h5type; \
} \
static int numberOfBands() \
{ \
return 3; \
} \
typedef type value_type; \
}; \
VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR) VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
VIGRA_H5_DATATYPE(signed char, H5T_NATIVE_SCHAR)
VIGRA_H5_DATATYPE(unsigned char, H5T_NATIVE_UCHAR)
VIGRA_H5_DATATYPE(signed short, H5T_NATIVE_SHORT)
VIGRA_H5_DATATYPE(unsigned short, H5T_NATIVE_USHORT)
VIGRA_H5_DATATYPE(signed int, H5T_NATIVE_INT)
VIGRA_H5_DATATYPE(unsigned int, H5T_NATIVE_UINT)
VIGRA_H5_DATATYPE(signed long, H5T_NATIVE_LONG)
VIGRA_H5_DATATYPE(unsigned long, H5T_NATIVE_ULONG)
VIGRA_H5_DATATYPE(signed long long, H5T_NATIVE_LLONG)
VIGRA_H5_DATATYPE(unsigned long long, H5T_NATIVE_ULLONG)
VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT) VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT)
VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE) VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE)
VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE) VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE)
// char arrays with flexible length require 'handcrafted' H5 datatype // char arrays with flexible length require 'handcrafted' H5 datatype
template<> template <>
inline hid_t getH5DataType<char*>() struct HDF5TypeTraits<char*>
{ {
hid_t stringtype = H5Tcopy (H5T_C_S1); static hid_t getH5DataType()
H5Tset_size(stringtype, H5T_VARIABLE); {
return stringtype; hid_t stringtype = H5Tcopy (H5T_C_S1);
} H5Tset_size(stringtype, H5T_VARIABLE);
template<> return stringtype;
inline hid_t getH5DataType<const char*>() }
static int numberOfBands()
{
return 1;
}
};
template <>
struct HDF5TypeTraits<const char*>
{ {
hid_t stringtype = H5Tcopy (H5T_C_S1); static hid_t getH5DataType()
H5Tset_size(stringtype, H5T_VARIABLE); {
return stringtype; hid_t stringtype = H5Tcopy (H5T_C_S1);
} H5Tset_size(stringtype, H5T_VARIABLE);
#undef VIGRA_H5_DATATYPE return stringtype;
}
#define VIGRA_H5_SIGNED_DATATYPE(type) \ static int numberOfBands()
template<> \ {
inline hid_t getH5DataType<type>() \ return 1;
{ static hid_t types[] = {0, H5T_NATIVE_INT8, H5T_NATIVE_INT16, 0, H5T_NATI }
VE_INT32, 0,0,0,H5T_NATIVE_INT64}; \ };
return types[sizeof(type)];}
VIGRA_H5_SIGNED_DATATYPE(signed char)
VIGRA_H5_SIGNED_DATATYPE(signed short)
VIGRA_H5_SIGNED_DATATYPE(signed int)
VIGRA_H5_SIGNED_DATATYPE(signed long)
VIGRA_H5_SIGNED_DATATYPE(signed long long)
#undef VIGRA_H5_SIGNED_DATATYPE
#define VIGRA_H5_UNSIGNED_DATATYPE(type) \
template<> \
inline hid_t getH5DataType<type>() \
{ static hid_t types[] = {0, H5T_NATIVE_UINT8, H5T_NATIVE_UINT16, 0, H5T_NA
TIVE_UINT32, 0,0,0,H5T_NATIVE_UINT64}; \
return types[sizeof(type)];}
VIGRA_H5_UNSIGNED_DATATYPE(unsigned char)
VIGRA_H5_UNSIGNED_DATATYPE(unsigned short)
VIGRA_H5_UNSIGNED_DATATYPE(unsigned int)
VIGRA_H5_UNSIGNED_DATATYPE(unsigned long)
VIGRA_H5_UNSIGNED_DATATYPE(unsigned long long)
#undef VIGRA_H5_UNSIGNED_DATATYPE #undef VIGRA_H5_DATATYPE
#if 0 #if 0
template<> template<>
inline hid_t getH5DataType<FFTWComplex<float> >() inline hid_t getH5DataType<FFTWComplex<float> >()
{ {
hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<float>) ); hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<float>) );
H5Tinsert (complex_id, "real", 0, H5T_NATIVE_FLOAT); H5Tinsert (complex_id, "real", 0, H5T_NATIVE_FLOAT);
H5Tinsert (complex_id, "imaginary", sizeof(float), H5T_NATIVE_FLOAT); H5Tinsert (complex_id, "imaginary", sizeof(float), H5T_NATIVE_FLOAT);
return complex_id; return complex_id;
} }
skipping to change at line 471 skipping to change at line 912
} // namespace detail } // namespace detail
// helper friend function for callback HDF5_ls_inserter_callback() // helper friend function for callback HDF5_ls_inserter_callback()
void HDF5_ls_insert(void*, const std::string &); void HDF5_ls_insert(void*, const std::string &);
// callback function for ls(), called via HDF5File::H5Literate() // callback function for ls(), called via HDF5File::H5Literate()
// see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-3 3.2 // see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-3 3.2
// for as to why. // for as to why.
VIGRA_EXPORT H5O_type_t HDF5_get_type(hid_t, const char*); VIGRA_EXPORT H5O_type_t HDF5_get_type(hid_t, const char*);
extern "C" VIGRA_EXPORT herr_t HDF5_ls_inserter_callback(hid_t, const char* , const H5L_info_t*, void*); extern "C" VIGRA_EXPORT herr_t HDF5_ls_inserter_callback(hid_t, const char* , const H5L_info_t*, void*);
extern "C" VIGRA_EXPORT herr_t HDF5_listAttributes_inserter_callback(hid_t, const char*, const H5A_info_t*, void*);
/********************************************************/ /********************************************************/
/* */ /* */
/* HDF5File */ /* HDF5File */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Access to HDF5 files /** \brief Access to HDF5 files
HDF5File provides a convenient way of accessing data in HDF5 files. vigra:: MultiArray HDF5File provides a convenient way of accessing data in HDF5 files. vigra:: MultiArray
skipping to change at line 512 skipping to change at line 954
file.read("dataset", in_multi_array); file.read("dataset", in_multi_array);
\endcode \endcode
<b>\#include</b> \<vigra/hdf5impex.hxx\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class HDF5File class HDF5File
{ {
protected: protected:
HDF5Handle fileHandle_; HDF5HandleShared fileHandle_;
// current group handle // current group handle
HDF5Handle cGroupHandle_; HDF5Handle cGroupHandle_;
private: private:
// time tagging of datasets, turned off (= 0) by default. // time tagging of datasets, turned off (= 0) by default.
int track_time; int track_time;
// helper class for ls() bool read_only_;
// helper classes for ls() and listAttributes()
struct ls_closure struct ls_closure
{ {
virtual void insert(const std::string &) = 0; virtual void insert(const std::string &) = 0;
virtual ~ls_closure() {} virtual ~ls_closure() {}
}; };
// datastructure to hold a list of dataset and group names
// datastructure to hold a std::vector<std::string>
struct lsOpData : public ls_closure struct lsOpData : public ls_closure
{ {
std::vector<std::string> & objects; std::vector<std::string> & objects;
lsOpData(std::vector<std::string> & o) : objects(o) {} lsOpData(std::vector<std::string> & o) : objects(o) {}
void insert(const std::string & x) void insert(const std::string & x)
{ {
objects.push_back(x); objects.push_back(x);
} }
}; };
// (associative-)container closure
// datastructure to hold an associative container
template<class Container> template<class Container>
struct ls_container_data : public ls_closure struct ls_container_data : public ls_closure
{ {
Container & objects; Container & objects;
ls_container_data(Container & o) : objects(o) {} ls_container_data(Container & o) : objects(o) {}
void insert(const std::string & x) void insert(const std::string & x)
{ {
objects.insert(std::string(x)); objects.insert(std::string(x));
} }
}; };
public: public:
// helper for callback HDF5_ls_inserter_callback(), used by ls() // helper for callback HDF5_ls_inserter_callback(), used by ls()
friend void HDF5_ls_insert(void*, const std::string &); friend void HDF5_ls_insert(void*, const std::string &);
/** \brief Set how a file is opened. /** \brief Set how a file is opened.
OpenMode::New creates a new file. If the file already exists, o OpenMode::New creates a new file. If the file already exists, i
verwrite it. t is overwritten.
OpenMode::ReadWrite opens a file for reading/writing. The file
will be created if it doesn't exist.
OpenMode::Open opens a file for reading/writing. The file will OpenMode::ReadOnly opens a file for reading. The file as well a
be created, s any dataset to be accessed must already exist.
if necessary.
*/ */
enum OpenMode { enum OpenMode {
New, // Create new empty file (existing file will be dele New, // Create new empty file (existing file will be d
ted). eleted).
Open, // Open file. Create if not existing. Open, // Open file. Create if not existing.
OpenReadOnly // Open file in read-only mode. ReadWrite = Open, // Alias for Open.
OpenReadOnly, // Open file in read-only mode.
ReadOnly = OpenReadOnly, // Alias for OpenReadOnly
Replace, // for ChunkedArrayHDF5: replace dataset if it ex
ists, create otherwise
Default // for ChunkedArrayHDF5: use New if file doesn't
exist,
// ReadOnly if file and
dataset exist
// Open otherwise
}; };
/** \brief Default constructor. /** \brief Default constructor.
A file can later be opened via the open() function. A file can later be opened via the open() function. Time tagging of
datasets is disabled.
*/
HDF5File()
: track_time(0)
{}
/** \brief Construct with time tagging of datasets enabled.
If \a track_creation_times is non-zero, time tagging of datasets wi If \a track_creation_times is 'true', time tagging of datasets will
ll be enabled (it is disabled be enabled.
by default).
*/ */
HDF5File(int track_creation_times = 0) explicit HDF5File(bool track_creation_times)
: track_time(track_creation_times) : track_time(track_creation_times ? 1 : 0),
read_only_(true)
{} {}
/** \brief Open or create an HDF5File object. /** \brief Open or create an HDF5File object.
Creates or opens HDF5 file with given filename. Creates or opens HDF5 file with given filename.
The current group is set to "/". The current group is set to "/".
Note that the HDF5File class is not copyable (the copy constructor is Note that the HDF5File class is not copyable (the copy constructor is
private to enforce this). private to enforce this).
*/ */
HDF5File(std::string filename, OpenMode mode, int track_creation_times HDF5File(std::string filePath, OpenMode mode, bool track_creation_times
= 0) = false)
: track_time(track_creation_times) : track_time(track_creation_times ? 1 : 0)
{
open(filePath, mode);
}
/** \brief Initialize an HDF5File object from HDF5 file handle
Initializes an HDF5File object corresponding to the HDF5 file
opened elsewhere. If \a fileHandle is constructed with a
<tt>NULL</tt> destructor, ownership is not transferred
to the new HDF5File object, and you must ensure that the file is
not closed while the new HDF5File object is in use. Otherwise,
ownership will be shared.
The current group is set to the specified \a pathname. If
\a read_only is 'true', you cannot create new datasets or
overwrite data.
\warning In case the underlying HDF5 library used by Vigra is not
exactly the same library used to open the file with the given id,
this method will lead to crashes.
*/
explicit HDF5File(HDF5HandleShared const & fileHandle,
const std::string & pathname = "",
bool read_only = false)
: fileHandle_(fileHandle),
read_only_(read_only)
{ {
open(filename, mode); // get group handle for given pathname
// calling openCreateGroup_ without setting a valid cGroupHandle do
es
// not work. Starting from root() is a safe bet.
root();
cGroupHandle_ = HDF5Handle(openCreateGroup_(pathname), &H5Gclose,
"HDF5File(fileHandle, pathname): Failed to open group");
// extract track_time attribute
hbool_t track_times_tmp;
HDF5Handle plist_id(H5Fget_create_plist(fileHandle_), &H5Pclose,
"HDF5File(fileHandle, pathname): Failed to open file creati
on property list");
herr_t status = H5Pget_obj_track_times(plist_id, &track_times_tmp )
;
vigra_postcondition(status >= 0,
"HDF5File(fileHandle, pathname): cannot access track time attri
bute");
track_time = track_times_tmp;
}
/** \brief Copy a HDF5File object.
The new object will refer to the same file and group as \a othe
r.
*/
HDF5File(HDF5File const & other)
: fileHandle_(other.fileHandle_),
track_time(other.track_time),
read_only_(other.read_only_)
{
cGroupHandle_ = HDF5Handle(openCreateGroup_(other.currentGroupName_
()), &H5Gclose,
"HDF5File(HDF5File const &): Failed to o
pen group.");
} }
/** \brief The destructor flushes and closes the file. /** \brief The destructor flushes and closes the file.
*/ */
~HDF5File() ~HDF5File()
{ {
// The members fileHandle_ and cGroupHandle_ are automatically clos ed // The members fileHandle_ and cGroupHandle_ are automatically clos ed
// as they are of type HDF5Handle and are properly initialised. // as they are of type HDF5Handle and are properly initialised.
// The closing of fileHandle_ implies flushing the file to // The closing of fileHandle_ implies flushing the file to
// the operating system, see // the operating system, see
// http://www.hdfgroup.org/HDF5/doc/RM/RM_H5F.html#File-Close . // http://www.hdfgroup.org/HDF5/doc/RM/RM_H5F.html#File-Close .
} }
// copying is not permitted. /** \brief Assign a HDF5File object.
private:
HDF5File(const HDF5File &);
void operator=(const HDF5File &);
public: Calls close() on the present file and The new object will refer
to the same file and group as \a other.
*/
HDF5File & operator=(HDF5File const & other)
{
if(this != &other)
{
close();
fileHandle_ = other.fileHandle_;
cGroupHandle_ = HDF5Handle(openCreateGroup_(other.currentGroupN
ame_()), &H5Gclose,
"HDF5File::operator=(): Failed to op
en group.");
track_time = other.track_time;
read_only_ = other.read_only_;
}
return *this;
}
int file_use_count() const
{
return fileHandle_.use_count();
}
bool isOpen() const
{
return fileHandle_ != 0;
}
bool isReadOnly() const
{
return read_only_;
}
void setReadOnly(bool stat=true)
{
read_only_ = stat;
}
/** \brief Open or create the given file in the given mode and set the group to "/". /** \brief Open or create the given file in the given mode and set the group to "/".
If another file is currently open, it is first closed. If another file is currently open, it is first closed.
*/ */
void open(std::string filename, OpenMode mode) void open(std::string filePath, OpenMode mode)
{ {
close(); close();
std::string errorMessage = "HDF5File.open(): Could not open or crea std::string errorMessage = "HDF5File.open(): Could not open or crea
te file '" + filename + "'."; te file '" + filePath + "'.";
fileHandle_ = HDF5Handle(createFile_(filename, mode), &H5Fclose, er fileHandle_ = HDF5HandleShared(createFile_(filePath, mode), &H5Fclo
rorMessage.c_str()); se, errorMessage.c_str());
cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5F ile.open(): Failed to open root group."); cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5F ile.open(): Failed to open root group.");
setReadOnly(mode == OpenReadOnly);
} }
/** \brief Close the current file. /** \brief Close the current file.
*/ */
void close() void close()
{ {
bool success = cGroupHandle_.close() >= 0 && fileHandle_.close() >= 0; bool success = cGroupHandle_.close() >= 0 && fileHandle_.close() >= 0;
vigra_postcondition(success, "HDF5File.close() failed."); vigra_postcondition(success, "HDF5File.close() failed.");
} }
/** \brief Change current group to "/". /** \brief Change current group to "/".
*/ */
inline void root() inline void root()
{ {
std::string message = "HDF5File::root(): Could not open group '/'." ; std::string message = "HDF5File::root(): Could not open group '/'." ;
cGroupHandle_ = HDF5Handle(H5Gopen(fileHandle_, "/", H5P_DEFAULT),& H5Gclose,message.c_str()); cGroupHandle_ = HDF5Handle(H5Gopen(fileHandle_, "/", H5P_DEFAULT),& H5Gclose,message.c_str());
} }
/** \brief Change the current group. /** \brief Change the current group.
Both absolute and relative group names are allowed. Both absolute and relative group names are allowed.
*/ */
inline void cd(std::string groupName) inline void cd(std::string groupName)
{ {
std::string message = "HDF5File::cd(): Could not open group '" + gr cGroupHandle_ = getGroupHandle(groupName, "HDF5File::cd()");
oupName + "'.\n";
// make groupName clean
groupName = get_absolute_path(groupName);
if(groupName == "/")
{
cGroupHandle_ = HDF5Handle(openCreateGroup_("/"),&H5Gclose,mess
age.c_str());
}
else
{
vigra_precondition(H5Lexists(fileHandle_, groupName.c_str(), H5
P_DEFAULT) != 0, message);
cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName),&H5Gclos
e,message.c_str());
}
} }
/** \brief Change the current group to its parent group. /** \brief Change the current group to its parent group.
Returns true if successful, false otherwise. If unsuccessful, Returns true if successful, false otherwise. If unsuccessful,
the group will not change. the group will not change.
*/ */
inline bool cd_up() inline bool cd_up()
{ {
std::string groupName = currentGroupName_(); std::string groupName = currentGroupName_();
skipping to change at line 708 skipping to change at line 1240
} }
return true; return true;
} }
/** \brief Create a new group. /** \brief Create a new group.
If the first character is a "/", the path will be interpreted as absolute path, If the first character is a "/", the path will be interpreted as absolute path,
otherwise it will be interpreted as path relative to the curre nt group. otherwise it will be interpreted as path relative to the curre nt group.
*/ */
inline void mkdir(std::string groupName) inline void mkdir(std::string groupName)
{ {
vigra_precondition(!isReadOnly(),
"HDF5File::mkdir(): file is read-only.");
std::string message = "HDF5File::mkdir(): Could not create group '" + groupName + "'.\n"; std::string message = "HDF5File::mkdir(): Could not create group '" + groupName + "'.\n";
// make groupName clean // make groupName clean
groupName = get_absolute_path(groupName); groupName = get_absolute_path(groupName);
HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_ str()); HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_ str());
} }
/** \brief Change the current group; create it if necessary. /** \brief Change the current group; create it if necessary.
If the first character is a "/", the path will be interpreted as absolute path, If the first character is a "/", the path will be interpreted as absolute path,
otherwise it will be interpreted as path relative to the curre nt group. otherwise it will be interpreted as path relative to the curre nt group.
*/ */
inline void cd_mk(std::string groupName) inline void cd_mk(std::string groupName)
{ {
vigra_precondition(!isReadOnly(),
"HDF5File::cd_mk(): file is read-only.");
std::string message = "HDF5File::cd_mk(): Could not create group ' " + groupName + "'."; std::string message = "HDF5File::cd_mk(): Could not create group ' " + groupName + "'.";
// make groupName clean // make groupName clean
groupName = get_absolute_path(groupName); groupName = get_absolute_path(groupName);
cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName.c_str()),&H5G close,message.c_str()); cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName.c_str()),&H5G close,message.c_str());
} }
// helper function for the various ls() variants. // helper function for the various ls() variants.
void ls_H5Literate(ls_closure & data) const void ls_H5Literate(ls_closure & data) const
skipping to change at line 784 skipping to change at line 1322
return currentGroupName_(); return currentGroupName_();
} }
/** \brief Get the name of the associated file. /** \brief Get the name of the associated file.
*/ */
inline std::string filename() const inline std::string filename() const
{ {
return fileName_(); return fileName_();
} }
/** \brief Check if given datasetName exists.
*/
inline bool existsDataset(std::string datasetName) const
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
return (H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) >
0);
}
/** \brief Get the number of dimensions of a certain dataset /** \brief Get the number of dimensions of a certain dataset
If the first character is a "/", the path will be interpreted as absolute path, If the first character is a "/", the path will be interpreted as absolute path,
otherwise it will be interpreted as path relative to the curre nt group. otherwise it will be interpreted as path relative to the curre nt group.
*/ */
inline hssize_t getDatasetDimensions(std::string datasetName) hssize_t getDatasetDimensions(std::string datasetName) const
{ {
// make datasetName clean HDF5Handle datasetHandle = getDatasetHandle(datasetName);
datasetName = get_absolute_path(datasetName);
//Open dataset and dataspace return getDatasetDimensions_(datasetHandle);
std::string errorMessage = "HDF5File::getDatasetDimensions(): Unabl }
e to open dataset '" + datasetName + "'.";
HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName
), &H5Dclose, errorMessage.c_str());
errorMessage = "HDF5File::getDatasetDimensions(): Unable to access hssize_t getDatasetDimensions_(hid_t dataset) const
dataspace."; {
HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, std::string errorMessage = "HDF5File::getDatasetDimensions(): Unabl
errorMessage.c_str()); e to access dataspace.";
HDF5Handle dataspaceHandle(H5Dget_space(dataset), &H5Sclose, errorM
essage.c_str());
//return dimension information //return dimension information
return H5Sget_simple_extent_ndims(dataspaceHandle); return H5Sget_simple_extent_ndims(dataspaceHandle);
} }
/** \brief Get the shape of each dimension of a certain dataset. /** \brief Get the shape of each dimension of a certain dataset.
Normally, this function is called after determining the dimensio n of the Normally, this function is called after determining the dimensio n of the
dataset using \ref getDatasetDimensions(). dataset using \ref getDatasetDimensions().
If the first character is a "/", the path will be interpreted a s absolute path, If the first character is a "/", the path will be interpreted a s absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
order relative to the file contents. That is, when the axes in the file are order relative to the file contents. That is, when the axes in the file are
ordered as 'z', 'y', 'x', this function will return the shape i n the order ordered as 'z', 'y', 'x', this function will return the shape i n the order
'x', 'y', 'z'. 'x', 'y', 'z'.
*/ */
inline ArrayVector<hsize_t> getDatasetShape(std::string datasetName) ArrayVector<hsize_t> getDatasetShape(std::string datasetName) const
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
//Open dataset and dataspace //Open dataset and dataspace
std::string errorMessage = "HDF5File::getDatasetShape(): Unable to open dataset '" + datasetName + "'."; std::string errorMessage = "HDF5File::getDatasetShape(): Unable to open dataset '" + datasetName + "'.";
HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName ), &H5Dclose, errorMessage.c_str()); HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName ), &H5Dclose, errorMessage.c_str());
errorMessage = "HDF5File::getDatasetShape(): Unable to access datas pace."; errorMessage = "HDF5File::getDatasetShape(): Unable to access datas pace.";
HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str()); HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
skipping to change at line 841 skipping to change at line 1388
ArrayVector<hsize_t> shape(dimensions); ArrayVector<hsize_t> shape(dimensions);
ArrayVector<hsize_t> maxdims(dimensions); ArrayVector<hsize_t> maxdims(dimensions);
H5Sget_simple_extent_dims(dataspaceHandle, shape.data(), maxdims.da ta()); H5Sget_simple_extent_dims(dataspaceHandle, shape.data(), maxdims.da ta());
// invert the dimensions to guarantee VIGRA-compatible order. // invert the dimensions to guarantee VIGRA-compatible order.
std::reverse(shape.begin(), shape.end()); std::reverse(shape.begin(), shape.end());
return shape; return shape;
} }
/** Query the pixel type of the dataset.
Possible values are:
<DL>
<DT>"INT8"<DD> 8-bit signed integer (unsigned char)
<DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
<DT>"INT16"<DD> 16-bit signed integer (short)
<DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
<DT>"INT32"<DD> 32-bit signed integer (long)
<DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
<DT>"INT64"<DD> 64-bit signed integer (long long)
<DT>"UINT64"<DD> 64-bit unsigned integer (unsigned long long)
<DT>"FLOAT"<DD> 32-bit floating point (float)
<DT>"DOUBLE"<DD> 64-bit floating point (double)
<DT>"UNKNOWN"<DD> any other type
</DL>
*/
std::string getDatasetType(std::string const & datasetName) const
{
HDF5Handle datasetHandle = getDatasetHandle(datasetName);
hid_t datatype = H5Dget_type(datasetHandle);
H5T_class_t dataclass = H5Tget_class(datatype);
size_t datasize = H5Tget_size(datatype);
H5T_sign_t datasign = H5Tget_sign(datatype);
if(dataclass == H5T_FLOAT)
{
if(datasize == 4)
return "FLOAT";
else if(datasize == 8)
return "DOUBLE";
}
else if(dataclass == H5T_INTEGER)
{
if(datasign == H5T_SGN_NONE)
{
if(datasize == 1)
return "UINT8";
else if(datasize == 2)
return "UINT16";
else if(datasize == 4)
return "UINT32";
else if(datasize == 8)
return "UINT64";
}
else
{
if(datasize == 1)
return "INT8";
else if(datasize == 2)
return "INT16";
else if(datasize == 4)
return "INT32";
else if(datasize == 8)
return "INT64";
}
}
return "UNKNOWN";
}
/** \brief Obtain the HDF5 handle of a dataset. /** \brief Obtain the HDF5 handle of a dataset.
*/ */
inline HDF5Handle getDatasetHandle(std::string dataset_name) HDF5Handle getDatasetHandle(std::string const & datasetName) const
{
std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to
open dataset '" + datasetName + "'.";
return HDF5Handle(getDatasetHandle_(get_absolute_path(datasetName))
, &H5Dclose, errorMessage.c_str());
}
/** \brief Obtain a shared HDF5 handle of a dataset.
*/
HDF5HandleShared getDatasetHandleShared(std::string const & datasetName
) const
{ {
std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to
open dataset '" + dataset_name + "'."; open dataset '" + datasetName + "'.";
return HDF5Handle(getDatasetHandle_(dataset_name), &H5Dclose, error return HDF5HandleShared(getDatasetHandle_(get_absolute_path(dataset
Message.c_str()); Name)), &H5Dclose, errorMessage.c_str());
} }
/** \brief Obtain the HDF5 handle of a group. /** \brief Obtain the HDF5 handle of a group (create the group if i t doesn't exist).
*/ */
inline HDF5Handle getGroupHandle(std::string group_name) HDF5Handle getGroupHandle(std::string group_name,
std::string function_name = "HDF5File::getGro
upHandle()")
{ {
std::string errorMessage = "HDF5File::getGroupHandle(): Group '" + group_name + "' not found."; std::string errorMessage = function_name + ": Group '" + group_name + "' not found.";
// make group_name clean // make group_name clean
group_name = get_absolute_path(group_name); group_name = get_absolute_path(group_name);
// group must exist // group must exist
vigra_precondition(H5Lexists(fileHandle_, group_name.c_str(), H5P_D EFAULT) == 1, vigra_precondition(group_name == "/" || H5Lexists(fileHandle_, grou p_name.c_str(), H5P_DEFAULT) != 0,
errorMessage.c_str()); errorMessage.c_str());
// open group and return group handle // open group and return group handle
return HDF5Handle(openCreateGroup_(group_name), &H5Gclose, "Interna l error"); return HDF5Handle(openCreateGroup_(group_name), &H5Gclose, "Interna l error");
} }
// helper function for the various listAttributes() variants.
void ls_H5Aiterate(std::string const & group_or_dataset, ls_closure & d
ata) const
{
H5O_type_t h5_type = get_object_type_(group_or_dataset);
vigra_precondition(h5_type == H5O_TYPE_GROUP || h5_type == H5O_TYPE
_DATASET,
"HDF5File::listAttributes(): object \"" + group_or_dataset + "\
" is neither a group nor a dataset.");
// get object handle
HDF5Handle object_handle(h5_type == H5O_TYPE_GROUP
? const_cast<HDF5File*>(this)->openCre
ateGroup_(group_or_dataset)
: getDatasetHandle_(group_or_dataset),
h5_type == H5O_TYPE_GROUP
? &H5Gclose
: &H5Dclose,
"HDF5File::listAttributes(): unable to ope
n object.");
hsize_t n = 0;
H5Aiterate2(object_handle, H5_INDEX_NAME, H5_ITER_NATIVE, &n,
HDF5_listAttributes_inserter_callback, static_cast<void
*>(&data));
}
/** \brief List the attribute names of the given group or dataset.
If \a group_or_dataset is empty or <tt>"."</tt> (a dot), the co
mmand
refers to the current group of this file object.
*/
inline std::vector<std::string> listAttributes(std::string const & grou
p_or_dataset) const
{
std::vector<std::string> list;
lsOpData data(list);
ls_H5Aiterate(group_or_dataset, data);
return list;
}
/** \brief Insert the attribute names of the given group or dataset
into the given
\a container by calling <tt>container.insert(std::string
)</tt>.
If \a group_or_dataset is empty or <tt>"."</tt> (a dot), the co
mmand
refers to the current group of this file object.
*/
template<class Container>
void listAttributes(std::string const & group_or_dataset, Container & c
ontainer) const
{
ls_container_data<Container> data(container);
ls_H5Aiterate(group_or_dataset, data);
}
/** \brief Obtain the HDF5 handle of a attribute. /** \brief Obtain the HDF5 handle of a attribute.
*/ */
inline HDF5Handle getAttributeHandle(std::string dataset_name, std::str ing attribute_name) HDF5Handle getAttributeHandle(std::string dataset_name, std::string att ribute_name) const
{ {
std::string message = "HDF5File::getAttributeHandle(): Attribute '" + attribute_name + "' not found."; std::string message = "HDF5File::getAttributeHandle(): Attribute '" + attribute_name + "' not found.";
return HDF5Handle(H5Aopen(getDatasetHandle(dataset_name), attribute _name.c_str(), H5P_DEFAULT), return HDF5Handle(H5Aopen(getDatasetHandle(dataset_name), attribute _name.c_str(), H5P_DEFAULT),
&H5Aclose, message.c_str()); &H5Aclose, message.c_str());
} }
/* Writing Attributes */ /* Writing Attributes */
/** \brief Write MultiArray Attributes. /** \brief Write MultiArray Attributes.
* In contrast to datasets, subarray access, chunks and compressio n are not available. * In contrast to datasets, subarray access, chunks and compressio n are not available.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void writeAttribute(std::string object_name, std::string attribu inline void writeAttribute(std::string object_name,
te_name, const MultiArrayView<N, T, UnstridedArrayTag> & array) std::string attribute_name,
const MultiArrayView<N, T, Stride> & array)
{ {
// make object_name clean // make object_name clean
object_name = get_absolute_path(object_name); object_name = get_absolute_path(object_name);
write_attribute_(object_name, attribute_name, array, detail::getH5D ataType<T>(), 1); write_attribute_(object_name, attribute_name, array, detail::getH5D ataType<T>(), 1);
} }
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE, class Stride>
inline void writeAttribute(std::string datasetName, std::string attribu inline void writeAttribute(std::string datasetName,
teName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & a std::string attributeName,
rray) const MultiArrayView<N, TinyVector<T, SIZE>,
Stride> & array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
write_attribute_(datasetName, attributeName, array, detail::getH5Da taType<T>(), SIZE); write_attribute_(datasetName, attributeName, array, detail::getH5Da taType<T>(), SIZE);
} }
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void writeAttribute(std::string datasetName, std::string attribu inline void writeAttribute(std::string datasetName,
teName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array) std::string attributeName,
const MultiArrayView<N, RGBValue<T>, Stride>
& array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
write_attribute_(datasetName, attributeName, array, detail::getH5Da taType<T>(), 3); write_attribute_(datasetName, attributeName, array, detail::getH5Da taType<T>(), 3);
} }
/** \brief Write a single value. /** \brief Write a single value.
Specialization of the write function for simple datatypes Specialization of the write function for simple datatypes
*/ */
skipping to change at line 961 skipping to change at line 1629
"object '" + object_name + "' " "object '" + object_name + "' "
"not found."); "not found.");
return exists != 0; return exists != 0;
} }
// Reading Attributes // Reading Attributes
/** \brief Read MultiArray Attributes. /** \brief Read MultiArray Attributes.
* In contrast to datasets, subarray access is not available. * In contrast to datasets, subarray access is not available.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void readAttribute(std::string object_name, std::string attribut inline void readAttribute(std::string object_name,
e_name, const MultiArrayView<N, T, UnstridedArrayTag> & array) std::string attribute_name,
MultiArrayView<N, T, Stride> array)
{ {
// make object_name clean // make object_name clean
object_name = get_absolute_path(object_name); object_name = get_absolute_path(object_name);
read_attribute_(object_name, attribute_name, array, detail::getH5Da taType<T>(), 1); read_attribute_(object_name, attribute_name, array, detail::getH5Da taType<T>(), 1);
} }
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE, class Stride>
inline void readAttribute(std::string datasetName, std::string attribut inline void readAttribute(std::string datasetName,
eName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & ar std::string attributeName,
ray) MultiArrayView<N, TinyVector<T, SIZE>, Stride
> array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
read_attribute_(datasetName, attributeName, array, detail::getH5Dat aType<T>(), SIZE); read_attribute_(datasetName, attributeName, array, detail::getH5Dat aType<T>(), SIZE);
} }
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void readAttribute(std::string datasetName, std::string attribut inline void readAttribute(std::string datasetName,
eName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array) std::string attributeName,
MultiArrayView<N, RGBValue<T>, Stride> array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
read_attribute_(datasetName, attributeName, array, detail::getH5Dat aType<T>(), 3); read_attribute_(datasetName, attributeName, array, detail::getH5Dat aType<T>(), 3);
} }
/** \brief Read a single value. /** \brief Read a single value.
Specialization of the read function for simple datatypes Specialization of the read function for simple datatypes
*/ */
skipping to change at line 1029 skipping to change at line 1703
inline void readAttribute(std::string datasetName, std::string attribut eName, std::string &data) inline void readAttribute(std::string datasetName, std::string attribut eName, std::string &data)
{ readAtomicAttribute(datasetName,attributeName,data); } { readAtomicAttribute(datasetName,attributeName,data); }
// Writing data // Writing data
/** \brief Write multi arrays. /** \brief Write multi arrays.
Chunks can be activated by setting Chunks can be activated by setting
\code iChunkSize = size; //size \> 0 \code iChunkSize = size; //size \> 0
\endcode . \endcode .
The chunks will be hypercubes with edge length size. The chunks will be hypercubes with edge length size. When <tt>i
ChunkSize == 0</tt>
(default), the behavior depends on the <tt>compression</tt> set
ting: If no
compression is requested, the data is written without chunking.
Otherwise,
chuning is required, and the chunk size is automatically select
ed such that
each chunk contains about 300k pixels.
Compression can be activated by setting Compression can be activated by setting
\code compression = parameter; // 0 \< parameter \<= 9 \code compression = parameter; // 0 \< parameter \<= 9
\endcode \endcode
where 0 stands for no compression and 9 for maximum compression . where 0 stands for no compression and 9 for maximum compression .
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray, Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed
upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'. upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void write(std::string datasetName, const MultiArrayView<N, T, U inline void write(std::string datasetName,
nstridedArrayTag> & array, int iChunkSize = 0, int compression = 0) const MultiArrayView<N, T, Stride> & array,
int iChunkSize = 0, int compression = 0)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize; typename MultiArrayShape<N>::type chunkSize;
for(unsigned int i = 0; i < N; i++){ for(unsigned int i = 0; i < N; i++){
chunkSize[i] = iChunkSize; chunkSize[i] = iChunkSize;
} }
write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize , compression); write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize , compression);
} }
skipping to change at line 1074 skipping to change at line 1754
where 0 stands for no compression and 9 for maximum compression . where 0 stands for no compression and 9 for maximum compression .
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray, Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed
upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'. upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void write(std::string datasetName, const MultiArrayView<N, T, U inline void write(std::string datasetName,
nstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int const MultiArrayView<N, T, Stride> & array,
compression = 0) typename MultiArrayShape<N>::type chunkSize, int comp
ression = 0)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize , compression); write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize , compression);
} }
/** \brief Write a multi array into a larger volume. /** \brief Write a multi array into a larger volume.
blockOffset determines the position, where array is written. blockOffset determines the position, where array is written.
Chunks can be activated by providing a MultiArrayShape as chunk
Size.
chunkSize must have equal dimension as array.
Compression can be activated by setting
\code compression = parameter; // 0 \< parameter \<= 9
\endcode
where 0 stands for no compression and 9 for maximum compression
.
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray, Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed
upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'. upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void writeBlock(std::string datasetName, typename MultiArrayShap inline void writeBlock(std::string datasetName,
e<N>::type blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & arr typename MultiArrayShape<N>::type blockOffset,
ay) const MultiArrayView<N, T, Stride> & array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
typedef detail::HDF5TypeTraits<T> TypeTraits;
writeBlock_(datasetName, blockOffset, array,
TypeTraits::getH5DataType(), TypeTraits::numberOfBands(
));
}
writeBlock_(datasetName, blockOffset, array, detail::getH5DataType< template<unsigned int N, class T, class Stride>
T>(), 1); inline herr_t writeBlock(HDF5HandleShared dataset,
typename MultiArrayShape<N>::type blockOffset,
const MultiArrayView<N, T, Stride> & array)
{
typedef detail::HDF5TypeTraits<T> TypeTraits;
return writeBlock_(dataset, blockOffset, array,
TypeTraits::getH5DataType(), TypeTraits::numberO
fBands());
} }
// non-scalar (TinyVector) and unstrided multi arrays // non-scalar (TinyVector) and unstrided multi arrays
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE, class Stride>
inline void write(std::string datasetName, const MultiArrayView<N, Tiny inline void write(std::string datasetName,
Vector<T, SIZE>, UnstridedArrayTag> & array, int iChunkSize = 0, int compre const MultiArrayView<N, TinyVector<T, SIZE>, Stride>
ssion = 0) & array,
int iChunkSize = 0, int compression = 0)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize; typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){ for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize; chunkSize[i] = iChunkSize;
} }
write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkS ize, compression); write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkS ize, compression);
} }
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE, class Stride>
inline void write(std::string datasetName, const MultiArrayView<N, Tiny inline void write(std::string datasetName,
Vector<T, SIZE>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::t const MultiArrayView<N, TinyVector<T, SIZE>, Stride>
ype chunkSize, int compression = 0) & array,
typename MultiArrayShape<N>::type chunkSize, int comp
ression = 0)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkS ize, compression); write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkS ize, compression);
} }
/** \brief Write array vectors. /** \brief Write array vectors.
Compression can be activated by setting Compression can be activated by setting
skipping to change at line 1150 skipping to change at line 1841
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
*/ */
template<class T> template<class T>
void write(const std::string & datasetName, void write(const std::string & datasetName,
const ArrayVectorView<T> & array, const ArrayVectorView<T> & array,
int compression = 0) int compression = 0)
{ {
// convert to a (trivial) MultiArrayView and forward. // convert to a (trivial) MultiArrayView and forward.
MultiArrayShape<1>::type shape(array.size()); MultiArrayShape<1>::type shape(static_cast<MultiArrayIndex>(array.s ize()));
const MultiArrayView<1, T> m_array(shape, const_cast<T*>(array.data ())); const MultiArrayView<1, T> m_array(shape, const_cast<T*>(array.data ()));
write(datasetName, m_array, compression); write(datasetName, m_array, compression);
} }
template<unsigned int N, class T, int SIZE>
inline void writeBlock(std::string datasetName, typename MultiArrayShap
e<N>::type blockOffset, const MultiArrayView<N, TinyVector<T, SIZE>, Unstri
dedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<
T>(), SIZE);
}
// non-scalar (RGBValue) and unstrided multi arrays // non-scalar (RGBValue) and unstrided multi arrays
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void write(std::string datasetName, const MultiArrayView<N, RGBV inline void write(std::string datasetName,
alue<T>, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = const MultiArrayView<N, RGBValue<T>, Stride> & array,
0) int iChunkSize = 0, int compression = 0)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize; typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){ for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize; chunkSize[i] = iChunkSize;
} }
write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize , compression); write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize , compression);
} }
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void write(std::string datasetName, const MultiArrayView<N, RGBV inline void write(std::string datasetName,
alue<T>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chun const MultiArrayView<N, RGBValue<T>, Stride> & array,
kSize, int compression = 0) typename MultiArrayShape<N>::type chunkSize, int comp
ression = 0)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize , compression); write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize , compression);
} }
template<unsigned int N, class T>
inline void writeBlock(std::string datasetName, typename MultiArrayShap
e<N>::type blockOffset, const MultiArrayView<N, RGBValue<T>, UnstridedArray
Tag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<
T>(), 3);
}
/** \brief Write a single value. /** \brief Write a single value.
Specialization of the write function for simple datatypes Specialization of the write function for simple datatypes
*/ */
inline void write(std::string datasetName, char data) { writeAtomic(dat asetName,data); } inline void write(std::string datasetName, char data) { writeAtomic(dat asetName,data); }
inline void write(std::string datasetName, signed char data) { writeAto mic(datasetName,data); } inline void write(std::string datasetName, signed char data) { writeAto mic(datasetName,data); }
inline void write(std::string datasetName, signed short data) { writeAt omic(datasetName,data); } inline void write(std::string datasetName, signed short data) { writeAt omic(datasetName,data); }
inline void write(std::string datasetName, signed int data) { writeAtom ic(datasetName,data); } inline void write(std::string datasetName, signed int data) { writeAtom ic(datasetName,data); }
inline void write(std::string datasetName, signed long data) { writeAto mic(datasetName,data); } inline void write(std::string datasetName, signed long data) { writeAto mic(datasetName,data); }
inline void write(std::string datasetName, signed long long data) { wri teAtomic(datasetName,data); } inline void write(std::string datasetName, signed long long data) { wri teAtomic(datasetName,data); }
inline void write(std::string datasetName, unsigned char data) { writeA tomic(datasetName,data); } inline void write(std::string datasetName, unsigned char data) { writeA tomic(datasetName,data); }
skipping to change at line 1227 skipping to change at line 1904
/** \brief Read data into a multi array. /** \brief Read data into a multi array.
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset, Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
whose indices represent the 'z'-, 'y'-, and 'x'-axis in that or der, is reversed whose indices represent the 'z'-, 'y'-, and 'x'-axis in that or der, is reversed
upon reading into a MultiArrayView, i.e. in the array axis orde r must be 'x', 'y', 'z'. upon reading into a MultiArrayView, i.e. in the array axis orde r must be 'x', 'y', 'z'.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void read(std::string datasetName, MultiArrayView<N, T, Unstride inline void read(std::string datasetName, MultiArrayView<N, T, Stride>
dArrayTag> & array) array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
read_(datasetName, array, detail::getH5DataType<T>(), 1); read_(datasetName, array, detail::getH5DataType<T>(), 1);
} }
/** \brief Read data into a MultiArray. Resize MultiArray to the co rrect size. /** \brief Read data into a MultiArray. Resize MultiArray to the co rrect size.
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset, Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
whose indices represent the 'z'-, 'y'-, and 'x'-axis in that or der, is reversed whose indices represent the 'z'-, 'y'-, and 'x'-axis in that or der, is reversed
upon reading into a MultiArray, i.e. in the array axis order wi ll be 'x', 'y', 'z'. upon reading into a MultiArray, i.e. in the array axis order wi ll be 'x', 'y', 'z'.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Alloc>
inline void readAndResize(std::string datasetName, MultiArray<N, T> & a inline void readAndResize(std::string datasetName, MultiArray<N, T, All
rray) oc> & array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
// get dataset dimension // get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName); ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
// check if dimensions are correct // check if dimensions are correct
vigra_precondition(N == MultiArrayIndex(dimshape.size()), // the ob ject in the HDF5 file may have one additional dimension which we then inter pret as the pixel type bands vigra_precondition(N == MultiArrayIndex(dimshape.size()), // the ob ject in the HDF5 file may have one additional dimension which we then inter pret as the pixel type bands
"HDF5File::readAndResize(): Array dimension disagrees with data set dimension."); "HDF5File::readAndResize(): Array dimension disagrees with data set dimension.");
// reshape target MultiArray // reshape target MultiArray
typename MultiArrayShape<N>::type shape; typename MultiArrayShape<N>::type shape;
for(int k=0; k < (int)dimshape.size(); ++k) for(int k=0; k < static_cast<int>(dimshape.size()); ++k)
shape[k] = (MultiArrayIndex)dimshape[k]; shape[k] = static_cast<MultiArrayIndex>(dimshape[k]);
array.reshape(shape); array.reshape(shape);
read_(datasetName, array, detail::getH5DataType<T>(), 1); read_(datasetName, array, detail::getH5DataType<T>(), 1);
} }
/** \brief Read data into an array vector. /** \brief Read data into an array vector.
If the first character of datasetName is a "/", the path will be interpreted as absolute path, If the first character of datasetName is a "/", the path will be interpreted as absolute path,
otherwise it will be interpreted as path relative to the current group. otherwise it will be interpreted as path relative to the current group.
*/ */
template<class T> template<class T>
inline void read(const std::string & datasetName, ArrayVectorView<T> & array) inline void read(const std::string & datasetName, ArrayVectorView<T> ar ray)
{ {
// convert to a (trivial) MultiArrayView and forward. // convert to a (trivial) MultiArrayView and forward.
MultiArrayShape<1>::type shape(array.size()); MultiArrayShape<1>::type shape(array.size());
MultiArrayView<1, T> m_array(shape, (array.data())); MultiArrayView<1, T> m_array(shape, (array.data()));
read(datasetName, m_array); read(datasetName, m_array);
} }
/** \brief Read data into an array vector. Resize the array vector to the correct size. /** \brief Read data into an array vector. Resize the array vector to the correct size.
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
skipping to change at line 1301 skipping to change at line 1978
// get dataset dimension // get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName); ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
// check if dimensions are correct // check if dimensions are correct
vigra_precondition(1 == MultiArrayIndex(dimshape.size()), vigra_precondition(1 == MultiArrayIndex(dimshape.size()),
"HDF5File::readAndResize(): Array dimension disagrees with Data set dimension must equal one for vigra::ArrayVector."); "HDF5File::readAndResize(): Array dimension disagrees with Data set dimension must equal one for vigra::ArrayVector.");
// resize target array vector // resize target array vector
array.resize((typename ArrayVector<T>::size_type)dimshape[0]); array.resize((typename ArrayVector<T>::size_type)dimshape[0]);
// convert to a (trivial) MultiArrayView and forward. // convert to a (trivial) MultiArrayView and forward.
MultiArrayShape<1>::type shape(array.size()); MultiArrayShape<1>::type shape(static_cast<MultiArrayIndex>(array.s ize()));
MultiArrayView<1, T> m_array(shape, (array.data())); MultiArrayView<1, T> m_array(shape, (array.data()));
read_(datasetName, m_array, detail::getH5DataType<T>(), 1); read_(datasetName, m_array, detail::getH5DataType<T>(), 1);
} }
/** \brief Read a block of data into a multi array. /** \brief Read a block of data into a multi array.
This function allows to read a small block out of a larger volu me stored This function allows to read a small block out of a larger volu me stored
in an HDF5 dataset. in an HDF5 dataset.
blockOffset determines the position of the block. blockOffset determines the position of the block.
blockSize determines the size in each dimension of the block. blockSize determines the size in each dimension of the block.
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset, Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
whose indices represent the 'z'-, 'y'-, and 'x'-axis in that or der, is reversed whose indices represent the 'z'-, 'y'-, and 'x'-axis in that or der, is reversed
upon reading into a MultiArray, i.e. in the array axis order wi ll be 'x', 'y', 'z'. upon reading into a MultiArray, i.e. in the array axis order wi ll be 'x', 'y', 'z'.
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void readBlock(std::string datasetName, typename MultiArrayShape inline void readBlock(std::string datasetName,
<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiA typename MultiArrayShape<N>::type blockOffset,
rrayView<N, T, UnstridedArrayTag> & array) typename MultiArrayShape<N>::type blockShape,
MultiArrayView<N, T, Stride> array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
typedef detail::HDF5TypeTraits<T> TypeTraits;
readBlock_(datasetName, blockOffset, blockShape, array,
TypeTraits::getH5DataType(), TypeTraits::numberOfBands()
);
}
readBlock_(datasetName, blockOffset, blockShape, array, detail::get template<unsigned int N, class T, class Stride>
H5DataType<T>(), 1); inline herr_t readBlock(HDF5HandleShared dataset,
typename MultiArrayShape<N>::type blockOffset,
typename MultiArrayShape<N>::type blockShape,
MultiArrayView<N, T, Stride> array)
{
typedef detail::HDF5TypeTraits<T> TypeTraits;
return readBlock_(dataset, blockOffset, blockShape, array,
TypeTraits::getH5DataType(), TypeTraits::numberOf
Bands());
} }
// non-scalar (TinyVector) and unstrided target MultiArrayView // non-scalar (TinyVector) and unstrided target MultiArrayView
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE, class Stride>
inline void read(std::string datasetName, MultiArrayView<N, TinyVector< inline void read(std::string datasetName, MultiArrayView<N, TinyVector<
T, SIZE>, UnstridedArrayTag> & array) T, SIZE>, Stride> array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
read_(datasetName, array, detail::getH5DataType<T>(), SIZE); read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
} }
// non-scalar (TinyVector) MultiArray // non-scalar (TinyVector) MultiArray
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE, class Alloc>
inline void readAndResize(std::string datasetName, MultiArray<N, TinyVe inline void readAndResize(std::string datasetName, MultiArray<N, TinyVe
ctor<T, SIZE> > & array) ctor<T, SIZE>, Alloc> & array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
// get dataset dimension // get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName); ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
// check if dimensions are correct // check if dimensions are correct
vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) && vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) &&
SIZE == dimshape[0], // the object in the HDF5 f ile must have one additional dimension which we interpret as the pixel type bands SIZE == dimshape[0], // the object in the HDF5 f ile must have one additional dimension which we interpret as the pixel type bands
"HDF5File::readAndResize(): Array dimension disagrees with data set dimension."); "HDF5File::readAndResize(): Array dimension disagrees with data set dimension.");
// reshape target MultiArray // reshape target MultiArray
typename MultiArrayShape<N>::type shape; typename MultiArrayShape<N>::type shape;
for(int k=1; k < (int)dimshape.size(); ++k) for(int k=1; k < static_cast<int>(dimshape.size()); ++k)
shape[k-1] = (MultiArrayIndex)dimshape[k]; shape[k-1] = static_cast<MultiArrayIndex>(dimshape[k]);
array.reshape(shape); array.reshape(shape);
read_(datasetName, array, detail::getH5DataType<T>(), SIZE); read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
} }
template<unsigned int N, class T, int SIZE>
inline void readBlock(std::string datasetName, typename MultiArrayShape
<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiA
rrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
readBlock_(datasetName, blockOffset, blockShape, array, detail::get
H5DataType<T>(), SIZE);
}
// non-scalar (RGBValue) and unstrided target MultiArrayView // non-scalar (RGBValue) and unstrided target MultiArrayView
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T> inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T>
, UnstridedArrayTag> & array) , Stride> array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
read_(datasetName, array, detail::getH5DataType<T>(), 3); read_(datasetName, array, detail::getH5DataType<T>(), 3);
} }
// non-scalar (RGBValue) MultiArray // non-scalar (RGBValue) MultiArray
template<unsigned int N, class T> template<unsigned int N, class T, class Alloc>
inline void readAndResize(std::string datasetName, MultiArray<N, RGBVal inline void readAndResize(std::string datasetName, MultiArray<N, RGBVal
ue<T> > & array) ue<T>, Alloc> & array)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
// get dataset dimension // get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName); ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
// check if dimensions are correct // check if dimensions are correct
vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) && vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) &&
3 == dimshape[0], // the object in the HDF5 file must have one additional dimension which we interpret as the pixel type ba nds 3 == dimshape[0], // the object in the HDF5 file must have one additional dimension which we interpret as the pixel type ba nds
"HDF5File::readAndResize(): Array dimension disagrees with data set dimension."); "HDF5File::readAndResize(): Array dimension disagrees with data set dimension.");
// reshape target MultiArray // reshape target MultiArray
typename MultiArrayShape<N>::type shape; typename MultiArrayShape<N>::type shape;
for(int k=1; k < (int)dimshape.size(); ++k) for(int k=1; k < static_cast<int>(dimshape.size()); ++k)
shape[k-1] = (MultiArrayIndex)dimshape[k]; shape[k-1] = static_cast<MultiArrayIndex>(dimshape[k]);
array.reshape(shape); array.reshape(shape);
read_(datasetName, array, detail::getH5DataType<T>(), 3); read_(datasetName, array, detail::getH5DataType<T>(), 3);
} }
template<unsigned int N, class T>
inline void readBlock(std::string datasetName, typename MultiArrayShape
<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiA
rrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
readBlock_(datasetName, blockOffset, blockShape, array, detail::get
H5DataType<T>(), 3);
}
/** \brief Read a single value. /** \brief Read a single value.
Specialization of the read function for simple datatypes Specialization of the read function for simple datatypes
*/ */
inline void read(std::string datasetName, char &data) { readAtomic(data setName,data); } inline void read(std::string datasetName, char &data) { readAtomic(data setName,data); }
inline void read(std::string datasetName, signed char &data) { readAtom ic(datasetName,data); } inline void read(std::string datasetName, signed char &data) { readAtom ic(datasetName,data); }
inline void read(std::string datasetName, signed short &data) { readAto mic(datasetName,data); } inline void read(std::string datasetName, signed short &data) { readAto mic(datasetName,data); }
inline void read(std::string datasetName, signed int &data) { readAtomi c(datasetName,data); } inline void read(std::string datasetName, signed int &data) { readAtomi c(datasetName,data); }
inline void read(std::string datasetName, signed long &data) { readAtom ic(datasetName,data); } inline void read(std::string datasetName, signed long &data) { readAtom ic(datasetName,data); }
inline void read(std::string datasetName, signed long long &data) { rea dAtomic(datasetName,data); } inline void read(std::string datasetName, signed long long &data) { rea dAtomic(datasetName,data); }
inline void read(std::string datasetName, unsigned char &data) { readAt omic(datasetName,data); } inline void read(std::string datasetName, unsigned char &data) { readAt omic(datasetName,data); }
inline void read(std::string datasetName, unsigned short &data) { readA tomic(datasetName,data); } inline void read(std::string datasetName, unsigned short &data) { readA tomic(datasetName,data); }
inline void read(std::string datasetName, unsigned int &data) { readAto mic(datasetName,data); } inline void read(std::string datasetName, unsigned int &data) { readAto mic(datasetName,data); }
inline void read(std::string datasetName, unsigned long &data) { readAt omic(datasetName,data); } inline void read(std::string datasetName, unsigned long &data) { readAt omic(datasetName,data); }
inline void read(std::string datasetName, unsigned long long &data) { r eadAtomic(datasetName,data); } inline void read(std::string datasetName, unsigned long long &data) { r eadAtomic(datasetName,data); }
inline void read(std::string datasetName, float &data) { readAtomic(dat asetName,data); } inline void read(std::string datasetName, float &data) { readAtomic(dat asetName,data); }
inline void read(std::string datasetName, double &data) { readAtomic(da tasetName,data); } inline void read(std::string datasetName, double &data) { readAtomic(da tasetName,data); }
inline void read(std::string datasetName, long double &data) { readAtom ic(datasetName,data); } inline void read(std::string datasetName, long double &data) { readAtom ic(datasetName,data); }
inline void read(std::string datasetName, std::string &data) { readAtom ic(datasetName,data); } inline void read(std::string datasetName, std::string &data) { readAtom ic(datasetName,data); }
/** \brief Create a new dataset. /** \brief Create a new dataset.
This function can be used to create a dataset filled with a def ault value, This function can be used to create a dataset filled with a def ault value \a init,
for example before writing data into it using \ref writeBlock() . for example before writing data into it using \ref writeBlock() .
Attention: only atomic datatypes are provided. For spectral dat
a, add an
dimension (case RGB: add one dimension of size 3).
shape determines the dimension and the size of the dataset. shape determines the dimension and the size of the dataset.
Chunks can be activated by providing a MultiArrayShape as chunk Size. Chunks can be activated by providing a MultiArrayShape as chunk Size.
chunkSize must have equal dimension as array. chunkSize must have equal dimension as array.
Compression can be activated by setting Compression can be activated by setting
\code compression = parameter; // 0 \< parameter \<= 9 \code compression = parameter; // 0 \< parameter \<= 9
\endcode \endcode
where 0 stands for no compression and 9 for maximum compression where 0 stands for no compression and 9 for maximum compression
. . If
a non-zero compression level is specified, but the chunk size i
s zero,
a default chunk size will be chosen (compression always require
s chunks).
If the first character of datasetName is a "/", the path will b e interpreted as absolute path, If the first character of datasetName is a "/", the path will b e interpreted as absolute path,
otherwise it will be interpreted as path relative to the curren t group. otherwise it will be interpreted as path relative to the curren t group.
Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses Note that the memory order between VIGRA and HDF5 files differs : VIGRA uses
Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray, Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed whose indices represent the 'x'-, 'y'-, and 'z'-axis in that or der, is reversed
upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'. upon writing to an HDF5 file, i.e. in the file the axis order i s 'z', 'y', 'x'.
*/ */
template<unsigned int N, class T> template<int N, class T>
inline void createDataset(std::string datasetName, HDF5HandleShared
typename MultiArrayShape<N>::type shape, createDataset(std::string datasetName,
T init = T(), TinyVector<MultiArrayIndex, N> const & shape,
int iChunkSize = 0, typename detail::HDF5TypeTraits<T>::value_type init =
int compressionParameter = 0) typename detail::HDF5T
{ ypeTraits<T>::value_type(),
// make datasetName clean #ifdef _MSC_VER
datasetName = get_absolute_path(datasetName); TinyVector<MultiArrayIndex, N> const & chunkSize = TinyVe
ctor<MultiArrayIndex, N>(),
#else
TinyVector<MultiArrayIndex, N> const & chunkSize = (TinyV
ector<MultiArrayIndex, N>()),
#endif
int compressionParameter = 0);
// for backwards compatibility
template<int N, class T>
HDF5HandleShared
createDataset(std::string datasetName,
TinyVector<MultiArrayIndex, N> const & shape,
T init,
int iChunkSize,
int compressionParameter = 0)
{
typename MultiArrayShape<N>::type chunkSize; typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){ for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize; chunkSize[i] = iChunkSize;
} }
createDataset<N,T>(datasetName, shape, init, chunkSize, compression return this->template createDataset<N, T>(datasetName, shape, init,
Parameter); chunkSize, compressionPar
} ameter);
template<unsigned int N, class T>
inline void createDataset(std::string datasetName,
typename MultiArrayShape<N>::type shape,
T init,
typename MultiArrayShape<N>::type chunkSize,
int compressionParameter = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
std::string groupname = SplitString(datasetName).first();
std::string setname = SplitString(datasetName).last();
hid_t parent = openCreateGroup_(groupname);
// delete the dataset if it already exists
deleteDataset_(parent, setname);
// create dataspace
// add an extra dimension in case that the data is non-scalar
HDF5Handle dataspaceHandle;
// invert dimensions to guarantee c-order
hsize_t shape_inv[N];
for(unsigned int k=0; k<N; ++k)
shape_inv[N-1-k] = shape[k];
// create dataspace
dataspaceHandle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
&H5Sclose, "HDF5File::createDataset():
unable to create dataspace for scalar data.");
// set fill value
HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5F
ile::createDataset(): unable to create property list." );
H5Pset_fill_value(plist,detail::getH5DataType<T>(), &init);
// turn off time tagging of datasets by default.
H5Pset_obj_track_times(plist, track_time);
// enable chunks
if(chunkSize[0] > 0)
{
hsize_t cSize [N];
for(int i = 0; i<N; i++)
{
cSize[i] = chunkSize[N-1-i];
}
H5Pset_chunk (plist, N, cSize);
}
// enable compression
if(compressionParameter > 0)
{
H5Pset_deflate(plist, compressionParameter);
}
//create the dataset.
HDF5Handle datasetHandle ( H5Dcreate(parent, setname.c_str(), detai
l::getH5DataType<T>(), dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
&H5Dclose, "HDF5File::createDataset(): un
able to create dataset.");
if(parent != cGroupHandle_)
H5Gclose(parent);
} }
/** \brief Immediately write all data to disk /** \brief Immediately write all data to disk
*/ */
inline void flushToDisk() inline void flushToDisk()
{ {
H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL); H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
} }
private: private:
skipping to change at line 1563 skipping to change at line 2188
* For example, "/path/to/some/file" will be split (delimiter = "/ ") into * For example, "/path/to/some/file" will be split (delimiter = "/ ") into
* first() = "/path/to/some" and last() = "file". * first() = "/path/to/some" and last() = "file".
*/ */
class SplitString: public std::string { class SplitString: public std::string {
public: public:
SplitString(std::string &sstring): std::string(sstring) {}; SplitString(std::string &sstring): std::string(sstring) {};
// return the part of the string before the delimiter // return the part of the string before the delimiter
std::string first(char delimiter = '/') std::string first(char delimiter = '/')
{ {
size_t last = find_last_of(delimiter); size_t lastPos = find_last_of(delimiter);
if(last == std::string::npos) // delimiter not found --> no fir if(lastPos == std::string::npos) // delimiter not found --> no
st first
return ""; return "";
return std::string(begin(), begin()+last+1); return std::string(begin(), begin()+lastPos+1);
} }
// return the part of the string after the delimiter // return the part of the string after the delimiter
std::string last(char delimiter = '/') std::string last(char delimiter = '/')
{ {
size_t last = find_last_of(delimiter); size_t lastPos = find_last_of(delimiter);
if(last == std::string::npos) // delimiter not found --> only l if(lastPos == std::string::npos) // delimiter not found --> onl
ast y last
return std::string(*this); return std::string(*this);
return std::string(begin()+last+1, end()); return std::string(begin()+lastPos+1, end());
} }
}; };
template <class Shape>
ArrayVector<hsize_t>
defineChunks(Shape chunks, Shape const & shape, int numBands, int compr
ession = 0)
{
if(prod(chunks) > 0)
{
ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
if(numBands > 1)
res.insert(res.begin(), static_cast<hsize_t>(numBands));
return res;
}
else if(compression > 0)
{
// set default chunks to enable compression
chunks = min(detail::ChunkShape<Shape::static_size>::defaultSha
pe(), shape);
ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
if(numBands > 1)
res.insert(res.begin(), static_cast<hsize_t>(numBands));
return res;
}
else
{
return ArrayVector<hsize_t>();
}
}
public: public:
/** \brief takes any path and converts it into an absolute path /** \brief takes any path and converts it into an absolute path
in the current file. in the current file.
Elements like "." and ".." are treated as expected. Elements like "." and ".." are treated as expected.
Links are not supported or resolved. Links are not supported or resolved.
*/ */
inline std::string get_absolute_path(std::string path) const { inline std::string get_absolute_path(std::string path) const {
// check for empty input or "." and return the current folder // check for empty input or "." and return the current folder
skipping to change at line 1684 skipping to change at line 2335
*/ */
inline std::string fileName_() const inline std::string fileName_() const
{ {
int len = H5Fget_name(fileHandle_,NULL,1000); int len = H5Fget_name(fileHandle_,NULL,1000);
ArrayVector<char> name (len+1,0); ArrayVector<char> name (len+1,0);
H5Fget_name(fileHandle_,name.begin(),len+1); H5Fget_name(fileHandle_,name.begin(),len+1);
return std::string(name.begin()); return std::string(name.begin());
} }
/* create an empty file and open is /* create an empty file or open an existing one
*/ */
inline hid_t createFile_(std::string filePath, OpenMode mode = Open) inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
{ {
// try to open file // try to open file
FILE * pFile; FILE * pFile;
pFile = fopen ( filePath.c_str(), "r" ); pFile = fopen ( filePath.c_str(), "r" );
hid_t fileId; hid_t fileId;
// check if opening was successful (= file exists) // check if opening was successful (= file exists)
if ( pFile == NULL ) if ( pFile == NULL )
{ {
vigra_precondition(mode != OpenReadOnly,
"HDF5File::open(): cannot open non-existing file in read-on
ly mode.");
fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT , H5P_DEFAULT); fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT , H5P_DEFAULT);
} }
else if(mode == Open)
{
fclose( pFile );
fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
}
else if(mode == OpenReadOnly) {
fclose( pFile );
fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT)
;
}
else else
{ {
fclose(pFile); fclose(pFile);
std::remove(filePath.c_str()); if(mode == OpenReadOnly)
fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT {
, H5P_DEFAULT); fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFA
ULT);
}
else if(mode == New)
{
std::remove(filePath.c_str());
fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEF
AULT, H5P_DEFAULT);
}
else
{
fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAUL
T);
}
} }
return fileId; return fileId;
} }
/* open a group and subgroups. Create if necessary. /* \brief Open a group.
A negative value is returned when the group does not exist or wh
en opening
fails for other reasons.
*/ */
inline hid_t openCreateGroup_(std::string groupName) hid_t openGroup_(std::string groupName) const
{
return const_cast<HDF5File *>(this)->openCreateGroup_(groupName, fa
lse);
}
/* \brief Open or create a group.
If \a create is <tt>true</tt> and the group does not exist, it w
ill be created,
including all necessary parent groups. If group creation fails,
a negative
value is returned. Likewise, a negative value is returned when \
a create
is <tt>false</tt> and the group does not exist or when opening o
f the group
fails for other reasons.
*/
hid_t openCreateGroup_(std::string groupName, bool create = true)
{ {
// make groupName clean // make groupName clean
groupName = get_absolute_path(groupName); groupName = get_absolute_path(groupName);
// open root group // open root group
hid_t parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT); hid_t parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT);
if(groupName == "/") if(groupName == "/")
{ {
return parent; return parent;
} }
skipping to change at line 1748 skipping to change at line 2419
// open or create subgroups one by one // open or create subgroups one by one
std::string::size_type begin = 0, end = groupName.find('/'); std::string::size_type begin = 0, end = groupName.find('/');
while (end != std::string::npos) while (end != std::string::npos)
{ {
std::string group(groupName.begin()+begin, groupName.begin()+en d); std::string group(groupName.begin()+begin, groupName.begin()+en d);
hid_t prevParent = parent; hid_t prevParent = parent;
if(H5LTfind_dataset(parent, group.c_str()) == 0) if(H5LTfind_dataset(parent, group.c_str()) == 0)
{ {
parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, if(create)
H5P_DEFAULT, H5P_DEFAULT); parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAU
} else { LT, H5P_DEFAULT, H5P_DEFAULT);
else
parent = -1;
}
else
{
parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT); parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
} }
H5Gclose(prevParent); H5Gclose(prevParent);
if(parent < 0) if(parent < 0)
{ {
return parent; return parent;
} }
begin = end + 1; begin = end + 1;
end = groupName.find('/', begin); end = groupName.find('/', begin);
skipping to change at line 1790 skipping to change at line 2466
if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0) if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0)
{ {
vigra_postcondition(false, "HDF5File::deleteDataset_(): Una ble to delete existing data."); vigra_postcondition(false, "HDF5File::deleteDataset_(): Una ble to delete existing data.");
} }
#endif #endif
} }
} }
/* get the handle of a dataset specified by a string /* get the handle of a dataset specified by a string
*/ */
inline hid_t getDatasetHandle_(std::string datasetName) hid_t getDatasetHandle_(std::string datasetName) const
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
std::string groupname = SplitString(datasetName).first(); std::string groupname = SplitString(datasetName).first();
std::string setname = SplitString(datasetName).last(); std::string setname = SplitString(datasetName).last();
if(H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) <= 0) if(H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) <= 0)
{ {
std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << data setName << "' does not exist.\n"; std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << data setName << "' does not exist.\n";
return -1; return -1;
} }
// Open parent group // Open parent group
HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, "Int ernal error"); HDF5Handle groupHandle(openGroup_(groupname), &H5Gclose, "HDF5File: :getDatasetHandle_(): Internal error");
return H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT); return H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
} }
/* get the type of an object specified by a string /* get the type of an object specified by a string
*/ */
H5O_type_t get_object_type_(std::string name) H5O_type_t get_object_type_(std::string name) const
{ {
name = get_absolute_path(name); name = get_absolute_path(name);
std::string group_name = SplitString(name).first(); std::string group_name = SplitString(name).first();
std::string object_name = SplitString(name).last(); std::string object_name = SplitString(name).last();
if (!object_name.size()) if (!object_name.size())
return H5O_TYPE_GROUP; return H5O_TYPE_GROUP;
htri_t exists = H5Lexists(fileHandle_, name.c_str(), H5P_DEFAULT); htri_t exists = H5Lexists(fileHandle_, name.c_str(), H5P_DEFAULT);
vigra_precondition(exists > 0, "HDF5File::get_object_type_(): " vigra_precondition(exists > 0, "HDF5File::get_object_type_(): "
"object \"" + name + "\" " "object \"" + name + "\" "
"not found."); "not found.");
// open parent group // open parent group
HDF5Handle group_handle(openCreateGroup_(group_name), &H5Gclose, "I nternal error"); HDF5Handle group_handle(openGroup_(group_name), &H5Gclose, "Interna l error");
return HDF5_get_type(group_handle, name.c_str()); return HDF5_get_type(group_handle, name.c_str());
} }
/* low-level write function to write vigra MultiArray data as an at tribute /* low-level write function to write vigra MultiArray data as an at tribute
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
void write_attribute_(std::string name, const std::string & attribute_n void write_attribute_(std::string name,
ame, const std::string & attribute_name,
const MultiArrayView<N, T, UnstridedArrayTag> & a const MultiArrayView<N, T, Stride> & array,
rray,
const hid_t datatype, const hid_t datatype,
const int numBandsOfType) const int numBandsOfType);
{
// shape of the array. Add one dimension, if array contains non-sca
lars.
ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end
());
std::reverse(shape.begin(), shape.end());
if(numBandsOfType > 1)
shape.push_back(numBandsOfType);
HDF5Handle dataspace(H5Screate_simple(shape.size(),
shape.begin(), NULL),
&H5Sclose, "HDF5File::writeAttribute(): Can no
t"
" create dataspace.");
std::string errorMessage ("HDF5File::writeAttribute(): can not find
"
"object '" + name + "'.");
H5O_type_t h5_type = get_object_type_(name);
bool is_group = h5_type == H5O_TYPE_GROUP;
if (!is_group && h5_type != H5O_TYPE_DATASET)
vigra_precondition(0, "HDF5File::writeAttribute(): object \""
+ name + "\" is neither a group nor a "
"dataset.");
// get parent object handle
HDF5Handle object_handle(is_group
? openCreateGroup_(name)
: getDatasetHandle_(name),
is_group
? &H5Gclose
: &H5Dclose,
errorMessage.c_str());
// create / open attribute
bool exists = existsAttribute(name, attribute_name);
HDF5Handle attributeHandle(exists
? H5Aopen(object_handle,
attribute_name.c_str(),
H5P_DEFAULT)
: H5Acreate(object_handle,
attribute_name.c_str(), data
type,
dataspace, H5P_DEFAULT,
H5P_DEFAULT),
&H5Aclose,
"HDF5File::writeAttribute(): Can not cre
ate"
" attribute.");
// Write the data to the HDF5 object
H5Awrite(attributeHandle, datatype, array.data());
}
/* Write single value attribute /* Write single value attribute
This function allows to write data of atomic datatypes (int, lon g, double) This function allows to write data of atomic datatypes (int, lon g, double)
as an attribute in the HDF5 file. So it is not necessary to crea te a MultiArray as an attribute in the HDF5 file. So it is not necessary to crea te a MultiArray
of size 1 to write a single number. of size 1 to write a single number.
*/ */
template<class T> template<class T>
inline void writeAtomicAttribute(std::string datasetName, std::string a ttributeName, const T data) inline void writeAtomicAttribute(std::string datasetName, std::string a ttributeName, const T data)
{ {
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<1>::type chunkSize; typename MultiArrayShape<1>::type chunkSize;
chunkSize[0] = 0; chunkSize[0] = 0;
MultiArray<1,T> array(MultiArrayShape<1>::type(1)); MultiArray<1,T> array(MultiArrayShape<1>::type(1));
array[0] = data; array[0] = data;
write_attribute_(datasetName, attributeName, array, detail::getH5Da taType<T>(), 1); write_attribute_(datasetName, attributeName, array, detail::getH5Da taType<T>(), 1);
} }
/* low-level read function to write vigra MultiArray data from attr ibutes /* low-level read function to read vigra MultiArray data from attri butes
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void read_attribute_(std::string datasetName, std::string attrib void read_attribute_(std::string datasetName,
uteName, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatyp std::string attributeName,
e, const int numBandsOfType) MultiArrayView<N, T, Stride> array,
{ const hid_t datatype, const int numBandsOfType);
std::string dataset_path = get_absolute_path(datasetName);
// open Attribute handle
std::string message = "Error: could not get handle for attribute '"
+attributeName+"'' of object '"+dataset_path+"'.";
HDF5Handle attr_handle (H5Aopen_by_name(fileHandle_,dataset_path.c_
str(),attributeName.c_str(),H5P_DEFAULT,H5P_DEFAULT),&H5Aclose, message.c_s
tr());
// get Attribute dataspace
message = "Error: could not get dataspace for attribute '"+attribut
eName+"'' of object '"+dataset_path+"'.";
HDF5Handle attr_dataspace_handle (H5Aget_space(attr_handle),&H5Sclo
se,message.c_str());
// obtain Attribute shape
int dims = H5Sget_simple_extent_ndims(attr_dataspace_handle);
ArrayVector<hsize_t> dimshape(dims);
H5Sget_simple_extent_dims(attr_dataspace_handle, dimshape.data(), N
ULL);
// invert the dimensions to guarantee VIGRA-compatible order
std::reverse(dimshape.begin(), dimshape.end());
int offset = (numBandsOfType > 1)
? 1
: 0;
message = "Error: Array dimension disagrees with dataset dimension.
";
// the object in the HDF5 file may have one additional dimension wh
ich we then interpret as the pixel type bands
vigra_precondition((N + offset) == MultiArrayIndex(dims), message);
typename MultiArrayShape<N>::type shape;
for(int k=offset; k < (int)dimshape.size(); ++k)
shape[k-offset] = (MultiArrayIndex)dimshape[k];
message = "Error: Array shape disagrees with dataset shape";
vigra_precondition(shape == array.shape(), message);
// simply read in the data as is
H5Aread( attr_handle, datatype, array.data());
}
/* Read a single value attribute. /* Read a single value attribute.
This functions allows to read a single value attribute of atomic datatype (int, long, double) This functions allows to read a single value attribute of atomic datatype (int, long, double)
from the HDF5 file. So it is not necessary to create a MultiArra y from the HDF5 file. So it is not necessary to create a MultiArra y
of size 1 to read a single number. of size 1 to read a single number.
*/ */
template<class T> template<class T>
inline void readAtomicAttribute(std::string datasetName, std::string at tributeName, T & data) inline void readAtomicAttribute(std::string datasetName, std::string at tributeName, T & data)
{ {
// make datasetName clean // make datasetName clean
skipping to change at line 1969 skipping to change at line 2568
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
MultiArray<1,const char *> array(MultiArrayShape<1>::type(1)); MultiArray<1,const char *> array(MultiArrayShape<1>::type(1));
read_attribute_(datasetName, attributeName, array, detail::getH5Dat aType<const char *>(), 1); read_attribute_(datasetName, attributeName, array, detail::getH5Dat aType<const char *>(), 1);
data = std::string(array[0]); data = std::string(array[0]);
} }
/* low-level write function to write vigra unstrided MultiArray dat a /* low-level write function to write vigra unstrided MultiArray dat a
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void write_(std::string &datasetName, void write_(std::string &datasetName,
const MultiArrayView<N, T, UnstridedArrayTag> & arra const MultiArrayView<N, T, Stride> & array,
y,
const hid_t datatype, const hid_t datatype,
const int numBandsOfType, const int numBandsOfType,
typename MultiArrayShape<N>::type &chunkSize, typename MultiArrayShape<N>::type &chunkSize,
int compressionParameter = 0) int compressionParameter = 0);
{
std::string groupname = SplitString(datasetName).first();
std::string setname = SplitString(datasetName).last();
// shape of the array. Add one dimension, if array contains non-sca
lars.
ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end
());
std::reverse(shape.begin(), shape.end());
if(numBandsOfType > 1)
shape.push_back(numBandsOfType);
HDF5Handle dataspace(H5Screate_simple(shape.size(), shape.begin(),
NULL), &H5Sclose,
"HDF5File::write(): Can not create dataspace."
);
// create and open group:
std::string errorMessage ("HDF5File::write(): can not create group
'" + groupname + "'.");
HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, erro
rMessage.c_str());
// delete dataset, if it already exists
deleteDataset_(groupHandle, setname.c_str());
// set up properties list
HDF5Handle plist(H5Pcreate(H5P_DATASET_CREATE), &H5Pclose,
"HDF5File::write(): unable to create property list
." );
// turn off time tagging of datasets by default.
H5Pset_obj_track_times(plist, track_time);
// enable chunks
if(chunkSize[0] > 0)
{
ArrayVector<hsize_t> cSize(chunkSize.begin(), chunkSize.end());
std::reverse(cSize.begin(), cSize.end());
if(numBandsOfType > 1)
cSize.push_back(numBandsOfType);
H5Pset_chunk (plist, cSize.size(), cSize.begin());
}
// enable compression
if(compressionParameter > 0)
{
H5Pset_deflate(plist, compressionParameter);
}
// create dataset
HDF5Handle datasetHandle(H5Dcreate(groupHandle, setname.c_str(), da
tatype, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT),
&H5Dclose, "HDF5File::write(): Can not cre
ate dataset.");
// Write the data to the HDF5 dataset as is
herr_t write_status = H5Dwrite(datasetHandle, datatype, H5S_ALL,
H5S_ALL, H5P_DEFAULT, array.data());
vigra_precondition(write_status >= 0, "HDF5File::write_(): write to
"
"dataset \"" + datasetName + "\" "
"failed.");
}
/* Write single value as dataset. /* Write single value as dataset.
This functions allows to write data of atomic datatypes (int, lo ng, double) This functions allows to write data of atomic datatypes (int, lo ng, double)
as a dataset in the HDF5 file. So it is not necessary to create a MultiArray as a dataset in the HDF5 file. So it is not necessary to create a MultiArray
of size 1 to write a single number. of size 1 to write a single number.
If the first character of datasetName is a "/", the path will be interpreted as absolute path, If the first character of datasetName is a "/", the path will be interpreted as absolute path,
otherwise it will be interpreted as path relative to the current group. otherwise it will be interpreted as path relative to the current group.
*/ */
template<class T> template<class T>
skipping to change at line 2056 skipping to change at line 2599
typename MultiArrayShape<1>::type chunkSize; typename MultiArrayShape<1>::type chunkSize;
chunkSize[0] = 0; chunkSize[0] = 0;
MultiArray<1,T> array(MultiArrayShape<1>::type(1)); MultiArray<1,T> array(MultiArrayShape<1>::type(1));
array[0] = data; array[0] = data;
write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize ,0); write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize ,0);
} }
/* low-level read function to read vigra unstrided MultiArray data /* low-level read function to read vigra unstrided MultiArray data
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void read_(std::string datasetName, void read_(std::string datasetName,
MultiArrayView<N, T, UnstridedArrayTag> array, MultiArrayView<N, T, Stride> array,
const hid_t datatype, const int numBandsOfType) const hid_t datatype, const int numBandsOfType);
{
//Prepare to read without using HDF5ImportInfo
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
std::string errorMessage ("HDF5File::read(): Unable to open dataset
'" + datasetName + "'.");
HDF5Handle datasetHandle(getDatasetHandle_(datasetName), &H5Dclose,
errorMessage.c_str());
int offset = (numBandsOfType > 1)
? 1
: 0;
vigra_precondition((N + offset ) == MultiArrayIndex(dimshape.size()
), // the object in the HDF5 file may have one additional dimension which w
e then interpret as the pixel type bands
"HDF5File::read(): Array dimension disagrees with dataset dimen
sion.");
typename MultiArrayShape<N>::type shape;
for(int k=offset; k < (int)dimshape.size(); ++k)
shape[k-offset] = (MultiArrayIndex)dimshape[k];
vigra_precondition(shape == array.shape(),
"HDF5File::read(): Array shape disagrees with da
taset shape.");
if (offset)
vigra_precondition(dimshape[0] == static_cast<hsize_t>(numBands
OfType),
"HDF5File::read(): Band count doesn't match
destination array compound type.");
// simply read in the data as is
H5Dread( datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, ar
ray.data() ); // .data() possible since void pointer!
}
/* Read a single value. /* Read a single value.
This functions allows to read a single datum of atomic datatype (int, long, double) This functions allows to read a single datum of atomic datatype (int, long, double)
from the HDF5 file. So it is not necessary to create a MultiArra y from the HDF5 file. So it is not necessary to create a MultiArra y
of size 1 to read a single number. of size 1 to read a single number.
If the first character of datasetName is a "/", the path will be interpreted as absolute path, If the first character of datasetName is a "/", the path will be interpreted as absolute path,
otherwise it will be interpreted as path relative to the current group. otherwise it will be interpreted as path relative to the current group.
*/ */
template<class T> template<class T>
skipping to change at line 2119 skipping to change at line 2635
// make datasetName clean // make datasetName clean
datasetName = get_absolute_path(datasetName); datasetName = get_absolute_path(datasetName);
MultiArray<1,const char *> array(MultiArrayShape<1>::type(1)); MultiArray<1,const char *> array(MultiArrayShape<1>::type(1));
read_(datasetName, array, detail::getH5DataType<const char *>(), 1) ; read_(datasetName, array, detail::getH5DataType<const char *>(), 1) ;
data = std::string(array[0]); data = std::string(array[0]);
} }
/* low-level write function to write vigra unstrided MultiArray data into a sub-block of a dataset /* low-level write function to write vigra unstrided MultiArray data into a sub-block of a dataset
*/ */
template<unsigned int N, class T> template<unsigned int N, class T, class Stride>
inline void writeBlock_(std::string datasetName, typename MultiArraySha void writeBlock_(std::string datasetName,
pe<N>::type &blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & a typename MultiArrayShape<N>::type &blockOffset,
rray, const hid_t datatype, const int numBandsOfType) const MultiArrayView<N, T, Stride> & array,
const hid_t datatype,
const int numBandsOfType)
{ {
// open dataset if it exists // open dataset if it exists
std::string errorMessage = "HDF5File::writeBlock(): Error opening d ataset '" + datasetName + "'."; std::string errorMessage = "HDF5File::writeBlock(): Error opening d ataset '" + datasetName + "'.";
HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose,
, errorMessage.c_str()); errorMessage.c_str());
herr_t status = writeBlock_(dataset, blockOffset, array, datatype,
numBandsOfType);
vigra_postcondition(status >= 0,
"HDF5File::writeBlock(): write to dataset '" + datasetName + "'
via H5Dwrite() failed.");
}
/* low-level write function to write vigra unstrided MultiArray data
into a
sub-block of a dataset. Returns the result of the internal call
to <tt>H5Dwrite()</tt>.
*/
template<unsigned int N, class T, class Stride>
herr_t writeBlock_(HDF5HandleShared dataset,
typename MultiArrayShape<N>::type &blockOffset,
const MultiArrayView<N, T, Stride> & array,
const hid_t datatype,
const int numBandsOfType);
// hyperslab parameters for position, size, ... /* low-level read function to read vigra unstrided MultiArray data
hsize_t boffset [N]; from a sub-block of a dataset.
hsize_t bshape [N];
hsize_t bones [N];
for(int i = 0; i < N; i++){ The array must have the same shape as the block.
boffset[i] = blockOffset[N-1-i]; */
bshape[i] = array.size(N-1-i); template<unsigned int N, class T, class Stride>
bones[i] = 1; void readBlock_(std::string datasetName,
} typename MultiArrayShape<N>::type &blockOffset,
typename MultiArrayShape<N>::type &blockShape,
MultiArrayView<N, T, Stride> array,
const hid_t datatype, const int numBandsOfType)
{
std::string errorMessage ("HDF5File::readBlock(): Unable to open da
taset '" + datasetName + "'.");
HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose,
errorMessage.c_str());
herr_t status = readBlock_(dataset, blockOffset, blockShape, array,
datatype, numBandsOfType);
vigra_postcondition(status >= 0,
"HDF5File::readBlock(): read from dataset '" + datasetName + "'
via H5Dread() failed.");
}
/* low-level read function to read vigra unstrided MultiArray data
from a sub-block of a dataset.
The array must have the same shape as the block. Returns the res
ult of the internal call
to <tt>H5Dread()</tt>.
*/
template<unsigned int N, class T, class Stride>
herr_t readBlock_(HDF5HandleShared dataset,
typename MultiArrayShape<N>::type &blockOffset,
typename MultiArrayShape<N>::type &blockShape,
MultiArrayView<N, T, Stride> array,
const hid_t datatype, const int numBandsOfType);
}; /* class HDF5File */
/********************************************************************/
template<int N, class T>
HDF5HandleShared
HDF5File::createDataset(std::string datasetName,
TinyVector<MultiArrayIndex, N> const & shape,
typename detail::HDF5TypeTraits<T>::value_type init
,
TinyVector<MultiArrayIndex, N> const & chunkSize,
int compressionParameter)
{
vigra_precondition(!isReadOnly(),
"HDF5File::createDataset(): file is read-only.");
// make datasetName clean
datasetName = get_absolute_path(datasetName);
std::string groupname = SplitString(datasetName).first();
std::string setname = SplitString(datasetName).last();
// create a target dataspace in memory with the shape of the desire hid_t parent = openCreateGroup_(groupname);
d block
HDF5Handle memspace_handle (H5Screate_simple(N,bshape,NULL),&H5Sclo
se,"Unable to get origin dataspace");
// get file dataspace and select the desired block // delete the dataset if it already exists
HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose," deleteDataset_(parent, setname);
Unable to create target dataspace");
H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones
, bones, bshape);
// Write the data to the HDF5 dataset as is // invert dimensions to guarantee c-order
H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle // add an extra dimension in case that the data is non-scalar
, H5P_DEFAULT, array.data()); // .data() possible since void pointer! typedef detail::HDF5TypeTraits<T> TypeTraits;
ArrayVector<hsize_t> shape_inv;
if(TypeTraits::numberOfBands() > 1)
{
shape_inv.resize(N+1);
shape_inv[N] = TypeTraits::numberOfBands();
}
else
{
shape_inv.resize(N);
} }
for(int k=0; k<N; ++k)
shape_inv[N-1-k] = shape[k];
/* low-level read function to read vigra unstrided MultiArray data // create dataspace
from a sub-block of a dataset HDF5Handle
*/ dataspaceHandle = HDF5Handle(H5Screate_simple(shape_inv.size(), shape_i
template<unsigned int N, class T> nv.data(), NULL),
inline void readBlock_(std::string datasetName, typename MultiArrayShap &H5Sclose, "HDF5File::createDataset(): unab
e<N>::type &blockOffset, typename MultiArrayShape<N>::type &blockShape, Mul le to create dataspace for scalar data.");
tiArrayView<N, T, UnstridedArrayTag> &array, const hid_t datatype, const in
t numBandsOfType) // set fill value
HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File:
:createDataset(): unable to create property list." );
H5Pset_fill_value(plist, TypeTraits::getH5DataType(), &init);
// turn off time tagging of datasets by default.
H5Pset_obj_track_times(plist, track_time);
// enable chunks
ArrayVector<hsize_t> chunks(defineChunks(chunkSize, shape, TypeTraits::
numberOfBands(), compressionParameter));
if(chunks.size() > 0)
{ {
//Prepare to read without using HDF5ImportInfo std::reverse(chunks.begin(), chunks.end());
//ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName) ; H5Pset_chunk (plist, chunks.size(), chunks.begin());
hssize_t dimensions = getDatasetDimensions(datasetName); }
std::string errorMessage ("HDF5File::readBlock(): Unable to open da // enable compression
taset '" + datasetName + "'."); if(compressionParameter > 0)
HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose {
, errorMessage.c_str()); H5Pset_deflate(plist, compressionParameter);
}
int offset = (numBandsOfType > 1) //create the dataset.
? 1 HDF5HandleShared datasetHandle(H5Dcreate(parent, setname.c_str(),
: 0; TypeTraits::getH5DataType(),
dataspaceHandle, H5P_DEFAULT,
vigra_precondition(( (N + offset ) == MultiArrayIndex(dimensions)) plist, H5P_DEFAULT),
, // the object in the HDF5 file may have one additional dimension which we &H5Dclose,
then interpret as the pixel type bands "HDF5File::createDataset(): unable to cr
"readHDF5_block(): Array dimension disagrees with data dimensio eate dataset.");
n."); if(parent != cGroupHandle_)
H5Gclose(parent);
vigra_precondition(blockShape == array.shape(),
"readHDF5_block(): Array shape disagrees with block size.");
// hyperslab parameters for position, size, ...
hsize_t boffset [N];
hsize_t bshape [N];
hsize_t bones [N];
for(int i = 0; i < N; i++){ return datasetHandle;
// vigra and hdf5 use different indexing }
boffset[i] = blockOffset[N-1-i];
//bshape[i] = blockShape[i]; /********************************************************************/
bshape[i] = blockShape[N-1-i];
//boffset[i] = blockOffset[N-1-i]; template<unsigned int N, class T, class Stride>
bones[i] = 1; void HDF5File::write_(std::string &datasetName,
} const MultiArrayView<N, T, Stride> & array,
const hid_t datatype,
// create a target dataspace in memory with the shape of the desire const int numBandsOfType,
d block typename MultiArrayShape<N>::type &chunkSize,
HDF5Handle memspace_handle(H5Screate_simple(N,bshape,NULL),&H5Sclos int compressionParameter)
e, {
"Unable to create target dataspace"); vigra_precondition(!isReadOnly(),
"HDF5File::write(): file is read-only.");
// get file dataspace and select the desired block
HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle),&H5Sclose, std::string groupname = SplitString(datasetName).first();
"Unable to get dataspace"); std::string setname = SplitString(datasetName).last();
H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones
, bones, bshape); // shape of the array. Add one dimension, if array contains non-scalars
.
ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
std::reverse(shape.begin(), shape.end());
if(numBandsOfType > 1)
shape.push_back(numBandsOfType);
HDF5Handle dataspace(H5Screate_simple(shape.size(), shape.begin(), NULL
), &H5Sclose,
"HDF5File::write(): Can not create dataspace.");
// now read the data // create and open group:
H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, std::string errorMessage ("HDF5File::write(): can not create group '" +
H5P_DEFAULT, array.data() ); // .data() possible since void pointer! groupname + "'.");
HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, errorMes
sage.c_str());
// delete dataset, if it already exists
deleteDataset_(groupHandle, setname.c_str());
// set up properties list
HDF5Handle plist(H5Pcreate(H5P_DATASET_CREATE), &H5Pclose,
"HDF5File::write(): unable to create property list." )
;
// turn off time tagging of datasets by default.
H5Pset_obj_track_times(plist, track_time);
// enable chunks
ArrayVector<hsize_t> chunks(defineChunks(chunkSize, array.shape(), numB
andsOfType, compressionParameter));
if(chunks.size() > 0)
{
std::reverse(chunks.begin(), chunks.end());
H5Pset_chunk (plist, chunks.size(), chunks.begin());
} }
}; /* class HDF5File */ // enable compression
if(compressionParameter > 0)
{
H5Pset_deflate(plist, compressionParameter);
}
namespace detail { // create dataset
HDF5Handle datasetHandle(H5Dcreate(groupHandle, setname.c_str(), dataty
pe, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT),
&H5Dclose, "HDF5File::write(): Can not create
dataset.");
herr_t status = 0;
if(array.isUnstrided())
{
// Write the data directly from the array data buffer
status = H5Dwrite(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DE
FAULT, array.data());
}
else
{
// otherwise, we need an intermediate buffer
// FIXME: right now, the buffer has the same size as the array to b
e read
// incomplete code for better solutions is below
// MultiArray<N, T> buffer(array);
// status = H5Dwrite(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P
_DEFAULT, buffer.data());
int offset = numBandsOfType > 1 ? 1 : 0;
std::reverse(shape.begin(), shape.end());
if(chunks.size() > 0)
{
// if the file is chunked, we use a buffer that matches the chu
nk size.
std::reverse(chunks.begin(), chunks.end());
}
else
{
// otherwise, we compute a suitable chunk size.
ArrayVector<hsize_t>(shape.size(), 1).swap(chunks);
chunks[0] = numBandsOfType;
MultiArrayIndex prod = 1;
for(unsigned int k=0; k<N; ++k)
{
chunks[k+offset] = array.shape(k);
prod *= array.shape(k);
if(prod > 300000)
break;
}
}
ArrayVector<hsize_t> null(shape.size(), 0),
start(shape.size(), 0),
count(shape.size(), 1);
count[N-1-offset] = numBandsOfType;
typedef typename MultiArrayShape<N>::type Shape;
Shape chunkCount, chunkMaxShape;
for(unsigned int k=offset; k<chunks.size(); ++k)
{
chunkMaxShape[k-offset] = chunks[k];
chunkCount[k-offset] = static_cast<MultiArrayIndex>(std::ceil(d
ouble(shape[k]) / chunks[k]));
}
typename CoupledIteratorType<N>::type chunkIter = createCoupledIter
ator(chunkCount),
chunkEnd = chunkIter.getEndI
terator();
for(; chunkIter != chunkEnd; ++chunkIter)
{
Shape chunkStart(chunkIter.point() * chunkMaxShape),
chunkStop(min(chunkStart + chunkMaxShape, array.shape()))
;
MultiArray<N, T> buffer(array.subarray(chunkStart, chunkStop));
for(unsigned int k=0; k<N; ++k)
{
start[N-1-k] = chunkStart[k];
count[N-1-k] = buffer.shape(k);
}
if(offset == 1)
{
start[N] = 0;
count[N] = numBandsOfType;
}
HDF5Handle filespace(H5Dget_space(datasetHandle),
&H5Sclose, "HDF5File::write(): unable to c
reate hyperslabs.");
status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start.d
ata(), NULL, count.data(), NULL);
if(status < 0)
break;
HDF5Handle dataspace2(H5Screate_simple(count.size(), count.data
(), NULL),
&H5Sclose, "HDF5File::write(): unable to c
reate hyperslabs.");
status = H5Sselect_hyperslab(dataspace2, H5S_SELECT_SET, null.d
ata(), NULL, count.data(), NULL);
if(status < 0)
break;
status = H5Dwrite(datasetHandle, datatype, dataspace2, filespac
e, H5P_DEFAULT, buffer.data());
if(status < 0)
break;
}
}
vigra_postcondition(status >= 0,
"HDF5File::write(): write to dataset '" + datasetName + "' via H5Dw
rite() failed.");
}
/********************************************************************/
template<unsigned int N, class T, class Stride>
herr_t HDF5File::writeBlock_(HDF5HandleShared datasetHandle,
typename MultiArrayShape<N>::type &blockOffset
,
const MultiArrayView<N, T, Stride> & array,
const hid_t datatype,
const int numBandsOfType)
{
vigra_precondition(!isReadOnly(),
"HDF5File::writeBlock(): file is read-only.");
ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
hssize_t dimensions = getDatasetDimensions_(datasetHandle);
if(numBandsOfType > 1)
{
vigra_precondition(N+1 == dimensions,
"HDF5File::readBlock(): Array dimension disagrees with data dim
ension.");
bshape.resize(N+1);
boffset.resize(N+1);
bshape[N] = numBandsOfType;
boffset[N] = 0;
}
else
{
vigra_precondition(N == dimensions,
"HDF5File::readBlock(): Array dimension disagrees with data dim
ension.");
bshape.resize(N);
boffset.resize(N);
}
for(int i = 0; i < N; ++i)
{
// vigra and hdf5 use different indexing
bshape[N-1-i] = array.shape(i);
boffset[N-1-i] = blockOffset[i];
}
template <class Shape> // create a target dataspace in memory with the shape of the desired bl
inline void ock
selectHyperslabs(HDF5Handle & mid1, HDF5Handle & mid2, Shape const & shape, HDF5Handle memspace_handle (H5Screate_simple(bshape.size(), bshape.data
int & counter, const int elements, const int numBandsOfType) (), NULL),
{ &H5Sclose,
// select hyperslab in HDF5 file "Unable to get origin dataspace");
hsize_t shapeHDF5[2];
shapeHDF5[0] = 1; // get file dataspace and select the desired block
shapeHDF5[1] = elements; HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unab
hsize_t startHDF5[2]; le to create target dataspace");
startHDF5[0] = 0; H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET,
startHDF5[1] = counter * numBandsOfType * shape[0]; // we have to reser boffset.data(), bones.data(), bones.data(), bshape.
ve space for the pixel type channel(s) data());
hsize_t strideHDF5[2];
strideHDF5[0] = 1; herr_t status = 0;
strideHDF5[1] = 1; if(array.isUnstrided())
hsize_t countHDF5[2]; {
countHDF5[0] = 1; // when the array is unstrided, we can read the data directly from
countHDF5[1] = numBandsOfType * shape[0]; the array buffer
hsize_t blockHDF5[2]; status = H5Dwrite( datasetHandle, datatype, memspace_handle, datasp
blockHDF5[0] = 1; aceHandle, H5P_DEFAULT, array.data());
blockHDF5[1] = 1; }
mid1 = HDF5Handle(H5Screate_simple(2, shapeHDF5, NULL), else
&H5Sclose, "unable to create hyperslabs."); {
H5Sselect_hyperslab(mid1, H5S_SELECT_SET, startHDF5, strideHDF5, countH // otherwise, we must copy the data into an unstrided extra buffer
DF5, blockHDF5); MultiArray<N, T> buffer(array);
// select hyperslab in input data object status = H5Dwrite( datasetHandle, datatype, memspace_handle, datasp
hsize_t shapeData[2]; aceHandle, H5P_DEFAULT, buffer.data());
shapeData[0] = 1; }
shapeData[1] = numBandsOfType * shape[0]; return status;
hsize_t startData[2]; }
startData[0] = 0;
startData[1] = 0; /********************************************************************/
hsize_t strideData[2];
strideData[0] = 1; template<unsigned int N, class T, class Stride>
strideData[1] = 1; void HDF5File::write_attribute_(std::string name,
hsize_t countData[2]; const std::string & attribute_name,
countData[0] = 1; const MultiArrayView<N, T, Stride> & array,
countData[1] = numBandsOfType * shape[0]; const hid_t datatype,
hsize_t blockData[2]; const int numBandsOfType)
blockData[0] = 1; {
blockData[1] = 1; vigra_precondition(!isReadOnly(),
mid2 = HDF5Handle(H5Screate_simple(2, shapeData, NULL), "HDF5File::writeAttribute(): file is read-only.");
&H5Sclose, "unable to create hyperslabs.");
H5Sselect_hyperslab(mid2, H5S_SELECT_SET, startData, strideData, countD // shape of the array. Add one dimension, if array contains non-scalars
ata, blockData); .
} ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
std::reverse(shape.begin(), shape.end());
template <class DestIterator, class Shape, class T> if(numBandsOfType > 1)
inline void shape.push_back(numBandsOfType);
readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, c
onst hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elem HDF5Handle dataspace(H5Screate_simple(shape.size(),
ents, const int numBandsOfType, MetaInt<0>) shape.begin(), NULL),
{ &H5Sclose, "HDF5File::writeAttribute(): Can not"
HDF5Handle mid1, mid2; " create dataspace.");
// select hyperslabs std::string errorMessage ("HDF5File::writeAttribute(): can not find "
selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType); "object '" + name + "'.");
// read from hdf5 H5O_type_t h5_type = get_object_type_(name);
herr_t read_status = H5Dread(dataset_id, datatype, mid2, mid1, H5P_DEFA bool is_group = h5_type == H5O_TYPE_GROUP;
ULT, buffer.data()); if (!is_group && h5_type != H5O_TYPE_DATASET)
vigra_precondition(read_status >= 0, "readHDF5Impl(): read from dataset vigra_precondition(0, "HDF5File::writeAttribute(): object \""
failed."); + name + "\" is neither a group nor a "
"dataset.");
// increase counter // get parent object handle
counter++; HDF5Handle object_handle(is_group
? openCreateGroup_(name)
//std::cout << "numBandsOfType: " << numBandsOfType << std::endl; : getDatasetHandle_(name),
DestIterator dend = d + shape[0]; is_group
int k = 0; ? &H5Gclose
for(; d < dend; ++d, k++) : &H5Dclose,
{ errorMessage.c_str());
*d = buffer[k]; // create / open attribute
//std::cout << buffer[k] << "| "; bool exists = existsAttribute(name, attribute_name);
} HDF5Handle attributeHandle(exists
} ? H5Aopen(object_handle,
attribute_name.c_str(),
template <class DestIterator, class Shape, class T, int N> H5P_DEFAULT)
void : H5Acreate(object_handle,
readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, c attribute_name.c_str(), datatype
onst hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elem ,
ents, const int numBandsOfType, MetaInt<N>) dataspace, H5P_DEFAULT,
H5P_DEFAULT),
&H5Aclose,
"HDF5File::writeAttribute(): Can not create"
" attribute.");
herr_t status = 0;
if(array.isUnstrided())
{
// write the data directly from the array data buffer
status = H5Awrite(attributeHandle, datatype, array.data());
}
else
{
// write the data via an unstrided copy
// (we assume that attributes are small arrays, so that the wasted
memory is uncritical)
MultiArray<N, T> buffer(array);
status = H5Awrite(attributeHandle, datatype, buffer.data());
}
vigra_postcondition(status >= 0,
"HDF5File::writeAttribute(): write to attribute '" + attribute_name
+ "' via H5Awrite() failed.");
}
/********************************************************************/
template<unsigned int N, class T, class Stride>
void HDF5File::read_(std::string datasetName,
MultiArrayView<N, T, Stride> array,
const hid_t datatype, const int numBandsOfType)
{ {
DestIterator dend = d + shape[N]; //Prepare to read without using HDF5ImportInfo
for(; d < dend; ++d) ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
std::string errorMessage ("HDF5File::read(): Unable to open dataset '"
+ datasetName + "'.");
HDF5Handle datasetHandle(getDatasetHandle_(datasetName), &H5Dclose, err
orMessage.c_str());
// the object in the HDF5 file may have one additional dimension which
we
// interprete as the pixel type's bands
int offset = (numBandsOfType > 1)
? 1
: 0;
vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dimsh
ape.size()),
"HDF5File::read(): Array dimension disagrees with dataset dimension
.");
typename MultiArrayShape<N>::type shape;
for(int k=offset; k < (int)dimshape.size(); ++k)
shape[k-offset] = (MultiArrayIndex)dimshape[k];
vigra_precondition(shape == array.shape(),
"HDF5File::read(): Array shape disagrees with datase
t shape.");
if (offset)
vigra_precondition(dimshape[0] == static_cast<hsize_t>(numBandsOfTy
pe),
"HDF5File::read(): Band count doesn't match dest
ination array compound type.");
herr_t status = 0;
if(array.isUnstrided())
{ {
readHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counte // when the array is unstrided, we can read the data directly into
r, elements, numBandsOfType, MetaInt<N-1>()); the array buffer
status = H5Dread(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEF
AULT, array.data() );
} }
else
{
// otherwise, we need an intermediate buffer
ArrayVector<hsize_t> null(dimshape.size(), 0),
chunks(dimshape.size(), 1),
start(dimshape.size(), 0),
count(dimshape.size(), 1);
HDF5Handle properties(H5Dget_create_plist(datasetHandle),
&H5Pclose, "HDF5File::read(): failed to get pr
operty list");
if(H5D_CHUNKED == H5Pget_layout(properties))
{
// if the file is chunked, we use a buffer that matches the chu
nk size.
H5Pget_chunk(properties, static_cast<int>(chunks.size()), chunk
s.data());
std::reverse(chunks.begin(), chunks.end());
}
else
{
// otherwise, we compute a suitable chunk size.
chunks[0] = numBandsOfType;
MultiArrayIndex prod = 1;
for(unsigned int k=0; k<N; ++k)
{
chunks[k+offset] = array.shape(k);
prod *= array.shape(k);
if(prod > 300000)
break;
}
}
count[N-1-offset] = static_cast<hsize_t>(numBandsOfType);
typedef typename MultiArrayShape<N>::type Shape;
Shape chunkCount, chunkMaxShape;
for(unsigned int k=offset; k<chunks.size(); ++k)
{
chunkMaxShape[k-offset] = chunks[k];
chunkCount[k-offset] = (MultiArrayIndex)std::ceil(double(dimsha
pe[k]) / chunks[k]);
}
typename CoupledIteratorType<N>::type chunkIter = createCoupledIter
ator(chunkCount),
chunkEnd = chunkIter.getEndI
terator();
for(; chunkIter != chunkEnd; ++chunkIter)
{
Shape chunkStart(chunkIter.point() * chunkMaxShape),
chunkStop(min(chunkStart + chunkMaxShape, array.shape()))
;
MultiArray<N, T> buffer(chunkStop - chunkStart);
for(unsigned int k=0; k<N; ++k)
{
start[N-1-k] = chunkStart[k];
count[N-1-k] = buffer.shape(k);
}
if(offset == 1)
{
start[N] = 0;
count[N] = numBandsOfType;
}
HDF5Handle filespace(H5Dget_space(datasetHandle),
&H5Sclose, "HDF5File::read(): unable to cr
eate hyperslabs.");
status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start.d
ata(), NULL, count.data(), NULL);
if(status < 0)
break;
HDF5Handle dataspace(H5Screate_simple(count.size(), count.data(
), NULL),
&H5Sclose, "HDF5File::read(): unable to cr
eate hyperslabs.");
status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, null.da
ta(), NULL, count.data(), NULL);
if(status < 0)
break;
status = H5Dread(datasetHandle, datatype, dataspace, filespace,
H5P_DEFAULT, buffer.data());
if(status < 0)
break;
array.subarray(chunkStart, chunkStop) = buffer;
}
}
vigra_postcondition(status >= 0,
"HDF5File::read(): read from dataset '" + datasetName + "' via H5Dr
ead() failed.");
}
/********************************************************************/
template<unsigned int N, class T, class Stride>
herr_t HDF5File::readBlock_(HDF5HandleShared datasetHandle,
typename MultiArrayShape<N>::type &blockOffset,
typename MultiArrayShape<N>::type &blockShape,
MultiArrayView<N, T, Stride> array,
const hid_t datatype, const int numBandsOfType)
{
vigra_precondition(blockShape == array.shape(),
"HDF5File::readBlock(): Array shape disagrees with block size.");
ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
hssize_t dimensions = getDatasetDimensions_(datasetHandle);
if(numBandsOfType > 1)
{
vigra_precondition(N+1 == dimensions,
"HDF5File::readBlock(): Array dimension disagrees with data dim
ension.");
bshape.resize(N+1);
boffset.resize(N+1);
bshape[N] = numBandsOfType;
boffset[N] = 0;
}
else
{
vigra_precondition(N == dimensions,
"HDF5File::readBlock(): Array dimension disagrees with data dim
ension.");
bshape.resize(N);
boffset.resize(N);
}
for(int i = 0; i < N; ++i)
{
// vigra and hdf5 use different indexing
bshape[N-1-i] = blockShape[i];
boffset[N-1-i] = blockOffset[i];
}
// create a target dataspace in memory with the shape of the desired bl
ock
HDF5Handle memspace_handle(H5Screate_simple(bshape.size(), bshape.data(
), NULL),
&H5Sclose,
"Unable to create target dataspace");
// get file dataspace and select the desired block
HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose,
"Unable to get dataspace");
H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET,
boffset.data(), bones.data(), bones.data(), bshape.
data());
herr_t status = 0;
if(array.isUnstrided())
{
// when the array is unstrided, we can read the data directly into
the array buffer
status = H5Dread( datasetHandle, datatype, memspace_handle, dataspa
ceHandle, H5P_DEFAULT, array.data());
}
else
{
// otherwise, we need an unstrided extra buffer ...
MultiArray<N, T> buffer(array.shape());
status = H5Dread( datasetHandle, datatype, memspace_handle, dataspa
ceHandle, H5P_DEFAULT, buffer.data());
// ... and must copy the values
if(status >= 0)
array = buffer;
}
return status;
}
/********************************************************************/
template<unsigned int N, class T, class Stride>
void HDF5File::read_attribute_(std::string datasetName,
std::string attributeName,
MultiArrayView<N, T, Stride> array,
const hid_t datatype, const int numBandsOfTy
pe)
{
std::string dataset_path = get_absolute_path(datasetName);
// open Attribute handle
std::string message = "HDF5File::readAttribute(): could not get handle
for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
HDF5Handle attr_handle (H5Aopen_by_name(fileHandle_,dataset_path.c_str(
),attributeName.c_str(),H5P_DEFAULT,H5P_DEFAULT),&H5Aclose, message.c_str()
);
// get Attribute dataspace
message = "HDF5File::readAttribute(): could not get dataspace for attri
bute '"+attributeName+"'' of object '"+dataset_path+"'.";
HDF5Handle attr_dataspace_handle (H5Aget_space(attr_handle),&H5Sclose,m
essage.c_str());
// obtain Attribute shape
int raw_dims = H5Sget_simple_extent_ndims(attr_dataspace_handle);
int dims = std::max(raw_dims, 1); // scalar attributes may be stored wi
th raw_dims==0
ArrayVector<hsize_t> dimshape(dims);
if(raw_dims > 0)
H5Sget_simple_extent_dims(attr_dataspace_handle, dimshape.data(), N
ULL);
else
dimshape[0] = 1;
// invert the dimensions to guarantee VIGRA-compatible order
std::reverse(dimshape.begin(), dimshape.end());
int offset = (numBandsOfType > 1)
? 1
: 0;
message = "HDF5File::readAttribute(): Array dimension disagrees with da
taset dimension.";
// the object in the HDF5 file may have one additional dimension which
we then interpret as the pixel type bands
vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dims)
, message);
for(int k=offset; k < (int)dimshape.size(); ++k)
vigra_precondition(array.shape()[k-offset] == (MultiArrayIndex)dims
hape[k],
"HDF5File::readAttribute(): Array shape disagree
s with dataset shape");
herr_t status = 0;
if(array.isUnstrided())
{
// when the array is unstrided, we can read the data directly into
the array buffer
status = H5Aread( attr_handle, datatype, array.data());
}
else
{
// otherwise, we need an unstrided extra buffer ...
// (we assume that attributes are small arrays, so that the wasted
memory is uncritical)
MultiArray<N, T> buffer(array.shape());
status = H5Aread( attr_handle, datatype, buffer.data() );
// ... and must copy the values
if(status >= 0)
array = buffer;
}
vigra_postcondition(status >= 0,
"HDF5File::readAttribute(): read from attribute '" + attributeName
+ "' via H5Aread() failed.");
} }
} // namespace detail /********************************************************************/
/** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object /** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object
and write the into the given 'array'. and write the into the given 'array'.
The array must have the correct number of dimensions and shape for the dataset The array must have the correct number of dimensions and shape for the dataset
represented by 'info'. When the element type of 'array' differs from th e stored element represented by 'info'. When the element type of 'array' differs from th e stored element
type, HDF5 will convert the type on the fly (except when the HDF5 versi on is 1.6 or below, type, HDF5 will convert the type on the fly (except when the HDF5 versi on is 1.6 or below,
in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue, in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue,
\ref vigra::TinyVector, and \ref vigra::FFTWComplex) are recognized and handled correctly. \ref vigra::TinyVector, and \ref vigra::FFTWComplex) are recognized and handled correctly.
skipping to change at line 2321 skipping to change at line 3336
vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimens ional."); vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimens ional.");
MultiArrayShape<3>::type shape(info.shape().begin()); MultiArrayShape<3>::type shape(info.shape().begin());
MultiArray<3, int> array(shape); MultiArray<3, int> array(shape);
readHDF5(info, array); readHDF5(info, array);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void readHDF5) doxygen_overloaded_function(template <...> void readHDF5)
// scalar and unstrided target multi array template<unsigned int N, class T, class StrideTag>
template<unsigned int N, class T> inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Strid
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Unstr eTag> array)
idedArrayTag> array) // scalar
{
readHDF5(info, array, detail::getH5DataType<T>(), 1);
}
// non-scalar (TinyVector) and unstrided target multi array
template<unsigned int N, class T, int SIZE>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVect
or<T, SIZE>, UnstridedArrayTag> array)
{
readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
}
// non-scalar (RGBValue) and unstrided target multi array
template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue
<T>, UnstridedArrayTag> array)
{
readHDF5(info, array, detail::getH5DataType<T>(), 3);
}
// non-scalar (FFTWComplex) and unstrided target multi array
template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, FFTWComp
lex<T>, UnstridedArrayTag> array)
{
readHDF5(info, array, detail::getH5DataType<T>(), 2);
}
// unstrided target multi array
template<unsigned int N, class T>
void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArr
ayTag> array, const hid_t datatype, const int numBandsOfType)
{
int offset = (numBandsOfType > 1);
//std::cout << "offset: " << offset << ", N: " << N << ", dims: " << in
fo.numDimensions() << std::endl;
vigra_precondition(( (N + offset ) == info.numDimensions()), // the obj
ect in the HDF5 file may have one additional dimension which we then interp
ret as the pixel type bands
"readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimen
sions().");
typename MultiArrayShape<N>::type shape;
for(int k=offset; k<info.numDimensions(); ++k) {
shape[k-offset] = info.shapeOfDimension(k);
}
vigra_precondition(shape == array.shape(),
"readHDF5(): Array shape disagrees with HDF5ImportInfo.");
// simply read in the data as is
H5Dread( info.getDatasetHandle(), datatype, H5S_ALL, H5S_ALL, H5P_DEFAU
LT, array.data() ); // .data() possible since void pointer!
}
// scalar and strided target multi array
template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Strid
edArrayTag> array) // scalar
{ {
readHDF5(info, array, detail::getH5DataType<T>(), 1); readHDF5(info, array, 0, 0); // last two arguments are not used
} }
// non-scalar (TinyVector) and strided target multi array template<unsigned int N, class T, class StrideTag>
template<unsigned int N, class T, int SIZE> void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> a
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVect rray, const hid_t datatype, const int numBandsOfType)
or<T, SIZE>, StridedArrayTag> array)
{ {
readHDF5(info, array, detail::getH5DataType<T>(), SIZE); HDF5File file(info.getFilePath(), HDF5File::OpenReadOnly);
} file.read(info.getPathInFile(), array);
file.close();
// non-scalar (RGBValue) and strided target multi array
template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue
<T>, StridedArrayTag> array)
{
readHDF5(info, array, detail::getH5DataType<T>(), 3);
}
// strided target multi array
template<unsigned int N, class T>
void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArray
Tag> array, const hid_t datatype, const int numBandsOfType)
{
int offset = (numBandsOfType > 1);
//std::cout << "offset: " << offset << ", N: " << N << ", dims: " << in
fo.numDimensions() << std::endl;
vigra_precondition(( (N + offset ) == info.numDimensions()), // the obj
ect in the HDF5 file may have one additional dimension which we then interp
ret as the pixel type bands
"readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimen
sions().");
typename MultiArrayShape<N>::type shape;
for(int k=offset; k<info.numDimensions(); ++k) {
shape[k-offset] = info.shapeOfDimension(k);
}
vigra_precondition(shape == array.shape(),
"readHDF5(): Array shape disagrees with HDF5ImportInfo.");
//Get the data
int counter = 0;
int elements = numBandsOfType;
for(unsigned int i=0;i<N;++i)
elements *= shape[i];
ArrayVector<T> buffer(shape[0]);
detail::readHDF5Impl(array.traverser_begin(), shape, info.getDatasetHan
dle(), datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<
N-1>());
} }
inline hid_t openGroup(hid_t parent, std::string group_name) inline hid_t openGroup(hid_t parent, std::string group_name)
{ {
//std::cout << group_name << std::endl; //std::cout << group_name << std::endl;
size_t last_slash = group_name.find_last_of('/'); size_t last_slash = group_name.find_last_of('/');
if (last_slash == std::string::npos || last_slash != group_name.size() - 1) if (last_slash == std::string::npos || last_slash != group_name.size() - 1)
group_name = group_name + '/'; group_name = group_name + '/';
std::string::size_type begin = 0, end = group_name.find('/'); std::string::size_type begin = 0, end = group_name.find('/');
int ii = 0; int ii = 0;
skipping to change at line 2579 skipping to change at line 3510
//alloc memory for dataset. //alloc memory for dataset.
dataset_handle = HDF5Handle(H5Dcreate(group, dataset_handle = HDF5Handle(H5Dcreate(group,
data_set_name.c_str(), data_set_name.c_str(),
datatype, datatype,
dataspace_handle, dataspace_handle,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAU LT), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAU LT),
&H5Dclose, "createDataset(): unable to create dataset."); &H5Dclose, "createDataset(): unable to create dataset.");
} }
namespace detail {
template <class DestIterator, class Shape, class T>
inline void
writeHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id,
const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int ele
ments, const int numBandsOfType, MetaInt<0>)
{
DestIterator dend = d + (typename DestIterator::difference_type)shape[0
];
int k = 0;
//std::cout << "new:" << std::endl;
for(; d < dend; ++d, k++)
{
buffer[k] = *d;
//std::cout << buffer[k] << " ";
}
//std::cout << std::endl;
HDF5Handle mid1, mid2;
// select hyperslabs
selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
// write to hdf5
H5Dwrite(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
// increase counter
counter++;
}
template <class DestIterator, class Shape, class T, int N>
void
writeHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id,
const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int ele
ments, const int numBandsOfType, MetaInt<N>)
{
DestIterator dend = d + (typename DestIterator::difference_type)sha
pe[N];
for(; d < dend; ++d)
{
writeHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, c
ounter, elements, numBandsOfType, MetaInt<N-1>());
}
}
} // namespace detail
/** \brief Store array data in an HDF5 file. /** \brief Store array data in an HDF5 file.
The number of dimensions, shape and element type of the stored dataset is automatically The number of dimensions, shape and element type of the stored dataset is automatically
determined from the properties of the given \a array. Strided arrays ar e stored in an determined from the properties of the given \a array. Strided arrays ar e stored in an
unstrided way, i.e. in contiguous scan-order. Multi-channel element typ es unstrided way, i.e. in contiguous scan-order. Multi-channel element typ es
(i.e. \ref vigra::RGBValue, \ref vigra::TinyVector and \ref vigra::FFTW Complex) (i.e. \ref vigra::RGBValue, \ref vigra::TinyVector and \ref vigra::FFTW Complex)
are recognized and handled correctly are recognized and handled correctly
(in particular, the will form the innermost dimension of the stored dat aset). (in particular, the will form the innermost dimension of the stored dat aset).
\a pathInFile may contain '/'-separated group names, but must end with the name \a pathInFile may contain '/'-separated group names, but must end with the name
of the dataset to be created. of the dataset to be created.
skipping to change at line 2655 skipping to change at line 3547
\code \code
MultiArrayShape<3>::type shape(100, 200, 20); MultiArrayShape<3>::type shape(100, 200, 20);
MultiArray<3, int> array(shape); MultiArray<3, int> array(shape);
... // fill array with data ... // fill array with data
writeHDF5("mydata.h5", "/group1/my_dataset", array); writeHDF5("mydata.h5", "/group1/my_dataset", array);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void writeHDF5) doxygen_overloaded_function(template <...> void writeHDF5)
// scalar and unstrided multi arrays template<unsigned int N, class T, class StrideTag>
template<unsigned int N, class T> inline void writeHDF5(const char* filePath, const char* pathInFile, const M
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, T, StrideTag> & array)
ultiArrayView<N, T, UnstridedArrayTag> & array) // scalar
{ {
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1); //last two arguments are not used
writeHDF5(filePath, pathInFile, array, 0, 0);
} }
// non-scalar (TinyVector) and unstrided multi arrays template<unsigned int N, class T, class StrideTag>
template<unsigned int N, class T, int SIZE> void writeHDF5(const char* filePath, const char* pathInFile, const MultiArr
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ayView<N, T, StrideTag> & array, const hid_t datatype, const int numBandsOf
ultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array) Type)
{ {
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE HDF5File file(filePath, HDF5File::Open);
); file.write(pathInFile, array);
} file.close();
// non-scalar (RGBValue) and unstrided multi arrays
template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M
ultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
}
// non-scalar (FFTWComplex) and unstrided multi arrays
template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M
ultiArrayView<N, FFTWComplex<T>, UnstridedArrayTag> & array)
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 2);
}
// unstrided multi arrays
template<unsigned int N, class T>
void writeHDF5(const char* filePath, const char* pathInFile, const MultiArr
ayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int nu
mBandsOfType)
{
HDF5Handle file_handle;
HDF5Handle dataset_handle;
createDataset(filePath, pathInFile, array, datatype, numBandsOfType, fi
le_handle, dataset_handle);
// Write the data to the HDF5 dataset as is
H5Dwrite( dataset_handle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, arra
y.data()); // .data() possible since void pointer!
H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
}
// scalar and strided multi arrays
template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M
ultiArrayView<N, T, StridedArrayTag> & array) // scalar
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
}
// non-scalar (TinyVector) and strided multi arrays
template<unsigned int N, class T, int SIZE>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M
ultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> & array)
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE
);
}
// non-scalar (RGBValue) and strided multi arrays
template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M
ultiArrayView<N, RGBValue<T>, StridedArrayTag> & array)
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
}
// non-scalar (FFTWComplex) and strided multi arrays
template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M
ultiArrayView<N, FFTWComplex<T>, StridedArrayTag> & array)
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 2);
}
// strided multi arrays
template<unsigned int N, class T>
void writeHDF5(const char* filePath, const char* pathInFile, const MultiArr
ayView<N, T, StridedArrayTag> & array, const hid_t datatype, const int numB
andsOfType)
{
HDF5Handle file_handle;
HDF5Handle dataset_handle;
createDataset(filePath, pathInFile, array, datatype, numBandsOfType, fi
le_handle, dataset_handle);
vigra::TinyVector<int,N> shape;
vigra::TinyVector<int,N> stride;
int elements = numBandsOfType;
for(unsigned int k=0; k<N; ++k)
{
shape[k] = array.shape(k);
stride[k] = array.stride(k);
elements *= (int)shape[k];
}
int counter = 0;
ArrayVector<T> buffer((int)array.shape(0));
detail::writeHDF5Impl(array.traverser_begin(), shape, dataset_handle, d
atatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
} }
namespace detail namespace detail
{ {
struct MaxSizeFnc struct MaxSizeFnc
{ {
size_t size; size_t size;
MaxSizeFnc() MaxSizeFnc()
: size(0) : size(0)
 End of changes. 160 change blocks. 
1052 lines changed or deleted 1906 lines changed or added


 histogram.hxx   histogram.hxx 
skipping to change at line 67 skipping to change at line 67
double maximum; double maximum;
/** \brief Total number of bins in the histogram. */ /** \brief Total number of bins in the histogram. */
int binCount; int binCount;
/** \brief If true, range mapping bounds are defined by minimum and max imum of the data. */ /** \brief If true, range mapping bounds are defined by minimum and max imum of the data. */
bool local_auto_init; bool local_auto_init;
/** Initialize members with default values: /** Initialize members with default values:
- minimum, maximum = 0.0 - minimum, maximum = 0.0
- binCount = 64 - binCount = 64
- local_auto_init = false - local_auto_init = false
*/ */
HistogramOptions() HistogramOptions()
: minimum(0.0), maximum(0.0), : minimum(0.0), maximum(0.0),
binCount(64), binCount(64),
local_auto_init(false) local_auto_init(false)
{} {}
/** Set minimum = mi and maximum = ma. Requirement: mi < ma. /** Set minimum = mi and maximum = ma. Requirement: mi < ma.
*/ */
HistogramOptions & setMinMax(double mi, double ma) HistogramOptions & setMinMax(double mi, double ma)
skipping to change at line 182 skipping to change at line 182
bool hasData() const bool hasData() const
{ {
return bins_ != 0; return bins_ != 0;
} }
BinType const & operator[](int k) const BinType const & operator[](int k) const
{ {
return *(bins_ + k*stride_); return *(bins_ + k*stride_);
} }
double mapItem(DataType const & d) const double mapItem(DataType const & d) const
{ {
return scale_ * (d - offset_); return scale_ * (d - offset_);
} }
DataType mapItemInverse(double d) const DataType mapItemInverse(double d) const
{ {
return DataType(d * scaleInverse_ + offset_); return DataType(d * scaleInverse_ + offset_);
} }
void add(DataType const & d, BinType weight = NumericTraits<BinType>::o ne()) void add(DataType const & d, BinType weight = NumericTraits<BinType>::o ne())
{ {
get(int(mapItem(d))) += weight; get(int(mapItem(d))) += weight;
} }
protected: protected:
BinType & get(int index) BinType & get(int index)
{ {
if(index < 0) if(index < 0)
index = 0; index = 0;
if(index >= size_) if(index >= size_)
index = size_ - 1; index = size_ - 1;
return *(bins_ + index*stride_); return *(bins_ + index*stride_);
} }
}; };
template <class T> template <class T>
class TrapezoidKernel class TrapezoidKernel
{ {
public: public:
typedef T value_type; typedef T value_type;
T operator[](double f) const T operator[](double f) const
{ {
skipping to change at line 290 skipping to change at line 290
void add(DataType const & d, BinType weight = NumericTraits<BinType>::o ne()) void add(DataType const & d, BinType weight = NumericTraits<BinType>::o ne())
{ {
double mapped = this->mapItem(d); double mapped = this->mapItem(d);
double f = mapped - std::floor(mapped) - kernel_.radius(); double f = mapped - std::floor(mapped) - kernel_.radius();
int center = int(mapped); int center = int(mapped);
for(int k=center+radius_; k>=center-radius_; --k, f += 1.0) for(int k=center+radius_; k>=center-radius_; --k, f += 1.0)
{ {
this->get(k) += weight*kernel_[f]; this->get(k) += weight*kernel_[f];
} }
} }
DataType findMode() const DataType findMode() const
{ {
double mmax = 0, vmax = 0, m; double mmax = 0, vmax = 0, m;
for(int k=0; k<this->size(); ++k) for(int k=0; k<this->size(); ++k)
{ {
double l = k > 0 double l = k > 0
? (*this)[k-1] ? (*this)[k-1]
 End of changes. 5 change blocks. 
17 lines changed or deleted 17 lines changed or added


 imagecontainer.hxx   imagecontainer.hxx 
skipping to change at line 67 skipping to change at line 67
An ImageArray manages an array of images of the type given as An ImageArray manages an array of images of the type given as
template parameter. Use it like a ArrayVector<ImageType>, it has template parameter. Use it like a ArrayVector<ImageType>, it has
the same interface, only operator< is missing from ImageArray. It the same interface, only operator< is missing from ImageArray. It
offers additional functions for resizing the images and querying offers additional functions for resizing the images and querying
their common size. See \ref imageSize() for additional notes. their common size. See \ref imageSize() for additional notes.
A customized allocator can be passed as a template argument and via the constructor. A customized allocator can be passed as a template argument and via the constructor.
By default, the allocator of the <tt>ImageType</tt> is reused. By default, the allocator of the <tt>ImageType</tt> is reused.
<b>\#include</b> \<vigra/imagecontainer.hxx\> <b>\#include</b> \<vigra/imagecontainer.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class ImageType, template <class ImageType,
class Alloc = typename ImageType::allocator_type::template rebind<Ima geType>::other > class Alloc = typename ImageType::allocator_type::template rebind<Ima geType>::other >
class ImageArray class ImageArray
{ {
Size2D imageSize_; Size2D imageSize_;
protected: protected:
typedef ArrayVector<ImageType, Alloc> ImageVector; typedef ArrayVector<ImageType, Alloc> ImageVector;
skipping to change at line 461 skipping to change at line 460
template parameter, where each level has half the width and height template parameter, where each level has half the width and height
of its predecessor. It actually represents a sequence of pyramid of its predecessor. It actually represents a sequence of pyramid
levels whose start and end index are configurable. For Burt-style levels whose start and end index are configurable. For Burt-style
pyramids, see also \ref pyramidReduceBurtFilter and \ref pyramids, see also \ref pyramidReduceBurtFilter and \ref
pyramidExpandBurtFilter. pyramidExpandBurtFilter.
A customized allocator can be passed as a template argument and A customized allocator can be passed as a template argument and
via the constructor. By default, the allocator of the via the constructor. By default, the allocator of the
<tt>ImageType</tt> is reused. <tt>ImageType</tt> is reused.
<b>\#include</b> \<vigra/imagecontainer.hxx\> <b>\#include</b> \<vigra/imagecontainer.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class ImageType, template <class ImageType,
class Alloc = typename ImageType::allocator_type::template rebind<Ima geType>::other > class Alloc = typename ImageType::allocator_type::template rebind<Ima geType>::other >
class ImagePyramid class ImagePyramid
{ {
int lowestLevel_, highestLevel_; int lowestLevel_, highestLevel_;
protected: protected:
typedef ArrayVector<ImageType, Alloc> ImageVector; typedef ArrayVector<ImageType, Alloc> ImageVector;
 End of changes. 2 change blocks. 
4 lines changed or deleted 2 lines changed or added


 imageinfo.hxx   imageinfo.hxx 
skipping to change at line 138 skipping to change at line 138
to define the properties of an image to be written to disk. to define the properties of an image to be written to disk.
<b>\#include</b> \<vigra/imageinfo.hxx\><br> <b>\#include</b> \<vigra/imageinfo.hxx\><br>
Namespace: vigra Namespace: vigra
**/ **/
class ImageExportInfo class ImageExportInfo
{ {
public: public:
/** Construct ImageExportInfo object. /** Construct ImageExportInfo object.
The image will be stored under the given filename. The image will be stored under the given \a filename.
The file type will be guessed from the extension unless overrid den The file type will be guessed from the extension unless overrid den
by \ref setFileType(). Recognized extensions: '.bmp', '.exr', ' .gif', by \ref setFileType(). Recognized extensions: '.bmp', '.exr', ' .gif',
'.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras', '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras',
'.tif', '.tiff', '.xv', '.hdr'. '.tif', '.tiff', '.xv', '.hdr'.
EXR support requires libopenexr, JPEG support requires libjpeg, EXR support requires libopenexr, JPEG support requires libjpeg,
PNG support requires libpng and TIFF support requires libtiff. PNG support requires libpng and TIFF support requires libtiff.
If the data is exported to TIFF, the \a mode may be "a", in whi
ch case
the exported image is appended to the existing file, resulting
in a
multi-page TIFF image.
**/ **/
VIGRA_EXPORT ImageExportInfo( const char *, const char * = "w" ); VIGRA_EXPORT ImageExportInfo( const char * filename, const char * mode = "w" );
VIGRA_EXPORT ~ImageExportInfo(); VIGRA_EXPORT ~ImageExportInfo();
/** Set image file name. /** Set image file name.
The file type will be guessed from the extension unless overrid den The file type will be guessed from the extension unless overrid den
by \ref setFileType(). Recognized extensions: '.bmp', '.exr', ' .gif', by \ref setFileType(). Recognized extensions: '.bmp', '.exr', ' .gif',
'.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras', '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras',
'.tif', '.tiff', '.xv', '.hdr'. '.tif', '.tiff', '.xv', '.hdr'.
EXR support requires libopenexr, JPEG support requires libjpeg, EXR support requires libopenexr, JPEG support requires libjpeg,
PNG support requires libpng and TIFF support requires libtiff. PNG support requires libpng and TIFF support requires libtiff.
skipping to change at line 171 skipping to change at line 176
/** Return the image file opening mode. /** Return the image file opening mode.
**/ **/
VIGRA_EXPORT const char * getMode() const; VIGRA_EXPORT const char * getMode() const;
/** Store image as given file type. /** Store image as given file type.
This will override any type guessed This will override any type guessed
from the file name's extension. Recognized file types: from the file name's extension. Recognized file types:
<DL> <DL>
<DT>"BMP"<DD> Microsoft Windows bitmap image file. <DT><b>BMP:</b><DD> Microsoft Windows bitmap image file.
<DT>"EXR"<DD> OpenEXR high dynamic range image format. <DT><b>EXR:</b><DD> OpenEXR high dynamic range image format.
(only available if libopenexr is installed) (only available if libopenexr is installed)
<DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col <DT><b>GIF:</b><DD> CompuServe graphics interchange format; 8-b
or. it color.
<DT>"HDR"<DD> Radiance RGBE high dynamic range image format. <DT><b>HDR:</b><DD> Radiance RGBE high dynamic range image form
<DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format; at.
<DT><b>JPEG:</b><DD> Joint Photographic Experts Group JFIF form
at;
compressed 24-bit color (only available if libjpeg is installed ). compressed 24-bit color (only available if libjpeg is installed ).
<DT>"PNG"<DD> Portable Network Graphic <DT><b>PNG:</b><DD> Portable Network Graphic
(only available if libpng is installed). (only available if libpng is installed).
<DT>"PBM"<DD> Portable bitmap format (black and white). <DT><b>PBM:</b><DD> Portable bitmap format (black and white).
<DT>"PGM"<DD> Portable graymap format (gray scale). <DT><b>PGM:</b><DD> Portable graymap format (gray scale).
<DT>"PNM"<DD> Portable anymap. <DT><b>PNM:</b><DD> Portable anymap.
<DT>"PPM"<DD> Portable pixmap format (color). <DT><b>PPM:</b><DD> Portable pixmap format (color).
<DT>"SUN"<DD> SUN Rasterfile. <DT><b>SUN:</b><DD> SUN Rasterfile.
<DT>"TIFF"<DD> Tagged Image File Format. <DT><b>TIFF:</b><DD> Tagged Image File Format.
(only available if libtiff is installed.) (only available if libtiff is installed.)
<DT>"VIFF"<DD> Khoros Visualization image file. <DT><b>VIFF:</b><DD> Khoros Visualization image file.
</DL> </DL>
With the exception of TIFF, VIFF, PNG, and PNM all file types s tore With the exception of TIFF, VIFF, PNG, and PNM all file types s tore
1 byte (gray scale and mapped RGB) or 3 bytes (RGB) per only 1 byte (gray scale and mapped RGB) or 3 bytes (RGB) per
pixel. pixel.
PNG can store UInt8 and UInt16 values, and supports 1 and 3 cha nnel PNG can store UInt8 and UInt16 values, and supports 1 and 3 cha nnel
images. One additional alpha channel is also supported. images. One additional alpha channel is also supported.
PNM can store 1 and 3 channel images with UInt8, UInt16 and UIn t32 PNM can store 1 and 3 channel images with UInt8, UInt16 and UIn t32
values in each channel. values in each channel.
TIFF and VIFF are additionally able to store short and long TIFF and VIFF are additionally able to store short and long
integers (2 or 4 bytes) and real values (32 bit float and integers (2 or 4 bytes) and real values (32 bit float and
skipping to change at line 225 skipping to change at line 230
**/ **/
VIGRA_EXPORT ImageExportInfo & setFileType( const char * ); VIGRA_EXPORT ImageExportInfo & setFileType( const char * );
VIGRA_EXPORT const char * getFileType() const; VIGRA_EXPORT const char * getFileType() const;
/** Set compression type and quality. /** Set compression type and quality.
This option is ignored when the target file format doesn't reco gnize This option is ignored when the target file format doesn't reco gnize
the compression type. Valid arguments: the compression type. Valid arguments:
<DL> <DL>
<DT>"NONE"<DD> (recognized by EXR and TIFF): do not compress (m any other formats don't <DT><b>NONE:</b><DD> (recognized by EXR and TIFF): do not compr ess (many other formats don't
compress either, but it is not an option for the m). compress either, but it is not an option for the m).
<DT>"JPEG"<DD> (recognized by JPEG and TIFF): use JPEG compress ion. <DT><b>JPEG:</b><DD> (recognized by JPEG and TIFF): use JPEG co mpression.
You can also specify a compression quality param eter by You can also specify a compression quality param eter by
passing "JPEG QUALITY=N", where "N" must be an i nteger between 1 and 100 passing "JPEG QUALITY=N", where "N" must be an i nteger between 1 and 100
(e.g. "JPEG QUALITY=70"). (e.g. "JPEG QUALITY=70").
<DT>"JPEG-ARITH"<DD> (recognized by new versions of JPEG): use arithmetic coding as a back-end <DT><b>JPEG-ARITH:</b><DD> (recognized by new versions of JPEG) : use arithmetic coding as a back-end
after JPEG compression (by default, the back-end is Huffman coding). after JPEG compression (by default, the back-end is Huffman coding).
You can also specify a compression quality param eter by You can also specify a compression quality param eter by
passing "JPEG-ARITH QUALITY=N", where "N" must b e an integer between 1 and 100 passing "JPEG-ARITH QUALITY=N", where "N" must b e an integer between 1 and 100
(e.g. "JPEG-ARITH QUALITY=70"). (e.g. "JPEG-ARITH QUALITY=70").
<DT>"RLE", "RunLength"<DD> (recognized by EXR and TIFF): use ru n-length encoding. (BMP also <DT><b>RLE, RunLength:</b><DD> (recognized by EXR and TIFF): us e run-length encoding. (BMP also
uses run-length encoding, but there it is not an option). uses run-length encoding, but there it is not an option).
<DT>"PACKBITS"<DD> (recognized by TIFF): use packbits encoding <DT><b>PACKBITS:</b><DD> (recognized by TIFF): use packbits enc
(a variant of RLE). oding (a variant of RLE).
<DT>"DEFLATE"<DD> (recognized by TIFF): use deflate encoding, a <DT><b>DEFLATE:</b><DD> (recognized by TIFF): use deflate encod
s defined in zlib (PNG also ing, as defined in zlib (PNG also
uses deflate, but there it is not an option). uses deflate, but there it is not an option).
<DT>"LZW"<DD> (recognized by TIFF): use Lempel-Ziv-Welch encodi <DT><b>LZW:</b><DD> (recognized by TIFF): use Lempel-Ziv-Welch
ng. encoding.
<DT>"ZIP"<DD> (recognized by EXR): use zip-style encoding. <DT><b>ZIP:</b><DD> (recognized by EXR): use zip-style encoding
<DT>"PIZ"<DD> (recognized by EXR): use wavelet encoding. .
<DT>"PXR24"<DD> (recognized by EXR): reduce to 24-bit, then use <DT><b>PIZ:</b><DD> (recognized by EXR): use wavelet encoding.
zip-style encoding. <DT><b>PXR24:</b><DD> (recognized by EXR): reduce to 24-bit, th
<DT>"B44", "B44A"<DD> (recognized by EXR): see OpenEXR document en use zip-style encoding.
ation. <DT><b>B44, B44A:</b><DD> (recognized by EXR): see OpenEXR docu
<DT>"ASCII"<DD> (recognized by PNM): store pixels as ASCII (hum mentation.
an readable numbers). <DT><b>ASCII:</b><DD> (recognized by PNM): store pixels as ASCI
<DT>"RAW"<DD> (recognized by PNM): store pixels as uncompressed I (human readable numbers).
binary data. <DT><b>RAW:</b><DD> (recognized by PNM): store pixels as uncomp
<DT>"BILEVEL"<DD> (recognized by PNM): store as one bit per pix ressed binary data.
el. <DT><b>BILEVEL:</b><DD> (recognized by PNM): store as one bit p
<DT>"1" ... "100"<DD> deprecated (equivalent to <tt>setCompress er pixel.
ion("JPEG QUALITY=number")</tt> <DT><b>1 ... 100:</b><DD> deprecated (equivalent to <tt>setComp
ression("JPEG QUALITY=number")</tt>
where the number denotes the desired quality). where the number denotes the desired quality).
</DL> </DL>
Some of these options (e.g. "JPEG-ARITH", "LZW", "B44", "B44A") may only be available when Some of these options (e.g. "JPEG-ARITH", "LZW", "B44", "B44A") may only be available when
they have been enabled in the corresponding third-party library . they have been enabled in the corresponding third-party library .
**/ **/
VIGRA_EXPORT ImageExportInfo & setCompression( const char * type); VIGRA_EXPORT ImageExportInfo & setCompression( const char * type);
VIGRA_EXPORT const char * getCompression() const; VIGRA_EXPORT const char * getCompression() const;
/** Set the pixel type of the image file. Possible values are: /** Set the pixel type of the image file. Possible values are:
<DL> <DL>
<DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) <DT><b>UINT8:</b><DD> 8-bit unsigned integer (unsigned char)
<DT>"INT16"<DD> 16-bit signed integer (short) <DT><b>INT16:</b><DD> 16-bit signed integer (short)
<DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short) <DT><b>UINT16:</b><DD> 16-bit unsigned integer (unsigned short)
<DT>"INT32"<DD> 32-bit signed integer (long) <DT><b>INT32:</b><DD> 32-bit signed integer (long)
<DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long) <DT><b>UINT32:</b><DD> 32-bit unsigned integer (unsigned long)
<DT>"FLOAT"<DD> 32-bit floating point (float) <DT><b>FLOAT:</b><DD> 32-bit floating point (float)
<DT>"DOUBLE"<DD> 64-bit floating point (double) <DT><b>DOUBLE:</b><DD> 64-bit floating point (double)
</DL> </DL>
<b>Usage:</b> <b>Usage:</b>
\code \code
FImage img(w,h); FImage img(w,h);
// by default, float images are exported with pixeltype float // by default, float images are exported with pixeltype float
// when the target format support this type, i.e. is TIFF or VI FF. // when the target format support this type, i.e. is TIFF or VI FF.
exportImage(srcImageRange(img), ImageExportInfo("asFloat.tif")) ; exportImage(srcImageRange(img), ImageExportInfo("asFloat.tif")) ;
// if this is not desired, force a different pixeltype // if this is not desired, force a different pixeltype
exportImage(srcImageRange(img), ImageExportInfo("asByte.tif").s etPixelType("UINT8")); exportImage(srcImageRange(img), ImageExportInfo("asByte.tif").s etPixelType("UINT8"));
\endcode \endcode
**/ **/
VIGRA_EXPORT ImageExportInfo & setPixelType( const char * ); VIGRA_EXPORT ImageExportInfo & setPixelType( const char * );
/** Get the pixel type of the image. Possible values are: /** Get the pixel type of the image. Possible values are:
<DL> <DL>
<DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) <DT><b>UINT8:</b><DD> 8-bit unsigned integer (unsigned char)
<DT>"INT16"<DD> 16-bit signed integer (short) <DT><b>INT16:</b><DD> 16-bit signed integer (short)
<DT>"INT32"<DD> 32-bit signed integer (long) <DT><b>INT32:</b><DD> 32-bit signed integer (long)
<DT>"FLOAT"<DD> 32-bit floating point (float) <DT><b>FLOAT:</b><DD> 32-bit floating point (float)
<DT>"DOUBLE"<DD> 64-bit floating point (double) <DT><b>DOUBLE:</b><DD> 64-bit floating point (double)
</DL> </DL>
**/ **/
VIGRA_EXPORT const char * getPixelType() const; VIGRA_EXPORT const char * getPixelType() const;
VIGRA_EXPORT ImageExportInfo & setForcedRangeMapping(double fromMin, do uble fromMax, VIGRA_EXPORT ImageExportInfo & setForcedRangeMapping(double fromMin, do uble fromMax,
double toMin, double t oMax); double toMin, double t oMax);
VIGRA_EXPORT bool hasForcedRangeMapping() const; VIGRA_EXPORT bool hasForcedRangeMapping() const;
VIGRA_EXPORT double getFromMin() const; VIGRA_EXPORT double getFromMin() const;
VIGRA_EXPORT double getFromMax() const; VIGRA_EXPORT double getFromMax() const;
VIGRA_EXPORT double getToMin() const; VIGRA_EXPORT double getToMin() const;
skipping to change at line 320 skipping to change at line 325
/** Set the image resolution in vertical direction /** Set the image resolution in vertical direction
**/ **/
VIGRA_EXPORT ImageExportInfo & setYResolution( float ); VIGRA_EXPORT ImageExportInfo & setYResolution( float );
VIGRA_EXPORT float getYResolution() const; VIGRA_EXPORT float getYResolution() const;
/** Set the position of the upper Left corner on a global /** Set the position of the upper Left corner on a global
canvas. canvas.
Currently only supported by TIFF, PNG and OpenEXR files. Currently only supported by TIFF, PNG and OpenEXR files.
The offset is encoded in the XPosition and YPosition TIFF tags. The offset is encoded in the XPosition and YPosition TIFF tags.
TIFF
requires that the resolution must also be set.
@param pos position of the upper left corner in pixels @param pos position of the upper left corner in pixels
(must be >= 0) (must be >= 0 for TIFF)
**/ **/
VIGRA_EXPORT ImageExportInfo & setPosition(const Diff2D & pos); VIGRA_EXPORT ImageExportInfo & setPosition(const Diff2D & pos);
/** Get the position of the upper left corner on /** Get the position of the upper left corner on
a global canvas. a global canvas.
**/ **/
VIGRA_EXPORT Diff2D getPosition() const; VIGRA_EXPORT Diff2D getPosition() const;
/** Get the size of the canvas, on which the image is positioned at /** Get the size of the canvas, on which the image is positioned at
getPosition() getPosition()
skipping to change at line 396 skipping to change at line 402
public: public:
enum PixelType { UINT8, INT16, UINT16, INT32, UINT32, FLOAT, DOUBLE }; enum PixelType { UINT8, INT16, UINT16, INT32, UINT32, FLOAT, DOUBLE };
/** Construct ImageImportInfo object. /** Construct ImageImportInfo object.
The image with the given filename is read into memory. The image with the given filename is read into memory.
The file type will be determined by the first few bytes of the The file type will be determined by the first few bytes of the
file (magic number). Recognized file types: file (magic number). Recognized file types:
<DL> <DL>
<DT>"BMP"<DD> Microsoft Windows bitmap image file. <DT><b>BMP:</b><DD> Microsoft Windows bitmap image file.
<DT>"EXR"<DD> OpenEXR high dynamic range image format. <DT><b>EXR:</b><DD> OpenEXR high dynamic range image format.
(only available if libopenexr is installed) (only available if libopenexr is installed)
<DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col <DT><b>GIF:</b><DD> CompuServe graphics interchange format; 8-b
or. it color.
<DT>"HDR"<DD> Radiance RGBE high dynamic range image format. <DT><b>HDR:</b><DD> Radiance RGBE high dynamic range image form
<DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format; at.
<DT><b>JPEG:</b><DD> Joint Photographic Experts Group JFIF form
at;
compressed 24-bit color (only available if libjpeg is installed ). compressed 24-bit color (only available if libjpeg is installed ).
<DT>"PNG"<DD> Portable Network Graphic <DT><b>PNG:</b><DD> Portable Network Graphic
(only available if libpng is installed). (only available if libpng is installed).
<DT>"PBM"<DD> Portable bitmap format (black and white). <DT><b>PBM:</b><DD> Portable bitmap format (black and white).
<DT>"PGM"<DD> Portable graymap format (gray scale). <DT><b>PGM:</b><DD> Portable graymap format (gray scale).
<DT>"PNM"<DD> Portable anymap. <DT><b>PNM:</b><DD> Portable anymap.
<DT>"PPM"<DD> Portable pixmap format (color). <DT><b>PPM:</b><DD> Portable pixmap format (color).
<DT>"SUN"<DD> SUN Rasterfile. <DT><b>SUN:</b><DD> SUN Rasterfile.
<DT>"TIFF"<DD> Tagged Image File Format. <DT><b>TIFF:</b><DD> Tagged Image File Format.
(only available if libtiff is installed.) (only available if libtiff is installed.)
<DT>"VIFF"<DD> Khoros Visualization image file. <DT><b>VIFF:</b><DD> Khoros Visualization image file.
</DL> </DL>
The parameter \a page can be used in conjunction with multi-pag
e TIFF
files in order to specify the desired page (i.e. image) in the
file.
**/ **/
VIGRA_EXPORT ImageImportInfo( const char *, unsigned int = 0 ); VIGRA_EXPORT ImageImportInfo( const char * filename, unsigned int page = 0 );
VIGRA_EXPORT ~ImageImportInfo(); VIGRA_EXPORT ~ImageImportInfo();
VIGRA_EXPORT const char * getFileName() const; VIGRA_EXPORT const char * getFileName() const;
/** Get the file type of the image associated with this /** Get the file type of the image associated with this
info object. info object.
See ImageImportInfo::ImageImportInfo for a list of the See ImageImportInfo::ImageImportInfo for a list of the
available file types. available file types.
**/ **/
skipping to change at line 477 skipping to change at line 486
VIGRA_EXPORT bool isGrayscale() const; VIGRA_EXPORT bool isGrayscale() const;
/** Returns true if the image is colored (RGB). /** Returns true if the image is colored (RGB).
**/ **/
VIGRA_EXPORT bool isColor() const; VIGRA_EXPORT bool isColor() const;
/** Query the pixel type of the image. /** Query the pixel type of the image.
Possible values are: Possible values are:
<DL> <DL>
<DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) <DT><b>UINT8:</b><DD> 8-bit unsigned integer (unsigned char)
<DT>"INT16"<DD> 16-bit signed integer (short) <DT><b>INT16:</b><DD> 16-bit signed integer (short)
<DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short) <DT><b>UINT16:</b><DD> 16-bit unsigned integer (unsigned short)
<DT>"INT32"<DD> 32-bit signed integer (long) <DT><b>INT32:</b><DD> 32-bit signed integer (long)
<DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long) <DT><b>UINT32:</b><DD> 32-bit unsigned integer (unsigned long)
<DT>"FLOAT"<DD> 32-bit floating point (float) <DT><b>FLOAT:</b><DD> 32-bit floating point (float)
<DT>"DOUBLE"<DD> 64-bit floating point (double) <DT><b>DOUBLE:</b><DD> 64-bit floating point (double)
</DL> </DL>
**/ **/
VIGRA_EXPORT const char * getPixelType() const; VIGRA_EXPORT const char * getPixelType() const;
/** Query the pixel type of the image. /** Query the pixel type of the image.
Same as getPixelType(), but the result is returned as a Same as getPixelType(), but the result is returned as a
ImageImportInfo::PixelType enum. This is useful to implement ImageImportInfo::PixelType enum. This is useful to implement
a switch() on the pixel type. a switch() on the pixel type.
Possible values are: Possible values are:
<DL> <DL>
<DT>UINT8<DD> 8-bit unsigned integer (unsigned char) <DT><b>UINT8:</b><DD> 8-bit unsigned integer (unsigned char)
<DT>INT16<DD> 16-bit signed integer (short) <DT><b>INT16:</b><DD> 16-bit signed integer (short)
<DT>UINT16<DD> 16-bit unsigned integer (unsigned short) <DT><b>UINT16:</b><DD> 16-bit unsigned integer (unsigned short)
<DT>INT32<DD> 32-bit signed integer (long) <DT><b>INT32:</b><DD> 32-bit signed integer (long)
<DT>UINT32<DD> 32-bit unsigned integer (unsigned long) <DT><b>UINT32:</b><DD> 32-bit unsigned integer (unsigned long)
<DT>FLOAT<DD> 32-bit floating point (float) <DT><b>FLOAT:</b><DD> 32-bit floating point (float)
<DT>DOUBLE<DD> 64-bit floating point (double) <DT><b>DOUBLE:</b><DD> 64-bit floating point (double)
</DL> </DL>
**/ **/
VIGRA_EXPORT PixelType pixelType() const; VIGRA_EXPORT PixelType pixelType() const;
/** Returns true if the image has 1 byte per pixel (gray) or /** Returns true if the image has 1 byte per pixel (gray) or
3 bytes per pixel (RGB). 3 bytes per pixel (RGB).
**/ **/
VIGRA_EXPORT bool isByte() const; VIGRA_EXPORT bool isByte() const;
/** Returns the layer offset of the current image, if there is one /** Returns the layer offset of the current image, if there is one
 End of changes. 29 change blocks. 
84 lines changed or deleted 103 lines changed or added


 imageiterator.hxx   imageiterator.hxx 
skipping to change at line 388 skipping to change at line 388
type & operator=(type const & rhs) type & operator=(type const & rhs)
{ {
current_ = rhs.current_; current_ = rhs.current_;
return *this; return *this;
} }
void operator++() {++current_;} void operator++() {++current_;}
void operator++(int) {++current_;} void operator++(int) {++current_;}
void operator--() {--current_;} void operator--() {--current_;}
void operator--(int) {--current_;} void operator--(int) {--current_;}
void operator+=(int dx) {current_ += dx; } void operator+=(std::ptrdiff_t dx) {current_ += dx; }
void operator-=(int dx) {current_ -= dx; } void operator-=(std::ptrdiff_t dx) {current_ -= dx; }
bool operator==(type const & rhs) const bool operator==(type const & rhs) const
{ return current_ == rhs.current_; } { return current_ == rhs.current_; }
bool operator!=(type const & rhs) const bool operator!=(type const & rhs) const
{ return current_ != rhs.current_; } { return current_ != rhs.current_; }
bool operator<(type const & rhs) const bool operator<(type const & rhs) const
{ return current_ < rhs.current_; } { return current_ < rhs.current_; }
bool operator<=(type const & rhs) const bool operator<=(type const & rhs) const
{ return current_ <= rhs.current_; } { return current_ <= rhs.current_; }
bool operator>(type const & rhs) const bool operator>(type const & rhs) const
{ return current_ > rhs.current_; } { return current_ > rhs.current_; }
bool operator>=(type const & rhs) const bool operator>=(type const & rhs) const
{ return current_ >= rhs.current_; } { return current_ >= rhs.current_; }
int operator-(type const & rhs) const std::ptrdiff_t operator-(type const & rhs) const
{ return current_ - rhs.current_; } { return current_ - rhs.current_; }
T operator()() const T operator()() const
{ return current_; } { return current_; }
T operator()(int d) const T operator()(std::ptrdiff_t d) const
{ return current_ + d; } { return current_ + d; }
T current_; T current_;
}; };
}; };
template <> template <>
class DirectionSelector<StridedArrayTag> class DirectionSelector<StridedArrayTag>
{ {
public: public:
template <class T> template <class T>
class type class type
{ {
public: public:
type(int stride, T base = 0) type(std::ptrdiff_t stride, T base = 0)
: stride_(stride), : stride_(stride),
current_(base) current_(base)
{} {}
type(type const & rhs) type(type const & rhs)
: stride_(rhs.stride_), : stride_(rhs.stride_),
current_(rhs.current_) current_(rhs.current_)
{} {}
type & operator=(type const & rhs) type & operator=(type const & rhs)
{ {
stride_ = rhs.stride_; stride_ = rhs.stride_;
current_ = rhs.current_; current_ = rhs.current_;
return *this; return *this;
} }
void operator++() {current_ += stride_; } void operator++() {current_ += stride_; }
void operator++(int) {current_ += stride_; } void operator++(int) {current_ += stride_; }
void operator--() {current_ -= stride_; } void operator--() {current_ -= stride_; }
void operator--(int) {current_ -= stride_; } void operator--(int) {current_ -= stride_; }
void operator+=(int dy) {current_ += dy*stride_; } void operator+=(std::ptrdiff_t dy) {current_ += dy*stride_; }
void operator-=(int dy) {current_ -= dy*stride_; } void operator-=(std::ptrdiff_t dy) {current_ -= dy*stride_; }
bool operator==(type const & rhs) const bool operator==(type const & rhs) const
{ return (current_ == rhs.current_); } { return (current_ == rhs.current_); }
bool operator!=(type const & rhs) const bool operator!=(type const & rhs) const
{ return (current_ != rhs.current_); } { return (current_ != rhs.current_); }
bool operator<(type const & rhs) const bool operator<(type const & rhs) const
{ return (current_ < rhs.current_); } { return (current_ < rhs.current_); }
bool operator<=(type const & rhs) const bool operator<=(type const & rhs) const
{ return (current_ <= rhs.current_); } { return (current_ <= rhs.current_); }
bool operator>(type const & rhs) const bool operator>(type const & rhs) const
{ return (current_ > rhs.current_); } { return (current_ > rhs.current_); }
bool operator>=(type const & rhs) const bool operator>=(type const & rhs) const
{ return (current_ >= rhs.current_); } { return (current_ >= rhs.current_); }
int operator-(type const & rhs) const std::ptrdiff_t operator-(type const & rhs) const
{ return (current_ - rhs.current_) / stride_; } { return (current_ - rhs.current_) / stride_; }
T operator()() const T operator()() const
{ return current_; } { return current_; }
T operator()(int d) const T operator()(std::ptrdiff_t d) const
{ return current_ + d*stride_; } { return current_ + d*stride_; }
int stride_; std::ptrdiff_t stride_;
T current_; T current_;
}; };
}; };
template <class StridedOrUnstrided> template <class StridedOrUnstrided>
class LinearIteratorSelector; class LinearIteratorSelector;
template <> template <>
class LinearIteratorSelector<UnstridedArrayTag> class LinearIteratorSelector<UnstridedArrayTag>
{ {
skipping to change at line 541 skipping to change at line 541
/* ImageIteratorBase */ /* ImageIteratorBase */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Base class for 2D random access iterators. /** \brief Base class for 2D random access iterators.
This class contains the navigational part of the iterator. This class contains the navigational part of the iterator.
It is usually not constructed directly, but via some derived class such as It is usually not constructed directly, but via some derived class such as
\ref ImageIterator or \ref StridedImageIterator. \ref ImageIterator or \ref StridedImageIterator.
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
The usage examples assume that you constructed two iterators like The usage examples assume that you constructed two iterators like
this: this:
\code \code
vigra::ImageIterator<SomePixelType> iterator(base, width); vigra::ImageIterator<SomePixelType> iterator(base, width);
vigra::ImageIterator<SomePixelType> iterator1(base, width); vigra::ImageIterator<SomePixelType> iterator1(base, width);
\endcode \endcode
skipping to change at line 617 skipping to change at line 616
typedef typename ColumnIteratorSelector::res column_iterator; typedef typename ColumnIteratorSelector::res column_iterator;
/** Let operations act in X direction /** Let operations act in X direction
*/ */
typedef typename typedef typename
vigra::detail::DirectionSelector<StridedOrUnstrided>::template type <pointer> MoveX; vigra::detail::DirectionSelector<StridedOrUnstrided>::template type <pointer> MoveX;
/** Let operations act in Y direction /** Let operations act in Y direction
*/ */
typedef typename typedef typename
vigra::detail::DirectionSelector<StridedArrayTag>::template type<in t> MoveY; vigra::detail::DirectionSelector<StridedArrayTag>::template type<st d::ptrdiff_t> MoveY;
/** @name Comparison of Iterators */ /** @name Comparison of Iterators */
//@{ //@{
/** usage: <TT> iterator == iterator1 </TT> /** usage: <TT> iterator == iterator1 </TT>
*/ */
bool operator==(ImageIteratorBase const & rhs) const bool operator==(ImageIteratorBase const & rhs) const
{ {
return (x == rhs.x) && (y == rhs.y); return (x == rhs.x) && (y == rhs.y);
} }
skipping to change at line 681 skipping to change at line 680
MoveY y; MoveY y;
//@} //@}
protected: protected:
/** Construct from raw memory with a vertical stride of <TT>ystride </TT>. /** Construct from raw memory with a vertical stride of <TT>ystride </TT>.
<TT>ystride</TT> must equal the physical image width (row length), <TT>ystride</TT> must equal the physical image width (row length),
even if the iterator will only be used for a sub image. This constr uctor even if the iterator will only be used for a sub image. This constr uctor
must only be called for unstrided iterators must only be called for unstrided iterators
(<tt>StridedOrUnstrided == UnstridedArrayTag</tt>) (<tt>StridedOrUnstrided == UnstridedArrayTag</tt>)
*/ */
ImageIteratorBase(pointer base, int ystride) ImageIteratorBase(pointer base, std::ptrdiff_t ystride)
: x(base), : x(base),
y(ystride) y(ystride)
{} {}
/** Construct from raw memory with a horizontal stride of <TT>xstri de</TT> /** Construct from raw memory with a horizontal stride of <TT>xstri de</TT>
and a vertical stride of <TT>ystride</TT>. This constructor and a vertical stride of <TT>ystride</TT>. This constructor
may be used for iterators that shall skip pixels. Thus, it may be used for iterators that shall skip pixels. Thus, it
must only be called for strided iterators must only be called for strided iterators
(<tt>StridedOrUnstrided == StridedArrayTag</tt>) (<tt>StridedOrUnstrided == StridedArrayTag</tt>)
*/ */
ImageIteratorBase(pointer base, int xstride, int ystride) ImageIteratorBase(pointer base, std::ptrdiff_t xstride, std::ptrdiff_t ystride)
: x(xstride, base), : x(xstride, base),
y(ystride) y(ystride)
{} {}
/** Copy constructor */ /** Copy constructor */
ImageIteratorBase(ImageIteratorBase const & rhs) ImageIteratorBase(ImageIteratorBase const & rhs)
: x(rhs.x), : x(rhs.x),
y(rhs.y) y(rhs.y)
{} {}
skipping to change at line 792 skipping to change at line 791
usage: <TT> SomePixelType value = iterator[Diff2D(1,1)] </TT> usage: <TT> SomePixelType value = iterator[Diff2D(1,1)] </TT>
*/ */
index_reference operator[](Diff2D const & d) const index_reference operator[](Diff2D const & d) const
{ {
return *current(d.x, d.y); return *current(d.x, d.y);
} }
/** Access pixel at offset (dx, dy) from current location. <br> /** Access pixel at offset (dx, dy) from current location. <br>
usage: <TT> SomePixelType value = iterator(dx, dy) </TT> usage: <TT> SomePixelType value = iterator(dx, dy) </TT>
*/ */
index_reference operator()(int dx, int dy) const index_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
{ {
return *current(dx, dy); return *current(dx, dy);
} }
/** Read pixel with offset [dy][dx] from current pixel. /** Read pixel with offset [dy][dx] from current pixel.
Note that the 'x' index is the trailing index. <br> Note that the 'x' index is the trailing index. <br>
usage: <TT> SomePixelType value = iterator[dy][dx] </TT> usage: <TT> SomePixelType value = iterator[dy][dx] </TT>
*/ */
pointer operator[](int dy) const pointer operator[](std::ptrdiff_t dy) const
{ {
return x() + y(dy); return x() + y(dy);
} }
//@} //@}
row_iterator rowIterator() const row_iterator rowIterator() const
{ {
return RowIteratorSelector::construct(current(), x); return RowIteratorSelector::construct(current(), x);
} }
column_iterator columnIterator() const column_iterator columnIterator() const
{ {
return ColumnIteratorSelector::construct(current(), y); return ColumnIteratorSelector::construct(current(), y);
} }
private: private:
pointer current() const pointer current() const
{ return x() + y(); } { return x() + y(); }
pointer current(int dx, int dy) const pointer current(std::ptrdiff_t dx, std::ptrdiff_t dy) const
{ return x(dx) + y(dy); } { return x(dx) + y(dy); }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* ImageIterator */ /* ImageIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Standard 2D random access iterator for images that store the /** \brief Standard 2D random access iterator for images that store the
data in a linear array. data in a linear array.
Most functions and local types are inherited from ImageIteratorBase. Most functions and local types are inherited from ImageIteratorBase.
See the paper: U. Koethe: See the paper: U. Koethe:
<a href="http://hci.iwr.uni-heidelberg.de/vigra/documents/GenericProg2D .ps">Reusable Algorithms in Image Processing</a> <a href="http://hci.iwr.uni-heidelberg.de/vigra/documents/GenericProg2D .ps">Reusable Algorithms in Image Processing</a>
for a discussion of the concepts behind ImageIterators. for a discussion of the concepts behind ImageIterators.
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE> template <class PIXELTYPE>
class ImageIterator class ImageIterator
: public ImageIteratorBase<ImageIterator<PIXELTYPE>, : public ImageIteratorBase<ImageIterator<PIXELTYPE>,
PIXELTYPE, PIXELTYPE &, PIXELTYPE *> PIXELTYPE, PIXELTYPE &, PIXELTYPE *>
{ {
public: public:
typedef ImageIteratorBase<ImageIterator<PIXELTYPE>, typedef ImageIteratorBase<ImageIterator<PIXELTYPE>,
skipping to change at line 865 skipping to change at line 863
typedef typename Base::pointer pointer; typedef typename Base::pointer pointer;
typedef typename Base::difference_type difference_type; typedef typename Base::difference_type difference_type;
/** Construct from raw memory with a vertical stride of <TT>ystride </TT>. /** Construct from raw memory with a vertical stride of <TT>ystride </TT>.
<TT>ystride</TT> must equal the physical image width (row length), <TT>ystride</TT> must equal the physical image width (row length),
even if the iterator will only be used for a sub image. even if the iterator will only be used for a sub image.
If the raw memory is encapsulated in an image object this If the raw memory is encapsulated in an image object this
object should have a factory function that constructs the object should have a factory function that constructs the
iterator. iterator.
*/ */
ImageIterator(pointer base, int ystride) ImageIterator(pointer base, std::ptrdiff_t ystride)
: Base(base, ystride) : Base(base, ystride)
{} {}
/** Default constructor */ /** Default constructor */
ImageIterator() ImageIterator()
: Base() : Base()
{} {}
}; };
skipping to change at line 887 skipping to change at line 885
/* */ /* */
/* ConstImageIterator */ /* ConstImageIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Standard 2D random access const iterator for images that /** \brief Standard 2D random access const iterator for images that
store the data as a linear array. store the data as a linear array.
Most functions are inherited from ImageIteratorBase. Most functions are inherited from ImageIteratorBase.
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE> template <class PIXELTYPE>
class ConstImageIterator class ConstImageIterator
: public ImageIteratorBase<ConstImageIterator<PIXELTYPE>, : public ImageIteratorBase<ConstImageIterator<PIXELTYPE>,
PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *> PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *>
{ {
public: public:
typedef ImageIteratorBase<ConstImageIterator<PIXELTYPE>, typedef ImageIteratorBase<ConstImageIterator<PIXELTYPE>,
skipping to change at line 911 skipping to change at line 908
typedef typename Base::pointer pointer; typedef typename Base::pointer pointer;
typedef typename Base::difference_type difference_type; typedef typename Base::difference_type difference_type;
/** Construct from raw memory with a vertical stride of <TT>ystride </TT>. /** Construct from raw memory with a vertical stride of <TT>ystride </TT>.
<TT>ystride</TT> must equal the physical image width (row length), <TT>ystride</TT> must equal the physical image width (row length),
even if the iterator will only be used for a sub image. even if the iterator will only be used for a sub image.
If the raw memory is encapsulated in an image object this If the raw memory is encapsulated in an image object this
object should have a factory function that constructs the object should have a factory function that constructs the
iterator. iterator.
*/ */
ConstImageIterator(pointer base, int ystride) ConstImageIterator(pointer base, std::ptrdiff_t ystride)
: Base(base, ystride) : Base(base, ystride)
{} {}
ConstImageIterator(ImageIterator<PIXELTYPE> const & o) ConstImageIterator(ImageIterator<PIXELTYPE> const & o)
: Base(o.x, o.y) : Base(o.x, o.y)
{} {}
/** Default constructor */ /** Default constructor */
ConstImageIterator() ConstImageIterator()
: Base() : Base()
skipping to change at line 961 skipping to change at line 958
int xskip = 2, yskip = 2; int xskip = 2, yskip = 2;
int wskip = w / xskip + 1, hskip = h / yskip + 1; int wskip = w / xskip + 1, hskip = h / yskip + 1;
StridedImageIterator<BImage::value_type> upperLeft(&img(0,0), w, xskip, yskip); StridedImageIterator<BImage::value_type> upperLeft(&img(0,0), w, xskip, yskip);
StridedImageIterator<BImage::value_type> lowerRight = upperLeft + Diff2 D(wskip, hskip); StridedImageIterator<BImage::value_type> lowerRight = upperLeft + Diff2 D(wskip, hskip);
// now navigation with upperLeft and lowerRight lets the image appear t o have half // now navigation with upperLeft and lowerRight lets the image appear t o have half
// the original resolution in either dimension // the original resolution in either dimension
\endcode \endcode
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE> template <class PIXELTYPE>
class StridedImageIterator class StridedImageIterator
: public ImageIteratorBase<StridedImageIterator<PIXELTYPE>, : public ImageIteratorBase<StridedImageIterator<PIXELTYPE>,
PIXELTYPE, PIXELTYPE &, PIXELTYPE *, StridedArra yTag> PIXELTYPE, PIXELTYPE &, PIXELTYPE *, StridedArra yTag>
{ {
public: public:
typedef ImageIteratorBase<StridedImageIterator<PIXELTYPE>, typedef ImageIteratorBase<StridedImageIterator<PIXELTYPE>,
PIXELTYPE, PIXELTYPE &, PIXELTYPE *, StridedA rrayTag> Base; PIXELTYPE, PIXELTYPE &, PIXELTYPE *, StridedA rrayTag> Base;
typedef typename Base::pointer pointer; typedef typename Base::pointer pointer;
typedef typename Base::difference_type difference_type; typedef typename Base::difference_type difference_type;
/** Construct from raw memory with a vertical stride of <TT>ystride </TT>, /** Construct from raw memory with a vertical stride of <TT>ystride </TT>,
jumping by <tt>xskip</tt> horizontally and <tt>yskip</tt> verticall y. jumping by <tt>xskip</tt> horizontally and <tt>yskip</tt> verticall y.
<tt>ystride</tt> must be the physical width (row length) of the ima ge. <tt>ystride</tt> must be the physical width (row length) of the ima ge.
*/ */
StridedImageIterator(pointer base, int ystride, int xskip, int yskip) StridedImageIterator(pointer base, std::ptrdiff_t ystride, std::ptrdiff _t xskip, std::ptrdiff_t yskip)
: Base(base, xskip, ystride*yskip) : Base(base, xskip, ystride*yskip)
{} {}
/** Default constructor */ /** Default constructor */
StridedImageIterator() StridedImageIterator()
: Base() : Base()
{} {}
}; };
skipping to change at line 1022 skipping to change at line 1018
int xskip = 2, yskip = 2; int xskip = 2, yskip = 2;
int wskip = w / xskip + 1, hskip = h / yskip + 1; int wskip = w / xskip + 1, hskip = h / yskip + 1;
ConstStridedImageIterator<BImage::value_type> upperLeft(&img(0,0), w, x skip, yskip); ConstStridedImageIterator<BImage::value_type> upperLeft(&img(0,0), w, x skip, yskip);
ConstStridedImageIterator<BImage::value_type> lowerRight = upperLeft + Diff2D(wskip, hskip); ConstStridedImageIterator<BImage::value_type> lowerRight = upperLeft + Diff2D(wskip, hskip);
// now navigation with upperLeft and lowerRight lets the image appear t o have half // now navigation with upperLeft and lowerRight lets the image appear t o have half
// the original resolution in either dimension // the original resolution in either dimension
\endcode \endcode
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE> template <class PIXELTYPE>
class ConstStridedImageIterator class ConstStridedImageIterator
: public ImageIteratorBase<ConstStridedImageIterator<PIXELTYPE>, : public ImageIteratorBase<ConstStridedImageIterator<PIXELTYPE>,
PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *, PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *,
StridedArrayTag> StridedArrayTag>
{ {
public: public:
skipping to change at line 1045 skipping to change at line 1040
PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *, PIXELTYPE, PIXELTYPE const &, PIXELTYPE const *,
StridedArrayTag> Base; StridedArrayTag> Base;
typedef typename Base::pointer pointer; typedef typename Base::pointer pointer;
typedef typename Base::difference_type difference_type; typedef typename Base::difference_type difference_type;
/** Construct from raw memory with a vertical stride of <TT>ystride </TT>, /** Construct from raw memory with a vertical stride of <TT>ystride </TT>,
jumping by <tt>xskip</tt> horizontally and <tt>yskip</tt> verticall y. jumping by <tt>xskip</tt> horizontally and <tt>yskip</tt> verticall y.
<tt>ystride</tt> must be the physical width (row length) of the ima ge. <tt>ystride</tt> must be the physical width (row length) of the ima ge.
*/ */
ConstStridedImageIterator(pointer base, int ystride, int xskip, int ysk ip) ConstStridedImageIterator(pointer base, std::ptrdiff_t ystride, std::pt rdiff_t xskip, std::ptrdiff_t yskip)
: Base(base, xskip, ystride*yskip) : Base(base, xskip, ystride*yskip)
{} {}
/** Copy-construct from mutable iterator */ /** Copy-construct from mutable iterator */
ConstStridedImageIterator(StridedImageIterator<PIXELTYPE> const & o) ConstStridedImageIterator(StridedImageIterator<PIXELTYPE> const & o)
: Base(o.x, o.y) : Base(o.x, o.y)
{} {}
/** Default constructor */ /** Default constructor */
ConstStridedImageIterator() ConstStridedImageIterator()
skipping to change at line 1228 skipping to change at line 1223
#undef VIGRA_DEFINE_ITERATORTRAITS #undef VIGRA_DEFINE_ITERATORTRAITS
#endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION #endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION
template <class PIXELTYPE> template <class PIXELTYPE>
class ConstValueIteratorPolicy class ConstValueIteratorPolicy
{ {
public: public:
typedef PIXELTYPE value_type; typedef PIXELTYPE value_type;
typedef int difference_type; typedef std::ptrdiff_t difference_type;
typedef PIXELTYPE const & reference; typedef PIXELTYPE const & reference;
typedef PIXELTYPE const & index_reference; typedef PIXELTYPE const & index_reference;
typedef PIXELTYPE const * pointer; typedef PIXELTYPE const * pointer;
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category;
struct BaseType struct BaseType
{ {
BaseType(PIXELTYPE const & v = PIXELTYPE(), int p = 0) BaseType(PIXELTYPE const & v = PIXELTYPE(), std::ptrdiff_t p = 0)
: value(v), pos(p) : value(v), pos(p)
{} {}
PIXELTYPE value; PIXELTYPE value;
int pos; std::ptrdiff_t pos;
}; };
static void initialize(BaseType & d) {} static void initialize(BaseType & /* d */) {}
static reference dereference(BaseType const & d) static reference dereference(BaseType const & d)
{ return d.value; } { return d.value; }
static index_reference dereference(BaseType d, difference_type) static index_reference dereference(BaseType d, difference_type)
{ {
return d.value; return d.value;
} }
static bool equal(BaseType const & d1, BaseType const & d2) static bool equal(BaseType const & d1, BaseType const & d2)
skipping to change at line 1285 skipping to change at line 1280
/* ConstValueIterator */ /* ConstValueIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Iterator that always returns the constant specified in the /** \brief Iterator that always returns the constant specified in the
constructor. constructor.
This iterator can be used to simulate an image that This iterator can be used to simulate an image that
does not actually exist. does not actually exist.
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class PIXELTYPE> template <class PIXELTYPE>
class ConstValueIterator class ConstValueIterator
{ {
public: public:
/** The type of the constant the iterator holds. /** The type of the constant the iterator holds.
*/ */
typedef PIXELTYPE value_type; typedef PIXELTYPE value_type;
skipping to change at line 1332 skipping to change at line 1326
/** The associated row iterator. /** The associated row iterator.
*/ */
typedef IteratorAdaptor<ConstValueIteratorPolicy<PIXELTYPE> > row_itera tor; typedef IteratorAdaptor<ConstValueIteratorPolicy<PIXELTYPE> > row_itera tor;
/** The associated column iterator. /** The associated column iterator.
*/ */
typedef IteratorAdaptor<ConstValueIteratorPolicy<PIXELTYPE> > column_it erator; typedef IteratorAdaptor<ConstValueIteratorPolicy<PIXELTYPE> > column_it erator;
/** Let operations act in X direction /** Let operations act in X direction
*/ */
typedef int MoveX; typedef std::ptrdiff_t MoveX;
/** Let operations act in Y direction /** Let operations act in Y direction
*/ */
typedef int MoveY; typedef std::ptrdiff_t MoveY;
/** Default Constructor. (the constant is set to /** Default Constructor. (the constant is set to
<TT>NumericTraits<PIXELTYPE>::zero()</TT> ) <TT>NumericTraits<PIXELTYPE>::zero()</TT> )
*/ */
ConstValueIterator() ConstValueIterator()
: value_(NumericTraits<PIXELTYPE>::zero()), x(0), y(0) : value_(NumericTraits<PIXELTYPE>::zero()), x(0), y(0)
{} {}
/** Construct with given constant. /** Construct with given constant.
*/ */
skipping to change at line 1443 skipping to change at line 1437
/** Call member function for stored constant. /** Call member function for stored constant.
*/ */
pointer operator->() const pointer operator->() const
{ {
return &value_; return &value_;
} }
/** Read pixel at a distance (return specified constant). /** Read pixel at a distance (return specified constant).
*/ */
index_reference operator()(int const &, int const &) const index_reference operator()(std::ptrdiff_t const &, std::ptrdiff_t const &) const
{ {
return value_; return value_;
} }
/** Read pixel at a distance (return specified constant). /** Read pixel at a distance (return specified constant).
*/ */
index_reference operator[](Diff2D const &) const index_reference operator[](Diff2D const &) const
{ {
return value_; return value_;
} }
skipping to change at line 1468 skipping to change at line 1462
{ return row_iterator(typename row_iterator::BaseType(value_, x)); } { return row_iterator(typename row_iterator::BaseType(value_, x)); }
/** Get column iterator at current position (which will also hold t he constant). /** Get column iterator at current position (which will also hold t he constant).
*/ */
column_iterator columnIterator() const column_iterator columnIterator() const
{ return column_iterator(typename column_iterator::BaseType(value_, y)); } { return column_iterator(typename column_iterator::BaseType(value_, y)); }
/** @name Specify coordinate direction for navigation commands */ /** @name Specify coordinate direction for navigation commands */
//@{ //@{
/// refer to x coordinate /// refer to x coordinate
int x; std::ptrdiff_t x;
/// refer to y coordinate /// refer to y coordinate
int y; std::ptrdiff_t y;
//@} //@}
private: private:
PixelType value_; PixelType value_;
}; };
#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
template <class T> template <class T>
skipping to change at line 1557 skipping to change at line 1551
vigra::inspectImageIf( vigra::inspectImageIf(
srcIterRange(Diff2D(), Diff2D() + img.size()), srcIterRange(Diff2D(), Diff2D() + img.size()),
srcImage(img), srcImage(img),
center); center);
std::cout << "Center of mass: " << center.xCenter() << std::cout << "Center of mass: " << center.xCenter() <<
", " << center.yCenter() << std::endl; ", " << center.yCenter() << std::endl;
\endcode \endcode
<b>\#include</b> \<vigra/imageiterator.hxx\> <b>\#include</b> \<vigra/imageiterator.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
typedef Diff2D CoordinateIterator; typedef Diff2D CoordinateIterator;
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_IMAGEITERATOR_HXX #endif // VIGRA_IMAGEITERATOR_HXX
 End of changes. 34 change blocks. 
43 lines changed or deleted 36 lines changed or added


 imageiteratoradapter.hxx   imageiteratoradapter.hxx 
skipping to change at line 70 skipping to change at line 70
one column of the image. If the underlying iterator is a const iterator , one column of the image. If the underlying iterator is a const iterator ,
the column iterator will also be const (i.e. doesn't allow to change the column iterator will also be const (i.e. doesn't allow to change
the values it points to). the values it points to).
The iterator gets associated with the accessor of the base iterator. The iterator gets associated with the accessor of the base iterator.
Note that image iterators usually have a member <TT>columnIterator()</T T> Note that image iterators usually have a member <TT>columnIterator()</T T>
which returns a column iterator optimized for that particular image cla ss. which returns a column iterator optimized for that particular image cla ss.
ColumnIterator is only necessary if this 'native' column iterator ColumnIterator is only necessary if this 'native' column iterator
is not usable in a particular situation or is not provided. is not usable in a particular situation or is not provided.
<b>\#include</b> \<vigra/imageiteratoradapter.hxx\> <b>\#include</b> \<vigra/imageiteratoradapter.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class IMAGE_ITERATOR> template <class IMAGE_ITERATOR>
class ColumnIterator : private IMAGE_ITERATOR class ColumnIterator : private IMAGE_ITERATOR
{ {
public: public:
/** the iterator's value type /** the iterator's value type
*/ */
typedef typename IMAGE_ITERATOR::value_type value_type; typedef typename IMAGE_ITERATOR::value_type value_type;
skipping to change at line 276 skipping to change at line 275
one row of the image. If the underlying iterator is a const iterator, one row of the image. If the underlying iterator is a const iterator,
the row iterator will also be const (i.e. doesn't allow to change the row iterator will also be const (i.e. doesn't allow to change
the values it points to). the values it points to).
The iterator gets associated with the accessor of the base iterator. The iterator gets associated with the accessor of the base iterator.
Note that image iterators usually have a member <TT>rowIterator()</TT> Note that image iterators usually have a member <TT>rowIterator()</TT>
which returns a row iterator optimized for that particular image class. which returns a row iterator optimized for that particular image class.
RowIterator is only necessary if this 'native' row iterator RowIterator is only necessary if this 'native' row iterator
is not usable in a particular situation or is not provided. is not usable in a particular situation or is not provided.
<b>\#include</b> \<vigra/imageiteratoradapter.hxx\> <b>\#include</b> \<vigra/imageiteratoradapter.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class IMAGE_ITERATOR> template <class IMAGE_ITERATOR>
class RowIterator : private IMAGE_ITERATOR class RowIterator : private IMAGE_ITERATOR
{ {
public: public:
/** the iterator's value type /** the iterator's value type
*/ */
typedef typename IMAGE_ITERATOR::value_type value_type; typedef typename IMAGE_ITERATOR::value_type value_type;
skipping to change at line 475 skipping to change at line 473
/********************************************************/ /********************************************************/
/** \brief Iterator adapter to iterate along an arbitrary line on the image . /** \brief Iterator adapter to iterate along an arbitrary line on the image .
This iterator may be initialized from a standard ImageIterator, This iterator may be initialized from a standard ImageIterator,
a MultibandImageIterator and so on. a MultibandImageIterator and so on.
It gives you STL-compatible (forward iterator) access to It gives you STL-compatible (forward iterator) access to
an arbitrary line on the image. an arbitrary line on the image.
The iterator gets associated with the accessor of the base iterator. The iterator gets associated with the accessor of the base iterator.
<b>\#include</b> \<vigra/imageiteratoradapter.hxx\> <b>\#include</b> \<vigra/imageiteratoradapter.hxx\> <br/>
Namespace: vigra Namespace: vigra
*/ */
template <class IMAGE_ITERATOR> template <class IMAGE_ITERATOR>
class LineIterator : private IMAGE_ITERATOR class LineIterator : private IMAGE_ITERATOR
{ {
public: public:
/** the iterator's value type /** the iterator's value type
*/ */
typedef typename IMAGE_ITERATOR::value_type value_type; typedef typename IMAGE_ITERATOR::value_type value_type;
 End of changes. 3 change blocks. 
6 lines changed or deleted 3 lines changed or added


 impex.hxx   impex.hxx 
skipping to change at line 37 skipping to change at line 37
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
/*! /**
* \file impex.hxx * \file impex.hxx
* \brief image import and export functions * \brief image import and export functions
* *
* This module implements functions importImage() and exportImage(). * This module implements functions importImage() and exportImage().
* The matching implementation for any given datatype is selected by * The matching implementation for any given datatype is selected by
* template meta code. * template meta code.
* *
*/ */
#ifndef VIGRA_IMPEX_HXX #ifndef VIGRA_IMPEX_HXX
#define VIGRA_IMPEX_HXX #define VIGRA_IMPEX_HXX
#include "stdimage.hxx" #include "stdimage.hxx"
#include "imageinfo.hxx" #include "imageinfo.hxx"
#include "impexbase.hxx" #include "impexbase.hxx"
#include "multi_shape.hxx"
namespace vigra namespace vigra
{ {
/** \addtogroup VigraImpex /** \addtogroup VigraImpex
* @{ * @{
*/ */
namespace detail namespace detail
{ {
template <class ValueType, template <class ValueType,
class ImageIterator, class ImageAccessor> class ImageIterator, class ImageAccessor>
skipping to change at line 103 skipping to change at line 104
template <class ValueType, template <class ValueType,
class ImageIterator, class ImageAccessor> class ImageIterator, class ImageAccessor>
void void
read_image_bands(Decoder* decoder, read_image_bands(Decoder* decoder,
ImageIterator image_iterator, ImageAccessor image_ accessor) ImageIterator image_iterator, ImageAccessor image_ accessor)
{ {
typedef typename ImageIterator::row_iterator ImageRowIterator; typedef typename ImageIterator::row_iterator ImageRowIterator;
const unsigned width(decoder->getWidth()); const unsigned width(decoder->getWidth());
const unsigned height(decoder->getHeight()); const unsigned height(decoder->getHeight());
const unsigned bands(decoder->getNumBands());
const unsigned offset(decoder->getOffset()); const unsigned offset(decoder->getOffset());
const unsigned accessor_size(image_accessor.size(image_iterator )); const unsigned accessor_size(image_accessor.size(image_iterator ));
// OPTIMIZATION: Specialization for the most common case // OPTIMIZATION: Specialization for the most common case
// of an RGB-image, i.e. 3 channels. // of an RGB-image, i.e. 3 channels.
if (accessor_size == 3U) if (accessor_size == 3U)
{ {
const ValueType* scanline_0; const ValueType* scanline_0;
const ValueType* scanline_1; const ValueType* scanline_1;
const ValueType* scanline_2; const ValueType* scanline_2;
for (unsigned y = 0U; y != height; ++y) for (unsigned y = 0U; y != height; ++y)
{ {
decoder->nextScanline(); decoder->nextScanline();
scanline_0 = static_cast<const ValueType*>(decoder->cur rentScanlineOfBand(0)); scanline_0 = static_cast<const ValueType*>(decoder->cur rentScanlineOfBand(0));
scanline_1 = static_cast<const ValueType*>(decoder->cur
rentScanlineOfBand(1)); if(bands == 1)
scanline_2 = static_cast<const ValueType*>(decoder->cur {
rentScanlineOfBand(2)); scanline_1 = scanline_0;
scanline_2 = scanline_0;
}
else
{
scanline_1 = static_cast<const ValueType*>(decoder-
>currentScanlineOfBand(1));
scanline_2 = static_cast<const ValueType*>(decoder-
>currentScanlineOfBand(2));
}
ImageRowIterator is(image_iterator.rowIterator()); ImageRowIterator is(image_iterator.rowIterator());
const ImageRowIterator is_end(is + width); const ImageRowIterator is_end(is + width);
while (is != is_end) while (is != is_end)
{ {
image_accessor.setComponent(*scanline_0, is, 0); image_accessor.setComponent(*scanline_0, is, 0);
image_accessor.setComponent(*scanline_1, is, 1); image_accessor.setComponent(*scanline_1, is, 1);
image_accessor.setComponent(*scanline_2, is, 2); image_accessor.setComponent(*scanline_2, is, 2);
skipping to change at line 149 skipping to change at line 160
} }
} }
else else
{ {
std::vector<const ValueType*> scanlines(accessor_size); std::vector<const ValueType*> scanlines(accessor_size);
for (unsigned y = 0U; y != height; ++y) for (unsigned y = 0U; y != height; ++y)
{ {
decoder->nextScanline(); decoder->nextScanline();
for (unsigned i = 0U; i != accessor_size; ++i) scanlines[0] = static_cast<const ValueType*>(decoder->c
urrentScanlineOfBand(0));
if(bands == 1)
{ {
scanlines[i] = static_cast<const ValueType*>(decode for (unsigned i = 1U; i != accessor_size; ++i)
r->currentScanlineOfBand(i)); {
scanlines[i] = scanlines[0];
}
}
else
{
for (unsigned i = 1U; i != accessor_size; ++i)
{
scanlines[i] = static_cast<const ValueType*>(de
coder->currentScanlineOfBand(i));
}
} }
ImageRowIterator is(image_iterator.rowIterator()); ImageRowIterator is(image_iterator.rowIterator());
const ImageRowIterator is_end(is + width); const ImageRowIterator is_end(is + width);
while (is != is_end) while (is != is_end)
{ {
for (unsigned i = 0U; i != accessor_size; ++i) for (unsigned i = 0U; i != accessor_size; ++i)
{ {
image_accessor.setComponent(*scanlines[i], is, static_cast<int>(i)); image_accessor.setComponent(*scanlines[i], is, static_cast<int>(i));
skipping to change at line 216 skipping to change at line 239
decoder->close(); decoder->close();
} }
template <class ImageIterator, class ImageAccessor> template <class ImageIterator, class ImageAccessor>
void void
importImage(const ImageImportInfo& import_info, importImage(const ImageImportInfo& import_info,
ImageIterator image_iterator, ImageAccessor image_acces sor, ImageIterator image_iterator, ImageAccessor image_acces sor,
/* isScalar? */ VigraFalseType) /* isScalar? */ VigraFalseType)
{ {
vigra_precondition((static_cast<unsigned int>(import_info.numBa
nds())
== image_accessor.size(image_iterator)) ||
import_info.numBands() == 1,
"importImage(): Number of channels in input and destination
image don't match.");
VIGRA_UNIQUE_PTR<Decoder> decoder(vigra::decoder(import_info)); VIGRA_UNIQUE_PTR<Decoder> decoder(vigra::decoder(import_info));
switch (pixel_t_of_string(decoder->getPixelType())) switch (pixel_t_of_string(decoder->getPixelType()))
{ {
case UNSIGNED_INT_8: case UNSIGNED_INT_8:
read_image_bands<UInt8>(decoder.get(), image_iterator, imag e_accessor); read_image_bands<UInt8>(decoder.get(), image_iterator, imag e_accessor);
break; break;
case UNSIGNED_INT_16: case UNSIGNED_INT_16:
read_image_bands<UInt16>(decoder.get(), image_iterator, ima ge_accessor); read_image_bands<UInt16>(decoder.get(), image_iterator, ima ge_accessor);
break; break;
skipping to change at line 256 skipping to change at line 284
} }
template<class ValueType, template<class ValueType,
class ImageIterator, class ImageAccessor, class ImageScale r> class ImageIterator, class ImageAccessor, class ImageScale r>
void void
write_image_band(Encoder* encoder, write_image_band(Encoder* encoder,
ImageIterator image_upper_left, ImageIterator imag e_lower_right, ImageAccessor image_accessor, ImageIterator image_upper_left, ImageIterator imag e_lower_right, ImageAccessor image_accessor,
const ImageScaler& image_scaler) const ImageScaler& image_scaler)
{ {
typedef typename ImageIterator::row_iterator ImageRowIterator; typedef typename ImageIterator::row_iterator ImageRowIterator;
typedef typename ImageAccessor::value_type ImageValueType;
typedef RequiresExplicitCast<ValueType> explicit_cast; typedef RequiresExplicitCast<ValueType> explicit_cast;
vigra_precondition(image_lower_right.x >= image_upper_left.x, vigra_precondition(image_lower_right.x >= image_upper_left.x,
"vigra::detail::write_image_band: negative w idth"); "vigra::detail::write_image_band: negative w idth");
vigra_precondition(image_lower_right.y >= image_upper_left.y, vigra_precondition(image_lower_right.y >= image_upper_left.y,
"vigra::detail::write_image_band: negative h eight"); "vigra::detail::write_image_band: negative h eight");
const unsigned width(static_cast<unsigned>(image_lower_right.x - image_upper_left.x)); const unsigned width(static_cast<unsigned>(image_lower_right.x - image_upper_left.x));
const unsigned height(static_cast<unsigned>(image_lower_right.y - image_upper_left.y)); const unsigned height(static_cast<unsigned>(image_lower_right.y - image_upper_left.y));
skipping to change at line 600 skipping to change at line 627
break; break;
default: default:
vigra_fail("vigra::detail::exportImage<non-scalar>: not reached"); vigra_fail("vigra::detail::exportImage<non-scalar>: not reached");
} }
} }
encoder->close(); encoder->close();
} }
} // end namespace detail } // end namespace detail
/*! /**
* \brief Read the image specified by the given \ref \brief Read an image from a file.
* vigra::ImageImportInfo object.
* If the first parameter is \ref vigra::ImageImportInfo, this function as
* <B>Declarations</B> sumes that the destination
* image has already the appropriate shape. If the first parameter is a st
* Pass arguments explicitly: ring, the destination
* \code must be a \ref vigra::MultiArray reference, which will be reshaped auto
* namespace vigra { matically.
* template <class ImageIterator, class Accessor>
* void If the input image has only a single band, but the destination has mult
* importImage(const ImageImportInfo& importInfo, iple bands (e.g. is an RGB
* ImageIterator imageIterator, Accessor imageAccessor) image), all bands will receive the same data. When a multi-band file is
* } read into a single-band
* \endcode destination array, only the first band is read. Any other mismatch betw
* een the number of bands in
* Use argument objects in conjunction with \ref ArgumentObjectFactorie input and output is an error and will throw a precondition exception.
s :
* \code <B>Declarations</B>
* namespace vigra {
* template <class ImageIterator, class Accessor> pass 2D array views:
* inline void \code
* importImage(const ImageImportInfo& importInfo, namespace vigra {
* const pair<ImageIterator, Accessor>& image) // read the data into an array view of appropriate size
* } template <class T, class S>
* \endcode void
* importImage(ImageImportInfo const & import_info,
* <B>Usage</B> MultiArrayView<2, T, S> image);
*
* <B>\#include \<vigra/impex.hxx\></B> // resize the given array and then read the data
* template <class T, class A>
* Namespace: vigra void
* importImage(char const * filename,
* \code MultiArray<2, T, A> & image);
* ImageImportInfo info("myimage.gif");
* template <class T, class A>
* if (info.isGrayscale()) void
* { importImage(std::string const & filename,
* // create byte image of appropriate size MultiArray<2, T, A> & image);
* BImage image(info.width(), info.height()); }
* \endcode
* importImage(info, destImage(image));
* ... \deprecatedAPI{importImage}
* } pass \ref ImageIterators and \ref DataAccessors :
* else \code
* { namespace vigra {
* // create byte RGB image of appropriate size template <class ImageIterator, class Accessor>
* BRGBImage image(info.width(), info.height()); void
* importImage(const ImageImportInfo& importInfo,
* importImage(info, destImage(image)); ImageIterator imageIterator, Accessor imageAccessor)
* ... }
* } \endcode
* \endcode Use argument objects in conjunction with \ref ArgumentObjectFactories :
* \code
* <B>Preconditions</B> namespace vigra {
* template <class ImageIterator, class Accessor>
* - The image file must be readable and void
* - the file type must be one of the following: importImage(const ImageImportInfo& importInfo,
* const pair<ImageIterator, Accessor>& image)
* | Type | Extension | Name }
| Support Library | \endcode
* |------|-----------|------------------------------------------------ \deprecatedEnd
------------|-----------------|
* | BMP | bmp | Microsoft Windows bitmap image file <b> Usage:</b>
| |
* | EXR | exr | OpenEXR high dynamic range image format <B>\#include</B> \<vigra/impex.hxx\><br/>
| libopenexr | Namespace: vigra
* | GIF | gif | CompuServe graphics interchange format, 8-bit c
olor | | \code
* | HDR | hdr | Radiance RGBE high dynamic range image format ImageImportInfo info("myimage.gif");
| libexr? |
* | JPEG | jpg, jpeg | Joint Photographic Experts Group JFIF format, 2 if (info.isGrayscale())
4-bit color | libjpeg | {
* | PBM | pbm | Portable bitmap format (black and white) // create byte image of appropriate size
| | MultiArray<2, unsigned char> image(info.width(), info.height());
* | PGM | pgm | Portable graymap format (gray scale)
| | importImage(info, image);
* | PNG | png | Portable Network Graphic ...
| libpng | }
* | PNM | pnm | Portable anymap else
| | {
* | PPM | ppm | Portable pixmap format (color) // create byte RGB image of appropriate size
| | MultiArray<2, RGBValue<unsigned char> > image(info.width(), info.he
* | SUN | ras | SUN Rasterfile ight());
| |
* | TIFF | tif, tiff | Tagged Image File Format importImage(info, image);
| libtiff | ...
* | VIFF | xv | Khoros Visualization image file }
| | \endcode
*/ When the type of input image is already known, this can be shortened:
doxygen_overloaded_function(template <...> inline void importImage) \code
// create empty float image
MultiArray<2, float> image;
// resize image and read the data
importImage("myimage.png", image);
\endcode
\deprecatedUsage{importImage}
\code
ImageImportInfo info("myimage.gif");
if (info.isGrayscale())
{
// create byte image of appropriate size
BImage image(info.width(), info.height());
importImage(info, destImage(image));
...
}
else
{
// create byte RGB image of appropriate size
BRGBImage image(info.width(), info.height());
importImage(info, destImage(image));
...
}
\endcode
\deprecatedEnd
<B>Preconditions</B>
- The image file must be readable.
- The required support library must be installed (if the table doesn't
specify an external library,
VIGRA supports the format natively).
- The file type must be one of the following:
<table cellspacing="10">
<tr align="left">
<th>Type</th><th> Extension </th><th> Name </
th><th> Support Library </th>
</tr><tr>
<td> BMP </td><td> bmp </td><td> Microsoft Windows bitmap ima
ge file </td><td> </td>
</tr><tr>
<td> EXR </td><td> exr </td><td> OpenEXR high dynamic range i
mage format </td><td> libopenexr </td>
</tr><tr>
<td> GIF </td><td> gif </td><td> CompuServe graphics intercha
nge format, 8-bit color </td><td> </td>
</tr><tr>
<td> HDR </td><td> hdr </td><td> Radiance RGBE high dynamic r
ange image format </td><td> </td>
</tr><tr>
<td> JPEG </td><td> jpg, jpeg </td><td> Joint Photographic Experts G
roup JFIF format, 24-bit color </td><td> libjpeg </td>
</tr><tr>
<td> PBM </td><td> pbm </td><td> Portable bitmap format (blac
k and white) </td><td> </td>
</tr><tr>
<td> PGM </td><td> pgm </td><td> Portable graymap format (gra
y scale) </td><td> </td>
</tr><tr>
<td> PNG </td><td> png </td><td> Portable Network Graphic
</td><td> libpng </td>
</tr><tr>
<td> PNM </td><td> pnm </td><td> Portable anymap
</td><td> </td>
</tr><tr>
<td> PPM </td><td> ppm </td><td> Portable pixmap format (colo
r) </td><td> </td>
</tr><tr>
<td> SUN </td><td> ras </td><td> SUN Rasterfile
</td><td> </td>
</tr><tr>
<td> TIFF </td><td> tif, tiff </td><td> Tagged Image File Format
</td><td> libtiff </td>
</tr><tr>
<td> VIFF </td><td> xv </td><td> Khoros Visualization image f
ile </td><td> </td>
</table>
*/
doxygen_overloaded_function(template <...> void importImage)
template <class ImageIterator, class ImageAccessor> template <class ImageIterator, class ImageAccessor>
inline void inline void
importImage(const ImageImportInfo& import_info, importImage(const ImageImportInfo& import_info,
ImageIterator image_iterator, ImageAccessor image_accessor) ImageIterator image_iterator, ImageAccessor image_accessor)
{ {
typedef typename ImageAccessor::value_type ImageValueType; typedef typename ImageAccessor::value_type ImageValueType;
typedef typename NumericTraits<ImageValueType>::isScalar is_scalar; typedef typename NumericTraits<ImageValueType>::isScalar is_scalar;
detail::importImage(import_info, detail::importImage(import_info,
image_iterator, image_accessor, image_iterator, image_accessor,
is_scalar()); is_scalar());
} }
template <class ImageIterator, class ImageAccessor> template <class ImageIterator, class ImageAccessor>
inline void inline void
importImage(const ImageImportInfo& import_info, importImage(ImageImportInfo const & import_info,
const vigra::pair<ImageIterator, ImageAccessor>& image) pair<ImageIterator, ImageAccessor> image)
{ {
importImage(import_info, importImage(import_info,
image.first, image.second); image.first, image.second);
} }
/*! template <class T, class S>
* \brief Write an image given a \ref vigra::ImageExportInfo object. inline void
* importImage(ImageImportInfo const & import_info,
* If the file format to be exported to supports the pixel type of MultiArrayView<2, T, S> image)
* the source image, the pixel type will be kept {
* (e.g. <tt>float</tt> can be stored as TIFF without conversion, vigra_precondition(import_info.shape() == image.shape(),
* in contrast to most other image export toolkits). Otherwise, "importImage(): shape mismatch between input and output.");
* the pixel values are transformed to the range 0..255 and importImage(import_info, destImage(image));
* converted to <tt>unsigned char</tt>. Currently, the following }
* file formats are supported. The pixel types given in brackets
* are those that are written without conversion: template <class T, class A>
* - BMP: Microsoft Windows bitmap image file (pixel types: UINT8 a inline void
s gray and RGB); importImage(char const * name,
* - GIF: CompuServe graphics interchange format, 8-bit color (pixe MultiArray<2, T, A> & image)
l types: UINT8 as gray and RGB); {
* - JPEG: Joint Photographic Experts Group JFIF format, compressed ImageImportInfo info(name);
24-bit color image.reshape(info.shape());
* (pixel types: UINT8 as gray and RGB), only available if importImage(info, destImage(image));
libjpeg is installed; }
* - PNG: Portable Network Graphic (pixel types: UINT8 and UINT16 w
ith up to 4 channels), template <class T, class A>
* only available if libpng is installed; inline void
* - PBM: Portable bitmap format (black and white); importImage(std::string const & name,
* - PGM: Portable graymap format (pixel types: UINT8, INT16, INT32 MultiArray<2, T, A> & image)
as gray scale); {
* - PNM: Portable anymap (pixel types: UINT8, INT16, INT32 as gray importImage(name.c_str(), image);
and RGB); }
* - PPM: Portable pixmap format (pixel types: UINT8, INT16, INT32
as RGB); /** \brief Write an image to a file.
* - SUN: SUN Rasterfile (pixel types: UINT8 as gray and RGB);
* - TIFF: Tagged Image File Format The file can be specified either by a file name or by a \ref vigra::Ima
* (pixel types: UINT8, INT16, INT32, FLOAT, DOUBLE with up t geExportInfo object.
o 4 channels), In the latter case, you have much more control about how the file is wr
* only available if libtiff is installed; itten. By default,
* - VIFF: Khoros Visualization image file the file format to be created is guessed from the filename extension. T
* (pixel types: UINT8, INT16, INT32, FLOAT, DOUBLE with arbi his can be
trary many channels); overridden by an explicit file type in the ImageExportInfo object. If t
* he file format
* <B>Declarations</B> supports compression (e.g. JPEG and TIFF), default compression paramete
* rs are used
* Pass arguments explicitly: which can be overridden by the ImageExportInfo object.
* \code
* namespace vigra { If the file format to be created supports the pixel type of the source
* template <class ImageIterator, class ImageAccessor> image, this
* void pixel type will be kept in the file (e.g. <tt>float</tt> can be stored
* exportImage(ImageIterator imageUpperLeft, ImageIterator imageLow by TIFF without
erRight, ImageAccessor imageAccessor, conversion) unless the ImageExportInfo object
* const ImageExportInfo& exportInfo) explicitly requests a different storage type. If the array's pixel type
* } is not supported by
* \endcode the file format, the pixel values are transformed to the range 0..255 a
* nd
* Use argument objects in conjunction with \ref ArgumentObjectFactorie converted to <tt>unsigned char</tt>, unless another mapping is explicit
s : ly requested by
* \code the ImageExportInfo object.
* namespace vigra {
* template <class ImageIterator, class ImageAccessor> Currently, the following file formats are supported. The pixel types g
* void exportImage(ImageIterator imageUpperLeft, ImageIterator iven in brackets
imageLowerRight, ImageAccessor imageAccessor, are those that are written without conversion:
* const ImageExportInfo& exportInfo) - BMP: Microsoft Windows bitmap image file (pixel types: UINT8 as g
* } ray and RGB);
* \endcode - GIF: CompuServe graphics interchange format, 8-bit color (pixel t
* ypes: UINT8 as gray and RGB);
* <B>Usage</B> - JPEG: Joint Photographic Experts Group JFIF format, compressed 24
* -bit color
* <B>\#include \<vigra/impex.hxx\></B> (pixel types: UINT8 as gray and RGB), only available if lib
* jpeg is installed;
* Namespace: vigra - PNG: Portable Network Graphic (pixel types: UINT8 and UINT16 with
* \code up to 4 channels),
* BRGBImage image(width, height); only available if libpng is installed;
* ... - PBM: Portable bitmap format (black and white);
* - PGM: Portable graymap format (pixel types: UINT8, INT16, INT32 as
* // write as JPEG image, using compression quality 80 gray scale);
* exportImage(srcImageRange(image), - PNM: Portable anymap (pixel types: UINT8, INT16, INT32 as gray an
* ImageExportInfo("my-image.jpg").setCompression("80") d RGB);
); - PPM: Portable pixmap format (pixel types: UINT8, INT16, INT32 as
* RGB);
* // Force it to a particular pixel type. The pixel type must be - SUN: SUN Rasterfile (pixel types: UINT8 as gray and RGB);
supported by the - TIFF: Tagged Image File Format
* // desired image file format, otherwise an \ref vigra::Precondit (pixel types: UINT8, INT16, INT32, FLOAT, DOUBLE with up to 4
ionViolation channels),
* // exception will be thrown. only available if libtiff is installed;
* exportImage(srcImageRange(image), - VIFF: Khoros Visualization image file
* ImageExportInfo("my-INT16-image.tif").setPixelType(" (pixel types: UINT8, INT16, INT32, FLOAT, DOUBLE with arbitra
INT16")); ry many channels);
* \endcode
* <B>Declarations</B>
* <B>Preconditions</B>
* pass 2D array views:
* - The image file must be writable and \code
* - the file type must be one of the supported file types. namespace vigra {
*/ template <class T, class S>
doxygen_overloaded_function(template <...> inline void exportImage) void
exportImage(MultiArrayView<2, T, S> const & image,
ImageExportInfo const & export_info);
template <class T, class S>
void
exportImage(MultiArrayView<2, T, S> const & image,
char const * filename);
template <class T, class S>
void
exportImage(MultiArrayView<2, T, S> const & image,
std::string const & filename);
}
\endcode
\deprecatedAPI{exportImage}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class ImageIterator, class ImageAccessor>
void
exportImage(ImageIterator imageUpperLeft, ImageIterator imageLowerR
ight, ImageAccessor imageAccessor,
const ImageExportInfo& exportInfo)
}
\endcode
Use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class ImageIterator, class ImageAccessor>
void exportImage(ImageIterator imageUpperLeft, ImageIterator im
ageLowerRight, ImageAccessor imageAccessor,
const ImageExportInfo& exportInfo)
}
\endcode
\deprecatedEnd
<b> Usage:</b>
<B>\#include</B> \<vigra/impex.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, RGBValue<unsigned char> > image(width, height);
...
// write as JPEG image, using compression quality 80
exportImage(image,
ImageExportInfo("my-image.jpg").setCompression("80"));
// Force it to a particular pixel type. The pixel type must be support
ed by the
// desired image file format, otherwise an \ref vigra::PreconditionViol
ation
// exception will be thrown.
exportImage(image,
ImageExportInfo("my-INT16-image.tif").setPixelType("INT16")
);
\endcode
\deprecatedUsage{exportImage}
\code
BRGBImage image(width, height);
...
// write as JPEG image, using compression quality 80
exportImage(srcImageRange(image),
ImageExportInfo("my-image.jpg").setCompression("80"));
// Force it to a particular pixel type. The pixel type must be support
ed by the
// desired image file format, otherwise an \ref vigra::PreconditionViol
ation
// exception will be thrown.
exportImage(srcImageRange(image),
ImageExportInfo("my-INT16-image.tif").setPixelType("INT16")
);
\endcode
\deprecatedEnd
<B>Preconditions</B>
- The image file must be writable and
- the file type must be one of the supported file types.
*/
doxygen_overloaded_function(template <...> void exportImage)
template <class ImageIterator, class ImageAccessor> template <class ImageIterator, class ImageAccessor>
inline void inline void
exportImage(ImageIterator image_upper_left, ImageIterator image_lower_r ight, ImageAccessor image_accessor, exportImage(ImageIterator image_upper_left, ImageIterator image_lower_r ight, ImageAccessor image_accessor,
const ImageExportInfo& export_info) const ImageExportInfo& export_info)
{ {
typedef typename ImageAccessor::value_type ImageValueType; typedef typename ImageAccessor::value_type ImageValueType;
typedef typename NumericTraits<ImageValueType>::isScalar is_scalar; typedef typename NumericTraits<ImageValueType>::isScalar is_scalar;
try try
skipping to change at line 801 skipping to change at line 980
info.setCompression(""); info.setCompression("");
detail::exportImage(image_upper_left, image_lower_right, image_ accessor, detail::exportImage(image_upper_left, image_lower_right, image_ accessor,
info, info,
is_scalar()); is_scalar());
} }
} }
template <class ImageIterator, class ImageAccessor> template <class ImageIterator, class ImageAccessor>
inline void inline void
exportImage(const vigra::triple<ImageIterator, ImageIterator, ImageAcce exportImage(triple<ImageIterator, ImageIterator, ImageAccessor> image,
ssor>& image, ImageExportInfo const & export_info)
const ImageExportInfo& export_info)
{ {
exportImage(image.first, image.second, image.third, exportImage(image.first, image.second, image.third,
export_info); export_info);
} }
template <class T, class S>
inline void
exportImage(MultiArrayView<2, T, S> const & image,
ImageExportInfo const & export_info)
{
exportImage(srcImageRange(image), export_info);
}
template <class T, class S>
inline void
exportImage(MultiArrayView<2, T, S> const & image,
char const * name)
{
ImageExportInfo export_info(name);
exportImage(srcImageRange(image), export_info);
}
template <class T, class S>
inline void
exportImage(MultiArrayView<2, T, S> const & image,
std::string const & name)
{
ImageExportInfo export_info(name.c_str());
exportImage(srcImageRange(image), export_info);
}
/** @} */ /** @} */
} // end namespace vigra } // end namespace vigra
#endif // VIGRA_IMPEX_HXX #endif // VIGRA_IMPEX_HXX
 End of changes. 13 change blocks. 
197 lines changed or deleted 422 lines changed or added


 impexalpha.hxx   impexalpha.hxx 
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_IMPEXALPHA_HXX #ifndef VIGRA_IMPEXALPHA_HXX
#define VIGRA_IMPEXALPHA_HXX #define VIGRA_IMPEXALPHA_HXX
#include <vector> #include <vector>
#include "imageinfo.hxx" #include "imageinfo.hxx"
#include "impex.hxx" #include "impex.hxx"
#include "impexbase.hxx" #include "impexbase.hxx"
#include "multi_shape.hxx"
namespace vigra namespace vigra
{ {
/** \addtogroup VigraImpex /** \addtogroup VigraImpex
* @{ * @{
*/ */
namespace detail namespace detail
{ {
template <class ValueType, template <class ValueType,
class ImageIterator, class ImageAccessor, class ImageIterator, class ImageAccessor,
skipping to change at line 308 skipping to change at line 309
alpha_iterator, alpha_ac cessor); alpha_iterator, alpha_ac cessor);
break; break;
default: default:
vigra_fail("vigra::detail::importImageAlpha<non-scalar>: no t reached"); vigra_fail("vigra::detail::importImageAlpha<non-scalar>: no t reached");
} }
decoder->close(); decoder->close();
} }
} // end namespace detail } // end namespace detail
/*! /**
* \brief Read the image specified by the given \ref
* vigra::ImageImportInfo object including its alpha channel. \brief Read the image specified by the given \ref
* vigra::ImageImportInfo object including its alpha channel.
* <B>Declarations</B>
* See \ref importImage() for more information.
* Pass arguments explicitly:
* \code <B>Declarations</B>
* namespace vigra {
* template <class ImageIterator, class ImageAccessor, pass 2D array views:
* class AlphaIterator, class AlphaAccessor> \code
* void namespace vigra {
* importImageAlpha(const ImageImportInfo& importInfo, template <class T1, class S1,
* ImageIterator imageIterator, ImageAccessor class T2, class S2>
imageAccessor, void
* AlphaIterator alphaIterator, AlphaAccessor importImageAlpha(ImageImportInfo const & import_info,
alphaAccessor) MultiArrayView<2, T1, S1> image,
* } MultiArrayView<2, T2, S2> alpha);
* \endcode }
* \endcode
* Use argument objects in conjunction with \ref ArgumentObjectFactorie
s : \deprecatedAPI{importImageAlpha}
* \code pass \ref ImageIterators and \ref DataAccessors :
* namespace vigra { \code
* template <class ImageIterator, class ImageAccessor, namespace vigra {
* class AlphaIterator, class AlphaAccessor> template <class ImageIterator, class ImageAccessor,
* void class AlphaIterator, class AlphaAccessor>
* importImageAlpha(const ImageImportInfo& importInfo, void
* const pair<ImageIterator, ImageAccessor>& i importImageAlpha(const ImageImportInfo& importInfo,
mage, ImageIterator imageIterator, ImageAccessor ima
* const pair<AlphaIterator, AlphaAccessor>& a geAccessor,
lpha) AlphaIterator alphaIterator, AlphaAccessor alp
* } haAccessor)
* \endcode }
* \endcode
* <B>Usage</B> Use argument objects in conjunction with \ref ArgumentObjectFactories :
* \code
* <B>\#include \<vigra/impexalpha.hxx\></B> namespace vigra {
* template <class ImageIterator, class ImageAccessor,
* Namespace: vigra class AlphaIterator, class AlphaAccessor>
* \code void
* typedef UInt8 value_t; importImageAlpha(const ImageImportInfo& importInfo,
* ImageImportInfo info("zorro.tif"); const pair<ImageIterator, ImageAccessor>& imag
* e,
* if (info.isGrayscale()) const pair<AlphaIterator, AlphaAccessor>& alph
* { a)
* BasicImage<value_t> alpha(info.size()); }
* BasicImage<value_t> image(info.size()); \endcode
* \deprecatedEnd
* importImageAlpha(info,
* image.upperLeft(), image.accessor(), <b> Usage:</b>
* alpha.upperLeft(), alpha.accessor());
* ... <B>\#include</B> \<vigra/impexalpha.hxx\><br/>
* } Namespace: vigra
* else
* { \code
* BasicImage<value_t> alpha(info.size()); typedef UInt8 value_t;
* BasicImage<vigra::RGBValue<value_t> > image(info.size()); ImageImportInfo info("zorro.tif");
*
* importImageAlpha(info, if (info.isGrayscale())
* image.upperLeft(), image.accessor(), {
* alpha.upperLeft(), alpha.accessor()); MultiArray<2, value_t> alpha(info.shape());
* ... MultiArray<2, value_t> image(info.shape());
* }
* \endcode importImageAlpha(info, image, alpha);
* ...
* <B>Preconditions</B> }
* else
* - The same preconditions hold as for importImage(), however the {
* only image formats that support alpha channels are MultiArray<2, value_t> alpha(info.shape());
* + TIFF and MultiArray<2, RGBValue<value_t> > image(info.shape());
* + PNG.
* In particular, JPEG does <B>not</B> support alpha channels. importImageAlpha(info, image, alpha);
* - The alpha channel always is scalar-valued, i.e. comprises a ...
* single band. }
*/ \endcode
doxygen_overloaded_function(template <...> inline void importImageAlpha
) \deprecatedUsage{importImageAlpha}
\code
typedef UInt8 value_t;
ImageImportInfo info("zorro.tif");
if (info.isGrayscale())
{
BasicImage<value_t> alpha(info.size());
BasicImage<value_t> image(info.size());
importImageAlpha(info,
image.upperLeft(), image.accessor(),
alpha.upperLeft(), alpha.accessor());
...
}
else
{
BasicImage<value_t> alpha(info.size());
BasicImage<vigra::RGBValue<value_t> > image(info.size());
importImageAlpha(info,
image.upperLeft(), image.accessor(),
alpha.upperLeft(), alpha.accessor());
...
}
\endcode
\deprecatedEnd
<B>Preconditions</B>
- The same preconditions hold as for importImage(), however the
only image formats that support alpha channels are
+ TIFF and
+ PNG.
In particular, JPEG does <B>not</B> support alpha channels.
- The alpha channel always is scalar-valued, i.e. comprises a
single band.
*/
doxygen_overloaded_function(template <...> void importImageAlpha)
template <class ImageIterator, class ImageAccessor, template <class ImageIterator, class ImageAccessor,
class AlphaIterator, class AlphaAccessor> class AlphaIterator, class AlphaAccessor>
inline void inline void
importImageAlpha(const ImageImportInfo& import_info, importImageAlpha(const ImageImportInfo& import_info,
ImageIterator image_iterator, ImageAccessor image_acce ssor, ImageIterator image_iterator, ImageAccessor image_acce ssor,
AlphaIterator alpha_iterator, AlphaAccessor alpha_acce ssor) AlphaIterator alpha_iterator, AlphaAccessor alpha_acce ssor)
{ {
typedef typename ImageAccessor::value_type ImageValueType; typedef typename ImageAccessor::value_type ImageValueType;
typedef typename vigra::NumericTraits<ImageValueType>::isScalar is_ scalar; typedef typename vigra::NumericTraits<ImageValueType>::isScalar is_ scalar;
detail::importImageAlpha(import_info, detail::importImageAlpha(import_info,
image_iterator, image_accessor, image_iterator, image_accessor,
alpha_iterator, alpha_accessor, alpha_iterator, alpha_accessor,
is_scalar()); is_scalar());
} }
template <class ImageIterator, class ImageAccessor, template <class ImageIterator, class ImageAccessor,
class AlphaIterator, class AlphaAccessor> class AlphaIterator, class AlphaAccessor>
inline void inline void
importImageAlpha(const ImageImportInfo& import_info, importImageAlpha(ImageImportInfo const & import_info,
const vigra::pair<ImageIterator, ImageAccessor>& image pair<ImageIterator, ImageAccessor> image,
, pair<AlphaIterator, AlphaAccessor> alpha)
const vigra::pair<AlphaIterator, AlphaAccessor>& alpha
)
{ {
importImageAlpha(import_info, importImageAlpha(import_info,
image.first, image.second, image.first, image.second,
alpha.first, alpha.second); alpha.first, alpha.second);
} }
template <class T1, class S1,
class T2, class S2>
inline void
importImageAlpha(ImageImportInfo const & import_info,
MultiArrayView<2, T1, S1> image,
MultiArrayView<2, T2, S2> alpha)
{
vigra_precondition(import_info.shape() == image.shape() && import_i
nfo.shape() == alpha.shape(),
"importImageAlpha(): shape mismatch between input and output.")
;
importImageAlpha(import_info, destImage(image), destImage(alpha));
}
namespace detail namespace detail
{ {
template<class ValueType, template<class ValueType,
class ImageIterator, class ImageAccessor, class ImageScale r, class ImageIterator, class ImageAccessor, class ImageScale r,
class AlphaIterator, class AlphaAccessor, class AlphaScale r> class AlphaIterator, class AlphaAccessor, class AlphaScale r>
void void
write_image_band_and_alpha(Encoder* encoder, write_image_band_and_alpha(Encoder* encoder,
ImageIterator image_upper_left, ImageIte rator image_lower_right, ImageAccessor image_accessor, ImageIterator image_upper_left, ImageIte rator image_lower_right, ImageAccessor image_accessor,
const ImageScaler& image_scaler, const ImageScaler& image_scaler,
AlphaIterator alpha_upper_left, AlphaAcc essor alpha_accessor, AlphaIterator alpha_upper_left, AlphaAcc essor alpha_accessor,
const AlphaScaler& alpha_scaler) const AlphaScaler& alpha_scaler)
{ {
typedef typename ImageIterator::row_iterator ImageRowIterator; typedef typename ImageIterator::row_iterator ImageRowIterator;
typedef typename ImageAccessor::value_type ImageValueType;
typedef typename AlphaIterator::row_iterator AlphaRowIterator; typedef typename AlphaIterator::row_iterator AlphaRowIterator;
typedef typename AlphaAccessor::value_type AlphaValueType;
typedef detail::RequiresExplicitCast<ValueType> explicit_cast; typedef detail::RequiresExplicitCast<ValueType> explicit_cast;
vigra_precondition(image_lower_right.x >= image_upper_left.x, vigra_precondition(image_lower_right.x >= image_upper_left.x,
"vigra::detail::write_image_band_and_alpha: negative width"); "vigra::detail::write_image_band_and_alpha: negative width");
vigra_precondition(image_lower_right.y >= image_upper_left.y, vigra_precondition(image_lower_right.y >= image_upper_left.y,
"vigra::detail::write_image_band_and_alpha: negative height"); "vigra::detail::write_image_band_and_alpha: negative height");
const unsigned width(static_cast<unsigned>(image_lower_right.x - image_upper_left.x)); const unsigned width(static_cast<unsigned>(image_lower_right.x - image_upper_left.x));
const unsigned height(static_cast<unsigned>(image_lower_right.y - image_upper_left.y)); const unsigned height(static_cast<unsigned>(image_lower_right.y - image_upper_left.y));
skipping to change at line 732 skipping to change at line 782
typedef typename ImageBaseType::value_type ImageValueType; typedef typename ImageBaseType::value_type ImageValueType;
VIGRA_UNIQUE_PTR<Encoder> encoder(vigra::encoder(export_info)); VIGRA_UNIQUE_PTR<Encoder> encoder(vigra::encoder(export_info));
std::string pixel_type(export_info.getPixelType()); std::string pixel_type(export_info.getPixelType());
const bool downcast(negotiatePixelType(encoder->getFileType(), TypeAsString<ImageValueType>::result(), pixel_type)); const bool downcast(negotiatePixelType(encoder->getFileType(), TypeAsString<ImageValueType>::result(), pixel_type));
const pixel_t type(pixel_t_of_string(pixel_type)); const pixel_t type(pixel_t_of_string(pixel_type));
encoder->setPixelType(pixel_type); encoder->setPixelType(pixel_type);
vigra_precondition(isBandNumberSupported(encoder->getFileType() , image_accessor.size(image_upper_left)), vigra_precondition(isBandNumberSupported(encoder->getFileType() , image_accessor.size(image_upper_left) + 1U),
"exportImageAlpha(): file format does not su pport requested number of bands (color channels)"); "exportImageAlpha(): file format does not su pport requested number of bands (color channels)");
const range_t image_source_range(find_source_value_range(export _info, const range_t image_source_range(find_source_value_range(export _info,
image_ upper_left, image_lower_right, image_accessor)); image_ upper_left, image_lower_right, image_accessor));
const range_t alpha_source_range(find_source_value_range(export _info, const range_t alpha_source_range(find_source_value_range(export _info,
alpha_ upper_left, alpha_ upper_left,
alpha_ upper_left + (image_lower_right - image_upper_left), alpha_ upper_left + (image_lower_right - image_upper_left),
alpha_ accessor)); alpha_ accessor));
const range_t destination_range(find_destination_value_range(ex port_info, pixel_t_of_string(pixel_type))); const range_t destination_range(find_destination_value_range(ex port_info, pixel_t_of_string(pixel_type)));
skipping to change at line 839 skipping to change at line 889
break; break;
default: default:
vigra_fail("vigra::detail::exportImageAlpha<non-scalar> : not reached"); vigra_fail("vigra::detail::exportImageAlpha<non-scalar> : not reached");
} }
} }
encoder->close(); encoder->close();
} }
} // end namespace detail } // end namespace detail
/*! /**
* \brief Write the image specified by the given \ref \brief Write the image and its alpha channel to a file.
* vigra::ImageExportInfo object including an alpha channel.
* See \ref exportImage() for more information.
* <B>Declarations</B>
* <B>Declarations</B>
* Pass arguments explicitly:
* \code pass 2D array views:
* namespace vigra { \code
* template <class ImageIterator, class ImageAccessor, namespace vigra {
* class AlphaIterator, class AlphaAccessor> template <class T1, class S1,
* void class T2, class S2>
* exportImageAlpha(ImageIterator imageUpperLeft, ImageIterator void
imageLowerRight, ImageAccessor imageAccessor, exportImageAlpha(MultiArrayView<2, T1, S1> const & image,
* AlphaIterator alphaUpperLeft, AlphaAccessor MultiArrayView<2, T2, S2> const & alpha,
alphaAccessor, ImageExportInfo const & export_info);
* const ImageExportInfo& exportInfo)
* } template <class T1, class S1,
* \endcode class T2, class S2>
* void
* Use argument objects in conjunction with \ref ArgumentObjectFactorie exportImageAlpha(MultiArrayView<2, T1, S1> const & image,
s : MultiArrayView<2, T2, S2> const & alpha,
* \code char const * filename)
* namespace vigra {
* template <class ImageIterator, class ImageAccessor, template <class T1, class S1,
* class AlphaIterator, class AlphaAccessor> class T2, class S2>
* void void
* exportImageAlpha(const triple<ImageIterator, ImageIterator, Imag exportImageAlpha(MultiArrayView<2, T1, S1> const & image,
eAccessor>& image, MultiArrayView<2, T2, S2> const & alpha,
* const pair<AlphaIterator, AlphaAccessor>& alpha std::string const & filename)
, }
* const ImageExportInfo& exportInfo) \endcode
* }
* \endcode \deprecatedAPI{exportImageAlpha}
* pass \ref ImageIterators and \ref DataAccessors :
* <B>Usage</B> \code
* namespace vigra {
* <B>\#include \<vigra/impexalpha.hxx\></B> template <class ImageIterator, class ImageAccessor,
* class AlphaIterator, class AlphaAccessor>
* Namespace: vigra void
* \code exportImageAlpha(ImageIterator imageUpperLeft, ImageIterator im
* typedef UInt8 value_t; ageLowerRight, ImageAccessor imageAccessor,
* ImageExportInfo info("zorro.tif"); AlphaIterator alphaUpperLeft, AlphaAccessor al
* phaAccessor,
* if (info.isGrayscale()) const ImageExportInfo& exportInfo)
* { }
* BasicImage<value_t> alpha; \endcode
* BasicImage<value_t> image; Use argument objects in conjunction with \ref ArgumentObjectFactories :
* \code
* ... namespace vigra {
* template <class ImageIterator, class ImageAccessor,
* exportImageAlpha(image.upperLeft(), image.lowerRight(), imag class AlphaIterator, class AlphaAccessor>
e.accessor(), void
* alpha.upperLeft(), alpha.accessor(), exportImageAlpha(const triple<ImageIterator, ImageIterator, ImageAc
* info); cessor>& image,
* } const pair<AlphaIterator, AlphaAccessor>& alpha,
* else const ImageExportInfo& exportInfo)
* { }
* BasicImage<value_t> alpha; \endcode
* BasicImage<vigra::RGBValue<value_t> > image; \deprecatedEnd
*
* ... <b> Usage:</b>
*
* exportImageAlpha(image.upperLeft(), image.lowerRight(), imag <B>\#include</B> \<vigra/impexalpha.hxx\><br/>
e.accessor(), Namespace: vigra
* alpha.upperLeft(), alpha.accessor(),
* info); \code
* } typedef UInt8 value_t;
* \endcode
* MultiArray<2, value_t> alpha(width, height);
* <B>Preconditions</B> MultiArray<2, RGBValue<value_t> > image(width, height);
*
* - The same preconditions hold as for exportImage(), however the ... // do some image processing
* only image formats that support alpha channels are
* + TIFF and // specify the output filename
* + PNG. exportImageAlpha(image, alpha, "zorro.tif");
* In particular, JPEG does <B>not</B> support alpha channels.
* - The alpha channel always is scalar-valued, i.e. comprises a // use a ImageExportInfo if you need more control over the export
* single band. exportImageAlpha(image, alpha, ImageExportInfo("zorro.tif").setPixelTyp
*/ e("FLOAT"));
doxygen_overloaded_function(template <...> inline void exportImageAlpha \endcode
)
\deprecatedUsage{exportImageAlpha}
\code
typedef UInt8 value_t;
ImageExportInfo info("zorro.tif");
if (info.isGrayscale())
{
BasicImage<value_t> alpha;
BasicImage<value_t> image;
...
exportImageAlpha(image.upperLeft(), image.lowerRight(), image.acces
sor(),
alpha.upperLeft(), alpha.accessor(),
info);
}
else
{
BasicImage<value_t> alpha;
BasicImage<vigra::RGBValue<value_t> > image;
...
exportImageAlpha(image.upperLeft(), image.lowerRight(), image.acces
sor(),
alpha.upperLeft(), alpha.accessor(),
info);
}
\endcode
\deprecatedEnd
<B>Preconditions</B>
- The same preconditions hold as for exportImage(), however the
only image formats that support alpha channels are
+ TIFF and
+ PNG.
In particular, JPEG does <B>not</B> support alpha channels.
- The alpha channel always is scalar-valued, i.e. comprises a
single band.
*/
doxygen_overloaded_function(template <...> void exportImageAlpha)
template <class ImageIterator, class ImageAccessor, template <class ImageIterator, class ImageAccessor,
class AlphaIterator, class AlphaAccessor> class AlphaIterator, class AlphaAccessor>
inline void inline void
exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lo wer_right, ImageAccessor image_accessor, exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lo wer_right, ImageAccessor image_accessor,
AlphaIterator alpha_upper_left, AlphaAccessor alpha_ac cessor, AlphaIterator alpha_upper_left, AlphaAccessor alpha_ac cessor,
const ImageExportInfo& export_info) const ImageExportInfo& export_info)
{ {
typedef typename ImageAccessor::value_type ImageValueType; typedef typename ImageAccessor::value_type ImageValueType;
typedef typename vigra::NumericTraits<ImageValueType>::isScalar is_ scalar; typedef typename vigra::NumericTraits<ImageValueType>::isScalar is_ scalar;
skipping to change at line 946 skipping to change at line 1041
detail::exportImageAlpha(image_upper_left, image_lower_right, i mage_accessor, detail::exportImageAlpha(image_upper_left, image_lower_right, i mage_accessor,
alpha_upper_left, alpha_accessor, alpha_upper_left, alpha_accessor,
info, info,
is_scalar()); is_scalar());
} }
} }
template <class ImageIterator, class ImageAccessor, template <class ImageIterator, class ImageAccessor,
class AlphaIterator, class AlphaAccessor> class AlphaIterator, class AlphaAccessor>
inline void inline void
exportImageAlpha(const vigra::triple<ImageIterator, ImageIterator, Imag exportImageAlpha(triple<ImageIterator, ImageIterator, ImageAccessor> im
eAccessor>& image, age,
const vigra::pair<AlphaIterator, AlphaAccessor>& alpha pair<AlphaIterator, AlphaAccessor> alpha,
, ImageExportInfo const & export_info)
const ImageExportInfo& export_info)
{ {
exportImageAlpha(image.first, image.second, image.third, exportImageAlpha(image.first, image.second, image.third,
alpha.first, alpha.second, alpha.first, alpha.second,
export_info); export_info);
} }
template <class T1, class S1,
class T2, class S2>
inline void
exportImageAlpha(MultiArrayView<2, T1, S1> const & image,
MultiArrayView<2, T2, S2> const & alpha,
ImageExportInfo const & export_info)
{
exportImageAlpha(srcImageRange(image),
srcImage(alpha),
export_info);
}
template <class T1, class S1,
class T2, class S2>
inline void
exportImageAlpha(MultiArrayView<2, T1, S1> const & image,
MultiArrayView<2, T2, S2> const & alpha,
char const * name)
{
ImageExportInfo export_info(name);
exportImageAlpha(srcImageRange(image),
srcImage(alpha),
export_info);
}
template <class T1, class S1,
class T2, class S2>
inline void
exportImageAlpha(MultiArrayView<2, T1, S1> const & image,
MultiArrayView<2, T2, S2> const & alpha,
std::string const & name)
{
ImageExportInfo export_info(name.c_str());
exportImageAlpha(srcImageRange(image),
srcImage(alpha),
export_info);
}
/** @} */ /** @} */
} // end namespace vigra } // end namespace vigra
#endif // VIGRA_IMPEXALPHA_HXX #endif // VIGRA_IMPEXALPHA_HXX
 End of changes. 10 change blocks. 
174 lines changed or deleted 302 lines changed or added


 impexbase.hxx   impexbase.hxx 
skipping to change at line 62 skipping to change at line 62
SIGNED_INT_32, SIGNED_INT_32,
IEEE_FLOAT_32, IEEE_FLOAT_32,
IEEE_FLOAT_64 IEEE_FLOAT_64
} pixel_t; } pixel_t;
namespace detail namespace detail
{ {
inline static pixel_t inline static pixel_t
pixel_t_of_string(const std::string& pixel_type) pixel_t_of_string(const std::string& pixel_type)
{ {
if (pixel_type == "UINT8") if (pixel_type == "BILEVEL")
{
return UNSIGNED_INT_8;
}
else if (pixel_type == "UINT8")
{ {
return UNSIGNED_INT_8; return UNSIGNED_INT_8;
} }
else if (pixel_type == "UINT16") else if (pixel_type == "UINT16")
{ {
return UNSIGNED_INT_16; return UNSIGNED_INT_16;
} }
else if (pixel_type == "UINT32") else if (pixel_type == "UINT32")
{ {
return UNSIGNED_INT_32; return UNSIGNED_INT_32;
 End of changes. 1 change blocks. 
1 lines changed or deleted 5 lines changed or added


 initimage.hxx   initimage.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_INITIMAGE_HXX #ifndef VIGRA_INITIMAGE_HXX
#define VIGRA_INITIMAGE_HXX #define VIGRA_INITIMAGE_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "iteratortraits.hxx" #include "iteratortraits.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup InitAlgo Algorithms to Initialize Images /** \addtogroup InitAlgo Algorithms to Initialize Images
Init images or image borders Init images or image borders
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
skipping to change at line 151 skipping to change at line 152
/********************************************************/ /********************************************************/
/* */ /* */
/* initImage */ /* initImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Write a value to every pixel in an image or rectangular ROI. /** \brief Write a value to every pixel in an image or rectangular ROI.
This function can be used to init the image. This function can be used to init the image.
It uses an accessor to access the pixel data.
The initial value can either be a constant of appropriate type (compati ble with The initial value can either be a constant of appropriate type (compati ble with
the destination's value_type), or a functor with compatible result_type . These two the destination's value_type), or a functor with compatible result_type . These two
cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt> cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt>
yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its
<tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>. <tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>.
Function \ref initMultiArray() implements the same functionality for ar
bitrary dimensional
arrays. In many situations, the assignment functions of \ref vigra::Mul
tiArrayView offer
a simpler and more readable alternative to the init functions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S, class VALUETYPE>
void
initImage(MultiArrayView<2, T, S> img, VALUETYPE const & v);
template <class T, class S, class FUNCTOR>
void
initImage(MultiArrayView<2, T, S> img, FUNCTOR const & v);
}
\endcode
\deprecatedAPI{initImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
void initImage(ImageIterator upperleft, ImageIterator lowerright, void initImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, VALUETYPE const & v); Accessor a, VALUETYPE const & v);
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void initImage(ImageIterator upperleft, ImageIterator lowerright, void initImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, FUNCTOR const & v); Accessor a, FUNCTOR const & v);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
void initImage(triple<ImageIterator, ImageIterator, Accessor> img, VALUETYPE const & v); void initImage(triple<ImageIterator, ImageIterator, Accessor> img, VALUETYPE const & v);
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void initImage(triple<ImageIterator, ImageIterator, Accessor> img, FUNCTOR const & v); void initImage(triple<ImageIterator, ImageIterator, Accessor> img, FUNCTOR const & v);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/initimage.hxx\><br> <b>\#include</b> \<vigra/initimage.hxx\><br>
Namespace: vigra Namespace: vigra
Initialize with a constant: Initialize with a constant:
\code \code
vigra::BImage img(100, 100); MultiArray<2, unsigned char> img(100, 100);
// init the image with the value 128 // init the image with the value 128
vigra::initImage(destImageRange(img), 128); initImage(img, 128);
// init the interior with the value 1
initImage(img.subarray(Shape2(10), Shape2(-10)), 1);
// equivalent to
img = 128;
img.init(128);
img.subarray(Shape2(10), Shape2(-10)) = 1;
\endcode \endcode
Initialize with a functor: Initialize with a functor:
\code \code
struct Counter { struct Counter {
Counter() : count(0) {} Counter() : count(0) {}
int operator()() const { return count++; } int operator()() const { return count++; }
mutable int count; mutable int count;
}; };
vigra::IImage img(100, 100); MultiArray<2, int> img(100, 100);
// write the current count in every pixel // write the current count in every pixel
vigra::initImage(destImageRange(img), Counter()); initImage(img, Counter());
// equivalent to
#include <vigra/algorithm.hxx>
linearSequence(img.begin(), img.end());
\endcode \endcode
<b> Required Interface:</b> \deprecatedUsage{initImage}
\code
vigra::BImage img(100, 100);
// init the image with the value 128
vigra::initImage(destImageRange(img), 128);
// Initialize with a functor:
struct Counter {
Counter() : count(0) {}
int operator()() const { return count++; }
mutable int count;
};
// write the current count in every pixel
vigra::initImage(destImageRange(img), Counter());
\endcode
<b> Required Interface:</b>
\code \code
ImageIterator upperleft, lowerright; ImageIterator upperleft, lowerright;
ImageIterator::row_iterator ix = upperleft.rowIterator(); ImageIterator::row_iterator ix = upperleft.rowIterator();
Accessor accessor; Accessor accessor;
VALUETYPE v; VALUETYPE v;
accessor.set(v, ix); accessor.set(v, ix);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void initImage) doxygen_overloaded_function(template <...> void initImage)
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
void void
initImage(ImageIterator upperleft, ImageIterator lowerright, initImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, VALUETYPE const & v) Accessor a, VALUETYPE const & v)
{ {
int w = lowerright.x - upperleft.x; int w = lowerright.x - upperleft.x;
for(; upperleft.y < lowerright.y; ++upperleft.y) for(; upperleft.y < lowerright.y; ++upperleft.y)
{ {
initLineImpl(upperleft.rowIterator(), upperleft.rowIterator() + w, a, initLineImpl(upperleft.rowIterator(), upperleft.rowIterator() + w, a,
v, typename FunctorTraits<VALUETYPE>::isInitializer()) ; v, typename FunctorTraits<VALUETYPE>::isInitializer()) ;
} }
} }
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
inline inline void
void
initImage(triple<ImageIterator, ImageIterator, Accessor> img, VALUETYPE con st & v) initImage(triple<ImageIterator, ImageIterator, Accessor> img, VALUETYPE con st & v)
{ {
initImage(img.first, img.second, img.third, v); initImage(img.first, img.second, img.third, v);
} }
template <class T, class S, class VALUETYPE>
inline void
initImage(MultiArrayView<2, T, S> img, VALUETYPE const & v)
{
initImage(destImageRange(img), v);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* initImageWithFunctor */ /* initImageWithFunctor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Write the result of a functor call to every pixel in an image or rectangular ROI. /** \brief Write the result of a functor call to every pixel in an image or rectangular ROI.
This function can be used to init the image by calling the given This function can be used to init the image by calling the given
functor for each pixel. It uses an accessor to access the pixel data. T he functor is functor for each pixel. The functor is
passed by reference, so that its internal state can be updated in each call. passed by reference, so that its internal state can be updated in each call.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S, class FUNCTOR>
void
initImageWithFunctor(MultiArrayView<2, T, S> img, FUNCTOR & f);
}
\endcode
\deprecatedAPI{initImageWithFunctor}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void void
initImageWithFunctor(ImageIterator upperleft, ImageIterator lowerri ght, initImageWithFunctor(ImageIterator upperleft, ImageIterator lowerri ght,
Accessor a, FUNCTOR & f); Accessor a, FUNCTOR & f);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void void
initImageWithFunctor(triple<ImageIterator, ImageIterator, Accessor> img, FUNCTOR & f); initImageWithFunctor(triple<ImageIterator, ImageIterator, Accessor> img, FUNCTOR & f);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/initimage.hxx\><br> <b>\#include</b> \<vigra/initimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
struct Counter { struct Counter {
Counter() : count(0) {} Counter() : count(0) {}
int operator()() const { return count++; } int operator()() const { return count++; }
int count;
};
MultiArray<2, int> img(100, 100);
// write the current count in every pixel
Counter counter;
initImageWithFunctor(img, counter);
// equivalent to
#include <vigra/algorithm.hxx>
linearSequence(img.begin(), img.end());
\endcode
\deprecatedUsage{initImageWithFunctor}
\code
struct Counter {
Counter() : count(0) {}
int operator()() const { return count++; }
mutable int count; mutable int count;
}; };
vigra::IImage img(100, 100); vigra::IImage img(100, 100);
// write the current count in every pixel // write the current count in every pixel
Counter counter; Counter counter;
vigra::initImageWithFunctor(destImageRange(img), counter); vigra::initImageWithFunctor(destImageRange(img), counter);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft, lowerright; ImageIterator upperleft, lowerright;
ImageIterator::row_iterator ix = upperleft.rowIterator(); ImageIterator::row_iterator ix = upperleft.rowIterator();
Accessor accessor; Accessor accessor;
Functor f; Functor f;
accessor.set(f(), ix); accessor.set(f(), ix);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void initImageWithFunctor) doxygen_overloaded_function(template <...> void initImageWithFunctor)
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void void
initImageWithFunctor(ImageIterator upperleft, ImageIterator lowerright, initImageWithFunctor(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, FUNCTOR & f) Accessor a, FUNCTOR & f)
{ {
int w = lowerright.x - upperleft.x; int w = lowerright.x - upperleft.x;
for(; upperleft.y < lowerright.y; ++upperleft.y) for(; upperleft.y < lowerright.y; ++upperleft.y)
{ {
initLineFunctor(upperleft.rowIterator(), upperleft.rowIterator() + w, a, f); initLineFunctor(upperleft.rowIterator(), upperleft.rowIterator() + w, a, f);
} }
} }
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
inline inline void
void
initImageWithFunctor(triple<ImageIterator, ImageIterator, Accessor> img, FU NCTOR & f) initImageWithFunctor(triple<ImageIterator, ImageIterator, Accessor> img, FU NCTOR & f)
{ {
initImageWithFunctor(img.first, img.second, img.third, f); initImageWithFunctor(img.first, img.second, img.third, f);
} }
template <class T, class S, class FUNCTOR>
inline void
initImageWithFunctor(MultiArrayView<2, T, S> img, FUNCTOR & f)
{
initImageWithFunctor(destImageRange(img), f);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* initImageIf */ /* initImageIf */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Write value to pixel in the image if mask is true. /** \brief Write value to pixel in the image if mask is true.
This function can be used to init a region-of-interest of the image. This function can be used to init a region-of-interest of the image.
It uses an accessor to access the pixel data.
The initial value can either be a constant of appropriate type (compati ble with The initial value can either be a constant of appropriate type (compati ble with
the destination's value_type), or a functor with compatible result_type . These two the destination's value_type), or a functor with compatible result_type . These two
cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt> cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt>
yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its
<tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>. <tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S,
class TM, class SM,
class VALUETYPE>
void
initImageIf(MultiArrayView<2, T, S> img,
MultiArrayView<2, TM, SM> const & mask,
VALUETYPE const & v);
template <class T, class S,
class TM, class SM,
class FUNCTOR>
void
initImageIf(MultiArrayView<2, T, S> img,
MultiArrayView<2, TM, SM> const & mask,
FUNCTOR const & v);
}
\endcode
\deprecatedAPI{initImageIf}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class VALUETYPE> class VALUETYPE>
void initImageIf(ImageIterator upperleft, ImageIterator lowerright, Accessor a, void initImageIf(ImageIterator upperleft, ImageIterator lowerright, Accessor a,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
VALUETYPE const & v); VALUETYPE const & v);
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class FUNCTOR> class FUNCTOR>
void initImageIf(ImageIterator upperleft, ImageIterator lowerright, Accessor a, void initImageIf(ImageIterator upperleft, ImageIterator lowerright, Accessor a,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
FUNCTOR const & v); FUNCTOR const & v);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class VALUETYPE> class VALUETYPE>
void initImageIf(triple<ImageIterator, ImageIterator, Accessor> img , void initImageIf(triple<ImageIterator, ImageIterator, Accessor> img ,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
VALUETYPE const & v); VALUETYPE const & v);
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class FUNCTOR> class FUNCTOR>
void initImageIf(triple<ImageIterator, ImageIterator, Accessor> img , void initImageIf(triple<ImageIterator, ImageIterator, Accessor> img ,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
FUNCTOR const & v); FUNCTOR const & v);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/initimage.hxx\><br> <b>\#include</b> \<vigra/initimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, RGBValue<unsigned char> > img(100, 100),
MultiArray<2, unsigned char> mask(100, 100);
... // init the ROI mask
// set the ROI to one
initImageIf(img, mask,
NumericTraits<RGBValue<unsigned char> >::one());
\endcode
\deprecatedUsage{initImageIf}
\code \code
vigra::BImage img(100, 100); vigra::BImage img(100, 100);
vigra::BImage mask(100, 100); vigra::BImage mask(100, 100);
// zero the ROI // zero the ROI
vigra::initImageIf(destImageRange(img), vigra::initImageIf(destImageRange(img),
maskImage(mask), maskImage(mask),
vigra::NumericTraits<vigra::BImage::PixelType>::zero()); vigra::NumericTraits<vigra::BImage::PixelType>::zero());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft, lowerright; ImageIterator upperleft, lowerright;
MaskImageIterator mask_upperleft; MaskImageIterator mask_upperleft;
ImageIterator::row_iterator ix = upperleft.rowIterator(); ImageIterator::row_iterator ix = upperleft.rowIterator();
MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator(); MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
Accessor accessor; Accessor accessor;
MaskAccessor mask_accessor; MaskAccessor mask_accessor;
VALUETYPE v; VALUETYPE v;
if(mask_accessor(mx)) accessor.set(v, ix); if(mask_accessor(mx)) accessor.set(v, ix);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void initImageIf) doxygen_overloaded_function(template <...> void initImageIf)
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class VALUETYPE> class VALUETYPE>
void void
initImageIf(ImageIterator upperleft, ImageIterator lowerright, Accessor a, initImageIf(ImageIterator upperleft, ImageIterator lowerright, Accessor a,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
VALUETYPE const & v) VALUETYPE const & v)
skipping to change at line 455 skipping to change at line 573
initLineIfImpl(upperleft.rowIterator(), initLineIfImpl(upperleft.rowIterator(),
upperleft.rowIterator() + w, a, upperleft.rowIterator() + w, a,
mask_upperleft.rowIterator(), ma, mask_upperleft.rowIterator(), ma,
v, typename FunctorTraits<VALUETYPE>::isInitializer()); v, typename FunctorTraits<VALUETYPE>::isInitializer());
} }
} }
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class VALUETYPE> class VALUETYPE>
inline inline void
void
initImageIf(triple<ImageIterator, ImageIterator, Accessor> img, initImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
VALUETYPE const & v) VALUETYPE const & v)
{ {
initImageIf(img.first, img.second, img.third, mask.first, mask.second, v); initImageIf(img.first, img.second, img.third, mask.first, mask.second, v);
} }
template <class T, class S,
class TM, class SM,
class VALUETYPE>
inline void
initImageIf(MultiArrayView<2, T, S> img,
MultiArrayView<2, TM, SM> const & mask,
VALUETYPE const & v)
{
vigra_precondition(img.shape() == mask.shape(),
"initImageIf(): shape mismatch between input and mask.");
initImageIf(destImageRange(img), maskImage(mask), v);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* initImageBorder */ /* initImageBorder */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Write value to the specified border pixels in the image. /** \brief Write value to the specified border pixels in the image.
A pixel is initialized if its distance to the border A pixel is initialized if its distance to the border
is at most 'borderwidth'. It uses an accessor to access the pixel data. is at most 'borderwidth'.
The initial value can either be a constant of appropriate type (compati ble with The initial value can either be a constant of appropriate type (compati ble with
the destination's value_type), or a functor with compatible result_type . These two the destination's value_type), or a functor with compatible result_type . These two
cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt> cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt>
yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its
<tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>. <tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S, class VALUETYPE>
void
initImageBorder(MultiArrayView<2, T, S> img,
int border_width, VALUETYPE const & v);
template <class T, class S, class FUNCTOR>
void
initImageBorder(MultiArrayView<2, T, S> img,
int border_width, FUNCTOR const & v);
}
\endcode
\deprecatedAPI{initImageBorder}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
void initImageBorder(ImageIterator upperleft, ImageIterator lowerri ght, Accessor a, void initImageBorder(ImageIterator upperleft, ImageIterator lowerri ght, Accessor a,
int border_width, VALUETYPE const & v); int border_width, VALUETYPE const & v);
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void initImageBorder(ImageIterator upperleft, ImageIterator lowerri ght, Accessor a, void initImageBorder(ImageIterator upperleft, ImageIterator lowerri ght, Accessor a,
int border_width, FUNCTOR const & v); int border_width, FUNCTOR const & v);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
void initImageBorder(triple<ImageIterator, ImageIterator, Accessor> img, void initImageBorder(triple<ImageIterator, ImageIterator, Accessor> img,
int border_width, VALUETYPE const & v); int border_width, VALUETYPE const & v);
template <class ImageIterator, class Accessor, class FUNCTOR> template <class ImageIterator, class Accessor, class FUNCTOR>
void initImageBorder(triple<ImageIterator, ImageIterator, Accessor> img, void initImageBorder(triple<ImageIterator, ImageIterator, Accessor> img,
int border_width, FUNCTOR const & v); int border_width, FUNCTOR const & v);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/initimage.hxx\><br> <b>\#include</b> \<vigra/initimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <vigra/random.hxx>
MultiArray<2, int> img(100, 100);
// fill a border of 5 pixels with random numbers
initImageBorder(img, 5, MersenneTwister());
\endcode
\deprecatedUsage{initImageBorder}
\code
vigra::BImage img(100, 100); vigra::BImage img(100, 100);
// zero a border of 5 pixel // zero a border of 5 pixel
vigra::initImageBorder(destImageRange(img), vigra::initImageBorder(destImageRange(img),
5, vigra::NumericTraits<vigra::BImage::PixelType>::zero ()); 5, vigra::NumericTraits<vigra::BImage::PixelType>::zero ());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
<br/>see \ref initImage()
see \ref initImage() \deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void initImageBorder) doxygen_overloaded_function(template <...> void initImageBorder)
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
inline inline
void void
initImageBorder(ImageIterator upperleft, ImageIterator lowerright, initImageBorder(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, int border_width, VALUETYPE const & v) Accessor a, int border_width, VALUETYPE const & v)
{ {
int w = lowerright.x - upperleft.x; int w = lowerright.x - upperleft.x;
skipping to change at line 548 skipping to change at line 702
int hb = (border_width > h) ? h : border_width; int hb = (border_width > h) ? h : border_width;
int wb = (border_width > w) ? w : border_width; int wb = (border_width > w) ? w : border_width;
initImage(upperleft, upperleft+Diff2D(w,hb), a, v); initImage(upperleft, upperleft+Diff2D(w,hb), a, v);
initImage(upperleft, upperleft+Diff2D(wb,h), a, v); initImage(upperleft, upperleft+Diff2D(wb,h), a, v);
initImage(upperleft+Diff2D(0,h-hb), lowerright, a, v); initImage(upperleft+Diff2D(0,h-hb), lowerright, a, v);
initImage(upperleft+Diff2D(w-wb,0), lowerright, a, v); initImage(upperleft+Diff2D(w-wb,0), lowerright, a, v);
} }
template <class ImageIterator, class Accessor, class VALUETYPE> template <class ImageIterator, class Accessor, class VALUETYPE>
inline inline void
void
initImageBorder(triple<ImageIterator, ImageIterator, Accessor> img, initImageBorder(triple<ImageIterator, ImageIterator, Accessor> img,
int border_width, VALUETYPE const & v) int border_width, VALUETYPE const & v)
{ {
initImageBorder(img.first, img.second, img.third, border_width, v); initImageBorder(img.first, img.second, img.third, border_width, v);
} }
template <class T, class S, class VALUETYPE>
inline void
initImageBorder(MultiArrayView<2, T, S> img,
int border_width, VALUETYPE const & v)
{
initImageBorder(destImageRange(img), border_width, v);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_INITIMAGE_HXX #endif // VIGRA_INITIMAGE_HXX
 End of changes. 50 change blocks. 
46 lines changed or deleted 209 lines changed or added


 inspectimage.hxx   inspectimage.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_INSPECTIMAGE_HXX #define VIGRA_INSPECTIMAGE_HXX
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "iteratortraits.hxx" #include "iteratortraits.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "rgbvalue.hxx" #include "rgbvalue.hxx"
#include "inspector_passes.hxx" #include "inspector_passes.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup InspectAlgo Algorithms to Inspect Images /** \addtogroup InspectAlgo Algorithms to Inspect Images
Apply read-only functor to every pixel Collect information and statistics over all or selected pixels.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectLine */ /* inspectLine */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, class Functor> template <class SrcIterator, class SrcAccessor, class Functor>
skipping to change at line 124 skipping to change at line 125
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectImage */ /* inspectImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply read-only functor to every pixel in the image. /** \brief Apply read-only functor to every pixel in the image.
This function can be used to collect statistics of the image etc. This function can be used to collect statistics of the image etc.
The results must be stored in the functor, which serves as a return The results must be stored in the functor, which serves as a return val
value. ue
The function uses an accessor to access the pixel data. (and is therefore passed by reference).
For many common statistics, the use of \ref vigra::acc::extractFeatures
() in combination with
\ref FeatureAccumulators is more convenient.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class Functor> template <class T, class S, class Functor>
void void
inspectImage(ImageIterator upperleft, ImageIterator lowerright, inspectImage(MultiArrayView<2, T, S> const & img,
Accessor a, Functor & f) Functor & f);
} }
\endcode \endcode
\deprecatedAPI{inspectImage}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class ImageIterator, class Accessor, class Functor>
void
inspectImage(ImageIterator upperleft, ImageIterator lowerright, Acc
essor a,
Functor & f)
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, class Functor> template <class ImageIterator, class Accessor, class Functor>
void void
inspectImage(triple<ImageIterator, ImageIterator, Accessor> img, inspectImage(triple<ImageIterator, ImageIterator, Accessor> img,
Functor & f) Functor & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> img(width, height);
... // fill img
// init functor
FindMinMax<unsined char> minmax;
inspectImage(img, minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max;
\endcode
\deprecatedUsage{inspectImage}
\code
// init functor // init functor
vigra::BImage img; vigra::BImage img;
vigra::FindMinMax<vigra::BImage::PixelType> minmax; vigra::FindMinMax<vigra::BImage::PixelType> minmax;
vigra::inspectImage(srcImageRange(img), minmax); vigra::inspectImage(srcImageRange(img), minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max; cout << "Min: " << minmax.min << " Max: " << minmax.max;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ConstImageIterator upperleft, lowerright; ConstImageIterator upperleft, lowerright;
ConstImageIterator::row_iterator ix = upperleft.rowIterator(); ConstImageIterator::row_iterator ix = upperleft.rowIterator();
Accessor accessor; Accessor accessor;
Functor functor; Functor functor;
functor(accessor(ix)); // return not used functor(accessor(ix)); // return not used
\endcode \endcode
\deprecatedEnd
\see InspectFunctor, FeatureAccumulators
*/ */
doxygen_overloaded_function(template <...> void inspectImage) doxygen_overloaded_function(template <...> void inspectImage)
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
struct inspectImage_binder struct inspectImage_binder
{ {
ImageIterator upperleft; ImageIterator upperleft;
ImageIterator lowerright; ImageIterator lowerright;
Accessor a; Accessor a;
skipping to change at line 213 skipping to change at line 239
template <class ImageIterator, class Accessor, class Functor> template <class ImageIterator, class Accessor, class Functor>
void void
inspectImage(ImageIterator upperleft, ImageIterator lowerright, inspectImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, Functor & f) Accessor a, Functor & f)
{ {
inspectImage_binder<ImageIterator, Accessor> g(upperleft, lowerright, a ); inspectImage_binder<ImageIterator, Accessor> g(upperleft, lowerright, a );
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
template <class ImageIterator, class Accessor, class Functor> template <class ImageIterator, class Accessor, class Functor>
inline inline void
void
inspectImage(triple<ImageIterator, ImageIterator, Accessor> img, inspectImage(triple<ImageIterator, ImageIterator, Accessor> img,
Functor & f) Functor & f)
{ {
inspectImage(img.first, img.second, img.third, f); inspectImage(img.first, img.second, img.third, f);
} }
template <class T, class S, class Functor>
inline void
inspectImage(MultiArrayView<2, T, S> const & img,
Functor & f)
{
inspectImage(srcImageRange(img), f);
}
namespace functor namespace functor
{ {
template <class T> class UnaryAnalyser; template <class T> class UnaryAnalyser;
} }
template <class ImageIterator, class Accessor, class Functor> template <class ImageIterator, class Accessor, class Functor>
inline inline
void void
inspectImage(ImageIterator upperleft, ImageIterator lowerright, inspectImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, functor::UnaryAnalyser<Functor> const & f) Accessor a, functor::UnaryAnalyser<Functor> const & f)
{ {
inspectImage(upperleft, lowerright, a, inspectImage(upperleft, lowerright, a,
const_cast<functor::UnaryAnalyser<Functor> &>(f)); const_cast<functor::UnaryAnalyser<Functor> &>(f));
} }
template <class ImageIterator, class Accessor, class Functor> template <class ImageIterator, class Accessor, class Functor>
inline inline void
void
inspectImage(triple<ImageIterator, ImageIterator, Accessor> img, inspectImage(triple<ImageIterator, ImageIterator, Accessor> img,
functor::UnaryAnalyser<Functor> const & f) functor::UnaryAnalyser<Functor> const & f)
{ {
inspectImage(img.first, img.second, img.third, inspectImage(img.first, img.second, img.third,
const_cast<functor::UnaryAnalyser<Functor> &>(f)); const_cast<functor::UnaryAnalyser<Functor> &>(f));
} }
template <class T, class S, class Functor>
inline void
inspectImage(MultiArrayView<2, T, S> const & img,
functor::UnaryAnalyser<Functor> const & f)
{
inspectImage(srcImageRange(img),
const_cast<functor::UnaryAnalyser<Functor> &>(f));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectImageIf */ /* inspectImageIf */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply read-only functor to every pixel in the ROI. /** \brief Apply read-only functor to every pixel in the ROI.
This function can be used to collect statistics of the roi etc. This function can be used to collect statistics of the ROI etc.
The functor is called whenever the return value of the mask's The functor is called whenever the return value of the mask's
accessor is not zero. accessor is not zero.
The results must be stored in the functor, which serves as a return The results must be stored in the functor, which serves as a return
value. value (and is therefore passed by reference.
Accessors are used to access the pixel and mask data.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S,
class TM, class SM, class Functor>
void
inspectImageIf(MultiArrayView<2, T, S> const & img,
MultiArrayView<2, TM, SM> const & mask,
Functor & f);
}
\endcode
\deprecatedAPI{inspectImageIf}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class Functo r> class MaskImageIterator, class MaskAccessor, class Functo r>
void void
inspectImageIf(ImageIterator upperleft, ImageIterator lowerright, inspectImageIf(ImageIterator upperleft, ImageIterator lowerright,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
Functor & f) Functor & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class Functor> class MaskImageIterator, class MaskAccessor, class Functor>
void void
inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img, inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
Functor & f) Functor & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, unsigned char> img(100, 100),
mask(100, 100);
... // fill img and mask
// init functor
FindMinMax<unsigned char> minmax;
inspectImageIf(img, mask, minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max;
\endcode
\deprecatedUsage{inspectImageIf}
\code \code
vigra::BImage img(100, 100); vigra::BImage img(100, 100);
vigra::BImage mask(100, 100); vigra::BImage mask(100, 100);
// init functor // init functor
vigra::FindMinMax<vigra::BImage::PixelType> minmax; vigra::FindMinMax<vigra::BImage::PixelType> minmax;
vigra::inspectImageIf(srcImageRange(img), vigra::inspectImageIf(srcImageRange(img),
maskImage(mask), minmax); maskImage(mask), minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max; cout << "Min: " << minmax.min << " Max: " << minmax.max;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ConstImageIterator upperleft, lowerright; ConstImageIterator upperleft, lowerright;
MaskImageIterator mask_upperleft; MaskImageIterator mask_upperleft;
ConstImageIterator::row_iterator ix = upperleft.rowIterator(); ConstImageIterator::row_iterator ix = upperleft.rowIterator();
MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator(); MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
Accessor accessor; Accessor accessor;
MaskAccessor mask_accessor; MaskAccessor mask_accessor;
Functor functor; Functor functor;
if(mask_accessor(mx)) functor(accessor(ix)); if(mask_accessor(mx)) functor(accessor(ix));
\endcode \endcode
\deprecatedEnd
\see InspectFunctor, FeatureAccumulators
*/ */
doxygen_overloaded_function(template <...> void inspectImageIf) doxygen_overloaded_function(template <...> void inspectImageIf)
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor> class MaskImageIterator, class MaskAccessor>
struct inspectImageIf_binder struct inspectImageIf_binder
{ {
ImageIterator upperleft; ImageIterator upperleft;
ImageIterator lowerright; ImageIterator lowerright;
Accessor a; Accessor a;
skipping to change at line 370 skipping to change at line 436
Functor & f) Functor & f)
{ {
inspectImageIf_binder<ImageIterator, Accessor, MaskImageIterator, inspectImageIf_binder<ImageIterator, Accessor, MaskImageIterator,
MaskAcce ssor> MaskAcce ssor>
g(upperleft, lowerright, a, mask_upperleft, ma); g(upperleft, lowerright, a, mask_upperleft, ma);
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class Functor> class MaskImageIterator, class MaskAccessor, class Functor>
inline
void
inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
pair<MaskImageIterator, MaskAccessor> mask,
Functor & f)
{
inspectImageIf(img.first, img.second, img.third,
mask.first, mask.second, f);
}
template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class Functor>
inline void inline void
inspectImageIf(ImageIterator upperleft, inspectImageIf(ImageIterator upperleft,
ImageIterator lowerright, Accessor a, ImageIterator lowerright, Accessor a,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
functor::UnaryAnalyser<Functor> const & f) functor::UnaryAnalyser<Functor> const & f)
{ {
inspectImageIf(upperleft, lowerright, a, inspectImageIf(upperleft, lowerright, a,
mask_upperleft, ma, const_cast<functor::UnaryAnalyser<Fu nctor> &>(f)); mask_upperleft, ma, const_cast<functor::UnaryAnalyser<Fu nctor> &>(f));
} }
template <class ImageIterator, class Accessor, template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class Functor> class MaskImageIterator, class MaskAccessor, class Functor>
inline void
inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
pair<MaskImageIterator, MaskAccessor> mask,
Functor & f)
{
inspectImageIf(img.first, img.second, img.third,
mask.first, mask.second, f);
}
template <class ImageIterator, class Accessor,
class MaskImageIterator, class MaskAccessor, class Functor>
inline void inline void
inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img, inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
functor::UnaryAnalyser<Functor> const & f) functor::UnaryAnalyser<Functor> const & f)
{ {
inspectImageIf(img.first, img.second, img.third, inspectImageIf(img.first, img.second, img.third,
mask.first, mask.second, const_cast<functor::UnaryAnalys er<Functor> &>(f)); mask.first, mask.second, const_cast<functor::UnaryAnalys er<Functor> &>(f));
} }
template <class T, class S,
class TM, class SM, class Functor>
inline void
inspectImageIf(MultiArrayView<2, T, S> const & img,
MultiArrayView<2, TM, SM> const & mask,
Functor & f)
{
vigra_precondition(img.shape() == mask.shape(),
"inspectImageIf(): shape mismatch between input and output.");
inspectImageIf(srcImageRange(img),
maskImage(mask), f);
}
template <class T, class S,
class TM, class SM, class Functor>
inline void
inspectImageIf(MultiArrayView<2, T, S> const & img,
MultiArrayView<2, TM, SM> const & mask,
functor::UnaryAnalyser<Functor> const & f)
{
inspectImageIf(srcImageRange(img),
maskImage(mask), const_cast<functor::UnaryAnalyser<Funct
or> &>(f));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectTwoImages */ /* inspectTwoImages */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply read-only functor to every pixel of both images. /** \brief Apply read-only functor to every pixel of both images.
This function can be used to collect statistics for each region of a This function can be used to collect statistics for each region of a
labeled image, especially in conjunction with labeled image, especially in conjunction with
the \ref ArrayOfRegionStatistics functor. The results must be the \ref ArrayOfRegionStatistics functor. The results must be
stored in the functor which serves as a return value. stored in the functor which serves as a return value.
Accessors are used to access the pixel data.
Note: For many common statistics, the use of \ref vigra::acc::extractFe
atures() in combination
with \ref FeatureAccumulators is more convenient.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Functor>
void
inspectTwoImages(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, T2, S2> const & img2,
Functor & f);
}
\endcode
\deprecatedAPI{inspectTwoImages}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class Functor> class Functor>
void void
inspectTwoImages(ImageIterator1 upperleft1, ImageIterator1 lowerrig ht1, Accessor1 a1, inspectTwoImages(ImageIterator1 upperleft1, ImageIterator1 lowerrig ht1, Accessor1 a1,
ImageIterator2 upperleft2, Accessor2 a2, ImageIterator2 upperleft2, Accessor2 a2,
Functor & f) Functor & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class Functor> class Functor>
void void
inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1, inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2, pair<ImageIterator2, Accessor2> img2,
Functor & f) Functor & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> image1(width, height), image2(width, heigh
t);
SomeStatisticsFunctor stats(...); // init functor
inspectTwoImages(image1, image2, stats);
\endcode
\deprecatedUsage{inspectTwoImages}
\code
vigra::BImage image1; vigra::BImage image1;
vigra::BImage image2; vigra::BImage image2;
SomeStatisticsFunctor stats(...); // init functor SomeStatisticsFunctor stats(...); // init functor
vigra::inspectTwoImages(srcImageRange(image1), srcImage(image2), vigra::inspectTwoImages(srcImageRange(image1), srcImage(image2),
stats); stats);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator1 upperleft1, lowerright1; ImageIterator1 upperleft1, lowerright1;
ImageIterator2 upperleft2; ImageIterator2 upperleft2;
ImageIterator1::row_iterator ix1 = upperleft1.rowIterator(); ImageIterator1::row_iterator ix1 = upperleft1.rowIterator();
ImageIterator2::row_iterator ix2 = upperleft2.rowIterator(); ImageIterator2::row_iterator ix2 = upperleft2.rowIterator();
Accessor1 accessor1; Accessor1 accessor1;
Accessor2 accessor2; Accessor2 accessor2;
Functor functor; Functor functor;
functor(accessor1(ix1), accessor2(ix2)); // return not used functor(accessor1(ix1), accessor2(ix2)); // return not used
\endcode \endcode
\deprecatedEnd
\see InspectFunctor, FeatureAccumulators
*/ */
doxygen_overloaded_function(template <...> void inspectTwoImages) doxygen_overloaded_function(template <...> void inspectTwoImages)
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2> class ImageIterator2, class Accessor2>
struct inspectTwoImages_binder struct inspectTwoImages_binder
{ {
ImageIterator1 upperleft1; ImageIterator1 upperleft1;
ImageIterator1 lowerright1; ImageIterator1 lowerright1;
Accessor1 a1; Accessor1 a1;
skipping to change at line 523 skipping to change at line 636
ImageIterator2 upperleft2, Accessor2 a2, ImageIterator2 upperleft2, Accessor2 a2,
Functor & f) Functor & f)
{ {
inspectTwoImages_binder<ImageIterator1, Accessor1, inspectTwoImages_binder<ImageIterator1, Accessor1,
ImageIterator2, Accessor2> ImageIterator2, Accessor2>
g(upperleft1, lowerright1, a1, upperleft2, a2); g(upperleft1, lowerright1, a1, upperleft2, a2);
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2,
class Functor>
inline
void
inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2,
Functor & f)
{
inspectTwoImages(img1.first, img1.second, img1.third,
img2.first, img2.second, f);
}
template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class Functor> class Functor>
inline void inline void
inspectTwoImages(ImageIterator1 upperleft1, ImageIterator1 lowerright1, Acc essor1 a1, inspectTwoImages(ImageIterator1 upperleft1, ImageIterator1 lowerright1, Acc essor1 a1,
ImageIterator2 upperleft2, Accessor2 a2, ImageIterator2 upperleft2, Accessor2 a2,
functor::UnaryAnalyser<Functor> const & f) functor::UnaryAnalyser<Functor> const & f)
{ {
inspectTwoImages(upperleft1, lowerright1, a1, inspectTwoImages(upperleft1, lowerright1, a1,
upperleft2, a2, const_cast<functor::UnaryAnalyser<Func tor> &>(f)); upperleft2, a2, const_cast<functor::UnaryAnalyser<Func tor> &>(f));
} }
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class Functor> class Functor>
inline inline void
void
inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1, inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2, pair<ImageIterator2, Accessor2> img2,
functor::UnaryAnalyser<Functor> const & f) Functor & f)
{
inspectTwoImages(img1.first, img1.second, img1.third,
img2.first, img2.second, f);
}
template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2,
class Functor>
inline void
inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2,
functor::UnaryAnalyser<Functor> const & f)
{ {
inspectTwoImages(img1.first, img1.second, img1.third, inspectTwoImages(img1.first, img1.second, img1.third,
img2.first, img2.second, const_cast<functor::UnaryAnal yser<Functor> &>(f)); img2.first, img2.second, const_cast<functor::UnaryAnal yser<Functor> &>(f));
} }
template <class T1, class S1,
class T2, class S2,
class Functor>
inline void
inspectTwoImages(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, T2, S2> const & img2,
Functor & f)
{
vigra_precondition(img1.shape() == img2.shape(),
"inspectTwoImages(): shape mismatch between input and output.");
inspectTwoImages(srcImageRange(img1),
srcImage(img2),
f);
}
template <class T1, class S1,
class T2, class S2,
class Functor>
inline void
inspectTwoImages(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, T2, S2> const & img2,
functor::UnaryAnalyser<Functor> const & f)
{
vigra_precondition(img1.shape() == img2.shape(),
"inspectTwoImages(): shape mismatch between input and output.");
inspectTwoImages(srcImageRange(img1),
srcImage(img2), const_cast<functor::UnaryAnalyser<Func
tor> &>(f));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectTwoImagesIf */ /* inspectTwoImagesIf */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply read-only functor to those pixels of both images where /** \brief Apply read-only functor to those pixels of both images where
the mask image is non-zero. the mask image is non-zero.
This function can be used to collect statistics for selected regions of a This function can be used to collect statistics for selected regions of a
labeled image, especially in conjunction with labeled image, especially in conjunction with
the \ref ArrayOfRegionStatistics functor. The results must be the \ref ArrayOfRegionStatistics functor. The results must be
stored in the functor which serves as a return value. stored in the functor which serves as a return value.
Accessors are used to access the pixel data.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class TM, class SM,
class Functor>
void
inspectTwoImagesIf(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, T2, S2> const & img2,
MultiArrayView<2, TM, SM> const & mask,
Functor & f);
}
\endcode
\deprecatedAPI{inspectTwoImagesIf}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class Functor> class Functor>
void void
inspectTwoImagesIf(ImageIterator1 upperleft1, ImageIterator1 lowerr ight1, Accessor1 a1, inspectTwoImagesIf(ImageIterator1 upperleft1, ImageIterator1 lowerr ight1, Accessor1 a1,
ImageIterator2 upperleft2, Accessor2 a2, ImageIterator2 upperleft2, Accessor2 a2,
MaskImageIterator mupperleft, MaskAccessor mask, MaskImageIterator mupperleft, MaskAccessor mask,
Functor & f) Functor & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class Functor> class Functor>
void void
inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1 > img1, inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1 > img1,
pair<ImageIterator2, Accessor2> img2, pair<ImageIterator2, Accessor2> img2,
pair<MaskImageIterator, MaskAccessor> mimg, pair<MaskImageIterator, MaskAccessor> mimg,
Functor & f) Functor & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, unsigned char> image1(width, height), image2(width, heigh
t),
maskimage(width, height);
SomeStatisticsFunctor stats(...); // init functor
inspectTwoImagesIf(image1, image2, maskimage, region_stats);
\endcode
\deprecatedUsage{inspectTwoImagesIf}
\code \code
vigra::BImage image1; vigra::BImage image1;
vigra::BImage image2; vigra::BImage image2;
vigra::BImage maskimage; vigra::BImage maskimage;
SomeStatisticsFunctor stats(...); // init functor SomeStatisticsFunctor stats(...); // init functor
vigra::inspectTwoImagesIf(srcImageRange(image1), srcImage(image2), vigra::inspectTwoImagesIf(srcImageRange(image1), srcImage(image2),
srcImage(maskimage), region_stats); srcImage(maskimage), region_stats);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator1 upperleft1, lowerright1; ImageIterator1 upperleft1, lowerright1;
ImageIterator2 upperleft2; ImageIterator2 upperleft2;
MaskImageIterator upperleftm; MaskImageIterator upperleftm;
ImageIterator1::row_iterator ix1 = upperleft1.rowIterator(); ImageIterator1::row_iterator ix1 = upperleft1.rowIterator();
ImageIterator2::row_iterator ix2 = upperleft2.rowIterator(); ImageIterator2::row_iterator ix2 = upperleft2.rowIterator();
MaskImageIterator::row_iterator mx = mupperleft.rowIterator(); MaskImageIterator::row_iterator mx = mupperleft.rowIterator();
Accessor1 accessor1; Accessor1 accessor1;
Accessor2 accessor2; Accessor2 accessor2;
MaskAccessor mask; MaskAccessor mask;
Functor functor; Functor functor;
if(mask(mx)) if(mask(mx))
functor(accessor1(ix1), accessor2(ix2)); functor(accessor1(ix1), accessor2(ix2));
\endcode \endcode
\deprecatedEnd
\see InspectFunctor, FeatureAccumulators
*/ */
doxygen_overloaded_function(template <...> void inspectTwoImagesIf) doxygen_overloaded_function(template <...> void inspectTwoImagesIf)
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor> class MaskImageIterator, class MaskAccessor>
struct inspectTwoImagesIf_binder struct inspectTwoImagesIf_binder
{ {
ImageIterator1 upperleft1; ImageIterator1 upperleft1;
ImageIterator1 lowerright1; ImageIterator1 lowerright1;
skipping to change at line 703 skipping to change at line 868
ImageIterator2, Accessor2, ImageIterator2, Accessor2,
MaskImageIterator, MaskAccessor> MaskImageIterator, MaskAccessor>
g(upperleft1, lowerright1, a1, upperleft2, a2, mupperleft, mask); g(upperleft1, lowerright1, a1, upperleft2, a2, mupperleft, mask);
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class Functor> class Functor>
inline
void
inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2,
pair<MaskImageIterator, MaskAccessor> m,
Functor & f)
{
inspectTwoImagesIf(img1.first, img1.second, img1.third,
img2.first, img2.second,
m.first, m.second,
f);
}
template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor,
class Functor>
inline void inline void
inspectTwoImagesIf(ImageIterator1 upperleft1, ImageIterator1 lowerright1, A ccessor1 a1, inspectTwoImagesIf(ImageIterator1 upperleft1, ImageIterator1 lowerright1, A ccessor1 a1,
ImageIterator2 upperleft2, Accessor2 a2, ImageIterator2 upperleft2, Accessor2 a2,
MaskImageIterator mupperleft, MaskAccessor mask, MaskImageIterator mupperleft, MaskAccessor mask,
functor::UnaryAnalyser<Functor> const & f) functor::UnaryAnalyser<Functor> const & f)
{ {
inspectTwoImagesIf(upperleft1, lowerright1, a1, inspectTwoImagesIf(upperleft1, lowerright1, a1,
upperleft2, a2, upperleft2, a2,
mupperleft, mask, mupperleft, mask,
const_cast<functor::UnaryAnalyser<Functor> &>(f)); const_cast<functor::UnaryAnalyser<Functor> &>(f));
} }
template <class ImageIterator1, class Accessor1, template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2, class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class Functor> class Functor>
inline inline void
void inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2,
pair<MaskImageIterator, MaskAccessor> m,
Functor & f)
{
inspectTwoImagesIf(img1.first, img1.second, img1.third,
img2.first, img2.second,
m.first, m.second,
f);
}
template <class ImageIterator1, class Accessor1,
class ImageIterator2, class Accessor2,
class MaskImageIterator, class MaskAccessor,
class Functor>
inline void
inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1> img1, inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
pair<ImageIterator2, Accessor2> img2, pair<ImageIterator2, Accessor2> img2,
pair<MaskImageIterator, MaskAccessor> m, pair<MaskImageIterator, MaskAccessor> m,
functor::UnaryAnalyser<Functor> const & f) functor::UnaryAnalyser<Functor> const & f)
{ {
inspectTwoImagesIf(img1.first, img1.second, img1.third, inspectTwoImagesIf(img1.first, img1.second, img1.third,
img2.first, img2.second, img2.first, img2.second,
m.first, m.second, m.first, m.second,
const_cast<functor::UnaryAnalyser<Functor> &>(f)); const_cast<functor::UnaryAnalyser<Functor> &>(f));
} }
template <class T1, class S1,
class T2, class S2,
class TM, class SM,
class Functor>
inline void
inspectTwoImagesIf(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, T2, S2> const & img2,
MultiArrayView<2, TM, SM> const & mask,
Functor & f)
{
vigra_precondition(img1.shape() == img2.shape() && img1.shape() == mask
.shape(),
"inspectTwoImagesIf(): shape mismatch between input and output.");
inspectTwoImagesIf(srcImageRange(img1),
srcImage(img2),
maskImage(mask),
f);
}
template <class T1, class S1,
class T2, class S2,
class TM, class SM,
class Functor>
inline void
inspectTwoImagesIf(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, T2, S2> const & img2,
MultiArrayView<2, TM, SM> const & mask,
functor::UnaryAnalyser<Functor> const & f)
{
vigra_precondition(img1.shape() == img2.shape() && img1.shape() == mask
.shape(),
"inspectTwoImagesIf(): shape mismatch between input and output.");
inspectTwoImagesIf(srcImageRange(img1),
srcImage(img2),
maskImage(mask),
const_cast<functor::UnaryAnalyser<Functor> &>(f));
}
//@} //@}
/** \addtogroup InspectFunctor Functors To Inspect Images /** \addtogroup InspectFunctor Functors To Inspect Images
Functors which report image statistics Functors which report image statistics
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* FindMinMax */ /* FindMinMax */
skipping to change at line 775 skipping to change at line 974
These functors can also be used in conjunction with These functors can also be used in conjunction with
\ref ArrayOfRegionStatistics to find the extremes of all regions in \ref ArrayOfRegionStatistics to find the extremes of all regions in
a labeled image. a labeled image.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> is true (<tt>VigraTrueType</tt> ) <tt>FunctorTraits::isUnaryAnalyser</tt> is true (<tt>VigraTrueType</tt> )
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
vigra::FindMinMax<vigra::BImage::PixelType> minmax; // init functor vigra::FindMinMax<vigra::BImage::PixelType> minmax; // init functor
vigra::inspectImage(srcImageRange(img), minmax); vigra::inspectImage(srcImageRange(img), minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max; cout << "Min: " << minmax.min << " Max: " << minmax.max;
skipping to change at line 918 skipping to change at line 1117
\ref ArrayOfRegionStatistics to find the sum of all regions in \ref ArrayOfRegionStatistics to find the sum of all regions in
a labeled image, and with the reduce mode of transformMultiArray(). a labeled image, and with the reduce mode of transformMultiArray().
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt> <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
vigra::FindSum<vigra::BImage::PixelType> sum; // init functor vigra::FindSum<vigra::BImage::PixelType> sum; // init functor
vigra::inspectImage(srcImageRange(img), sum); vigra::inspectImage(srcImageRange(img), sum);
cout << "Sum: " << sum(); cout << "Sum: " << sum();
skipping to change at line 1019 skipping to change at line 1218
\ref ArrayOfRegionStatistics to find the average of all regions in \ref ArrayOfRegionStatistics to find the average of all regions in
a labeled image. a labeled image.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt> <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
vigra::FindAverage<vigra::BImage::PixelType> average; // init functor vigra::FindAverage<vigra::BImage::PixelType> average; // init functor
vigra::inspectImage(srcImageRange(img), average); vigra::inspectImage(srcImageRange(img), average);
cout << "Average: " << average(); cout << "Average: " << average();
skipping to change at line 1167 skipping to change at line 1366
conjunction with \ref ArrayOfRegionStatistics to find the statistics of all conjunction with \ref ArrayOfRegionStatistics to find the statistics of all
regions in a labeled image. regions in a labeled image.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt> <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
vigra::FindAverageAndVariance<vigra::BImage::PixelType> averageAndVaria nce; // init functor vigra::FindAverageAndVariance<vigra::BImage::PixelType> averageAndVaria nce; // init functor
vigra::inspectImage(srcImageRange(img), averageAndVariance); vigra::inspectImage(srcImageRange(img), averageAndVariance);
cout << "Average: " << averageAndVariance.average() << "\n"; cout << "Average: " << averageAndVariance.average() << "\n";
cout << "Standard deviation: " << sqrt(averageAndVariance.variance()) < < "\n"; cout << "Standard deviation: " << sqrt(averageAndVariance.variance()) < < "\n";
skipping to change at line 1345 skipping to change at line 1544
a labeled image. a labeled image.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt> <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img, mask; vigra::BImage img, mask;
vigra::FindROISize<vigra::BImage::PixelType> roisize; // init functor vigra::FindROISize<vigra::BImage::PixelType> roisize; // init functor
vigra::inspectImageIf(srcImageRange(img), srcImage(mask), roisize); vigra::inspectImageIf(srcImageRange(img), srcImage(mask), roisize);
cout << "Size of ROI: " << roisize.count; cout << "Size of ROI: " << roisize.count;
skipping to change at line 1454 skipping to change at line 1653
of all regions in a labeled image. of all regions in a labeled image.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt> <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img, mask; vigra::BImage img, mask;
... ...
vigra::FindBoundingRectangle roiRect; // init functor vigra::FindBoundingRectangle roiRect; // init functor
// Diff2D is used as the iterator for the source image. This // Diff2D is used as the iterator for the source image. This
// simulates an image where each pixel value equals the pixel's // simulates an image where each pixel value equals the pixel's
// coordinates. The image 'mask' determines the ROI. // coordinates. The image 'mask' determines the ROI.
skipping to change at line 1600 skipping to change at line 1799
\ref ArrayOfRegionStatistics to realize a look-up table. \ref ArrayOfRegionStatistics to realize a look-up table.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt> <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitia lizer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
vigra::ArrayOfRegionStatistics<LastValueFunctor<unsigned char> > lut(25 5); vigra::ArrayOfRegionStatistics<LastValueFunctor<unsigned char> > lut(25 5);
for(int i=0; i<256; ++i) for(int i=0; i<256; ++i)
{ {
lut[i] = ...; // init look-up table lut[i] = ...; // init look-up table
} }
skipping to change at line 1696 skipping to change at line 1895
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryAnalyser</tt>, <tt>FunctorTraits::isBinaryAna lyser</tt> <tt>FunctorTraits::isUnaryAnalyser</tt>, <tt>FunctorTraits::isBinaryAna lyser</tt>
and <tt>FunctorTraits::isInitializer</tt> and <tt>FunctorTraits::isInitializer</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
... // fill the image ... // fill the image
// create a functor to sum the elements of the image // create a functor to sum the elements of the image
vigra::ReduceFunctor<std::plus<int>, int> sumElements(std::plus<int>, 0 ); vigra::ReduceFunctor<std::plus<int>, int> sumElements(std::plus<int>, 0 );
vigra::inspectImage(srcImageRange(img), sumElements); vigra::inspectImage(srcImageRange(img), sumElements);
skipping to change at line 1830 skipping to change at line 2029
pixel's label. pixel's label.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isBinaryAnalyser</tt> and <tt>FunctorTraits::isUnary Functor</tt> <tt>FunctorTraits::isBinaryAnalyser</tt> and <tt>FunctorTraits::isUnary Functor</tt>
are true (<tt>VigraTrueType</tt>) are true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/inspectimage.hxx\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage img; vigra::BImage img;
vigra::IImage labels; vigra::IImage labels;
int max_label; int max_label;
... ...
// init functor as an array of 'max_label' FindMinMax-Functors // init functor as an array of 'max_label' FindMinMax-Functors
vigra::ArrayOfRegionStatistics<vigra::FindMinMax<vigra::BImage::PixelTy pe> > vigra::ArrayOfRegionStatistics<vigra::FindMinMax<vigra::BImage::PixelTy pe> >
minmax(max_label); minmax(max_label);
 End of changes. 75 change blocks. 
112 lines changed or deleted 321 lines changed or added


 iteratoradapter.hxx   iteratoradapter.hxx 
skipping to change at line 35 skipping to change at line 35
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_ITERATORADAPTER_HXX #ifndef VIGRA_ITERATORADAPTER_HXX
#define VIGRA_ITERATORADAPTER_HXX #define VIGRA_ITERATORADAPTER_HXX
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* IteratorAdaptor */ /* IteratorAdaptor */
/* */ /* */
/********************************************************/ /********************************************************/
/*! \brief Quickly create 1-dimensional iterator adapters. /** \brief Quickly create 1-dimensional iterator adapters.
This class supports the easy creation of 1D iterator adapters out This class supports the easy creation of 1D iterator adapters out
of existing iterators. To use it, you must first implement a policy cla ss of existing iterators. To use it, you must first implement a policy cla ss
that defines the iterator's behavior. The policy is used to that defines the iterator's behavior. The policy is used to
instantiate the IteratorAdapter template, which thus automatically instantiate the IteratorAdapter template, which thus automatically
obtains all required functions of an STL-compatible iterator. obtains all required functions of an STL-compatible iterator.
General information on how this works can be found on the General information on how this works can be found on the
<a href="http://www.boost.org/libs/utility/iterator_adaptors.htm">Boost Iterator Adaptor</a> <a href="http://www.boost.org/libs/utility/iterator_adaptors.htm">Boost Iterator Adaptor</a>
page, although there are some differences in the details of the page, although there are some differences in the details of the
boost and VIGRA implementations. boost and VIGRA implementations.
skipping to change at line 298 skipping to change at line 297
pointer operator->() const pointer operator->() const
{ {
return &Policy::dereference(adaptee_); return &Policy::dereference(adaptee_);
} }
protected: protected:
BaseType adaptee_; BaseType adaptee_;
}; };
namespace detail_iterator_facade{
}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_ITERATORADAPTER_HXX */ #endif /* VIGRA_ITERATORADAPTER_HXX */
 End of changes. 3 change blocks. 
2 lines changed or deleted 5 lines changed or added


 labelimage.hxx   labelimage.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_LABELIMAGE_HXX #ifndef VIGRA_LABELIMAGE_HXX
#define VIGRA_LABELIMAGE_HXX #define VIGRA_LABELIMAGE_HXX
#include <vector> #include <vector>
#include <functional> #include <functional>
#include "utilities.hxx" #include "utilities.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "union_find.hxx" #include "union_find.hxx"
#include "sized_int.hxx" #include "sized_int.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup Labeling Connected Components Labeling /** \addtogroup Labeling Connected Components Labeling
The 2-dimensional connected components algorithms may use either 4 or 8 connectivity. The 2-dimensional connected components algorithms may use either 4 or 8 connectivity.
By means of a functor the merge criterion can be defined arbitrarily. By means of a functor the merge criterion can be defined arbitrarily.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* labelImage */ /* labelImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find the connected components of a segmented image. /** \brief Find the connected components of a segmented image.
Connected components are defined as regions with uniform pixel
values. Thus, <TT>T1</TT> either must be
equality comparable, or a suitable EqualityFunctor must be
provided that realizes the desired predicate. The
destination's value type <tt>T2</tt> should be large enough to hold the
labels
without overflow. Region numbers will be a consecutive sequence
starting with one and ending with the region number returned by
the function (inclusive). The parameter '<TT>eight_neighbors</TT>'
determines whether the regions should be 4-connected (false) or
8-connected (true).
Return: the number of regions found (= largest region label)
See \ref labelMultiArray() for a dimension-independent implementation o
f
connected components labelling.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class EqualityFunctor = std::equal_to<T1> >
unsigned int
labelImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool eight_neighbors, EqualityFunctor equal = EqualityFu
nctor());
}
\endcode
\deprecatedAPI{labelImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int labelImage(SrcIterator upperlefts, unsigned int labelImage(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors); bool eight_neighbors);
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class EqualityFunctor> class EqualityFunctor>
unsigned int labelImage(SrcIterator upperlefts, unsigned int labelImage(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors, EqualityFunctor equal ); bool eight_neighbors, EqualityFunctor equal );
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccesso r> src, unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
bool eight_neighbors); bool eight_neighbors);
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class EqualityFunctor> class EqualityFunctor>
unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccesso r> src, unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
bool eight_neighbors, EqualityFunctor equal ) bool eight_neighbors, EqualityFunctor equal )
} }
\endcode \endcode
\deprecatedEnd
Connected components are defined as regions with uniform pixel
values. Thus, <TT>SrcAccessor::value_type</TT> either must be
equality comparable (first form), or an EqualityFunctor must be
provided that realizes the desired predicate (second form). The
destination's value type should be large enough to hold the labels
without overflow. Region numbers will be a consecutive sequence
starting with one and ending with the region number returned by
the function (inclusive). The parameter '<TT>eight_neighbors</TT>'
determines whether the regions should be 4-connected or
8-connected. The function uses accessors.
Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/labelimage.hxx\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
MultiArray<2, unsigned int> labels(w,h);
// threshold at 128
transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
// find 4-connected regions
labelImage(src, labels, false);
\endcode
\deprecatedUsage{labelImage}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
vigra::IImage labels(w,h); vigra::IImage labels(w,h);
// threshold at 128 // threshold at 128
vigra::transformImage(srcImageRange(src), destImage(src), vigra::transformImage(srcImageRange(src), destImage(src),
vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType> ( vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType> (
128, 256, 0, 255)); 128, 256, 0, 255));
// find 4-connected regions // find 4-connected regions
vigra::labelImage(srcImageRange(src), destImage(labels), false); vigra::labelImage(srcImageRange(src), destImage(labels), false);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u == u // first form u == u // first form
EqualityFunctor equal; // second form EqualityFunctor equal; // second form
equal(u, u) // second form equal(u, u) // second form
int i; int i;
dest_accessor.set(i, dest_upperleft); dest_accessor.set(i, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int labelImage) doxygen_overloaded_function(template <...> unsigned int labelImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class EqualityFunctor> class EqualityFunctor>
unsigned int labelImage(SrcIterator upperlefts, unsigned int labelImage(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors, EqualityFunctor equal) bool eight_neighbors, EqualityFunctor equal)
{ {
typedef typename DestAccessor::value_type LabelType; typedef typename DestAccessor::value_type LabelType;
int w = lowerrights.x - upperlefts.x; int w = lowerrights.x - upperlefts.x;
int h = lowerrights.y - upperlefts.y; int h = lowerrights.y - upperlefts.y;
int x,y,i; int x,y,i;
static const Diff2D neighbor[] = { const Diff2D neighbor[] = {
Diff2D(-1,0), // left Diff2D(-1,0), // left
Diff2D(-1,-1), // topleft Diff2D(-1,-1), // topleft
Diff2D(0,-1), // top Diff2D(0,-1), // top
Diff2D(1,-1) // topright Diff2D(1,-1) // topright
}; };
static const int left = 0, /* unused: topleft = 1, */ top = 2, toprigh t = 3; const int left = 0, /* unused: topleft = 1, */ top = 2, topright = 3;
int step = eight_neighbors ? 1 : 2; int step = eight_neighbors ? 1 : 2;
SrcIterator ys = upperlefts; SrcIterator ys = upperlefts;
DestIterator yd = upperleftd; DestIterator yd = upperleftd;
detail::UnionFindArray<LabelType> label; UnionFindArray<LabelType> label;
// pass 1: scan image from upper left to lower right // pass 1: scan image from upper left to lower right
// to find connected components // to find connected components
// Each component will be represented by a tree of pixels. Each // Each component will be represented by a tree of pixels. Each
// pixel contains the scan order address of its parent in the // pixel contains the scan order address of its parent in the
// tree. In order for pass 2 to work correctly, the parent must // tree. In order for pass 2 to work correctly, the parent must
// always have a smaller scan order address than the child. // always have a smaller scan order address than the child.
// Therefore, we can merge trees only at their roots, because the // Therefore, we can merge trees only at their roots, because the
// root of the combined tree must have the smallest scan order // root of the combined tree must have the smallest scan order
skipping to change at line 215 skipping to change at line 243
for(x = 0; x != w; ++x, ++xs.x, ++xd.x) for(x = 0; x != w; ++x, ++xs.x, ++xd.x)
{ {
int beginNeighbor = (x == 0) ? top : left; int beginNeighbor = (x == 0) ? top : left;
if(x == w-1 && endNeighbor == topright) endNeighbor = top; if(x == w-1 && endNeighbor == topright) endNeighbor = top;
for(i=beginNeighbor; i<=endNeighbor; i+=step) for(i=beginNeighbor; i<=endNeighbor; i+=step)
{ {
if(equal(sa(xs), sa(xs, neighbor[i]))) if(equal(sa(xs), sa(xs, neighbor[i])))
{ {
LabelType neighborLabel = label.find(da(xd,neighbor[i]) ); LabelType neighborIndex = label.findIndex(da(xd,neighbo r[i]));
for(int j=i+2; j<=endNeighbor; j+=step) for(int j=i+2; j<=endNeighbor; j+=step)
{ {
if(equal(sa(xs), sa(xs, neighbor[j]))) if(equal(sa(xs), sa(xs, neighbor[j])))
{ {
neighborLabel = label.makeUnion(da(xd, neighbor [j]), neighborLabel); neighborIndex = label.makeUnion(da(xd, neighbor [j]), neighborIndex);
break; break;
} }
} }
da.set(neighborLabel, xd); da.set(neighborIndex, xd);
break; break;
} }
} }
if(i > endNeighbor) if(i > endNeighbor)
{ {
da.set(label.makeNewLabel(), xd); da.set(label.makeNewIndex(), xd);
} }
} }
} }
// pass 2: assign one label to each region (tree) // pass 2: assign one label to each region (tree)
// so that labels form a consecutive sequence 1, 2, ... // so that labels form a consecutive sequence 1, 2, ...
unsigned int count = label.makeContiguous(); unsigned int count = label.makeContiguous();
yd = upperleftd; yd = upperleftd;
for(y=0; y != h; ++y, ++yd.y) for(y=0; y != h; ++y, ++yd.y)
{ {
typename DestIterator::row_iterator xd = yd.rowIterator(); typename DestIterator::row_iterator xd = yd.rowIterator();
for(x = 0; x != w; ++x, ++xd) for(x = 0; x != w; ++x, ++xd)
{ {
da.set(label[da(xd)], xd); da.set(label.findLabel(da(xd)), xd);
} }
} }
return count; return count;
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class EqualityFunctor>
inline
unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
bool eight_neighbors, EqualityFunctor equal)
{
return labelImage(src.first, src.second, src.third,
dest.first, dest.second, eight_neighbors, equal);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
unsigned int labelImage(SrcIterator upperlefts, unsigned int labelImage(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors) bool eight_neighbors)
{ {
return labelImage(upperlefts, lowerrights, sa, return labelImage(upperlefts, lowerrights, sa,
upperleftd, da, eight_neighbors, upperleftd, da, eight_neighbors,
std::equal_to<typename SrcAccessor::value_type>()); std::equal_to<typename SrcAccessor::value_type>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class EqualityFunctor>
inline unsigned int
labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
bool eight_neighbors, EqualityFunctor equal)
{
return labelImage(src.first, src.second, src.third,
dest.first, dest.second, eight_neighbors, equal);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline unsigned int
unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
bool eight_neighbors) bool eight_neighbors)
{ {
return labelImage(src.first, src.second, src.third, return labelImage(src.first, src.second, src.third,
dest.first, dest.second, eight_neighbors, dest.first, dest.second, eight_neighbors,
std::equal_to<typename SrcAccessor::value_type>()); std::equal_to<typename SrcAccessor::value_type>());
}
template <class T1, class S1,
class T2, class S2,
class EqualityFunctor>
inline unsigned int
labelImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool eight_neighbors, EqualityFunctor equal)
{
vigra_precondition(src.shape() == dest.shape(),
"labelImage(): shape mismatch between input and output.");
return labelImage(srcImageRange(src),
destImage(dest), eight_neighbors, equal);
}
template <class T1, class S1,
class T2, class S2>
inline unsigned int
labelImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool eight_neighbors)
{
return labelImage(srcImageRange(src),
destImage(dest), eight_neighbors,
std::equal_to<T1>());
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* labelImageWithBackground */ /* labelImageWithBackground */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find the connected components of a segmented image, /** \brief Find the connected components of a segmented image,
excluding the background from labeling. excluding the background from labeling.
This function works like \ref labelImage(), but considers all backgroun
d pixels
(i.e. pixels having the given '<TT>background_value</TT>') as a single
region that
is ignored when determining connected components and remains untouched
in the
destination image. Usually, you will zero-initialize the output image,
so that
the background gets label 0 (remember that actual region labels start a
t one).
Return: the number of non-background regions found (= largest region l
abel)
See \ref labelMultiArrayWithBackground() for a dimension-independent im
plementation
if this algorithm.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class ValueType,
class EqualityFunctor = std::equal_to<T1> >
unsigned int
labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool eight_neighbors,
ValueType background_value,
EqualityFunctor equal = EqualityFunctor())
;
}
\endcode
\deprecatedAPI{labelImageWithBackground}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType> class ValueType>
int labelImageWithBackground(SrcIterator upperlefts, int labelImageWithBackground(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors, bool eight_neighbors,
ValueType background_value ); ValueType background_value );
skipping to change at line 323 skipping to change at line 405
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType, class EqualityFunctor> class ValueType, class EqualityFunctor>
int labelImageWithBackground(SrcIterator upperlefts, int labelImageWithBackground(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors, bool eight_neighbors,
ValueType background_value, EqualityFunctor equal); ValueType background_value, EqualityFunctor equal);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType> class ValueType>
int labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAc cessor> src, int labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
bool eight_neighbors, bool eight_neighbors,
ValueType background_value); ValueType background_value);
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType, class EqualityFunctor> class ValueType, class EqualityFunctor>
int labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAc cessor> src, int labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
bool eight_neighbors, bool eight_neighbors,
ValueType background_value, EqualityFu nctor equal); ValueType background_value, EqualityFu nctor equal);
} }
\endcode \endcode
\deprecatedEnd
Connected components are defined as regions with uniform pixel
values. Thus, <TT>SrcAccessor::value_type</TT> either must be
equality comparable (first form), or an EqualityFunctor must be
provided that realizes the desired predicate (second form). All
pixel equal to the given '<TT>background_value</TT>' are ignored
when determining connected components and remain untouched in the
destination image and
The destination's value type should be large enough to hold the
labels without overflow. Region numbers will be a consecutive
sequence starting with one and ending with the region number
returned by the function (inclusive). The parameter
'<TT>eight_neighbors</TT>' determines whether the regions should
be 4-connected or 8-connected. The function uses accessors.
Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/labelimage.hxx\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
MultiArray<2, unsigned int> labels(w,h);
// threshold at 128
transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
// find 4-connected regions of foreground (= white pixels) only
labelImageWithBackground(src, labels, false, 0);
\endcode
\deprecatedUsage{labelImageWithBackground}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
vigra::IImage labels(w,h); vigra::IImage labels(w,h);
// threshold at 128 // threshold at 128
vigra::transformImage(srcImageRange(src), destImage(src), vigra::transformImage(srcImageRange(src), destImage(src),
vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType >( vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType >(
128, 256, 0, 255)); 128, 256, 0, 255));
// find 4-connected regions of foreground (= white pixels) only // find 4-connected regions of foreground (= white pixels) only
vigra::labelImageWithBackground(srcImageRange(src), destImage(labels), vigra::labelImageWithBackground(srcImageRange(src), destImage(labels),
false, 0); false, 0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
ValueType background_value; ValueType background_value;
u == u // first form u == u // first form
u == background_value // first form u == background_value // first form
EqualityFunctor equal; // second form EqualityFunctor equal; // second form
equal(u, u) // second form equal(u, u) // second form
equal(u, background_value) // second form equal(u, background_value) // second form
int i; int i;
dest_accessor.set(i, dest_upperleft); dest_accessor.set(i, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int labelImageWithBackg round) doxygen_overloaded_function(template <...> unsigned int labelImageWithBackg round)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType, class EqualityFunctor> class ValueType, class EqualityFunctor>
unsigned int labelImageWithBackground( unsigned int labelImageWithBackground(
SrcIterator upperlefts, SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
bool eight_neighbors, bool eight_neighbors,
ValueType background_value, EqualityFunctor equal) ValueType background_value, EqualityFunctor equal)
{ {
int w = lowerrights.x - upperlefts.x; int w = lowerrights.x - upperlefts.x;
int h = lowerrights.y - upperlefts.y; int h = lowerrights.y - upperlefts.y;
int x,y,i; int x,y,i;
static const Diff2D neighbor[] = { const Diff2D neighbor[] = {
Diff2D(-1,0), // left Diff2D(-1,0), // left
Diff2D(-1,-1), // topleft Diff2D(-1,-1), // topleft
Diff2D(0,-1), // top Diff2D(0,-1), // top
Diff2D(1,-1) // topright Diff2D(1,-1) // topright
}; };
static const int left = 0, /* unused: topleft = 1,*/ top = 2, topright = 3; const int left = 0, /* unused: topleft = 1,*/ top = 2, topright = 3;
int step = eight_neighbors ? 1 : 2; int step = eight_neighbors ? 1 : 2;
SrcIterator ys(upperlefts); SrcIterator ys(upperlefts);
SrcIterator xs(ys); SrcIterator xs(ys);
// temporary image to store region labels // temporary image to store region labels
typedef BasicImage<IntBiggest> TmpImage; typedef BasicImage<IntBiggest> TmpImage;
TmpImage labelimage(w, h); TmpImage labelimage(w, h);
TmpImage::ScanOrderIterator label = labelimage.begin(); TmpImage::ScanOrderIterator label = labelimage.begin();
TmpImage::Iterator yt = labelimage.upperLeft(); TmpImage::Iterator yt = labelimage.upperLeft();
skipping to change at line 466 skipping to change at line 541
} }
else else
{ {
int beginNeighbor = (x == 0) ? top : left; int beginNeighbor = (x == 0) ? top : left;
if(x == w-1 && endNeighbor == topright) endNeighbor = top; if(x == w-1 && endNeighbor == topright) endNeighbor = top;
for(i=beginNeighbor; i<=endNeighbor; i+=step) for(i=beginNeighbor; i<=endNeighbor; i+=step)
{ {
if(equal(sa(xs), sa(xs, neighbor[i]))) if(equal(sa(xs), sa(xs, neighbor[i])))
{ {
IntBiggest neighborLabel = xt[neighbor[i]]; IntBiggest neighborIndex = xt[neighbor[i]];
for(int j=i+2; j<=endNeighbor; j+=step) for(int j=i+2; j<=endNeighbor; j+=step)
{ {
if(equal(sa(xs), sa(xs, neighbor[j]))) if(equal(sa(xs), sa(xs, neighbor[j])))
{ {
IntBiggest neighborLabel1 = xt[neighbor[j]] ; IntBiggest neighborLabel1 = xt[neighbor[j]] ;
if(neighborLabel != neighborLabel1) if(neighborIndex != neighborLabel1)
{ {
// find roots of the region trees // find roots of the region trees
while(neighborLabel != label[neighborLa bel]) while(neighborIndex != label[neighborIn dex])
{ {
neighborLabel = label[neighborLabel ]; neighborIndex = label[neighborIndex ];
} }
while(neighborLabel1 != label[neighborL abel1]) while(neighborLabel1 != label[neighborL abel1])
{ {
neighborLabel1 = label[neighborLabe l1]; neighborLabel1 = label[neighborLabe l1];
} }
// merge the trees // merge the trees
if(neighborLabel1 < neighborLabel) if(neighborLabel1 < neighborIndex)
{ {
label[neighborLabel] = neighborLabe label[neighborIndex] = neighborLabe
l1; l1;
neighborLabel = neighborLabel1; neighborIndex = neighborLabel1;
} }
else if(neighborLabel < neighborLabel1) else if(neighborIndex < neighborLabel1)
{ {
label[neighborLabel1] = neighborLab el; label[neighborLabel1] = neighborInd ex;
} }
} }
break; break;
} }
} }
*xt = neighborLabel; *xt = neighborIndex;
break; break;
} }
} }
if(i > endNeighbor) if(i > endNeighbor)
{ {
// new region // new region
// The initial label of a new region equals the // The initial label of a new region equals the
// scan order address of it's first pixel. // scan order address of it's first pixel.
// This is essential for correct operation of the algor ithm. // This is essential for correct operation of the algor ithm.
skipping to change at line 546 skipping to change at line 621
} }
da.set(label[i]+1, xd); da.set(label[i]+1, xd);
} }
} }
return count; return count;
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType, class EqualityFunctor> class ValueType>
inline inline
unsigned int labelImageWithBackground( unsigned int labelImageWithBackground(
triple<SrcIterator, SrcIterator, SrcAccessor> src, SrcIterator upperlefts,
pair<DestIterator, DestAccessor> dest, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da,
bool eight_neighbors, bool eight_neighbors,
ValueType background_value, EqualityFunctor equal) ValueType background_value)
{
return labelImageWithBackground(upperlefts, lowerrights, sa,
upperleftd, da,
eight_neighbors, background_value,
std::equal_to<typename SrcAccessor::value_type>
());
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class ValueType, class EqualityFunctor>
inline unsigned int
labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
bool eight_neighbors,
ValueType background_value, EqualityFunctor equal)
{ {
return labelImageWithBackground(src.first, src.second, src.third, return labelImageWithBackground(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
eight_neighbors, background_value, equa l); eight_neighbors, background_value, equa l);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class ValueType> class ValueType>
inline inline unsigned int
unsigned int labelImageWithBackground( labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, bool eight_neighbors,
bool eight_neighbors, ValueType background_value)
ValueType background_value)
{ {
return labelImageWithBackground(src.first, src.second, src.third, return labelImageWithBackground(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
eight_neighbors, background_value, eight_neighbors, background_value,
std::equal_to<typename SrcAccessor::value_type> std::equal_to<typename SrcAccessor::val
()); ue_type>());
} }
template <class SrcIterator, class SrcAccessor, template <class T1, class S1,
class DestIterator, class DestAccessor, class T2, class S2,
class ValueType, class EqualityFunctor>
inline unsigned int
labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool eight_neighbors,
ValueType background_value, EqualityFunctor equal)
{
vigra_precondition(src.shape() == dest.shape(),
"labelImageWithBackground(): shape mismatch between input and outpu
t.");
return labelImageWithBackground(srcImageRange(src),
destImage(dest),
eight_neighbors, background_value, equa
l);
}
template <class T1, class S1,
class T2, class S2,
class ValueType> class ValueType>
inline inline unsigned int
unsigned int labelImageWithBackground( labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
SrcIterator upperlefts, MultiArrayView<2, T2, S2> dest,
SrcIterator lowerrights, SrcAccessor sa, bool eight_neighbors,
DestIterator upperleftd, DestAccessor da, ValueType background_value)
bool eight_neighbors,
ValueType background_value)
{ {
return labelImageWithBackground(upperlefts, lowerrights, sa, vigra_precondition(src.shape() == dest.shape(),
upperleftd, da, "labelImageWithBackground(): shape mismatch between input and outpu
eight_neighbors, background_value, t.");
std::equal_to<typename SrcAccessor::value_type> return labelImageWithBackground(srcImageRange(src),
()); destImage(dest),
eight_neighbors, background_value,
std::equal_to<T1>());
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* regionImageToCrackEdgeImage */ /* regionImageToCrackEdgeImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Transform a labeled image into a crack edge image. /** \brief Transform a labeled image into a crack edge (interpixel edge) im age.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2, class DestValue>
void
regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DestValue edge_marker);
}
\endcode
\deprecatedAPI{regionImageToCrackEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
void regionImageToCrackEdgeImage( void regionImageToCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue edge_marker) DestValue edge_marker)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
void regionImageToCrackEdgeImage( void regionImageToCrackEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue edge_marker) DestValue edge_marker)
} }
\endcode \endcode
\deprecatedEnd
This algorithm inserts border pixels (so called "crack edges") This algorithm inserts border pixels (so called "crack edges" or "inter pixel edges")
between regions in a labeled image like this (<TT>a</TT> and between regions in a labeled image like this (<TT>a</TT> and
<TT>c</TT> are the original labels, and <TT>0</TT> is the value of <TT>c</TT> are the original labels, and <TT>0</TT> is the value of
<TT>edge_marker</TT> and denotes the inserted edges): <TT>edge_marker</TT> and denotes the inserted edges):
\code \code
original image insert zero- and one-cells original image insert zero- and one-cells
a 0 c c c a 0 c c c
a c c a 0 0 0 c a c c a 0 0 0 c
a a c => a a a 0 c a a c => a a a 0 c
skipping to change at line 652 skipping to change at line 771
no background. Therefore, it is suitable as a post-processing no background. Therefore, it is suitable as a post-processing
operation of \ref labelImage() or \ref seededRegionGrowing(). operation of \ref labelImage() or \ref seededRegionGrowing().
The destination image must be twice the size of the original The destination image must be twice the size of the original
(precisely, <TT>(2*w-1)</TT> by <TT>(2*h-1)</TT> pixels). The (precisely, <TT>(2*w-1)</TT> by <TT>(2*h-1)</TT> pixels). The
source value type (<TT>SrcAccessor::value-type</TT>) must be source value type (<TT>SrcAccessor::value-type</TT>) must be
equality-comparable. equality-comparable.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/labelimage.hxx\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h);
MultiArray<2, unsigned int> labels(w,h),
cellgrid(2*w-1, 2*h-1);
// threshold at 128
transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
// find 4-connected regions
labelImage(src, labels, false);
// create cell grid image, mark edges with 0
regionImageToCrackEdgeImage(labels, cellgrid, 0);
\endcode
\deprecatedUsage{regionImageToCrackEdgeImage}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
vigra::IImage labels(w,h); vigra::IImage labels(w,h);
vigra::IImage cellgrid(2*w-1, 2*h-1); vigra::IImage cellgrid(2*w-1, 2*h-1);
// threshold at 128 // threshold at 128
vigra::transformImage(srcImageRange(src), destImage(src), vigra::transformImage(srcImageRange(src), destImage(src),
vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType> ( vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType> (
128, 256, 0, 255)); 128, 256, 0, 255));
// find 4-connected regions // find 4-connected regions
vigra::labelImage(srcImageRange(src), destImage(labels), false); vigra::labelImage(srcImageRange(src), destImage(labels), false);
// create cell grid image, mark edges with 0 // create cell grid image, mark edges with 0
vigra::regionImageToCrackEdgeImage(srcImageRange(labels), destImage(cel lgrid), 0); vigra::regionImageToCrackEdgeImage(srcImageRange(labels), destImage(cel lgrid), 0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator src_upperleft, src_lowerright; ImageIterator src_upperleft, src_lowerright;
ImageIterator dest_upperleft; ImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u != u u != u
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft); dest_accessor.set(edge_marker, dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
The destination image must have twice the size of the source: The destination image must have twice the size of the source:
\code \code
w_dest = 2 * w_src - 1 w_dest = 2 * w_src - 1
h_dest = 2 * h_src - 1 h_dest = 2 * h_src - 1
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void regionImageToCrackEdgeImage ) doxygen_overloaded_function(template <...> void regionImageToCrackEdgeImage )
skipping to change at line 710 skipping to change at line 844
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
void regionImageToCrackEdgeImage( void regionImageToCrackEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue edge_marker) DestValue edge_marker)
{ {
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
int x,y; int x,y;
static const Diff2D right(1,0); const Diff2D right(1,0);
static const Diff2D left(-1,0); const Diff2D left(-1,0);
static const Diff2D bottomright(1,1); const Diff2D bottomright(1,1);
static const Diff2D bottom(0,1); const Diff2D bottom(0,1);
static const Diff2D top(0,-1); const Diff2D top(0,-1);
SrcIterator iy = sul; SrcIterator iy = sul;
DestIterator dy = dul; DestIterator dy = dul;
for(y=0; y<h-1; ++y, ++iy.y, dy.y+=2) for(y=0; y<h-1; ++y, ++iy.y, dy.y+=2)
{ {
SrcIterator ix = iy; SrcIterator ix = iy;
DestIterator dx = dy; DestIterator dx = dy;
for(x=0; x<w-1; ++x, ++ix.x, dx.x+=2) for(x=0; x<w-1; ++x, ++ix.x, dx.x+=2)
skipping to change at line 778 skipping to change at line 912
} }
else else
{ {
da.set(sa(ix), dx, right); da.set(sa(ix), dx, right);
} }
} }
da.set(sa(ix), dx); da.set(sa(ix), dx);
dy = dul + Diff2D(1,1); dy = dul + Diff2D(1,1);
const Diff2D dist[] = {right, top, left, bottom };
// find missing 0-cells // find missing 0-cells
for(y=0; y<h-1; ++y, dy.y+=2) for(y=0; y<h-1; ++y, dy.y+=2)
{ {
DestIterator dx = dy; DestIterator dx = dy;
for(x=0; x<w-1; ++x, dx.x+=2) for(x=0; x<w-1; ++x, dx.x+=2)
{ {
static const Diff2D dist[] = {right, top, left, bottom };
int i; int i;
for(i=0; i<4; ++i) for(i=0; i<4; ++i)
{ {
if(da(dx, dist[i]) == edge_marker) break; if(da(dx, dist[i]) == edge_marker) break;
} }
if(i < 4) da.set(edge_marker, dx); if(i < 4) da.set(edge_marker, dx);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline inline void
void regionImageToCrackEdgeImage( regionImageToCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> s
triple<SrcIterator, SrcIterator, SrcAccessor> src, rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue edge_marker) DestValue edge_marker)
{ {
regionImageToCrackEdgeImage(src.first, src.second, src.third, regionImageToCrackEdgeImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
edge_marker); edge_marker);
}
template <class T1, class S1,
class T2, class S2, class DestValue>
inline void
regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DestValue edge_marker)
{
vigra_precondition(2*src.shape()-Shape2(1) == dest.shape(),
"regionImageToCrackEdgeImage(): shape mismatch between input and ou
tput.");
regionImageToCrackEdgeImage(srcImageRange(src),
destImage(dest),
edge_marker);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* regionImageToEdgeImage */ /* regionImageToEdgeImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Transform a labeled image into an edge image. /** \brief Transform a labeled image into an edge image.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2, class DestValue>
void
regionImageToEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DestValue edge_marker);
}
\endcode
\deprecatedAPI{regionImageToEdgeImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
void regionImageToEdgeImage( void regionImageToEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue edge_marker) DestValue edge_marker)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
void regionImageToEdgeImage( void regionImageToEdgeImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue edge_marker) DestValue edge_marker)
} }
\endcode \endcode
\deprecatedEnd
This algorithm marks all pixels with the given <TT>edge_marker</TT> This algorithm marks all pixels with the given <TT>edge_marker</TT>
which belong to a different region (label) than their right or lower which belong to a different region (label) than their right or lower
neighbors: neighbors:
\code \code
original image edges original image edges
(assuming edge_marker == 1) (assuming edge_marker == 1)
a c c 1 1 * a c c 1 1 *
a a c => * 1 1 a a c => * 1 1
a a a * * * a a a * * *
\endcode \endcode
The non-edge pixels of the destination image will not be touched. The non-edge pixels of the destination image will not be touched.
The source value type (<TT>SrcAccessor::value-type</TT>) must be The source value type <TT>T1</TT> must be
equality-comparable. equality-comparable.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/labelimage.hxx\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h),
edges(w,h);
MultiArray<2, unsigned int> labels(w,h);
edges = 255; // init background (non-edge) to 255
// threshold at 128
transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
// find 4-connected regions
labelImage(src, labels, false);
// create edge image, mark edges with 0
regionImageToEdgeImage(labels, edges, 0);
\endcode
\deprecatedUsage{regionImageToEdgeImage}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
vigra::IImage labels(w,h); vigra::IImage labels(w,h);
vigra::IImage edges(w, h); vigra::IImage edges(w, h);
edges = 255; // init background (non-edge) to 255 edges = 255; // init background (non-edge) to 255
// threshold at 128 // threshold at 128
vigra::transformImage(srcImageRange(src), destImage(src), vigra::transformImage(srcImageRange(src), destImage(src),
vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>( vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(
128, 256, 0, 255)); 128, 256, 0, 255));
// find 4-connected regions // find 4-connected regions
vigra::labelImage(srcImageRange(src), destImage(labels), false); vigra::labelImage(srcImageRange(src), destImage(labels), false);
// create edge image, mark edges with 0 // create edge image, mark edges with 0
vigra::regionImageToEdgeImage(srcImageRange(labels), destImage(edges), 0); vigra::regionImageToEdgeImage(srcImageRange(labels), destImage(edges), 0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator src_upperleft, src_lowerright; ImageIterator src_upperleft, src_lowerright;
ImageIterator dest_upperleft; ImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u != u u != u
DestValue edge_marker; DestValue edge_marker;
dest_accessor.set(edge_marker, dest_upperleft); dest_accessor.set(edge_marker, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void regionImageToEdgeImage) doxygen_overloaded_function(template <...> void regionImageToEdgeImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
void regionImageToEdgeImage( void regionImageToEdgeImage(
SrcIterator sul, SrcIterator slr, SrcAccessor sa, SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue edge_marker) DestValue edge_marker)
{ {
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
int x,y; int x,y;
static const Diff2D right(1,0); const Diff2D right(1,0);
static const Diff2D left(-1,0); const Diff2D left(-1,0);
static const Diff2D bottomright(1,1); const Diff2D bottomright(1,1);
static const Diff2D bottom(0,1); const Diff2D bottom(0,1);
static const Diff2D top(0,-1); const Diff2D top(0,-1);
SrcIterator iy = sul; SrcIterator iy = sul;
DestIterator dy = dul; DestIterator dy = dul;
for(y=0; y<h-1; ++y, ++iy.y, ++dy.y) for(y=0; y<h-1; ++y, ++iy.y, ++dy.y)
{ {
SrcIterator ix = iy; SrcIterator ix = iy;
DestIterator dx = dy; DestIterator dx = dy;
for(x=0; x<w-1; ++x, ++ix.x, ++dx.x) for(x=0; x<w-1; ++x, ++ix.x, ++dx.x)
skipping to change at line 962 skipping to change at line 1137
{ {
if(sa(ix, right) != sa(ix)) if(sa(ix, right) != sa(ix))
{ {
da.set(edge_marker, dx); da.set(edge_marker, dx);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline inline void
void regionImageToEdgeImage( regionImageToEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, DestValue edge_marker)
DestValue edge_marker)
{ {
regionImageToEdgeImage(src.first, src.second, src.third, regionImageToEdgeImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
edge_marker); edge_marker);
}
template <class T1, class S1,
class T2, class S2, class DestValue>
inline void
regionImageToEdgeImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DestValue edge_marker)
{
vigra_precondition(src.shape() == dest.shape(),
"regionImageToEdgeImage(): shape mismatch between input and output.
");
regionImageToEdgeImage(srcImageRange(src),
destImage(dest),
edge_marker);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_LABELIMAGE_HXX #endif // VIGRA_LABELIMAGE_HXX
 End of changes. 77 change blocks. 
149 lines changed or deleted 354 lines changed or added


 labelvolume.hxx   labelvolume.hxx 
skipping to change at line 59 skipping to change at line 59
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* labelVolume */ /* labelVolume */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find the connected components of a segmented volume. /** \brief Find the connected components of a segmented volume.
Connected components are defined as regions with uniform voxel
values. Thus, <TT>T1</TT> either must be equality comparable,
or an EqualityFunctor must be provided explicitly that realizes
the desired equivalence predicate. The destination's value type
<tt>T2</tt> should be large enough to hold the labels
without overflow. Region numbers will be a consecutive sequence
starting with one and ending with the region number returned by
the function (inclusive).
Return: the number of regions found (= largest region label)
See \ref labelMultiArray() for a dimension-independent implementation o
f
connected components labelling.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 3D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Neighborhood3D,
class EqualityFunctor = std::equal_to<T1> >
unsigned int
labelVolume(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest,
Neighborhood3D neighborhood3D,
EqualityFunctor equal = EqualityFunctor());
}
\endcode
\deprecatedAPI{labelVolume}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D> class Neighborhood3D>
unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, Src Accessor sa, unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, Src Accessor sa,
DestIterator d_Iter, DestAccessor da, DestIterator d_Iter, DestAccessor da,
Neighborhood3D neighborhood3D); Neighborhood3D neighborhood3D);
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class EqualityFunctor> class Neighborhood3D, class EqualityFunctor>
unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, Src Accessor sa, unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, Src Accessor sa,
DestIterator d_Iter, DestAccessor da, DestIterator d_Iter, DestAccessor da,
Neighborhood3D neighborhood3D, EqualityFun ctor equal); Neighborhood3D neighborhood3D, EqualityFun ctor equal);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D> class Neighborhood3D>
unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src, unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D); Neighborhood3D neighborhood3D);
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class EqualityFunctor> class Neighborhood3D, class EqualityFunctor>
unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src, unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D, EqualityFun ctor equal); Neighborhood3D neighborhood3D, EqualityFun ctor equal);
} }
\endcode \endcode
use with 3D-Six-Neighborhood: use with 3D-Six-Neighborhood:
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccess or> src, unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccess or> src,
pair<DestIterator, DestAccessor> dest); pair<DestIterator, DestAccessor> dest);
} }
\endcode \endcode
\deprecatedEnd
Connected components are defined as regions with uniform voxel
values. Thus, <TT>SrcAccessor::value_type</TT> either must be
equality comparable (first form), or an EqualityFunctor must be
provided that realizes the desired predicate (second form). The
destination's value type should be large enough to hold the labels
without overflow. Region numbers will be a consecutive sequence
starting with one and ending with the region number returned by
the function (inclusive).
Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/labelvolume.hxx\><br> <b>\#include</b> \<vigra/labelvolume.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef MultiArray<3,int> IntVolume;
IntVolume src(Shape3(w,h,d));
IntVolume dest(Shape3(w,h,d));
// find 6-connected regions
int max_region_label = labelVolumeSix(src, dest);
// find 26-connected regions
int max_region_label = labelVolume(src, dest, NeighborCode3DTwentySix()
);
\endcode
\deprecatedUsage{labelVolume}
\code
typedef vigra::MultiArray<3,int> IntVolume; typedef vigra::MultiArray<3,int> IntVolume;
IntVolume src(IntVolume::difference_type(w,h,d)); IntVolume src(IntVolume::difference_type(w,h,d));
IntVolume dest(IntVolume::difference_type(w,h,d)); IntVolume dest(IntVolume::difference_type(w,h,d));
// find 6-connected regions // find 6-connected regions
int max_region_label = vigra::labelVolumeSix(srcMultiArrayRange(src), d estMultiArray(dest)); int max_region_label = vigra::labelVolumeSix(srcMultiArrayRange(src), d estMultiArray(dest));
// find 26-connected regions // find 26-connected regions
int max_region_label = vigra::labelVolume(srcMultiArrayRange(src), dest MultiArray(dest), NeighborCode3DTwentySix()); int max_region_label = vigra::labelVolume(srcMultiArrayRange(src), dest MultiArray(dest), NeighborCode3DTwentySix());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_begin; SrcIterator src_begin;
SrcShape shape; SrcShape shape;
DestIterator dest_begin; DestIterator dest_begin;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_begin); SrcAccessor::value_type u = src_accessor(src_begin);
u == u // first form u == u // first form
EqualityFunctor equal; // second form EqualityFunctor equal; // second form
equal(u, u) // second form equal(u, u) // second form
int i; int i;
dest_accessor.set(i, dest_begin); dest_accessor.set(i, dest_begin);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int labelVolume) doxygen_overloaded_function(template <...> unsigned int labelVolume)
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D>
unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor
sa,
DestIterator d_Iter, DestAccessor da,
Neighborhood3D neighborhood3D)
{
return labelVolume(s_Iter, srcShape, sa, d_Iter, da, neighborhood3D
, std::equal_to<typename SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D>
unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D)
{
return labelVolume(src.first, src.second, src.third, dest.first, dest.s
econd, neighborhood3D, std::equal_to<typename SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D, class EqualityFunctor>
unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D, EqualityFunctor equ
al)
{
return labelVolume(src.first, src.second, src.third, dest.first, dest.s
econd, neighborhood3D, equal);
}
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D, class EqualityFunctor> class Neighborhood3D, class EqualityFunctor>
unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa, unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
DestIterator d_Iter, DestAccessor da, DestIterator d_Iter, DestAccessor da,
Neighborhood3D, EqualityFunctor equal) Neighborhood3D, EqualityFunctor equal)
{ {
typedef typename DestAccessor::value_type LabelType; typedef typename DestAccessor::value_type LabelType;
//basically needed for iteration and border-checks //basically needed for iteration and border-checks
int w = srcShape[0], h = srcShape[1], d = srcShape[2]; int w = srcShape[0], h = srcShape[1], d = srcShape[2];
int x,y,z; int x,y,z;
// temporary image to store region labels // temporary image to store region labels
detail::UnionFindArray<LabelType> label; UnionFindArray<LabelType> label;
//Declare traversers for all three dims at target //Declare traversers for all three dims at target
SrcIterator zs = s_Iter; SrcIterator zs = s_Iter;
DestIterator zd = d_Iter; DestIterator zd = d_Iter;
// initialize the neighborhood traversers // initialize the neighborhood traversers
NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast ); NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast );
++nce; ++nce;
// pass 1: scan image from upper left front to lower right back // pass 1: scan image from upper left front to lower right back
// to find connected components // to find connected components
skipping to change at line 245 skipping to change at line 245
SrcIterator ys(zs); SrcIterator ys(zs);
DestIterator yd(zd); DestIterator yd(zd);
for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1()) for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1())
{ {
SrcIterator xs(ys); SrcIterator xs(ys);
DestIterator xd(yd); DestIterator xd(yd);
for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0()) for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
{ {
LabelType currentLabel = label.nextFreeLabel(); LabelType currentIndex = label.nextFreeIndex();
//check whether there is a special border treatment to be u sed or not //check whether there is a special border treatment to be u sed or not
AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, d); AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, d);
//We are not at the border! //We are not at the border!
if(atBorder == NotAtBorder) if(atBorder == NotAtBorder)
{ {
NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::CausalFirst); NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::CausalFirst);
do do
{ {
// if colors are equal // if colors are equal
if(equal(sa(xs), sa(xs, *nc))) if(equal(sa(xs), sa(xs, *nc)))
{ {
currentLabel = label.makeUnion(label[da(xd,*nc) ], currentLabel); currentIndex = label.makeUnion(da(xd,*nc), curr entIndex);
} }
++nc; ++nc;
} }
while(nc!=nce); while(nc!=nce);
} }
else //we are at a border - handle this!! else //we are at a border - handle this!!
{ {
NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::nearBorderDirectionsCausal(atBorder,0)); NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::nearBorderDirectionsCausal(atBorder,0));
int j=0; int j=0;
while(nc.direction() != Neighborhood3D::Error) while(nc.direction() != Neighborhood3D::Error)
{ {
/* int dummy = x+(*nc)[0]; // prevents an apparently
SrcShape s(x,y,z), sn = s + *nc; incorrect optimization in gcc 4.8
if (dummy<0)
if (sn[0]<0 || sn[0]>=w || sn[1]<0 || sn[1]>=h || s
n[2]<0 || sn[2]>=d)
{ {
std::cerr << "coordinate error at " << s << ", of std::cerr << "internal error " << dummy << std:
fset " << *nc << ", index " << (nc).direction() << " at border " << :endl;
atBorder << std::endl;
} }
*/
// colors equal??? // colors equal???
if(equal(sa(xs), sa(xs, *nc))) if(equal(sa(xs), sa(xs, *nc)))
{ {
currentLabel = label.makeUnion(label[da(xd,*nc) ], currentLabel); currentIndex = label.makeUnion(da(xd,*nc), curr entIndex);
} }
nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j)); nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j));
} }
} }
da.set(label.finalizeLabel(currentLabel), xd); da.set(label.finalizeIndex(currentIndex), xd);
} }
} }
} }
LabelType count = label.makeContiguous(); LabelType count = label.makeContiguous();
// pass 2: assign one label to each region (tree) // pass 2: assign one label to each region (tree)
// so that labels form a consecutive sequence 1, 2, ... // so that labels form a consecutive sequence 1, 2, ...
zd = d_Iter; zd = d_Iter;
for(z=0; z != d; ++z, ++zd.dim2()) for(z=0; z != d; ++z, ++zd.dim2())
{ {
DestIterator yd(zd); DestIterator yd(zd);
for(y=0; y != h; ++y, ++yd.dim1()) for(y=0; y != h; ++y, ++yd.dim1())
{ {
DestIterator xd(yd); DestIterator xd(yd);
for(x = 0; x != w; ++x, ++xd.dim0()) for(x = 0; x != w; ++x, ++xd.dim0())
{ {
da.set(label[da(xd)], xd); da.set(label.findLabel(da(xd)), xd);
} }
} }
} }
return count; return count;
} }
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D>
unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor
sa,
DestIterator d_Iter, DestAccessor da,
Neighborhood3D neighborhood3D)
{
return labelVolume(s_Iter, srcShape, sa, d_Iter, da, neighborhood3D
, std::equal_to<typename SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood3D>
unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D)
{
return labelVolume(src.first, src.second, src.third, dest.first, dest.s
econd, neighborhood3D, std::equal_to<typename SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood3D, class EqualityFunctor>
unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D, EqualityFunctor equ
al)
{
return labelVolume(src.first, src.second, src.third, dest.first, dest.s
econd, neighborhood3D, equal);
}
template <class T1, class S1,
class T2, class S2,
class Neighborhood3D, class EqualityFunctor>
inline unsigned int
labelVolume(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest,
Neighborhood3D neighborhood3D,
EqualityFunctor equal)
{
vigra_precondition(source.shape() == dest.shape(),
"labelVolume(): shape mismatch between input and output.");
return labelVolume(srcMultiArrayRange(source), destMultiArray(dest), ne
ighborhood3D, equal);
}
template <class T1, class S1,
class T2, class S2,
class Neighborhood3D>
inline unsigned int
labelVolume(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest,
Neighborhood3D neighborhood3D)
{
vigra_precondition(source.shape() == dest.shape(),
"labelVolume(): shape mismatch between input and output.");
return labelVolume(srcMultiArrayRange(source), destMultiArray(dest), ne
ighborhood3D, std::equal_to<T1>());
}
/********************************************************/ /********************************************************/
/* */ /* */
/* labelVolumeSix */ /* labelVolumeSix */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find the connected components of a segmented volume /** \brief Find the connected components of a segmented volume
using the 6-neighborhood. using the 6-neighborhood.
See \ref labelVolume() for detailed documentation. See \ref labelVolume() for detailed documentation.
*/ */
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccessor> src, unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest) pair<DestIterator, DestAccessor> dest)
{ {
return labelVolume(src.first, src.second, src.third, dest.first, dest.s econd, NeighborCode3DSix(), std::equal_to<typename SrcAccessor::value_type> ()); return labelVolume(src.first, src.second, src.third, dest.first, dest.s econd, NeighborCode3DSix(), std::equal_to<typename SrcAccessor::value_type> ());
} }
template <class T1, class S1,
class T2, class S2>
unsigned int labelVolumeSix(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest)
{
return labelVolume(srcMultiArrayRange(source), destMultiArray(dest),
NeighborCode3DSix(), std::equal_to<T1>());
}
/********************************************************/ /********************************************************/
/* */ /* */
/* labelVolumeWithBackground */ /* labelVolumeWithBackground */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find the connected components of a segmented volume, /** \brief Find the connected components of a segmented volume,
excluding the background from labeling. excluding the background from labeling.
This function works like \ref labelVolume(), but considers all backgrou
nd voxels
(i.e. voxels having the given '<TT>background_value</TT>') as a single
region that
is ignored when determining connected components and remains untouched
in the
destination array. Usually, you will zero-initialize the output array,
so that
the background gets label 0 (remember that actual region labels start a
t one).
Return: the number of regions found (= largest region label)
See \ref labelMultiArrayWithBackground() for a dimension-independent im
plementation
if this algorithm.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 3D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Neighborhood3D,
class ValueType,
class EqualityFunctor = std::equalt_to<T1> >
unsigned int
labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest,
Neighborhood3D neighborhood3D,
ValueType backgroundValue,
EqualityFunctor equal = EqualityFunctor()
);
}
\endcode
\deprecatedAPI{labelVolumeWithBackground}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class ValueType> class Neighborhood3D, class ValueType>
unsigned int labelVolumeWithBackground( SrcIterator s_Iter, SrcS hape srcShape, SrcAccessor sa, unsigned int labelVolumeWithBackground( SrcIterator s_Iter, SrcS hape srcShape, SrcAccessor sa,
DestIterator d_It er, DestAccessor da, DestIterator d_It er, DestAccessor da,
Neighborhood3D ne ighborhood3D, ValueType background_value); Neighborhood3D ne ighborhood3D, ValueType background_value);
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class ValueType, class Equa lityFunctor> class Neighborhood3D, class ValueType, class Equa lityFunctor>
unsigned int labelVolumeWithBackground( SrcIterator s_Iter, SrcS hape srcShape, SrcAccessor sa, unsigned int labelVolumeWithBackground( SrcIterator s_Iter, SrcS hape srcShape, SrcAccessor sa,
DestIterator d_ Iter, DestAccessor da, DestIterator d_ Iter, DestAccessor da,
Neighborhood3D ne ighborhood3D, ValueType background_value, Neighborhood3D ne ighborhood3D, ValueType background_value,
EqualityFunctor equal); EqualityFunctor equal);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class ValueType> class Neighborhood3D, class ValueType>
unsigned int labelVolumeWithBackground( triple<SrcIterator, SrcS hape, SrcAccessor> src, unsigned int labelVolumeWithBackground( triple<SrcIterator, SrcS hape, SrcAccessor> src,
pair<DestIterator , DestAccessor> dest, pair<DestIterator , DestAccessor> dest,
Neighborhood3D ne ighborhood3D, ValueType background_value); Neighborhood3D ne ighborhood3D, ValueType background_value);
skipping to change at line 391 skipping to change at line 480
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class ValueType, class Equa lityFunctor> class Neighborhood3D, class ValueType, class Equa lityFunctor>
unsigned int labelVolumeWithBackground( triple<SrcIterator, SrcS hape, SrcAccessor> src, unsigned int labelVolumeWithBackground( triple<SrcIterator, SrcS hape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood3D neig hborhood3D, ValueType background_value, Neighborhood3D neig hborhood3D, ValueType background_value,
EqualityFunctor equ al); EqualityFunctor equ al);
} }
\endcode \endcode
\deprecatedEnd
Connected components are defined as regions with uniform voxel
values. Thus, <TT>SrcAccessor::value_type</TT> either must be
equality comparable (first form), or an EqualityFunctor must be
provided that realizes the desired predicate (second form). All
voxel equal to the given '<TT>background_value</TT>' are ignored
when determining connected components and remain untouched in the
destination volume.
The destination's value type should be large enough to hold the
labels without overflow. Region numbers will be a consecutive
sequence starting with one and ending with the region number
returned by the function (inclusive).
Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/labelvolume.hxx\><br> <b>\#include</b> \<vigra/labelvolume.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3,int> IntVolume; typedef vigra::MultiArray<3,int> IntVolume;
IntVolume src(Shape3(w,h,d));
IntVolume dest(Shape3(w,h,d));
// find 6-connected regions
int max_region_label = labelVolumeWithBackground(src, dest, NeighborCod
e3DSix(), 0);
\endcode
\deprecatedUsage{labelVolumeWithBackground}
\code
typedef vigra::MultiArray<3,int> IntVolume;
IntVolume src(IntVolume::difference_type(w,h,d)); IntVolume src(IntVolume::difference_type(w,h,d));
IntVolume dest(IntVolume::difference_type(w,h,d)); IntVolume dest(IntVolume::difference_type(w,h,d));
// find 6-connected regions // find 6-connected regions
int max_region_label = vigra::labelVolumeWithBackground( int max_region_label = vigra::labelVolumeWithBackground(
srcMultiArrayRange(src), destMultiArray(dest), NeighborCode3DSix(), 0); srcMultiArrayRange(src), destMultiArray(dest), NeighborCode3DSix(), 0);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_begin; SrcIterator src_begin;
SrcShape shape; SrcShape shape;
DestIterator dest_begin; DestIterator dest_begin;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_begin); SrcAccessor::value_type u = src_accessor(src_begin);
u == u // first form u == u // first form
EqualityFunctor equal; // second form EqualityFunctor equal; // second form
equal(u, u) // second form equal(u, u) // second form
int i; int i;
dest_accessor.set(i, dest_begin); dest_accessor.set(i, dest_begin);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int labelVolumeWithBack ground) doxygen_overloaded_function(template <...> unsigned int labelVolumeWithBack ground)
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D, class Neighborhood3D,
class ValueType>
unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShap
e, SrcAccessor sa,
DestIterator d_Iter, DestAccessor da
,
Neighborhood3D neighborhood3D, Value
Type backgroundValue)
{
return labelVolumeWithBackground(s_Iter, srcShape, sa, d_Iter, da, neig
hborhood3D, backgroundValue, std::equal_to<typename SrcAccessor::value_type
>());
}
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D,
class ValueType>
unsigned int labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAcc
essor> src,
pair<DestIterator, DestAccessor> des
t,
Neighborhood3D neighborhood3D, Value
Type backgroundValue)
{
return labelVolumeWithBackground(src.first, src.second, src.third, dest
.first, dest.second, neighborhood3D, backgroundValue, std::equal_to<typenam
e SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D,
class ValueType, class EqualityFunctor>
unsigned int labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAcc
essor> src,
pair<DestIterator, DestAccessor> des
t,
Neighborhood3D neighborhood3D, Value
Type backgroundValue, EqualityFunctor equal)
{
return labelVolumeWithBackground(src.first, src.second, src.third, dest
.first, dest.second, neighborhood3D, backgroundValue, equal);
}
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D,
class ValueType, class EqualityFunctor> class ValueType, class EqualityFunctor>
unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShap e, SrcAccessor sa, unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShap e, SrcAccessor sa,
DestIterator d_Iter, DestAccessor da , DestIterator d_Iter, DestAccessor da ,
Neighborhood3D, Neighborhood3D,
ValueType backgroundValue, EqualityF unctor equal) ValueType backgroundValue, EqualityF unctor equal)
{ {
typedef typename DestAccessor::value_type LabelType; typedef typename DestAccessor::value_type LabelType;
//basically needed for iteration and border-checks //basically needed for iteration and border-checks
int w = srcShape[0], h = srcShape[1], d = srcShape[2]; int w = srcShape[0], h = srcShape[1], d = srcShape[2];
int x,y,z; int x,y,z;
// temporary image to store region labels // temporary image to store region labels
detail::UnionFindArray<LabelType> label; UnionFindArray<LabelType> label;
//Declare traversers for all three dims at target //Declare traversers for all three dims at target
SrcIterator zs = s_Iter; SrcIterator zs = s_Iter;
DestIterator zd = d_Iter; DestIterator zd = d_Iter;
// initialize the neighborhood traversers // initialize the neighborhood traversers
NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast ); NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast );
++nce; ++nce;
// pass 1: scan image from upper left front to lower right back // pass 1: scan image from upper left front to lower right back
// to find connected components // to find connected components
skipping to change at line 531 skipping to change at line 582
for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1()) for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1())
{ {
SrcIterator xs(ys); SrcIterator xs(ys);
DestIterator xd(yd); DestIterator xd(yd);
for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0()) for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
{ {
if(equal(sa(xs), backgroundValue)) if(equal(sa(xs), backgroundValue))
{ {
da.set(label[0], xd); //da.set(label.getIndex(0), xd);
da.set(0, xd);
continue; continue;
} }
LabelType currentLabel = label.nextFreeLabel(); LabelType currentIndex = label.nextFreeIndex();
//check whether there is a special border treatment to be u sed or not //check whether there is a special border treatment to be u sed or not
AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, d); AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, d);
//We are not at the border! //We are not at the border!
if(atBorder == NotAtBorder) if(atBorder == NotAtBorder)
{ {
NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::CausalFirst); NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::CausalFirst);
do do
{ {
// if colors are equal // if colors are equal
if(equal(sa(xs), sa(xs, *nc))) if(equal(sa(xs), sa(xs, *nc)))
{ {
currentLabel = label.makeUnion(label[da(xd,*nc) ], currentLabel); currentIndex = label.makeUnion(da(xd,*nc), curr entIndex);
} }
++nc; ++nc;
} }
while(nc!=nce); while(nc!=nce);
} }
else //we are at a border - handle this!! else //we are at a border - handle this!!
{ {
NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::nearBorderDirectionsCausal(atBorder,0)); NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo d3D::nearBorderDirectionsCausal(atBorder,0));
int j=0; int j=0;
while(nc.direction() != Neighborhood3D::Error) while(nc.direction() != Neighborhood3D::Error)
{ {
int dummy = x+(*nc)[0]; // prevents an apparently
incorrect optimization in gcc 4.8
if (dummy<0)
{
std::cerr << "internal error " << dummy << std:
:endl;
}
// colors equal??? // colors equal???
if(equal(sa(xs), sa(xs, *nc))) if(equal(sa(xs), sa(xs, *nc)))
{ {
currentLabel = label.makeUnion(label[da(xd,*nc) ], currentLabel); currentIndex = label.makeUnion(da(xd,*nc), curr entIndex);
} }
nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j)); nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j));
} }
} }
da.set(label.finalizeLabel(currentLabel), xd); da.set(label.finalizeIndex(currentIndex), xd);
} }
} }
} }
LabelType count = label.makeContiguous(); LabelType count = label.makeContiguous();
// pass 2: assign one label to each region (tree) // pass 2: assign one label to each region (tree)
// so that labels form a consecutive sequence 1, 2, ... // so that labels form a consecutive sequence 1, 2, ...
zd = d_Iter; zd = d_Iter;
for(z=0; z != d; ++z, ++zd.dim2()) for(z=0; z != d; ++z, ++zd.dim2())
{ {
DestIterator yd(zd); DestIterator yd(zd);
for(y=0; y != h; ++y, ++yd.dim1()) for(y=0; y != h; ++y, ++yd.dim1())
{ {
DestIterator xd(yd); DestIterator xd(yd);
for(x = 0; x != w; ++x, ++xd.dim0()) for(x = 0; x != w; ++x, ++xd.dim0())
{ {
da.set(label[da(xd)], xd); da.set(label.findLabel(da(xd)), xd);
} }
} }
} }
return count; return count;
} }
template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood3D,
class ValueType>
inline unsigned int
labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, SrcAccesso
r sa,
DestIterator d_Iter, DestAccessor da,
Neighborhood3D neighborhood3D, ValueType backgrou
ndValue)
{
return labelVolumeWithBackground(s_Iter, srcShape, sa, d_Iter, da, neig
hborhood3D, backgroundValue, std::equal_to<typename SrcAccessor::value_type
>());
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood3D,
class ValueType,
class EqualityFunctor>
inline unsigned int
labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D, ValueType backgrou
ndValue, EqualityFunctor equal)
{
return labelVolumeWithBackground(src.first, src.second, src.third, dest
.first, dest.second, neighborhood3D, backgroundValue, equal);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood3D,
class ValueType>
inline unsigned int
labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D, ValueType backgrou
ndValue)
{
return labelVolumeWithBackground(src.first, src.second, src.third, dest
.first, dest.second,
neighborhood3D, backgroundValue, std::
equal_to<typename SrcAccessor::value_type>());
}
template <class T1, class S1,
class T2, class S2,
class Neighborhood3D,
class ValueType,
class EqualityFunctor>
inline unsigned int
labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest,
Neighborhood3D neighborhood3D,
ValueType backgroundValue,
EqualityFunctor equal)
{
vigra_precondition(source.shape() == dest.shape(),
"labelVolumeWithBackground(): shape mismatch between input and outp
ut.");
return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiA
rray(dest),
neighborhood3D, backgroundValue, equal
);
}
template <class T1, class S1,
class T2, class S2,
class Neighborhood3D,
class ValueType>
inline unsigned int
labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
MultiArrayView<3, T2, S2> dest,
Neighborhood3D neighborhood3D,
ValueType backgroundValue)
{
vigra_precondition(source.shape() == dest.shape(),
"labelVolumeWithBackground(): shape mismatch between input and outp
ut.");
return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiA
rray(dest),
neighborhood3D, backgroundValue,
std::equal_to<T1>());
}
//@} //@}
} //end of namespace vigra } //end of namespace vigra
#endif //VIGRA_LABELVOLUME_HXX #endif //VIGRA_LABELVOLUME_HXX
 End of changes. 39 change blocks. 
143 lines changed or deleted 286 lines changed or added


 linear_solve.hxx   linear_solve.hxx 
skipping to change at line 163 skipping to change at line 163
{ {
typedef typename Matrix<T>::difference_type Shape; typedef typename Matrix<T>::difference_type Shape;
const MultiArrayIndex m = rowCount(r); const MultiArrayIndex m = rowCount(r);
const MultiArrayIndex n = columnCount(r); const MultiArrayIndex n = columnCount(r);
const MultiArrayIndex rhsCount = columnCount(rhs); const MultiArrayIndex rhsCount = columnCount(rhs);
vigra_precondition(m == rowCount(rhs), vigra_precondition(m == rowCount(rhs),
"qrGivensStepImpl(): Matrix shape mismatch."); "qrGivensStepImpl(): Matrix shape mismatch.");
Matrix<T> givens(2,2); Matrix<T> givens(2,2);
for(int k=m-1; k>(int)i; --k) for(int k=m-1; k>static_cast<int>(i); --k)
{ {
if(!givensReflectionMatrix(r(k-1,i), r(k,i), givens)) if(!givensReflectionMatrix(r(k-1,i), r(k,i), givens))
continue; // r(k,i) was already zero continue; // r(k,i) was already zero
r(k-1,i) = givens(0,0)*r(k-1,i) + givens(0,1)*r(k,i); r(k-1,i) = givens(0,0)*r(k-1,i) + givens(0,1)*r(k,i);
r(k,i) = 0.0; r(k,i) = 0.0;
r.subarray(Shape(k-1,i+1), Shape(k+1,n)) = givens*r.subarray(Shape( k-1,i+1), Shape(k+1,n)); r.subarray(Shape(k-1,i+1), Shape(k+1,n)) = givens*r.subarray(Shape( k-1,i+1), Shape(k+1,n));
rhs.subarray(Shape(k-1,0), Shape(k+1,rhsCount)) = givens*rhs.subarr ay(Shape(k-1,0), Shape(k+1,rhsCount)); rhs.subarray(Shape(k-1,0), Shape(k+1,rhsCount)) = givens*rhs.subarr ay(Shape(k-1,0), Shape(k+1,rhsCount));
} }
skipping to change at line 247 skipping to change at line 247
if(j == i) if(j == i)
return; return;
if(j < i) if(j < i)
std::swap(j,i); std::swap(j,i);
columnVector(r, i).swapData(columnVector(r, j)); columnVector(r, i).swapData(columnVector(r, j));
std::swap(permutation[i], permutation[j]); std::swap(permutation[i], permutation[j]);
Matrix<T> givens(2,2); Matrix<T> givens(2,2);
for(int k=m-1; k>(int)i; --k) for(int k=m-1; k>static_cast<int>(i); --k)
{ {
if(!givensReflectionMatrix(r(k-1,i), r(k,i), givens)) if(!givensReflectionMatrix(r(k-1,i), r(k,i), givens))
continue; // r(k,i) was already zero continue; // r(k,i) was already zero
r(k-1,i) = givens(0,0)*r(k-1,i) + givens(0,1)*r(k,i); r(k-1,i) = givens(0,0)*r(k-1,i) + givens(0,1)*r(k,i);
r(k,i) = 0.0; r(k,i) = 0.0;
r.subarray(Shape(k-1,i+1), Shape(k+1,n)) = givens*r.subarray(Shape( k-1,i+1), Shape(k+1,n)); r.subarray(Shape(k-1,i+1), Shape(k+1,n)) = givens*r.subarray(Shape( k-1,i+1), Shape(k+1,n));
rhs.subarray(Shape(k-1,0), Shape(k+1,rhsCount)) = givens*rhs.subarr ay(Shape(k-1,0), Shape(k+1,rhsCount)); rhs.subarray(Shape(k-1,0), Shape(k+1,rhsCount)) = givens*rhs.subarr ay(Shape(k-1,0), Shape(k+1,rhsCount));
} }
skipping to change at line 391 skipping to change at line 391
MultiArrayIndex n = rowCount(newColumn) - 1; MultiArrayIndex n = rowCount(newColumn) - 1;
T gamma = newColumn(n,0); T gamma = newColumn(n,0);
if(gamma == 0.0) if(gamma == 0.0)
{ {
v = 0.0; v = 0.0;
return; return;
} }
T yv = dot(columnVector(newColumn, Shape(0,0),n), columnVector(z, Shape T yv = dot(columnVector(newColumn, Shape(0,0), static_cast<int>(n)),
(0,0),n)); columnVector(z, Shape(0,0), static_cast<int>(n)));
// use atan2 as it is robust against overflow/underflow // use atan2 as it is robust against overflow/underflow
T t = 0.5*std::atan2(T(-2.0*yv), T(squaredNorm(gamma / v) + squaredNorm (yv) - 1.0)), T t = 0.5*std::atan2(T(-2.0*yv), T(squaredNorm(gamma / v) + squaredNorm (yv) - 1.0)),
s = std::sin(t), s = std::sin(t),
c = std::cos(t); c = std::cos(t);
columnVector(z, Shape(0,0),n) *= c; columnVector(z, Shape(0,0), static_cast<int>(n)) *= c;
z(n,0) = (s - c*yv) / gamma; z(n,0) = (s - c*yv) / gamma;
v *= norm(gamma) / hypot(c*gamma, v*(s - c*yv)); v *= norm(gamma) / hypot(c*gamma, v*(s - c*yv));
} }
// QR algorithm with optional column pivoting // QR algorithm with optional column pivoting
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
unsigned int unsigned int
qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T, C2> & rhs, MultiArrayView<2, T, C3> & householder, qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T, C2> & rhs, MultiArrayView<2, T, C3> & householder,
ArrayVector<MultiArrayIndex> & permutation, dou ble epsilon) ArrayVector<MultiArrayIndex> & permutation, dou ble epsilon)
{ {
skipping to change at line 428 skipping to change at line 429
const MultiArrayIndex rhsCount = columnCount(rhs); const MultiArrayIndex rhsCount = columnCount(rhs);
bool transformRHS = rhsCount > 0; bool transformRHS = rhsCount > 0;
vigra_precondition(!transformRHS || m == rowCount(rhs), vigra_precondition(!transformRHS || m == rowCount(rhs),
"qrTransformToTriangularImpl(): RHS matrix shape mis match."); "qrTransformToTriangularImpl(): RHS matrix shape mis match.");
bool storeHouseholderSteps = columnCount(householder) > 0; bool storeHouseholderSteps = columnCount(householder) > 0;
vigra_precondition(!storeHouseholderSteps || r.shape() == householder.s hape(), vigra_precondition(!storeHouseholderSteps || r.shape() == householder.s hape(),
"qrTransformToTriangularImpl(): Householder matrix s hape mismatch."); "qrTransformToTriangularImpl(): Householder matrix s hape mismatch.");
bool pivoting = permutation.size() > 0; bool pivoting = permutation.size() > 0;
vigra_precondition(!pivoting || n == (MultiArrayIndex)permutation.size( ), vigra_precondition(!pivoting || n == static_cast<MultiArrayIndex>(permu tation.size()),
"qrTransformToTriangularImpl(): Permutation array si ze mismatch."); "qrTransformToTriangularImpl(): Permutation array si ze mismatch.");
if(n == 0) if(n == 0)
return 0; // trivial solution return 0; // trivial solution
Matrix<SNType> columnSquaredNorms; Matrix<SNType> columnSquaredNorms;
if(pivoting) if(pivoting)
{ {
columnSquaredNorms.reshape(Shape(1,n)); columnSquaredNorms.reshape(Shape(1,n));
for(MultiArrayIndex k=0; k<n; ++k) for(MultiArrayIndex k=0; k<n; ++k)
skipping to change at line 483 skipping to change at line 484
zmin(0,0) = 1.0 / r(0,0); zmin(0,0) = 1.0 / r(0,0);
} }
for(MultiArrayIndex k=1; k<maxRank; ++k) for(MultiArrayIndex k=1; k<maxRank; ++k)
{ {
if(pivoting) if(pivoting)
{ {
for(MultiArrayIndex l=k; l<n; ++l) for(MultiArrayIndex l=k; l<n; ++l)
columnSquaredNorms[l] -= squaredNorm(r(k, l)); columnSquaredNorms[l] -= squaredNorm(r(k, l));
int pivot = k + argMax(rowVector(columnSquaredNorms, Shape(0,k) , n)); int pivot = k + argMax(rowVector(columnSquaredNorms, Shape(0,k) , n));
if(pivot != (int)k) if(pivot != static_cast<int>(k))
{ {
columnVector(r, k).swapData(columnVector(r, pivot)); columnVector(r, k).swapData(columnVector(r, pivot));
std::swap(columnSquaredNorms[k], columnSquaredNorms[pivot]) ; std::swap(columnSquaredNorms[k], columnSquaredNorms[pivot]) ;
std::swap(permutation[k], permutation[pivot]); std::swap(permutation[k], permutation[pivot]);
} }
} }
qrHouseholderStepImpl(k, r, rhs, householder); qrHouseholderStepImpl(k, r, rhs, householder);
if(simpleSingularValueApproximation) if(simpleSingularValueApproximation)
skipping to change at line 519 skipping to change at line 520
#endif #endif
if(epsilon == 0.0) if(epsilon == 0.0)
tolerance = m*maxApproxSingularValue*NumericTraits<T>::epsilon( ); tolerance = m*maxApproxSingularValue*NumericTraits<T>::epsilon( );
if(minApproxSingularValue > tolerance) if(minApproxSingularValue > tolerance)
++rank; ++rank;
else else
pivoting = false; // matrix doesn't have full rank, triangulize the rest without pivoting pivoting = false; // matrix doesn't have full rank, triangulize the rest without pivoting
} }
return (unsigned int)rank; return static_cast<unsigned int>(rank);
} }
template <class T, class C1, class C2> template <class T, class C1, class C2>
unsigned int unsigned int
qrTransformToUpperTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & rhs, qrTransformToUpperTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & rhs,
ArrayVector<MultiArrayIndex> & permutation, do uble epsilon = 0.0) ArrayVector<MultiArrayIndex> & permutation, do uble epsilon = 0.0)
{ {
Matrix<T> dontStoreHouseholderVectors; // intentionally empty Matrix<T> dontStoreHouseholderVectors; // intentionally empty
return qrTransformToTriangularImpl(r, rhs, dontStoreHouseholderVectors, permutation, epsilon); return qrTransformToTriangularImpl(r, rhs, dontStoreHouseholderVectors, permutation, epsilon);
} }
// QR algorithm with optional row pivoting // QR algorithm with optional row pivoting
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
unsigned int unsigned int
qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & rhs, MultiArrayView<2, T, C3> & householderMatrix, qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & rhs, MultiArrayView<2, T, C3> & householderMatrix,
double epsilon = 0.0) double epsilon = 0.0)
{ {
ArrayVector<MultiArrayIndex> permutation((unsigned int)rowCount(rhs)); ArrayVector<MultiArrayIndex> permutation(static_cast<unsigned int>(rowC
for(MultiArrayIndex k=0; k<(MultiArrayIndex)permutation.size(); ++k) ount(rhs)));
for(MultiArrayIndex k=0; k<static_cast<MultiArrayIndex>(permutation.siz
e()); ++k)
permutation[k] = k; permutation[k] = k;
Matrix<T> dontTransformRHS; // intentionally empty Matrix<T> dontTransformRHS; // intentionally empty
MultiArrayView<2, T, StridedArrayTag> rt = transpose(r), MultiArrayView<2, T, StridedArrayTag> rt = transpose(r),
ht = transpose(householderMatrix) ; ht = transpose(householderMatrix) ;
unsigned int rank = qrTransformToTriangularImpl(rt, dontTransformRHS, h t, permutation, epsilon); unsigned int rank = qrTransformToTriangularImpl(rt, dontTransformRHS, h t, permutation, epsilon);
// apply row permutation to RHS // apply row permutation to RHS
Matrix<T> tempRHS(rhs); Matrix<T> tempRHS(rhs);
for(MultiArrayIndex k=0; k<(MultiArrayIndex)permutation.size(); ++k) for(MultiArrayIndex k=0; k<static_cast<MultiArrayIndex>(permutation.siz e()); ++k)
rowVector(rhs, k) = rowVector(tempRHS, permutation[k]); rowVector(rhs, k) = rowVector(tempRHS, permutation[k]);
return rank; return rank;
} }
// QR algorithm without column pivoting // QR algorithm without column pivoting
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline bool inline bool
qrTransformToUpperTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & rhs, qrTransformToUpperTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & rhs,
double epsilon = 0.0) double epsilon = 0.0)
{ {
ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty
return (qrTransformToUpperTriangular(r, rhs, noPivoting, epsilon) == return (qrTransformToUpperTriangular(r, rhs, noPivoting, epsilon) ==
(unsigned int)columnCount(r)); static_cast<unsigned int>(columnCount(r)));
} }
// QR algorithm without row pivoting // QR algorithm without row pivoting
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline bool inline bool
qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & householder, qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2 , T, C2> & householder,
double epsilon = 0.0) double epsilon = 0.0)
{ {
Matrix<T> noPivoting; // intentionally empty Matrix<T> noPivoting; // intentionally empty
return (qrTransformToLowerTriangular(r, noPivoting, householder, epsilo n) == return (qrTransformToLowerTriangular(r, noPivoting, householder, epsilo n) ==
(unsigned int)rowCount(r)); static_cast<unsigned int>(rowCount(r)));
} }
// restore ordering of result vector elements after QR solution with column pivoting // restore ordering of result vector elements after QR solution with column pivoting
template <class T, class C1, class C2, class Permutation> template <class T, class C1, class C2, class Permutation>
void inverseRowPermutation(MultiArrayView<2, T, C1> &permuted, MultiArrayVi ew<2, T, C2> &res, void inverseRowPermutation(MultiArrayView<2, T, C1> &permuted, MultiArrayVi ew<2, T, C2> &res,
Permutation const & permutation) Permutation const & permutation)
{ {
for(MultiArrayIndex k=0; k<columnCount(permuted); ++k) for(MultiArrayIndex k=0; k<columnCount(permuted); ++k)
for(MultiArrayIndex l=0; l<rowCount(permuted); ++l) for(MultiArrayIndex l=0; l<rowCount(permuted); ++l)
res(permutation[l], k) = permuted(l,k); res(permutation[l], k) = permuted(l,k);
skipping to change at line 632 skipping to change at line 633
vigra_precondition(n == rowCount(res), vigra_precondition(n == rowCount(res),
"linearSolveQR(): Mismatch between column count of coefficient m atrix and row count of solution."); "linearSolveQR(): Mismatch between column count of coefficient m atrix and row count of solution.");
vigra_precondition(epsilon >= 0.0, vigra_precondition(epsilon >= 0.0,
"linearSolveQR(): 'epsilon' must be non-negative."); "linearSolveQR(): 'epsilon' must be non-negative.");
if(m < n) if(m < n)
{ {
// minimum norm solution of underdetermined system // minimum norm solution of underdetermined system
Matrix<T> householderMatrix(n, m); Matrix<T> householderMatrix(n, m);
MultiArrayView<2, T, StridedArrayTag> ht = transpose(householderMat rix); MultiArrayView<2, T, StridedArrayTag> ht = transpose(householderMat rix);
rank = (MultiArrayIndex)detail::qrTransformToLowerTriangular(A, b, ht, epsilon); rank = static_cast<MultiArrayIndex>(detail::qrTransformToLowerTrian gular(A, b, ht, epsilon));
res.subarray(Shape(rank,0), Shape(n, rhsCount)).init(NumericTraits< T>::zero()); res.subarray(Shape(rank,0), Shape(n, rhsCount)).init(NumericTraits< T>::zero());
if(rank < m) if(rank < m)
{ {
// system is also rank-deficient => compute minimum norm least squares solution // system is also rank-deficient => compute minimum norm least squares solution
MultiArrayView<2, T, C1> Asub = A.subarray(ul, Shape(m,rank)); MultiArrayView<2, T, C1> Asub = A.subarray(ul, Shape(m,rank));
detail::qrTransformToUpperTriangular(Asub, b, epsilon); detail::qrTransformToUpperTriangular(Asub, b, epsilon);
linearSolveUpperTriangular(A.subarray(ul, Shape(rank,rank)), linearSolveUpperTriangular(A.subarray(ul, Shape(rank,rank)),
b.subarray(ul, Shape(rank,rhsCount)) , b.subarray(ul, Shape(rank,rhsCount)) ,
res.subarray(ul, Shape(rank, rhsCoun t))); res.subarray(ul, Shape(rank, rhsCoun t)));
} }
skipping to change at line 655 skipping to change at line 656
// system has full rank => compute minimum norm solution // system has full rank => compute minimum norm solution
linearSolveLowerTriangular(A.subarray(ul, Shape(rank,rank)), linearSolveLowerTriangular(A.subarray(ul, Shape(rank,rank)),
b.subarray(ul, Shape(rank, rhsCount) ), b.subarray(ul, Shape(rank, rhsCount) ),
res.subarray(ul, Shape(rank, rhsCoun t))); res.subarray(ul, Shape(rank, rhsCoun t)));
} }
detail::applyHouseholderColumnReflections(householderMatrix.subarra y(ul, Shape(n, rank)), res); detail::applyHouseholderColumnReflections(householderMatrix.subarra y(ul, Shape(n, rank)), res);
} }
else else
{ {
// solution of well-determined or overdetermined system // solution of well-determined or overdetermined system
ArrayVector<MultiArrayIndex> permutation((unsigned int)n); ArrayVector<MultiArrayIndex> permutation(static_cast<unsigned int>( n));
for(MultiArrayIndex k=0; k<n; ++k) for(MultiArrayIndex k=0; k<n; ++k)
permutation[k] = k; permutation[k] = k;
rank = (MultiArrayIndex)detail::qrTransformToUpperTriangular(A, b, permutation, epsilon); rank = static_cast<MultiArrayIndex>(detail::qrTransformToUpperTrian gular(A, b, permutation, epsilon));
Matrix<T> permutedSolution(n, rhsCount); Matrix<T> permutedSolution(n, rhsCount);
if(rank < n) if(rank < n)
{ {
// system is rank-deficient => compute minimum norm solution // system is rank-deficient => compute minimum norm solution
Matrix<T> householderMatrix(n, rank); Matrix<T> householderMatrix(n, rank);
MultiArrayView<2, T, StridedArrayTag> ht = transpose(householde rMatrix); MultiArrayView<2, T, StridedArrayTag> ht = transpose(householde rMatrix);
MultiArrayView<2, T, C1> Asub = A.subarray(ul, Shape(rank,n)); MultiArrayView<2, T, C1> Asub = A.subarray(ul, Shape(rank,n));
detail::qrTransformToLowerTriangular(Asub, ht, epsilon); detail::qrTransformToLowerTriangular(Asub, ht, epsilon);
linearSolveLowerTriangular(A.subarray(ul, Shape(rank,rank)), linearSolveLowerTriangular(A.subarray(ul, Shape(rank,rank)),
skipping to change at line 683 skipping to change at line 684
} }
else else
{ {
// system has full rank => compute exact or least squares solut ion // system has full rank => compute exact or least squares solut ion
linearSolveUpperTriangular(A.subarray(ul, Shape(rank,rank)), linearSolveUpperTriangular(A.subarray(ul, Shape(rank,rank)),
b.subarray(ul, Shape(rank,rhsCount)) , b.subarray(ul, Shape(rank,rhsCount)) ,
permutedSolution); permutedSolution);
} }
detail::inverseRowPermutation(permutedSolution, res, permutation); detail::inverseRowPermutation(permutedSolution, res, permutation);
} }
return (unsigned int)rank; return static_cast<unsigned int>(rank);
} }
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
unsigned int linearSolveQR(MultiArrayView<2, T, C1> const & A, MultiArrayVi ew<2, T, C2> const & b, unsigned int linearSolveQR(MultiArrayView<2, T, C1> const & A, MultiArrayVi ew<2, T, C2> const & b,
MultiArrayView<2, T, C3> & res) MultiArrayView<2, T, C3> & res)
{ {
Matrix<T> r(A), rhs(b); Matrix<T> r(A), rhs(b);
return linearSolveQRReplace(r, rhs, res); return linearSolveQRReplace(r, rhs, res);
} }
skipping to change at line 711 skipping to change at line 712
/** Create the inverse or pseudo-inverse of matrix \a v. /** Create the inverse or pseudo-inverse of matrix \a v.
If the matrix \a v is square, \a res must have the same shape and w ill contain the If the matrix \a v is square, \a res must have the same shape and w ill contain the
inverse of \a v. If \a v is rectangular, \a res must have the trans posed shape inverse of \a v. If \a v is rectangular, \a res must have the trans posed shape
of \a v. The inverse is then computed in the least-squares of \a v. The inverse is then computed in the least-squares
sense, i.e. \a res will be the pseudo-inverse (Moore-Penrose invers e). sense, i.e. \a res will be the pseudo-inverse (Moore-Penrose invers e).
The function returns <tt>true</tt> upon success, and <tt>false</tt> if \a v The function returns <tt>true</tt> upon success, and <tt>false</tt> if \a v
is not invertible (has not full rank). The inverse is computed by m eans of QR is not invertible (has not full rank). The inverse is computed by m eans of QR
decomposition. This function can be applied in-place. decomposition. This function can be applied in-place.
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
bool inverse(const MultiArrayView<2, T, C1> &v, MultiArrayView<2, T, C2> &r es) bool inverse(const MultiArrayView<2, T, C1> &v, MultiArrayView<2, T, C2> &r es)
{ {
typedef typename MultiArrayShape<2>::type Shape; typedef typename MultiArrayShape<2>::type Shape;
const MultiArrayIndex n = columnCount(v); const MultiArrayIndex n = columnCount(v);
const MultiArrayIndex m = rowCount(v); const MultiArrayIndex m = rowCount(v);
vigra_precondition(n == rowCount(res) && m == columnCount(res), vigra_precondition(n == rowCount(res) && m == columnCount(res),
skipping to change at line 765 skipping to change at line 766
is not invertible, <tt>vigra::PreconditionViolation</tt> exception is thrown. is not invertible, <tt>vigra::PreconditionViolation</tt> exception is thrown.
Usage: Usage:
\code \code
vigra::Matrix<double> v(n, n); vigra::Matrix<double> v(n, n);
v = ...; v = ...;
vigra::Matrix<double> m = inverse(v); vigra::Matrix<double> m = inverse(v);
\endcode \endcode
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
TemporaryMatrix<T> inverse(const MultiArrayView<2, T, C> &v) TemporaryMatrix<T> inverse(const MultiArrayView<2, T, C> &v)
{ {
TemporaryMatrix<T> ret(columnCount(v), rowCount(v)); // transpose shap e TemporaryMatrix<T> ret(columnCount(v), rowCount(v)); // transpose shap e
vigra_precondition(inverse(v, ret), vigra_precondition(inverse(v, ret),
"inverse(): matrix is not invertible."); "inverse(): matrix is not invertible.");
return ret; return ret;
} }
skipping to change at line 808 skipping to change at line 809
\a method must be one of the following: \a method must be one of the following:
<DL> <DL>
<DT>"Cholesky"<DD> Compute the solution by means of Cholesky decomp osition. This <DT>"Cholesky"<DD> Compute the solution by means of Cholesky decomp osition. This
method is faster than "LU", but requires the mat rix \a a method is faster than "LU", but requires the mat rix \a a
to be symmetric positive definite. If this is to be symmetric positive definite. If this is
not the case, a <tt>ContractViolation</tt> excep tion is thrown. not the case, a <tt>ContractViolation</tt> excep tion is thrown.
<DT>"LU"<DD> (default) Compute the solution by means of LU decompos ition. <DT>"LU"<DD> (default) Compute the solution by means of LU decompos ition.
</DL> </DL>
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1> template <class T, class C1>
T determinant(MultiArrayView<2, T, C1> const & a, std::string method = "LU" ) T determinant(MultiArrayView<2, T, C1> const & a, std::string method = "LU" )
{ {
MultiArrayIndex n = columnCount(a); MultiArrayIndex n = columnCount(a);
vigra_precondition(rowCount(a) == n, vigra_precondition(rowCount(a) == n,
"determinant(): Square matrix required."); "determinant(): Square matrix required.");
method = tolower(method); method = tolower(method);
skipping to change at line 851 skipping to change at line 852
vigra_precondition(false, "determinant(): Unknown solution method." ); vigra_precondition(false, "determinant(): Unknown solution method." );
} }
return T(); return T();
} }
/** Compute the logarithm of the determinant of a symmetric positive de finite matrix. /** Compute the logarithm of the determinant of a symmetric positive de finite matrix.
This is useful to avoid multiplication of very large numbers in big matrices. This is useful to avoid multiplication of very large numbers in big matrices.
It is implemented by means of Cholesky decomposition. It is implemented by means of Cholesky decomposition.
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1> template <class T, class C1>
T logDeterminant(MultiArrayView<2, T, C1> const & a) T logDeterminant(MultiArrayView<2, T, C1> const & a)
{ {
MultiArrayIndex n = columnCount(a); MultiArrayIndex n = columnCount(a);
vigra_precondition(rowCount(a) == n, vigra_precondition(rowCount(a) == n,
"logDeterminant(): Square matrix required."); "logDeterminant(): Square matrix required.");
if(n == 1) if(n == 1)
{ {
skipping to change at line 899 skipping to change at line 900
triangular matrix, such that (up to round-off errors): triangular matrix, such that (up to round-off errors):
\code \code
A == L * transpose(L); A == L * transpose(L);
\endcode \endcode
This implementation cannot be applied in-place, i.e. <tt>&L == &A</ tt> is an error. This implementation cannot be applied in-place, i.e. <tt>&L == &A</ tt> is an error.
If \a A is not symmetric, a <tt>ContractViolation</tt> exception is thrown. If it If \a A is not symmetric, a <tt>ContractViolation</tt> exception is thrown. If it
is not positive definite, the function returns <tt>false</tt>. is not positive definite, the function returns <tt>false</tt>.
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
bool choleskyDecomposition(MultiArrayView<2, T, C1> const & A, bool choleskyDecomposition(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> &L) MultiArrayView<2, T, C2> &L)
{ {
MultiArrayIndex n = columnCount(A); MultiArrayIndex n = columnCount(A);
vigra_precondition(rowCount(A) == n, vigra_precondition(rowCount(A) == n,
"choleskyDecomposition(): Input matrix must be squar e."); "choleskyDecomposition(): Input matrix must be squar e.");
vigra_precondition(n == columnCount(L) && n == rowCount(L), vigra_precondition(n == columnCount(L) && n == rowCount(L),
skipping to change at line 954 skipping to change at line 955
(up to round-off errors): (up to round-off errors):
\code \code
a == q * r; a == q * r;
\endcode \endcode
If \a a doesn't have full rank, the function returns <tt>false</tt> . If \a a doesn't have full rank, the function returns <tt>false</tt> .
The decomposition is computed by householder transformations. It ca n be applied in-place, The decomposition is computed by householder transformations. It ca n be applied in-place,
i.e. <tt>&a == &q</tt> or <tt>&a == &r</tt> are allowed. i.e. <tt>&a == &q</tt> or <tt>&a == &r</tt> are allowed.
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool qrDecomposition(MultiArrayView<2, T, C1> const & a, bool qrDecomposition(MultiArrayView<2, T, C1> const & a,
MultiArrayView<2, T, C2> &q, MultiArrayView<2, T, C3> &r, MultiArrayView<2, T, C2> &q, MultiArrayView<2, T, C3> &r,
double epsilon = 0.0) double epsilon = 0.0)
{ {
const MultiArrayIndex m = rowCount(a); const MultiArrayIndex m = rowCount(a);
const MultiArrayIndex n = columnCount(a); const MultiArrayIndex n = columnCount(a);
vigra_precondition(n == columnCount(r) && m == rowCount(r) && vigra_precondition(n == columnCount(r) && m == rowCount(r) &&
m == columnCount(q) && m == rowCount(q), m == columnCount(q) && m == rowCount(q),
"qrDecomposition(): Matrix shape mismatch."); "qrDecomposition(): Matrix shape mismatch.");
q = identityMatrix<T>(m); q = identityMatrix<T>(m);
MultiArrayView<2,T, StridedArrayTag> tq = transpose(q); MultiArrayView<2,T, StridedArrayTag> tq = transpose(q);
r = a; r = a;
ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty
return ((MultiArrayIndex)detail::qrTransformToUpperTriangular(r, tq, no Pivoting, epsilon) == std::min(m,n)); return (static_cast<MultiArrayIndex>(detail::qrTransformToUpperTriangul ar(r, tq, noPivoting, epsilon) == std::min(m,n)));
} }
/** Deprecated, use \ref linearSolveUpperTriangular(). /** Deprecated, use \ref linearSolveUpperTriangular().
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
inline inline
bool reverseElimination(const MultiArrayView<2, T, C1> &r, const MultiArray View<2, T, C2> &b, bool reverseElimination(const MultiArrayView<2, T, C1> &r, const MultiArray View<2, T, C2> &b,
MultiArrayView<2, T, C3> x) MultiArrayView<2, T, C3> x)
{ {
return linearSolveUpperTriangular(r, b, x); return linearSolveUpperTriangular(r, b, x);
skipping to change at line 1006 skipping to change at line 1007
columns of \a b. This implementation can be applied in-place, i.e. <tt>&b == &x</tt> is allowed. columns of \a b. This implementation can be applied in-place, i.e. <tt>&b == &x</tt> is allowed.
The following size requirements apply: The following size requirements apply:
\code \code
rowCount(r) == columnCount(r); rowCount(r) == columnCount(r);
rowCount(r) == rowCount(b); rowCount(r) == rowCount(b);
columnCount(r) == rowCount(x); columnCount(r) == rowCount(x);
columnCount(b) == columnCount(x); columnCount(b) == columnCount(x);
\endcode \endcode
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool linearSolveUpperTriangular(const MultiArrayView<2, T, C1> &r, const Mu ltiArrayView<2, T, C2> &b, bool linearSolveUpperTriangular(const MultiArrayView<2, T, C1> &r, const Mu ltiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> x) MultiArrayView<2, T, C3> x)
{ {
typedef MultiArrayShape<2>::type Shape;
MultiArrayIndex m = rowCount(r); MultiArrayIndex m = rowCount(r);
MultiArrayIndex rhsCount = columnCount(b); MultiArrayIndex rhsCount = columnCount(b);
vigra_precondition(m == columnCount(r), vigra_precondition(m == columnCount(r),
"linearSolveUpperTriangular(): square coefficient matrix required." ); "linearSolveUpperTriangular(): square coefficient matrix required." );
vigra_precondition(m == rowCount(b) && m == rowCount(x) && rhsCount == columnCount(x), vigra_precondition(m == rowCount(b) && m == rowCount(x) && rhsCount == columnCount(x),
"linearSolveUpperTriangular(): matrix shape mismatch."); "linearSolveUpperTriangular(): matrix shape mismatch.");
for(MultiArrayIndex k = 0; k < rhsCount; ++k) for(MultiArrayIndex k = 0; k < rhsCount; ++k)
{ {
for(int i=m-1; i>=0; --i) for(int i=m-1; i>=0; --i)
skipping to change at line 1057 skipping to change at line 1057
columns of \a b. This implementation can be applied in-place, i.e. <tt>&b == &x</tt> is allowed. columns of \a b. This implementation can be applied in-place, i.e. <tt>&b == &x</tt> is allowed.
The following size requirements apply: The following size requirements apply:
\code \code
rowCount(l) == columnCount(l); rowCount(l) == columnCount(l);
rowCount(l) == rowCount(b); rowCount(l) == rowCount(b);
columnCount(l) == rowCount(x); columnCount(l) == rowCount(x);
columnCount(b) == columnCount(x); columnCount(b) == columnCount(x);
\endcode \endcode
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool linearSolveLowerTriangular(const MultiArrayView<2, T, C1> &l, const Mu ltiArrayView<2, T, C2> &b, bool linearSolveLowerTriangular(const MultiArrayView<2, T, C1> &l, const Mu ltiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> x) MultiArrayView<2, T, C3> x)
{ {
MultiArrayIndex m = columnCount(l); MultiArrayIndex m = columnCount(l);
MultiArrayIndex n = columnCount(b); MultiArrayIndex n = columnCount(b);
vigra_precondition(m == rowCount(l), vigra_precondition(m == rowCount(l),
"linearSolveLowerTriangular(): square coefficient matrix required." ); "linearSolveLowerTriangular(): square coefficient matrix required." );
skipping to change at line 1105 skipping to change at line 1105
columns of \a b. This implementation can be applied in-place, i.e. <tt>&b == &x</tt> is allowed. columns of \a b. This implementation can be applied in-place, i.e. <tt>&b == &x</tt> is allowed.
The following size requirements apply: The following size requirements apply:
\code \code
rowCount(L) == columnCount(L); rowCount(L) == columnCount(L);
rowCount(L) == rowCount(b); rowCount(L) == rowCount(b);
columnCount(L) == rowCount(x); columnCount(L) == rowCount(x);
columnCount(b) == columnCount(x); columnCount(b) == columnCount(x);
\endcode \endcode
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
inline inline
void choleskySolve(MultiArrayView<2, T, C1> & L, MultiArrayView<2, T, C2> c onst & b, MultiArrayView<2, T, C3> & x) void choleskySolve(MultiArrayView<2, T, C1> const & L, MultiArrayView<2, T, C2> const & b, MultiArrayView<2, T, C3> & x)
{ {
/* Solve L * y = b */ /* Solve L * y = b */
linearSolveLowerTriangular(L, b, x); linearSolveLowerTriangular(L, b, x);
/* Solve L^T * x = y */ /* Solve L^T * x = y */
linearSolveUpperTriangular(transpose(L), x, x); linearSolveUpperTriangular(transpose(L), x, x);
} }
/** Solve a linear system. /** Solve a linear system.
<b> Declarations:</b>
\code
// use MultiArrayViews for input and output
template <class T, class C1, class C2, class C3>
bool linearSolve(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const & b,
MultiArrayView<2, T, C3> res,
std::string method = "QR");
// use TinyVector for RHS and result
template <class T, class C1, int N>
bool linearSolve(MultiArrayView<2, T, C1> const & A,
TinyVector<T, N> const & b,
TinyVector<T, N> & res,
std::string method = "QR");
\endcode
\a A is the coefficient matrix, and the column vectors \a A is the coefficient matrix, and the column vectors
in \a b are the right-hand sides of the equation (so, several equat ions in \a b are the right-hand sides of the equation (so, several equat ions
with the same coefficients can be solved in one go). The result is returned with the same coefficients can be solved in one go). The result is returned
in \a res, whose columns contain the solutions for the correspondin g in \a res, whose columns contain the solutions for the correspondin g
columns of \a b. The number of columns of \a A must equal the numbe r of rows of columns of \a b. The number of columns of \a A must equal the numbe r of rows of
both \a b and \a res, and the number of columns of \a b and \a res must match. both \a b and \a res, and the number of columns of \a b and \a res must match.
If right-hand-side and result are specified as TinyVector, the numb
er of columns
of \a A must equal N.
\a method must be one of the following: \a method must be one of the following:
<DL> <DL>
<DT>"Cholesky"<DD> Compute the solution by means of Cholesky decomp osition. The <DT>"Cholesky"<DD> Compute the solution by means of Cholesky decomp osition. The
coefficient matrix \a A must by symmetric positi ve definite. If coefficient matrix \a A must by symmetric positi ve definite. If
this is not the case, the function returns <tt>f alse</tt>. this is not the case, the function returns <tt>f alse</tt>.
<DT>"QR"<DD> (default) Compute the solution by means of QR decompos ition. The <DT>"QR"<DD> (default) Compute the solution by means of QR decompos ition. The
coefficient matrix \a A can be square or rectang ular. In the latter case, coefficient matrix \a A can be square or rectang ular. In the latter case,
it must have more rows than columns, and the sol ution will be computed in the it must have more rows than columns, and the sol ution will be computed in the
skipping to change at line 1164 skipping to change at line 1184
(provided they have the required shapes). (provided they have the required shapes).
The following size requirements apply: The following size requirements apply:
\code \code
rowCount(r) == rowCount(b); rowCount(r) == rowCount(b);
columnCount(r) == rowCount(x); columnCount(r) == rowCount(x);
columnCount(b) == columnCount(x); columnCount(b) == columnCount(x);
\endcode \endcode
<b>\#include</b> \<vigra/linear_solve.hxx\> or<br> <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
doxygen_overloaded_function(template <...> bool linearSolve)
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool linearSolve(const MultiArrayView<2, T, C1> &A, const MultiArrayView<2, bool linearSolve(MultiArrayView<2, T, C1> const & A,
T, C2> &b, MultiArrayView<2, T, C2> const & b,
MultiArrayView<2, T, C3> & res, std::string method = "QR") MultiArrayView<2, T, C3> res,
std::string method = "QR")
{ {
typedef typename Matrix<T>::difference_type Shape;
typedef typename Matrix<T>::view_type SubMatrix;
const MultiArrayIndex n = columnCount(A); const MultiArrayIndex n = columnCount(A);
const MultiArrayIndex m = rowCount(A); const MultiArrayIndex m = rowCount(A);
vigra_precondition(n <= m, vigra_precondition(n <= m,
"linearSolve(): Coefficient matrix A must have at least as many row s as columns."); "linearSolve(): Coefficient matrix A must have at least as many row s as columns.");
vigra_precondition(n == rowCount(res) && vigra_precondition(n == rowCount(res) &&
m == rowCount(b) && columnCount(b) == columnCount(re s), m == rowCount(b) && columnCount(b) == columnCount(re s),
"linearSolve(): matrix shape mismatch."); "linearSolve(): matrix shape mismatch.");
method = tolower(method); method = tolower(method);
skipping to change at line 1196 skipping to change at line 1217
{ {
vigra_precondition(columnCount(A) == rowCount(A), vigra_precondition(columnCount(A) == rowCount(A),
"linearSolve(): Cholesky method requires square coefficient mat rix."); "linearSolve(): Cholesky method requires square coefficient mat rix.");
Matrix<T> L(A.shape()); Matrix<T> L(A.shape());
if(!choleskyDecomposition(A, L)) if(!choleskyDecomposition(A, L))
return false; // false if A wasn't symmetric positive definite return false; // false if A wasn't symmetric positive definite
choleskySolve(L, b, res); choleskySolve(L, b, res);
} }
else if(method == "qr") else if(method == "qr")
{ {
return (MultiArrayIndex)linearSolveQR(A, b, res) == n; return static_cast<MultiArrayIndex>(linearSolveQR(A, b, res)) == n;
} }
else if(method == "ne") else if(method == "ne")
{ {
return linearSolve(transpose(A)*A, transpose(A)*b, res, "Cholesky") ; return linearSolve(transpose(A)*A, transpose(A)*b, res, "Cholesky") ;
} }
else if(method == "svd") else if(method == "svd")
{ {
MultiArrayIndex rhsCount = columnCount(b); MultiArrayIndex rhsCount = columnCount(b);
Matrix<T> u(A.shape()), s(n, 1), v(n, n); Matrix<T> u(A.shape()), s(n, 1), v(n, n);
MultiArrayIndex rank = (MultiArrayIndex)singularValueDecomposition( A, u, s, v); MultiArrayIndex rank = static_cast<MultiArrayIndex>(singularValueDe composition(A, u, s, v));
Matrix<T> t = transpose(u)*b; Matrix<T> t = transpose(u)*b;
for(MultiArrayIndex l=0; l<rhsCount; ++l) for(MultiArrayIndex l=0; l<rhsCount; ++l)
{ {
for(MultiArrayIndex k=0; k<rank; ++k) for(MultiArrayIndex k=0; k<rank; ++k)
t(k,l) /= s(k,0); t(k,l) /= s(k,0);
for(MultiArrayIndex k=rank; k<n; ++k) for(MultiArrayIndex k=rank; k<n; ++k)
t(k,l) = NumericTraits<T>::zero(); t(k,l) = NumericTraits<T>::zero();
} }
res = v*t; res = v*t;
return (rank == n); return (rank == n);
} }
else else
{ {
vigra_precondition(false, "linearSolve(): Unknown solution method." ); vigra_precondition(false, "linearSolve(): Unknown solution method." );
} }
return true; return true;
} }
template <class T, class C1, int N>
bool linearSolve(MultiArrayView<2, T, C1> const & A,
TinyVector<T, N> const & b,
TinyVector<T, N> & res,
std::string method = "QR")
{
Shape2 shape(N, 1);
return linearSolve(A, MultiArrayView<2, T>(shape, b.data()), MultiArray
View<2, T>(shape, res.data()), method);
}
//@} //@}
} // namespace linalg } // namespace linalg
using linalg::inverse; using linalg::inverse;
using linalg::determinant; using linalg::determinant;
using linalg::logDeterminant; using linalg::logDeterminant;
using linalg::linearSolve; using linalg::linearSolve;
using linalg::choleskySolve; using linalg::choleskySolve;
using linalg::choleskyDecomposition; using linalg::choleskyDecomposition;
 End of changes. 36 change blocks. 
48 lines changed or deleted 81 lines changed or added


 localminmax.hxx   localminmax.hxx 
skipping to change at line 48 skipping to change at line 48
#include <vector> #include <vector>
#include <functional> #include <functional>
#include "utilities.hxx" #include "utilities.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "initimage.hxx" #include "initimage.hxx"
#include "labelimage.hxx" #include "labelimage.hxx"
#include "labelvolume.hxx" #include "labelvolume.hxx"
#include "pixelneighborhood.hxx" #include "pixelneighborhood.hxx"
#include "voxelneighborhood.hxx" #include "voxelneighborhood.hxx"
#include "multi_shape.hxx"
namespace vigra namespace vigra
{ {
/** \addtogroup LocalMinMax Local Minima and Maxima /** \addtogroup LocalMinMax Local Minima and Maxima
Detect local minima and maxima in a gray level image, Detect local minima and maxima in a gray level image,
including extremal plateaus larger than 1 pixel including extremal plateaus larger than 1 pixel
*/ */
//@{ //@{
skipping to change at line 195 skipping to change at line 196
bool allowExtremaAtBorder = false) bool allowExtremaAtBorder = false)
{ {
int w = shp[0]; int w = shp[0];
int h = shp[1]; int h = shp[1];
int d = shp[2]; int d = shp[2];
int x, y, z; int x, y, z;
if (allowExtremaAtBorder) if (allowExtremaAtBorder)
{ {
throw std::runtime_error("not implemented!"); throw std::runtime_error("Not implemented (use localMinima() or loc
/* alMaxima() instead).");
SrcIterator is = sul;
DestIterator id = dul;
for(x=0; x<w; ++x, ++is.x, ++id.x)
{
if(isLocalExtremum(is, sa, neighborhood, threshold, compare,
isAtImageBorder(x, 0, w, h)))
da.set(marker, id);
}
is = sul + Diff2D(0,1);
id = dul + Diff2D(0,1);
for(y=1; y<h-1; ++y, ++is.y, ++id.y)
{
if(isLocalExtremum(is, sa, neighborhood, threshold, compare,
isAtImageBorder(0, y, w, h)))
da.set(marker, id);
}
is = sul + Diff2D(w-1,1);
id = dul + Diff2D(w-1,1);
for(y=1; y<h-1; ++y, ++is.y, ++id.y)
{
if(isLocalExtremum(is, sa, neighborhood, threshold, compare,
isAtImageBorder(w-1, y, w, h)))
da.set(marker, id);
}
is = sul + Diff2D(0,h-1);
id = dul + Diff2D(0,h-1);
for(x=0; x<w; ++x, ++is.x, ++id.x)
{
if(isLocalExtremum(is, sa, neighborhood, threshold, compare,
isAtImageBorder(x, h-1, w, h)))
da.set(marker, id);
}
*/
} }
w -= 2; w -= 2;
h -= 2; h -= 2;
d -= 2; d -= 2;
sul.dim0() += 1; sul.dim0() += 1;
sul.dim1() += 1; sul.dim1() += 1;
sul.dim2() += 1; sul.dim2() += 1;
dul += Diff3D(1, 1, 1); dul += Diff3D(1, 1, 1);
skipping to change at line 512 skipping to change at line 472
for (x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0(), ++xl.dim0()) for (x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0(), ++xl.dim0())
{ {
if(isExtremum[*xl]) if(isExtremum[*xl])
da.set(marker, xd); da.set(marker, xd);
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue,
class Neighborhood, class Compare, class Equal>
void
extendedLocalMinMaxOld(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestValue marker,
Neighborhood /*neighborhood*/,
Compare compare, Equal equal,
typename SrcAccessor::value_type threshold,
bool allowExtremaAtBorder = false)
{
typedef typename SrcAccessor::value_type SrcType;
int w = slr.x - sul.x;
int h = slr.y - sul.y;
int i,x,y;
BasicImage<int> labels(w,h);
int number_of_regions =
labelImage(sul, slr, sa, labels.upperLeft(), labels.accessor(),
(Neighborhood::DirectionCount == 8), equal);
// assume that a region is a extremum until the opposite is proved
std::vector<unsigned char> isExtremum(number_of_regions+1, (unsigned ch
ar)1);
BasicImage<int>::traverser ly = labels.upperLeft();
for(y=0; y<h; ++y, ++sul.y, ++ly.y)
{
SrcIterator sx = sul;
BasicImage<int>::traverser lx(ly);
for(x=0; x<w; ++x, ++sx.x, ++lx.x)
{
int lab = *lx;
SrcType v = sa(sx);
if(x == 0 || y == 0 || x == w-1 || y == h-1 || !compare(v, thre
shold))
{
// mark all regions that touch the image border as non-extr
emum
// likewise for all pixels that don't exceed the threshold
isExtremum[lab] = 0;
continue;
}
NeighborhoodCirculator<SrcIterator, Neighborhood> sc(sx);
NeighborhoodCirculator<BasicImage<int>::traverser, Neighborhood
> lc(lx);
for(i=0; i<Neighborhood::DirectionCount; ++i, ++sc, ++lc)
{
if(lab != *lc && compare(sa(sc),v))
isExtremum[lab] = 0;
}
}
}
ly = labels.upperLeft();
for(y=0; y<h; ++y, ++dul.y, ++ly.y)
{
DestIterator xd = dul;
BasicImage<int>::Iterator lx(ly);
for(x=0; x<w; ++x, ++xd.x, ++lx.x)
{
if(isExtremum[*lx])
da.set(marker, xd);
}
}
}
} // namespace detail } // namespace detail
/** \brief Options object for localMinima() and localMaxima(). /** \brief Options object for localMinima() and localMaxima().
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/localminmax.hxx\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(w,h), minima(w,h); MultiArray<2, unsigned char> src(w,h), minima(w,h);
... // fill src ... // fill src
// use 4-neighborhood, allow minima at the image border, // use 4-neighborhood, allow minima at the image border,
// and discard those where the gray value is not below 5 // and discard those where the gray value is not below 5
vigra::localMinima(srcImageRange(src), destImage(minima), localMinima(src, minima,
vigra::LocalMinmaxOptions().neighborhood(4).allowAtB LocalMinmaxOptions().neighborhood(4).allowAtBorder().thresh
order().threshold(5)); old(5));
\endcode \endcode
*/ */
class LocalMinmaxOptions class LocalMinmaxOptions
{ {
public: public:
double marker, thresh; double marker, thresh;
int neigh; int neigh;
bool use_threshold, allow_at_border, allow_plateaus; bool use_threshold, allow_at_border, allow_plateaus;
skipping to change at line 629 skipping to change at line 518
use_threshold(false), use_threshold(false),
allow_at_border(false), allow_at_border(false),
allow_plateaus(false) allow_plateaus(false)
{} {}
/**\brief Use the given neighborhood. /**\brief Use the given neighborhood.
The value '0' indicates direct neighborhood (i.e. 4-neighborhoo d The value '0' indicates direct neighborhood (i.e. 4-neighborhoo d
in 2D, 6-neighborhood in 3D, 2*N neighborhood in N-D), the valu e '1' in 2D, 6-neighborhood in 3D, 2*N neighborhood in N-D), the valu e '1'
indicates indirect neighborhood (i.e. 8-neighborhood in 2D, indicates indirect neighborhood (i.e. 8-neighborhood in 2D,
26-neighborhood in 3D, 3<sup>N</sup>-1 neighborhood in N-D). Th 26-neighborhood in 3D, 3<sup>N</sup>-1 neighborhood in N-D). Th
e specific number e appropriate
of neighbors for the desired dimension can also be used. number of neighbors for the desired dimension and the constants
<tt>DirectNeighborhood</tt> and <tt>IndirectNeighborhood</tt> c
an be used as well.
Default: 1 (indirect neighborhood) Default: 1 (indirect neighborhood)
*/ */
LocalMinmaxOptions & neighborhood(unsigned int n) LocalMinmaxOptions & neighborhood(unsigned int n)
{ {
neigh = n; neigh = n;
return *this; return *this;
} }
LocalMinmaxOptions & neighborhood(NeighborhoodType n)
{
neigh = n;
return *this;
}
/**\brief Mark extrema in the destination image with the given valu e. /**\brief Mark extrema in the destination image with the given valu e.
Default: 1 Default: 1
*/ */
LocalMinmaxOptions & markWith(double m) LocalMinmaxOptions & markWith(double m)
{ {
marker = m; marker = m;
return *this; return *this;
} }
skipping to change at line 696 skipping to change at line 592
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* localMinima */ /* localMinima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local minima in an image or multi-dimensional array. /** \brief Find local minima in an image or multi-dimensional array.
Note: the function is not yet implemented for arbitrary dimensional
arrays, but see \ref localMinima3D() for 3D.
By default, minima are defined as points which are not By default, minima are defined as points which are not
at the array border and whose value is lower than the value at the array border and whose value is lower than the value
of all indirect neighbors (i.e. 8-neighbors in 2D, of all indirect neighbors (i.e. 8-neighbors in 2D,
26-neighbors in 3D, 3<sup>N</sup>-1 neighbors in N-D). 26-neighbors in 3D, 3<sup>N</sup>-1 neighbors in N-D).
The detected points will be marked The detected points will be marked
with the default value 1 in the destination array. with the default value 1 in the destination array.
The defaults can be overridden in various ways by providing The defaults can be overridden in various ways by providing
\ref LocalMinmaxOptions : you can switch to the direct neighborhood \ref LocalMinmaxOptions : you can switch to the direct neighborhood
(i.e. 4-neighborhood in 2D, 6-neighborhood in 3D, 2*N neighborhood (i.e. 4-neighborhood in 2D, 6-neighborhood in 3D, 2*N neighborhood
skipping to change at line 733 skipping to change at line 626
\code \code
namespace vigra { namespace vigra {
template <unsigned int N, class T1, class C1, class T2, class C2> template <unsigned int N, class T1, class C1, class T2, class C2>
void void
localMinima(MultiArrayView<N, T1, C1> src, localMinima(MultiArrayView<N, T1, C1> src,
MultiArrayView<N, T2, C2> dest, MultiArrayView<N, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions ()); LocalMinmaxOptions const & options = LocalMinmaxOptions ());
} }
\endcode \endcode
pass image iterators explicitly: \deprecatedAPI{localMinima}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
LocalMinmaxOptions const & options = LocalMinmaxOptions ()); LocalMinmaxOptions const & options = LocalMinmaxOptions ());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions ()); LocalMinmaxOptions const & options = LocalMinmaxOptions ());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/localminmax.hxx\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
<b>\#include</b> \<vigra/multi_localminmax.hxx\><br> <b>\#include</b> \<vigra/multi_localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// 3D examples using MultiArray // 3D examples (other dimensions work likewise)
vigra::MultiArrayShape<3>::type shape(w,h,d); Shape3 shape(w,h,d);
vigra::MultiArray<3, unsigned char> src(shape), minima(shape); MultiArray<3, unsigned char> src(shape), minima(shape);
... // fill src ... // fill src
// use default parameterisation // use default parameterisation
vigra::localMinima(src, minima); localMinima(src, minima);
// reset destination image // reset destination image
minima = 0; minima = 0;
// use 6-neighborhood and allow minima at the image border // use direct neighborhood (i.e. 6-neighborhood since we are in 3D)
vigra::localMinima(src, minima, // and allow minima at the image border
vigra::LocalMinmaxOptions().neighborhood(6).allowAtB localMinima(src, minima,
order()); LocalMinmaxOptions().neighborhood(0).allowAtBorder());
\endcode \endcode
\deprecatedUsage{localMinima}
\code \code
// 2D examples using BasicImage // 2D examples using BasicImage
vigra::BImage src(w,h), minima(w,h); BImage src(w,h), minima(w,h);
... // fill src ... // fill src
// use default parameterisation // use default parameterisation
vigra::localMinima(srcImageRange(src), destImage(minima)); localMinima(srcImageRange(src), destImage(minima));
// reset destination image // reset destination image
minima = 0; minima = 0;
// use 4-neighborhood and allow minima at the image border // use 4-neighborhood and allow minima at the image border
vigra::localMinima(srcImageRange(src), destImage(minima), localMinima(srcImageRange(src), destImage(minima),
vigra::LocalMinmaxOptions().neighborhood(4).allowAtB LocalMinmaxOptions().neighborhood(4).allowAtBorder()
order()); );
// reset destination image // reset destination image
minima = 0; minima = 0;
// allow extended minima (minimal plateaus) and use value '255' as a ma rker // allow extended minima (minimal plateaus) and use value '255' as a ma rker
vigra::localMinima(srcImageRange(src), destImage(minima), localMinima(srcImageRange(src), destImage(minima),
vigra::LocalMinmaxOptions().allowPlateaus().markWith LocalMinmaxOptions().allowPlateaus().markWith(255));
(255));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestIterator dest_upperleft; DestIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u < u u < u
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void localMinima) doxygen_overloaded_function(template <...> void localMinima)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
LocalMinmaxOptions const & options = LocalMinmaxOptions()) LocalMinmaxOptions const & options = LocalMinmaxOptions())
{ {
skipping to change at line 961 skipping to change at line 856
/************************************************************************** / /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* localMinima3D */ /* localMinima3D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local minima in a 3D multi array. /** \brief Find local minima in a 3D multi array.
By default, minima are defined as points which are not Deprecated, use localMinima() instead.
at the array border and whose value is lower than the value
of all indirect neighbors.
The detected points will be marked. See localMinima() for more details.
*/ */
doxygen_overloaded_function(template <...> void localMinima3D) doxygen_overloaded_function(template <...> void localMinima3D)
template<class SrcIterator, class SrcAccessor, class SrcShape, template<class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa, localMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker, DestValue marker,
skipping to change at line 1014 skipping to change at line 906
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src, localMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, DestValue marker,
NeighborCode3DSix neighborhood) NeighborCode3DSix neighborhood)
{ {
localMinima3D(src.first, src.second, src.third, dest.first, dest.second , localMinima3D(src.first, src.second, src.third, dest.first, dest.second ,
marker, neighborhood); marker, neighborhood);
} }
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src, localMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, DestValue marker,
NeighborCode3DTwentySix neighborhood) NeighborCode3DTwentySix neighborhood)
{ {
localMinima3D(src.first, src.second, src.third, dest.first, dest.second , localMinima3D(src.first, src.second, src.third, dest.first, dest.second ,
marker, neighborhood); marker, neighborhood);
}
template<class T1, class S1,
class T2, class S2,
class DestValue,
class Neighborhood>
inline void
localMinima3D(MultiArrayView<3, T1, S1> const & src,
MultiArrayView<3, T2, S2> dest,
DestValue marker,
Neighborhood neighborhood)
{
localMinima3D(srcMultiArrayRange(src), destMultiArray(dest),
marker, neighborhood);
}
template<class T1, class S1,
class T2, class S2,
class DestValue>
inline void
localMinima3D(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DestValue marker)
{
localMinima3D(srcMultiArrayRange(src), destMultiArray(dest),
marker, NeighborCode3DSix());
} }
/************************************************************************** / /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* localMaxima */ /* localMaxima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local maxima in an image or multi-dimensional array. /** \brief Find local maxima in an image or multi-dimensional array.
Note: the function is not yet implemented for arbitrary dimensional
arrays, but see \ref localMaxima3D() for 3D.
By default, maxima are defined as points which are not By default, maxima are defined as points which are not
at the array border and whose value is higher than the value at the array border and whose value is higher than the value
of all indirect neighbors (i.e. 8-neighbors in 2D, of all indirect neighbors (i.e. 8-neighbors in 2D,
26-neighbors in 3D, 3<sup>N</sup>-1 neighbors in N-D). 26-neighbors in 3D, 3<sup>N</sup>-1 neighbors in N-D).
The detected points will be marked The detected points will be marked
with the default value 1 in the destination array. with the default value 1 in the destination array.
The defaults can be overridden in various ways by providing The defaults can be overridden in various ways by providing
\ref LocalMinmaxOptions : you can switch to the direct neighborhood \ref LocalMinmaxOptions : you can switch to the direct neighborhood
(i.e. 4-neighborhood in 2D, 6-neighborhood in 3D, 2*N neighborhood (i.e. 4-neighborhood in 2D, 6-neighborhood in 3D, 2*N neighborhood
skipping to change at line 1076 skipping to change at line 991
\code \code
namespace vigra { namespace vigra {
template <unsigned int N, class T1, class C1, class T2, class C2> template <unsigned int N, class T1, class C1, class T2, class C2>
void void
localMaxima(MultiArrayView<N, T1, C1> src, localMaxima(MultiArrayView<N, T1, C1> src,
MultiArrayView<N, T2, C2> dest, MultiArrayView<N, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions ()); LocalMinmaxOptions const & options = LocalMinmaxOptions ());
} }
\endcode \endcode
pass image iterators explicitly: \deprecatedAPI{localMaxima}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
LocalMinmaxOptions const & options = LocalMinmaxOptions ()); LocalMinmaxOptions const & options = LocalMinmaxOptions ());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions ()); LocalMinmaxOptions const & options = LocalMinmaxOptions ());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/localminmax.hxx\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
<b>\#include</b> \<vigra/multi_localminmax.hxx\><br> <b>\#include</b> \<vigra/multi_localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// 3D examples using MultiArray // 3D examples (other dimensions work likewise)
vigra::MultiArrayShape<3>::type shape(w,h,d); Shape3 shape(w,h,d);
vigra::MultiArray<3, unsigned char> src(shape), maxima(shape); MultiArray<3, unsigned char> src(shape), maxima(shape);
... // fill src ... // fill src
// use default parameterisation // use default parameterisation
vigra::localMaxima(src, maxima); localMaxima(src, maxima);
// reset destination image // reset destination image
maxima = 0; maxima = 0;
// use 6-neighborhood and allow maxima at the image border // use direct neighborhood (i.e. 6-neighborhood sine we are in 3D)
vigra::localMaxima(src, maxima, // and allow maxima at the image border
vigra::LocalMinmaxOptions().neighborhood(6).allowAtB localMaxima(src, maxima,
order()); LocalMinmaxOptions().neighborhood(0).allowAtBorder());
\endcode \endcode
\deprecatedUsage{localMaxima}
\code \code
// 2D examples using BasicImage // 2D examples using BasicImage
vigra::BImage src(w,h), maxima(w,h); BImage src(w,h), maxima(w,h);
... // fill src ... // fill src
// use default parameterisation // use default parameterisation
vigra::localMaxima(srcImageRange(src), destImage(maxima)); localMaxima(srcImageRange(src), destImage(maxima));
// reset destination image // reset destination image
maxima = 0; maxima = 0;
// use 4-neighborhood and allow maxima at the image border // use 4-neighborhood and allow maxima at the image border
vigra::localMaxima(srcImageRange(src), destImage(maxima), localMaxima(srcImageRange(src), destImage(maxima),
vigra::LocalMinmaxOptions().neighborhood(4).allowAtB LocalMinmaxOptions().neighborhood(4).allowAtBorder()
order()); );
// reset destination image // reset destination image
maxima = 0; maxima = 0;
// allow extended maxima (maximal plateaus) and use value '255' as a ma rker // allow extended maxima (maximal plateaus) and use value '255' as a ma rker
vigra::localMaxima(srcImageRange(src), destImage(maxima), localMaxima(srcImageRange(src), destImage(maxima),
vigra::LocalMinmaxOptions().allowPlateaus().markWith LocalMinmaxOptions().allowPlateaus().markWith(255));
(255));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestIterator dest_upperleft; DestIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
u < u u < u
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void localMaxima) doxygen_overloaded_function(template <...> void localMaxima)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
LocalMinmaxOptions const & options = LocalMinmaxOptions()) LocalMinmaxOptions const & options = LocalMinmaxOptions())
{ {
skipping to change at line 1303 skipping to change at line 1220
/************************************************************************** / /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* localMaxima3D */ /* localMaxima3D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local maxima in a 3D multi array. /** \brief Find local maxima in a 3D multi array.
By default, maxima are defined as points which are not Deprecated, use \ref localMaxima() instead.
at the array border and whose value is higher than the value
of all indirect neighbors.
The detected points will be marked as specified. See localMaxima() for mor
details.
*/ */
doxygen_overloaded_function(template <...> void localMaxima3D) doxygen_overloaded_function(template <...> void localMaxima3D)
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa, localMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker, DestValue marker,
NeighborCode3DSix neighborhood) NeighborCode3DSix neighborhood)
skipping to change at line 1351 skipping to change at line 1265
DestValue marker, DestValue marker,
NeighborCode3DTwentySix neighborhood) NeighborCode3DTwentySix neighborhood)
{ {
localMaxima3D(src.first, src.second, src.third, dest.first, dest.second , localMaxima3D(src.first, src.second, src.third, dest.first, dest.second ,
marker, neighborhood); marker, neighborhood);
} }
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMaxima3D(vigra::triple<SrcIterator, SrcShape, SrcAccessor> src, localMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
std::pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker) DestValue marker)
{ {
localMaxima3D(src.first, src.second, src.third, dest.first, dest.second , localMaxima3D(src.first, src.second, src.third, dest.first, dest.second ,
marker, NeighborCode3DSix()); marker, NeighborCode3DSix());
} }
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> src, localMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, DestValue marker,
NeighborCode3DSix neighborhood) NeighborCode3DSix neighborhood)
{ {
localMaxima3D(src.first, src.second, src.third, dest.first, dest.second , localMaxima3D(src.first, src.second, src.third, dest.first, dest.second ,
marker, neighborhood); marker, neighborhood);
} }
template<class T1, class S1,
class T2, class S2,
class DestValue,
class Neighborhood>
inline void
localMaxima3D(MultiArrayView<3, T1, S1> const & src,
MultiArrayView<3, T2, S2> dest,
DestValue marker,
Neighborhood neighborhood)
{
localMaxima3D(srcMultiArrayRange(src), destMultiArray(dest),
marker, neighborhood);
}
template<class T1, class S1,
class T2, class S2,
class DestValue>
inline void
localMaxima3D(MultiArrayView<3, T1, S1> const & src,
MultiArrayView<3, T2, S2> dest,
DestValue marker)
{
localMaxima3D(srcMultiArrayRange(src), destMultiArray(dest),
marker, NeighborCode3DSix());
}
/************************************************************************** / /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMinima */ /* extendedLocalMinima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local minimal regions in an image or volume. /** \brief Find local minimal regions (plateaus) in an array.
Note: the function is not yet implemented for arbitrary dimensional This function is only needed when you want to pass a non-standard equal
arrays, but see \ref extendedLocalMinima3D() for 3D. ity
predicate via <tt>EqualityFunctor</tt>. Otherwise (i.e. when equality
This function finds regions of uniform pixel value is defined by the '==' operator of the source value type <tt>T1</tt>),
whose neighboring regions are all have smaller values you can simply call \ref localMinima() with the option
(minimal plateaus of arbitrary size). By default, the pixels <tt>LocalMinmaxOptions::allowPlateaus()</tt>.
in a plateau have exactly identical values. By passing an <tt>EqualityF
unctor</tt> This function finds regions of uniform pixel values
with tolerance, one can allow for plateaus that are not quite constant whose neighboring regions all have larger values, i.e. it finds minimal
(this is often necessary with float pixel values). Pass plateaus of arbitrary size (including size 1). The <tt>EqualityFunctor<
\ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode /tt>
to determine the neighborhood where pixel values are compared. determines when pixels are considered equal, so that one can allow
for plateaus that are not quite constant (this is often necessary
Minimal regions are with float pixel values). Otherwise, the functionality is identical to
marked in the destination image with the given marker value \ref localMinima().
(default is 1), all other destination pixels remain unchanged.
<TT>SrcAccessor::value_type</TT> must be equality-comparable and
less-comparable. A pixel or region touching the image border will
never be marked as minimum or minimal plateau. Use localMinima() with t
he
appropriate options if you need that functionality. Likewise if you wan
t to
apply a threshold onl the fly. In fact, all functionality
except for 'equality with tolerance' can be accessed via that function
in
a more readable way, so localMinima() should be preferred.
The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
use 3-dimensional arrays: use arbitrary-dimensional arrays:
\code \code
namespace vigra { namespace vigra {
template <class T1, class C1, class T2, class C2, template <unsigned int N, class T1, class S1,
class Neighborhood> class T2, class S2,
void class EqualityFunctor>
extendedLocalMinima(MultiArrayView<3, T1, C1> src, unsigned int
MultiArrayView<3, T2, C2> dest, extendedLocalMinima(MultiArrayView<N, T1, S1> const & src,
LocalMinmaxOptions const & options = LocalMinma MultiArrayView<N, T2, S2> dest,
xOptions()); EqualityFunctor const & equal,
LocalMinmaxOptions options = LocalMinmaxOptions
());
\endcode \endcode
pass image iterators explicitly: \deprecatedAPI{extendedLocalMinima}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue = DestAccessor::value_type, class DestValue = DestAccessor::value_type,
class Neighborhood = EightNeighborCode, class Neighborhood = EightNeighborCode,
class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> > class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> >
void void
extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor s a, extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor s a,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker = NumericTraits<DestValue>::on e(), DestValue marker = NumericTraits<DestValue>::on e(),
Neighborhood neighborhood = EightNeighborCode() , Neighborhood neighborhood = EightNeighborCode() ,
EqualityFunctor equal = EqualityFunctor()); EqualityFunctor equal = EqualityFunctor());
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood = NeighborCode3DSix,
class EqualityFunctor = std::equal_to<typename SrcAssessor
::value_type> >
void
extendedLocalMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa
,
DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood = Neighborhood(),
EqualityFunctor equal = EqualityFunctor());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue = DestAccessor::value_type, class DestValue = DestAccessor::value_type,
class Neighborhood = EightNeighborCode, class Neighborhood = EightNeighborCode,
class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> > class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> >
void void
extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker = NumericTraits<DestValue>::on e(), DestValue marker = NumericTraits<DestValue>::on e(),
Neighborhood neighborhood = EightNeighborCode() , Neighborhood neighborhood = EightNeighborCode() ,
EqualityFunctor equal = EqualityFunctor()); EqualityFunctor equal = EqualityFunctor());
template<class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood>
void
extendedLocalMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> sr
c,
pair<DestIterator, DestAccessor> dest,
typename DestAccessor::value_type marker,
Neighborhood neighborhood);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/localminmax.hxx\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// define an equality functor
template <class T>
struct EqualWithToleranceFunctor
{
EqualWithToleranceFunctor(T tolerance)
: t(tolerance)
{}
bool operator()(T l, T r) const
{
return abs(l-r) <= t;
}
T t;
};
MultiArray<2, unsigned char> src(w,h), minima(w,h);
// allow plateaus
localMinima(src, minima, LocalMinmaxOptions().allowPlateaus());
// reset result image
minima.init(0);
// allow plateaus with tolerance (grayvalues may differ by one)
extendedLocalMinima(src, minima, EqualWithToleranceFunctor<unsigned cha
r>(1));
\endcode
\deprecatedUsage{extendedLocalMinima}
\code
// optional: define an equality functor // optional: define an equality functor
template <class T> template <class T>
struct EqualWithToleranceFunctor struct EqualWithToleranceFunctor
{ {
EqualWithToleranceFunctor(T tolerance) EqualWithToleranceFunctor(T tolerance)
: t(tolerance) : t(tolerance)
{} {}
bool operator()(T l, T r) const bool operator()(T l, T r) const
{ {
return vigra::abs(l-r) <= t; return abs(l-r) <= t;
} }
T t; T t;
}; };
vigra::BImage src(w,h), minima(w,h); BImage src(w,h), minima(w,h);
// init destiniation image // init destiniation image
minima.init(0); minima.init(0);
vigra::extendedLocalMinima(srcImageRange(src), destImage(minima)); extendedLocalMinima(srcImageRange(src), destImage(minima));
// allow plateaus with tolerance // allow plateaus with tolerance
minima.init(0); minima.init(0);
vigra::extendedLocalMinima(srcImageRange(src), destImage(minima), 1.0, extendedLocalMinima(srcImageRange(src), destImage(minima), 1.0,
FourNeighborCode(),
EqualWithToleranceFunctor<unsigned char>(1)) ; EqualWithToleranceFunctor<unsigned char>(1)) ;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
EqualityFunctor equal; EqualityFunctor equal;
u == u u == u
equal(u, u); equal(u, u);
u < u u < u
DestValue marker; DestValue marker;
dest_accessor.set(marker, dest_upperleft); dest_accessor.set(marker, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void extendedLocalMinima) doxygen_overloaded_function(template <...> void extendedLocalMinima)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood, class EqualityFunctor> class Neighborhood, class EqualityFunctor>
inline void inline void
extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker, typename DestAccessor::value_type marker,
skipping to change at line 1550 skipping to change at line 1530
marker, neighborhood, std::equal_to<SrcType>()); marker, neighborhood, std::equal_to<SrcType>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker) typename DestAccessor::value_type marker)
{ {
typedef typename SrcAccessor::value_type SrcType;
extendedLocalMinima(sul, slr, sa, dul, da, extendedLocalMinima(sul, slr, sa, dul, da,
marker, EightNeighborCode()); marker, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da) DestIterator dul, DestAccessor da)
{ {
skipping to change at line 1622 skipping to change at line 1600
/************************************************************************** / /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMinima3D */ /* extendedLocalMinima3D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local minimal regions in a volume. /** \brief Find local minimal regions in a volume.
This function finds regions of uniform pixel value See \ref extendedLocalMinima().
whose neighboring regions are all have smaller values
(minimal plateaus of arbitrary size). By default, the pixels
in a plateau have exactly identical values. By passing an <tt>EqualityFunc
tor</tt>
with tolerance, one can allow for plateaus that are not quite constant
(this is often necessary with float pixel values). Pass the neighborhood
where pixel values are compared. See extendedLocalMinima() for more detail
s.
*/ */
doxygen_overloaded_function(template <...> void extendedLocalMinima3D) doxygen_overloaded_function(template <...> void extendedLocalMinima3D)
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood, class DestIterator, class DestAccessor, class Neighborhood,
class EqualityFunctor> class EqualityFunctor>
inline void inline void
extendedLocalMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa, extendedLocalMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
skipping to change at line 1696 skipping to change at line 1668
} }
/************************************************************************** / /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMaxima */ /* extendedLocalMaxima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local maximal regions in an image or volume. /** \brief Find local maximal regions in an array.
Note: the function is not yet implemented for arbitrary dimensional
arrays, but see \ref extendedLocalMaxima3D() for 3D.
This function finds regions of uniform pixel value This function is only needed when you want to pass a non-standard equal
whose neighboring regions are all have smaller values ity
(maximal plateaus of arbitrary size). By default, the pixels predicate via <tt>EqualityFunctor</tt>. Otherwise (i.e. when equality
in a plateau have exactly identical values. By passing an <tt>EqualityF is defined by the '==' operator of the source value type <tt>T1</tt>),
unctor</tt> you can simply call \ref localMaxima() with the option
with tolerance, one can allow for plateaus that are not quite constant <tt>LocalMinmaxOptions::allowPlateaus()</tt>.
(this is often necessary with float pixel values). Pass
\ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode This function finds regions of uniform pixel values
to determine the neighborhood where pixel values are compared. whose neighboring regions all have smaller values, i.e. it finds maxima
l
Maximal regions are plateaus of arbitrary size (including size 1). The <tt>EqualityFunctor<
marked in the destination image with the given marker value /tt>
(default is 1), all other destination pixels remain unchanged. determines when pixels are considered equal, so that one can allow
<TT>SrcAccessor::value_type</TT> must be equality-comparable and for plateaus that are not quite constant (this is often necessary
less-comparable. A pixel or region touching the image border will with float pixel values). Otherwise, the functionality is identical to
never be marked as maximum or maximal plateau. Use localMaxima() with t \ref localMaxima().
he
appropriate options if you need that functionality. Likewise if you wan
t to
apply a threshold onl the fly. In fact, all functionality
except for 'equality with tolerance' can be accessed via that function
in
a more readable way, so localMaxima() should be preferred.
The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
use 3-dimensional arrays: use arbitrary-dimensional arrays:
\code \code
namespace vigra { namespace vigra {
template <class T1, class C1, class T2, class C2, template <unsigned int N, class T1, class S1,
class Neighborhood> class T2, class S2>
void unsigned int // return number of maxima
extendedLocalMaxima(MultiArrayView<3, T1, C1> src, extendedLocalMaxima(MultiArrayView<N, T1, S1> const & src,
MultiArrayView<3, T2, C2> dest, MultiArrayView<N, T2, S2> dest,
LocalMinmaxOptions const & options = LocalMinma LocalMinmaxOptions options = LocalMinmaxOptions
xOptions()); ());
\endcode \endcode
pass image iterators explicitly: \deprecatedAPI{extendedLocalMaxima}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue = DestAccessor::value_type, class DestValue = DestAccessor::value_type,
class Neighborhood = EightNeighborCode, class Neighborhood = EightNeighborCode,
class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> > class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> >
void void
extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor s a, extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor s a,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker = NumericTraits<DestValue>::on e(), DestValue marker = NumericTraits<DestValue>::on e(),
Neighborhood neighborhood = EightNeighborCode() , Neighborhood neighborhood = EightNeighborCode() ,
EqualityFunctor equal = EqualityFunctor()) EqualityFunctor equal = EqualityFunctor())
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood = NeighborCode3DSix,
class EqualityFunctor = std::equal_to<typename SrcAssessor
::value_type> >
void
extendedLocalMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa
,
DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood = Neighborhood(),
EqualityFunctor equal = EqualityFunctor());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue = DestAccessor::value_type, class DestValue = DestAccessor::value_type,
class Neighborhood = EightNeighborCode, class Neighborhood = EightNeighborCode,
class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> > class EqualityFunctor = std::equal_to<typename SrcAssesso r::value_type> >
void void
extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker = NumericTraits<DestValue>::on e(), DestValue marker = NumericTraits<DestValue>::on e(),
Neighborhood neighborhood = EightNeighborCode() , Neighborhood neighborhood = EightNeighborCode() ,
EqualityFunctor equal = EqualityFunctor()) EqualityFunctor equal = EqualityFunctor())
template<class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor,
class Neighborhood>
void
extendedLocalMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> sr
c,
pair<DestIterator, DestAccessor> dest,
typename DestAccessor::value_type marker,
Neighborhood neighborhood);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/localminmax.hxx\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// define an equality functor
template <class T>
struct EqualWithToleranceFunctor
{
EqualWithToleranceFunctor(T tolerance)
: t(tolerance)
{}
bool operator()(T l, T r) const
{
return abs(l-r) <= t;
}
T t;
};
MultiArray<2, unsigned char> src(w,h), maxima(w,h);
// allow plateaus
localMaxima(src, maxima, LocalMinmaxOptions().allowPlateaus());
// reset result image
maxima.init(0);
// allow plateaus with tolerance (grayvalues may differ by one)
extendedLocalMaxima(src, maxima, EqualWithToleranceFunctor<unsigned cha
r>(1));
\endcode
\deprecatedUsage{extendedLocalMaxima}
\code
// optional: define an equality functor // optional: define an equality functor
template <class T> template <class T>
struct EqualWithToleranceFunctor struct EqualWithToleranceFunctor
{ {
EqualWithToleranceFunctor(T tolerance) EqualWithToleranceFunctor(T tolerance)
: t(tolerance) : t(tolerance)
{} {}
bool operator()(T l, T r) const bool operator()(T l, T r) const
{ {
return vigra::abs(l-r) <= t; return abs(l-r) <= t;
} }
T t; T t;
}; };
vigra::BImage src(w,h), maxima(w,h); BImage src(w,h), maxima(w,h);
// init destiniation image // init destiniation image
maxima.init(0); maxima.init(0);
vigra::extendedLocalMaxima(srcImageRange(src), destImage(maxima)); extendedLocalMaxima(srcImageRange(src), destImage(maxima));
// allow plateaus with tolerance // allow plateaus with tolerance
maxima.init(0); maxima.init(0);
vigra::extendedLocalMaxima(srcImageRange(src), destImage(maxima), 1.0, extendedLocalMaxima(srcImageRange(src), destImage(maxima), 1.0,
FourNeighborCode(),
EqualWithToleranceFunctor<unsigned char>(1)) ; EqualWithToleranceFunctor<unsigned char>(1)) ;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
EqualityFunctor equal; EqualityFunctor equal;
u == u u == u
equal(u, u); equal(u, u);
u < u u < u
DestValue marker; DestValue marker;
dest_accessor.set(marker, dest_upperleft); dest_accessor.set(marker, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void extendedLocalMaxima) doxygen_overloaded_function(template <...> void extendedLocalMaxima)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood, class EqualityFunctor> class Neighborhood, class EqualityFunctor>
inline void inline void
extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker, typename DestAccessor::value_type marker,
skipping to change at line 1867 skipping to change at line 1878
marker, neighborhood, std::equal_to<SrcType>()); marker, neighborhood, std::equal_to<SrcType>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker) typename DestAccessor::value_type marker)
{ {
typedef typename SrcAccessor::value_type SrcType;
extendedLocalMaxima(sul, slr, sa, dul, da, extendedLocalMaxima(sul, slr, sa, dul, da,
marker, EightNeighborCode()); marker, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da) DestIterator dul, DestAccessor da)
{ {
skipping to change at line 1937 skipping to change at line 1946
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMaxima3D */ /* extendedLocalMaxima3D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local maximal regions in 3D multi array. /** \brief Find local maximal regions in 3D multi array.
This function finds regions of uniform pixel value See \ref extendedLocalMaxima().
whose neighboring regions are all have smaller values
(maximal plateaus of arbitrary size). By default, the pixels
in a plateau have exactly identical values. By passing an <tt>EqualityFunc
tor</tt>
with tolerance, one can allow for plateaus that are not quite constant
(this is often necessary with float pixel values). Pass
the neighborhood where pixel values are compared. See extendedLocalMaxima(
) for more details.
*/ */
doxygen_overloaded_function(template <...> void extendedLocalMaxima3D) doxygen_overloaded_function(template <...> void extendedLocalMaxima3D)
template<class SrcIterator, class SrcShape, class SrcAccessor, template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood, class DestIterator, class DestAccessor, class Neighborhood,
class EqualityFunctor> class EqualityFunctor>
inline void inline void
extendedLocalMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa, extendedLocalMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
 End of changes. 85 change blocks. 
299 lines changed or deleted 296 lines changed or added


 mathutil.hxx   mathutil.hxx 
skipping to change at line 53 skipping to change at line 53
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
#include <complex> #include <complex>
#include "config.hxx" #include "config.hxx"
#include "error.hxx" #include "error.hxx"
#include "tuple.hxx" #include "tuple.hxx"
#include "sized_int.hxx" #include "sized_int.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "algorithm.hxx" #include "algorithm.hxx"
/*! \page MathConstants Mathematical Constants /** \page MathConstants Mathematical Constants
<TT>M_PI, M_SQRT2 etc.</TT> <TT>M_PI, M_SQRT2 etc.</TT>
<b>\#include</b> \<vigra/mathutil.hxx\> <b>\#include</b> \<vigra/mathutil.hxx\>
Since mathematical constants such as <TT>M_PI</TT> and <TT>M_SQRT2</TT> Since mathematical constants such as <TT>M_PI</TT> and <TT>M_SQRT2</TT>
are not officially standardized, we provide definitions here for those are not officially standardized, we provide definitions here for those
compilers that don't support them. compilers that don't support them.
\code \code
skipping to change at line 109 skipping to change at line 109
#endif #endif
#ifndef M_PI_4 #ifndef M_PI_4
# define M_PI_4 0.78539816339744830962 # define M_PI_4 0.78539816339744830962
#endif #endif
#ifndef M_SQRT2 #ifndef M_SQRT2
# define M_SQRT2 1.41421356237309504880 # define M_SQRT2 1.41421356237309504880
#endif #endif
#ifndef M_E
# define M_E 2.71828182845904523536
#endif
#ifndef M_EULER_GAMMA #ifndef M_EULER_GAMMA
# define M_EULER_GAMMA 0.5772156649015329 # define M_EULER_GAMMA 0.5772156649015329
#endif #endif
namespace vigra { namespace vigra {
/** \addtogroup MathFunctions Mathematical Functions /** \addtogroup MathFunctions Mathematical Functions
Useful mathematical functions and functors. Useful mathematical functions and functors.
*/ */
skipping to change at line 158 skipping to change at line 162
VIGRA_DEFINE_MISSING_ABS(signed char) VIGRA_DEFINE_MISSING_ABS(signed char)
VIGRA_DEFINE_MISSING_ABS(signed short) VIGRA_DEFINE_MISSING_ABS(signed short)
#if defined(_MSC_VER) && _MSC_VER < 1600 #if defined(_MSC_VER) && _MSC_VER < 1600
VIGRA_DEFINE_MISSING_ABS(signed long long) VIGRA_DEFINE_MISSING_ABS(signed long long)
#endif #endif
#undef VIGRA_DEFINE_MISSING_ABS #undef VIGRA_DEFINE_MISSING_ABS
#ifndef _MSC_VER
using std::isinf;
using std::isnan;
#else
template <class REAL>
inline bool isinf(REAL v)
{
return _finite(v) == 0;
}
template <class REAL>
inline bool isnan(REAL v)
{
return _isnan(v) != 0;
}
#endif
// scalar dot is needed for generic functions that should work with // scalar dot is needed for generic functions that should work with
// scalars and vectors alike // scalars and vectors alike
#define VIGRA_DEFINE_SCALAR_DOT(T) \ #define VIGRA_DEFINE_SCALAR_DOT(T) \
inline NumericTraits<T>::Promote dot(T l, T r) { return l*r; } inline NumericTraits<T>::Promote dot(T l, T r) { return l*r; }
VIGRA_DEFINE_SCALAR_DOT(unsigned char) VIGRA_DEFINE_SCALAR_DOT(unsigned char)
VIGRA_DEFINE_SCALAR_DOT(unsigned short) VIGRA_DEFINE_SCALAR_DOT(unsigned short)
VIGRA_DEFINE_SCALAR_DOT(unsigned int) VIGRA_DEFINE_SCALAR_DOT(unsigned int)
VIGRA_DEFINE_SCALAR_DOT(unsigned long) VIGRA_DEFINE_SCALAR_DOT(unsigned long)
skipping to change at line 194 skipping to change at line 219
inline float pow(float v, double e) inline float pow(float v, double e)
{ {
return std::pow(v, (float)e); return std::pow(v, (float)e);
} }
inline long double pow(long double v, double e) inline long double pow(long double v, double e)
{ {
return std::pow(v, (long double)e); return std::pow(v, (long double)e);
} }
/*! The rounding function. /** \brief The rounding function.
Defined for all floating point types. Rounds towards the nearest in teger Defined for all floating point types. Rounds towards the nearest in teger
such that <tt>abs(round(t)) == round(abs(t))</tt> for all <tt>t</tt >. such that <tt>abs(round(t)) == round(abs(t))</tt> for all <tt>t</tt >.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
#ifdef DOXYGEN // only for documentation #ifdef DOXYGEN // only for documentation
REAL round(REAL v); REAL round(REAL v);
#endif #endif
skipping to change at line 227 skipping to change at line 252
: ceil(t - 0.5); : ceil(t - 0.5);
} }
inline long double round(long double t) inline long double round(long double t)
{ {
return t >= 0.0 return t >= 0.0
? floor(t + 0.5) ? floor(t + 0.5)
: ceil(t - 0.5); : ceil(t - 0.5);
} }
/*! Round and cast to integer. /** \brief Round and cast to integer.
Rounds to the nearest integer like round(), but casts the result to Rounds to the nearest integer like round(), but casts the result to
<tt>int</tt> (this will be faster and is usually needed anyway). <tt>int</tt> (this will be faster and is usually needed anyway).
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline int roundi(double t) inline int roundi(double t)
{ {
return t >= 0.0 return t >= 0.0
? int(t + 0.5) ? int(t + 0.5)
: int(t - 0.5); : int(t - 0.5);
} }
/*! Round up to the nearest power of 2. /** \brief Round up to the nearest power of 2.
Efficient algorithm for finding the smallest power of 2 which is no t smaller than \a x Efficient algorithm for finding the smallest power of 2 which is no t smaller than \a x
(function clp2() from Henry Warren: "Hacker's Delight", Addison-Wes ley, 2003, (function clp2() from Henry Warren: "Hacker's Delight", Addison-Wes ley, 2003,
see http://www.hackersdelight.org/). see http://www.hackersdelight.org/).
If \a x > 2^31, the function will return 0 because integer arithmet ic is defined modulo 2^32. If \a x > 2^31, the function will return 0 because integer arithmet ic is defined modulo 2^32.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline UInt32 ceilPower2(UInt32 x) inline UInt32 ceilPower2(UInt32 x)
skipping to change at line 265 skipping to change at line 290
x = x - 1; x = x - 1;
x = x | (x >> 1); x = x | (x >> 1);
x = x | (x >> 2); x = x | (x >> 2);
x = x | (x >> 4); x = x | (x >> 4);
x = x | (x >> 8); x = x | (x >> 8);
x = x | (x >>16); x = x | (x >>16);
return x + 1; return x + 1;
} }
/*! Round down to the nearest power of 2. /** \brief Round down to the nearest power of 2.
Efficient algorithm for finding the largest power of 2 which is not greater than \a x Efficient algorithm for finding the largest power of 2 which is not greater than \a x
(function flp2() from Henry Warren: "Hacker's Delight", Addison-Wes ley, 2003, (function flp2() from Henry Warren: "Hacker's Delight", Addison-Wes ley, 2003,
see http://www.hackersdelight.org/). see http://www.hackersdelight.org/).
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline UInt32 floorPower2(UInt32 x) inline UInt32 floorPower2(UInt32 x)
{ {
skipping to change at line 287 skipping to change at line 312
x = x | (x >> 2); x = x | (x >> 2);
x = x | (x >> 4); x = x | (x >> 4);
x = x | (x >> 8); x = x | (x >> 8);
x = x | (x >>16); x = x | (x >>16);
return x - (x >> 1); return x - (x >> 1);
} }
namespace detail { namespace detail {
template <class T> template <class T>
class IntLog2 struct IntLog2
{ {
public:
static Int32 table[64]; static Int32 table[64];
}; };
template <class T> template <class T>
Int32 IntLog2<T>::table[64] = { Int32 IntLog2<T>::table[64] = {
-1, 0, -1, 15, -1, 1, 28, -1, 16, -1, -1, -1, 2, 21, -1, 0, -1, 15, -1, 1, 28, -1, 16, -1, -1, -1, 2, 21,
29, -1, -1, -1, 19, 17, 10, -1, 12, -1, -1, 3, -1, 6, 29, -1, -1, -1, 19, 17, 10, -1, 12, -1, -1, 3, -1, 6,
-1, 22, 30, -1, 14, -1, 27, -1, -1, -1, 20, -1, 18, 9 , -1, 22, 30, -1, 14, -1, 27, -1, -1, -1, 20, -1, 18, 9 ,
11, -1, 5, -1, -1, 13, 26, -1, -1, 8, -1, 4, -1, 25, 11, -1, 5, -1, -1, 13, 26, -1, -1, 8, -1, 4, -1, 25,
-1, 7, 24, -1, 23, -1, 31, -1}; -1, 7, 24, -1, 23, -1, 31, -1};
} // namespace detail } // namespace detail
/*! Compute the base-2 logarithm of an integer. /** \brief Compute the base-2 logarithm of an integer.
Returns the position of the left-most 1-bit in the given number \a x, or Returns the position of the left-most 1-bit in the given number \a x, or
-1 if \a x == 0. That is, -1 if \a x == 0. That is,
\code \code
assert(k >= 0 && k < 32 && log2i(1 << k) == k); assert(k >= 0 && k < 32 && log2i(1 << k) == k);
\endcode \endcode
The function uses Robert Harley's algorithm to determine the number of leading zeros The function uses Robert Harley's algorithm to determine the number of leading zeros
in \a x (algorithm nlz10() at http://www.hackersdelight.org/). But note that the functions in \a x (algorithm nlz10() at http://www.hackersdelight.org/). But note that the functions
skipping to change at line 331 skipping to change at line 355
// Propagate leftmost 1-bit to the right. // Propagate leftmost 1-bit to the right.
x = x | (x >> 1); x = x | (x >> 1);
x = x | (x >> 2); x = x | (x >> 2);
x = x | (x >> 4); x = x | (x >> 4);
x = x | (x >> 8); x = x | (x >> 8);
x = x | (x >>16); x = x | (x >>16);
x = x*0x06EB14F9; // Multiplier is 7*255**3. x = x*0x06EB14F9; // Multiplier is 7*255**3.
return detail::IntLog2<Int32>::table[x >> 26]; return detail::IntLog2<Int32>::table[x >> 26];
} }
/*! The square function. /** \brief The square function.
<tt>sq(x) = x*x</tt> is needed so often that it makes sense to defi ne it as a function. <tt>sq(x) = x*x</tt> is needed so often that it makes sense to defi ne it as a function.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
inline inline
typename NumericTraits<T>::Promote sq(T t) typename NumericTraits<T>::Promote sq(T t)
{ {
skipping to change at line 371 skipping to change at line 395
static V call(const V & x) static V call(const V & x)
{ {
return n / 2 return n / 2
? cond_mult<V, n & 1>::call(x, power_static<V, n / 2>::call(x * x)) ? cond_mult<V, n & 1>::call(x, power_static<V, n / 2>::call(x * x))
: n & 1 ? x : V(); : n & 1 ? x : V();
} }
}; };
template <class V> template <class V>
struct power_static<V, 0> struct power_static<V, 0>
{ {
static V call(const V & x) static V call(const V & /* x */)
{ {
return V(1); return V(1);
} }
}; };
} // namespace detail } // namespace detail
/*! Exponentiation to a positive integer power by squaring. /** \brief Exponentiation to a positive integer power by squaring.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned n, class V> template <unsigned n, class V>
inline V power(const V & x) inline V power(const V & x)
{ {
return detail::power_static<V, n>::call(x); return detail::power_static<V, n>::call(x);
} }
//doxygen_overloaded_function(template <unsigned n, class V> power(const V & x)) //doxygen_overloaded_function(template <unsigned n, class V> power(const V & x))
namespace detail { namespace detail {
template <class T> template <class T>
class IntSquareRoot struct IntSquareRoot
{ {
public:
static UInt32 sqq_table[]; static UInt32 sqq_table[];
static UInt32 exec(UInt32 v); static UInt32 exec(UInt32 v);
}; };
template <class T> template <class T>
UInt32 IntSquareRoot<T>::sqq_table[] = { UInt32 IntSquareRoot<T>::sqq_table[] = {
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57,
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83,
84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 1 02, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 1 02,
103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 1 18, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 1 18,
skipping to change at line 490 skipping to change at line 513
if (xn * xn > x) /* Correct rounding if necessary */ if (xn * xn > x) /* Correct rounding if necessary */
xn--; xn--;
return xn; return xn;
} }
} // namespace detail } // namespace detail
using VIGRA_CSTD::sqrt; using VIGRA_CSTD::sqrt;
/*! Signed integer square root. /** \brief Signed integer square root.
Useful for fast fixed-point computations. Useful for fast fixed-point computations.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline Int32 sqrti(Int32 v) inline Int32 sqrti(Int32 v)
{ {
if(v < 0) if(v < 0)
throw std::domain_error("sqrti(Int32): negative argument."); throw std::domain_error("sqrti(Int32): negative argument.");
return (Int32)detail::IntSquareRoot<UInt32>::exec((UInt32)v); return (Int32)detail::IntSquareRoot<UInt32>::exec((UInt32)v);
} }
/*! Unsigned integer square root. /** \brief Unsigned integer square root.
Useful for fast fixed-point computations. Useful for fast fixed-point computations.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline UInt32 sqrti(UInt32 v) inline UInt32 sqrti(UInt32 v)
{ {
return detail::IntSquareRoot<UInt32>::exec(v); return detail::IntSquareRoot<UInt32>::exec(v);
} }
#ifdef VIGRA_NO_HYPOT #ifdef VIGRA_NO_HYPOT
/*! Compute the Euclidean distance (length of the hypotenuse of a right -angled triangle). /** \brief Compute the Euclidean distance (length of the hypotenuse of a right-angled triangle).
The hypot() function returns the sqrt(a*a + b*b). The hypot() function returns the sqrt(a*a + b*b).
It is implemented in a way that minimizes round-off error. It is implemented in a way that minimizes round-off error.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double hypot(double a, double b) inline double hypot(double a, double b)
{ {
double absa = VIGRA_CSTD::fabs(a), absb = VIGRA_CSTD::fabs(b); double absa = VIGRA_CSTD::fabs(a), absb = VIGRA_CSTD::fabs(b);
skipping to change at line 542 skipping to change at line 565
? 0.0 ? 0.0
: absb * VIGRA_CSTD::sqrt(1.0 + sq(absa/absb)); : absb * VIGRA_CSTD::sqrt(1.0 + sq(absa/absb));
} }
#else #else
using ::hypot; using ::hypot;
#endif #endif
/*! The sign function. /** \brief The sign function.
Returns 1, 0, or -1 depending on the sign of \a t, but with the sam e type as \a t. Returns 1, 0, or -1 depending on the sign of \a t, but with the sam e type as \a t.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
inline T sign(T t) inline T sign(T t)
{ {
return t > NumericTraits<T>::zero() return t > NumericTraits<T>::zero()
? NumericTraits<T>::one() ? NumericTraits<T>::one()
: t < NumericTraits<T>::zero() : t < NumericTraits<T>::zero()
? -NumericTraits<T>::one() ? -NumericTraits<T>::one()
: NumericTraits<T>::zero(); : NumericTraits<T>::zero();
} }
/*! The integer sign function. /** \brief The integer sign function.
Returns 1, 0, or -1 depending on the sign of \a t, converted to int . Returns 1, 0, or -1 depending on the sign of \a t, converted to int .
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
inline int signi(T t) inline int signi(T t)
{ {
return t > NumericTraits<T>::zero() return t > NumericTraits<T>::zero()
? 1 ? 1
: t < NumericTraits<T>::zero() : t < NumericTraits<T>::zero()
? -1 ? -1
: 0; : 0;
} }
/*! The binary sign function. /** \brief The binary sign function.
Transfers the sign of \a t2 to \a t1. Transfers the sign of \a t2 to \a t1.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T1, class T2> template <class T1, class T2>
inline T1 sign(T1 t1, T2 t2) inline T1 sign(T1 t1, T2 t2)
{ {
return t2 >= NumericTraits<T2>::zero() return t2 >= NumericTraits<T2>::zero()
? abs(t1) ? abs(t1)
: -abs(t1); : -abs(t1);
} }
#ifdef DOXYGEN // only for documentation #ifdef DOXYGEN // only for documentation
/*! Check if an integer is even. /** \brief Check if an integer is even.
Defined for all integral types. Defined for all integral types.
*/ */
bool even(int t); bool even(int t);
/*! Check if an integer is odd. /** \brief Check if an integer is odd.
Defined for all integral types. Defined for all integral types.
*/ */
bool odd(int t); bool odd(int t);
#endif #endif
#define VIGRA_DEFINE_ODD_EVEN(T) \ #define VIGRA_DEFINE_ODD_EVEN(T) \
inline bool even(T t) { return (t&1) == 0; } \ inline bool even(T t) { return (t&1) == 0; } \
inline bool odd(T t) { return (t&1) == 1; } inline bool odd(T t) { return (t&1) == 1; }
skipping to change at line 652 skipping to change at line 675
#undef VIGRA_DEFINE_NORM #undef VIGRA_DEFINE_NORM
template <class T> template <class T>
inline typename NormTraits<std::complex<T> >::SquaredNormType inline typename NormTraits<std::complex<T> >::SquaredNormType
squaredNorm(std::complex<T> const & t) squaredNorm(std::complex<T> const & t)
{ {
return sq(t.real()) + sq(t.imag()); return sq(t.real()) + sq(t.imag());
} }
#ifdef DOXYGEN // only for documentation #ifdef DOXYGEN // only for documentation
/*! The squared norm of a numerical object. /** \brief The squared norm of a numerical object.
For scalar types: equals <tt>vigra::sq(t)</tt><br>. <ul>
For vectorial types: equals <tt>vigra::dot(t, t)</tt><br>. <li>For scalar types: equals <tt>vigra::sq(t)</tt>.
For complex types: equals <tt>vigra::sq(t.real()) + vigra::sq(t.ima <li>For vectorial types (including TinyVector): equals <tt>vigra::d
g())</tt><br>. ot(t, t)</tt>.
For matrix types: results in the squared Frobenius norm (sum of squ <li>For complex number types: equals <tt>vigra::sq(t.real()) + vigr
ares of the matrix elements). a::sq(t.imag())</tt>.
<li>For array and matrix types: results in the squared Frobenius no
rm (sum of squares of the matrix elements).
</ul>
*/ */
NormTraits<T>::SquaredNormType squaredNorm(T const & t); NormTraits<T>::SquaredNormType squaredNorm(T const & t);
#endif #endif
/*! The norm of a numerical object. /** \brief The norm of a numerical object.
For scalar types: implemented as <tt>abs(t)</tt><br> For scalar types: implemented as <tt>abs(t)</tt><br>
otherwise: implemented as <tt>sqrt(squaredNorm(t))</tt>. otherwise: implemented as <tt>sqrt(squaredNorm(t))</tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
inline typename NormTraits<T>::NormType inline typename NormTraits<T>::NormType
norm(T const & t) norm(T const & t)
{ {
typedef typename NormTraits<T>::SquaredNormType SNT; typedef typename NormTraits<T>::SquaredNormType SNT;
return sqrt(static_cast<typename SquareRootTraits<SNT>::SquareRootArgum ent>(squaredNorm(t))); return sqrt(static_cast<typename SquareRootTraits<SNT>::SquareRootArgum ent>(squaredNorm(t)));
} }
/*! Compute the eigenvalues of a 2x2 real symmetric matrix. /** \brief Compute the eigenvalues of a 2x2 real symmetric matrix.
This uses the analytical eigenvalue formula This uses the analytical eigenvalue formula
\f[ \f[
\lambda_{1,2} = \frac{1}{2}\left(a_{00} + a_{11} \pm \sqrt{(a_{0 0} - a_{11})^2 + 4 a_{01}^2}\right) \lambda_{1,2} = \frac{1}{2}\left(a_{00} + a_{11} \pm \sqrt{(a_{0 0} - a_{11})^2 + 4 a_{01}^2}\right)
\f] \f]
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
void symmetric2x2Eigenvalues(T a00, T a01, T a11, T * r0, T * r1) void symmetric2x2Eigenvalues(T a00, T a01, T a11, T * r0, T * r1)
{ {
double d = hypot(a00 - a11, 2.0*a01); double d = hypot(a00 - a11, 2.0*a01);
*r0 = static_cast<T>(0.5*(a00 + a11 + d)); *r0 = static_cast<T>(0.5*(a00 + a11 + d));
*r1 = static_cast<T>(0.5*(a00 + a11 - d)); *r1 = static_cast<T>(0.5*(a00 + a11 - d));
if(*r0 < *r1) if(*r0 < *r1)
std::swap(*r0, *r1); std::swap(*r0, *r1);
} }
/*! Compute the eigenvalues of a 3x3 real symmetric matrix. /** \brief Compute the eigenvalues of a 3x3 real symmetric matrix.
This uses a numerically stable version of the analytical eigenvalue formula according to This uses a numerically stable version of the analytical eigenvalue formula according to
<p> <p>
David Eberly: <a href="http://www.geometrictools.com/Documentation/ EigenSymmetric3x3.pdf"> David Eberly: <a href="http://www.geometrictools.com/Documentation/ EigenSymmetric3x3.pdf">
<em>"Eigensystems for 3 × 3 Symmetric Matrices (Revisited)"</em></a >, Geometric Tools Documentation, 2006 <em>"Eigensystems for 3 × 3 Symmetric Matrices (Revisited)"</em></ a>, Geometric Tools Documentation, 2006
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
void symmetric3x3Eigenvalues(T a00, T a01, T a02, T a11, T a12, T a22, void symmetric3x3Eigenvalues(T a00, T a01, T a02, T a11, T a12, T a22,
T * r0, T * r1, T * r2) T * r0, T * r1, T * r2)
{ {
static double inv3 = 1.0 / 3.0, root3 = std::sqrt(3.0); double inv3 = 1.0 / 3.0, root3 = std::sqrt(3.0);
double c0 = a00*a11*a22 + 2.0*a01*a02*a12 - a00*a12*a12 - a11*a02*a02 - a22*a01*a01; double c0 = a00*a11*a22 + 2.0*a01*a02*a12 - a00*a12*a12 - a11*a02*a02 - a22*a01*a01;
double c1 = a00*a11 - a01*a01 + a00*a22 - a02*a02 + a11*a22 - a12*a12; double c1 = a00*a11 - a01*a01 + a00*a22 - a02*a02 + a11*a22 - a12*a12;
double c2 = a00 + a11 + a22; double c2 = a00 + a11 + a22;
double c2Div3 = c2*inv3; double c2Div3 = c2*inv3;
double aDiv3 = (c1 - c2*c2Div3)*inv3; double aDiv3 = (c1 - c2*c2Div3)*inv3;
if (aDiv3 > 0.0) if (aDiv3 > 0.0)
aDiv3 = 0.0; aDiv3 = 0.0;
double mbDiv2 = 0.5*(c0 + c2Div3*(2.0*c2Div3*c2Div3 - c1)); double mbDiv2 = 0.5*(c0 + c2Div3*(2.0*c2Div3*c2Div3 - c1));
double q = mbDiv2*mbDiv2 + aDiv3*aDiv3*aDiv3; double q = mbDiv2*mbDiv2 + aDiv3*aDiv3*aDiv3;
skipping to change at line 795 skipping to change at line 820
y = (y + l)/4.0; y = (y + l)/4.0;
z = (z + l)/4.0; z = (z + l)/4.0;
} }
double d = X*Y - sq(Z); double d = X*Y - sq(Z);
double p = X*Y*Z; double p = X*Y*Z;
return (1.0 - d/10.0 + p/14.0 + sq(d)/24.0 - d*p*3.0/44.0) / VIGRA_CSTD ::sqrt(m); return (1.0 - d/10.0 + p/14.0 + sq(d)/24.0 - d*p*3.0/44.0) / VIGRA_CSTD ::sqrt(m);
} }
} // namespace detail } // namespace detail
/*! The incomplete elliptic integral of the first kind. /** \brief The incomplete elliptic integral of the first kind.
Computes This function computes
\f[ \f[
\mbox{F}(x, k) = \int_0^x \frac{1}{\sqrt{1 - k^2 \sin(t)^2}} dt \mbox{F}(x, k) = \int_0^x \frac{1}{\sqrt{1 - k^2 \sin(t)^2}} d t
\f] \f]
according to the algorithm given in Press et al. "Numerical Recipes ". according to the algorithm given in Press et al. "Numerical Recipes ".
Note: In some libraries (e.g. Mathematica), the second parameter of the elliptic integral Note: In some libraries (e.g. Mathematica), the second parameter of the elliptic integral
functions must be k^2 rather than k. Check the documentation when r esults disagree! functions must be k^2 rather than k. Check the documentation when r esults disagree!
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double ellipticIntegralF(double x, double k) inline double ellipticIntegralF(double x, double k)
{ {
double c2 = sq(VIGRA_CSTD::cos(x)); double c2 = sq(VIGRA_CSTD::cos(x));
double s = VIGRA_CSTD::sin(x); double s = VIGRA_CSTD::sin(x);
return s*detail::ellipticRF(c2, 1.0 - sq(k*s), 1.0); return s*detail::ellipticRF(c2, 1.0 - sq(k*s), 1.0);
} }
/*! The incomplete elliptic integral of the second kind. /** \brief The incomplete elliptic integral of the second kind.
Computes This function computes
\f[ \f[
\mbox{E}(x, k) = \int_0^x \sqrt{1 - k^2 \sin(t)^2} dt \mbox{E}(x, k) = \int_0^x \sqrt{1 - k^2 \sin(t)^2} dt
\f] \f]
according to the algorithm given in Press et al. "Numerical Recipes ". The according to the algorithm given in Press et al. "Numerical Recipes ". The
complete elliptic integral of the second kind is simply <tt>ellipti cIntegralE(M_PI/2, k)</TT>. complete elliptic integral of the second kind is simply <tt>ellipti cIntegralE(M_PI/2, k)</TT>.
Note: In some libraries (e.g. Mathematica), the second parameter of the elliptic integral Note: In some libraries (e.g. Mathematica), the second parameter of the elliptic integral
functions must be k^2 rather than k. Check the documentation when r esults disagree! functions must be k^2 rather than k. Check the documentation when r esults disagree!
skipping to change at line 843 skipping to change at line 868
Namespace: vigra Namespace: vigra
*/ */
inline double ellipticIntegralE(double x, double k) inline double ellipticIntegralE(double x, double k)
{ {
double c2 = sq(VIGRA_CSTD::cos(x)); double c2 = sq(VIGRA_CSTD::cos(x));
double s = VIGRA_CSTD::sin(x); double s = VIGRA_CSTD::sin(x);
k = sq(k*s); k = sq(k*s);
return s*(detail::ellipticRF(c2, 1.0-k, 1.0) - k/3.0*detail::ellipticRD (c2, 1.0-k, 1.0)); return s*(detail::ellipticRF(c2, 1.0-k, 1.0) - k/3.0*detail::ellipticRD (c2, 1.0-k, 1.0));
} }
#ifdef _MSC_VER #if defined(_MSC_VER) && _MSC_VER < 1800
namespace detail { namespace detail {
template <class T> template <class T>
double erfImpl(T x) double erfImpl(T x)
{ {
double t = 1.0/(1.0+0.5*VIGRA_CSTD::fabs(x)); double t = 1.0/(1.0+0.5*VIGRA_CSTD::fabs(x));
double ans = t*VIGRA_CSTD::exp(-x*x-1.26551223+t*(1.00002368+t*(0.37409 196+ double ans = t*VIGRA_CSTD::exp(-x*x-1.26551223+t*(1.00002368+t*(0.37409 196+
t*(0.09678418+t*(-0.18628806+t*(0.27886 807+ t*(0.09678418+t*(-0.18628806+t*(0.27886 807+
t*(-1.13520398+t*(1.48851587+t*(-0.8221 5223+ t*(-1.13520398+t*(1.48851587+t*(-0.8221 5223+
t*0.17087277))))))))); t*0.17087277)))))))));
if (x >= 0.0) if (x >= 0.0)
return 1.0 - ans; return 1.0 - ans;
else else
return ans - 1.0; return ans - 1.0;
} }
} // namespace detail } // namespace detail
/*! The error function. /** \brief The error function.
If <tt>erf()</tt> is not provided in the C standard math library (a s it should according to the If <tt>erf()</tt> is not provided in the C standard math library (a s it should according to the
new C99 standard ?), VIGRA implements <tt>erf()</tt> as an approxim ation of the error new C99 standard ?), VIGRA implements <tt>erf()</tt> as an approxim ation of the error
function function
\f[ \f[
\mbox{erf}(x) = \int_0^x e^{-t^2} dt \mbox{erf}(x) = \int_0^x e^{-t^2} dt
\f] \f]
according to the formula given in Press et al. "Numerical Recipes". according to the formula given in Press et al. "Numerical Recipes".
skipping to change at line 989 skipping to change at line 1014
if((pans * sum < eps2) && (hold < eps2)) if((pans * sum < eps2) && (hold < eps2))
break; // converged break; // converged
} }
if(m == maxit) if(m == maxit)
vigra_fail("noncentralChi2P(): no convergence."); vigra_fail("noncentralChi2P(): no convergence.");
return std::make_pair(0.5 * ao * density, std::min(1.0, std::max(0.0, a o * probability))); return std::make_pair(0.5 * ao * density, std::min(1.0, std::max(0.0, a o * probability)));
} }
} // namespace detail } // namespace detail
/*! Chi square distribution. /** \brief Chi square distribution.
Computes the density of a chi square distribution with \a degreesOf Freedom Computes the density of a chi square distribution with \a degreesOf Freedom
and tolerance \a accuracy at the given argument \a arg and tolerance \a accuracy at the given argument \a arg
by calling <tt>noncentralChi2(degreesOfFreedom, 0.0, arg, accuracy) </tt>. by calling <tt>noncentralChi2(degreesOfFreedom, 0.0, arg, accuracy) </tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double chi2(unsigned int degreesOfFreedom, double arg, double accura cy = 1e-7) inline double chi2(unsigned int degreesOfFreedom, double arg, double accura cy = 1e-7)
{ {
return detail::noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy). first; return detail::noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy). first;
} }
/*! Cumulative chi square distribution. /** \brief Cumulative chi square distribution.
Computes the cumulative density of a chi square distribution with \ a degreesOfFreedom Computes the cumulative density of a chi square distribution with \ a degreesOfFreedom
and tolerance \a accuracy at the given argument \a arg, i.e. the pr obability that and tolerance \a accuracy at the given argument \a arg, i.e. the pr obability that
a random number drawn from the distribution is below \a arg a random number drawn from the distribution is below \a arg
by calling <tt>noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accura cy)</tt>. by calling <tt>noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accura cy)</tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double chi2CDF(unsigned int degreesOfFreedom, double arg, double acc uracy = 1e-7) inline double chi2CDF(unsigned int degreesOfFreedom, double arg, double acc uracy = 1e-7)
{ {
return detail::noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy). second; return detail::noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy). second;
} }
/*! Non-central chi square distribution. /** \brief Non-central chi square distribution.
Computes the density of a non-central chi square distribution with \a degreesOfFreedom, Computes the density of a non-central chi square distribution with \a degreesOfFreedom,
noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument
\a arg. It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (code ported from \a arg. It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (code ported from
http://lib.stat.cmu.edu/apstat/231). The algorithm has linear compl exity in the number of http://lib.stat.cmu.edu/apstat/231). The algorithm has linear compl exity in the number of
degrees of freedom. degrees of freedom.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double noncentralChi2(unsigned int degreesOfFreedom, inline double noncentralChi2(unsigned int degreesOfFreedom,
double noncentrality, double arg, double accuracy = 1e-7) double noncentrality, double arg, double accuracy = 1e-7)
{ {
return detail::noncentralChi2CDF(degreesOfFreedom, noncentrality, arg, accuracy).first; return detail::noncentralChi2CDF(degreesOfFreedom, noncentrality, arg, accuracy).first;
} }
/*! Cumulative non-central chi square distribution. /** \brief Cumulative non-central chi square distribution.
Computes the cumulative density of a chi square distribution with \ a degreesOfFreedom, Computes the cumulative density of a chi square distribution with \ a degreesOfFreedom,
noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument
\a arg, i.e. the probability that a random number drawn from the di stribution is below \a arg \a arg, i.e. the probability that a random number drawn from the di stribution is below \a arg
It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (c ode ported from It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (c ode ported from
http://lib.stat.cmu.edu/apstat/231). The algorithm has linear compl exity in the number of http://lib.stat.cmu.edu/apstat/231). The algorithm has linear compl exity in the number of
degrees of freedom (see noncentralChi2CDFApprox() for a constant-ti me algorithm). degrees of freedom (see noncentralChi2CDFApprox() for a constant-ti me algorithm).
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double noncentralChi2CDF(unsigned int degreesOfFreedom, inline double noncentralChi2CDF(unsigned int degreesOfFreedom,
double noncentrality, double arg, double accuracy = 1e-7) double noncentrality, double arg, double accuracy = 1e-7)
{ {
return detail::noncentralChi2CDF(degreesOfFreedom, noncentrality, arg, accuracy).second; return detail::noncentralChi2CDF(degreesOfFreedom, noncentrality, arg, accuracy).second;
} }
/*! Cumulative non-central chi square distribution (approximate). /** \brief Cumulative non-central chi square distribution (approximate) .
Computes approximate values of the cumulative density of a chi squa re distribution with \a degreesOfFreedom, Computes approximate values of the cumulative density of a chi squa re distribution with \a degreesOfFreedom,
and noncentrality parameter \a noncentrality at the given argument and noncentrality parameter \a noncentrality at the given argument
\a arg, i.e. the probability that a random number drawn from the di stribution is below \a arg \a arg, i.e. the probability that a random number drawn from the di stribution is below \a arg
It uses the approximate transform into a normal distribution due to Wilson and Hilferty It uses the approximate transform into a normal distribution due to Wilson and Hilferty
(see Abramovitz, Stegun: "Handbook of Mathematical Functions", form ula 26.3.32). (see Abramovitz, Stegun: "Handbook of Mathematical Functions", form ula 26.3.32).
The algorithm's running time is independent of the inputs, i.e. is should be used The algorithm's running time is independent of the inputs, i.e. is should be used
when noncentralChi2CDF() is too slow, and approximate values are su fficient. The accuracy is only when noncentralChi2CDF() is too slow, and approximate values are su fficient. The accuracy is only
about 0.1 for few degrees of freedom, but reaches about 0.001 above dof = 5. about 0.1 for few degrees of freedom, but reaches about 0.001 above dof = 5.
skipping to change at line 1087 skipping to change at line 1112
T facLM(T l, T m) T facLM(T l, T m)
{ {
T tmp = NumericTraits<T>::one(); T tmp = NumericTraits<T>::one();
for(T f = l-m+1; f <= l+m; ++f) for(T f = l-m+1; f <= l+m; ++f)
tmp *= f; tmp *= f;
return tmp; return tmp;
} }
} // namespace detail } // namespace detail
/*! Associated Legendre polynomial. /** \brief Associated Legendre polynomial.
Computes the value of the associated Legendre polynomial of order < tt>l, m</tt> Computes the value of the associated Legendre polynomial of order < tt>l, m</tt>
for argument <tt>x</tt>. <tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>, for argument <tt>x</tt>. <tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>,
otherwise an exception is thrown. The standard Legendre polynomials are the otherwise an exception is thrown. The standard Legendre polynomials are the
special case <tt>m == 0</tt>. special case <tt>m == 0</tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class REAL> template <class REAL>
skipping to change at line 1136 skipping to change at line 1161
REAL other = 0.0; REAL other = 0.0;
for(unsigned int i = m+2; i <= l; ++i) for(unsigned int i = m+2; i <= l; ++i)
{ {
other = ( (2.0*i-1.0) * x * result_1 - (i+m-1.0)*result) / (i-m); other = ( (2.0*i-1.0) * x * result_1 - (i+m-1.0)*result) / (i-m);
result = result_1; result = result_1;
result_1 = other; result_1 = other;
} }
return other; return other;
} }
/*! Legendre polynomial. /** \brief \brief Legendre polynomial.
Computes the value of the Legendre polynomial of order <tt>l</tt> f or argument <tt>x</tt>. Computes the value of the Legendre polynomial of order <tt>l</tt> f or argument <tt>x</tt>.
<tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>, otherwise an exception is thrown. <tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>, otherwise an exception is thrown.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class REAL> template <class REAL>
REAL legendre(unsigned int l, REAL x) REAL legendre(unsigned int l, REAL x)
{ {
return legendre(l, 0, x); return legendre(l, 0, x);
} }
/*! sin(pi*x). /** \brief sin(pi*x).
Essentially calls <tt>std::sin(M_PI*x)</tt> but uses a more accurat e implementation Essentially calls <tt>std::sin(M_PI*x)</tt> but uses a more accurat e implementation
to make sure that <tt>sin_pi(1.0) == 0.0</tt> (which does not hold for to make sure that <tt>sin_pi(1.0) == 0.0</tt> (which does not hold for
<tt>std::sin(M_PI)</tt> due to round-off error), and <tt>sin_pi(0.5 ) == 1.0</tt>. <tt>std::sin(M_PI)</tt> due to round-off error), and <tt>sin_pi(0.5 ) == 1.0</tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class REAL> template <class REAL>
REAL sin_pi(REAL x) REAL sin_pi(REAL x)
skipping to change at line 1189 skipping to change at line 1214
rem = 1.0 - rem; rem = 1.0 - rem;
if(rem == 0.5) if(rem == 0.5)
rem = NumericTraits<REAL>::one(); rem = NumericTraits<REAL>::one();
else else
rem = std::sin(M_PI * rem); rem = std::sin(M_PI * rem);
return invert return invert
? -rem ? -rem
: rem; : rem;
} }
/*! cos(pi*x). /** \brief cos(pi*x).
Essentially calls <tt>std::cos(M_PI*x)</tt> but uses a more accurat e implementation Essentially calls <tt>std::cos(M_PI*x)</tt> but uses a more accurat e implementation
to make sure that <tt>cos_pi(1.0) == -1.0</tt> and <tt>cos_pi(0.5) == 0.0</tt>. to make sure that <tt>cos_pi(1.0) == -1.0</tt> and <tt>cos_pi(0.5) == 0.0</tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class REAL> template <class REAL>
REAL cos_pi(REAL x) REAL cos_pi(REAL x)
{ {
return sin_pi(x+0.5); return sin_pi(x+0.5);
} }
namespace detail { namespace detail {
template <class REAL> template <class REAL>
REAL gammaImpl(REAL x) struct GammaImpl
{
static REAL gamma(REAL x);
static REAL loggamma(REAL x);
static double g[];
static double a[];
static double t[];
static double u[];
static double v[];
static double s[];
static double r[];
static double w[];
};
template <class REAL>
double GammaImpl<REAL>::g[] = {
1.0,
0.5772156649015329,
-0.6558780715202538,
-0.420026350340952e-1,
0.1665386113822915,
-0.421977345555443e-1,
-0.9621971527877e-2,
0.7218943246663e-2,
-0.11651675918591e-2,
-0.2152416741149e-3,
0.1280502823882e-3,
-0.201348547807e-4,
-0.12504934821e-5,
0.1133027232e-5,
-0.2056338417e-6,
0.6116095e-8,
0.50020075e-8,
-0.11812746e-8,
0.1043427e-9,
0.77823e-11,
-0.36968e-11,
0.51e-12,
-0.206e-13,
-0.54e-14,
0.14e-14
};
template <class REAL>
double GammaImpl<REAL>::a[] = {
7.72156649015328655494e-02,
3.22467033424113591611e-01,
6.73523010531292681824e-02,
2.05808084325167332806e-02,
7.38555086081402883957e-03,
2.89051383673415629091e-03,
1.19270763183362067845e-03,
5.10069792153511336608e-04,
2.20862790713908385557e-04,
1.08011567247583939954e-04,
2.52144565451257326939e-05,
4.48640949618915160150e-05
};
template <class REAL>
double GammaImpl<REAL>::t[] = {
4.83836122723810047042e-01,
-1.47587722994593911752e-01,
6.46249402391333854778e-02,
-3.27885410759859649565e-02,
1.79706750811820387126e-02,
-1.03142241298341437450e-02,
6.10053870246291332635e-03,
-3.68452016781138256760e-03,
2.25964780900612472250e-03,
-1.40346469989232843813e-03,
8.81081882437654011382e-04,
-5.38595305356740546715e-04,
3.15632070903625950361e-04,
-3.12754168375120860518e-04,
3.35529192635519073543e-04
};
template <class REAL>
double GammaImpl<REAL>::u[] = {
-7.72156649015328655494e-02,
6.32827064025093366517e-01,
1.45492250137234768737e+00,
9.77717527963372745603e-01,
2.28963728064692451092e-01,
1.33810918536787660377e-02
};
template <class REAL>
double GammaImpl<REAL>::v[] = {
0.0,
2.45597793713041134822e+00,
2.12848976379893395361e+00,
7.69285150456672783825e-01,
1.04222645593369134254e-01,
3.21709242282423911810e-03
};
template <class REAL>
double GammaImpl<REAL>::s[] = {
-7.72156649015328655494e-02,
2.14982415960608852501e-01,
3.25778796408930981787e-01,
1.46350472652464452805e-01,
2.66422703033638609560e-02,
1.84028451407337715652e-03,
3.19475326584100867617e-05
};
template <class REAL>
double GammaImpl<REAL>::r[] = {
0.0,
1.39200533467621045958e+00,
7.21935547567138069525e-01,
1.71933865632803078993e-01,
1.86459191715652901344e-02,
7.77942496381893596434e-04,
7.32668430744625636189e-06
};
template <class REAL>
double GammaImpl<REAL>::w[] = {
4.18938533204672725052e-01,
8.33333333333329678849e-02,
-2.77777777728775536470e-03,
7.93650558643019558500e-04,
-5.95187557450339963135e-04,
8.36339918996282139126e-04,
-1.63092934096575273989e-03
};
template <class REAL>
REAL GammaImpl<REAL>::gamma(REAL x)
{ {
int i, k, m, ix = (int)x; int i, k, m, ix = (int)x;
double ga = 0.0, gr = 0.0, r = 0.0, z = 0.0; double ga = 0.0, gr = 0.0, r = 0.0, z = 0.0;
static double g[] = {
1.0,
0.5772156649015329,
-0.6558780715202538,
-0.420026350340952e-1,
0.1665386113822915,
-0.421977345555443e-1,
-0.9621971527877e-2,
0.7218943246663e-2,
-0.11651675918591e-2,
-0.2152416741149e-3,
0.1280502823882e-3,
-0.201348547807e-4,
-0.12504934821e-5,
0.1133027232e-5,
-0.2056338417e-6,
0.6116095e-8,
0.50020075e-8,
-0.11812746e-8,
0.1043427e-9,
0.77823e-11,
-0.36968e-11,
0.51e-12,
-0.206e-13,
-0.54e-14,
0.14e-14};
vigra_precondition(x <= 171.0, vigra_precondition(x <= 171.0,
"gamma(): argument cannot exceed 171.0."); "gamma(): argument cannot exceed 171.0.");
if (x == ix) if (x == ix)
{ {
if (ix > 0) if (ix > 0)
{ {
ga = 1.0; // use factorial ga = 1.0; // use factorial
for (i=2; i<ix; ++i) for (i=2; i<ix; ++i)
{ {
skipping to change at line 1306 skipping to change at line 1437
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
* *
* Developed at SunPro, a Sun Microsystems, Inc. business. * Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this * Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice * software is freely granted, provided that this notice
* is preserved. * is preserved.
* ==================================================== * ====================================================
* *
*/ */
template <class REAL> template <class REAL>
REAL loggammaImpl(REAL x) REAL GammaImpl<REAL>::loggamma(REAL x)
{ {
vigra_precondition(x > 0.0, vigra_precondition(x > 0.0,
"loggamma(): argument must be positive."); "loggamma(): argument must be positive.");
vigra_precondition(x <= 1.0e307, vigra_precondition(x <= 1.0e307,
"loggamma(): argument must not exceed 1e307."); "loggamma(): argument must not exceed 1e307.");
double res; double res;
if (x < 4.2351647362715017e-22) if (x < 4.2351647362715017e-22)
{ {
res = -std::log(x); res = -std::log(x);
} }
else if ((x == 2.0) || (x == 1.0)) else if ((x == 2.0) || (x == 1.0))
{ {
res = 0.0; res = 0.0;
} }
else if (x < 2.0) else if (x < 2.0)
{ {
static const double a[] = { 7.72156649015328655494e-02, const double tc = 1.46163214496836224576e+00;
3.22467033424113591611e-01, const double tf = -1.21486290535849611461e-01;
6.73523010531292681824e-02, const double tt = -3.63867699703950536541e-18;
2.05808084325167332806e-02,
7.38555086081402883957e-03,
2.89051383673415629091e-03,
1.19270763183362067845e-03,
5.10069792153511336608e-04,
2.20862790713908385557e-04,
1.08011567247583939954e-04,
2.52144565451257326939e-05,
4.48640949618915160150e-05 };
static const double t[] = { 4.83836122723810047042e-01,
-1.47587722994593911752e-01,
6.46249402391333854778e-02,
-3.27885410759859649565e-02,
1.79706750811820387126e-02,
-1.03142241298341437450e-02,
6.10053870246291332635e-03,
-3.68452016781138256760e-03,
2.25964780900612472250e-03,
-1.40346469989232843813e-03,
8.81081882437654011382e-04,
-5.38595305356740546715e-04,
3.15632070903625950361e-04,
-3.12754168375120860518e-04,
3.35529192635519073543e-04 };
static const double u[] = { -7.72156649015328655494e-02,
6.32827064025093366517e-01,
1.45492250137234768737e+00,
9.77717527963372745603e-01,
2.28963728064692451092e-01,
1.33810918536787660377e-02 };
static const double v[] = { 0.0,
2.45597793713041134822e+00,
2.12848976379893395361e+00,
7.69285150456672783825e-01,
1.04222645593369134254e-01,
3.21709242282423911810e-03 };
static const double tc = 1.46163214496836224576e+00;
static const double tf = -1.21486290535849611461e-01;
static const double tt = -3.63867699703950536541e-18;
if (x <= 0.9) if (x <= 0.9)
{ {
res = -std::log(x); res = -std::log(x);
if (x >= 0.7316) if (x >= 0.7316)
{ {
double y = 1.0-x; double y = 1.0-x;
double z = y*y; double z = y*y;
double p1 = a[0]+z*(a[2]+z*(a[4]+z*(a[6]+z*(a[8]+z*a[10]))) ); double p1 = a[0]+z*(a[2]+z*(a[4]+z*(a[6]+z*(a[8]+z*a[10]))) );
double p2 = z*(a[1]+z*(a[3]+z*(a[5]+z*(a[7]+z*(a[9]+z*a[11] ))))); double p2 = z*(a[1]+z*(a[3]+z*(a[5]+z*(a[7]+z*(a[9]+z*a[11] )))));
double p = y*p1+p2; double p = y*p1+p2;
skipping to change at line 1433 skipping to change at line 1525
{ {
double y = x-1.0; double y = x-1.0;
double p1 = y*(u[0]+y*(u[1]+y*(u[2]+y*(u[3]+y*(u[4]+y*u[5]) )))); double p1 = y*(u[0]+y*(u[1]+y*(u[2]+y*(u[3]+y*(u[4]+y*u[5]) ))));
double p2 = 1.0+y*(v[1]+y*(v[2]+y*(v[3]+y*(v[4]+y*v[5])))); double p2 = 1.0+y*(v[1]+y*(v[2]+y*(v[3]+y*(v[4]+y*v[5]))));
res += (-0.5*y + p1/p2); res += (-0.5*y + p1/p2);
} }
} }
} }
else if(x < 8.0) else if(x < 8.0)
{ {
static const double s[] = { -7.72156649015328655494e-02,
2.14982415960608852501e-01,
3.25778796408930981787e-01,
1.46350472652464452805e-01,
2.66422703033638609560e-02,
1.84028451407337715652e-03,
3.19475326584100867617e-05 };
static const double r[] = { 0.0,
1.39200533467621045958e+00,
7.21935547567138069525e-01,
1.71933865632803078993e-01,
1.86459191715652901344e-02,
7.77942496381893596434e-04,
7.32668430744625636189e-06 };
double i = std::floor(x); double i = std::floor(x);
double y = x-i; double y = x-i;
double p = y*(s[0]+y*(s[1]+y*(s[2]+y*(s[3]+y*(s[4]+y*(s[5]+y*s[6])) )))); double p = y*(s[0]+y*(s[1]+y*(s[2]+y*(s[3]+y*(s[4]+y*(s[5]+y*s[6])) ))));
double q = 1.0+y*(r[1]+y*(r[2]+y*(r[3]+y*(r[4]+y*(r[5]+y*r[6]))))); double q = 1.0+y*(r[1]+y*(r[2]+y*(r[3]+y*(r[4]+y*(r[5]+y*r[6])))));
res = 0.5*y+p/q; res = 0.5*y+p/q;
double z = 1.0; double z = 1.0;
while (i > 2.0) while (i > 2.0)
{ {
--i; --i;
z *= (y+i); z *= (y+i);
} }
res += std::log(z); res += std::log(z);
} }
else if (x < 2.8823037615171174e+17) else if (x < 2.8823037615171174e+17)
{ {
static const double w[] = { 4.18938533204672725052e-01,
8.33333333333329678849e-02,
-2.77777777728775536470e-03,
7.93650558643019558500e-04,
-5.95187557450339963135e-04,
8.36339918996282139126e-04,
-1.63092934096575273989e-03 };
double t = std::log(x); double t = std::log(x);
double z = 1.0/x; double z = 1.0/x;
double y = z*z; double y = z*z;
double yy = w[0]+z*(w[1]+y*(w[2]+y*(w[3]+y*(w[4]+y*(w[5]+y*w[6])))) ); double yy = w[0]+z*(w[1]+y*(w[2]+y*(w[3]+y*(w[4]+y*(w[5]+y*w[6])))) );
res = (x-0.5)*(t-1.0)+yy; res = (x-0.5)*(t-1.0)+yy;
} }
else else
{ {
res = x*(std::log(x) - 1.0); res = x*(std::log(x) - 1.0);
} }
return res; return res;
} }
} // namespace detail } // namespace detail
/*! The gamma function. /** \brief The gamma function.
This function implements the algorithm from<br> This function implements the algorithm from<br>
Zhang and Jin: "Computation of Special Functions", John Wiley and S ons, 1996. Zhang and Jin: "Computation of Special Functions", John Wiley and S ons, 1996.
The argument must be <= 171.0 and cannot be zero or a negative inte ger. An The argument must be <= 171.0 and cannot be zero or a negative inte ger. An
exception is thrown when these conditions are violated. exception is thrown when these conditions are violated.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double gamma(double x) inline double gamma(double x)
{ {
return detail::gammaImpl(x); return detail::GammaImpl<double>::gamma(x);
} }
/*! The natural logarithm of the gamma function. /** \brief The natural logarithm of the gamma function.
This function is based on a free implementation by Sun Microsystems , Inc., see This function is based on a free implementation by Sun Microsystems , Inc., see
<a href="http://www.sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/sr c/newlib/libm/mathfp/er_lgamma.c?rev=1.6&content-type=text/plain&cvsroot=sr c">sourceware.org</a> archive. It can be removed once all compilers support the new C99 <a href="http://www.sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/sr c/newlib/libm/mathfp/er_lgamma.c?rev=1.6&content-type=text/plain&cvsroot=sr c">sourceware.org</a> archive. It can be removed once all compilers support the new C99
math functions. math functions.
The argument must be positive and < 1e30. An exception is thrown wh en these conditions are violated. The argument must be positive and < 1e30. An exception is thrown wh en these conditions are violated.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double loggamma(double x) inline double loggamma(double x)
{ {
return detail::loggammaImpl(x); return detail::GammaImpl<double>::loggamma(x);
} }
namespace detail { namespace detail {
// both f1 and f2 are unsigned here // both f1 and f2 are unsigned here
template<class FPT> template<class FPT>
inline inline
FPT safeFloatDivision( FPT f1, FPT f2 ) FPT safeFloatDivision( FPT f1, FPT f2 )
{ {
return f2 < NumericTraits<FPT>::one() && f1 > f2 * NumericTraits<FPT>: :max() return f2 < NumericTraits<FPT>::one() && f1 > f2 * NumericTraits<FPT>: :max()
? NumericTraits<FPT>::max() ? NumericTraits<FPT>::max()
: (f2 > NumericTraits<FPT>::one() && f1 < f2 * NumericTrait s<FPT>::smallestPositive()) || : (f2 > NumericTraits<FPT>::one() && f1 < f2 * NumericTrait s<FPT>::smallestPositive()) ||
f1 == NumericTraits<FPT>::zero() f1 == NumericTraits<FPT>::zero()
? NumericTraits<FPT>::zero() ? NumericTraits<FPT>::zero()
: f1/f2; : f1/f2;
} }
} // namespace detail } // namespace detail
/*! Tolerance based floating-point comparison. /** \brief Tolerance based floating-point equality.
Check whether two floating point numbers are equal within the given tolerance. Check whether two floating point numbers are equal within the given tolerance.
This is useful because floating point numbers that should be equal in theory are This is useful because floating point numbers that should be equal in theory are
rarely exactly equal in practice. If the tolerance \a epsilon is no t given, rarely exactly equal in practice. If the tolerance \a epsilon is no t given,
twice the machine epsilon is used. twice the machine epsilon is used.
<b>\#include</b> \<vigra/mathutil.hxx\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T1, class T2> template <class T1, class T2>
skipping to change at line 1567 skipping to change at line 1638
return (d1 <= epsilon && d2 <= epsilon); return (d1 <= epsilon && d2 <= epsilon);
} }
template <class T1, class T2> template <class T1, class T2>
inline bool closeAtTolerance(T1 l, T2 r) inline bool closeAtTolerance(T1 l, T2 r)
{ {
typedef typename PromoteTraits<T1, T2>::Promote T; typedef typename PromoteTraits<T1, T2>::Promote T;
return closeAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon()); return closeAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon());
} }
/** \brief Tolerance based floating-point less-or-equal.
Check whether two floating point numbers are less or equal within t
he given tolerance.
That is, \a l can actually be greater than \a r within the given \a
epsilon.
This is useful because floating point numbers that should be equal
in theory are
rarely exactly equal in practice. If the tolerance \a epsilon is no
t given,
twice the machine epsilon is used.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
template <class T1, class T2>
inline bool
lessEqualAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote ep
silon)
{
return l < r || closeAtTolerance(l, r, epsilon);
}
template <class T1, class T2>
inline bool lessEqualAtTolerance(T1 l, T2 r)
{
typedef typename PromoteTraits<T1, T2>::Promote T;
return lessEqualAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon())
;
}
/** \brief Tolerance based floating-point greater-or-equal.
Check whether two floating point numbers are greater or equal withi
n the given tolerance.
That is, \a l can actually be less than \a r within the given \a ep
silon.
This is useful because floating point numbers that should be equal
in theory are
rarely exactly equal in practice. If the tolerance \a epsilon is no
t given,
twice the machine epsilon is used.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
template <class T1, class T2>
inline bool
greaterEqualAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote
epsilon)
{
return r < l || closeAtTolerance(l, r, epsilon);
}
template <class T1, class T2>
inline bool greaterEqualAtTolerance(T1 l, T2 r)
{
typedef typename PromoteTraits<T1, T2>::Promote T;
return greaterEqualAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon
());
}
//@} //@}
#define VIGRA_MATH_FUNC_HELPER(TYPE) \
inline TYPE clipLower(const TYPE t){ \
return t < static_cast<TYPE>(0.0) ? static_cast<TYPE>(0.0) : t; \
} \
inline TYPE clipLower(const TYPE t,const TYPE valLow){ \
return t < static_cast<TYPE>(valLow) ? static_cast<TYPE>(valLow) :
t; \
} \
inline TYPE clipUpper(const TYPE t,const TYPE valHigh){ \
return t > static_cast<TYPE>(valHigh) ? static_cast<TYPE>(valHigh)
: t; \
} \
inline TYPE clip(const TYPE t,const TYPE valLow, const TYPE valHigh){ \
if(t<valLow) \
return valLow; \
else if(t>valHigh) \
return valHigh; \
else \
return t; \
} \
inline TYPE sum(const TYPE t){ \
return t; \
}\
inline NumericTraits<TYPE>::RealPromote mean(const TYPE t){ \
return t; \
}\
inline TYPE isZero(const TYPE t){ \
return t==static_cast<TYPE>(0); \
} \
inline NumericTraits<TYPE>::RealPromote sizeDividedSquaredNorm(const TY
PE t){ \
return squaredNorm(t); \
} \
inline NumericTraits<TYPE>::RealPromote sizeDividedNorm(const TYPE t){
\
return norm(t); \
}
VIGRA_MATH_FUNC_HELPER(unsigned char)
VIGRA_MATH_FUNC_HELPER(unsigned short)
VIGRA_MATH_FUNC_HELPER(unsigned int)
VIGRA_MATH_FUNC_HELPER(unsigned long)
VIGRA_MATH_FUNC_HELPER(unsigned long long)
VIGRA_MATH_FUNC_HELPER(signed char)
VIGRA_MATH_FUNC_HELPER(signed short)
VIGRA_MATH_FUNC_HELPER(signed int)
VIGRA_MATH_FUNC_HELPER(signed long)
VIGRA_MATH_FUNC_HELPER(signed long long)
VIGRA_MATH_FUNC_HELPER(float)
VIGRA_MATH_FUNC_HELPER(double)
VIGRA_MATH_FUNC_HELPER(long double)
#undef VIGRA_MATH_FUNC_HELPER
} // namespace vigra } // namespace vigra
#endif /* VIGRA_MATHUTIL_HXX */ #endif /* VIGRA_MATHUTIL_HXX */
 End of changes. 59 change blocks. 
146 lines changed or deleted 334 lines changed or added


 matrix.hxx   matrix.hxx 
skipping to change at line 116 skipping to change at line 116
(no one wants to spend half the day installing a new library just to (no one wants to spend half the day installing a new library just to
discover that the new algorithm idea didn't work anyway). discover that the new algorithm idea didn't work anyway).
<b>See also:</b> <b>See also:</b>
<ul> <ul>
<li> \ref LinearAlgebraFunctions <li> \ref LinearAlgebraFunctions
</ul> </ul>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class ALLOC = std::allocator<T> > template <class T, class ALLOC = std::allocator<T> >
class Matrix class Matrix
: public MultiArray<2, T, ALLOC> : public MultiArray<2, T, ALLOC>
{ {
typedef MultiArray<2, T, ALLOC> BaseType; typedef MultiArray<2, T, ALLOC> BaseType;
public: public:
typedef Matrix<T, ALLOC> matrix_type; typedef Matrix<T, ALLOC> matrix_type;
typedef TemporaryMatrix<T, ALLOC> temp_type; typedef TemporaryMatrix<T, ALLOC> temp_type;
typedef MultiArrayView<2, T, UnstridedArrayTag> view_type; typedef MultiArrayView<2, T> view_type;
typedef typename BaseType::value_type value_type; typedef typename BaseType::value_type value_type;
typedef typename BaseType::pointer pointer; typedef typename BaseType::pointer pointer;
typedef typename BaseType::const_pointer const_pointer; typedef typename BaseType::const_pointer const_pointer;
typedef typename BaseType::reference reference; typedef typename BaseType::reference reference;
typedef typename BaseType::const_reference const_reference; typedef typename BaseType::const_reference const_reference;
typedef typename BaseType::difference_type difference_type; typedef typename BaseType::difference_type difference_type;
typedef typename BaseType::difference_type_1 difference_type_1; typedef typename BaseType::difference_type_1 difference_type_1;
typedef ALLOC allocator_type; typedef ALLOC allocator_type;
/** default constructor /** default constructor
skipping to change at line 153 skipping to change at line 153
*/ */
explicit Matrix(ALLOC const & alloc) explicit Matrix(ALLOC const & alloc)
: BaseType(alloc) : BaseType(alloc)
{} {}
/** construct with given shape and init all /** construct with given shape and init all
elements with zero. Note that the order of the axes is elements with zero. Note that the order of the axes is
<tt>difference_type(rows, columns)</tt> which <tt>difference_type(rows, columns)</tt> which
is the opposite of the usual VIGRA convention. is the opposite of the usual VIGRA convention.
*/ */
explicit Matrix(const difference_type &shape, explicit Matrix(const difference_type &aShape,
ALLOC const & alloc = allocator_type()) ALLOC const & alloc = allocator_type())
: BaseType(shape, alloc) : BaseType(aShape, alloc)
{} {}
/** construct with given shape and init all /** construct with given shape and init all
elements with zero. Note that the order of the axes is elements with zero. Note that the order of the axes is
<tt>(rows, columns)</tt> which <tt>(rows, columns)</tt> which
is the opposite of the usual VIGRA convention. is the opposite of the usual VIGRA convention.
*/ */
Matrix(difference_type_1 rows, difference_type_1 columns, Matrix(difference_type_1 rows, difference_type_1 columns,
ALLOC const & alloc = allocator_type()) ALLOC const & alloc = allocator_type())
: BaseType(difference_type(rows, columns), alloc) : BaseType(difference_type(rows, columns), alloc)
{} {}
/** construct with given shape and init all /** construct with given shape and init all
elements with the constant \a init. Note that the order of the axes is elements with the constant \a init. Note that the order of the axes is
<tt>difference_type(rows, columns)</tt> which <tt>difference_type(rows, columns)</tt> which
is the opposite of the usual VIGRA convention. is the opposite of the usual VIGRA convention.
*/ */
Matrix(const difference_type &shape, const_reference init, Matrix(const difference_type &aShape, const_reference init,
allocator_type const & alloc = allocator_type()) allocator_type const & alloc = allocator_type())
: BaseType(shape, init, alloc) : BaseType(aShape, init, alloc)
{} {}
/** construct with given shape and init all /** construct with given shape and init all
elements with the constant \a init. Note that the order of the axes is elements with the constant \a init. Note that the order of the axes is
<tt>(rows, columns)</tt> which <tt>(rows, columns)</tt> which
is the opposite of the usual VIGRA convention. is the opposite of the usual VIGRA convention.
*/ */
Matrix(difference_type_1 rows, difference_type_1 columns, const_referen ce init, Matrix(difference_type_1 rows, difference_type_1 columns, const_referen ce init,
allocator_type const & alloc = allocator_type()) allocator_type const & alloc = allocator_type())
: BaseType(difference_type(rows, columns), init, alloc) : BaseType(difference_type(rows, columns), init, alloc)
skipping to change at line 335 skipping to change at line 335
/** reshape to the given shape and initialize with \a init. /** reshape to the given shape and initialize with \a init.
*/ */
void reshape(difference_type_1 rows, difference_type_1 columns, const_r eference init) void reshape(difference_type_1 rows, difference_type_1 columns, const_r eference init)
{ {
BaseType::reshape(difference_type(rows, columns), init); BaseType::reshape(difference_type(rows, columns), init);
} }
/** reshape to the given shape and initialize with zero. /** reshape to the given shape and initialize with zero.
*/ */
void reshape(difference_type const & shape) void reshape(difference_type const & newShape)
{ {
BaseType::reshape(shape); BaseType::reshape(newShape);
} }
/** reshape to the given shape and initialize with \a init. /** reshape to the given shape and initialize with \a init.
*/ */
void reshape(difference_type const & shape, const_reference init) void reshape(difference_type const & newShape, const_reference init)
{ {
BaseType::reshape(shape, init); BaseType::reshape(newShape, init);
} }
/** Create a matrix view that represents the row vector of row \a d . /** Create a matrix view that represents the row vector of row \a d .
*/ */
view_type rowVector(difference_type_1 d) const view_type rowVector(difference_type_1 d) const
{ {
return vigra::linalg::rowVector(*this, d); return vigra::linalg::rowVector(*this, d);
} }
/** Create a matrix view that represents the column vector of colum n \a d. /** Create a matrix view that represents the column vector of colum n \a d.
skipping to change at line 550 skipping to change at line 550
// Functions receiving a TemporaryMatrix can thus often avoid to allocate n ew temporary // Functions receiving a TemporaryMatrix can thus often avoid to allocate n ew temporary
// memory. // memory.
template <class T, class ALLOC> // default ALLOC already declared above template <class T, class ALLOC> // default ALLOC already declared above
class TemporaryMatrix class TemporaryMatrix
: public Matrix<T, ALLOC> : public Matrix<T, ALLOC>
{ {
typedef Matrix<T, ALLOC> BaseType; typedef Matrix<T, ALLOC> BaseType;
public: public:
typedef Matrix<T, ALLOC> matrix_type; typedef Matrix<T, ALLOC> matrix_type;
typedef TemporaryMatrix<T, ALLOC> temp_type; typedef TemporaryMatrix<T, ALLOC> temp_type;
typedef MultiArrayView<2, T, UnstridedArrayTag> view_type; typedef MultiArrayView<2, T, StridedArrayTag> view_type;
typedef typename BaseType::value_type value_type; typedef typename BaseType::value_type value_type;
typedef typename BaseType::pointer pointer; typedef typename BaseType::pointer pointer;
typedef typename BaseType::const_pointer const_pointer; typedef typename BaseType::const_pointer const_pointer;
typedef typename BaseType::reference reference; typedef typename BaseType::reference reference;
typedef typename BaseType::const_reference const_reference; typedef typename BaseType::const_reference const_reference;
typedef typename BaseType::difference_type difference_type; typedef typename BaseType::difference_type difference_type;
typedef typename BaseType::difference_type_1 difference_type_1; typedef typename BaseType::difference_type_1 difference_type_1;
typedef ALLOC allocator_type; typedef ALLOC allocator_type;
TemporaryMatrix(difference_type const & shape) TemporaryMatrix(difference_type const & shape)
skipping to change at line 660 skipping to change at line 660
/** \defgroup LinearAlgebraFunctions Matrix Functions /** \defgroup LinearAlgebraFunctions Matrix Functions
\brief Basic matrix algebra, element-wise mathematical functions, row a nd columns statistics, data normalization etc. \brief Basic matrix algebra, element-wise mathematical functions, row a nd columns statistics, data normalization etc.
\ingroup LinearAlgebraModule \ingroup LinearAlgebraModule
*/ */
//@{ //@{
/** Number of rows of a matrix represented as a <tt>MultiArrayView<2, . ..></tt> /** Number of rows of a matrix represented as a <tt>MultiArrayView<2, . ..></tt>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline MultiArrayIndex inline MultiArrayIndex
rowCount(const MultiArrayView<2, T, C> &x) rowCount(const MultiArrayView<2, T, C> &x)
{ {
return x.shape(0); return x.shape(0);
} }
/** Number of columns of a matrix represented as a <tt>MultiArrayView<2 , ...></tt> /** Number of columns of a matrix represented as a <tt>MultiArrayView<2 , ...></tt>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline MultiArrayIndex inline MultiArrayIndex
columnCount(const MultiArrayView<2, T, C> &x) columnCount(const MultiArrayView<2, T, C> &x)
{ {
return x.shape(1); return x.shape(1);
} }
/** Create a row vector view for row \a d of the matrix \a m /** Create a row vector view for row \a d of the matrix \a m
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline MultiArrayView <2, T, C> inline MultiArrayView <2, T, C>
rowVector(MultiArrayView <2, T, C> const & m, MultiArrayIndex d) rowVector(MultiArrayView <2, T, C> const & m, MultiArrayIndex d)
{ {
typedef typename MultiArrayView <2, T, C>::difference_type Shape; typedef typename MultiArrayView <2, T, C>::difference_type Shape;
return m.subarray(Shape(d, 0), Shape(d+1, columnCount(m))); return m.subarray(Shape(d, 0), Shape(d+1, columnCount(m)));
} }
/** Create a row vector view of the matrix \a m starting at element \a first and ranging /** Create a row vector view of the matrix \a m starting at element \a first and ranging
to column \a end (non-inclusive). to column \a end (non-inclusive).
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline MultiArrayView <2, T, C> inline MultiArrayView <2, T, C>
rowVector(MultiArrayView <2, T, C> const & m, MultiArrayShape<2>::type firs t, MultiArrayIndex end) rowVector(MultiArrayView <2, T, C> const & m, MultiArrayShape<2>::type firs t, MultiArrayIndex end)
{ {
typedef typename MultiArrayView <2, T, C>::difference_type Shape; typedef typename MultiArrayView <2, T, C>::difference_type Shape;
return m.subarray(first, Shape(first[0]+1, end)); return m.subarray(first, Shape(first[0]+1, end));
} }
/** Create a column vector view for column \a d of the matrix \a m /** Create a column vector view for column \a d of the matrix \a m
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline MultiArrayView <2, T, C> inline MultiArrayView <2, T, C>
columnVector(MultiArrayView<2, T, C> const & m, MultiArrayIndex d) columnVector(MultiArrayView<2, T, C> const & m, MultiArrayIndex d)
{ {
typedef typename MultiArrayView <2, T, C>::difference_type Shape; typedef typename MultiArrayView <2, T, C>::difference_type Shape;
return m.subarray(Shape(0, d), Shape(rowCount(m), d+1)); return m.subarray(Shape(0, d), Shape(rowCount(m), d+1));
} }
/** Create a column vector view of the matrix \a m starting at element \a first and /** Create a column vector view of the matrix \a m starting at element \a first and
ranging to row \a end (non-inclusive). ranging to row \a end (non-inclusive).
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
**/ **/
template <class T, class C> template <class T, class C>
inline MultiArrayView <2, T, C> inline MultiArrayView <2, T, C>
columnVector(MultiArrayView<2, T, C> const & m, MultiArrayShape<2>::type fi rst, int end) columnVector(MultiArrayView<2, T, C> const & m, MultiArrayShape<2>::type fi rst, int end)
{ {
typedef typename MultiArrayView <2, T, C>::difference_type Shape; typedef typename MultiArrayView <2, T, C>::difference_type Shape;
return m.subarray(first, Shape(end, first[1]+1)); return m.subarray(first, Shape(end, first[1]+1));
} }
/** Create a sub vector view of the vector \a m starting at element \a first and /** Create a sub vector view of the vector \a m starting at element \a first and
ranging to row \a end (non-inclusive). ranging to row \a end (non-inclusive).
Note: This function may only be called when either <tt>rowCount(m) == 1</tt> or Note: This function may only be called when either <tt>rowCount(m) == 1</tt> or
<tt>columnCount(m) == 1</tt>, i.e. when \a m really represents a ve ctor. <tt>columnCount(m) == 1</tt>, i.e. when \a m really represents a ve ctor.
Otherwise, a PreconditionViolation exception is raised. Otherwise, a PreconditionViolation exception is raised.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
**/ **/
template <class T, class C> template <class T, class C>
inline MultiArrayView <2, T, C> inline MultiArrayView <2, T, C>
subVector(MultiArrayView<2, T, C> const & m, int first, int end) subVector(MultiArrayView<2, T, C> const & m, int first, int end)
{ {
typedef typename MultiArrayView <2, T, C>::difference_type Shape; typedef typename MultiArrayView <2, T, C>::difference_type Shape;
if(columnCount(m) == 1) if(columnCount(m) == 1)
return m.subarray(Shape(first, 0), Shape(end, 1)); return m.subarray(Shape(first, 0), Shape(end, 1));
vigra_precondition(rowCount(m) == 1, vigra_precondition(rowCount(m) == 1,
"linalg::subVector(): Input must be a vector (1xN or Nx1)."); "linalg::subVector(): Input must be a vector (1xN or Nx1).");
return m.subarray(Shape(0, first), Shape(1, end)); return m.subarray(Shape(0, first), Shape(1, end));
} }
/** Check whether matrix \a m is symmetric. /** Check whether matrix \a m is symmetric.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
bool bool
isSymmetric(MultiArrayView<2, T, C> const & m) isSymmetric(MultiArrayView<2, T, C> const & m)
{ {
const MultiArrayIndex size = rowCount(m); const MultiArrayIndex size = rowCount(m);
if(size != columnCount(m)) if(size != columnCount(m))
return false; return false;
for(MultiArrayIndex i = 0; i < size; ++i) for(MultiArrayIndex i = 0; i < size; ++i)
for(MultiArrayIndex j = i+1; j < size; ++j) for(MultiArrayIndex j = i+1; j < size; ++j)
if(m(j, i) != m(i, j)) if(m(j, i) != m(i, j))
return false; return false;
return true; return true;
} }
/** Compute the trace of a square matrix. /** Compute the trace of a square matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
typename NumericTraits<T>::Promote typename NumericTraits<T>::Promote
trace(MultiArrayView<2, T, C> const & m) trace(MultiArrayView<2, T, C> const & m)
{ {
typedef typename NumericTraits<T>::Promote SumType; typedef typename NumericTraits<T>::Promote SumType;
const MultiArrayIndex size = rowCount(m); const MultiArrayIndex size = rowCount(m);
vigra_precondition(size == columnCount(m), "linalg::trace(): Matrix mus t be square."); vigra_precondition(size == columnCount(m), "linalg::trace(): Matrix mus t be square.");
skipping to change at line 812 skipping to change at line 812
for(MultiArrayIndex i = 0; i < size; ++i) for(MultiArrayIndex i = 0; i < size; ++i)
sum += m(i, i); sum += m(i, i);
return sum; return sum;
} }
#ifdef DOXYGEN // documentation only -- function is already defined in vigr a/multi_array.hxx #ifdef DOXYGEN // documentation only -- function is already defined in vigr a/multi_array.hxx
/** calculate the squared Frobenius norm of a matrix. /** calculate the squared Frobenius norm of a matrix.
Equal to the sum of squares of the matrix elements. Equal to the sum of squares of the matrix elements.
<b>\#include</b> \<vigra/matrix.hxx\> <b>\#include</b> \<vigra/matrix.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class ALLOC> template <class T, class ALLOC>
typename Matrix<T, ALLLOC>::SquaredNormType typename Matrix<T, ALLLOC>::SquaredNormType
squaredNorm(const Matrix<T, ALLLOC> &a); squaredNorm(const Matrix<T, ALLLOC> &a);
/** calculate the Frobenius norm of a matrix. /** calculate the Frobenius norm of a matrix.
Equal to the root of the sum of squares of the matrix elements. Equal to the root of the sum of squares of the matrix elements.
<b>\#include</b> \<vigra/matrix.hxx\> <b>\#include</b> \<vigra/matrix.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class ALLOC> template <class T, class ALLOC>
typename Matrix<T, ALLLOC>::NormType typename Matrix<T, ALLLOC>::NormType
norm(const Matrix<T, ALLLOC> &a); norm(const Matrix<T, ALLLOC> &a);
#endif // DOXYGEN #endif // DOXYGEN
/** initialize the given square matrix as an identity matrix. /** initialize the given square matrix as an identity matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
void identityMatrix(MultiArrayView<2, T, C> &r) void identityMatrix(MultiArrayView<2, T, C> &r)
{ {
const MultiArrayIndex rows = rowCount(r); const MultiArrayIndex rows = rowCount(r);
vigra_precondition(rows == columnCount(r), vigra_precondition(rows == columnCount(r),
"identityMatrix(): Matrix must be square."); "identityMatrix(): Matrix must be square.");
for(MultiArrayIndex i = 0; i < rows; ++i) { for(MultiArrayIndex i = 0; i < rows; ++i) {
for(MultiArrayIndex j = 0; j < rows; ++j) for(MultiArrayIndex j = 0; j < rows; ++j)
skipping to change at line 857 skipping to change at line 857
} }
} }
/** create an identity matrix of the given size. /** create an identity matrix of the given size.
Usage: Usage:
\code \code
vigra::Matrix<double> m = vigra::identityMatrix<double>(size); vigra::Matrix<double> m = vigra::identityMatrix<double>(size);
\endcode \endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T> template <class T>
TemporaryMatrix<T> identityMatrix(MultiArrayIndex size) TemporaryMatrix<T> identityMatrix(MultiArrayIndex size)
{ {
TemporaryMatrix<T> ret(size, size, NumericTraits<T>::zero()); TemporaryMatrix<T> ret(size, size, NumericTraits<T>::zero());
for(MultiArrayIndex i = 0; i < size; ++i) for(MultiArrayIndex i = 0; i < size; ++i)
ret(i, i) = NumericTraits<T>::one(); ret(i, i) = NumericTraits<T>::one();
return ret; return ret;
} }
/** create matrix of ones of the given size. /** create matrix of ones of the given size.
Usage: Usage:
\code \code
vigra::Matrix<double> m = vigra::ones<double>(rows, cols); vigra::Matrix<double> m = vigra::ones<double>(rows, cols);
\endcode \endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T> template <class T>
TemporaryMatrix<T> ones(MultiArrayIndex rows, MultiArrayIndex cols) TemporaryMatrix<T> ones(MultiArrayIndex rows, MultiArrayIndex cols)
{ {
return TemporaryMatrix<T>(rows, cols, NumericTraits<T>::one()); return TemporaryMatrix<T>(rows, cols, NumericTraits<T>::one());
} }
template <class T, class C1, class C2> template <class T, class C1, class C2>
void diagonalMatrixImpl(MultiArrayView<1, T, C1> const & v, MultiArrayView< 2, T, C2> &r) void diagonalMatrixImpl(MultiArrayView<1, T, C1> const & v, MultiArrayView< 2, T, C2> &r)
skipping to change at line 901 skipping to change at line 901
vigra_precondition(rowCount(r) == size && columnCount(r) == size, vigra_precondition(rowCount(r) == size && columnCount(r) == size,
"diagonalMatrix(): result must be a square matrix."); "diagonalMatrix(): result must be a square matrix.");
for(MultiArrayIndex i = 0; i < size; ++i) for(MultiArrayIndex i = 0; i < size; ++i)
r(i, i) = v(i); r(i, i) = v(i);
} }
/** make a diagonal matrix from a vector. /** make a diagonal matrix from a vector.
The vector is given as matrix \a v, which must either have a single The vector is given as matrix \a v, which must either have a single
row or column. The result is written into the square matrix \a r. row or column. The result is written into the square matrix \a r.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
void diagonalMatrix(MultiArrayView<2, T, C1> const & v, MultiArrayView<2, T , C2> &r) void diagonalMatrix(MultiArrayView<2, T, C1> const & v, MultiArrayView<2, T , C2> &r)
{ {
vigra_precondition(rowCount(v) == 1 || columnCount(v) == 1, vigra_precondition(rowCount(v) == 1 || columnCount(v) == 1,
"diagonalMatrix(): input must be a vector."); "diagonalMatrix(): input must be a vector.");
r.init(NumericTraits<T>::zero()); r.init(NumericTraits<T>::zero());
if(rowCount(v) == 1) if(rowCount(v) == 1)
diagonalMatrixImpl(v.bindInner(0), r); diagonalMatrixImpl(v.bindInner(0), r);
skipping to change at line 929 skipping to change at line 929
row or column. The result is returned as a temporary matrix. row or column. The result is returned as a temporary matrix.
Usage: Usage:
\code \code
vigra::Matrix<double> v(1, len); vigra::Matrix<double> v(1, len);
v = ...; v = ...;
vigra::Matrix<double> m = diagonalMatrix(v); vigra::Matrix<double> m = diagonalMatrix(v);
\endcode \endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
TemporaryMatrix<T> diagonalMatrix(MultiArrayView<2, T, C> const & v) TemporaryMatrix<T> diagonalMatrix(MultiArrayView<2, T, C> const & v)
{ {
vigra_precondition(rowCount(v) == 1 || columnCount(v) == 1, vigra_precondition(rowCount(v) == 1 || columnCount(v) == 1,
"diagonalMatrix(): input must be a vector."); "diagonalMatrix(): input must be a vector.");
MultiArrayIndex size = v.elementCount(); MultiArrayIndex size = v.elementCount();
TemporaryMatrix<T> ret(size, size, NumericTraits<T>::zero()); TemporaryMatrix<T> ret(size, size, NumericTraits<T>::zero());
if(rowCount(v) == 1) if(rowCount(v) == 1)
diagonalMatrixImpl(v.bindInner(0), ret); diagonalMatrixImpl(v.bindInner(0), ret);
else else
diagonalMatrixImpl(v.bindOuter(0), ret); diagonalMatrixImpl(v.bindOuter(0), ret);
return ret; return ret;
} }
/** transpose matrix \a v. /** transpose matrix \a v.
The result is written into \a r which must have the correct (i.e. The result is written into \a r which must have the correct (i.e.
transposed) shape. transposed) shape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
void transpose(const MultiArrayView<2, T, C1> &v, MultiArrayView<2, T, C2> &r) void transpose(const MultiArrayView<2, T, C1> &v, MultiArrayView<2, T, C2> &r)
{ {
const MultiArrayIndex rows = rowCount(r); const MultiArrayIndex rows = rowCount(r);
const MultiArrayIndex cols = columnCount(r); const MultiArrayIndex cols = columnCount(r);
vigra_precondition(rows == columnCount(v) && cols == rowCount(v), vigra_precondition(rows == columnCount(v) && cols == rowCount(v),
"transpose(): arrays must have transposed shapes."); "transpose(): arrays must have transposed shapes.");
for(MultiArrayIndex i = 0; i < cols; ++i) for(MultiArrayIndex i = 0; i < cols; ++i)
skipping to change at line 980 skipping to change at line 980
is assigned to another matrix. is assigned to another matrix.
Usage: Usage:
\code \code
vigra::Matrix<double> v(rows, cols); vigra::Matrix<double> v(rows, cols);
v = ...; v = ...;
vigra::Matrix<double> m = transpose(v); vigra::Matrix<double> m = transpose(v);
\endcode \endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline MultiArrayView<2, T, StridedArrayTag> inline MultiArrayView<2, T, StridedArrayTag>
transpose(MultiArrayView<2, T, C> const & v) transpose(MultiArrayView<2, T, C> const & v)
{ {
return v.transpose(); return v.transpose();
} }
/** Create new matrix by concatenating two matrices \a a and \a b verti cally, i.e. on top of each other. /** Create new matrix by concatenating two matrices \a a and \a b verti cally, i.e. on top of each other.
The two matrices must have the same number of columns. The two matrices must have the same number of columns.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
joinVertically(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T , C2> &b) joinVertically(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T , C2> &b)
{ {
typedef typename TemporaryMatrix<T>::difference_type Shape; typedef typename TemporaryMatrix<T>::difference_type Shape;
MultiArrayIndex n = columnCount(a); MultiArrayIndex n = columnCount(a);
vigra_precondition(n == columnCount(b), vigra_precondition(n == columnCount(b),
skipping to change at line 1021 skipping to change at line 1021
TemporaryMatrix<T> t(ma + mb, n, T()); TemporaryMatrix<T> t(ma + mb, n, T());
t.subarray(Shape(0,0), Shape(ma, n)) = a; t.subarray(Shape(0,0), Shape(ma, n)) = a;
t.subarray(Shape(ma,0), Shape(ma+mb, n)) = b; t.subarray(Shape(ma,0), Shape(ma+mb, n)) = b;
return t; return t;
} }
/** Create new matrix by concatenating two matrices \a a and \a b horiz ontally, i.e. side by side. /** Create new matrix by concatenating two matrices \a a and \a b horiz ontally, i.e. side by side.
The two matrices must have the same number of rows. The two matrices must have the same number of rows.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
joinHorizontally(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) joinHorizontally(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
typedef typename TemporaryMatrix<T>::difference_type Shape; typedef typename TemporaryMatrix<T>::difference_type Shape;
MultiArrayIndex m = rowCount(a); MultiArrayIndex m = rowCount(a);
vigra_precondition(m == rowCount(b), vigra_precondition(m == rowCount(b),
skipping to change at line 1049 skipping to change at line 1049
t.subarray(Shape(0, na), Shape(m, na + nb)) = b; t.subarray(Shape(0, na), Shape(m, na + nb)) = b;
return t; return t;
} }
/** Initialize a matrix with repeated copies of a given matrix. /** Initialize a matrix with repeated copies of a given matrix.
Matrix \a r will consist of \a verticalCount downward repetitions o f \a v, Matrix \a r will consist of \a verticalCount downward repetitions o f \a v,
and \a horizontalCount side-by-side repetitions. When \a v has size <tt>m</tt> by <tt>n</tt>, and \a horizontalCount side-by-side repetitions. When \a v has size <tt>m</tt> by <tt>n</tt>,
\a r must have size <tt>(m*verticalCount)</tt> by <tt>(n*horizontal Count)</tt>. \a r must have size <tt>(m*verticalCount)</tt> by <tt>(n*horizontal Count)</tt>.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
void repeatMatrix(MultiArrayView<2, T, C1> const & v, MultiArrayView<2, T, C2> &r, void repeatMatrix(MultiArrayView<2, T, C1> const & v, MultiArrayView<2, T, C2> &r,
unsigned int verticalCount, unsigned int horizontalCount) unsigned int verticalCount, unsigned int horizontalCount)
{ {
typedef typename Matrix<T>::difference_type Shape; typedef typename Matrix<T>::difference_type Shape;
MultiArrayIndex m = rowCount(v), n = columnCount(v); MultiArrayIndex m = rowCount(v), n = columnCount(v);
vigra_precondition(m*verticalCount == rowCount(r) && n*horizontalCount == columnCount(r), vigra_precondition(m*verticalCount == rowCount(r) && n*horizontalCount == columnCount(r),
"repeatMatrix(): Shape mismatch."); "repeatMatrix(): Shape mismatch.");
for(MultiArrayIndex l=0; l<(MultiArrayIndex)horizontalCount; ++l) for(MultiArrayIndex l=0; l<static_cast<MultiArrayIndex>(horizontalCount ); ++l)
{ {
for(MultiArrayIndex k=0; k<(MultiArrayIndex)verticalCount; ++k) for(MultiArrayIndex k=0; k<static_cast<MultiArrayIndex>(verticalCou nt); ++k)
{ {
r.subarray(Shape(k*m, l*n), Shape((k+1)*m, (l+1)*n)) = v; r.subarray(Shape(k*m, l*n), Shape((k+1)*m, (l+1)*n)) = v;
} }
} }
} }
/** Create a new matrix by repeating a given matrix. /** Create a new matrix by repeating a given matrix.
The resulting matrix \a r will consist of \a verticalCount downward repetitions of \a v, The resulting matrix \a r will consist of \a verticalCount downward repetitions of \a v,
and \a horizontalCount side-by-side repetitions, i.e. it will be of size and \a horizontalCount side-by-side repetitions, i.e. it will be of size
<tt>(m*verticalCount)</tt> by <tt>(n*horizontalCount)</tt> when \a v has size <tt>m</tt> by <tt>n</tt>. <tt>(m*verticalCount)</tt> by <tt>(n*horizontalCount)</tt> when \a v has size <tt>m</tt> by <tt>n</tt>.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
TemporaryMatrix<T> TemporaryMatrix<T>
repeatMatrix(MultiArrayView<2, T, C> const & v, unsigned int verticalCount, unsigned int horizontalCount) repeatMatrix(MultiArrayView<2, T, C> const & v, unsigned int verticalCount, unsigned int horizontalCount)
{ {
MultiArrayIndex m = rowCount(v), n = columnCount(v); MultiArrayIndex m = rowCount(v), n = columnCount(v);
TemporaryMatrix<T> ret(verticalCount*m, horizontalCount*n); TemporaryMatrix<T> ret(verticalCount*m, horizontalCount*n);
repeatMatrix(v, ret, verticalCount, horizontalCount); repeatMatrix(v, ret, verticalCount, horizontalCount);
return ret; return ret;
} }
/** add matrices \a a and \a b. /** add matrices \a a and \a b.
The result is written into \a r. All three matrices must have the s ame shape. The result is written into \a r. All three matrices must have the s ame shape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void add(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b, void add(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
const MultiArrayIndex rrows = rowCount(r); const MultiArrayIndex rrows = rowCount(r);
const MultiArrayIndex rcols = columnCount(r); const MultiArrayIndex rcols = columnCount(r);
vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) && vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) &&
rrows == rowCount(b) && rcols == columnCount(b), rrows == rowCount(b) && rcols == columnCount(b),
skipping to change at line 1121 skipping to change at line 1121
for(MultiArrayIndex j = 0; j < rrows; ++j) { for(MultiArrayIndex j = 0; j < rrows; ++j) {
r(j, i) = a(j, i) + b(j, i); r(j, i) = a(j, i) + b(j, i);
} }
} }
} }
/** add matrices \a a and \a b. /** add matrices \a a and \a b.
The two matrices must have the same shape. The two matrices must have the same shape.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator+(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) operator+(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
return TemporaryMatrix<T>(a) += b; return TemporaryMatrix<T>(a) += b;
} }
template <class T, class C> template <class T, class C>
skipping to change at line 1156 skipping to change at line 1156
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator+(const TemporaryMatrix<T> &a, const TemporaryMatrix<T> &b) operator+(const TemporaryMatrix<T> &a, const TemporaryMatrix<T> &b)
{ {
return const_cast<TemporaryMatrix<T> &>(a) += b; return const_cast<TemporaryMatrix<T> &>(a) += b;
} }
/** add scalar \a b to every element of the matrix \a a. /** add scalar \a b to every element of the matrix \a a.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator+(const MultiArrayView<2, T, C> &a, T b) operator+(const MultiArrayView<2, T, C> &a, T b)
{ {
return TemporaryMatrix<T>(a) += b; return TemporaryMatrix<T>(a) += b;
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator+(const TemporaryMatrix<T> &a, T b) operator+(const TemporaryMatrix<T> &a, T b)
{ {
return const_cast<TemporaryMatrix<T> &>(a) += b; return const_cast<TemporaryMatrix<T> &>(a) += b;
} }
/** add scalar \a a to every element of the matrix \a b. /** add scalar \a a to every element of the matrix \a b.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator+(T a, const MultiArrayView<2, T, C> &b) operator+(T a, const MultiArrayView<2, T, C> &b)
{ {
return TemporaryMatrix<T>(b) += a; return TemporaryMatrix<T>(b) += a;
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator+(T a, const TemporaryMatrix<T> &b) operator+(T a, const TemporaryMatrix<T> &b)
{ {
return const_cast<TemporaryMatrix<T> &>(b) += a; return const_cast<TemporaryMatrix<T> &>(b) += a;
} }
/** subtract matrix \a b from \a a. /** subtract matrix \a b from \a a.
The result is written into \a r. All three matrices must have the s ame shape. The result is written into \a r. All three matrices must have the s ame shape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void sub(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b, void sub(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
const MultiArrayIndex rrows = rowCount(r); const MultiArrayIndex rrows = rowCount(r);
const MultiArrayIndex rcols = columnCount(r); const MultiArrayIndex rcols = columnCount(r);
vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) && vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) &&
rrows == rowCount(b) && rcols == columnCount(b), rrows == rowCount(b) && rcols == columnCount(b),
skipping to change at line 1223 skipping to change at line 1223
for(MultiArrayIndex j = 0; j < rrows; ++j) { for(MultiArrayIndex j = 0; j < rrows; ++j) {
r(j, i) = a(j, i) - b(j, i); r(j, i) = a(j, i) - b(j, i);
} }
} }
} }
/** subtract matrix \a b from \a a. /** subtract matrix \a b from \a a.
The two matrices must have the same shape. The two matrices must have the same shape.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) operator-(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
return TemporaryMatrix<T>(a) -= b; return TemporaryMatrix<T>(a) -= b;
} }
template <class T, class C> template <class T, class C>
skipping to change at line 1266 skipping to change at line 1266
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(const TemporaryMatrix<T> &a, const TemporaryMatrix<T> &b) operator-(const TemporaryMatrix<T> &a, const TemporaryMatrix<T> &b)
{ {
return const_cast<TemporaryMatrix<T> &>(a) -= b; return const_cast<TemporaryMatrix<T> &>(a) -= b;
} }
/** negate matrix \a a. /** negate matrix \a a.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(const MultiArrayView<2, T, C> &a) operator-(const MultiArrayView<2, T, C> &a)
{ {
return TemporaryMatrix<T>(a) *= -NumericTraits<T>::one(); return TemporaryMatrix<T>(a) *= -NumericTraits<T>::one();
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(const TemporaryMatrix<T> &a) operator-(const TemporaryMatrix<T> &a)
{ {
return const_cast<TemporaryMatrix<T> &>(a) *= -NumericTraits<T>::one(); return const_cast<TemporaryMatrix<T> &>(a) *= -NumericTraits<T>::one();
} }
/** subtract scalar \a b from every element of the matrix \a a. /** subtract scalar \a b from every element of the matrix \a a.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(const MultiArrayView<2, T, C> &a, T b) operator-(const MultiArrayView<2, T, C> &a, T b)
{ {
return TemporaryMatrix<T>(a) -= b; return TemporaryMatrix<T>(a) -= b;
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(const TemporaryMatrix<T> &a, T b) operator-(const TemporaryMatrix<T> &a, T b)
{ {
return const_cast<TemporaryMatrix<T> &>(a) -= b; return const_cast<TemporaryMatrix<T> &>(a) -= b;
} }
/** subtract every element of the matrix \a b from scalar \a a. /** subtract every element of the matrix \a b from scalar \a a.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator-(T a, const MultiArrayView<2, T, C> &b) operator-(T a, const MultiArrayView<2, T, C> &b)
{ {
return TemporaryMatrix<T>(b.shape(), a) -= b; return TemporaryMatrix<T>(b.shape(), a) -= b;
} }
/** calculate the inner product of two matrices representing vectors. /** calculate the inner product of two matrices representing vectors.
Typically, matrix \a x has a single row, and matrix \a y has Typically, matrix \a x has a single row, and matrix \a y has
a single column, and the other dimensions match. In addition, this a single column, and the other dimensions match. In addition, this
function handles the cases when either or both of the two inputs ar e function handles the cases when either or both of the two inputs ar e
transposed (e.g. it can compute the dot product of two column vecto rs). transposed (e.g. it can compute the dot product of two column vecto rs).
A <tt>PreconditionViolation</tt> exception is thrown when A <tt>PreconditionViolation</tt> exception is thrown when
the shape conditions are violated. the shape conditions are violated.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
typename NormTraits<T>::SquaredNormType typename NormTraits<T>::SquaredNormType
dot(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2> &y) dot(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2> &y)
{ {
typename NormTraits<T>::SquaredNormType ret = typename NormTraits<T>::SquaredNormType ret =
NumericTraits<typename NormTraits<T>::SquaredNormType>::zero(); NumericTraits<typename NormTraits<T>::SquaredNormType>::zero();
if(y.shape(1) == 1) if(y.shape(1) == 1)
{ {
skipping to change at line 1369 skipping to change at line 1369
vigra_precondition(false, "dot(): wrong matrix shapes."); vigra_precondition(false, "dot(): wrong matrix shapes.");
} }
else else
vigra_precondition(false, "dot(): wrong matrix shapes."); vigra_precondition(false, "dot(): wrong matrix shapes.");
return ret; return ret;
} }
/** calculate the inner product of two vectors. The vector /** calculate the inner product of two vectors. The vector
lengths must match. lengths must match.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
typename NormTraits<T>::SquaredNormType typename NormTraits<T>::SquaredNormType
dot(const MultiArrayView<1, T, C1> &x, const MultiArrayView<1, T, C2> &y) dot(const MultiArrayView<1, T, C1> &x, const MultiArrayView<1, T, C2> &y)
{ {
const MultiArrayIndex n = x.elementCount(); const MultiArrayIndex n = x.elementCount();
vigra_precondition(n == y.elementCount(), vigra_precondition(n == y.elementCount(),
"dot(): shape mismatch."); "dot(): shape mismatch.");
typename NormTraits<T>::SquaredNormType ret = typename NormTraits<T>::SquaredNormType ret =
NumericTraits<typename NormTraits<T>::SquaredNormType>::zer o(); NumericTraits<typename NormTraits<T>::SquaredNormType>::zer o();
for(MultiArrayIndex i = 0; i < n; ++i) for(MultiArrayIndex i = 0; i < n; ++i)
ret += x(i) * y(i); ret += x(i) * y(i);
return ret; return ret;
} }
/** calculate the cross product of two vectors of length 3. /** calculate the cross product of two vectors of length 3.
The result is written into \a r. The result is written into \a r.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void cross(const MultiArrayView<1, T, C1> &x, const MultiArrayView<1, T, C2 > &y, void cross(const MultiArrayView<1, T, C1> &x, const MultiArrayView<1, T, C2 > &y,
MultiArrayView<1, T, C3> &r) MultiArrayView<1, T, C3> &r)
{ {
vigra_precondition(3 == x.elementCount() && 3 == y.elementCount() && 3 == r.elementCount(), vigra_precondition(3 == x.elementCount() && 3 == y.elementCount() && 3 == r.elementCount(),
"cross(): vectors must have length 3."); "cross(): vectors must have length 3.");
r(0) = x(1)*y(2) - x(2)*y(1); r(0) = x(1)*y(2) - x(2)*y(1);
r(1) = x(2)*y(0) - x(0)*y(2); r(1) = x(2)*y(0) - x(0)*y(2);
r(2) = x(0)*y(1) - x(1)*y(0); r(2) = x(0)*y(1) - x(1)*y(0);
} }
/** calculate the cross product of two matrices representing vectors. /** calculate the cross product of two matrices representing vectors.
That is, \a x, \a y, and \a r must have a single column of length 3 . The result That is, \a x, \a y, and \a r must have a single column of length 3 . The result
is written into \a r. is written into \a r.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void cross(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2 > &y, void cross(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2 > &y,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
vigra_precondition(3 == rowCount(x) && 3 == rowCount(y) && 3 == rowCoun t(r) , vigra_precondition(3 == rowCount(x) && 3 == rowCount(y) && 3 == rowCoun t(r) ,
"cross(): vectors must have length 3."); "cross(): vectors must have length 3.");
r(0,0) = x(1,0)*y(2,0) - x(2,0)*y(1,0); r(0,0) = x(1,0)*y(2,0) - x(2,0)*y(1,0);
r(1,0) = x(2,0)*y(0,0) - x(0,0)*y(2,0); r(1,0) = x(2,0)*y(0,0) - x(0,0)*y(2,0);
r(2,0) = x(0,0)*y(1,0) - x(1,0)*y(0,0); r(2,0) = x(0,0)*y(1,0) - x(1,0)*y(0,0);
} }
/** calculate the cross product of two matrices representing vectors. /** calculate the cross product of two matrices representing vectors.
That is, \a x, and \a y must have a single column of length 3. The result That is, \a x, and \a y must have a single column of length 3. The result
is returned as a temporary matrix. is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
TemporaryMatrix<T> TemporaryMatrix<T>
cross(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2> &y) cross(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2> &y)
{ {
TemporaryMatrix<T> ret(3, 1); TemporaryMatrix<T> ret(3, 1);
cross(x, y, ret); cross(x, y, ret);
return ret; return ret;
} }
/** calculate the outer product of two matrices representing vectors. /** calculate the outer product of two matrices representing vectors.
That is, matrix \a x must have a single column, and matrix \a y mus t That is, matrix \a x must have a single column, and matrix \a y mus t
have a single row, and the other dimensions must match. The result have a single row, and the other dimensions must match. The result
is written into \a r. is written into \a r.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void outer(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2 > &y, void outer(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2 > &y,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
const MultiArrayIndex rows = rowCount(r); const MultiArrayIndex rows = rowCount(r);
const MultiArrayIndex cols = columnCount(r); const MultiArrayIndex cols = columnCount(r);
vigra_precondition(rows == rowCount(x) && cols == columnCount(y) && vigra_precondition(rows == rowCount(x) && cols == columnCount(y) &&
1 == columnCount(x) && 1 == rowCount(y), 1 == columnCount(x) && 1 == rowCount(y),
skipping to change at line 1468 skipping to change at line 1468
for(MultiArrayIndex i = 0; i < cols; ++i) for(MultiArrayIndex i = 0; i < cols; ++i)
for(MultiArrayIndex j = 0; j < rows; ++j) for(MultiArrayIndex j = 0; j < rows; ++j)
r(j, i) = x(j, 0) * y(0, i); r(j, i) = x(j, 0) * y(0, i);
} }
/** calculate the outer product of two matrices representing vectors. /** calculate the outer product of two matrices representing vectors.
That is, matrix \a x must have a single column, and matrix \a y mus t That is, matrix \a x must have a single column, and matrix \a y mus t
have a single row, and the other dimensions must match. The result have a single row, and the other dimensions must match. The result
is returned as a temporary matrix. is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
TemporaryMatrix<T> TemporaryMatrix<T>
outer(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2> &y) outer(const MultiArrayView<2, T, C1> &x, const MultiArrayView<2, T, C2> &y)
{ {
const MultiArrayIndex rows = rowCount(x); const MultiArrayIndex rows = rowCount(x);
const MultiArrayIndex cols = columnCount(y); const MultiArrayIndex cols = columnCount(y);
vigra_precondition(1 == columnCount(x) && 1 == rowCount(y), vigra_precondition(1 == columnCount(x) && 1 == rowCount(y),
"outer(): shape mismatch."); "outer(): shape mismatch.");
TemporaryMatrix<T> ret(rows, cols); TemporaryMatrix<T> ret(rows, cols);
outer(x, y, ret); outer(x, y, ret);
return ret; return ret;
} }
/** calculate the outer product of a matrix (representing a vector) wit h itself. /** calculate the outer product of a matrix (representing a vector) wit h itself.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
TemporaryMatrix<T> TemporaryMatrix<T>
outer(const MultiArrayView<2, T, C> &x) outer(const MultiArrayView<2, T, C> &x)
{ {
const MultiArrayIndex rows = rowCount(x); const MultiArrayIndex rows = rowCount(x);
const MultiArrayIndex cols = columnCount(x); const MultiArrayIndex cols = columnCount(x);
vigra_precondition(rows == 1 || cols == 1, vigra_precondition(rows == 1 || cols == 1,
"outer(): matrix does not represent a vector."); "outer(): matrix does not represent a vector.");
skipping to change at line 1518 skipping to change at line 1518
} }
else else
{ {
for(MultiArrayIndex i = 0; i < size; ++i) for(MultiArrayIndex i = 0; i < size; ++i)
for(MultiArrayIndex j = 0; j < size; ++j) for(MultiArrayIndex j = 0; j < size; ++j)
ret(j, i) = x(j, 0) * x(i, 0); ret(j, i) = x(j, 0) * x(i, 0);
} }
return ret; return ret;
} }
/** calculate the outer product of a TinyVector with itself.
The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg
*/
template <class T, int N>
TemporaryMatrix<T>
outer(const TinyVector<T, N> &x)
{
TemporaryMatrix<T> ret(N, N);
for(MultiArrayIndex i = 0; i < N; ++i)
for(MultiArrayIndex j = 0; j < N; ++j)
ret(j, i) = x[j] * x[i];
return ret;
}
template <class T> template <class T>
class PointWise class PointWise
{ {
public: public:
T const & t; T const & t;
PointWise(T const & it) PointWise(T const & it)
: t(it) : t(it)
{} {}
}; };
template <class T> template <class T>
PointWise<T> pointWise(T const & t) PointWise<T> pointWise(T const & t)
{ {
return PointWise<T>(t); return PointWise<T>(t);
} }
/** multiply matrix \a a with scalar \a b. /** multiply matrix \a a with scalar \a b.
The result is written into \a r. \a a and \a r must have the same s hape. The result is written into \a r. \a a and \a r must have the same s hape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
void smul(const MultiArrayView<2, T, C1> &a, T b, MultiArrayView<2, T, C2> &r) void smul(const MultiArrayView<2, T, C1> &a, T b, MultiArrayView<2, T, C2> &r)
{ {
const MultiArrayIndex rows = rowCount(a); const MultiArrayIndex rows = rowCount(a);
const MultiArrayIndex cols = columnCount(a); const MultiArrayIndex cols = columnCount(a);
vigra_precondition(rows == rowCount(r) && cols == columnCount(r), vigra_precondition(rows == rowCount(r) && cols == columnCount(r),
"smul(): Matrix sizes must agree."); "smul(): Matrix sizes must agree.");
for(MultiArrayIndex i = 0; i < cols; ++i) for(MultiArrayIndex i = 0; i < cols; ++i)
for(MultiArrayIndex j = 0; j < rows; ++j) for(MultiArrayIndex j = 0; j < rows; ++j)
r(j, i) = a(j, i) * b; r(j, i) = a(j, i) * b;
} }
/** multiply scalar \a a with matrix \a b. /** multiply scalar \a a with matrix \a b.
The result is written into \a r. \a b and \a r must have the same s hape. The result is written into \a r. \a b and \a r must have the same s hape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C2, class C3> template <class T, class C2, class C3>
void smul(T a, const MultiArrayView<2, T, C2> &b, MultiArrayView<2, T, C3> &r) void smul(T a, const MultiArrayView<2, T, C2> &b, MultiArrayView<2, T, C3> &r)
{ {
smul(b, a, r); smul(b, a, r);
} }
/** perform matrix multiplication of matrices \a a and \a b. /** perform matrix multiplication of matrices \a a and \a b.
The result is written into \a r. The three matrices must have match ing shapes. The result is written into \a r. The three matrices must have match ing shapes.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void mmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b, void mmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
const MultiArrayIndex rrows = rowCount(r); const MultiArrayIndex rrows = rowCount(r);
const MultiArrayIndex rcols = columnCount(r); const MultiArrayIndex rcols = columnCount(r);
const MultiArrayIndex acols = columnCount(a); const MultiArrayIndex acols = columnCount(a);
vigra_precondition(rrows == rowCount(a) && rcols == columnCount(b) && a cols == rowCount(b), vigra_precondition(rrows == rowCount(a) && rcols == columnCount(b) && a cols == rowCount(b),
skipping to change at line 1600 skipping to change at line 1619
for(MultiArrayIndex k = 1; k < acols; ++k) for(MultiArrayIndex k = 1; k < acols; ++k)
for(MultiArrayIndex j = 0; j < rrows; ++j) for(MultiArrayIndex j = 0; j < rrows; ++j)
r(j, i) += a(j, k) * b(k, i); r(j, i) += a(j, k) * b(k, i);
} }
} }
/** perform matrix multiplication of matrices \a a and \a b. /** perform matrix multiplication of matrices \a a and \a b.
\a a and \a b must have matching shapes. \a a and \a b must have matching shapes.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
mmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) mmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
TemporaryMatrix<T> ret(rowCount(a), columnCount(b)); TemporaryMatrix<T> ret(rowCount(a), columnCount(b));
mmul(a, b, ret); mmul(a, b, ret);
return ret; return ret;
} }
/** multiply two matrices \a a and \a b pointwise. /** multiply two matrices \a a and \a b pointwise.
The result is written into \a r. All three matrices must have the s ame shape. The result is written into \a r. All three matrices must have the s ame shape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void pmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b, void pmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
const MultiArrayIndex rrows = rowCount(r); const MultiArrayIndex rrows = rowCount(r);
const MultiArrayIndex rcols = columnCount(r); const MultiArrayIndex rcols = columnCount(r);
vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) && vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) &&
rrows == rowCount(b) && rcols == columnCount(b), rrows == rowCount(b) && rcols == columnCount(b),
skipping to change at line 1641 skipping to change at line 1660
for(MultiArrayIndex j = 0; j < rrows; ++j) { for(MultiArrayIndex j = 0; j < rrows; ++j) {
r(j, i) = a(j, i) * b(j, i); r(j, i) = a(j, i) * b(j, i);
} }
} }
} }
/** multiply matrices \a a and \a b pointwise. /** multiply matrices \a a and \a b pointwise.
\a a and \a b must have matching shapes. \a a and \a b must have matching shapes.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
pmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) pmul(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
TemporaryMatrix<T> ret(a.shape()); TemporaryMatrix<T> ret(a.shape());
pmul(a, b, ret); pmul(a, b, ret);
return ret; return ret;
} }
skipping to change at line 1668 skipping to change at line 1687
Usage: Usage:
\code \code
Matrix<double> a(m,n), b(m,n); Matrix<double> a(m,n), b(m,n);
Matrix<double> c = a * pointWise(b); Matrix<double> c = a * pointWise(b);
// is equivalent to // is equivalent to
// Matrix<double> c = pmul(a, b); // Matrix<double> c = pmul(a, b);
\endcode \endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C, class U> template <class T, class C, class U>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator*(const MultiArrayView<2, T, C> &a, PointWise<U> b) operator*(const MultiArrayView<2, T, C> &a, PointWise<U> b)
{ {
return pmul(a, b.t); return pmul(a, b.t);
} }
/** multiply matrix \a a with scalar \a b. /** multiply matrix \a a with scalar \a b.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator*(const MultiArrayView<2, T, C> &a, T b) operator*(const MultiArrayView<2, T, C> &a, T b)
{ {
return TemporaryMatrix<T>(a) *= b; return TemporaryMatrix<T>(a) *= b;
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator*(const TemporaryMatrix<T> &a, T b) operator*(const TemporaryMatrix<T> &a, T b)
{ {
return const_cast<TemporaryMatrix<T> &>(a) *= b; return const_cast<TemporaryMatrix<T> &>(a) *= b;
} }
/** multiply scalar \a a with matrix \a b. /** multiply scalar \a a with matrix \a b.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator*(T a, const MultiArrayView<2, T, C> &b) operator*(T a, const MultiArrayView<2, T, C> &b)
{ {
return TemporaryMatrix<T>(b) *= a; return TemporaryMatrix<T>(b) *= a;
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator*(T a, const TemporaryMatrix<T> &b) operator*(T a, const TemporaryMatrix<T> &b)
{ {
return const_cast<TemporaryMatrix<T> &>(b) *= a; return const_cast<TemporaryMatrix<T> &>(b) *= a;
} }
/** multiply matrix \a a with TinyVector \a b. /** multiply matrix \a a with TinyVector \a b.
\a a must be of size <tt>N x N</tt>. Vector \a b and the result \a a must be of size <tt>N x N</tt>. Vector \a b and the result
vector are interpreted as column vectors. vector are interpreted as column vectors.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class A, int N, class DATA, class DERIVED> template <class T, class A, int N, class DATA, class DERIVED>
TinyVector<T, N> TinyVector<T, N>
operator*(const Matrix<T, A> &a, const TinyVectorBase<T, N, DATA, DERIVED> &b) operator*(const Matrix<T, A> &a, const TinyVectorBase<T, N, DATA, DERIVED> &b)
{ {
vigra_precondition(N == rowCount(a) && N == columnCount(a), vigra_precondition(N == rowCount(a) && N == columnCount(a),
"operator*(Matrix, TinyVector): Shape mismatch."); "operator*(Matrix, TinyVector): Shape mismatch.");
TinyVector<T, N> res = TinyVectorView<T, N>(&a(0,0)) * b[0]; TinyVector<T, N> res = TinyVectorView<T, N>(&a(0,0)) * b[0];
for(MultiArrayIndex i = 1; i < N; ++i) for(MultiArrayIndex i = 1; i < N; ++i)
res += TinyVectorView<T, N>(&a(0,i)) * b[i]; res += TinyVectorView<T, N>(&a(0,i)) * b[i];
return res; return res;
} }
/** multiply TinyVector \a a with matrix \a b. /** multiply TinyVector \a a with matrix \a b.
\a b must be of size <tt>N x N</tt>. Vector \a a and the result \a b must be of size <tt>N x N</tt>. Vector \a a and the result
vector are interpreted as row vectors. vector are interpreted as row vectors.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, int N, class DATA, class DERIVED, class A> template <class T, int N, class DATA, class DERIVED, class A>
TinyVector<T, N> TinyVector<T, N>
operator*(const TinyVectorBase<T, N, DATA, DERIVED> &a, const Matrix<T, A> &b) operator*(const TinyVectorBase<T, N, DATA, DERIVED> &a, const Matrix<T, A> &b)
{ {
vigra_precondition(N == rowCount(b) && N == columnCount(b), vigra_precondition(N == rowCount(b) && N == columnCount(b),
"operator*(TinyVector, Matrix): Shape mismatch."); "operator*(TinyVector, Matrix): Shape mismatch.");
TinyVector<T, N> res; TinyVector<T, N> res;
for(MultiArrayIndex i = 0; i < N; ++i) for(MultiArrayIndex i = 0; i < N; ++i)
res[i] = dot(a, TinyVectorView<T, N>(&b(0,i))); res[i] = dot(a, TinyVectorView<T, N>(&b(0,i)));
return res; return res;
} }
/** perform matrix multiplication of matrices \a a and \a b. /** perform matrix multiplication of matrices \a a and \a b.
\a a and \a b must have matching shapes. \a a and \a b must have matching shapes.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator*(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) operator*(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
TemporaryMatrix<T> ret(rowCount(a), columnCount(b)); TemporaryMatrix<T> ret(rowCount(a), columnCount(b));
mmul(a, b, ret); mmul(a, b, ret);
return ret; return ret;
} }
/** divide matrix \a a by scalar \a b. /** divide matrix \a a by scalar \a b.
The result is written into \a r. \a a and \a r must have the same s hape. The result is written into \a r. \a a and \a r must have the same s hape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
void sdiv(const MultiArrayView<2, T, C1> &a, T b, MultiArrayView<2, T, C2> &r) void sdiv(const MultiArrayView<2, T, C1> &a, T b, MultiArrayView<2, T, C2> &r)
{ {
const MultiArrayIndex rows = rowCount(a); const MultiArrayIndex rows = rowCount(a);
const MultiArrayIndex cols = columnCount(a); const MultiArrayIndex cols = columnCount(a);
vigra_precondition(rows == rowCount(r) && cols == columnCount(r), vigra_precondition(rows == rowCount(r) && cols == columnCount(r),
"sdiv(): Matrix sizes must agree."); "sdiv(): Matrix sizes must agree.");
for(MultiArrayIndex i = 0; i < cols; ++i) for(MultiArrayIndex i = 0; i < cols; ++i)
for(MultiArrayIndex j = 0; j < rows; ++j) for(MultiArrayIndex j = 0; j < rows; ++j)
r(j, i) = a(j, i) / b; r(j, i) = a(j, i) / b;
} }
/** divide two matrices \a a and \a b pointwise. /** divide two matrices \a a and \a b pointwise.
The result is written into \a r. All three matrices must have the s ame shape. The result is written into \a r. All three matrices must have the s ame shape.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
void pdiv(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b, void pdiv(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b,
MultiArrayView<2, T, C3> &r) MultiArrayView<2, T, C3> &r)
{ {
const MultiArrayIndex rrows = rowCount(r); const MultiArrayIndex rrows = rowCount(r);
const MultiArrayIndex rcols = columnCount(r); const MultiArrayIndex rcols = columnCount(r);
vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) && vigra_precondition(rrows == rowCount(a) && rcols == columnCount(a) &&
rrows == rowCount(b) && rcols == columnCount(b), rrows == rowCount(b) && rcols == columnCount(b),
skipping to change at line 1828 skipping to change at line 1847
for(MultiArrayIndex j = 0; j < rrows; ++j) { for(MultiArrayIndex j = 0; j < rrows; ++j) {
r(j, i) = a(j, i) / b(j, i); r(j, i) = a(j, i) / b(j, i);
} }
} }
} }
/** divide matrices \a a and \a b pointwise. /** divide matrices \a a and \a b pointwise.
\a a and \a b must have matching shapes. \a a and \a b must have matching shapes.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
pdiv(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b) pdiv(const MultiArrayView<2, T, C1> &a, const MultiArrayView<2, T, C2> &b)
{ {
TemporaryMatrix<T> ret(a.shape()); TemporaryMatrix<T> ret(a.shape());
pdiv(a, b, ret); pdiv(a, b, ret);
return ret; return ret;
} }
skipping to change at line 1855 skipping to change at line 1874
Usage: Usage:
\code \code
Matrix<double> a(m,n), b(m,n); Matrix<double> a(m,n), b(m,n);
Matrix<double> c = a / pointWise(b); Matrix<double> c = a / pointWise(b);
// is equivalent to // is equivalent to
// Matrix<double> c = pdiv(a, b); // Matrix<double> c = pdiv(a, b);
\endcode \endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C, class U> template <class T, class C, class U>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator/(const MultiArrayView<2, T, C> &a, PointWise<U> b) operator/(const MultiArrayView<2, T, C> &a, PointWise<U> b)
{ {
return pdiv(a, b.t); return pdiv(a, b.t);
} }
/** divide matrix \a a by scalar \a b. /** divide matrix \a a by scalar \a b.
The result is returned as a temporary matrix. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator/(const MultiArrayView<2, T, C> &a, T b) operator/(const MultiArrayView<2, T, C> &a, T b)
{ {
return TemporaryMatrix<T>(a) /= b; return TemporaryMatrix<T>(a) /= b;
} }
template <class T> template <class T>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator/(const TemporaryMatrix<T> &a, T b) operator/(const TemporaryMatrix<T> &a, T b)
{ {
return const_cast<TemporaryMatrix<T> &>(a) /= b; return const_cast<TemporaryMatrix<T> &>(a) /= b;
} }
/** Create a matrix whose elements are the quotients between scalar \a a and /** Create a matrix whose elements are the quotients between scalar \a a and
matrix \a b. The result is returned as a temporary matrix. matrix \a b. The result is returned as a temporary matrix.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: vigra::linalg Namespace: vigra::linalg
*/ */
template <class T, class C> template <class T, class C>
inline TemporaryMatrix<T> inline TemporaryMatrix<T>
operator/(T a, const MultiArrayView<2, T, C> &b) operator/(T a, const MultiArrayView<2, T, C> &b)
{ {
return TemporaryMatrix<T>(b.shape(), a) / pointWise(b); return TemporaryMatrix<T>(b.shape(), a) / pointWise(b);
} }
using vigra::argMin; using vigra::argMin;
using vigra::argMinIf; using vigra::argMinIf;
using vigra::argMax; using vigra::argMax;
using vigra::argMaxIf; using vigra::argMaxIf;
/*! Find the index of the minimum element in a matrix. /** \brief Find the index of the minimum element in a matrix.
The function returns the index in column-major scan-order sense, The function returns the index in column-major scan-order sense,
i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>. i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>.
If the matrix is actually a vector, this is just the row or columns index. If the matrix is actually a vector, this is just the row or columns index.
In case of a truly 2-dimensional matrix, the index can be converted to an In case of a truly 2-dimensional matrix, the index can be converted to an
index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt> index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt>
<b>Required Interface:</b> <b>Required Interface:</b>
\code \code
skipping to change at line 1939 skipping to change at line 1958
{ {
if(a[k] < vopt) if(a[k] < vopt)
{ {
vopt = a[k]; vopt = a[k];
best = k; best = k;
} }
} }
return best; return best;
} }
/*! Find the index of the maximum element in a matrix. /** \brief Find the index of the maximum element in a matrix.
The function returns the index in column-major scan-order sense, The function returns the index in column-major scan-order sense,
i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>. i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>.
If the matrix is actually a vector, this is just the row or columns index. If the matrix is actually a vector, this is just the row or columns index.
In case of a truly 2-dimensional matrix, the index can be converted to an In case of a truly 2-dimensional matrix, the index can be converted to an
index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt> index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt>
<b>Required Interface:</b> <b>Required Interface:</b>
\code \code
skipping to change at line 1972 skipping to change at line 1991
{ {
if(vopt < a[k]) if(vopt < a[k])
{ {
vopt = a[k]; vopt = a[k];
best = k; best = k;
} }
} }
return best; return best;
} }
/*! Find the index of the minimum element in a matrix subject to a cond ition. /** \brief Find the index of the minimum element in a matrix subject to a condition.
The function returns <tt>-1</tt> if no element conforms to \a condi tion. The function returns <tt>-1</tt> if no element conforms to \a condi tion.
Otherwise, the index of the maximum element is returned in column-m ajor scan-order sense, Otherwise, the index of the maximum element is returned in column-m ajor scan-order sense,
i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>. i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>.
If the matrix is actually a vector, this is just the row or columns index. If the matrix is actually a vector, this is just the row or columns index.
In case of a truly 2-dimensional matrix, the index can be converted to an In case of a truly 2-dimensional matrix, the index can be converted to an
index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt> index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt>
<b>Required Interface:</b> <b>Required Interface:</b>
skipping to change at line 2007 skipping to change at line 2026
{ {
if(condition(a[k]) && a[k] < vopt) if(condition(a[k]) && a[k] < vopt)
{ {
vopt = a[k]; vopt = a[k];
best = k; best = k;
} }
} }
return best; return best;
} }
/*! Find the index of the maximum element in a matrix subject to a cond ition. /** \brief Find the index of the maximum element in a matrix subject to a condition.
The function returns <tt>-1</tt> if no element conforms to \a condi tion. The function returns <tt>-1</tt> if no element conforms to \a condi tion.
Otherwise, the index of the maximum element is returned in column-m ajor scan-order sense, Otherwise, the index of the maximum element is returned in column-m ajor scan-order sense,
i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>. i.e. according to the order used by <tt>MultiArrayView::operator[]< /tt>.
If the matrix is actually a vector, this is just the row or columns index. If the matrix is actually a vector, this is just the row or columns index.
In case of a truly 2-dimensional matrix, the index can be converted to an In case of a truly 2-dimensional matrix, the index can be converted to an
index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt> index pair by calling <tt>MultiArrayView::scanOrderIndexToCoordinat e()</tt>
<b>Required Interface:</b> <b>Required Interface:</b>
skipping to change at line 2100 skipping to change at line 2119
} }
template <class C> template <class C>
linalg::TemporaryMatrix<int> pow(MultiArrayView<2, int, C> const & v, int e xponent) linalg::TemporaryMatrix<int> pow(MultiArrayView<2, int, C> const & v, int e xponent)
{ {
linalg::TemporaryMatrix<int> t(v.shape()); linalg::TemporaryMatrix<int> t(v.shape());
MultiArrayIndex m = rowCount(v), n = columnCount(v); MultiArrayIndex m = rowCount(v), n = columnCount(v);
for(MultiArrayIndex i = 0; i < n; ++i) for(MultiArrayIndex i = 0; i < n; ++i)
for(MultiArrayIndex j = 0; j < m; ++j) for(MultiArrayIndex j = 0; j < m; ++j)
t(j, i) = (int)vigra::pow((double)v(j, i), exponent); t(j, i) = static_cast<int>(vigra::pow(static_cast<double>(v(j, i)), exponent));
return t; return t;
} }
inline inline
linalg::TemporaryMatrix<int> pow(linalg::TemporaryMatrix<int> const & v, in t exponent) linalg::TemporaryMatrix<int> pow(linalg::TemporaryMatrix<int> const & v, in t exponent)
{ {
linalg::TemporaryMatrix<int> & t = const_cast<linalg::TemporaryMatrix<i nt> &>(v); linalg::TemporaryMatrix<int> & t = const_cast<linalg::TemporaryMatrix<i nt> &>(v);
MultiArrayIndex m = rowCount(t), n = columnCount(t); MultiArrayIndex m = rowCount(t), n = columnCount(t);
for(MultiArrayIndex i = 0; i < n; ++i) for(MultiArrayIndex i = 0; i < n; ++i)
for(MultiArrayIndex j = 0; j < m; ++j) for(MultiArrayIndex j = 0; j < m; ++j)
t(j, i) = (int)vigra::pow((double)t(j, i), exponent); t(j, i) = static_cast<int>(vigra::pow(static_cast<double>(t(j, i)), exponent));
return t; return t;
} }
/** Matrix point-wise sqrt. */ /** Matrix point-wise sqrt. */
template <class T, class C> template <class T, class C>
linalg::TemporaryMatrix<T> sqrt(MultiArrayView<2, T, C> const & v); linalg::TemporaryMatrix<T> sqrt(MultiArrayView<2, T, C> const & v);
/** Matrix point-wise exp. */ /** Matrix point-wise exp. */
template <class T, class C> template <class T, class C>
linalg::TemporaryMatrix<T> exp(MultiArrayView<2, T, C> const & v); linalg::TemporaryMatrix<T> exp(MultiArrayView<2, T, C> const & v);
/** Matrix point-wise log. */ /** Matrix point-wise log. */
skipping to change at line 2289 skipping to change at line 2308
} // namespace vigra } // namespace vigra
namespace std { namespace std {
/** \addtogroup LinearAlgebraFunctions /** \addtogroup LinearAlgebraFunctions
*/ */
//@{ //@{
/** print a matrix \a m to the stream \a s. /** print a matrix \a m to the stream \a s.
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespace: std Namespace: std
*/ */
template <class T, class C> template <class T, class C>
ostream & ostream &
operator<<(ostream & s, const vigra::MultiArrayView<2, T, C> &m) operator<<(ostream & s, const vigra::MultiArrayView<2, T, C> &m)
{ {
const vigra::MultiArrayIndex rows = vigra::linalg::rowCount(m); const vigra::MultiArrayIndex rows = vigra::linalg::rowCount(m);
const vigra::MultiArrayIndex cols = vigra::linalg::columnCount(m); const vigra::MultiArrayIndex cols = vigra::linalg::columnCount(m);
ios::fmtflags flags = s.setf(ios::right | ios::fixed, ios::adjustfield | ios::floatfield); ios::fmtflags flags = s.setf(ios::right | ios::fixed, ios::adjustfield | ios::floatfield);
for(vigra::MultiArrayIndex j = 0; j < rows; ++j) for(vigra::MultiArrayIndex j = 0; j < rows; ++j)
skipping to change at line 2365 skipping to change at line 2384
vigra_precondition(1 == rowCount(mean) && n == columnCount(mean) && vigra_precondition(1 == rowCount(mean) && n == columnCount(mean) &&
1 == rowCount(sumOfSquaredDifferences) && n == colum nCount(sumOfSquaredDifferences), 1 == rowCount(sumOfSquaredDifferences) && n == colum nCount(sumOfSquaredDifferences),
"columnStatistics(): Shape mismatch between input an d output."); "columnStatistics(): Shape mismatch between input an d output.");
// two-pass algorithm for incremental variance computation // two-pass algorithm for incremental variance computation
mean.init(NumericTraits<T2>::zero()); mean.init(NumericTraits<T2>::zero());
for(MultiArrayIndex k=0; k<m; ++k) for(MultiArrayIndex k=0; k<m; ++k)
{ {
mean += rowVector(A, k); mean += rowVector(A, k);
} }
mean /= (double)m; mean /= static_cast<double>(m);
sumOfSquaredDifferences.init(NumericTraits<T3>::zero()); sumOfSquaredDifferences.init(NumericTraits<T3>::zero());
for(MultiArrayIndex k=0; k<m; ++k) for(MultiArrayIndex k=0; k<m; ++k)
{ {
sumOfSquaredDifferences += sq(rowVector(A, k) - mean); sumOfSquaredDifferences += sq(rowVector(A, k) - mean);
} }
} }
} // namespace detail } // namespace detail
skipping to change at line 2422 skipping to change at line 2441
MultiArrayView<2, T2, C2> & mean, MultiArrayView<2, T2, C2> & mean,
MultiArrayView<2, T3, C3> & stdDev, MultiArrayView<2, T3, C3> & stdDev,
MultiArrayView<2, T4, C4> & norm); MultiArrayView<2, T4, C4> & norm);
} } } }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
\code \code
Matrix A(rows, columns); Matrix A(rows, columns);
.. // fill A .. // fill A
Matrix columnMean(1, columns), columnStdDev(1, columns), columnNorm(1, columns); Matrix columnMean(1, columns), columnStdDev(1, columns), columnNorm(1, columns);
columnStatistics(A, columnMean, columnStdDev, columnNorm); columnStatistics(A, columnMean, columnStdDev, columnNorm);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void columnStatistics) doxygen_overloaded_function(template <...> void columnStatistics)
template <class T1, class C1, class T2, class C2> template <class T1, class C1, class T2, class C2>
void void
columnStatistics(MultiArrayView<2, T1, C1> const & A, columnStatistics(MultiArrayView<2, T1, C1> const & A,
MultiArrayView<2, T2, C2> & mean) MultiArrayView<2, T2, C2> & mean)
{ {
MultiArrayIndex m = rowCount(A); MultiArrayIndex m = rowCount(A);
MultiArrayIndex n = columnCount(A); MultiArrayIndex n = columnCount(A);
vigra_precondition(1 == rowCount(mean) && n == columnCount(mean), vigra_precondition(1 == rowCount(mean) && n == columnCount(mean),
skipping to change at line 2525 skipping to change at line 2544
MultiArrayView<2, T2, C2> & mean, MultiArrayView<2, T2, C2> & mean,
MultiArrayView<2, T3, C3> & stdDev, MultiArrayView<2, T3, C3> & stdDev,
MultiArrayView<2, T4, C4> & norm); MultiArrayView<2, T4, C4> & norm);
} } } }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
\code \code
Matrix A(rows, columns); Matrix A(rows, columns);
.. // fill A .. // fill A
Matrix rowMean(rows, 1), rowStdDev(rows, 1), rowNorm(rows, 1); Matrix rowMean(rows, 1), rowStdDev(rows, 1), rowNorm(rows, 1);
rowStatistics(a, rowMean, rowStdDev, rowNorm); rowStatistics(a, rowMean, rowStdDev, rowNorm);
\endcode \endcode
*/ */
skipping to change at line 2594 skipping to change at line 2613
vigra_precondition(std::min(rowCount(features), columnCount(features)) == 1, vigra_precondition(std::min(rowCount(features), columnCount(features)) == 1,
"updateCovarianceMatrix(): Features must be a row or column vecto r."); "updateCovarianceMatrix(): Features must be a row or column vecto r.");
vigra_precondition(mean.shape() == features.shape(), vigra_precondition(mean.shape() == features.shape(),
"updateCovarianceMatrix(): Shape mismatch between feature vector and mean vector."); "updateCovarianceMatrix(): Shape mismatch between feature vector and mean vector.");
vigra_precondition(n == rowCount(covariance) && n == columnCount(covari ance), vigra_precondition(n == rowCount(covariance) && n == columnCount(covari ance),
"updateCovarianceMatrix(): Shape mismatch between feature vector and covariance matrix."); "updateCovarianceMatrix(): Shape mismatch between feature vector and covariance matrix.");
// West's algorithm for incremental covariance matrix computation // West's algorithm for incremental covariance matrix computation
Matrix<T2> t = features - mean; Matrix<T2> t = features - mean;
++count; ++count;
double f = 1.0 / count, T2 f = T2(1.0) / count,
f1 = 1.0 - f; f1 = T2(1.0) - f;
mean += f*t; mean += f*t;
if(rowCount(features) == 1) // update column covariance from current ro w if(rowCount(features) == 1) // update column covariance from current ro w
{ {
for(MultiArrayIndex k=0; k<n; ++k) for(MultiArrayIndex k=0; k<n; ++k)
{ {
covariance(k, k) += f1*sq(t(0, k)); covariance(k, k) += f1*sq(t(0, k));
for(MultiArrayIndex l=k+1; l<n; ++l) for(MultiArrayIndex l=k+1; l<n; ++l)
{ {
covariance(k, l) += f1*t(0, k)*t(0, l); covariance(k, l) += f1*t(0, k)*t(0, l);
skipping to change at line 2626 skipping to change at line 2645
{ {
covariance(k, l) += f1*t(k, 0)*t(l, 0); covariance(k, l) += f1*t(k, 0)*t(l, 0);
covariance(l, k) = covariance(k, l); covariance(l, k) = covariance(k, l);
} }
} }
} }
} }
} // namespace detail } // namespace detail
/*! Compute the covariance matrix between the columns of a matrix \a fe atures. /** \brief Compute the covariance matrix between the columns of a matri x \a features.
The result matrix \a covariance must by a square matrix with as man y rows and The result matrix \a covariance must by a square matrix with as man y rows and
columns as the number of columns in matrix \a features. columns as the number of columns in matrix \a features.
<b>\#include</b> \<vigra/matrix.hxx\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T1, class C1, class T2, class C2> template <class T1, class C1, class T2, class C2>
void covarianceMatrixOfColumns(MultiArrayView<2, T1, C1> const & features, void covarianceMatrixOfColumns(MultiArrayView<2, T1, C1> const & features,
MultiArrayView<2, T2, C2> & covariance) MultiArrayView<2, T2, C2> & covariance)
skipping to change at line 2649 skipping to change at line 2668
vigra_precondition(n == rowCount(covariance) && n == columnCount(covari ance), vigra_precondition(n == rowCount(covariance) && n == columnCount(covari ance),
"covarianceMatrixOfColumns(): Shape mismatch between feature matr ix and covariance matrix."); "covarianceMatrixOfColumns(): Shape mismatch between feature matr ix and covariance matrix.");
MultiArrayIndex count = 0; MultiArrayIndex count = 0;
Matrix<T2> means(1, n); Matrix<T2> means(1, n);
covariance.init(NumericTraits<T2>::zero()); covariance.init(NumericTraits<T2>::zero());
for(MultiArrayIndex k=0; k<m; ++k) for(MultiArrayIndex k=0; k<m; ++k)
detail::updateCovarianceMatrix(rowVector(features, k), count, means , covariance); detail::updateCovarianceMatrix(rowVector(features, k), count, means , covariance);
covariance /= T2(m - 1); covariance /= T2(m - 1);
} }
/*! Compute the covariance matrix between the columns of a matrix \a fe atures. /** \brief Compute the covariance matrix between the columns of a matri x \a features.
The result is returned as a square temporary matrix with as many ro ws and The result is returned as a square temporary matrix with as many ro ws and
columns as the number of columns in matrix \a features. columns as the number of columns in matrix \a features.
<b>\#include</b> \<vigra/matrix.hxx\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class C> template <class T, class C>
TemporaryMatrix<T> TemporaryMatrix<T>
covarianceMatrixOfColumns(MultiArrayView<2, T, C> const & features) covarianceMatrixOfColumns(MultiArrayView<2, T, C> const & features)
{ {
TemporaryMatrix<T> res(columnCount(features), columnCount(features)); TemporaryMatrix<T> res(columnCount(features), columnCount(features));
covarianceMatrixOfColumns(features, res); covarianceMatrixOfColumns(features, res);
return res; return res;
} }
/*! Compute the covariance matrix between the rows of a matrix \a featu res. /** \brief Compute the covariance matrix between the rows of a matrix \ a features.
The result matrix \a covariance must by a square matrix with as man y rows and The result matrix \a covariance must by a square matrix with as man y rows and
columns as the number of rows in matrix \a features. columns as the number of rows in matrix \a features.
<b>\#include</b> \<vigra/matrix.hxx\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T1, class C1, class T2, class C2> template <class T1, class C1, class T2, class C2>
void covarianceMatrixOfRows(MultiArrayView<2, T1, C1> const & features, void covarianceMatrixOfRows(MultiArrayView<2, T1, C1> const & features,
MultiArrayView<2, T2, C2> & covariance) MultiArrayView<2, T2, C2> & covariance)
{ {
MultiArrayIndex m = rowCount(features), n = columnCount(features); MultiArrayIndex m = rowCount(features), n = columnCount(features);
vigra_precondition(m == rowCount(covariance) && m == columnCount(covari ance), vigra_precondition(m == rowCount(covariance) && m == columnCount(covari ance),
"covarianceMatrixOfRows(): Shape mismatch between feature matrix and covariance matrix."); "covarianceMatrixOfRows(): Shape mismatch between feature matrix and covariance matrix.");
MultiArrayIndex count = 0; MultiArrayIndex count = 0;
Matrix<T2> means(m, 1); Matrix<T2> means(m, 1);
covariance.init(NumericTraits<T2>::zero()); covariance.init(NumericTraits<T2>::zero());
for(MultiArrayIndex k=0; k<n; ++k) for(MultiArrayIndex k=0; k<n; ++k)
detail::updateCovarianceMatrix(columnVector(features, k), count, me ans, covariance); detail::updateCovarianceMatrix(columnVector(features, k), count, me ans, covariance);
covariance /= T2(m - 1); covariance /= T2(n - 1);
} }
/*! Compute the covariance matrix between the rows of a matrix \a featu res. /** \brief Compute the covariance matrix between the rows of a matrix \ a features.
The result is returned as a square temporary matrix with as many ro ws and The result is returned as a square temporary matrix with as many ro ws and
columns as the number of rows in matrix \a features. columns as the number of rows in matrix \a features.
<b>\#include</b> \<vigra/matrix.hxx\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class C> template <class T, class C>
TemporaryMatrix<T> TemporaryMatrix<T>
covarianceMatrixOfRows(MultiArrayView<2, T, C> const & features) covarianceMatrixOfRows(MultiArrayView<2, T, C> const & features)
skipping to change at line 2811 skipping to change at line 2830
} }
else else
{ {
scaling(0, k) = NumericTraits<T>::one(); scaling(0, k) = NumericTraits<T>::one();
} }
} }
} }
} // namespace detail } // namespace detail
/*! Standardize the columns of a matrix according to given <tt>DataPrep arationGoals</tt>. /** \brief Standardize the columns of a matrix according to given <tt>D ataPreparationGoals</tt>.
For every column of the matrix \a A, this function computes mean, For every column of the matrix \a A, this function computes mean,
standard deviation, and norm. It then applies a linear transformation t o the values of standard deviation, and norm. It then applies a linear transformation t o the values of
the column according to these statistics and the given <tt>DataPreparat ionGoals</tt>. the column according to these statistics and the given <tt>DataPreparat ionGoals</tt>.
The result is returned in matrix \a res which must have the same size a s \a A. The result is returned in matrix \a res which must have the same size a s \a A.
Optionally, the transformation applied can also be returned in the matr ices \a offset Optionally, the transformation applied can also be returned in the matr ices \a offset
and \a scaling (see below for an example how these matrices can be used to standardize and \a scaling (see below for an example how these matrices can be used to standardize
more data according to the same transformation). more data according to the same transformation).
The following <tt>DataPreparationGoals</tt> are supported: The following <tt>DataPreparationGoals</tt> are supported:
skipping to change at line 2868 skipping to change at line 2887
prepareColumns(MultiArrayView<2, T, C1> const & A, prepareColumns(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> & res, MultiArrayView<2, T, C2> & res,
DataPreparationGoals goals = ZeroMean | UnitVariance ); DataPreparationGoals goals = ZeroMean | UnitVariance );
} } } }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
\code \code
Matrix A(rows, columns); Matrix A(rows, columns);
.. // fill A .. // fill A
Matrix standardizedA(rows, columns), offset(1, columns), scaling(1, col umns); Matrix standardizedA(rows, columns), offset(1, columns), scaling(1, col umns);
prepareColumns(A, standardizedA, offset, scaling, ZeroMean | UnitNorm); prepareColumns(A, standardizedA, offset, scaling, ZeroMean | UnitNorm);
// use offset and scaling to prepare additional data according to the s ame transformation // use offset and scaling to prepare additional data according to the s ame transformation
Matrix newData(nrows, columns); Matrix newData(nrows, columns);
skipping to change at line 2904 skipping to change at line 2923
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline void inline void
prepareColumns(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> & res, prepareColumns(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> & res,
DataPreparationGoals goals = ZeroMean | UnitVariance) DataPreparationGoals goals = ZeroMean | UnitVariance)
{ {
Matrix<T> offset(1, columnCount(A)), scaling(1, columnCount(A)); Matrix<T> offset(1, columnCount(A)), scaling(1, columnCount(A));
detail::prepareDataImpl(A, res, offset, scaling, goals); detail::prepareDataImpl(A, res, offset, scaling, goals);
} }
/*! Standardize the rows of a matrix according to given <tt>DataPrepara tionGoals</tt>. /** \brief Standardize the rows of a matrix according to given <tt>Data PreparationGoals</tt>.
This algorithm works in the same way as \ref prepareColumns() (see ther e for detailed This algorithm works in the same way as \ref prepareColumns() (see ther e for detailed
documentation), but is applied to the rows of the matrix \a A instead. Accordingly, the documentation), but is applied to the rows of the matrix \a A instead. Accordingly, the
matrices holding the parameters of the linear transformation must be co lumn vectors matrices holding the parameters of the linear transformation must be co lumn vectors
with as many rows as \a A. with as many rows as \a A.
<b> Declarations:</b> <b> Declarations:</b>
Standardize the matrix and return the parameters of the linear transfor mation. Standardize the matrix and return the parameters of the linear transfor mation.
The matrices \a offset and \a scaling must be column vectors The matrices \a offset and \a scaling must be column vectors
skipping to change at line 2944 skipping to change at line 2963
prepareRows(MultiArrayView<2, T, C1> const & A, prepareRows(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> & res, MultiArrayView<2, T, C2> & res,
DataPreparationGoals goals = ZeroMean | UnitVariance); DataPreparationGoals goals = ZeroMean | UnitVariance);
} } } }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/matrix.hxx\> or<br> <b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
\code \code
Matrix A(rows, columns); Matrix A(rows, columns);
.. // fill A .. // fill A
Matrix standardizedA(rows, columns), offset(rows, 1), scaling(rows, 1); Matrix standardizedA(rows, columns), offset(rows, 1), scaling(rows, 1);
prepareRows(A, standardizedA, offset, scaling, ZeroMean | UnitNorm); prepareRows(A, standardizedA, offset, scaling, ZeroMean | UnitNorm);
// use offset and scaling to prepare additional data according to the s ame transformation // use offset and scaling to prepare additional data according to the s ame transformation
Matrix newData(rows, ncolumns); Matrix newData(rows, ncolumns);
 End of changes. 92 change blocks. 
148 lines changed or deleted 167 lines changed or added


 memory.hxx   memory.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MEMORY_HXX #ifndef VIGRA_MEMORY_HXX
#define VIGRA_MEMORY_HXX #define VIGRA_MEMORY_HXX
#include "config.hxx"
#ifdef VIGRA_SHARED_PTR_IN_TR1
# include <tr1/memory>
#else
# include <memory>
#endif
#include <cstring>
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
namespace vigra { namespace vigra {
enum SkipInitializationTag { SkipInitialization}; enum SkipInitializationTag { SkipInitialization};
template<class T> template<class T>
struct CanSkipInitialization struct CanSkipInitialization
{ {
typedef typename TypeTraits<T>::isBuiltinType type; typedef typename TypeTraits<T>::isBuiltinType type;
skipping to change at line 65 skipping to change at line 74
template <class Src, class Dest> template <class Src, class Dest>
Dest uninitializedCopy(Src s, Src end, Dest d) Dest uninitializedCopy(Src s, Src end, Dest d)
{ {
typedef typename std::iterator_traits<Dest>::value_type T; typedef typename std::iterator_traits<Dest>::value_type T;
for(; s != end; ++s, ++d) for(; s != end; ++s, ++d)
new(d) T(static_cast<T const &>(*s)); new(d) T(static_cast<T const &>(*s));
return d; return d;
} }
template <class T> template <class T>
inline void destroy_n(T * /* p */, std::ptrdiff_t /* n */, VigraTrueType /* isPOD */) struct PlacementNewAllocator
{ {
} T * allocate(std::size_t n)
{
return (T*)::operator new(n*sizeof(T));
}
void deallocate(T * p, std::size_t)
{
return ::operator delete(p);
}
void construct(T * p, T const & initial)
{
new(p) T(initial);
}
void destroy(T * p)
{
p->~T();
}
};
template <class T>
inline void
destroy_n(T * /* p */, std::size_t /* n */, VigraTrueType /* isPOD */)
{}
template <class T> template <class T>
inline void destroy_n(T * p, std::ptrdiff_t n, VigraFalseType /* isPOD */) inline void
destroy_n(T * p, std::size_t n, VigraFalseType /* isPOD */)
{ {
T * end = p + n; for(std::size_t i=0; i < n; ++i, ++p)
for(; p != end; ++p)
p->~T(); p->~T();
} }
template <class T> template <class T>
inline void destroy_n(T * p, std::ptrdiff_t n) inline void
destroy_n(T * p, std::size_t n)
{ {
destroy_n(p, n, typename TypeTraits<T>::isPOD()); destroy_n(p, n, typename TypeTraits<T>::isPOD());
} }
template <class T, class Alloc>
inline T *
alloc_initialize_n(std::size_t n, T const & initial, Alloc & alloc)
{
T * p = alloc.allocate(n);
bool useMemset = TypeTraits<T>::isPOD::value &&
(initial == T());
if(useMemset)
{
std::memset(p, 0, n*sizeof(T));
}
else
{
std::size_t i=0;
try
{
for (; i < n; ++i)
alloc.construct(p+i, initial);
}
catch (...)
{
for (std::size_t j=0; j < i; ++j)
alloc.destroy(p+j);
alloc.deallocate(p, n);
throw;
}
}
return p;
}
template <class T>
inline T *
alloc_initialize_n(std::size_t n, T const & initial)
{
PlacementNewAllocator<T> alloc;
return alloc_initialize_n<T>(n, initial, alloc);
}
template <class T>
inline T *
alloc_initialize_n(std::size_t n)
{
PlacementNewAllocator<T> alloc;
return alloc_initialize_n<T>(n, T(), alloc);
}
template <class T, class Alloc>
inline void
destroy_dealloc_impl(T * p, std::size_t n, Alloc & alloc, VigraTrueType /*
isPOD */)
{
alloc.deallocate(p, n);
}
template <class T, class Alloc>
inline void
destroy_dealloc_impl(T * p, std::size_t n, Alloc & alloc, VigraFalseType /*
isPOD */)
{
for (std::size_t i=0; i < n; ++i)
alloc.destroy(p + i);
alloc.deallocate(p, n);
}
template <class T, class Alloc>
inline T *
destroy_dealloc_n(T * p, std::size_t n, Alloc & alloc)
{
if(p != 0)
destroy_dealloc_impl(p, n, alloc, typename TypeTraits<T>::isPOD());
return 0;
}
template <class T>
inline T *
destroy_dealloc_n(T * p, std::size_t n)
{
if(p != 0)
{
PlacementNewAllocator<T> alloc;
destroy_dealloc_impl(p, n, alloc, typename TypeTraits<T>::isPOD());
}
return 0;
}
/********************************************************************/ /********************************************************************/
// g++ 2.95 has std::destroy() in the STL // g++ 2.95 has std::destroy() in the STL
#if !defined(__GNUC__) || __GNUC__ >= 3 #if !defined(__GNUC__) || __GNUC__ >= 3
template <class T> template <class T>
inline void destroy(T * p, VigraTrueType /* isPOD */) inline void destroy(T * /* p */, VigraTrueType /* isPOD */)
{ {
} }
template <class T> template <class T>
inline void destroy(T * p, VigraFalseType /* isPOD */) inline void destroy(T * p, VigraFalseType /* isPOD */)
{ {
p->~T(); p->~T();
} }
template <class T> template <class T>
 End of changes. 8 change blocks. 
7 lines changed or deleted 126 lines changed or added


 metaprogramming.hxx   metaprogramming.hxx 
skipping to change at line 91 skipping to change at line 91
}; };
/** \addtogroup MultiArrayTags Multi-dimensional Array Tags /** \addtogroup MultiArrayTags Multi-dimensional Array Tags
Meta-programming tags to mark array's as strided or unstrided. Meta-programming tags to mark array's as strided or unstrided.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* StridedArrayTag */ /* tags for MultiArray memory layout */
/* */ /* */
/********************************************************/ /********************************************************/
/** tag for marking a MultiArray strided. /** tag for marking a MultiArray strided.
<b>\#include</b> <b>\#include</b> \<vigra/metaprogramming.hxx\> <br/>
\<vigra/multi_array.hxx\> Namespace: vigra
Namespace: vigra
*/ */
struct StridedArrayTag {}; struct StridedArrayTag {};
/********************************************************/
/* */
/* UnstridedArrayTag */
/* */
/********************************************************/
/** tag for marking a MultiArray unstrided. /** tag for marking a MultiArray unstrided.
<b>\#include</b> <b>\#include</b> \<vigra/metaprogramming.hxx\> <br/>
\<vigra/multi_array.hxx\> Namespace: vigra
Namespace: vigra
*/ */
struct UnstridedArrayTag {}; struct UnstridedArrayTag {};
/** tag for marking a MultiArray chunked.
<b>\#include</b> \<vigra/metaprogramming.hxx\> <br/>
Namespace: vigra
*/
struct ChunkedArrayTag {};
/********************************************************/
/* */
/* TypeTraits */
/* */
/********************************************************/
template<class T> template<class T>
class TypeTraits class TypeTraits
{ {
public: public:
typedef VigraFalseType isConst; typedef VigraFalseType isConst;
typedef VigraFalseType isPOD; typedef VigraFalseType isPOD;
typedef VigraFalseType isBuiltinType; typedef VigraFalseType isBuiltinType;
}; };
#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
skipping to change at line 400 skipping to change at line 403
template <class DERIVED, class BASE> template <class DERIVED, class BASE>
struct IsDerivedFrom struct IsDerivedFrom
{ {
typedef char falseResult[1]; typedef char falseResult[1];
typedef char trueResult[2]; typedef char trueResult[2];
static falseResult * testIsDerivedFrom(...); static falseResult * testIsDerivedFrom(...);
static trueResult * testIsDerivedFrom(BASE const *); static trueResult * testIsDerivedFrom(BASE const *);
enum { resultSize = sizeof(*testIsDerivedFrom((DERIVED const *)0)) }; enum { resultSize = sizeof(*testIsDerivedFrom(static_cast<DERIVED const *>(0))) };
static const bool value = (resultSize == 2); static const bool value = (resultSize == 2);
typedef typename typedef typename
IfBool<value, VigraTrueType, VigraFalseType>::type IfBool<value, VigraTrueType, VigraFalseType>::type
type; type;
static const bool boolResult = value; // deprecated static const bool boolResult = value; // deprecated
typedef type result; // deprecated typedef type result; // deprecated
}; };
template <class T> template <class T>
struct UnqualifiedType struct UnqualifiedType
{ {
typedef T type; typedef T type;
static const bool isConst = false;
static const bool isReference = false;
static const bool isPointer = false;
}; };
template <class T> template <class T>
struct UnqualifiedType<T const> struct UnqualifiedType<T const>
{ {
typedef T type; typedef T type;
static const bool isConst = true;
static const bool isReference = false;
static const bool isPointer = false;
}; };
template <class T> template <class T>
struct UnqualifiedType<T &> struct UnqualifiedType<T &>
: public UnqualifiedType<T> : public UnqualifiedType<T>
{}; {
static const bool isReference = true;
};
template <class T> template <class T>
struct UnqualifiedType<T const &> struct UnqualifiedType<T const &>
: public UnqualifiedType<T> : public UnqualifiedType<T const>
{}; {
static const bool isReference = true;
};
template <class T> template <class T>
struct UnqualifiedType<T *> struct UnqualifiedType<T *>
: public UnqualifiedType<T> : public UnqualifiedType<T>
{}; {
static const bool isPointer = true;
};
template <class T> template <class T>
struct UnqualifiedType<T const *> struct UnqualifiedType<T const *>
: public UnqualifiedType<T> : public UnqualifiedType<T const>
{}; {
static const bool isPointer = true;
};
template <bool, class T = void> template <bool, class T = void>
struct enable_if {}; struct enable_if {};
template <class T> template <class T>
struct enable_if<true, T> { typedef T type; }; struct enable_if<true, T> { typedef T type; };
struct sfinae_void; struct sfinae_void;
template <class T, template<class> class USER> template <class T, template<class> class USER>
struct sfinae_test struct sfinae_test
{ {
typedef char falseResult[1]; typedef char falseResult[1];
typedef char trueResult[2]; typedef char trueResult[2];
static falseResult * test(...); static falseResult * test(...);
static trueResult * test(USER<sfinae_void>); static trueResult * test(USER<sfinae_void>);
enum { resultSize = sizeof(*test((T*)0)) }; enum { resultSize = sizeof(*test(static_cast<T*>(0))) };
static const bool value = (resultSize == 2); static const bool value = (resultSize == 2);
typedef typename typedef typename
IfBool<value, VigraTrueType, VigraFalseType>::type IfBool<value, VigraTrueType, VigraFalseType>::type
type; type;
}; };
template <class T> template <class T>
struct has_argument_type : public sfinae_test<T, has_argument_type> struct has_argument_type : public sfinae_test<T, has_argument_type>
{ {
skipping to change at line 533 skipping to change at line 550
template <class T> template <class T>
struct IsArray struct IsArray
{ {
typedef char falseResult[1]; typedef char falseResult[1];
typedef char trueResult[2]; typedef char trueResult[2];
static falseResult * test(...); static falseResult * test(...);
template <class U, unsigned n> template <class U, unsigned n>
static trueResult * test(U (*)[n]); static trueResult * test(U (*)[n]);
enum { resultSize = sizeof(*test((T*)0)) }; enum { resultSize = sizeof(*test(static_cast<T*>(0))) };
static const bool value = (resultSize == 2); static const bool value = (resultSize == 2);
typedef typename typedef typename
IfBool<value, VigraTrueType, VigraFalseType>::type IfBool<value, VigraTrueType, VigraFalseType>::type
type; type;
}; };
template <class D, class B, class Z> inline template <class D, class B, class Z> inline
D & static_cast_2(Z & z) D & static_cast_2(Z & z)
{ {
skipping to change at line 643 skipping to change at line 660
static const unsigned value = 1; static const unsigned value = 1;
}; };
template <class X, X z, X u> template <class X, X z, X u>
struct MetaLog2<X, z, 1, 0, 1, z, z, u, typename EnableMetaLog2<X>::type> struct MetaLog2<X, z, 1, 0, 1, z, z, u, typename EnableMetaLog2<X>::type>
{ {
// A value of zero for MetaLog2<X, 0> is likely to cause most harm, // A value of zero for MetaLog2<X, 0> is likely to cause most harm,
// such as division by zero or zero array sizes, this is actually inden ded. // such as division by zero or zero array sizes, this is actually inden ded.
static const unsigned value = 0; static const unsigned value = 0;
}; };
template <int X, unsigned int N>
struct MetaPow
{
static const long long value = MetaPow<X, N-1>::value * X;
};
template <int X>
struct MetaPow<X, 0>
{
static const long long value = 1;
};
/************************************************************************** **/ /************************************************************************** **/
/* */ /* */
/* TypeList and its functions */ /* TypeList and its functions */
/* */ /* */
/************************************************************************** **/ /************************************************************************** **/
template<class HEAD, class TAIL=void> template<class HEAD, class TAIL=void>
struct TypeList struct TypeList
{ {
typedef TypeList<HEAD, TAIL> type; typedef TypeList<HEAD, TAIL> type;
typedef HEAD Head; typedef HEAD Head;
typedef TAIL Tail; typedef TAIL Tail;
}; };
template <class List, class T> template <class List, class T>
struct Contains; struct Contains;
template <class Head, class Tail, class T> template <class Head, class Tail, class T>
struct Contains<TypeList<Head, Tail>, T> struct Contains<TypeList<Head, Tail>, T>
{ {
 End of changes. 16 change blocks. 
25 lines changed or deleted 54 lines changed or added


 multi_array.hxx   multi_array.hxx 
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MULTI_ARRAY_HXX #ifndef VIGRA_MULTI_ARRAY_HXX
#define VIGRA_MULTI_ARRAY_HXX #define VIGRA_MULTI_ARRAY_HXX
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include "accessor.hxx" #include "accessor.hxx"
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "rgbvalue.hxx" #include "rgbvalue.hxx"
#include "basicimageview.hxx" #include "basicimage.hxx"
#include "imageiterator.hxx" #include "imageiterator.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "multi_iterator.hxx" #include "multi_iterator.hxx"
#include "multi_pointoperators.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "algorithm.hxx"
// Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined. // Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
#ifdef VIGRA_CHECK_BOUNDS #ifdef VIGRA_CHECK_BOUNDS
#define VIGRA_ASSERT_INSIDE(diff) \ #define VIGRA_ASSERT_INSIDE(diff) \
vigra_precondition(this->isInside(diff), "Index out of bounds") vigra_precondition(this->isInside(diff), "Index out of bounds")
#else #else
#define VIGRA_ASSERT_INSIDE(diff) #define VIGRA_ASSERT_INSIDE(diff)
#endif #endif
namespace vigra namespace vigra
{ {
namespace detail namespace detail
{ {
/********************************************************/
/* */
/* defaultStride */
/* */
/********************************************************/
/* generates the stride for a gapless shape.
Namespace: vigra::detail
*/
template <unsigned int N>
inline TinyVector <MultiArrayIndex, N>
defaultStride(const TinyVector <MultiArrayIndex, N> &shape)
{
TinyVector <MultiArrayIndex, N> ret;
ret [0] = 1;
for (int i = 1; i < (int)N; ++i)
ret [i] = ret [i-1] * shape [i-1];
return ret;
}
/********************************************************/
/* */
/* ScanOrderToOffset */
/* */
/********************************************************/
/* transforms an index in scan order sense to a pointer offset in a possibl
y
strided, multi-dimensional array.
Namespace: vigra::detail
*/
template <int K>
struct ScanOrderToOffset
{
template <int N>
static MultiArrayIndex
exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> &shape,
const TinyVector <MultiArrayIndex, N> & stride)
{
return stride[N-K] * (d % shape[N-K]) +
ScanOrderToOffset<K-1>::exec(d / shape[N-K], shape, stride);
}
};
template <>
struct ScanOrderToOffset<1>
{
template <int N>
static MultiArrayIndex
exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> & /*shape
*/,
const TinyVector <MultiArrayIndex, N> & stride)
{
return stride[N-1] * d;
}
};
template <int K>
struct ScanOrderToCoordinate
{
template <int N>
static void
exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> &shape,
TinyVector <MultiArrayIndex, N> & result)
{
result[N-K] = (d % shape[N-K]);
ScanOrderToCoordinate<K-1>::exec(d / shape[N-K], shape, result);
}
};
template <>
struct ScanOrderToCoordinate<1>
{
template <int N>
static void
exec(MultiArrayIndex d, const TinyVector <MultiArrayIndex, N> & /*shape
*/,
TinyVector <MultiArrayIndex, N> & result)
{
result[N-1] = d;
}
};
template <class C>
struct CoordinatesToOffest
{
template <int N>
static MultiArrayIndex
exec(const TinyVector <MultiArrayIndex, N> & stride, MultiArrayIndex x)
{
return stride[0] * x;
}
template <int N>
static MultiArrayIndex
exec(const TinyVector <MultiArrayIndex, N> & stride, MultiArrayIndex x,
MultiArrayIndex y)
{
return stride[0] * x + stride[1] * y;
}
};
template <>
struct CoordinatesToOffest<UnstridedArrayTag>
{
template <int N>
static MultiArrayIndex
exec(const TinyVector <MultiArrayIndex, N> & /*stride*/, MultiArrayInde
x x)
{
return x;
}
template <int N>
static MultiArrayIndex
exec(const TinyVector <MultiArrayIndex, N> & stride, MultiArrayIndex x,
MultiArrayIndex y)
{
return x + stride[1] * y;
}
};
/********************************************************/ /********************************************************/
/* */ /* */
/* MaybeStrided */ /* MaybeStrided */
/* */ /* */
/********************************************************/ /********************************************************/
/* metatag implementing a test for marking MultiArrays that were /* metatag implementing a test for marking MultiArrays that were
indexed at the zero'th dimension as strided, and all others as indexed at the zero'th dimension as strided, and all others as
unstrided. unstrided.
<b>\#include</b> <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
\<vigra/multi_array.hxx\> Namespace: vigra::detail
Namespace: vigra::detail
*/ */
template <class StrideTag, unsigned int N> template <class StrideTag, unsigned int N>
struct MaybeStrided struct MaybeStrided
{ {
typedef StrideTag type; typedef StrideTag type;
}; };
template <class StrideTag> template <class StrideTag>
struct MaybeStrided <StrideTag, 0> struct MaybeStrided <StrideTag, 0>
{ {
skipping to change at line 217 skipping to change at line 101
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIteratorChooser */ /* MultiIteratorChooser */
/* */ /* */
/********************************************************/ /********************************************************/
/* metatag implementing a test (by pattern matching) for marking /* metatag implementing a test (by pattern matching) for marking
MultiArrays that were indexed at the zero'th dimension as strided. MultiArrays that were indexed at the zero'th dimension as strided.
<b>\#include</b> <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
\<vigra/multi_array.hxx\> Namespace: vigra::detail
Namespace: vigra::detail
*/ */
template <class O> template <class O>
struct MultiIteratorChooser struct MultiIteratorChooser;
{
struct Nil {};
template <unsigned int N, class T, class REFERENCE, class POINTER>
struct Traverser
{
typedef Nil type;
};
};
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIteratorChooser <StridedArrayTag> */ /* MultiIteratorChooser <StridedArrayTag> */
/* */ /* */
/********************************************************/ /********************************************************/
/* specialization of the MultiIteratorChooser for strided arrays. /* specialization of the MultiIteratorChooser for strided arrays.
<b>\#include</b> <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
\<vigra/multi_array.hxx\> Namespace: vigra::detail
Namespace: vigra::detail
*/ */
template <> template <>
struct MultiIteratorChooser <StridedArrayTag> struct MultiIteratorChooser <StridedArrayTag>
{ {
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
struct Traverser struct Traverser
{ {
typedef StridedMultiIterator <N, T, REFERENCE, POINTER> type; typedef StridedMultiIterator <N, T, REFERENCE, POINTER> type;
}; };
template <unsigned int N, class T, class REFERENCE, class POINTER>
struct Iterator
{
typedef StridedScanOrderIterator <N, T, REFERENCE, POINTER> type;
};
template <class Iter, class View>
static Iter constructIterator(View * v)
{
return v->begin();
}
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIteratorChooser <UnstridedArrayTag> */ /* MultiIteratorChooser <UnstridedArrayTag> */
/* */ /* */
/********************************************************/ /********************************************************/
/* specialization of the MultiIteratorChooser for unstrided arrays. /* specialization of the MultiIteratorChooser for unstrided arrays.
<b>\#include</b> <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
\<vigra/multi_array.hxx\> Namespace: vigra::detail
Namespace: vigra::detail
*/ */
template <> template <>
struct MultiIteratorChooser <UnstridedArrayTag> struct MultiIteratorChooser <UnstridedArrayTag>
{ {
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
struct Traverser struct Traverser
{ {
typedef MultiIterator <N, T, REFERENCE, POINTER> type; typedef MultiIterator <N, T, REFERENCE, POINTER> type;
}; };
template <unsigned int N, class T, class REFERENCE, class POINTER>
struct Iterator
{
typedef POINTER type;
};
template <class Iter, class View>
static Iter constructIterator(View * v)
{
return v->data();
}
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* helper functions */ /* helper functions */
/* */ /* */
/********************************************************/ /********************************************************/
template <class DestIterator, class Shape, class T> template <class DestIterator, class Shape, class T>
inline void inline void
skipping to change at line 314 skipping to change at line 207
initMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); initMultiArrayData(d.begin(), shape, init, MetaInt<N-1>());
} }
} }
// FIXME: the explicit overload for MultiIterator<1, UInt8, ... > works aro und a compiler crash in VisualStudio 2010 // FIXME: the explicit overload for MultiIterator<1, UInt8, ... > works aro und a compiler crash in VisualStudio 2010
#define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \ #define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \
template <class SrcIterator, class Shape, class DestIterator> \ template <class SrcIterator, class Shape, class DestIterator> \
inline void \ inline void \
name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me taInt<0>) \ name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me taInt<0>) \
{ \ { \
SrcIterator send = s + shape[0]; \ for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
for(; s < send; ++s, ++d) \
{ \ { \
*d op detail::RequiresExplicitCast<typename DestIterator::value_typ e>::cast(*s); \ *d op detail::RequiresExplicitCast<typename DestIterator::value_typ e>::cast(*s); \
} \ } \
} \ } \
\ \
template <class Ref, class Ptr, class Shape, class DestIterator> \ template <class Ref, class Ptr, class Shape, class DestIterator> \
inline void \ inline void \
name##MultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & sh ape, DestIterator d, MetaInt<0>) \ name##MultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & sh ape, DestIterator d, MetaInt<0>) \
{ \ { \
Ptr s = &(*si), send = s + shape[0]; \ Ptr s = &(*si); \
for(; s < send; ++s, ++d) \ for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
{ \ { \
*d op detail::RequiresExplicitCast<typename DestIterator::value_typ e>::cast(*s); \ *d op detail::RequiresExplicitCast<typename DestIterator::value_typ e>::cast(*s); \
} \ } \
} \ } \
\ \
template <class SrcIterator, class Shape, class DestIterator, int N> \ template <class SrcIterator, class Shape, class DestIterator, int N> \
void \ void \
name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me taInt<N>) \ name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me taInt<N>) \
{ \ { \
SrcIterator send = s + shape[N]; \ for(MultiArrayIndex i=0; i < shape[N]; ++i, ++s, ++d) \
for(; s < send; ++s, ++d) \
{ \ { \
name##MultiArrayData(s.begin(), shape, d.begin(), MetaInt<N-1>()); \ name##MultiArrayData(s.begin(), shape, d.begin(), MetaInt<N-1>()); \
} \ } \
} \ } \
\ \
template <class DestIterator, class Shape, class T> \ template <class DestIterator, class Shape, class T> \
inline void \ inline void \
name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i nit, MetaInt<0>) \ name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i nit, MetaInt<0>) \
{ \ { \
DestIterator dend = d + shape[0]; \ for(MultiArrayIndex i=0; i < shape[0]; ++i, ++d) \
for(; d < dend; ++d) \
{ \ { \
*d op detail::RequiresExplicitCast<typename DestIterator::value_typ e>::cast(init); \ *d op detail::RequiresExplicitCast<typename DestIterator::value_typ e>::cast(init); \
} \ } \
} \ } \
\ \
template <class DestIterator, class Shape, class T, int N> \ template <class DestIterator, class Shape, class T, int N> \
void \ void \
name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i nit, MetaInt<N>) \ name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i nit, MetaInt<N>) \
{ \ { \
DestIterator dend = d + shape[N]; \ for(MultiArrayIndex i=0; i < shape[N]; ++i, ++d) \
for(; d < dend; ++d) \
{ \ { \
name##ScalarMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); \ name##ScalarMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); \
} \ } \
} }
VIGRA_COPY_MULTI_ARRAY_DATA(copy, =) VIGRA_COPY_MULTI_ARRAY_DATA(copy, =)
VIGRA_COPY_MULTI_ARRAY_DATA(copyAdd, +=) VIGRA_COPY_MULTI_ARRAY_DATA(copyAdd, +=)
VIGRA_COPY_MULTI_ARRAY_DATA(copySub, -=) VIGRA_COPY_MULTI_ARRAY_DATA(copySub, -=)
VIGRA_COPY_MULTI_ARRAY_DATA(copyMul, *=) VIGRA_COPY_MULTI_ARRAY_DATA(copyMul, *=)
VIGRA_COPY_MULTI_ARRAY_DATA(copyDiv, /=) VIGRA_COPY_MULTI_ARRAY_DATA(copyDiv, /=)
skipping to change at line 589 skipping to change at line 478
} // namespace detail } // namespace detail
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiArrayView */ /* MultiArrayView */
/* */ /* */
/********************************************************/ /********************************************************/
// forward declarations // forward declarations
template <unsigned int N, class T, class C = UnstridedArrayTag>
class MultiArrayView;
template <unsigned int N, class T, class A = std::allocator<T> >
class MultiArray;
namespace multi_math { namespace multi_math {
template <class T> template <class T>
struct MultiMathOperand; struct MultiMathOperand;
namespace detail { namespace math_detail {
template <unsigned int N, class T, class C, class E> template <unsigned int N, class T, class C, class E>
void assign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &); void assign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class C, class E> template <unsigned int N, class T, class C, class E>
void plusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &); void plusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class C, class E> template <unsigned int N, class T, class C, class E>
void minusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &); void minusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
skipping to change at line 631 skipping to change at line 515
template <unsigned int N, class T, class A, class E> template <unsigned int N, class T, class A, class E>
void minusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const & ); void minusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const & );
template <unsigned int N, class T, class A, class E> template <unsigned int N, class T, class A, class E>
void multiplyAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> cons t &); void multiplyAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> cons t &);
template <unsigned int N, class T, class A, class E> template <unsigned int N, class T, class A, class E>
void divideAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &); void divideAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
} // namespace detail } // namespace math_detail
} // namespace multi_math } // namespace multi_math
template <class T> class FindSum; template <class T> class FindSum;
struct UnsuitableTypeForExpandElements {}; struct UnsuitableTypeForExpandElements {};
template <class T> template <class T>
struct ExpandElementResult struct ExpandElementResult
{ {
skipping to change at line 718 skipping to change at line 602
template <unsigned int N, class T, class C> template <unsigned int N, class T, class C>
struct NormTraits<MultiArrayView<N, T, C> > struct NormTraits<MultiArrayView<N, T, C> >
{ {
typedef MultiArrayView<N, T, C> Ty pe; typedef MultiArrayView<N, T, C> Ty pe;
typedef typename NormTraits<T>::SquaredNormType SquaredNormType; typedef typename NormTraits<T>::SquaredNormType SquaredNormType;
typedef typename SquareRootTraits<SquaredNormType>::SquareRootResult No rmType; typedef typename SquareRootTraits<SquaredNormType>::SquareRootResult No rmType;
}; };
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
struct NormTraits<MultiArray<N, T, A> > struct NormTraits<MultiArray<N, T, A> >
: public NormTraits<MultiArrayView<N, T, UnstridedArrayTag> > : public NormTraits<typename MultiArray<N, T, A>::view_type>
{ {
typedef NormTraits<MultiArrayView<N, T, UnstridedArrayTag> > BaseType; typedef NormTraits<typename MultiArray<N, T, A>::view_type> BaseType;
typedef MultiArray<N, T, A> Type; typedef MultiArray<N, T, A> Type;
typedef typename BaseType::SquaredNormType SquaredNor mType; typedef typename BaseType::SquaredNormType SquaredNor mType;
typedef typename BaseType::NormType NormType; typedef typename BaseType::NormType NormType;
}; };
/** \brief Base class for, and view to, \ref vigra::MultiArray. /** \brief Base class for, and view to, \ref vigra::MultiArray.
This class implements the interface of both MultiArray and This class implements the interface of both MultiArray and
MultiArrayView. By default, MultiArrayViews are tagged as MultiArrayView. By default, MultiArrayViews are tagged as
unstrided. If necessary, strided arrays are constructed automatically strided (using <tt>StridedArrayTag</tt> as third template parameter).
by calls to a variant of the bind...() function. This means that the array elements need not be consecutive in memory,
making the view flexible to represent all kinds of subarrays and slices.
In certain cases (which have become rare due to improvements of
optimizer and processor technology), an array may be tagged with
<tt>UnstridedArrayTag</tt> which indicates that the first array dimension
is guaranteed to be unstrided, i.e. has consecutive elements in memory.
In addition to the member functions described here, <tt>MultiArrayView</tt> In addition to the member functions described here, <tt>MultiArrayView</tt>
and its subclasses support arithmetic and algebraic functions via the and its subclasses support arithmetic and algebraic functions via the
module \ref MultiMathModule. module \ref MultiMathModule.
If you want to apply an algorithm requiring an image to a If you want to apply an algorithm requiring an image to a
<tt>MultiArrayView</tt> of appropriate (2-dimensional) shape, you can <tt>MultiArrayView</tt> of appropriate (2-dimensional) shape, you can
create a \ref vigra::BasicImageView that acts as a wrapper with the create a \ref vigra::BasicImageView that acts as a wrapper with the
necessary interface -- see \ref MultiArrayToImage. necessary interface -- see \ref MultiArrayToImage.
skipping to change at line 753 skipping to change at line 642
\code \code
N: the array dimension N: the array dimension
T: the type of the array elements T: the type of the array elements
C: a tag determining whether the array's inner dimension is strided C: a tag determining whether the array's inner dimension is strided
or not. An array is unstrided if the array elements occupy consecuti ve or not. An array is unstrided if the array elements occupy consecuti ve
memory location, strided if there is an offset in between (e.g. memory location, strided if there is an offset in between (e.g.
when a view is created that skips every other array element). when a view is created that skips every other array element).
The compiler can generate faster code for unstrided arrays. The compiler can generate faster code for unstrided arrays.
Possible values: UnstridedArrayTag (default), StridedArrayTag Possible values: StridedArrayTag (default), UnstridedArrayTag
\endcode \endcode
<b>\#include</b> <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
\<vigra/multi_array.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
class MultiArrayView class MultiArrayView
{ {
public: public:
/** the array's actual dimensionality. /** the array's actual dimensionality.
This ensures that MultiArrayView can also be used for This ensures that MultiArrayView can also be used for
scalars (that is, when <tt>N == 0</tt>). Calculated as:<br> scalars (that is, when <tt>N == 0</tt>). Calculated as:<br>
skipping to change at line 799 skipping to change at line 686
typedef value_type *pointer; typedef value_type *pointer;
/** const pointer type /** const pointer type
*/ */
typedef const value_type *const_pointer; typedef const value_type *const_pointer;
/** difference type (used for multi-dimensional offsets and indices ) /** difference type (used for multi-dimensional offsets and indices )
*/ */
typedef typename MultiArrayShape<actual_dimension>::type difference_typ e; typedef typename MultiArrayShape<actual_dimension>::type difference_typ e;
/** key type (argument of index operator array[i] -- same as differ
ence_type)
*/
typedef difference_type key_type;
/** size type /** size type
*/ */
typedef difference_type size_type; typedef difference_type size_type;
/** difference and index type for a single dimension /** difference and index type for a single dimension
*/ */
typedef MultiArrayIndex difference_type_1; typedef MultiArrayIndex difference_type_1;
/** scan-order iterator (StridedScanOrderIterator) type /** scan-order iterator (StridedScanOrderIterator) type
*/ */
skipping to change at line 833 skipping to change at line 724
StrideTag>::template Traverser <actual_dimension, T, T const &, T c onst *>::type const_traverser; StrideTag>::template Traverser <actual_dimension, T, T const &, T c onst *>::type const_traverser;
/** the view type associated with this array. /** the view type associated with this array.
*/ */
typedef MultiArrayView <N, T, StrideTag> view_type; typedef MultiArrayView <N, T, StrideTag> view_type;
/** the matrix type associated with this array. /** the matrix type associated with this array.
*/ */
typedef MultiArray <N, T> matrix_type; typedef MultiArray <N, T> matrix_type;
protected: bool checkInnerStride(UnstridedArrayTag) const
{
return m_stride[0] <= 1;
}
bool checkInnerStride(StridedArrayTag) const
{
return true;
}
protected:
typedef typename difference_type::value_type diff_zero_t; typedef typename difference_type::value_type diff_zero_t;
/** the shape of the image pointed to is stored here. /** the shape of the image pointed to is stored here.
*/ */
difference_type m_shape; difference_type m_shape;
/** the strides (offset of a sample to the next) for every dimensio n /** the strides (offset of a sample to the next) for every dimensio n
are stored here. are stored here.
*/ */
difference_type m_stride; difference_type m_stride;
/** pointer to the image. /** pointer to the image.
*/ */
pointer m_ptr; pointer m_ptr;
template <class CN>
void assignImpl(const MultiArrayView <N, T, CN>& rhs);
template <class U, class CN> template <class U, class CN>
void copyImpl(const MultiArrayView <N, U, CN>& rhs); void copyImpl(const MultiArrayView <N, U, CN>& rhs);
template <class U, class CN> template <class U, class CN>
void swapDataImpl(MultiArrayView <N, U, CN> rhs); void swapDataImpl(MultiArrayView <N, U, CN> rhs);
template <class CN> template <class CN>
bool arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const; bool arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const;
template <class U, class CN> template <class U, class CN>
bool arraysOverlap(const MultiArrayView <N, U, CN>&) const bool arraysOverlap(const MultiArrayView <N, U, CN>&) const
{ {
return false; return false;
} }
bool checkInnerStride(UnstridedArrayTag)
{
return m_stride[0] <= 1;
}
bool checkInnerStride(StridedArrayTag)
{
return true;
}
public: public:
/** default constructor: create an invalid view, /** default constructor: create an invalid view,
* i.e. hasData() returns false and size() is zero. * i.e. hasData() returns false and size() is zero.
*/ */
MultiArrayView () MultiArrayView ()
: m_shape (diff_zero_t(0)), m_stride (diff_zero_t(0)), m_ptr (0) : m_shape (diff_zero_t(0)), m_stride (diff_zero_t(0)), m_ptr (0)
{} {}
/** construct from another array view.
Throws a precondition error if this array has UnstridedArrayTag
, but the
innermost dimension of \a other is strided.
*/
template <class Stride>
MultiArrayView (const MultiArrayView<N, T, Stride> &other)
: m_shape (other.shape()),
m_stride (other.stride()),
m_ptr (other.data())
{
vigra_precondition(other.checkInnerStride(StrideTag()),
"MultiArrayView<..., UnstridedArrayTag>(MultiArrayView const &)
: cannot create unstrided view from strided array.");
}
/** construct from shape and pointer /** construct from shape and pointer
*/ */
MultiArrayView (const difference_type &shape, pointer ptr) MultiArrayView (const difference_type &shape, const_pointer ptr)
: m_shape (shape), : m_shape (shape),
m_stride (detail::defaultStride <MultiArrayView<N,T>::actual_dimensio m_stride (detail::defaultStride<actual_dimension>(shape)),
n> (shape)), m_ptr (const_cast<pointer>(ptr))
m_ptr (ptr)
{} {}
/** Construct from shape, strides (offset of a sample to the /** Construct from shape, strides (offset of a sample to the
next) for every dimension, and pointer. (Note that next) for every dimension, and pointer. (Note that
strides are not given in bytes, but in offset steps of the strides are not given in bytes, but in offset steps of the
respective pointer type.) respective pointer type.)
*/ */
MultiArrayView (const difference_type &shape, MultiArrayView (const difference_type &shape,
const difference_type &stride, const difference_type &stride,
pointer ptr) const_pointer ptr)
: m_shape (shape), : m_shape (shape),
m_stride (stride), m_stride (stride),
m_ptr (ptr) m_ptr (const_cast<pointer>(ptr))
{ {
vigra_precondition(checkInnerStride(StrideTag()), vigra_precondition(checkInnerStride(StrideTag()),
"MultiArrayView<..., UnstridedArrayTag>::MultiArrayView(): Firs t dimension of given array is not unstrided."); "MultiArrayView<..., UnstridedArrayTag>::MultiArrayView(): Firs t dimension of given array is not unstrided.");
} }
/** Construct from an old-style BasicImage.
*/
template <class ALLOC>
MultiArrayView (BasicImage<T, ALLOC> const & image)
: m_shape (Shape2(image.width(), image.height())),
m_stride (detail::defaultStride<actual_dimension>(m_shape)),
m_ptr (const_cast<pointer>(image.data()))
{}
/** Conversion to a strided view. /** Conversion to a strided view.
*/ */
operator MultiArrayView<N, T, StridedArrayTag>() const operator MultiArrayView<N, T, StridedArrayTag>() const
{ {
return MultiArrayView<N, T, StridedArrayTag>(m_shape, m_stride, m_p tr); return MultiArrayView<N, T, StridedArrayTag>(m_shape, m_stride, m_p tr);
} }
/** Reset this <tt>MultiArrayView</tt> to an invalid state (as after
default construction).
Can e.g. be used prior to assignment to make a view object p
oint to new data.
*/
void reset() {
m_shape = diff_zero_t(0);
m_stride = diff_zero_t(0);
m_ptr = 0;
}
/** Assignment. There are 3 cases: /** Assignment. There are 3 cases:
<ul> <ul>
<li> When this <tt>MultiArrayView</tt> does not point to valid data <li> When this <tt>MultiArrayView</tt> does not point to valid data
(e.g. after default construction), it becomes a copy of \a (e.g. after default construction), it becomes a new view o
rhs. f \a rhs.
<li> When the shapes of the two arrays match, the array content <li> Otherwise, when the shapes of the two arrays match, the co
s are copied. ntents
(i.e. the elements) of \a rhs are copied.
<li> Otherwise, a <tt>PreconditionViolation</tt> exception is t hrown. <li> Otherwise, a <tt>PreconditionViolation</tt> exception is t hrown.
</ul> </ul>
*/ */
MultiArrayView & operator=(MultiArrayView const & rhs); MultiArrayView & operator=(MultiArrayView const & rhs)
{
if(this != &rhs)
assignImpl(rhs);
return *this;
}
/** Assignment of a differently typed MultiArrayView. Fails with template<class Stride2>
<tt>PreconditionViolation</tt> exception when the shapes do not MultiArrayView & operator=(MultiArrayView<N, T, Stride2> const & rhs)
match. {
assignImpl(rhs);
return *this;
}
/** Assignment of a differently typed MultiArrayView. It copies the
elements
of\a rhs or fails with <tt>PreconditionViolation</tt> exception
when
the shapes do not match.
*/ */
template<class U, class C1> template<class U, class C1>
MultiArrayView & operator=(MultiArrayView<N, U, C1> const & rhs) MultiArrayView & operator=(MultiArrayView<N, U, C1> const & rhs)
{ {
vigra_precondition(this->shape() == rhs.shape(), vigra_precondition(this->shape() == rhs.shape(),
"MultiArrayView::operator=() size mismatch."); "MultiArrayView::operator=(): shape mismatch.");
this->copyImpl(rhs); this->copyImpl(rhs);
return *this; return *this;
} }
/** Assignment of a scalar. Equivalent to MultiArrayView::init(v). /** Assignment of a scalar. Equivalent to MultiArrayView::init(v).
*/ */
MultiArrayView & operator=(value_type const & v) MultiArrayView & operator=(value_type const & v)
{ {
return init(v); return init(v);
} }
skipping to change at line 1007 skipping to change at line 947
detail::copyDivScalarMultiArrayData(traverser_begin(), shape(), rhs , MetaInt<actual_dimension-1>()); detail::copyDivScalarMultiArrayData(traverser_begin(), shape(), rhs , MetaInt<actual_dimension-1>());
return *this; return *this;
} }
/** Assignment of an array expression. Fails with /** Assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArrayView & operator=(multi_math::MultiMathOperand<Expression> con st & rhs) MultiArrayView & operator=(multi_math::MultiMathOperand<Expression> con st & rhs)
{ {
multi_math::detail::assign(*this, rhs); multi_math::math_detail::assign(*this, rhs);
return *this; return *this;
} }
/** Add-assignment of an array expression. Fails with /** Add-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArrayView & operator+=(multi_math::MultiMathOperand<Expression> co nst & rhs) MultiArrayView & operator+=(multi_math::MultiMathOperand<Expression> co nst & rhs)
{ {
multi_math::detail::plusAssign(*this, rhs); multi_math::math_detail::plusAssign(*this, rhs);
return *this; return *this;
} }
/** Subtract-assignment of an array expression. Fails with /** Subtract-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArrayView & operator-=(multi_math::MultiMathOperand<Expression> co nst & rhs) MultiArrayView & operator-=(multi_math::MultiMathOperand<Expression> co nst & rhs)
{ {
multi_math::detail::minusAssign(*this, rhs); multi_math::math_detail::minusAssign(*this, rhs);
return *this; return *this;
} }
/** Multiply-assignment of an array expression. Fails with /** Multiply-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArrayView & operator*=(multi_math::MultiMathOperand<Expression> co nst & rhs) MultiArrayView & operator*=(multi_math::MultiMathOperand<Expression> co nst & rhs)
{ {
multi_math::detail::multiplyAssign(*this, rhs); multi_math::math_detail::multiplyAssign(*this, rhs);
return *this; return *this;
} }
/** Divide-assignment of an array expression. Fails with /** Divide-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArrayView & operator/=(multi_math::MultiMathOperand<Expression> co nst & rhs) MultiArrayView & operator/=(multi_math::MultiMathOperand<Expression> co nst & rhs)
{ {
multi_math::detail::divideAssign(*this, rhs); multi_math::math_detail::divideAssign(*this, rhs);
return *this; return *this;
} }
/** array access. /** array access.
*/ */
reference operator[] (const difference_type &d) reference operator[] (const difference_type &d)
{ {
VIGRA_ASSERT_INSIDE(d); VIGRA_ASSERT_INSIDE(d);
return m_ptr [dot (d, m_stride)]; return m_ptr [dot (d, m_stride)];
} }
skipping to change at line 1262 skipping to change at line 1202
} }
/** check whether the array is unstrided (i.e. has consecutive memo ry) up /** check whether the array is unstrided (i.e. has consecutive memo ry) up
to the given dimension. to the given dimension.
\a dimension can range from 0 ... N-1. If a certain dimension i s unstrided, \a dimension can range from 0 ... N-1. If a certain dimension i s unstrided,
all lower dimensions are also unstrided. all lower dimensions are also unstrided.
*/ */
bool isUnstrided(unsigned int dimension = N-1) const bool isUnstrided(unsigned int dimension = N-1) const
{ {
difference_type p = shape() - difference_type(1); difference_type s = vigra::detail::defaultStride<actual_dimension>(
for(unsigned int k = dimension+1; k < N; ++k) shape());
p[k] = 0; for(unsigned int k = 0; k <= dimension; ++k)
return (&operator[](p) - m_ptr) == coordinateToScanOrderIndex(p); if(stride(k) != s[k])
return false;
return true;
} }
/** bind the M outmost dimensions to certain indices. /** bind the M outmost dimensions to certain indices.
this reduces the dimensionality of the image to this reduces the dimensionality of the image to
max { 1, N-M }. max { 1, N-M }.
<b>Usage:</b> <b>Usage:</b>
\code \code
// create a 3D array of size 40x30x20 // create a 3D array of size 40x30x20
typedef MultiArray<3, double>::difference_type Shape; typedef MultiArray<3, double>::difference_type Shape;
skipping to change at line 1448 skipping to change at line 1389
// temporarily add a singleton dimension to the destination arr ay // temporarily add a singleton dimension to the destination arr ay
transformMultiArray(srcMultiArrayRange(original), transformMultiArray(srcMultiArrayRange(original),
destMultiArrayRange(rowAverages.insertSingl etonDimension(0)), destMultiArrayRange(rowAverages.insertSingl etonDimension(0)),
FindAverage<double>()); FindAverage<double>());
\endcode \endcode
*/ */
MultiArrayView <N+1, T, StrideTag> MultiArrayView <N+1, T, StrideTag>
insertSingletonDimension (difference_type_1 i) const; insertSingletonDimension (difference_type_1 i) const;
/** create a multiband view for this array.
The type <tt>MultiArrayView<N, Multiband<T> ></tt> tells VIGRA
algorithms which recognize the <tt>Multiband</tt> modifier to
interpret the outermost (last) dimension as a channel dimension
.
In effect, these algorithms will treat the data as a set of
(N-1)-dimensional arrays instead of a single N-dimensional arra
y.
*/
MultiArrayView<N, Multiband<value_type>, StrideTag> multiband() const
{
return MultiArrayView<N, Multiband<value_type>, StrideTag>(*this);
}
/** Create a view to the diagonal elements of the array. /** Create a view to the diagonal elements of the array.
This produces a 1D array view whose size equals the size This produces a 1D array view whose size equals the size
of the shortest dimension of the original array. of the shortest dimension of the original array.
<b>Usage:</b> <b>Usage:</b>
\code \code
// create a 3D array of size 40x30x20 // create a 3D array of size 40x30x20
typedef MultiArray<3, double>::difference_type Shape; typedef MultiArray<3, double>::difference_type Shape;
MultiArray<3, double> array3(Shape(40, 30, 20)); MultiArray<3, double> array3(Shape(40, 30, 20));
skipping to change at line 1472 skipping to change at line 1426
\endcode \endcode
*/ */
MultiArrayView<1, T, StridedArrayTag> diagonal() const MultiArrayView<1, T, StridedArrayTag> diagonal() const
{ {
return MultiArrayView<1, T, StridedArrayTag>(Shape1(vigra::min(m_sh ape)), return MultiArrayView<1, T, StridedArrayTag>(Shape1(vigra::min(m_sh ape)),
Shape1(vigra::sum(m_st ride)), m_ptr); Shape1(vigra::sum(m_st ride)), m_ptr);
} }
/** create a rectangular subarray that spans between the /** create a rectangular subarray that spans between the
points p and q, where p is in the subarray, q not. points p and q, where p is in the subarray, q not.
If an element of p or q is negative, it is subtracted
from the correspongng shape.
<b>Usage:</b> <b>Usage:</b>
\code \code
// create a 3D array of size 40x30x20 // create a 3D array of size 40x30x20
typedef MultiArray<3, double>::difference_type Shape; typedef MultiArray<3, double>::difference_type Shape;
MultiArray<3, double> array3(Shape(40, 30, 20)); MultiArray<3, double> array3(Shape(40, 30, 20));
// get a subarray set is smaller by one element at all sides // get a subarray set is smaller by one element at all sides
MultiArrayView <3, double> subarray = array3.subarray(Shape(1,1 MultiArrayView <3, double> subarray = array3.subarray(Shape(1,
,1), Shape(39, 29, 19)); 1,1), Shape(39, 29, 19));
// specifying the end point with a vector of '-1' is equivalent
MultiArrayView <3, double> subarray2 = array3.subarray(Shape(1,
1,1), Shape(-1, -1, -1));
\endcode \endcode
*/ */
MultiArrayView subarray (const difference_type &p, MultiArrayView subarray (difference_type p, difference_type q) const
const difference_type &q) const
{ {
detail::RelativeToAbsoluteCoordinate<actual_dimension-1>::exec(shap
e(), p);
detail::RelativeToAbsoluteCoordinate<actual_dimension-1>::exec(shap
e(), q);
const difference_type_1 offset = dot (m_stride, p); const difference_type_1 offset = dot (m_stride, p);
return MultiArrayView (q - p, m_stride, m_ptr + offset); return MultiArrayView (q - p, m_stride, m_ptr + offset);
} }
/** apply an additional striding to the image, thereby reducing /** apply an additional striding to the image, thereby reducing
the shape of the array. the shape of the array.
for example, multiplying the stride of dimension one by three for example, multiplying the stride of dimension one by three
turns an appropriately laid out (interleaved) rgb image into turns an appropriately laid out (interleaved) rgb image into
a single band image. a single band image.
*/ */
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
stridearray (const difference_type &s) const stridearray (const difference_type &s) const
{ {
difference_type shape = m_shape; difference_type shape = m_shape;
for (unsigned int i = 0; i < actual_dimension; ++i) for (unsigned int i = 0; i < actual_dimension; ++i)
shape [i] /= s [i]; shape[i] = (shape[i] + s[i] - 1) / s[i];
return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr); return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr);
} }
/** Transpose an array. If N==2, this implements the usual matrix t ransposition. /** Transpose an array. If N==2, this implements the usual matrix t ransposition.
For N > 2, it reverses the order of the indices. For N > 2, it reverses the order of the indices.
<b>Usage:</b><br> <b>Usage:</b><br>
\code \code
typedef MultiArray<2, double>::difference_type Shape; typedef MultiArray<2, double>::difference_type Shape;
MultiArray<2, double> array(10, 20); MultiArray<2, double> array(10, 20);
MultiArray<2, double, StridedArrayTag> transposed = array.trans pose(); MultiArrayView<2, double, StridedArrayTag> transposed = array.t ranspose();
for(int i=0; i<array.shape(0), ++i) for(int i=0; i<array.shape(0), ++i)
for(int j=0; j<array.shape(1); ++j) for(int j=0; j<array.shape(1); ++j)
assert(array(i, j) == transposed(j, i)); assert(array(i, j) == transposed(j, i));
\endcode \endcode
*/ */
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
transpose () const transpose () const
{ {
difference_type shape(m_shape.begin(), difference_type::ReverseCopy ), difference_type shape(m_shape.begin(), difference_type::ReverseCopy ),
stride(m_stride.begin(), difference_type::ReverseCo py); stride(m_stride.begin(), difference_type::ReverseCo py);
return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr) ; return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr) ;
} }
/** permute the dimensions of the array. /** Permute the dimensions of the array.
The function exchanges the meaning of the dimensions without co The function exchanges the orer of the array's axes without cop
pying the data. ying the data.
In case of a 2-dimensional array, this is simply array transpos Argument\a permutation specifies the desired order such that
ition. In higher dimensions, <tt>permutation[k] = j</tt> means that axis <tt>j</tt> in the o
there are more possibilities. riginal array
becomes axis <tt>k</tt> in the transposed array.
<b>Usage:</b><br> <b>Usage:</b><br>
\code \code
typedef MultiArray<2, double>::difference_type Shape; typedef MultiArray<2, double>::difference_type Shape;
MultiArray<2, double> array(10, 20); MultiArray<2, double> array(10, 20);
MultiArray<2, double, StridedArrayTag> transposed = array.permu teDimensions(Shape(1,0)); MultiArrayView<2, double, StridedArrayTag> transposed = array.t ranspose(Shape(1,0));
for(int i=0; i<array.shape(0), ++i) for(int i=0; i<array.shape(0), ++i)
for(int j=0; j<array.shape(1); ++j) for(int j=0; j<array.shape(1); ++j)
assert(array(i, j) == transposed(j, i)); assert(array(i, j) == transposed(j, i));
\endcode \endcode
*/ */
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
transpose(const difference_type &permutation) const
{
return permuteDimensions(permutation);
}
MultiArrayView <N, T, StridedArrayTag>
permuteDimensions (const difference_type &s) const; permuteDimensions (const difference_type &s) const;
/** Permute the dimensions of the array so that the strides are in ascending order. /** Permute the dimensions of the array so that the strides are in ascending order.
Determines the appropriate permutation and then calls permuteDi mensions(). Determines the appropriate permutation and then calls permuteDi mensions().
*/ */
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
permuteStridesAscending() const; permuteStridesAscending() const;
/** Permute the dimensions of the array so that the strides are in descending order. /** Permute the dimensions of the array so that the strides are in descending order.
Determines the appropriate permutation and then calls permuteDi mensions(). Determines the appropriate permutation and then calls permuteDi mensions().
skipping to change at line 1615 skipping to change at line 1582
} }
/** return the array's shape at a certain dimension /** return the array's shape at a certain dimension
(same as <tt>size(n)</tt>). (same as <tt>size(n)</tt>).
*/ */
difference_type_1 shape (difference_type_1 n) const difference_type_1 shape (difference_type_1 n) const
{ {
return m_shape [n]; return m_shape [n];
} }
/** return the array's width (same as <tt>shape(0)</tt>).
*/
difference_type_1 width() const
{
return m_shape [0];
}
/** return the array's height (same as <tt>shape(1)</tt>).
*/
difference_type_1 height() const
{
return m_shape [1];
}
/** return the array's stride for every dimension. /** return the array's stride for every dimension.
*/ */
const difference_type & stride () const const difference_type & stride () const
{ {
return m_stride; return m_stride;
} }
/** return the array's stride at a certain dimension. /** return the array's stride at a certain dimension.
*/ */
difference_type_1 stride (int n) const difference_type_1 stride (int n) const
skipping to change at line 1657 skipping to change at line 1638
/** check whether the given point is in the array range. /** check whether the given point is in the array range.
*/ */
bool isInside (difference_type const & p) const bool isInside (difference_type const & p) const
{ {
for(int d=0; d<actual_dimension; ++d) for(int d=0; d<actual_dimension; ++d)
if(p[d] < 0 || p[d] >= shape(d)) if(p[d] < 0 || p[d] >= shape(d))
return false; return false;
return true; return true;
} }
/** check whether the given point is not in the array range.
*/
bool isOutside (difference_type const & p) const
{
for(int d=0; d<actual_dimension; ++d)
if(p[d] < 0 || p[d] >= shape(d))
return true;
return false;
}
/** Check if the array contains only non-zero elements (or if all e lements /** Check if the array contains only non-zero elements (or if all e lements
are 'true' if the value type is 'bool'). are 'true' if the value type is 'bool').
*/ */
bool all() const bool all() const
{ {
bool res = true; bool res = true;
detail::reduceOverMultiArray(traverser_begin(), shape(), detail::reduceOverMultiArray(traverser_begin(), shape(),
res, res,
detail::AllTrueReduceFunctor(), detail::AllTrueReduceFunctor(),
skipping to change at line 1685 skipping to change at line 1675
{ {
bool res = false; bool res = false;
detail::reduceOverMultiArray(traverser_begin(), shape(), detail::reduceOverMultiArray(traverser_begin(), shape(),
res, res,
detail::AnyTrueReduceFunctor(), detail::AnyTrueReduceFunctor(),
MetaInt<actual_dimension-1>()); MetaInt<actual_dimension-1>());
return res; return res;
} }
/** Find the minimum and maximum element in this array. /** Find the minimum and maximum element in this array.
See \ref FeatureAccumulators for a general feature See \ref FeatureAccumulators for a general feature
extraction framework. extraction framework.
*/ */
void minmax(T * minimum, T * maximum) const void minmax(T * minimum, T * maximum) const
{ {
std::pair<T, T> res(NumericTraits<T>::max(), NumericTraits<T>::min( )); std::pair<T, T> res(NumericTraits<T>::max(), NumericTraits<T>::min( ));
detail::reduceOverMultiArray(traverser_begin(), shape(), detail::reduceOverMultiArray(traverser_begin(), shape(),
res, res,
detail::MinmaxReduceFunctor(), detail::MinmaxReduceFunctor(),
MetaInt<actual_dimension-1>()); MetaInt<actual_dimension-1>());
*minimum = res.first; *minimum = res.first;
*maximum = res.second; *maximum = res.second;
} }
/** Compute the mean and variance of the values in this array. /** Compute the mean and variance of the values in this array.
See \ref FeatureAccumulators for a general feature See \ref FeatureAccumulators for a general feature
extraction framework. extraction framework.
*/ */
template <class U> template <class U>
void meanVariance(U * mean, U * variance) const void meanVariance(U * mean, U * variance) const
{ {
typedef typename NumericTraits<U>::RealPromote R; typedef typename NumericTraits<U>::RealPromote R;
R zero; R zero = R();
triple<double, R, R> res(0.0, zero, zero); triple<double, R, R> res(0.0, zero, zero);
detail::reduceOverMultiArray(traverser_begin(), shape(), detail::reduceOverMultiArray(traverser_begin(), shape(),
res, res,
detail::MeanVarianceReduceFunctor(), detail::MeanVarianceReduceFunctor(),
MetaInt<actual_dimension-1>()); MetaInt<actual_dimension-1>());
*mean = res.second; *mean = res.second;
*variance = res.third / res.first; *variance = res.third / res.first;
} }
/** Compute the sum of the array elements. /** Compute the sum of the array elements.
skipping to change at line 1749 skipping to change at line 1739
\arg sums must have the same shape as this array, except for th e \arg sums must have the same shape as this array, except for th e
axes along which the sum is to be accumulated. These axes must be axes along which the sum is to be accumulated. These axes must be
singletons. Note that you must include <tt>multi_pointoperators .hxx</tt> singletons. Note that you must include <tt>multi_pointoperators .hxx</tt>
for this function to work. for this function to work.
<b>Usage:</b> <b>Usage:</b>
\code \code
#include <vigra/multi_array.hxx> #include <vigra/multi_array.hxx>
#include <vigra/multi_pointoperators.hxx> #include <vigra/multi_pointoperators.hxx>
MultiArray<2, double> A(rows, cols); MultiArray<2, double> A(Shape2(rows, cols));
... // fill A ... // fill A
// make the first axis a singleton to sum over the first index // make the first axis a singleton to sum over the first index
MultiArray<2, double> rowSums(1, cols); MultiArray<2, double> rowSums(Shape2(1, cols));
A.sum(rowSums); A.sum(rowSums);
// this is equivalent to // this is equivalent to
transformMultiArray(srcMultiArrayRange(A), transformMultiArray(srcMultiArrayRange(A),
destMultiArrayRange(rowSums), destMultiArrayRange(rowSums),
FindSum<double>()); FindSum<double>());
\endcode \endcode
*/ */
template <class U, class S> template <class U, class S>
void sum(MultiArrayView<N, U, S> sums) const void sum(MultiArrayView<N, U, S> sums) const
skipping to change at line 1847 skipping to change at line 1837
bool hasData () const bool hasData () const
{ {
return m_ptr != 0; return m_ptr != 0;
} }
/** returns a scan-order iterator pointing /** returns a scan-order iterator pointing
to the first array element. to the first array element.
*/ */
iterator begin() iterator begin()
{ {
return iterator(m_ptr, m_shape, m_stride); return iterator(*this);
} }
/** returns a const scan-order iterator pointing /** returns a const scan-order iterator pointing
to the first array element. to the first array element.
*/ */
const_iterator begin() const const_iterator begin() const
{ {
return const_iterator(m_ptr, m_shape, m_stride); return const_iterator(*this);
} }
/** returns a scan-order iterator pointing /** returns a scan-order iterator pointing
beyond the last array element. beyond the last array element.
*/ */
iterator end() iterator end()
{ {
return begin().getEndIterator(); return begin().getEndIterator();
} }
skipping to change at line 1914 skipping to change at line 1904
beyond the last element in dimension N, and to the beyond the last element in dimension N, and to the
first element in every other dimension. first element in every other dimension.
*/ */
const_traverser traverser_end () const const_traverser traverser_end () const
{ {
const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ()); const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
ret += m_shape [actual_dimension-1]; ret += m_shape [actual_dimension-1];
return ret; return ret;
} }
view_type view () view_type view () const
{ {
return *this; return *this;
} }
}; };
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
MultiArrayView<N, T, StrideTag> & class MultiArrayView<N, Multiband<T>, StrideTag>
MultiArrayView <N, T, StrideTag>::operator=(MultiArrayView const & rhs) : public MultiArrayView<N, T, StrideTag>
{
public:
MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
: MultiArrayView<N, T, StrideTag>(v)
{}
};
template <unsigned int N, class T, class Stride1>
template <class Stride2>
void
MultiArrayView <N, T, Stride1>::assignImpl(MultiArrayView<N, T, Stride2> co
nst & rhs)
{ {
if(this == &rhs)
return *this;
vigra_precondition(this->shape() == rhs.shape() || m_ptr == 0,
"MultiArrayView::operator=(MultiArrayView const &) size mismatch.")
;
if(m_ptr == 0) if(m_ptr == 0)
{ {
m_shape = rhs.m_shape; vigra_precondition(rhs.checkInnerStride(Stride1()),
m_stride = rhs.m_stride; "MultiArrayView<..., UnstridedArrayTag>::operator=(MultiArrayVi
m_ptr = rhs.m_ptr; ew const &): cannot create unstrided view from strided array.");
m_shape = rhs.shape();
m_stride = rhs.stride();
m_ptr = rhs.data();
} }
else else
{
vigra_precondition(this->shape() == rhs.shape(),
"MultiArrayView::operator=(MultiArrayView const &): shape misma
tch.");
this->copyImpl(rhs); this->copyImpl(rhs);
return *this; }
} }
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
template <class CN> template <class CN>
bool bool
MultiArrayView <N, T, StrideTag>::arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const MultiArrayView <N, T, StrideTag>::arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const
{ {
vigra_precondition (shape () == rhs.shape (), vigra_precondition (shape () == rhs.shape (),
"MultiArrayView::arraysOverlap(): shape mismatch."); "MultiArrayView::arraysOverlap(): shape mismatch.");
const_pointer first_element = this->m_ptr, const_pointer first_element = this->m_ptr,
skipping to change at line 2040 skipping to change at line 2043
MultiArrayView <N, T, StrideTag>::permuteDimensions (const difference_type &s) const MultiArrayView <N, T, StrideTag>::permuteDimensions (const difference_type &s) const
{ {
difference_type shape, stride, check((typename difference_type::value_t ype)0); difference_type shape, stride, check((typename difference_type::value_t ype)0);
for (unsigned int i = 0; i < actual_dimension; ++i) for (unsigned int i = 0; i < actual_dimension; ++i)
{ {
shape[i] = m_shape[s[i]]; shape[i] = m_shape[s[i]];
stride[i] = m_stride[s[i]]; stride[i] = m_stride[s[i]];
++check[s[i]]; ++check[s[i]];
} }
vigra_precondition(check == difference_type(1), vigra_precondition(check == difference_type(1),
"MultiArrayView::permuteDimensions(): every dimension must occur exa ctly once."); "MultiArrayView::transpose(): every dimension must occur exactly onc e.");
return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr); return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr);
} }
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
typename MultiArrayView <N, T, StrideTag>::difference_type typename MultiArrayView <N, T, StrideTag>::difference_type
MultiArrayView <N, T, StrideTag>::strideOrdering(difference_type stride) MultiArrayView <N, T, StrideTag>::strideOrdering(difference_type stride)
{ {
difference_type permutation; difference_type permutation;
for(int k=0; k<(int)N; ++k) for(int k=0; k<(int)N; ++k)
permutation[k] = k; permutation[k] = k;
skipping to change at line 2087 skipping to change at line 2090
permutation[ordering[k]] = k; permutation[ordering[k]] = k;
return permuteDimensions(permutation); return permuteDimensions(permutation);
} }
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
MultiArrayView <N, T, StrideTag>::permuteStridesDescending() const MultiArrayView <N, T, StrideTag>::permuteStridesDescending() const
{ {
difference_type ordering(strideOrdering(m_stride)), permutation; difference_type ordering(strideOrdering(m_stride)), permutation;
for(MultiArrayIndex k=0; k<N; ++k) for(MultiArrayIndex k=0; k<N; ++k)
permutation[ordering[N-1-k]] = k; permutation[N-1-ordering[k]] = k;
return permuteDimensions(permutation); return permuteDimensions(permutation);
} }
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
template <int M, class Index> template <int M, class Index>
MultiArrayView <N-M, T, StrideTag> MultiArrayView <N-M, T, StrideTag>
MultiArrayView <N, T, StrideTag>::bindOuter (const TinyVector <Index, M> &d ) const MultiArrayView <N, T, StrideTag>::bindOuter (const TinyVector <Index, M> &d ) const
{ {
TinyVector <MultiArrayIndex, M> stride; TinyVector <MultiArrayIndex, M> stride;
stride.init (m_stride.begin () + N-M, m_stride.end ()); stride.init (m_stride.begin () + N-M, m_stride.end ());
pointer ptr = m_ptr + dot (d, stride); pointer ptr = m_ptr + dot (d, stride);
static const int NNew = (N-M == 0) ? 1 : N-M; static const int NNew = (N-M == 0) ? 1 : N-M;
TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride; TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride;
if (N-M == 0) if (N-M == 0)
{ {
inner_shape [0] = 1; inner_shape [0] = 1;
inner_stride [0] = 0; inner_stride [0] = 1;
} }
else else
{ {
inner_shape.init (m_shape.begin (), m_shape.end () - M); inner_shape.init (m_shape.begin (), m_shape.end () - M);
inner_stride.init (m_stride.begin (), m_stride.end () - M); inner_stride.init (m_stride.begin (), m_stride.end () - M);
} }
return MultiArrayView <N-M, T, StrideTag> (inner_shape, inner_stride, p tr); return MultiArrayView <N-M, T, StrideTag> (inner_shape, inner_stride, p tr);
} }
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
skipping to change at line 2127 skipping to change at line 2130
MultiArrayView <N, T, StrideTag>::bindInner (const TinyVector <Index, M> &d ) const MultiArrayView <N, T, StrideTag>::bindInner (const TinyVector <Index, M> &d ) const
{ {
TinyVector <MultiArrayIndex, M> stride; TinyVector <MultiArrayIndex, M> stride;
stride.init (m_stride.begin (), m_stride.end () - N + M); stride.init (m_stride.begin (), m_stride.end () - N + M);
pointer ptr = m_ptr + dot (d, stride); pointer ptr = m_ptr + dot (d, stride);
static const int NNew = (N-M == 0) ? 1 : N-M; static const int NNew = (N-M == 0) ? 1 : N-M;
TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride; TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride;
if (N-M == 0) if (N-M == 0)
{ {
outer_shape [0] = 1; outer_shape [0] = 1;
outer_stride [0] = 0; outer_stride [0] = 1;
} }
else else
{ {
outer_shape.init (m_shape.begin () + M, m_shape.end ()); outer_shape.init (m_shape.begin () + M, m_shape.end ());
outer_stride.init (m_stride.begin () + M, m_stride.end ()); outer_stride.init (m_stride.begin () + M, m_stride.end ());
} }
return MultiArrayView <N-M, T, StridedArrayTag> return MultiArrayView <N-M, T, StridedArrayTag>
(outer_shape, outer_stride, ptr); (outer_shape, outer_stride, ptr);
} }
skipping to change at line 2149 skipping to change at line 2152
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type > MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type >
MultiArrayView <N, T, StrideTag>::bind (difference_type_1 d) const MultiArrayView <N, T, StrideTag>::bind (difference_type_1 d) const
{ {
static const int NNew = (N-1 == 0) ? 1 : N-1; static const int NNew = (N-1 == 0) ? 1 : N-1;
TinyVector <MultiArrayIndex, NNew> shape, stride; TinyVector <MultiArrayIndex, NNew> shape, stride;
// the remaining dimensions are 0..n-1,n+1..N-1 // the remaining dimensions are 0..n-1,n+1..N-1
if (N-1 == 0) if (N-1 == 0)
{ {
shape[0] = 1; shape[0] = 1;
stride[0] = 0; stride[0] = 1;
} }
else else
{ {
std::copy (m_shape.begin (), m_shape.begin () + M, shape.begin ()); std::copy (m_shape.begin (), m_shape.begin () + M, shape.begin ());
std::copy (m_shape.begin () + M+1, m_shape.end (), std::copy (m_shape.begin () + M+1, m_shape.end (),
shape.begin () + M); shape.begin () + M);
std::copy (m_stride.begin (), m_stride.begin () + M, stride.begin ( )); std::copy (m_stride.begin (), m_stride.begin () + M, stride.begin ( ));
std::copy (m_stride.begin () + M+1, m_stride.end (), std::copy (m_stride.begin () + M+1, m_stride.end (),
stride.begin () + M); stride.begin () + M);
} }
skipping to change at line 2173 skipping to change at line 2176
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N - 1, T, StrideTag> MultiArrayView <N - 1, T, StrideTag>
MultiArrayView <N, T, StrideTag>::bindOuter (difference_type_1 d) const MultiArrayView <N, T, StrideTag>::bindOuter (difference_type_1 d) const
{ {
static const int NNew = (N-1 == 0) ? 1 : N-1; static const int NNew = (N-1 == 0) ? 1 : N-1;
TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride; TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride;
if (N-1 == 0) if (N-1 == 0)
{ {
inner_shape [0] = 1; inner_shape [0] = 1;
inner_stride [0] = 0; inner_stride [0] = 1;
} }
else else
{ {
inner_shape.init (m_shape.begin (), m_shape.end () - 1); inner_shape.init (m_shape.begin (), m_shape.end () - 1);
inner_stride.init (m_stride.begin (), m_stride.end () - 1); inner_stride.init (m_stride.begin (), m_stride.end () - 1);
} }
return MultiArrayView <N-1, T, StrideTag> (inner_shape, inner_stride, return MultiArrayView <N-1, T, StrideTag> (inner_shape, inner_stride,
m_ptr + d * m_stride [N-1]); m_ptr + d * m_stride [N-1]);
} }
template <unsigned int N, class T, class StrideTag> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N - 1, T, StridedArrayTag> MultiArrayView <N - 1, T, StridedArrayTag>
MultiArrayView <N, T, StrideTag>::bindInner (difference_type_1 d) const MultiArrayView <N, T, StrideTag>::bindInner (difference_type_1 d) const
{ {
static const int NNew = (N-1 == 0) ? 1 : N-1; static const int NNew = (N-1 == 0) ? 1 : N-1;
TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride; TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride;
if (N-1 == 0) if (N-1 == 0)
{ {
outer_shape [0] = 1; outer_shape [0] = 1;
outer_stride [0] = 0; outer_stride [0] = 1;
} }
else else
{ {
outer_shape.init (m_shape.begin () + 1, m_shape.end ()); outer_shape.init (m_shape.begin () + 1, m_shape.end ());
outer_stride.init (m_stride.begin () + 1, m_stride.end ()); outer_stride.init (m_stride.begin () + 1, m_stride.end ());
} }
return MultiArrayView <N-1, T, StridedArrayTag> return MultiArrayView <N-1, T, StridedArrayTag>
(outer_shape, outer_stride, m_ptr + d * m_stride [0]); (outer_shape, outer_stride, m_ptr + d * m_stride [0]);
} }
skipping to change at line 2217 skipping to change at line 2220
{ {
vigra_precondition ( vigra_precondition (
n < static_cast <int> (N), n < static_cast <int> (N),
"MultiArrayView <N, T, StrideTag>::bindAt(): dimension out of range ."); "MultiArrayView <N, T, StrideTag>::bindAt(): dimension out of range .");
static const int NNew = (N-1 == 0) ? 1 : N-1; static const int NNew = (N-1 == 0) ? 1 : N-1;
TinyVector <MultiArrayIndex, NNew> shape, stride; TinyVector <MultiArrayIndex, NNew> shape, stride;
// the remaining dimensions are 0..n-1,n+1..N-1 // the remaining dimensions are 0..n-1,n+1..N-1
if (N-1 == 0) if (N-1 == 0)
{ {
shape [0] = 1; shape [0] = 1;
stride [0] = 0; stride [0] = 1;
} }
else else
{ {
std::copy (m_shape.begin (), m_shape.begin () + n, shape.begin ()); std::copy (m_shape.begin (), m_shape.begin () + n, shape.begin ());
std::copy (m_shape.begin () + n+1, m_shape.end (), std::copy (m_shape.begin () + n+1, m_shape.end (),
shape.begin () + n); shape.begin () + n);
std::copy (m_stride.begin (), m_stride.begin () + n, stride.begin ( )); std::copy (m_stride.begin (), m_stride.begin () + n, stride.begin ( ));
std::copy (m_stride.begin () + n+1, m_stride.end (), std::copy (m_stride.begin () + n+1, m_stride.end (),
stride.begin () + n); stride.begin () + n);
} }
skipping to change at line 2377 skipping to change at line 2380
The template parameters are as follows The template parameters are as follows
\code \code
N: the array dimension N: the array dimension
T: the type of the array elements T: the type of the array elements
A: the allocator used for internal storage management A: the allocator used for internal storage management
(default: std::allocator<T>) (default: std::allocator<T>)
\endcode \endcode
<b>\#include</b> <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
\<vigra/multi_array.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned int N, class T, class A /* default already declared abov e */> template <unsigned int N, class T, class A /* default already declared abov e */>
class MultiArray : public MultiArrayView <N, T> class MultiArray
: public MultiArrayView <N, typename vigra::detail::ResolveMultiband<T>::ty
pe,
typename vigra::detail::ResolveMultiband<T>::St
ride>
{ {
public:
typedef typename vigra::detail::ResolveMultiband<T>::Stride actual_stri
de;
public: /** the view type associated with this array.
using MultiArrayView <N, T>::actual_dimension; */
typedef MultiArrayView <N, typename vigra::detail::ResolveMultiband<T>:
:type,
typename vigra::detail::ResolveMultiband<T>:
:Stride> view_type;
using view_type::actual_dimension;
/** the allocator type used to allocate the memory /** the allocator type used to allocate the memory
*/ */
typedef A allocator_type; typedef A allocator_type;
/** the view type associated with this array.
*/
typedef MultiArrayView <N, T> view_type;
/** the matrix type associated with this array. /** the matrix type associated with this array.
*/ */
typedef MultiArray <N, T, A> matrix_type; typedef MultiArray <N, T, A> matrix_type;
/** the array's value type /** the array's value type
*/ */
typedef typename view_type::value_type value_type; typedef typename view_type::value_type value_type;
/** pointer type /** pointer type
*/ */
skipping to change at line 2435 skipping to change at line 2440
/** difference type (used for multi-dimensional offsets and indices ) /** difference type (used for multi-dimensional offsets and indices )
*/ */
typedef typename view_type::difference_type difference_type; typedef typename view_type::difference_type difference_type;
/** difference and index type for a single dimension /** difference and index type for a single dimension
*/ */
typedef typename view_type::difference_type_1 difference_type_1; typedef typename view_type::difference_type_1 difference_type_1;
/** traverser type /** traverser type
*/ */
typedef typename vigra::detail::MultiIteratorChooser < typedef typename view_type::traverser traverser;
UnstridedArrayTag>::template Traverser <N, T, T &, T *>::type
traverser;
/** traverser type to const data /** traverser type to const data
*/ */
typedef typename vigra::detail::MultiIteratorChooser < typedef typename view_type::const_traverser const_traverser;
UnstridedArrayTag>::template Traverser <N, T, T const &, T const *>
::type // /** sequential (random access) iterator type
const_traverser; // */
// typedef typename vigra::detail::MultiIteratorChooser<actual_stride>:
:template Iterator<N, value_type, reference, pointer>::type
// iterator;
// /** sequential (random access) const iterator type
// */
// typedef typename vigra::detail::MultiIteratorChooser<actual_stride>:
:template Iterator<N, value_type, const_reference, const_pointer>::type
// const_iterator;
/** sequential (random access) iterator type /** sequential (random access) iterator type
*/ */
typedef T * iterator; typedef typename view_type::iterator iterator;
/** sequential (random access) const iterator type /** sequential (random access) const iterator type
*/ */
typedef T * const_iterator; typedef typename view_type::const_iterator const_iterator;
protected: protected:
typedef typename difference_type::value_type diff_zero_t; typedef typename difference_type::value_type diff_zero_t;
/** the allocator used to allocate the memory /** the allocator used to allocate the memory
*/ */
allocator_type m_alloc; allocator_type m_alloc;
/** allocate memory for s pixels, write its address into the given /** allocate memory for s pixels, write its address into the given
skipping to change at line 2488 skipping to change at line 2499
/** deallocate the memory (of length s) starting at the given addre ss. /** deallocate the memory (of length s) starting at the given addre ss.
*/ */
void deallocate (pointer &ptr, difference_type_1 s); void deallocate (pointer &ptr, difference_type_1 s);
template <class U, class StrideTag> template <class U, class StrideTag>
void copyOrReshape (const MultiArrayView<N, U, StrideTag> &rhs); void copyOrReshape (const MultiArrayView<N, U, StrideTag> &rhs);
public: public:
/** default constructor /** default constructor
*/ */
MultiArray () MultiArray ()
: MultiArrayView <N, T> (difference_type (diff_zero_t(0)), : view_type (difference_type (diff_zero_t(0)),
difference_type (diff_zero_t(0)), 0) difference_type (diff_zero_t(0)), 0)
{} {}
/** construct with given allocator /** construct with given allocator
*/ */
MultiArray (allocator_type const & alloc) MultiArray (allocator_type const & alloc)
: MultiArrayView <N, T> (difference_type (diff_zero_t(0)), : view_type(difference_type (diff_zero_t(0)),
difference_type (diff_zero_t(0)), 0), difference_type (diff_zero_t(0)), 0),
m_alloc(alloc) m_alloc(alloc)
{} {}
/** construct with given length /** construct with given length
Use only for 1-dimensional arrays (<tt>N==1</tt>). Use only for 1-dimensional arrays (<tt>N==1</tt>).
*/ */
explicit MultiArray (difference_type_1 length, explicit MultiArray (difference_type_1 length,
allocator_type const & alloc = allocator_type()); allocator_type const & alloc = allocator_type());
/** construct with given width and height
Use only for 2-dimensional arrays (<tt>N==2</tt>).
*/
MultiArray (difference_type_1 width, difference_type_1 height,
allocator_type const & alloc = allocator_type());
/** construct with given shape /** construct with given shape
*/ */
explicit MultiArray (const difference_type &shape, explicit MultiArray (const difference_type &shape,
allocator_type const & alloc = allocator_type()); allocator_type const & alloc = allocator_type());
/** construct from shape with an initial value /** construct from shape with an initial value
*/ */
MultiArray (const difference_type &shape, const_reference init, MultiArray (const difference_type &shape, const_reference init,
allocator_type const & alloc = allocator_type()); allocator_type const & alloc = allocator_type());
/** construct from shape and initialize with a linear sequence in s
can order
(i.e. first pixel gets value 0, second on gets value 1 and so o
n).
*/
MultiArray (const difference_type &shape, MultiArrayInitializationTag i
nit,
allocator_type const & alloc = allocator_type());
/** construct from shape and copy values from the given array /** construct from shape and copy values from the given array
*/ */
MultiArray (const difference_type &shape, const_pointer init, MultiArray (const difference_type &shape, const_pointer init,
allocator_type const & alloc = allocator_type()); allocator_type const & alloc = allocator_type());
/** copy constructor /** copy constructor
*/ */
MultiArray (const MultiArray &rhs) MultiArray (const MultiArray &rhs)
: MultiArrayView <N, T> (rhs.m_shape, rhs.m_stride, 0), : view_type(rhs.m_shape, rhs.m_stride, 0),
m_alloc (rhs.m_alloc) m_alloc (rhs.m_alloc)
{ {
allocate (this->m_ptr, this->elementCount (), rhs.data ()); allocate (this->m_ptr, this->elementCount (), rhs.data ());
} }
/** constructor from an array expression /** constructor from an array expression
*/ */
template<class Expression> template<class Expression>
MultiArray (multi_math::MultiMathOperand<Expression> const & rhs, MultiArray (multi_math::MultiMathOperand<Expression> const & rhs,
allocator_type const & alloc = allocator_type()) allocator_type const & alloc = allocator_type())
: MultiArrayView <N, T> (difference_type (diff_zero_t(0)), : view_type(difference_type (diff_zero_t(0)),
difference_type (diff_zero_t(0)), 0), difference_type (diff_zero_t(0)), 0),
m_alloc (alloc) m_alloc (alloc)
{ {
multi_math::detail::assignOrResize(*this, rhs); multi_math::math_detail::assignOrResize(*this, rhs);
} }
/** construct by copying from a MultiArrayView /** construct by copying from a MultiArrayView
*/ */
template <class U, class StrideTag> template <class U, class StrideTag>
MultiArray (const MultiArrayView<N, U, StrideTag> &rhs, MultiArray (const MultiArrayView<N, U, StrideTag> &rhs,
allocator_type const & alloc = allocator_type()); allocator_type const & alloc = allocator_type());
/** assignment.<br> /** assignment.<br>
If the size of \a rhs is the same as the left-hand side arrays' s old size, only If the size of \a rhs is the same as the left-hand side arrays' s old size, only
skipping to change at line 2681 skipping to change at line 2705
{ {
view_type::operator/=(rhs); view_type::operator/=(rhs);
return *this; return *this;
} }
/** Assignment of an array expression. Fails with /** Assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArray & operator=(multi_math::MultiMathOperand<Expression> const & rhs) MultiArray & operator=(multi_math::MultiMathOperand<Expression> const & rhs)
{ {
multi_math::detail::assignOrResize(*this, rhs); multi_math::math_detail::assignOrResize(*this, rhs);
return *this; return *this;
} }
/** Add-assignment of an array expression. Fails with /** Add-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArray & operator+=(multi_math::MultiMathOperand<Expression> const & rhs) MultiArray & operator+=(multi_math::MultiMathOperand<Expression> const & rhs)
{ {
multi_math::detail::plusAssignOrResize(*this, rhs); multi_math::math_detail::plusAssignOrResize(*this, rhs);
return *this; return *this;
} }
/** Subtract-assignment of an array expression. Fails with /** Subtract-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArray & operator-=(multi_math::MultiMathOperand<Expression> const & rhs) MultiArray & operator-=(multi_math::MultiMathOperand<Expression> const & rhs)
{ {
multi_math::detail::minusAssignOrResize(*this, rhs); multi_math::math_detail::minusAssignOrResize(*this, rhs);
return *this; return *this;
} }
/** Multiply-assignment of an array expression. Fails with /** Multiply-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArray & operator*=(multi_math::MultiMathOperand<Expression> const & rhs) MultiArray & operator*=(multi_math::MultiMathOperand<Expression> const & rhs)
{ {
multi_math::detail::multiplyAssignOrResize(*this, rhs); multi_math::math_detail::multiplyAssignOrResize(*this, rhs);
return *this; return *this;
} }
/** Divide-assignment of an array expression. Fails with /** Divide-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template<class Expression> template<class Expression>
MultiArray & operator/=(multi_math::MultiMathOperand<Expression> const & rhs) MultiArray & operator/=(multi_math::MultiMathOperand<Expression> const & rhs)
{ {
multi_math::detail::divideAssignOrResize(*this, rhs); multi_math::math_detail::divideAssignOrResize(*this, rhs);
return *this; return *this;
} }
/** destructor /** destructor
*/ */
~MultiArray () ~MultiArray ()
{ {
deallocate (this->m_ptr, this->elementCount ()); deallocate (this->m_ptr, this->elementCount ());
} }
skipping to change at line 2747 skipping to change at line 2771
view_type::init(init); view_type::init(init);
return *this; return *this;
} }
/** Allocate new memory with the given shape and initialize with ze ros.<br> /** Allocate new memory with the given shape and initialize with ze ros.<br>
<em>Note:</em> this operation invalidates all dependent objects <em>Note:</em> this operation invalidates all dependent objects
(array views and iterators) (array views and iterators)
*/ */
void reshape (const difference_type &shape) void reshape (const difference_type &shape)
{ {
reshape (shape, T()); reshape (shape, value_type());
} }
/** Allocate new memory with the given shape and initialize it /** Allocate new memory with the given shape and initialize it
with the given value.<br> with the given value.<br>
<em>Note:</em> this operation invalidates all dependent objects <em>Note:</em> this operation invalidates all dependent objects
(array views and iterators) (array views and iterators)
*/ */
void reshape (const difference_type &shape, const_reference init); void reshape (const difference_type &shape, const_reference init);
/** Swap the contents with another MultiArray. This is fast, /** Swap the contents with another MultiArray. This is fast,
because no data are copied, but only pointers and shapes swappe d. because no data are copied, but only pointers and shapes swappe d.
<em>Note:</em> this operation invalidates all dependent objects <em>Note:</em> this operation invalidates all dependent objects
(array views and iterators) (array views and iterators)
*/ */
void swap (MultiArray & other); void swap (MultiArray & other);
/** sequential iterator pointing to the first array element. // /** sequential iterator pointing to the first array element.
*/ // */
iterator begin () // iterator begin ()
{ // {
return this->data(); // return vigra::detail::MultiIteratorChooser<actual_stride>::templ
} ate constructIterator<iterator>((view_type *)this);
// }
/** sequential iterator pointing beyond the last array element.
*/ // /** sequential iterator pointing beyond the last array element.
iterator end () // */
{ // iterator end ()
return this->data() + this->elementCount(); // {
} // return begin() + this->elementCount();
// }
/** sequential const iterator pointing to the first array element.
*/ // /** sequential const iterator pointing to the first array elemen
const_iterator begin () const t.
{ // */
return this->data(); // const_iterator begin () const
} // {
// return vigra::detail::MultiIteratorChooser<actual_stride>::templ
/** sequential const iterator pointing beyond the last array elemen ate constructIterator<iterator>((view_type const *)this);
t. // }
*/
const_iterator end () const // /** sequential const iterator pointing beyond the last array ele
{ ment.
return this->data() + this->elementCount(); // */
} // const_iterator end () const
// {
// return begin() + this->elementCount();
// }
/** get the allocator. /** get the allocator.
*/ */
allocator_type const & allocator () const allocator_type const & allocator () const
{ {
return m_alloc; return m_alloc;
} }
static difference_type defaultStride(difference_type const & shape)
{
return vigra::detail::ResolveMultiband<T>::defaultStride(shape);
}
}; };
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
MultiArray <N, T, A>::MultiArray (difference_type_1 length, MultiArray <N, T, A>::MultiArray (difference_type_1 length,
allocator_type const & alloc) allocator_type const & alloc)
: MultiArrayView <N, T> (difference_type(length), : view_type(difference_type(length),
detail::defaultStride <1> (difference_type(length) defaultStride(difference_type(length)),
), 0),
0), m_alloc(alloc)
{
allocate (this->m_ptr, this->elementCount (), value_type());
}
template <unsigned int N, class T, class A>
MultiArray <N, T, A>::MultiArray (difference_type_1 width, difference_type_
1 height,
allocator_type const & alloc)
: view_type(difference_type(width, height),
defaultStride(difference_type(width, height)),
0),
m_alloc(alloc) m_alloc(alloc)
{ {
allocate (this->m_ptr, this->elementCount (), T()); allocate (this->m_ptr, this->elementCount (), value_type());
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
MultiArray <N, T, A>::MultiArray (const difference_type &shape, MultiArray <N, T, A>::MultiArray (const difference_type &shape,
allocator_type const & alloc) allocator_type const & alloc)
: MultiArrayView <N, T> (shape, : view_type(shape,
detail::defaultStride <MultiArrayView<N,T>::actual defaultStride(shape),
_dimension> (shape), 0),
0),
m_alloc(alloc) m_alloc(alloc)
{ {
if (N == 0) if (N == 0)
{ {
this->m_shape [0] = 1; this->m_shape [0] = 1;
this->m_stride [0] = 0; this->m_stride [0] = 1;
} }
allocate (this->m_ptr, this->elementCount (), T()); allocate (this->m_ptr, this->elementCount (), value_type());
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_refer ence init, MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_refer ence init,
allocator_type const & alloc) allocator_type const & alloc)
: MultiArrayView <N, T> (shape, : view_type(shape,
detail::defaultStride <MultiArrayView<N,T>::actual defaultStride(shape),
_dimension> (shape), 0),
0),
m_alloc(alloc) m_alloc(alloc)
{ {
if (N == 0) if (N == 0)
{ {
this->m_shape [0] = 1; this->m_shape [0] = 1;
this->m_stride [0] = 0; this->m_stride [0] = 1;
} }
allocate (this->m_ptr, this->elementCount (), init); allocate (this->m_ptr, this->elementCount (), init);
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
MultiArray <N, T, A>::MultiArray (const difference_type &shape, MultiArrayI
nitializationTag init,
allocator_type const & alloc)
: view_type(shape,
defaultStride(shape),
0),
m_alloc(alloc)
{
if (N == 0)
{
this->m_shape [0] = 1;
this->m_stride [0] = 1;
}
allocate (this->m_ptr, this->elementCount (), value_type());
switch(init)
{
case LinearSequence:
linearSequence(this->begin(), this->end());
break;
default:
vigra_precondition(false,
"MultiArray(): invalid MultiArrayInitializationTag.");
}
}
template <unsigned int N, class T, class A>
MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_point er init, MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_point er init,
allocator_type const & alloc) allocator_type const & alloc)
: MultiArrayView <N, T> (shape, : view_type(shape,
detail::defaultStride <MultiArrayView<N,T>::actual defaultStride(shape),
_dimension> (shape), 0),
0),
m_alloc(alloc) m_alloc(alloc)
{ {
if (N == 0) if (N == 0)
{ {
this->m_shape [0] = 1; this->m_shape [0] = 1;
this->m_stride [0] = 0; this->m_stride [0] = 1;
} }
allocate (this->m_ptr, this->elementCount (), init); allocate (this->m_ptr, this->elementCount (), init);
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
template <class U, class StrideTag> template <class U, class StrideTag>
MultiArray <N, T, A>::MultiArray(const MultiArrayView<N, U, StrideTag> &rh s, MultiArray <N, T, A>::MultiArray(const MultiArrayView<N, U, StrideTag> &rh s,
allocator_type const & alloc) allocator_type const & alloc)
: MultiArrayView <N, T> (rhs.shape(), : view_type(rhs.shape(),
detail::defaultStride <MultiArrayView<N,T>::actual defaultStride(rhs.shape()),
_dimension>(rhs.shape()), 0),
0),
m_alloc (alloc) m_alloc (alloc)
{ {
allocate (this->m_ptr, rhs); allocate (this->m_ptr, rhs);
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
template <class U, class StrideTag> template <class U, class StrideTag>
void void
MultiArray <N, T, A>::copyOrReshape(const MultiArrayView<N, U, StrideTag> & rhs) MultiArray <N, T, A>::copyOrReshape(const MultiArrayView<N, U, StrideTag> & rhs)
{ {
skipping to change at line 2889 skipping to change at line 2954
{ {
MultiArray t(rhs); MultiArray t(rhs);
this->swap(t); this->swap(t);
} }
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
void MultiArray <N, T, A>::reshape (const difference_type & new_shape, void MultiArray <N, T, A>::reshape (const difference_type & new_shape,
const_reference initial) const_reference initial)
{ {
if (N== 0) if (N == 0)
{ {
return; return;
} }
else if(new_shape == this->shape()) else if(new_shape == this->shape())
{ {
this->init(initial); this->init(initial);
} }
else else
{ {
difference_type new_stride = detail::defaultStride <MultiArrayView< difference_type new_stride = defaultStride(new_shape);
N,T>::actual_dimension> (new_shape); difference_type_1 new_size = prod(new_shape);
difference_type_1 new_size = new_shape [MultiArrayView<N,T>::actual pointer new_ptr = pointer();
_dimension-1] * new_stride [MultiArrayView<N,T>::actual_dimension-1];
T *new_ptr;
allocate (new_ptr, new_size, initial); allocate (new_ptr, new_size, initial);
deallocate (this->m_ptr, this->elementCount ()); deallocate (this->m_ptr, this->elementCount ());
this->m_ptr = new_ptr; this->m_ptr = new_ptr;
this->m_shape = new_shape; this->m_shape = new_shape;
this->m_stride = new_stride; this->m_stride = new_stride;
} }
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
inline void inline void
skipping to change at line 2926 skipping to change at line 2991
std::swap(this->m_shape, other.m_shape); std::swap(this->m_shape, other.m_shape);
std::swap(this->m_stride, other.m_stride); std::swap(this->m_stride, other.m_stride);
std::swap(this->m_ptr, other.m_ptr); std::swap(this->m_ptr, other.m_ptr);
std::swap(this->m_alloc, other.m_alloc); std::swap(this->m_alloc, other.m_alloc);
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s, void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s,
const_reference init) const_reference init)
{ {
if(s == 0)
{
ptr = 0;
return;
}
ptr = m_alloc.allocate ((typename A::size_type)s); ptr = m_alloc.allocate ((typename A::size_type)s);
difference_type_1 i; difference_type_1 i = 0;
try { try {
for (i = 0; i < s; ++i) for (; i < s; ++i)
m_alloc.construct (ptr + i, init); m_alloc.construct (ptr + i, init);
} }
catch (...) { catch (...) {
for (difference_type_1 j = 0; j < i; ++j) for (difference_type_1 j = 0; j < i; ++j)
m_alloc.destroy (ptr + j); m_alloc.destroy (ptr + j);
m_alloc.deallocate (ptr, (typename A::size_type)s); m_alloc.deallocate (ptr, (typename A::size_type)s);
throw; throw;
} }
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
template <class U> template <class U>
void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s, void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s,
U const * init) U const * init)
{ {
if(s == 0)
{
ptr = 0;
return;
}
ptr = m_alloc.allocate ((typename A::size_type)s); ptr = m_alloc.allocate ((typename A::size_type)s);
difference_type_1 i; difference_type_1 i = 0;
try { try {
for (i = 0; i < s; ++i, ++init) for (; i < s; ++i, ++init)
m_alloc.construct (ptr + i, *init); m_alloc.construct (ptr + i, *init);
} }
catch (...) { catch (...) {
for (difference_type_1 j = 0; j < i; ++j) for (difference_type_1 j = 0; j < i; ++j)
m_alloc.destroy (ptr + j); m_alloc.destroy (ptr + j);
m_alloc.deallocate (ptr, (typename A::size_type)s); m_alloc.deallocate (ptr, (typename A::size_type)s);
throw; throw;
} }
} }
template <unsigned int N, class T, class A> template <unsigned int N, class T, class A>
template <class U, class StrideTag> template <class U, class StrideTag>
void MultiArray <N, T, A>::allocate (pointer & ptr, MultiArrayView<N, U, St rideTag> const & init) void MultiArray <N, T, A>::allocate (pointer & ptr, MultiArrayView<N, U, St rideTag> const & init)
{ {
difference_type_1 s = init.elementCount(); difference_type_1 s = init.elementCount();
if(s == 0)
{
ptr = 0;
return;
}
ptr = m_alloc.allocate ((typename A::size_type)s); ptr = m_alloc.allocate ((typename A::size_type)s);
pointer p = ptr; pointer p = ptr;
try { try {
detail::uninitializedCopyMultiArrayData(init.traverser_begin(), ini t.shape(), detail::uninitializedCopyMultiArrayData(init.traverser_begin(), ini t.shape(),
p, m_alloc, MetaInt<actual_ dimension-1>()); p, m_alloc, MetaInt<actual_ dimension-1>());
} }
catch (...) { catch (...) {
for (pointer pp = ptr; pp < p; ++pp) for (pointer pp = ptr; pp < p; ++pp)
m_alloc.destroy (pp); m_alloc.destroy (pp);
m_alloc.deallocate (ptr, (typename A::size_type)s); m_alloc.deallocate (ptr, (typename A::size_type)s);
skipping to change at line 3291 skipping to change at line 3371
return pair<ConstImageIterator<PixelType>, Accessor> return pair<ConstImageIterator<PixelType>, Accessor>
(ul, Accessor()); (ul, Accessor());
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* makeBasicImageView */ /* makeBasicImageView */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup MultiArrayToImage Wrap a \ref vigra::MultiArrayView in /** \addtogroup MultiArrayToImage Create BasicImageView from MultiArrayView
a \ref vigra::BasicImageView s
Some convenience functions for wrapping a \ref vigra::MultiArrayView's
data in a \ref vigra::BasicImageView.
*/ */
//@{ //@{
/** Create a \ref vigra::BasicImageView from an unstrided 2-dimensional /** Create a \ref vigra::BasicImageView from an unstrided 2-dimensional
\ref vigra::MultiArrayView. \ref vigra::MultiArrayView.
The \ref vigra::BasicImageView will have the same <tt>value_type </tt> The \ref vigra::BasicImageView will have the same <tt>value_type </tt>
as the original \ref vigra::MultiArrayView. as the original \ref vigra::MultiArrayView.
*/ */
template <class T> template <class T, class Stride>
BasicImageView <T> BasicImageView <T>
makeBasicImageView (MultiArrayView <2, T, UnstridedArrayTag> const &array) makeBasicImageView (MultiArrayView <2, T, Stride> const &array)
{ {
vigra_precondition(array.isUnstrided(),
"makeBasicImageView(array): array must be unstrided (i.e. array.isUn
strided() == true).");
return BasicImageView <T> (array.data (), array.shape (0), return BasicImageView <T> (array.data (), array.shape (0),
array.shape (1)); array.shape (1), array.stride(1));
} }
/** Create a \ref vigra::BasicImageView from a 3-dimensional /** Create a \ref vigra::BasicImageView from a 3-dimensional
\ref vigra::MultiArray. \ref vigra::MultiArray.
This wrapper flattens the two innermost dimensions of the array This wrapper flattens the two innermost dimensions of the array
into single rows of the resulting image. into single rows of the resulting image.
The \ref vigra::BasicImageView will have the same <tt>value_type </tt> The \ref vigra::BasicImageView will have the same <tt>value_type </tt>
as the original \ref vigra::MultiArray. as the original \ref vigra::MultiArray.
*/ */
template <class T> template <class T>
BasicImageView <T> BasicImageView <T>
makeBasicImageView (MultiArray <3, T> const &array) makeBasicImageView (MultiArray <3, T> const &array)
{ {
vigra_precondition(array.stride(1) == array.shape(0),
"makeBasicImageView(): cannot join strided dimensions");
return BasicImageView <T> (array.data (), return BasicImageView <T> (array.data (),
array.shape (0)*array.shape (1), array.shape (2)); array.shape (0)*array.shape (1), array.shape (2), array.stride(2));
} }
/** Create a \ref vigra::BasicImageView from a 3-dimensional /** Create a \ref vigra::BasicImageView from a 3-dimensional
\ref vigra::MultiArray. \ref vigra::MultiArray.
This wrapper only works if <tt>T</tt> is a scalar type and the This wrapper only works if <tt>T</tt> is a scalar type and the
array's innermost dimension has size 3. It then re-interprets array's innermost dimension has size 3. It then re-interprets
the data array as a 2-dimensional array with value_type the data array as a 2-dimensional array with value_type
<tt>RGBValue<T></tt>. <tt>RGBValue<T></tt>.
*/ */
template <class T> template <class T, class Stride>
BasicImageView <RGBValue<T> > BasicImageView <RGBValue<T> >
makeRGBImageView (MultiArray<3, T> const &array) makeRGBImageView (MultiArrayView<3, T, Stride> const &array)
{ {
vigra_precondition ( vigra_precondition(array.shape (0) == 3,
array.shape (0) == 3, "makeRGBImageView(): array.shape(0) must be 3 "makeRGBImageView(): array.shape(0) must be 3.");
."); vigra_precondition(array.isUnstrided(),
"makeRGBImageView(array): array must be unstrided (i.e. array.isUnst
rided() == true).");
return BasicImageView <RGBValue<T> > ( return BasicImageView <RGBValue<T> > (
reinterpret_cast <RGBValue <T> *> (array.data ()), reinterpret_cast <RGBValue <T> *> (array.data ()),
array.shape (1), array.shape (2)); array.shape (1), array.shape (2));
} }
//@} //@}
} // namespace vigra } // namespace vigra
#undef VIGRA_ASSERT_INSIDE #undef VIGRA_ASSERT_INSIDE
 End of changes. 132 change blocks. 
358 lines changed or deleted 462 lines changed or added


 multi_convolution.hxx   multi_convolution.hxx 
skipping to change at line 49 skipping to change at line 49
#define VIGRA_MULTI_CONVOLUTION_H #define VIGRA_MULTI_CONVOLUTION_H
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "accessor.hxx" #include "accessor.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "navigator.hxx" #include "navigator.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "multi_pointoperators.hxx" #include "multi_pointoperators.hxx"
#include "multi_math.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "algorithm.hxx" #include "algorithm.hxx"
#include <iostream>
namespace vigra namespace vigra
{ {
namespace detail namespace detail
{ {
struct DoubleYielder struct DoubleYielder
{ {
const double value; const double value;
DoubleYielder(double v, unsigned, const char *const) : value(v) {} DoubleYielder(double v, unsigned, const char *const) : value(v) {}
skipping to change at line 125 skipping to change at line 128
: sigma_eff_it(sigma_eff), sigma_d_it(sigma_d), step_size_it(step_s ize) {} : sigma_eff_it(sigma_eff), sigma_d_it(sigma_d), step_size_it(step_s ize) {}
void operator++() void operator++()
{ {
++sigma_eff_it; ++sigma_eff_it;
++sigma_d_it; ++sigma_d_it;
++step_size_it; ++step_size_it;
} }
double sigma_eff() const { return *sigma_eff_it; } double sigma_eff() const { return *sigma_eff_it; }
double sigma_d() const { return *sigma_d_it; } double sigma_d() const { return *sigma_d_it; }
double step_size() const { return *step_size_it; } double step_size() const { return *step_size_it; }
static double sqr(double x) { return x * x; }
static void sigma_precondition(double sigma, const char *const function _name) static void sigma_precondition(double sigma, const char *const function _name)
{ {
if (sigma < 0.0) if (sigma < 0.0)
{ {
std::string msg = "(): Scale must be positive."; std::string msg = "(): Scale must be positive.";
vigra_precondition(false, function_name + msg); vigra_precondition(false, function_name + msg);
} }
} }
double sigma_scaled(const char *const function_name = "unknown function ") const double sigma_scaled(const char *const function_name = "unknown function ") const
{ {
sigma_precondition(sigma_eff(), function_name); sigma_precondition(sigma_eff(), function_name);
sigma_precondition(sigma_d(), function_name); sigma_precondition(sigma_d(), function_name);
double sigma_squared = sqr(sigma_eff()) - sqr(sigma_d()); double sigma_squared = sq(sigma_eff()) - sq(sigma_d());
if (sigma_squared > 0.0) if (sigma_squared > 0.0)
{ {
return std::sqrt(sigma_squared) / step_size(); return std::sqrt(sigma_squared) / step_size();
} }
else else
{ {
std::string msg = "(): Scale would be imaginary or zero."; std::string msg = "(): Scale would be imaginary or zero.";
vigra_precondition(false, function_name + msg); vigra_precondition(false, function_name + msg);
return 0; return 0;
} }
skipping to change at line 201 skipping to change at line 203
} }
multiArrayScaleParam(double v0, double v1, double v2, double v3, doubl e v4, const char *const function_name = "multiArrayScaleParam") multiArrayScaleParam(double v0, double v1, double v2, double v3, doubl e v4, const char *const function_name = "multiArrayScaleParam")
{ {
precondition(5, function_name); precondition(5, function_name);
vec = p_vector(v0, v1, v2, v3, v4); vec = p_vector(v0, v1, v2, v3, v4);
} }
}; };
} // namespace detail } // namespace detail
#define VIGRA_CONVOLUTION_OPTIONS(function_name, default_value, member_name ) \ #define VIGRA_CONVOLUTION_OPTIONS(function_name, default_value, member_name , getter_setter_name) \
template <class Param> \ template <class Param> \
ConvolutionOptions & function_name(const Param & val) \ ConvolutionOptions & function_name(const Param & val) \
{ \ { \
member_name = ParamVec(val, "ConvolutionOptions::" #function_name); \ member_name = ParamVec(val, "ConvolutionOptions::" #function_name); \
return *this; \ return *this; \
} \ } \
ConvolutionOptions & function_name() \ ConvolutionOptions & function_name() \
{ \ { \
member_name = ParamVec(default_value, "ConvolutionOptions::" #funct ion_name); \ member_name = ParamVec(default_value, "ConvolutionOptions::" #funct ion_name); \
return *this; \ return *this; \
skipping to change at line 232 skipping to change at line 234
} \ } \
ConvolutionOptions & function_name(double v0, double v1, double v2, dou ble v3) \ ConvolutionOptions & function_name(double v0, double v1, double v2, dou ble v3) \
{ \ { \
member_name = ParamVec(v0, v1, v2, v3, "ConvolutionOptions::" #func tion_name); \ member_name = ParamVec(v0, v1, v2, v3, "ConvolutionOptions::" #func tion_name); \
return *this; \ return *this; \
} \ } \
ConvolutionOptions & function_name(double v0, double v1, double v2, dou ble v3, double v4) \ ConvolutionOptions & function_name(double v0, double v1, double v2, dou ble v3, double v4) \
{ \ { \
member_name = ParamVec(v0, v1, v2, v3, v4, "ConvolutionOptions::" # function_name); \ member_name = ParamVec(v0, v1, v2, v3, v4, "ConvolutionOptions::" # function_name); \
return *this; \ return *this; \
} \
typename ParamVec::p_vector get##getter_setter_name()const{ \
return member_name.vec; \
} \
void set##getter_setter_name(typename ParamVec::p_vector vec){ \
member_name.vec = vec; \
} }
/** \brief Options class template for convolutions. /** \brief Options class template for convolutions.
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
This class enables the calculation of scale space convolutions This class enables the calculation of scale space convolutions
such as \ref gaussianGradientMultiArray() on data with anisotropic such as \ref gaussianGradientMultiArray() on data with anisotropic
discretization. For these, the result of the ordinary calculation discretization. For these, the result of the ordinary calculation
has to be multiplied by factors of \f$1/w^{n}\f$ for each dimension, has to be multiplied by factors of \f$1/w^{n}\f$ for each dimension,
where \f$w\f$ is the step size of the grid in said dimension and where \f$w\f$ is the step size of the grid in said dimension and
\f$n\f$ is the differential order of the convolution, e.g., 1 for \f$n\f$ is the differential order of the convolution, e.g., 1 for
gaussianGradientMultiArray(), and 0 for gaussianSmoothMultiArray(), gaussianGradientMultiArray(), and 0 for gaussianSmoothMultiArray(),
respectively. Also for each dimension in turn, the convolution's scale respectively. Also for each dimension in turn, the convolution's scale
parameter \f$\sigma\f$ has to be replaced by parameter \f$\sigma\f$ has to be replaced by
skipping to change at line 311 skipping to change at line 320
ArrayVector<double>::iterator i = step_size.begin(); ArrayVector<double>::iterator i = step_size.begin();
++i; ++i;
ConvolutionOptions<2> opt = ConvolutionOptions<2>().stepSize(i); ConvolutionOptions<2> opt = ConvolutionOptions<2>().stepSize(i);
\endcode \endcode
<b>general usage in a convolution function call:</b> <b>general usage in a convolution function call:</b>
\code \code
MultiArray<3, double> test_image; MultiArray<3, double> test_image;
MultiArray<3, double> out_image; MultiArray<3, double> out_image;
gaussianSmoothMultiArray(srcMultiArrayRange(test_image),
destMultiArray(out_image), double scale = 5.0;
5.0, gaussianSmoothMultiArray(test_image, out_image, scale,
ConvolutionOptions<3>() ConvolutionOptions<3>()
.stepSize (1, 1, 3.2) .stepSize (1, 1, 3.2)
.resolutionStdDev(1, 1, 4) .resolutionStdDev(1, 1, 4)
); );
\endcode \endcode
*/ */
template <unsigned dim> template <unsigned dim>
class ConvolutionOptions class ConvolutionOptions
{ {
skipping to change at line 367 skipping to change at line 376
ConvolutionOptions outerOptions() const ConvolutionOptions outerOptions() const
{ {
ConvolutionOptions outer = *this; ConvolutionOptions outer = *this;
// backward-compatible values: // backward-compatible values:
return outer.stdDev(outer_scale()).resolutionStdDev(0.0); return outer.stdDev(outer_scale()).resolutionStdDev(0.0);
} }
// Step size per axis. // Step size per axis.
// Default: dim values of 1.0 // Default: dim values of 1.0
VIGRA_CONVOLUTION_OPTIONS(stepSize, 1.0, step_size) VIGRA_CONVOLUTION_OPTIONS(stepSize, 1.0, step_size, StepSize)
#ifdef DOXYGEN #ifdef DOXYGEN
/** Step size(s) per axis, i.e., the distance between two /** Step size(s) per axis, i.e., the distance between two
adjacent pixels. Required for <tt>MultiArray</tt> adjacent pixels. Required for <tt>MultiArray</tt>
containing anisotropic data. containing anisotropic data.
Note that a convolution containing a derivative operator Note that a convolution containing a derivative operator
of order <tt>n</tt> results in a multiplication by of order <tt>n</tt> results in a multiplication by
\f${\rm stepSize}^{-n}\f$ for each axis. \f${\rm stepSize}^{-n}\f$ for each axis.
Also, the above standard deviations Also, the above standard deviations
are scaled according to the step size of each axis. are scaled according to the step size of each axis.
Default value for the options object if this member function is not Default value for the options object if this member function is not
used: A value of 1.0 for each dimension. used: A value of 1.0 for each dimension.
*/ */
ConvolutionOptions<dim> & stepSize(...); ConvolutionOptions<dim> & stepSize(...);
#endif #endif
// Resolution standard deviation per axis. // Resolution standard deviation per axis.
// Default: dim values of 0.0 // Default: dim values of 0.0
VIGRA_CONVOLUTION_OPTIONS(resolutionStdDev, 0.0, sigma_d) VIGRA_CONVOLUTION_OPTIONS(resolutionStdDev, 0.0, sigma_d, ResolutionStd Dev)
#ifdef DOXYGEN #ifdef DOXYGEN
/** Resolution standard deviation(s) per axis, i.e., a supposed /** Resolution standard deviation(s) per axis, i.e., a supposed
pre-existing gaussian filtering by this value. pre-existing gaussian filtering by this value.
The standard deviation actually used by the convolution operato rs The standard deviation actually used by the convolution operato rs
is \f$\sqrt{{\rm sigma}^{2} - {\rm resolutionStdDev}^{2}}\f$ fo r each is \f$\sqrt{{\rm sigma}^{2} - {\rm resolutionStdDev}^{2}}\f$ fo r each
axis. axis.
Default value for the options object if this member function is not Default value for the options object if this member function is not
used: A value of 0.0 for each dimension. used: A value of 0.0 for each dimension.
*/ */
ConvolutionOptions<dim> & resolutionStdDev(...); ConvolutionOptions<dim> & resolutionStdDev(...);
#endif #endif
// Standard deviation of scale space operators. // Standard deviation of scale space operators.
// Default: dim values of 0.0 // Default: dim values of 0.0
VIGRA_CONVOLUTION_OPTIONS(stdDev, 0.0, sigma_eff) VIGRA_CONVOLUTION_OPTIONS(stdDev, 0.0, sigma_eff, StdDev)
VIGRA_CONVOLUTION_OPTIONS(innerScale, 0.0, sigma_eff) VIGRA_CONVOLUTION_OPTIONS(innerScale, 0.0, sigma_eff, InnerScale)
#ifdef DOXYGEN #ifdef DOXYGEN
/** Standard deviation(s) of scale space operators, or inner scale( s) for \ref structureTensorMultiArray(). /** Standard deviation(s) of scale space operators, or inner scale( s) for \ref structureTensorMultiArray().
Usually not Usually not
needed, since a single value for all axes may be specified as a parameter needed, since a single value for all axes may be specified as a parameter
<tt>sigma</tt> to the call of <tt>sigma</tt> to the call of
an convolution operator such as \ref gaussianGradientMultiArray (), and an convolution operator such as \ref gaussianGradientMultiArray (), and
anisotropic data requiring the use of the stepSize() member fun ction. anisotropic data requiring the use of the stepSize() member fun ction.
Default value for the options object if this member function is not Default value for the options object if this member function is not
skipping to change at line 433 skipping to change at line 442
an convolution operator such as \ref gaussianGradientMultiArray (), and an convolution operator such as \ref gaussianGradientMultiArray (), and
anisotropic data requiring the use of the stepSize() member fun ction. anisotropic data requiring the use of the stepSize() member fun ction.
Default value for the options object if this member function is not Default value for the options object if this member function is not
used: A value of 0.0 for each dimension. used: A value of 0.0 for each dimension.
*/ */
ConvolutionOptions<dim> & innerScale(...); ConvolutionOptions<dim> & innerScale(...);
#endif #endif
// Outer scale, for structure tensor. // Outer scale, for structure tensor.
// Default: dim values of 0.0 // Default: dim values of 0.0
VIGRA_CONVOLUTION_OPTIONS(outerScale, 0.0, outer_scale) VIGRA_CONVOLUTION_OPTIONS(outerScale, 0.0, outer_scale, OuterScale)
#ifdef DOXYGEN #ifdef DOXYGEN
/** Standard deviation(s) of the second convolution of the /** Standard deviation(s) of the second convolution of the
structure tensor. structure tensor.
Usually not needed, since a single value for Usually not needed, since a single value for
all axes may be specified as a parameter <tt>outerScale</tt> to all axes may be specified as a parameter <tt>outerScale</tt> to
the call of \ref structureTensorMultiArray(), and the call of \ref structureTensorMultiArray(), and
anisotropic data requiring the use of the stepSize() member anisotropic data requiring the use of the stepSize() member
function. function.
Default value for the options object if this member function is not Default value for the options object if this member function is not
skipping to change at line 471 skipping to change at line 480
Default: <tt>0.0</tt> (i.e. determine the window size automatic ally) Default: <tt>0.0</tt> (i.e. determine the window size automatic ally)
*/ */
ConvolutionOptions<dim> & filterWindowSize(double ratio) ConvolutionOptions<dim> & filterWindowSize(double ratio)
{ {
vigra_precondition(ratio >= 0.0, vigra_precondition(ratio >= 0.0,
"ConvolutionOptions::filterWindowSize(): ratio must not be nega tive."); "ConvolutionOptions::filterWindowSize(): ratio must not be nega tive.");
window_ratio = ratio; window_ratio = ratio;
return *this; return *this;
} }
double getFilterWindowSize() const {
return window_ratio;
}
/** Restrict the filter to a subregion of the input array. /** Restrict the filter to a subregion of the input array.
This is useful for speeding up computations by ignoring irrelev ant This is useful for speeding up computations by ignoring irrelev ant
areas in the array. <b>Note:</b> It is assumed that the output array areas in the array. <b>Note:</b> It is assumed that the output array
of the convolution has the size given in this function. of the convolution has the size given in this function. Negati
ve ROI
boundaries are interpreted relative to the end of the respectiv
e dimension
(i.e. <tt>if(to[k] < 0) to[k] += source.shape(k);</tt>).
Default: <tt>from = Shape(), to = Shape()</tt> (i.e. use entire array) Default: <tt>from = Shape(), to = Shape()</tt> (i.e. use entire array)
*/ */
ConvolutionOptions<dim> & subarray(Shape const & from, Shape const & to ) ConvolutionOptions<dim> & subarray(Shape const & from, Shape const & to )
{ {
from_point = from; from_point = from;
to_point = to; to_point = to;
return *this; return *this;
} }
std::pair<Shape, Shape> getSubarray()const{
std::pair<Shape, Shape> res;
res.first = from_point;
res.second = to_point;
return res;
}
}; };
namespace detail namespace detail
{ {
/********************************************************/ /********************************************************/
/* */ /* */
/* internalSeparableConvolveMultiArray */ /* internalSeparableConvolveMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 577 skipping to change at line 599
typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType;
typedef MultiArray<N, TmpType> TmpArray; typedef MultiArray<N, TmpType> TmpArray;
typedef typename TmpArray::traverser TmpIterator; typedef typename TmpArray::traverser TmpIterator;
typedef typename AccessorTraits<TmpType>::default_accessor TmpAcessor; typedef typename AccessorTraits<TmpType>::default_accessor TmpAcessor;
SrcShape sstart, sstop, axisorder, tmpshape; SrcShape sstart, sstop, axisorder, tmpshape;
TinyVector<double, N> overhead; TinyVector<double, N> overhead;
for(int k=0; k<N; ++k) for(int k=0; k<N; ++k)
{ {
axisorder[k] = k;
sstart[k] = start[k] - kit[k].right(); sstart[k] = start[k] - kit[k].right();
if(sstart[k] < 0) if(sstart[k] < 0)
sstart[k] = 0; sstart[k] = 0;
sstop[k] = stop[k] - kit[k].left(); sstop[k] = stop[k] - kit[k].left();
if(sstop[k] > shape[k]) if(sstop[k] > shape[k])
sstop[k] = shape[k]; sstop[k] = shape[k];
overhead[k] = double(sstop[k] - sstart[k]) / (stop[k] - start[k]); overhead[k] = double(sstop[k] - sstart[k]) / (stop[k] - start[k]);
} }
indexSort(overhead.begin(), overhead.end(), axisorder.begin(), std::gre ater<double>()); indexSort(overhead.begin(), overhead.end(), axisorder.begin(), std::gre ater<double>());
SrcShape dstart, dstop(sstop - sstart); SrcShape dstart, dstop(sstop - sstart);
dstop[axisorder[0]] = stop[axisorder[0]] - start[axisorder[0]]; dstop[axisorder[0]] = stop[axisorder[0]] - start[axisorder[0]];
// temporary array to hold the current line to enable in-place operatio n // temporary array to hold the current line to enable in-place operatio n
MultiArray<N, TmpType> tmp(dstop); MultiArray<N, TmpType> tmp(dstop);
typedef MultiArrayNavigator<SrcIterator, N> SNavigator; typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<TmpIterator, N> TNavigator; typedef MultiArrayNavigator<TmpIterator, N> TNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator;
TmpAcessor acc; TmpAcessor acc;
{ {
// only operate on first dimension here // only operate on first dimension here
SNavigator snav( si, sstart, sstop, axisorder[0]); SNavigator snav( si, sstart, sstop, axisorder[0]);
TNavigator tnav( tmp.traverser_begin(), dstart, dstop, axisorder[0] ); TNavigator tnav( tmp.traverser_begin(), dstart, dstop, axisorder[0] );
ArrayVector<TmpType> tmpline(sstop[axisorder[0]] - sstart[axisorder [0]]); ArrayVector<TmpType> tmpline(sstop[axisorder[0]] - sstart[axisorder [0]]);
skipping to change at line 685 skipping to change at line 706
This function computes a separated convolution on all dimensions This function computes a separated convolution on all dimensions
of the given multi-dimensional array. Both source and destination of the given multi-dimensional array. Both source and destination
arrays are represented by iterators, shape objects and accessors. arrays are represented by iterators, shape objects and accessors.
The destination array is required to already have the correct size. The destination array is required to already have the correct size.
There are two variants of this functions: one takes a single kernel There are two variants of this functions: one takes a single kernel
of type \ref vigra::Kernel1D which is then applied to all dimensions, of type \ref vigra::Kernel1D which is then applied to all dimensions,
whereas the other requires an iterator referencing a sequence of whereas the other requires an iterator referencing a sequence of
\ref vigra::Kernel1D objects, one for every dimension of the data. \ref vigra::Kernel1D objects, one for every dimension of the data.
Then the first kernel in this sequence is applied to the innermost Then the first kernel in this sequence is applied to the innermost
dimension (e.g. the x-dimension of an image), while the last is applied dimension (e.g. the x-axis of an image), while the last is applied to t
to the he
outermost dimension (e.g. the z-dimension in a 3D image). outermost dimension (e.g. the z-axis in a 3D image).
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>source.data() == dest.data()</tt> is allowed.
A full-sized internal array is only allocated if working on the destina tion A full-sized internal array is only allocated if working on the destina tion
array directly would cause round-off errors (i.e. if array directly would cause round-off errors (i.e. if
<tt>typeid(typename NumericTraits<typename DestAccessor::value_type>::R <tt>typeid(typename NumericTraits<T2>::RealPromote) != typeid(T2)</tt>)
ealPromote) .
!= typeid(typename DestAccessor::value_type)</tt>.
If <tt>start</tt> and <tt>stop</tt> have non-default values, they must represent If <tt>start</tt> and <tt>stop</tt> have non-default values, they must represent
a valid subarray of the input array. The convolution is then restricted to that a valid subarray of the input array. The convolution is then restricted to that
subarray, and it is assumed that the output array only refers to the subarray, and it is assumed that the output array only refers to the
subarray (i.e. <tt>diter</tt> points to the element corresponding to subarray (i.e. <tt>dest.shape() == stop - start</tt>). Negative ROI bou
<tt>start</tt>). ndaries are
interpreted relative to the end of the respective dimension
(i.e. <tt>if(stop[k] < 0) stop[k] += source.shape(k);</tt>).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// apply each kernel from the sequence 'kernels' in turn
template <unsigned int N, class T1, class S1,
class T2, class S2,
class KernelIterator>
void
separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, T2, S2> dest,
KernelIterator kernels,
typename MultiArrayShape<N>::type start
= typename MultiArrayShape<N>::type(),
typename MultiArrayShape<N>::type stop
= typename MultiArrayShape<N>::type());
// apply the same kernel to all dimensions
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T>
void
separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, T2, S2> dest,
Kernel1D<T> const & kernel,
typename MultiArrayShape<N>::type const
& start = typename MultiArrayShape<N>::type(),
typename MultiArrayShape<N>::type const
& stop = typename MultiArrayShape<N>::type());
}
\endcode
\deprecatedAPI{separableConvolveMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// apply the same kernel to all dimensions // apply the same kernel to all dimensions
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
void void
separableConvolveMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src, separableConvolveMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
Kernel1D<T> const & kernel, Kernel1D<T> const & kernel,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
skipping to change at line 726 skipping to change at line 775
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class KernelItera tor> class DestIterator, class DestAccessor, class KernelItera tor>
void void
separableConvolveMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src, separableConvolveMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
KernelIterator kernels, KernelIterator kernels,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()); SrcShape const & stop = SrcShape());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// apply the same kernel to all dimensions // apply the same kernel to all dimensions
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
void void
separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source, separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
Kernel1D<T> const & kernel, Kernel1D<T> const & kernel,
skipping to change at line 751 skipping to change at line 799
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class KernelItera tor> class DestIterator, class DestAccessor, class KernelItera tor>
void void
separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source, separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
KernelIterator kernels, KernelIterator kernels,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()); SrcShape const & stop = SrcShape());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape);
...
Kernel1D<float> gauss;
gauss.initGaussian(sigma);
// smooth all dimensions with the same kernel
separableConvolveMultiArray(source, dest, gauss);
// create 3 Gauss kernels, one for each dimension, but smooth the z-axi
s less
ArrayVector<Kernel1D<float> > kernels(3, gauss);
kernels[2].initGaussian(sigma / 2.0);
// perform Gaussian smoothing on all dimensions
separableConvolveMultiArray(source, dest, kernels.begin());
// create output array for a ROI
MultiArray<3, float> destROI(shape - Shape3(10,10,10));
// only smooth the given ROI (ignore 5 pixels on all sides of the array
)
separableConvolveMultiArray(source, destROI, gauss, Shape3(5,5,5), Shap
e3(-5,-5,-5));
\endcode
\deprecatedUsage{separableConvolveMultiArray}
\code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); MultiArray<3, unsigned char>::size_type shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape); MultiArray<3, float> dest(shape);
... ...
Kernel1D<float> gauss; Kernel1D<float> gauss;
gauss.initGaussian(sigma); gauss.initGaussian(sigma);
// create 3 Gauss kernels, one for each dimension // create 3 Gauss kernels, one for each dimension
ArrayVector<Kernel1D<float> > kernels(3, gauss); ArrayVector<Kernel1D<float> > kernels(3, gauss);
// perform Gaussian smoothing on all dimensions // perform Gaussian smoothing on all dimensions
separableConvolveMultiArray(srcMultiArrayRange(source), destMultiArray( dest), separableConvolveMultiArray(source, dest,
kernels.begin()); kernels.begin());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code
see \ref separableConvolveImage(), in addition:
see \ref separableConvolveMultiArray(), in addition: NumericTraits<T1>::RealPromote s = src[0];
\code s = s + s;
int dimension = 0; s = kernel(0) * s;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode \endcode
\deprecatedEnd
\see vigra::Kernel1D, convolveLine() \see vigra::Kernel1D, convolveLine()
*/ */
doxygen_overloaded_function(template <...> void separableConvolveMultiArray ) doxygen_overloaded_function(template <...> void separableConvolveMultiArray )
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class KernelIterator> class DestIterator, class DestAccessor, class KernelIterator>
void void
separableConvolveMultiArray( SrcIterator s, SrcShape const & shape, SrcAcce ssor src, separableConvolveMultiArray( SrcIterator s, SrcShape const & shape, SrcAcce ssor src,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
KernelIterator kernels, KernelIterator kernels,
SrcShape const & start = SrcShape(), SrcShape start = SrcShape(),
SrcShape const & stop = SrcShape()) SrcShape stop = SrcShape())
{ {
typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType;
if(stop != SrcShape()) if(stop != SrcShape())
{ {
enum { N = 1 + SrcIterator::level }; enum { N = 1 + SrcIterator::level };
detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, start);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, stop);
for(int k=0; k<N; ++k) for(int k=0; k<N; ++k)
vigra_precondition(0 <= start[k] && start[k] < stop[k] && stop[ k] <= shape[k], vigra_precondition(0 <= start[k] && start[k] < stop[k] && stop[ k] <= shape[k],
"separableConvolveMultiArray(): invalid subarray shape."); "separableConvolveMultiArray(): invalid subarray shape.");
detail::internalSeparableConvolveSubarray(s, shape, src, d, dest, k ernels, start, stop); detail::internalSeparableConvolveSubarray(s, shape, src, d, dest, k ernels, start, stop);
} }
else if(!IsSameType<TmpType, typename DestAccessor::value_type>::boolRe sult) else if(!IsSameType<TmpType, typename DestAccessor::value_type>::boolRe sult)
{ {
// need a temporary array to avoid rounding errors // need a temporary array to avoid rounding errors
MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); MultiArray<SrcShape::static_size, TmpType> tmpArray(shape);
skipping to change at line 820 skipping to change at line 901
copyMultiArray(srcMultiArrayRange(tmpArray), destIter(d, dest)); copyMultiArray(srcMultiArrayRange(tmpArray), destIter(d, dest));
} }
else else
{ {
// work directly on the destination array // work directly on the destination array
detail::internalSeparableConvolveMultiArrayTmp( s, shape, src, d, d est, kernels ); detail::internalSeparableConvolveMultiArrayTmp( s, shape, src, d, d est, kernels );
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class KernelIterator>
inline
void separableConvolveMultiArray(
triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest,
KernelIterator kit,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape())
{
separableConvolveMultiArray( source.first, source.second, source.third,
dest.first, dest.second, kit, start, stop
);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
inline void inline void
separableConvolveMultiArray( SrcIterator s, SrcShape const & shape, SrcAcce ssor src, separableConvolveMultiArray( SrcIterator s, SrcShape const & shape, SrcAcce ssor src,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
Kernel1D<T> const & kernel, Kernel1D<T> const & kernel,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()) SrcShape const & stop = SrcShape())
{ {
ArrayVector<Kernel1D<T> > kernels(shape.size(), kernel); ArrayVector<Kernel1D<T> > kernels(shape.size(), kernel);
separableConvolveMultiArray( s, shape, src, d, dest, kernels.begin(), s tart, stop); separableConvolveMultiArray( s, shape, src, d, dest, kernels.begin(), s tart, stop);
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class KernelIterator>
inline void
separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons
t & source,
pair<DestIterator, DestAccessor> const & dest,
KernelIterator kit,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape())
{
separableConvolveMultiArray( source.first, source.second, source.third,
dest.first, dest.second, kit, start, stop
);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
inline void inline void
separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source, separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
Kernel1D<T> const & kernel, Kernel1D<T> const & kernel,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()) SrcShape const & stop = SrcShape())
{ {
ArrayVector<Kernel1D<T> > kernels(source.second.size(), kernel); ArrayVector<Kernel1D<T> > kernels(source.second.size(), kernel);
separableConvolveMultiArray( source.first, source.second, source.third, separableConvolveMultiArray( source.first, source.second, source.third,
dest.first, dest.second, kernels.begin(), start, stop); dest.first, dest.second, kernels.begin(), start, stop);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2,
class KernelIterator>
inline void
separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
KernelIterator kit,
typename MultiArrayShape<N>::type start = typen
ame MultiArrayShape<N>::type(),
typename MultiArrayShape<N>::type stop = typena
me MultiArrayShape<N>::type())
{
if(stop != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), sta
rt);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), sto
p);
vigra_precondition(dest.shape() == (stop - start),
"separableConvolveMultiArray(): shape mismatch between ROI and
output.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"separableConvolveMultiArray(): shape mismatch between input an
d output.");
}
separableConvolveMultiArray( srcMultiArrayRange(source),
destMultiArray(dest), kit, start, stop );
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T>
inline void
separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
Kernel1D<T> const & kernel,
typename MultiArrayShape<N>::type const & start
= typename MultiArrayShape<N>::type(),
typename MultiArrayShape<N>::type const & stop
= typename MultiArrayShape<N>::type())
{
ArrayVector<Kernel1D<T> > kernels(N, kernel);
separableConvolveMultiArray(source, dest, kernels.begin(), start, stop)
;
}
/********************************************************/ /********************************************************/
/* */ /* */
/* convolveMultiArrayOneDimension */ /* convolveMultiArrayOneDimension */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Convolution along a single dimension of a multi-dimensional arra ys. /** \brief Convolution along a single dimension of a multi-dimensional arra ys.
This function computes a convolution along one dimension (specified by This function computes a convolution along one dimension (specified by
the parameter <tt>dim</tt> of the given multi-dimensional array with th e given the parameter <tt>dim</tt> of the given multi-dimensional array with th e given
<tt>kernel</tt>. Both source and destination arrays are represented by <tt>kernel</tt>. The destination array must already have the correct si
iterators, shape objects and accessors. The destination array is requir ze.
ed to
already have the correct size.
If <tt>start</tt> and <tt>stop</tt> have non-default values, they must represent If <tt>start</tt> and <tt>stop</tt> have non-default values, they must represent
a valid subarray of the input array. The convolution is then restricted to that a valid subarray of the input array. The convolution is then restricted to that
subarray, and it is assumed that the output array only refers to the subarray, and it is assumed that the output array only refers to the
subarray (i.e. <tt>diter</tt> points to the element corresponding to subarray (i.e. <tt>dest.shape() == stop - start</tt>). Negative ROI bou
<tt>start</tt>). ndaries are
interpreted relative to the end of the respective dimension
(i.e. <tt>if(stop[k] < 0) stop[k] += source.shape(k);</tt>).
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>source.data() == dest.data()</tt> is allowed.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T>
void
convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & so
urce,
MultiArrayView<N, T2, S2> dest,
unsigned int dim,
Kernel1D<T> const & kernel,
typename MultiArrayShape<N>::type st
art = typename MultiArrayShape<N>::type(),
typename MultiArrayShape<N>::type st
op = typename MultiArrayShape<N>::type());
}
\endcode
\deprecatedAPI{convolveMultiArrayOneDimension}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
void void
convolveMultiArrayOneDimension(SrcIterator siter, SrcShape const & shape, SrcAccessor src, convolveMultiArrayOneDimension(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
DestIterator diter, DestAccessor des t, DestIterator diter, DestAccessor des t,
unsigned int dim, vigra::Kernel1D<T> const & kernel, unsigned int dim, vigra::Kernel1D<T> const & kernel,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()); SrcShape const & stop = SrcShape());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
void void
convolveMultiArrayOneDimension(triple<SrcIterator, SrcShape, SrcAcc essor> const & source, convolveMultiArrayOneDimension(triple<SrcIterator, SrcShape, SrcAcc essor> const & source,
pair<DestIterator, DestAccessor> con st & dest, pair<DestIterator, DestAccessor> con st & dest,
unsigned int dim, vigra::Kernel1D<T> const & kernel, unsigned int dim, vigra::Kernel1D<T> const & kernel,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()); SrcShape const & stop = SrcShape());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape); MultiArray<3, float> dest(shape);
... ...
Kernel1D<float> gauss; Kernel1D<float> gauss;
gauss.initGaussian(sigma); gauss.initGaussian(sigma);
// perform Gaussian smoothing along dimensions 1 (height) // perform Gaussian smoothing along dimension 1 (height)
convolveMultiArrayOneDimension(srcMultiArrayRange(source), destMultiArr convolveMultiArrayOneDimension(source, dest, 1, gauss);
ay(dest), 1, gauss);
\endcode \endcode
\see separableConvolveMultiArray() \see separableConvolveMultiArray()
*/ */
doxygen_overloaded_function(template <...> void convolveMultiArrayOneDimens ion) doxygen_overloaded_function(template <...> void convolveMultiArrayOneDimens ion)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
void void
convolveMultiArrayOneDimension(SrcIterator s, SrcShape const & shape, SrcAc cessor src, convolveMultiArrayOneDimension(SrcIterator s, SrcShape const & shape, SrcAc cessor src,
skipping to change at line 971 skipping to change at line 1108
sstart[dim] = 0; sstart[dim] = 0;
sstop[dim] = shape[dim]; sstop[dim] = shape[dim];
dstop = stop - start; dstop = stop - start;
} }
SNavigator snav( s, sstart, sstop, dim ); SNavigator snav( s, sstart, sstop, dim );
DNavigator dnav( d, dstart, dstop, dim ); DNavigator dnav( d, dstart, dstop, dim );
for( ; snav.hasMore(); snav++, dnav++ ) for( ; snav.hasMore(); snav++, dnav++ )
{ {
// first copy source to temp for maximum cache efficiency // first copy source to temp for maximum cache efficiency
copyLine( snav.begin(), snav.end(), src, copyLine(snav.begin(), snav.end(), src,
tmp.begin(), typename AccessorTraits<TmpType>::default_accessor( tmp.begin(), typename AccessorTraits<TmpType>::default_acc
) ); essor() );
convolveLine(srcIterRange( tmp.begin(), tmp.end(), TmpAccessor()), convolveLine(srcIterRange( tmp.begin(), tmp.end(), TmpAccessor()),
destIter( dnav.begin(), dest ), destIter( dnav.begin(), dest ),
kernel1d( kernel), start[dim], stop[dim]); kernel1d( kernel), start[dim], stop[dim]);
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class T> class DestIterator, class DestAccessor, class T>
inline void inline void
convolveMultiArrayOneDimension(triple<SrcIterator, SrcShape, SrcAccessor> c onst & source, convolveMultiArrayOneDimension(triple<SrcIterator, SrcShape, SrcAccessor> c onst & source,
pair<DestIterator, DestAccessor> const & des t, pair<DestIterator, DestAccessor> const & des t,
unsigned int dim, vigra::Kernel1D<T> const & unsigned int dim,
kernel, Kernel1D<T> const & kernel,
SrcShape const & start = SrcShape(), SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape()) SrcShape const & stop = SrcShape())
{ {
convolveMultiArrayOneDimension(source.first, source.second, source.thir d, convolveMultiArrayOneDimension(source.first, source.second, source.thir d,
dest.first, dest.second, dim, kernel, st art, stop); dest.first, dest.second, dim, kernel, st art, stop);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2,
class T>
inline void
convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
unsigned int dim,
Kernel1D<T> const & kernel,
typename MultiArrayShape<N>::type start = ty
pename MultiArrayShape<N>::type(),
typename MultiArrayShape<N>::type stop = typ
ename MultiArrayShape<N>::type())
{
if(stop != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), sta
rt);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), sto
p);
vigra_precondition(dest.shape() == (stop - start),
"convolveMultiArrayOneDimension(): shape mismatch between ROI a
nd output.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"convolveMultiArrayOneDimension(): shape mismatch between input
and output.");
}
convolveMultiArrayOneDimension(srcMultiArrayRange(source),
destMultiArray(dest), dim, kernel, start
, stop);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* gaussianSmoothMultiArray */ /* gaussianSmoothMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Isotropic Gaussian smoothing of a multi-dimensional arrays. /** \brief Isotropic Gaussian smoothing of a multi-dimensional arrays.
This function computes an isotropic convolution of the given N-dimensio nal This function computes an isotropic convolution of the given N-dimensio nal
array with a Gaussian filter at the given standard deviation <tt>sigma< /tt>. array with a Gaussian filter at the given standard deviation <tt>sigma< /tt>.
Both source and destination arrays are represented by Both source and destination arrays are represented by
iterators, shape objects and accessors. The destination array is requir ed to iterators, shape objects and accessors. The destination array is requir ed to
already have the correct size. This function may work in-place, which m eans already have the correct size. This function may work in-place, which m eans
that <tt>siter == diter</tt> is allowed. It is implemented by a call to that <tt>source.data() == dest.data()</tt> is allowed. It is implemente d by a call to
\ref separableConvolveMultiArray() with the appropriate kernel. \ref separableConvolveMultiArray() with the appropriate kernel.
Anisotropic data should be passed with appropriate Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al
unless the parameter <tt>sigma</tt> is left out. unless the parameter <tt>sigma</tt> is omitted.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// pass filter scale explicitly
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOpt
ions<N>());
// pass filer scale(s) in the option object
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> opt);
}
\endcode
\deprecatedAPI{gaussianSmoothMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianSmoothMultiArray(SrcIterator siter, SrcShape const & shape, SrcAccessor src, gaussianSmoothMultiArray(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
double sigma, const ConvolutionOptions<N> double sigma,
& opt); const ConvolutionOptions<N> & opt = Convol
utionOptions<N>());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & d est, pair<DestIterator, DestAccessor> const & d est,
double sigma, const ConvolutionOptions<N> double sigma,
& opt); const ConvolutionOptions<N> & opt = Convol
utionOptions<N>());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape); MultiArray<3, float> dest(shape);
... ...
// perform isotropic Gaussian smoothing at scale 'sigma' // perform isotropic Gaussian smoothing at scale 'sigma'
gaussianSmoothMultiArray(srcMultiArrayRange(source), destMultiArray(des t), sigma); gaussianSmoothMultiArray(source, dest, sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b> <b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape); MultiArray<3, float> dest(shape);
TinyVector<float, 3> step_size; TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas; TinyVector<float, 3> resolution_sigmas;
... ...
// perform anisotropic Gaussian smoothing at scale 'sigma' // perform anisotropic Gaussian smoothing at scale 'sigma'
gaussianSmoothMultiArray(srcMultiArrayRange(source), destMultiArray(des t), sigma, gaussianSmoothMultiArray(source, dest, sigma,
ConvolutionOptions<3>().stepSize(step_size).re solutionStdDev(resolution_sigmas)); ConvolutionOptions<3>().stepSize(step_size).re solutionStdDev(resolution_sigmas));
\endcode \endcode
\see separableConvolveMultiArray() \see separableConvolveMultiArray()
*/ */
doxygen_overloaded_function(template <...> void gaussianSmoothMultiArray) doxygen_overloaded_function(template <...> void gaussianSmoothMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianSmoothMultiArray( SrcIterator s, SrcShape const & shape, SrcAccesso r src, gaussianSmoothMultiArray( SrcIterator s, SrcShape const & shape, SrcAccesso r src,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
const ConvolutionOptions<SrcShape::static_size> & opt, const ConvolutionOptions<SrcShape::static_size> & opt,
const char *const function_name = "gaussianSmoothMultiAr ray" ) const char *const function_name = "gaussianSmoothMultiAr ray" )
{ {
typedef typename DestAccessor::value_type DestType;
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
typename ConvolutionOptions<N>::ScaleIterator params = opt.scaleParams( ); typename ConvolutionOptions<N>::ScaleIterator params = opt.scaleParams( );
ArrayVector<Kernel1D<double> > kernels(N); ArrayVector<Kernel1D<double> > kernels(N);
for (int dim = 0; dim < N; ++dim, ++params) for (int dim = 0; dim < N; ++dim, ++params)
kernels[dim].initGaussian(params.sigma_scaled(function_name), 1.0, opt.window_ratio); kernels[dim].initGaussian(params.sigma_scaled(function_name), 1.0, opt.window_ratio);
separableConvolveMultiArray(s, shape, src, d, dest, kernels.begin(), op t.from_point, opt.to_point); separableConvolveMultiArray(s, shape, src, d, dest, kernels.begin(), op t.from_point, opt.to_point);
} }
skipping to change at line 1109 skipping to change at line 1296
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>())
{ {
ConvolutionOptions<SrcShape::static_size> par = opt; ConvolutionOptions<SrcShape::static_size> par = opt;
gaussianSmoothMultiArray(s, shape, src, d, dest, par.stdDev(sigma)); gaussianSmoothMultiArray(s, shape, src, d, dest, par.stdDev(sigma));
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
const ConvolutionOptions<SrcShape::static_size> & opt) const ConvolutionOptions<SrcShape::static_size> &
opt)
{ {
gaussianSmoothMultiArray( source.first, source.second, source.third, gaussianSmoothMultiArray( source.first, source.second, source.third,
dest.first, dest.second, opt ); dest.first, dest.second, opt );
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, double sig pair<DestIterator, DestAccessor> const & dest, dou
ma, ble sigma,
const ConvolutionOptions<SrcShape::static_size> & opt = C const ConvolutionOptions<SrcShape::static_size> &
onvolutionOptions<SrcShape::static_size>()) opt = ConvolutionOptions<SrcShape::static_size>())
{ {
gaussianSmoothMultiArray( source.first, source.second, source.third, gaussianSmoothMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma, opt ); dest.first, dest.second, sigma, opt );
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> opt)
{
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.from_point);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.to_point);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"gaussianSmoothMultiArray(): shape mismatch between ROI and out
put.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"gaussianSmoothMultiArray(): shape mismatch between input and o
utput.");
}
gaussianSmoothMultiArray( srcMultiArrayRange(source),
destMultiArray(dest), opt );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions<N>(
))
{
gaussianSmoothMultiArray( source, dest, opt.stdDev(sigma) );
}
/********************************************************/ /********************************************************/
/* */ /* */
/* gaussianGradientMultiArray */ /* gaussianGradientMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate Gaussian gradient of a multi-dimensional arrays. /** \brief Calculate Gaussian gradient of a multi-dimensional arrays.
This function computes the Gaussian gradient of the given N-dimensional This function computes the Gaussian gradient of the given N-dimensional
array with a sequence of first-derivative-of-Gaussian filters at the gi ven array with a sequence of first-derivative-of-Gaussian filters at the gi ven
standard deviation <tt>sigma</tt> (differentiation is applied to each d imension standard deviation <tt>sigma</tt> (differentiation is applied to each d imension
in turn, starting with the innermost dimension). Both source and destin in turn, starting with the innermost dimension). The destination array
ation arrays is
are represented by iterators, shape objects and accessors. The destinat
ion array is
required to have a vector valued pixel type with as many elements as th e number of required to have a vector valued pixel type with as many elements as th e number of
dimensions. This function is implemented by calls to dimensions. This function is implemented by calls to
\ref separableConvolveMultiArray() with the appropriate kernels. \ref separableConvolveMultiArray() with the appropriate kernels.
Anisotropic data should be passed with appropriate Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al
unless the parameter <tt>sigma</tt> is left out. unless the parameter <tt>sigma</tt> is omitted.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// pass filter scale explicitly
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianGradientMultiArray(MultiArrayView<N, T1, S1> const & source
,
MultiArrayView<N, TinyVector<T2, N>, S2>
dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionO
ptions<N>());
// pass filter scale(s) in option object
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianGradientMultiArray(MultiArrayView<N, T1, S1> const & source
,
MultiArrayView<N, TinyVector<T2, N>, S2>
dest,
ConvolutionOptions<N> opt);
}
\endcode
\deprecatedAPI{gaussianGradientMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianGradientMultiArray(SrcIterator siter, SrcShape const & shap e, SrcAccessor src, gaussianGradientMultiArray(SrcIterator siter, SrcShape const & shap e, SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
double sigma, const ConvolutionOptions<N double sigma,
> & opt); const ConvolutionOptions<N> & opt = Conv
olutionOptions<N>());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccesso r> const & source, gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccesso r> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double sigma, const ConvolutionOptions<N double sigma,
> & opt); const ConvolutionOptions<N> & opt = Conv
olutionOptions<N>());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, TinyVector<float, 3> > dest(shape); MultiArray<3, TinyVector<float, 3> > dest(shape);
... ...
// compute Gaussian gradient at scale sigma // compute Gaussian gradient at scale sigma
gaussianGradientMultiArray(srcMultiArrayRange(source), destMultiArray(d est), sigma); gaussianGradientMultiArray(source, dest, sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b> <b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, TinyVector<float, 3> > dest(shape); MultiArray<3, TinyVector<float, 3> > dest(shape);
TinyVector<float, 3> step_size; TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas; TinyVector<float, 3> resolution_sigmas;
... ...
// compute Gaussian gradient at scale sigma // compute Gaussian gradient at scale sigma
gaussianGradientMultiArray(srcMultiArrayRange(source), destMultiArray(d est), sigma, gaussianGradientMultiArray(source, dest, sigma,
ConvolutionOptions<3>().stepSize(step_size). resolutionStdDev(resolution_sigmas)); ConvolutionOptions<3>().stepSize(step_size). resolutionStdDev(resolution_sigmas));
\endcode \endcode
<b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition:
\code
int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode
\see separableConvolveMultiArray() \see separableConvolveMultiArray()
*/ */
doxygen_overloaded_function(template <...> void gaussianGradientMultiArray) doxygen_overloaded_function(template <...> void gaussianGradientMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcces sor src, gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcces sor src,
DestIterator di, DestAccessor dest, DestIterator di, DestAccessor dest,
ConvolutionOptions<SrcShape::static_size> const & opt, ConvolutionOptions<SrcShape::static_size> const & opt,
skipping to change at line 1266 skipping to change at line 1502
separableConvolveMultiArray(si, shape, src, di, ElementAccessor(dim , dest), kernels.begin(), separableConvolveMultiArray(si, shape, src, di, ElementAccessor(dim , dest), kernels.begin(),
opt.from_point, opt.to_point); opt.from_point, opt.to_point);
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcces sor src, gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcces sor src,
DestIterator di, DestAccessor dest, double sigma , DestIterator di, DestAccessor dest, double sigma ,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) ConvolutionOptions<SrcShape::static_size> opt = ConvolutionOptions<SrcShape::static_size>())
{ {
ConvolutionOptions<SrcShape::static_size> par = opt; gaussianGradientMultiArray(si, shape, src, di, dest, opt.stdDev(sigma))
gaussianGradientMultiArray(si, shape, src, di, dest, par.stdDev(sigma)) ;
;
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
ConvolutionOptions<SrcShape::static_size> const & opt ) ConvolutionOptions<SrcShape::static_size> const & opt )
{ {
gaussianGradientMultiArray( source.first, source.second, source.third, gaussianGradientMultiArray( source.first, source.second, source.third,
skipping to change at line 1295 skipping to change at line 1530
inline void inline void
gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double sigma, double sigma,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>())
{ {
gaussianGradientMultiArray( source.first, source.second, source.third, gaussianGradientMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma, opt ); dest.first, dest.second, sigma, opt );
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, N>, S2> dest,
ConvolutionOptions<N> opt )
{
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.from_point);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.to_point);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"gaussianGradientMultiArray(): shape mismatch between ROI and o
utput.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"gaussianGradientMultiArray(): shape mismatch between input and
output.");
}
gaussianGradientMultiArray( srcMultiArrayRange(source),
destMultiArray(dest), opt );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, N>, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions<N
>())
{
gaussianGradientMultiArray( source, dest, opt.stdDev(sigma) );
}
/********************************************************/
/* */
/* gaussianGradientMagnitude */
/* */
/********************************************************/
namespace detail {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianGradientMagnitudeImpl(MultiArrayView<N+1, T1, S1> const & src,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> opt = ConvolutionOption
s<N>())
{
typename MultiArrayShape<N>::type shape(src.shape().template subarray<0
,N>());
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, opt.from_poi
nt);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, opt.to_point
);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"gaussianGradientMagnitude(): shape mismatch between ROI and ou
tput.");
}
else
{
vigra_precondition(shape == dest.shape(),
"gaussianGradientMagnitude(): shape mismatch between input and
output.");
}
dest.init(0.0);
typedef typename NumericTraits<T1>::RealPromote TmpType;
MultiArray<N, TinyVector<TmpType, N> > grad(dest.shape());
using namespace multi_math;
for(int k=0; k<src.shape(N); ++k)
{
gaussianGradientMultiArray(src.bindOuter(k), grad, opt);
dest += squaredNorm(grad);
}
dest = sqrt(dest);
}
} // namespace detail
// documentation is in convolution.hxx
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & sr
c,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> const & opt)
{
detail::gaussianGradientMagnitudeImpl<N, T1>(src, dest, opt);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> const & opt)
{
detail::gaussianGradientMagnitudeImpl<N, T1>(src.insertSingletonDimensi
on(N), dest, opt);
}
template <unsigned int N, class T1, int M, class S1,
class T2, class S2>
inline void
gaussianGradientMagnitude(MultiArrayView<N, TinyVector<T1, M>, S1> const &
src,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> const & opt)
{
detail::gaussianGradientMagnitudeImpl<N, T1>(src.expandElements(N), des
t, opt);
}
template <unsigned int N, class T1, unsigned int R, unsigned int G, unsigne
d int B, class S1,
class T2, class S2>
inline void
gaussianGradientMagnitude(MultiArrayView<N, RGBValue<T1, R, G, B>, S1> cons
t & src,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> const & opt)
{
detail::gaussianGradientMagnitudeImpl<N, T1>(src.expandElements(N), des
t, opt);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions<N>
())
{
gaussianGradientMagnitude(src, dest, opt.stdDev(sigma));
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & sr
c,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions<N>
())
{
gaussianGradientMagnitude<N>(src, dest, opt.stdDev(sigma));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* symmetricGradientMultiArray */ /* symmetricGradientMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate gradient of a multi-dimensional arrays using symmetric difference filters. /** \brief Calculate gradient of a multi-dimensional arrays using symmetric difference filters.
This function computes the gradient of the given N-dimensional This function computes the gradient of the given N-dimensional
array with a sequence of symmetric difference filters a (differentiatio n is applied array with a sequence of symmetric difference filters a (differentiatio n is applied
to each dimension in turn, starting with the innermost dimension). Both to each dimension in turn, starting with the innermost dimension).
source and
destination arrays are represented by iterators, shape objects and acce
ssors.
The destination array is required to have a vector valued pixel type wi th as many The destination array is required to have a vector valued pixel type wi th as many
elements as the number of dimensions. This function is implemented by c alls to elements as the number of dimensions. This function is implemented by c alls to
\ref convolveMultiArrayOneDimension() with the symmetric difference ker nel. \ref convolveMultiArrayOneDimension() with the symmetric difference ker nel.
Anisotropic data should be passed with appropriate Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is optional \ref ConvolutionOptions, the parameter <tt>opt</tt> is optional
otherwise. otherwise.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, TinyVector<T2, N>, S2
> dest,
ConvolutionOptions<N> opt = Convolution
Options<N>());
}
\endcode
\deprecatedAPI{symmetricGradientMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
symmetricGradientMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src, symmetricGradientMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
const ConvolutionOptions<N> & opt); const ConvolutionOptions<N> & opt = Con volutionOptions<N>());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
symmetricGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source, symmetricGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
const ConvolutionOptions<N> & opt); const ConvolutionOptions<N> & opt = Con volutionOptions<N>());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); MultiArray<3, unsigned char>::size_type shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, TinyVector<float, 3> > dest(shape); MultiArray<3, TinyVector<float, 3> > dest(shape);
... ...
// compute gradient // compute gradient
symmetricGradientMultiArray(srcMultiArrayRange(source), destMultiArray( dest)); symmetricGradientMultiArray(srcMultiArrayRange(source), destMultiArray( dest));
\endcode \endcode
<b> Usage with anisotropic data:</b> <b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, TinyVector<float, 3> > dest(shape); MultiArray<3, TinyVector<float, 3> > dest(shape);
TinyVector<float, 3> step_size; TinyVector<float, 3> step_size;
... ...
// compute gradient // compute gradient
symmetricGradientMultiArray(srcMultiArrayRange(source), destMultiArray( dest), symmetricGradientMultiArray(source, dest,
ConvolutionOptions<3>().stepSize(step_size) ); ConvolutionOptions<3>().stepSize(step_size) );
\endcode \endcode
<b> Required Interface:</b>
see \ref convolveMultiArrayOneDimension(), in addition:
\code
int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode
\see convolveMultiArrayOneDimension() \see convolveMultiArrayOneDimension()
*/ */
doxygen_overloaded_function(template <...> void symmetricGradientMultiArray ) doxygen_overloaded_function(template <...> void symmetricGradientMultiArray )
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
symmetricGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce ssor src, symmetricGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce ssor src,
DestIterator di, DestAccessor dest, DestIterator di, DestAccessor dest,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>())
skipping to change at line 1404 skipping to change at line 1786
typedef typename ConvolutionOptions<N>::StepIterator StepType; typedef typename ConvolutionOptions<N>::StepIterator StepType;
for(int k=0; k<N; ++k) for(int k=0; k<N; ++k)
if(shape[k] <=0) if(shape[k] <=0)
return; return;
vigra_precondition(N == (int)dest.size(di), vigra_precondition(N == (int)dest.size(di),
"symmetricGradientMultiArray(): Wrong number of channels in output array."); "symmetricGradientMultiArray(): Wrong number of channels in output array.");
Kernel1D<KernelType> filter; Kernel1D<KernelType> filter;
filter.initSymmetricGradient(); filter.initSymmetricDifference();
StepType step_size_it = opt.stepParams(); StepType step_size_it = opt.stepParams();
typedef VectorElementAccessor<DestAccessor> ElementAccessor; typedef VectorElementAccessor<DestAccessor> ElementAccessor;
// compute gradient components // compute gradient components
for (int d = 0; d < N; ++d, ++step_size_it) for (int d = 0; d < N; ++d, ++step_size_it)
{ {
Kernel1D<KernelType> symmetric(filter); Kernel1D<KernelType> symmetric(filter);
detail::scaleKernel(symmetric, 1 / *step_size_it); detail::scaleKernel(symmetric, 1 / *step_size_it);
skipping to change at line 1432 skipping to change at line 1814
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
symmetricGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source, symmetricGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>())
{ {
symmetricGradientMultiArray(source.first, source.second, source.third, symmetricGradientMultiArray(source.first, source.second, source.third,
dest.first, dest.second, opt); dest.first, dest.second, opt);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, N>, S2> dest,
ConvolutionOptions<N> opt = ConvolutionOptions<
N>())
{
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.from_point);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.to_point);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"symmetricGradientMultiArray(): shape mismatch between ROI and
output.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"symmetricGradientMultiArray(): shape mismatch between input an
d output.");
}
symmetricGradientMultiArray(srcMultiArrayRange(source),
destMultiArray(dest), opt);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* laplacianOfGaussianMultiArray */ /* laplacianOfGaussianMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate Laplacian of a N-dimensional arrays using Gaussian der ivative filters. /** \brief Calculate Laplacian of a N-dimensional arrays using Gaussian der ivative filters.
This function computes the Laplacian the given N-dimensional This function computes the Laplacian of the given N-dimensional
array with a sequence of second-derivative-of-Gaussian filters at the g iven array with a sequence of second-derivative-of-Gaussian filters at the g iven
standard deviation <tt>sigma</tt>. Both source and destination arrays standard deviation <tt>sigma</tt>. Both source and destination
are represented by iterators, shape objects and accessors. Both source
and destination
arrays must have scalar value_type. This function is implemented by cal ls to arrays must have scalar value_type. This function is implemented by cal ls to
\ref separableConvolveMultiArray() with the appropriate kernels, follow ed by summation. \ref separableConvolveMultiArray() with the appropriate kernels, follow ed by summation.
Anisotropic data should be passed with appropriate Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al
unless the parameter <tt>sigma</tt> is left out. unless the parameter <tt>sigma</tt> is left out.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// pass scale explicitly
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & sou
rce,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = Convoluti
onOptions<N>());
// pass scale(s) in option object
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & sou
rce,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> opt );
}
\endcode
\deprecatedAPI{laplacianOfGaussianMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
laplacianOfGaussianMultiArray(SrcIterator siter, SrcShape const & s hape, SrcAccessor src, laplacianOfGaussianMultiArray(SrcIterator siter, SrcShape const & s hape, SrcAccessor src,
DestIterator diter, DestAccessor dest , DestIterator diter, DestAccessor dest ,
double sigma, const ConvolutionOption double sigma,
s<N> & opt); const ConvolutionOptions<N> & opt = C
onvolutionOptions<N>());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAcce ssor> const & source, laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAcce ssor> const & source,
pair<DestIterator, DestAccessor> cons t & dest, pair<DestIterator, DestAccessor> cons t & dest,
double sigma, const ConvolutionOption double sigma,
s<N> & opt); const ConvolutionOptions<N> & opt = C
onvolutionOptions<N>());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
Shape3 shape(width, height, depth);
MultiArray<3, float> source(shape); MultiArray<3, float> source(shape);
MultiArray<3, float> laplacian(shape); MultiArray<3, float> laplacian(shape);
... ...
// compute Laplacian at scale sigma // compute Laplacian at scale sigma
laplacianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArra y(laplacian), sigma); laplacianOfGaussianMultiArray(source, laplacian, sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b> <b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code \code
MultiArray<3, float> source(shape); MultiArray<3, float> source(shape);
MultiArray<3, float> laplacian(shape); MultiArray<3, float> laplacian(shape);
TinyVector<float, 3> step_size; TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas; TinyVector<float, 3> resolution_sigmas;
... ...
// compute Laplacian at scale sigma // compute Laplacian at scale sigma
laplacianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArra y(laplacian), sigma, laplacianOfGaussianMultiArray(source, laplacian, sigma,
ConvolutionOptions<3>().stepSize(step_siz e).resolutionStdDev(resolution_sigmas)); ConvolutionOptions<3>().stepSize(step_siz e).resolutionStdDev(resolution_sigmas));
\endcode \endcode
<b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition:
\code
int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode
\see separableConvolveMultiArray() \see separableConvolveMultiArray()
*/ */
doxygen_overloaded_function(template <...> void laplacianOfGaussianMultiArr ay) doxygen_overloaded_function(template <...> void laplacianOfGaussianMultiArr ay)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAc cessor src, laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAc cessor src,
DestIterator di, DestAccessor dest, DestIterator di, DestAccessor dest,
ConvolutionOptions<SrcShape::static_size> con st & opt ) ConvolutionOptions<SrcShape::static_size> con st & opt )
skipping to change at line 1577 skipping to change at line 1998
di, dest, Arg1() + Arg2() ); di, dest, Arg1() + Arg2() );
} }
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAc cessor src, laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAc cessor src,
DestIterator di, DestAccessor dest, double si gma, DestIterator di, DestAccessor dest, double si gma,
const ConvolutionOptions<SrcShape::static_siz e> & opt = ConvolutionOptions<SrcShape::static_size>()) ConvolutionOptions<SrcShape::static_size> opt = ConvolutionOptions<SrcShape::static_size>())
{ {
ConvolutionOptions<SrcShape::static_size> par = opt; laplacianOfGaussianMultiArray(si, shape, src, di, dest, opt.stdDev(sigm
laplacianOfGaussianMultiArray(si, shape, src, di, dest, par.stdDev(sigm a));
a));
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> co nst & source, laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> co nst & source,
pair<DestIterator, DestAccessor> const & dest , pair<DestIterator, DestAccessor> const & dest ,
ConvolutionOptions<SrcShape::static_size> con st & opt ) ConvolutionOptions<SrcShape::static_size> con st & opt )
{ {
laplacianOfGaussianMultiArray( source.first, source.second, source.thir d, laplacianOfGaussianMultiArray( source.first, source.second, source.thir d,
skipping to change at line 1606 skipping to change at line 2026
inline void inline void
laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> co nst & source, laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> co nst & source,
pair<DestIterator, DestAccessor> const & dest , pair<DestIterator, DestAccessor> const & dest ,
double sigma, double sigma,
const ConvolutionOptions<SrcShape::static_siz e> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_siz e> & opt = ConvolutionOptions<SrcShape::static_size>())
{ {
laplacianOfGaussianMultiArray( source.first, source.second, source.thir d, laplacianOfGaussianMultiArray( source.first, source.second, source.thir d,
dest.first, dest.second, sigma, opt ); dest.first, dest.second, sigma, opt );
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
ConvolutionOptions<N> opt )
{
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.from_point);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.to_point);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"laplacianOfGaussianMultiArray(): shape mismatch between ROI an
d output.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"laplacianOfGaussianMultiArray(): shape mismatch between input
and output.");
}
laplacianOfGaussianMultiArray( srcMultiArrayRange(source),
destMultiArray(dest), opt );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOption
s<N>())
{
laplacianOfGaussianMultiArray( source, dest, opt.stdDev(sigma) );
}
/********************************************************/
/* */
/* gaussianDivergenceMultiArray */
/* */
/********************************************************/
/** \brief Calculate the divergence of a vector field using Gaussian deriva
tive filters.
This function computes the divergence of the given N-dimensional vector
field
with a sequence of first-derivative-of-Gaussian filters at the given
standard deviation <tt>sigma</tt>. The input vector field can either be
given as a sequence
of scalar array views (one for each vector field component), represente
d by an
iterator range, or by a single vector array with the appropriate shape.
This function is implemented by calls to
\ref separableConvolveMultiArray() with the suitable kernels, followed
by summation.
Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option
al
unless the parameter <tt>sigma</tt> is omitted.
<b> Declarations:</b>
pass arbitrary-dimensional array views:
\code
namespace vigra {
// specify input vector field as a sequence of scalar arrays
template <class Iterator,
unsigned int N, class T, class S>
void
gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorF
ieldEnd,
MultiArrayView<N, T, S> divergence,
ConvolutionOptions<N> const & opt);
template <class Iterator,
unsigned int N, class T, class S>
void
gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorF
ieldEnd,
MultiArrayView<N, T, S> divergence,
double sigma,
ConvolutionOptions<N> opt = Convolutio
nOptions<N>());
// pass input vector field as an array of vectors
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S
1> const & vectorField,
MultiArrayView<N, T2, S2> divergence,
ConvolutionOptions<N> const & opt);
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S
1> const & vectorField,
MultiArrayView<N, T2, S2> divergence,
double sigma,
ConvolutionOptions<N> opt = Convolutio
nOptions<N>());
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code
Shape3 shape(width, height, depth);
MultiArray<3, TinyVector<float, 3> > source(shape);
MultiArray<3, float> laplacian(shape);
...
// compute divergence at scale sigma
gaussianDivergenceMultiArray(source, laplacian, sigma);
\endcode
<b> Usage with anisotropic data:</b>
\code
MultiArray<3, TinyVector<float, 3> > source(shape);
MultiArray<3, float> laplacian(shape);
TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas;
...
// compute divergence at scale sigma
gaussianDivergenceMultiArray(source, laplacian, sigma,
ConvolutionOptions<3>().stepSize(step_size
).resolutionStdDev(resolution_sigmas));
\endcode
*/
doxygen_overloaded_function(template <...> void gaussianDivergenceMultiArra
y)
template <class Iterator,
unsigned int N, class T, class S>
void
gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
MultiArrayView<N, T, S> divergence,
ConvolutionOptions<N> opt)
{
typedef typename std::iterator_traits<Iterator>::value_type ArrayType;
typedef typename ArrayType::value_type SrcType;
typedef typename NumericTraits<SrcType>::RealPromote TmpType;
typedef Kernel1D<double> Kernel;
vigra_precondition(std::distance(vectorField, vectorFieldEnd) == N,
"gaussianDivergenceMultiArray(): wrong number of input arrays.");
// more checks are performed in separableConvolveMultiArray()
typename ConvolutionOptions<N>::ScaleIterator params = opt.scaleParams(
);
ArrayVector<double> sigmas(N);
ArrayVector<Kernel> kernels(N);
for(unsigned int k = 0; k < N; ++k, ++params)
{
sigmas[k] = params.sigma_scaled("gaussianDivergenceMultiArray");
kernels[k].initGaussian(sigmas[k], 1.0, opt.window_ratio);
}
MultiArray<N, TmpType> tmpDeriv(divergence.shape());
for(unsigned int k=0; k < N; ++k, ++vectorField)
{
kernels[k].initGaussianDerivative(sigmas[k], 1, 1.0, opt.window_rat
io);
if(k == 0)
{
separableConvolveMultiArray(*vectorField, divergence, kernels.b
egin(), opt.from_point, opt.to_point);
}
else
{
separableConvolveMultiArray(*vectorField, tmpDeriv, kernels.beg
in(), opt.from_point, opt.to_point);
divergence += tmpDeriv;
}
kernels[k].initGaussian(sigmas[k], 1.0, opt.window_ratio);
}
}
template <class Iterator,
unsigned int N, class T, class S>
inline void
gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
MultiArrayView<N, T, S> divergence,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions
<N>())
{
gaussianDivergenceMultiArray(vectorField, vectorFieldEnd, divergence, o
pt.stdDev(sigma));
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const
& vectorField,
MultiArrayView<N, T2, S2> divergence,
ConvolutionOptions<N> const & opt)
{
ArrayVector<MultiArrayView<N, T1> > field;
for(unsigned int k=0; k<N; ++k)
field.push_back(vectorField.bindElementChannel(k));
gaussianDivergenceMultiArray(field.begin(), field.end(), divergence, op
t);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const
& vectorField,
MultiArrayView<N, T2, S2> divergence,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions
<N>())
{
gaussianDivergenceMultiArray(vectorField, divergence, opt.stdDev(sigma)
);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* hessianOfGaussianMultiArray */ /* hessianOfGaussianMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate Hessian matrix of a N-dimensional arrays using Gaussia n derivative filters. /** \brief Calculate Hessian matrix of a N-dimensional arrays using Gaussia n derivative filters.
This function computes the Hessian matrix the given scalar N-dimensiona l This function computes the Hessian matrix the given scalar N-dimensiona l
array with a sequence of second-derivative-of-Gaussian filters at the g iven array with a sequence of second-derivative-of-Gaussian filters at the g iven
standard deviation <tt>sigma</tt>. Both source and destination arrays standard deviation <tt>sigma</tt>. The destination array must
are represented by iterators, shape objects and accessors. The destinat
ion array must
have a vector valued element type with N*(N+1)/2 elements (it represent s the have a vector valued element type with N*(N+1)/2 elements (it represent s the
upper triangular part of the symmetric Hessian matrix). This function i upper triangular part of the symmetric Hessian matrix, flattened row-wi
s implemented by calls to se).
This function is implemented by calls to
\ref separableConvolveMultiArray() with the appropriate kernels. \ref separableConvolveMultiArray() with the appropriate kernels.
Anisotropic data should be passed with appropriate Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al
unless the parameter <tt>sigma</tt> is left out. unless the parameter <tt>sigma</tt> is omitted.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// pass scale explicitly
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
hessianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, TinyVector<T2, int(N*
(N+1)/2)>, S2> dest,
double sigma,
ConvolutionOptions<N> opt = Convolution
Options<N>());
// pass scale(s) in option object
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
hessianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, TinyVector<T2, int(N*
(N+1)/2)>, S2> dest,
ConvolutionOptions<N> opt);
}
\endcode
\deprecatedAPI{hessianOfGaussianMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
hessianOfGaussianMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src, hessianOfGaussianMultiArray(SrcIterator siter, SrcShape const & sha pe, SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
double sigma, const ConvolutionOptions< double sigma,
N> & opt); const ConvolutionOptions<N> & opt = Con
volutionOptions<N>());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source, hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double sigma, const ConvolutionOptions< double sigma,
N> & opt); const ConvolutionOptions<N> & opt = Con
volutionOptions<N>());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
Shape3 shape(width, height, depth);
MultiArray<3, float> source(shape); MultiArray<3, float> source(shape);
MultiArray<3, TinyVector<float, 6> > dest(shape); MultiArray<3, TinyVector<float, 6> > dest(shape);
... ...
// compute Hessian at scale sigma // compute Hessian at scale sigma
hessianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArray( dest), sigma); hessianOfGaussianMultiArray(source, dest, sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b> <b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code \code
MultiArray<3, float> source(shape); MultiArray<3, float> source(shape);
MultiArray<3, TinyVector<float, 6> > dest(shape); MultiArray<3, TinyVector<float, 6> > dest(shape);
TinyVector<float, 3> step_size; TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas; TinyVector<float, 3> resolution_sigmas;
... ...
// compute Hessian at scale sigma // compute Hessian at scale sigma
hessianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArray( dest), sigma, hessianOfGaussianMultiArray(source, dest, sigma,
ConvolutionOptions<3>().stepSize(step_size) .resolutionStdDev(resolution_sigmas)); ConvolutionOptions<3>().stepSize(step_size) .resolutionStdDev(resolution_sigmas));
\endcode \endcode
<b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition:
\code
int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode
\see separableConvolveMultiArray(), vectorToTensorMultiArray() \see separableConvolveMultiArray(), vectorToTensorMultiArray()
*/ */
doxygen_overloaded_function(template <...> void hessianOfGaussianMultiArray ) doxygen_overloaded_function(template <...> void hessianOfGaussianMultiArray )
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce ssor src, hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce ssor src,
DestIterator di, DestAccessor dest, DestIterator di, DestAccessor dest,
ConvolutionOptions<SrcShape::static_size> const & opt ) ConvolutionOptions<SrcShape::static_size> const & opt )
skipping to change at line 1756 skipping to change at line 2394
kernels.begin(), opt.from_point, op t.to_point); kernels.begin(), opt.from_point, op t.to_point);
} }
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce ssor src, hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce ssor src,
DestIterator di, DestAccessor dest, double sigm a, DestIterator di, DestAccessor dest, double sigm a,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) ConvolutionOptions<SrcShape::static_size> opt = ConvolutionOptions<SrcShape::static_size>())
{ {
ConvolutionOptions<SrcShape::static_size> par = opt; hessianOfGaussianMultiArray(si, shape, src, di, dest, opt.stdDev(sigma)
hessianOfGaussianMultiArray(si, shape, src, di, dest, par.stdDev(sigma) );
);
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source, hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
ConvolutionOptions<SrcShape::static_size> const & opt ) ConvolutionOptions<SrcShape::static_size> const & opt )
{ {
hessianOfGaussianMultiArray( source.first, source.second, source.third, hessianOfGaussianMultiArray( source.first, source.second, source.third,
skipping to change at line 1785 skipping to change at line 2422
inline void inline void
hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source, hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double sigma, double sigma,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>())
{ {
hessianOfGaussianMultiArray( source.first, source.second, source.third, hessianOfGaussianMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma, opt ); dest.first, dest.second, sigma, opt );
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
hessianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)
>, S2> dest,
ConvolutionOptions<N> opt )
{
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.from_point);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.to_point);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"hessianOfGaussianMultiArray(): shape mismatch between ROI and
output.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"hessianOfGaussianMultiArray(): shape mismatch between input an
d output.");
}
hessianOfGaussianMultiArray( srcMultiArrayRange(source),
destMultiArray(dest), opt );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
hessianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)
>, S2> dest,
double sigma,
ConvolutionOptions<N> opt = ConvolutionOptions<
N>())
{
hessianOfGaussianMultiArray( source, dest, opt.stdDev(sigma) );
}
namespace detail { namespace detail {
template<int N, class VectorType> template<int N, class VectorType>
struct StructurTensorFunctor struct StructurTensorFunctor
{ {
typedef VectorType result_type; typedef VectorType result_type;
typedef typename VectorType::value_type ValueType; typedef typename VectorType::value_type ValueType;
template <class T> template <class T>
VectorType operator()(T const & in) const VectorType operator()(T const & in) const
skipping to change at line 1821 skipping to change at line 2493
/* */ /* */
/* structureTensorMultiArray */ /* structureTensorMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate th structure tensor of a multi-dimensional arrays. /** \brief Calculate th structure tensor of a multi-dimensional arrays.
This function computes the gradient (outer product) tensor for each ele ment This function computes the gradient (outer product) tensor for each ele ment
of the given N-dimensional array with first-derivative-of-Gaussian filt ers at of the given N-dimensional array with first-derivative-of-Gaussian filt ers at
the given <tt>innerScale</tt>, followed by Gaussian smoothing at <tt>ou terScale</tt>. the given <tt>innerScale</tt>, followed by Gaussian smoothing at <tt>ou terScale</tt>.
Both source and destination arrays are represented by iterators, shape The destination array must have a vector valued pixel type with
objects and
accessors. The destination array must have a vector valued pixel type w
ith
N*(N+1)/2 elements (it represents the upper triangular part of the symm etric N*(N+1)/2 elements (it represents the upper triangular part of the symm etric
structure tensor matrix). If the source array is also vector valued, th e structure tensor matrix, flattened row-wise). If the source array is al so vector valued, the
resulting structure tensor is the sum of the individual tensors for eac h channel. resulting structure tensor is the sum of the individual tensors for eac h channel.
This function is implemented by calls to This function is implemented by calls to
\ref separableConvolveMultiArray() with the appropriate kernels. \ref separableConvolveMultiArray() with the appropriate kernels.
Anisotropic data should be passed with appropriate Anisotropic data should be passed with appropriate
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option al
unless the parameters <tt>innerScale</tt> and <tt>outerScale</tt> are unless the parameters <tt>innerScale</tt> and <tt>outerScale</tt> are
both left out. both omitted.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// pass scales explicitly
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, int(N*(N
+1)/2)>, S2> dest,
double innerScale, double outerScale,
ConvolutionOptions<N> opt = ConvolutionOp
tions<N>());
// pass scales in option object
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, int(N*(N
+1)/2)>, S2> dest,
ConvolutionOptions<N> opt );
}
\endcode
\deprecatedAPI{structureTensorMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
structureTensorMultiArray(SrcIterator siter, SrcShape const & shape , SrcAccessor src, structureTensorMultiArray(SrcIterator siter, SrcShape const & shape , SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
double innerScale, double outerScale, double innerScale, double outerScale,
const ConvolutionOptions<N> &; opt); ConvolutionOptions<N>; opt);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor > const & source, structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor > const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double innerScale, double outerScale, double innerScale, double outerScale,
const ConvolutionOptions<N> & opt); const ConvolutionOptions<N> & opt);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\> <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
Namespace: vigra
\code \code
Shape3 shape(width, height, depth);
MultiArray<3, RGBValue<float> > source(shape); MultiArray<3, RGBValue<float> > source(shape);
MultiArray<3, TinyVector<float, 6> > dest(shape); MultiArray<3, TinyVector<float, 6> > dest(shape);
... ...
// compute structure tensor at scales innerScale and outerScale // compute structure tensor at scales innerScale and outerScale
structureTensorMultiArray(srcMultiArrayRange(source), destMultiArray(de st), innerScale, outerScale); structureTensorMultiArray(source, dest, innerScale, outerScale);
\endcode \endcode
<b> Usage with anisotropic data:</b> <b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code \code
MultiArray<3, RGBValue<float> > source(shape); MultiArray<3, RGBValue<float> > source(shape);
MultiArray<3, TinyVector<float, 6> > dest(shape); MultiArray<3, TinyVector<float, 6> > dest(shape);
TinyVector<float, 3> step_size; TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas; TinyVector<float, 3> resolution_sigmas;
... ...
// compute structure tensor at scales innerScale and outerScale // compute structure tensor at scales innerScale and outerScale
structureTensorMultiArray(srcMultiArrayRange(source), destMultiArray(de st), innerScale, outerScale, structureTensorMultiArray(source, dest, innerScale, outerScale,
ConvolutionOptions<3>().stepSize(step_size).r esolutionStdDev(resolution_sigmas)); ConvolutionOptions<3>().stepSize(step_size).r esolutionStdDev(resolution_sigmas));
\endcode \endcode
<b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition:
\code
int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode
\see separableConvolveMultiArray(), vectorToTensorMultiArray() \see separableConvolveMultiArray(), vectorToTensorMultiArray()
*/ */
doxygen_overloaded_function(template <...> void structureTensorMultiArray) doxygen_overloaded_function(template <...> void structureTensorMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess or src, structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess or src,
DestIterator di, DestAccessor dest, DestIterator di, DestAccessor dest,
ConvolutionOptions<SrcShape::static_size> const & opt) ConvolutionOptions<SrcShape::static_size> opt)
{ {
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
static const int M = N*(N+1)/2; static const int M = N*(N+1)/2;
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
typedef typename DestType::value_type DestValueType; typedef typename DestType::value_type DestValueType;
typedef typename NumericTraits<DestValueType>::RealPromote KernelType; typedef typename NumericTraits<DestValueType>::RealPromote KernelType;
typedef TinyVector<KernelType, N> GradientVector; typedef TinyVector<KernelType, N> GradientVector;
typedef typename AccessorTraits<GradientVector>::default_accessor Gradi entAccessor; typedef typename AccessorTraits<GradientVector>::default_accessor Gradi entAccessor;
typedef typename AccessorTraits<DestType>::default_accessor GradientTen sorAccessor; typedef typename AccessorTraits<DestType>::default_accessor GradientTen sorAccessor;
skipping to change at line 1933 skipping to change at line 2618
vigra_precondition(M == (int)dest.size(di), vigra_precondition(M == (int)dest.size(di),
"structureTensorMultiArray(): Wrong number of channels in output ar ray."); "structureTensorMultiArray(): Wrong number of channels in output ar ray.");
ConvolutionOptions<N> innerOptions = opt; ConvolutionOptions<N> innerOptions = opt;
ConvolutionOptions<N> outerOptions = opt.outerOptions(); ConvolutionOptions<N> outerOptions = opt.outerOptions();
typename ConvolutionOptions<N>::ScaleIterator params = outerOptions.sca leParams(); typename ConvolutionOptions<N>::ScaleIterator params = outerOptions.sca leParams();
SrcShape gradientShape(shape); SrcShape gradientShape(shape);
if(opt.to_point != SrcShape()) if(opt.to_point != SrcShape())
{ {
detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, opt.from_poi
nt);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, opt.to_point
);
for(int k=0; k<N; ++k, ++params) for(int k=0; k<N; ++k, ++params)
{ {
Kernel1D<double> gauss; Kernel1D<double> gauss;
gauss.initGaussian(params.sigma_scaled("structureTensorMultiArr ay"), 1.0, opt.window_ratio); gauss.initGaussian(params.sigma_scaled("structureTensorMultiArr ay"), 1.0, opt.window_ratio);
int dilation = gauss.right(); int dilation = gauss.right();
innerOptions.from_point[k] = std::max<MultiArrayIndex>(0, opt.f rom_point[k] - dilation); innerOptions.from_point[k] = std::max<MultiArrayIndex>(0, opt.f rom_point[k] - dilation);
innerOptions.to_point[k] = std::min<MultiArrayIndex>(shape[k], opt.to_point[k] + dilation); innerOptions.to_point[k] = std::min<MultiArrayIndex>(shape[k], opt.to_point[k] + dilation);
} }
outerOptions.from_point -= innerOptions.from_point; outerOptions.from_point -= innerOptions.from_point;
outerOptions.to_point -= innerOptions.from_point; outerOptions.to_point -= innerOptions.from_point;
skipping to change at line 1968 skipping to change at line 2656
di, dest, outerOptions, di, dest, outerOptions,
"structureTensorMultiArray"); "structureTensorMultiArray");
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess or src, structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess or src,
DestIterator di, DestAccessor dest, DestIterator di, DestAccessor dest,
double innerScale, double outerScale, double innerScale, double outerScale,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) ConvolutionOptions<SrcShape::static_size> opt = C onvolutionOptions<SrcShape::static_size>())
{ {
ConvolutionOptions<SrcShape::static_size> par = opt;
structureTensorMultiArray(si, shape, src, di, dest, structureTensorMultiArray(si, shape, src, di, dest,
par.stdDev(innerScale).outerScale(outerScale) ); opt.stdDev(innerScale).outerScale(outerScale) );
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
ConvolutionOptions<SrcShape::static_size> const & opt ) ConvolutionOptions<SrcShape::static_size> const & opt )
{ {
structureTensorMultiArray( source.first, source.second, source.third, structureTensorMultiArray( source.first, source.second, source.third,
skipping to change at line 1999 skipping to change at line 2686
structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source, structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double innerScale, double outerScale, double innerScale, double outerScale,
const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>()) const ConvolutionOptions<SrcShape::static_size> & opt = ConvolutionOptions<SrcShape::static_size>())
{ {
structureTensorMultiArray( source.first, source.second, source.third, structureTensorMultiArray( source.first, source.second, source.third,
dest.first, dest.second, dest.first, dest.second,
innerScale, outerScale, opt); innerScale, outerScale, opt);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>,
S2> dest,
ConvolutionOptions<N> opt )
{
if(opt.to_point != typename MultiArrayShape<N>::type())
{
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.from_point);
detail::RelativeToAbsoluteCoordinate<N-1>::exec(source.shape(), opt
.to_point);
vigra_precondition(dest.shape() == (opt.to_point - opt.from_point),
"structureTensorMultiArray(): shape mismatch between ROI and ou
tput.");
}
else
{
vigra_precondition(source.shape() == dest.shape(),
"structureTensorMultiArray(): shape mismatch between input and
output.");
}
structureTensorMultiArray( srcMultiArrayRange(source),
destMultiArray(dest), opt );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>,
S2> dest,
double innerScale, double outerScale,
ConvolutionOptions<N> opt = ConvolutionOptions<N>
())
{
structureTensorMultiArray(source, dest, opt.innerScale(innerScale).oute
rScale(outerScale));
}
//@} //@}
} //-- namespace vigra } //-- namespace vigra
#endif //-- VIGRA_MULTI_CONVOLUTION_H #endif //-- VIGRA_MULTI_CONVOLUTION_H
 End of changes. 152 change blocks. 
238 lines changed or deleted 1083 lines changed or added


 multi_distance.hxx   multi_distance.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn, */
/* and Ullrich Koethe */ /* Philipp Schubert and Ullrich Koethe */
/* */ /* */
/* This file is part of the VIGRA computer vision library. */ /* This file is part of the VIGRA computer vision library. */
/* The VIGRA Website is */ /* The VIGRA Website is */
/* http://hci.iwr.uni-heidelberg.de/vigra/ */ /* http://hci.iwr.uni-heidelberg.de/vigra/ */
/* Please direct questions, bug reports, and contributions to */ /* Please direct questions, bug reports, and contributions to */
/* ullrich.koethe@iwr.uni-heidelberg.de or */ /* ullrich.koethe@iwr.uni-heidelberg.de or */
/* vigra@informatik.uni-hamburg.de */ /* vigra@informatik.uni-hamburg.de */
/* */ /* */
/* Permission is hereby granted, free of charge, to any person */ /* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */ /* obtaining a copy of this software and associated documentation */
skipping to change at line 51 skipping to change at line 51
#include <functional> #include <functional>
#include "array_vector.hxx" #include "array_vector.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "accessor.hxx" #include "accessor.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "navigator.hxx" #include "navigator.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "multi_pointoperators.hxx" #include "multi_pointoperators.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "multi_gridgraph.hxx" //for boundaryGraph & boundaryMultiDista
nce
#include "union_find.hxx" //for boundaryGraph & boundaryMultiDistanc
e
namespace vigra namespace vigra
{ {
namespace detail namespace detail
{ {
template <class Value> template <class Value>
struct DistParabolaStackEntry struct DistParabolaStackEntry
{ {
double left, center, right; double left, center, right;
Value prevVal; Value apex_height;
DistParabolaStackEntry(Value const & p, double l, double c, double r) DistParabolaStackEntry(Value const & p, double l, double c, double r)
: left(l), center(c), right(r), prevVal(p) : left(l), center(c), right(r), apex_height(p)
{} {}
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* distParabola */ /* distParabola */
/* */ /* */
/* Version with sigma (parabola spread) for morphology */ /* Version with sigma (parabola spread) for morphology */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor > class DestIterator, class DestAccessor >
void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa, void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor da, double sigma ) DestIterator id, DestAccessor da, double sigma )
{ {
// We assume that the data in the input is distance squared and treat i t as such // We assume that the data in the input is distance squared and treat i t as such
double w = iend - is; double w = iend - is;
if(w <= 0)
return;
double sigma2 = sigma * sigma; double sigma2 = sigma * sigma;
double sigma22 = 2.0 * sigma2; double sigma22 = 2.0 * sigma2;
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
typedef DistParabolaStackEntry<SrcType> Influence; typedef DistParabolaStackEntry<SrcType> Influence;
std::vector<Influence> _stack; std::vector<Influence> _stack;
_stack.push_back(Influence(sa(is), 0.0, 0.0, w)); _stack.push_back(Influence(sa(is), 0.0, 0.0, w));
++is; ++is;
double current = 1.0; double current = 1.0;
while(current < w ) for(;current < w; ++is, ++current)
{ {
Influence & s = _stack.back(); double intersection;
double diff = current - s.center;
double intersection = current + (sa(is) - s.prevVal - sigma2*sq(dif
f)) / (sigma22 * diff);
if( intersection < s.left) // previous point has no influence while(true)
{ {
_stack.pop_back(); Influence & s = _stack.back();
if(_stack.empty()) double diff = current - s.center;
intersection = current + (sa(is) - s.apex_height - sigma2*sq(di
ff)) / (sigma22 * diff);
if( intersection < s.left) // previous point has no influence
{ {
_stack.push_back(Influence(sa(is), 0.0, current, w)); _stack.pop_back();
if(!_stack.empty())
continue; // try new top of stack without advancing cu
rrent
else
intersection = 0.0;
} }
else else if(intersection < s.right)
{ {
continue; // try new top of stack without advancing current s.right = intersection;
} }
break;
} }
else if(intersection < s.right) _stack.push_back(Influence(sa(is), intersection, current, w));
{
s.right = intersection;
_stack.push_back(Influence(sa(is), intersection, current, w));
}
++is;
++current;
} }
// Now we have the stack indicating which rows are influenced by (and t herefore // Now we have the stack indicating which rows are influenced by (and t herefore
// closest to) which row. We can go through the stack and calculate the // closest to) which row. We can go through the stack and calculate the
// distance squared for each element of the column. // distance squared for each element of the column.
typename std::vector<Influence>::iterator it = _stack.begin(); typename std::vector<Influence>::iterator it = _stack.begin();
for(current = 0.0; current < w; ++current, ++id) for(current = 0.0; current < w; ++current, ++id)
{ {
while( current >= it->right) while( current >= it->right)
++it; ++it;
da.set(sigma2 * sq(current - it->center) + it->prevVal, id); da.set(sigma2 * sq(current - it->center) + it->apex_height, id);
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void distParabola(triple<SrcIterator, SrcIterator, SrcAccessor> src, inline void distParabola(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, double sigm a) pair<DestIterator, DestAccessor> dest, double sigm a)
{ {
distParabola(src.first, src.second, src.third, distParabola(src.first, src.second, src.third,
dest.first, dest.second, sigma); dest.first, dest.second, sigma);
skipping to change at line 232 skipping to change at line 238
DestIterator di, DestAccess or dest) DestIterator di, DestAccess or dest)
{ {
ArrayVector<double> sigmas(shape.size(), 1.0); ArrayVector<double> sigmas(shape.size(), 1.0);
internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigmas, f alse ); internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigmas, f alse );
} }
} // namespace detail } // namespace detail
/** \addtogroup MultiArrayDistanceTransform Euclidean distance transform fo r multi-dimensional arrays. /** \addtogroup MultiArrayDistanceTransform Euclidean distance transform fo r multi-dimensional arrays.
These functions perform the Euclidean distance transform an arbitrary d These functions perform variants of the Euclidean distance transform on
imensional arbitrary dimensional arrays.
array that is specified by iterators (compatible to \ref MultiIteratorP
age)
and shape objects. It can therefore be applied to a wide range of data
structures
(\ref vigra::MultiArrayView, \ref vigra::MultiArray etc.).
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* separableMultiDistSquared */ /* separableMultiDistSquared */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Euclidean distance squared on multi-dimensional arrays. /** \brief Euclidean distance squared on multi-dimensional arrays.
The algorithm is taken from Donald Bailey: "An Efficient Euclidean Dist ance Transform", The algorithm is taken from Donald Bailey: "An Efficient Euclidean Dist ance Transform",
Proc. IWCIA'04, Springer LNCS 3322, 2004. Proc. IWCIA'04, Springer LNCS 3322, 2004.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// explicitly specify pixel pitch for each coordinate
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Array>
void
separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
bool background,
Array const & pixelPitch);
// use default pixel pitch = 1.0 for each coordinate
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
bool background);
}
\endcode
\deprecatedAPI{separableMultiDistSquared}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// explicitly specify pixel pitch for each coordinate // explicitly specify pixel pitch for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array> class DestIterator, class DestAccessor, class Array>
void void
separableMultiDistSquared( SrcIterator s, SrcShape const & shape, S rcAccessor src, separableMultiDistSquared( SrcIterator s, SrcShape const & shape, S rcAccessor src,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
bool background, bool background,
Array const & pixelPitch); Array const & pixelPitch);
skipping to change at line 274 skipping to change at line 302
// use default pixel pitch = 1.0 for each coordinate // use default pixel pitch = 1.0 for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
separableMultiDistSquared(SrcIterator siter, SrcShape const & shape , SrcAccessor src, separableMultiDistSquared(SrcIterator siter, SrcShape const & shape , SrcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
bool background); bool background);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// explicitly specify pixel pitch for each coordinate // explicitly specify pixel pitch for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array> class DestIterator, class DestAccessor, class Array>
void void
separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAccesso r> const & source, separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAccesso r> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
bool background, bool background,
skipping to change at line 297 skipping to change at line 324
// use default pixel pitch = 1.0 for each coordinate // use default pixel pitch = 1.0 for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
separableMultiDistSquared(triple<SrcIterator, SrcShape, SrcAccessor > const & source, separableMultiDistSquared(triple<SrcIterator, SrcShape, SrcAccessor > const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
bool background); bool background);
} }
\endcode \endcode
\deprecatedEnd
This function performs a squared Euclidean squared distance transform o n the given This function performs a squared Euclidean squared distance transform o n the given
multi-dimensional array. Both source and destination multi-dimensional array. Both source and destination
arrays are represented by iterators, shape objects and accessors. arrays are represented by iterators, shape objects and accessors.
The destination array is required to already have the correct size. The destination array is required to already have the correct size.
This function expects a mask as its source, where background pixels are This function expects a mask as its source, where background pixels are
marked as zero, and non-background pixels as non-zero. If the parameter marked as zero, and non-background pixels as non-zero. If the parameter
<i>background</i> is true, then the squared distance of all background <i>background</i> is true, then the squared distance of all background
pixels to the nearest object is calculated. Otherwise, the distance of all pixels to the nearest object is calculated. Otherwise, the distance of all
skipping to change at line 321 skipping to change at line 349
microscopy, for example). microscopy, for example).
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>siter == diter</t t> is allowed.
A full-sized internal array is only allocated if working on the destina tion A full-sized internal array is only allocated if working on the destina tion
array directly would cause overflow errors (i.e. if array directly would cause overflow errors (i.e. if
<tt> NumericTraits<typename DestAccessor::value_type>::max() < N * M*M< /tt>, where M is the <tt> NumericTraits<typename DestAccessor::value_type>::max() < N * M*M< /tt>, where M is the
size of the largest dimension of the array. size of the largest dimension of the array.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_distance.hxx\> <b>\#include</b> \<vigra/multi_distance.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, unsigned int> dest(shape); MultiArray<3, unsigned int> dest(shape);
... ...
// Calculate Euclidean distance squared for all background pixels // Calculate Euclidean distance squared for all background pixels
separableMultiDistSquared(srcMultiArrayRange(source), destMultiArray(de st), true); separableMultiDistSquared(source, dest, true);
\endcode \endcode
\see vigra::distanceTransform(), vigra::separableMultiDistance() \see vigra::distanceTransform(), vigra::separableMultiDistance()
*/ */
doxygen_overloaded_function(template <...> void separableMultiDistSquared) doxygen_overloaded_function(template <...> void separableMultiDistSquared)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array> class DestIterator, class DestAccessor, class Array>
void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA ccessor src, void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA ccessor src,
DestIterator d, DestAccessor dest, bool bac kground, DestIterator d, DestAccessor dest, bool bac kground,
skipping to change at line 400 skipping to change at line 429
ifThenElse( Arg1() == Param(zero), Param(m axDist), Param(rzero) )); ifThenElse( Arg1() == Param(zero), Param(m axDist), Param(rzero) ));
else else
transformMultiArray( s, shape, src, d, dest, transformMultiArray( s, shape, src, d, dest,
ifThenElse( Arg1() != Param(zero), Param(m axDist), Param(rzero) )); ifThenElse( Arg1() != Param(zero), Param(m axDist), Param(rzero) ));
detail::internalSeparableMultiArrayDistTmp( d, shape, dest, d, dest , pixelPitch); detail::internalSeparableMultiArrayDistTmp( d, shape, dest, d, dest , pixelPitch);
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array>
inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc
essor> const & source,
pair<DestIterator, DestAccessor> con
st & dest, bool background,
Array const & pixelPitch)
{
separableMultiDistSquared( source.first, source.second, source.third,
dest.first, dest.second, background, pixelPi
tch );
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA ccessor src, void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA ccessor src,
DestIterator d, DestAccessor dest, bool bac kground) DestIterator d, DestAccessor dest, bool bac kground)
{ {
ArrayVector<double> pixelPitch(shape.size(), 1.0); ArrayVector<double> pixelPitch(shape.size(), 1.0);
separableMultiDistSquared( s, shape, src, d, dest, background, pixelPit ch ); separableMultiDistSquared( s, shape, src, d, dest, background, pixelPit ch );
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array>
inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc
essor> const & source,
pair<DestIterator, DestAccessor> con
st & dest, bool background,
Array const & pixelPitch)
{
separableMultiDistSquared( source.first, source.second, source.third,
dest.first, dest.second, background, pixelPi
tch );
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc essor> const & source, inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc essor> const & source,
pair<DestIterator, DestAccessor> con st & dest, bool background) pair<DestIterator, DestAccessor> con st & dest, bool background)
{ {
separableMultiDistSquared( source.first, source.second, source.third, separableMultiDistSquared( source.first, source.second, source.third,
dest.first, dest.second, background ); dest.first, dest.second, background );
} }
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Array>
inline void
separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest, bool background,
Array const & pixelPitch)
{
vigra_precondition(source.shape() == dest.shape(),
"separableMultiDistSquared(): shape mismatch between input and outp
ut.");
separableMultiDistSquared( srcMultiArrayRange(source),
destMultiArray(dest), background, pixelPitch
);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest, bool background)
{
vigra_precondition(source.shape() == dest.shape(),
"separableMultiDistSquared(): shape mismatch between input and outp
ut.");
separableMultiDistSquared( srcMultiArrayRange(source),
destMultiArray(dest), background );
}
/********************************************************/ /********************************************************/
/* */ /* */
/* separableMultiDistance */ /* separableMultiDistance */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Euclidean distance on multi-dimensional arrays. /** \brief Euclidean distance on multi-dimensional arrays.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
// explicitly specify pixel pitch for each coordinate
template <unsigned int N, class T1, class S1,
class T2, class S2, class Array>
void
separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
bool background,
Array const & pixelPitch);
// use default pixel pitch = 1.0 for each coordinate
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
bool background);
}
\endcode
\deprecatedAPI{separableMultiDistance}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// explicitly specify pixel pitch for each coordinate // explicitly specify pixel pitch for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array> class DestIterator, class DestAccessor, class Array>
void void
separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcA ccessor src, separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcA ccessor src,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
bool background, bool background,
Array const & pixelPitch); Array const & pixelPitch);
skipping to change at line 460 skipping to change at line 538
// use default pixel pitch = 1.0 for each coordinate // use default pixel pitch = 1.0 for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
separableMultiDistance(SrcIterator siter, SrcShape const & shape, S rcAccessor src, separableMultiDistance(SrcIterator siter, SrcShape const & shape, S rcAccessor src,
DestIterator diter, DestAccessor dest, DestIterator diter, DestAccessor dest,
bool background); bool background);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// explicitly specify pixel pitch for each coordinate // explicitly specify pixel pitch for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array> class DestIterator, class DestAccessor, class Array>
void void
separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccessor> const & source, separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & de st, pair<DestIterator, DestAccessor> const & de st,
bool background, bool background,
skipping to change at line 483 skipping to change at line 560
// use default pixel pitch = 1.0 for each coordinate // use default pixel pitch = 1.0 for each coordinate
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
separableMultiDistance(triple<SrcIterator, SrcShape, SrcAccessor> c onst & source, separableMultiDistance(triple<SrcIterator, SrcShape, SrcAccessor> c onst & source,
pair<DestIterator, DestAccessor> const & des t, pair<DestIterator, DestAccessor> const & des t,
bool background); bool background);
} }
\endcode \endcode
\deprecatedEnd
This function performs a Euclidean distance transform on the given This function performs a Euclidean distance transform on the given
multi-dimensional array. It simply calls \ref separableMultiDistSquared () multi-dimensional array. It simply calls \ref separableMultiDistSquared ()
and takes the pixel-wise square root of the result. See \ref separableM ultiDistSquared() and takes the pixel-wise square root of the result. See \ref separableM ultiDistSquared()
for more documentation. for more documentation.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_distance.hxx\> <b>\#include</b> \<vigra/multi_distance.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape); MultiArray<3, float> dest(shape);
... ...
// Calculate Euclidean distance squared for all background pixels // Calculate Euclidean distance for all background pixels
separableMultiDistance(srcMultiArrayRange(source), destMultiArray(dest) separableMultiDistance(source, dest, true);
, true);
\endcode \endcode
\see vigra::distanceTransform(), vigra::separableMultiDistSquared() \see vigra::distanceTransform(), vigra::separableMultiDistSquared()
*/ */
doxygen_overloaded_function(template <...> void separableMultiDistance) doxygen_overloaded_function(template <...> void separableMultiDistance)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Array> class DestIterator, class DestAccessor, class Array>
void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAcce ssor src, void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAcce ssor src,
DestIterator d, DestAccessor dest, bool backgr ound, DestIterator d, DestAccessor dest, bool backgr ound,
skipping to change at line 553 skipping to change at line 632
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccess or> const & source, inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccess or> const & source,
pair<DestIterator, DestAccessor> const & dest, bool background) pair<DestIterator, DestAccessor> const & dest, bool background)
{ {
separableMultiDistance( source.first, source.second, source.third, separableMultiDistance( source.first, source.second, source.third,
dest.first, dest.second, background ); dest.first, dest.second, background );
} }
template <unsigned int N, class T1, class S1,
class T2, class S2, class Array>
inline void
separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
bool background,
Array const & pixelPitch)
{
vigra_precondition(source.shape() == dest.shape(),
"separableMultiDistance(): shape mismatch between input and output.
");
separableMultiDistance( srcMultiArrayRange(source),
destMultiArray(dest), background, pixelPitch );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
bool background)
{
vigra_precondition(source.shape() == dest.shape(),
"separableMultiDistance(): shape mismatch between input and output.
");
separableMultiDistance( srcMultiArrayRange(source),
destMultiArray(dest), background );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% BoundaryDistanceTransform %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//rewrite labeled data and work with separableMultiDist
namespace lemon_graph {
template <class Graph, class T1Map, class T2Map>
void
markRegionBoundaries(Graph const & g,
T1Map const & labels,
T2Map & out)
{
typedef typename Graph::NodeIt graph_scanner;
typedef typename Graph::OutBackArcIt neighbor_iterator;
//find faces
for (graph_scanner node(g); node != INVALID; ++node)
{
typename T1Map::value_type center = labels[*node];
for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
{
// set adjacent nodes with different labels to 1
if(center != labels[g.target(*arc)])
{
out[*node] = 1;
out[g.target(*arc)] = 1;
}
}
}
}
} //-- namspace lemon_graph
doxygen_overloaded_function(template <...> unsigned int markRegionBoundarie
s)
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
markRegionBoundaries(MultiArrayView<N, T1, S1> const & labels,
MultiArrayView<N, T2, S2> out,
NeighborhoodType neighborhood=DirectNeighborhood)
{
vigra_precondition(labels.shape() == out.shape(),
"markRegionBoundaries(): shape mismatch between input and output.")
;
GridGraph<N, undirected_tag> graph(labels.shape(), neighborhood);
lemon_graph::markRegionBoundaries(graph, labels, out);
}
//MultiDistance which works directly on labeled data
namespace detail
{
/********************************************************/
/* */
/* boundaryDistParabola */
/* */
/********************************************************/
template <class DestIterator, class LabelIterator>
void
boundaryDistParabola(DestIterator is, DestIterator iend,
LabelIterator ilabels,
double dmax,
bool array_border_is_active=false)
{
// We assume that the data in the input is distance squared and treat i
t as such
double w = iend - is;
if(w <= 0)
return;
DestIterator id = is;
typedef typename LabelIterator::value_type LabelType;
typedef typename DestIterator::value_type DestType;
typedef detail::DistParabolaStackEntry<DestType> Influence;
typedef std::vector<Influence> Stack;
double apex_height = array_border_is_active
? 0.0
: dmax;
Stack _stack(1, Influence(apex_height, 0.0, -1.0, w));
LabelType current_label = *ilabels;
for(double begin = 0.0, current = 0.0; current <= w; ++ilabels, ++is, +
+current)
{
apex_height = (current < w)
? (current_label == *ilabels)
? *is
: 0.0
: array_border_is_active
? 0.0
: dmax;
while(true)
{
Influence & s = _stack.back();
double diff = current - s.center;
double intersection = current + (apex_height - s.apex_height -
sq(diff)) / (2.0 * diff);
if(intersection < s.left) // previous parabola has no influence
{
_stack.pop_back();
if(_stack.empty())
intersection = begin; // new parabola is valid for enti
re present segment
else
continue; // try new top of stack without advancing to
next pixel
}
else if(intersection < s.right)
{
s.right = intersection;
}
if(intersection < w)
_stack.push_back(Influence(apex_height, intersection, curre
nt, w));
if(current < w && current_label == *ilabels)
break; // finished present pixel, advance to next one
// label changed => finalize the current segment
typename Stack::iterator it = _stack.begin();
for(double c = begin; c < current; ++c, ++id)
{
while(c >= it->right)
++it;
*id = sq(c - it->center) + it->apex_height;
}
if(current == w)
break; // stop when this was the last segment
// initialize the new segment
begin = current;
current_label = *ilabels;
apex_height = *is;
Stack(1, Influence(0.0, begin-1.0, begin-1.0, w)).swap(_stack);
// don't advance to next pixel here, because the present pixel
must also
// be analysed in the context of the new segment
}
}
}
/********************************************************/
/* */
/* internalBoundaryMultiArrayDist */
/* */
/********************************************************/
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
internalBoundaryMultiArrayDist(
MultiArrayView<N, T1, S1> const & labels,
MultiArrayView<N, T2, S2> dest,
double dmax, bool array_border_is_active=false)
{
typedef typename MultiArrayView<N, T1, S1>::const_traverser LabelIterat
or;
typedef typename MultiArrayView<N, T2, S2>::traverser DestIterator;
typedef MultiArrayNavigator<LabelIterator, N> LabelNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator;
dest = dmax;
for( int d = 0; d < N; ++d )
{
LabelNavigator lnav( labels.traverser_begin(), labels.shape(), d );
DNavigator dnav( dest.traverser_begin(), dest.shape(), d );
for( ; dnav.hasMore(); dnav++, lnav++ )
{
boundaryDistParabola(dnav.begin(), dnav.end(),
lnav.begin(),
dmax, array_border_is_active);
}
}
}
} // namespace detail
/** \brief Specify which boundary is used for boundaryMultiDistance().
*/
enum BoundaryDistanceTag {
OuterBoundary, ///< Pixels just outside of each region
InterpixelBoundary, ///< Half-integer points between pixels of differen
t labels
InnerBoundary ///< Pixels just inside of each region
};
/********************************************************/
/* */
/* boundaryMultiDistance */
/* */
/********************************************************/
/** \brief Euclidean distance to the implicit boundaries of a multi-dimensi
onal label array.
<b> Declarations:</b>
pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
boundaryMultiDistance(MultiArrayView<N, T1, S1> const & labels,
MultiArrayView<N, T2, S2> dest,
bool array_border_is_active=false,
BoundaryDistanceTag boundary=InterpixelBounda
ry);
}
\endcode
This function computes the distance transform of a labeled image <i>sim
ultaneously</i>
for all regions. Depending on the requested type of \a boundary, three
modes
are supported:
<ul>
<li><tt>OuterBoundary</tt>: In each region, compute the distance to the
nearest pixel not
belonging to that regions. This is the same as if a normal d
istance transform
where applied to a binary image containing just this region.
</li>
<li><tt>InterpixelBoundary</tt> (default): Like <tt>OuterBoundary</tt>,
but shift the distance
to the interpixel boundary by subtractiong 1/2. This make th
e distences consistent
accross boundaries.</li>
<li><tt>InnerBoundary</tt>: In each region, compute the distance to the
nearest pixel in the
region which is adjacent to the boundary. </li>
</ul>
If <tt>array_border_is_active=true</tt>, the
outer border of the array (i.e. the interpixel boundary between the arr
ay
and the infinite region) is also used. Otherwise (the default), regions
touching the array border are treated as if they extended to infinity.
<b> Usage:</b>
<b>\#include</b> \<vigra/multi_distance.hxx\><br/>
Namespace: vigra
\code
Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape);
MultiArray<3, UInt32> labels(shape);
MultiArray<3, float> dest(shape);
...
// find regions (interpixel boundaries are implied)
labelMultiArray(source, labels);
// Calculate Euclidean distance to interpixel boundary for all pixels
boundaryMultiDistance(labels, dest);
\endcode
\see vigra::distanceTransform(), vigra::separableMultiDistance()
*/
doxygen_overloaded_function(template <...> void boundaryMultiDistance)
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
boundaryMultiDistance(MultiArrayView<N, T1, S1> const & labels,
MultiArrayView<N, T2, S2> dest,
bool array_border_is_active=false,
BoundaryDistanceTag boundary=InterpixelBoundary)
{
vigra_precondition(labels.shape() == dest.shape(),
"boundaryMultiDistance(): shape mismatch between input and output."
);
using namespace vigra::functor;
if(boundary == InnerBoundary)
{
MultiArray<N, unsigned char> boundaries(labels.shape());
markRegionBoundaries(labels, boundaries, IndirectNeighborhood);
if(array_border_is_active)
initMultiArrayBorder(boundaries, 1, 1);
separableMultiDistance(boundaries, dest, true);
}
else
{
T2 offset = 0.0;
if(boundary == InterpixelBoundary)
{
vigra_precondition(!NumericTraits<T2>::isIntegral::value,
"boundaryMultiDistance(..., InterpixelBoundary): output pix
el type must be float or double.");
offset = T2(0.5);
}
double dmax = squaredNorm(labels.shape()) + N;
if(dmax > double(NumericTraits<T2>::max()))
{
// need a temporary array to avoid overflows
typedef typename NumericTraits<T2>::RealPromote Real;
MultiArray<N, Real> tmpArray(labels.shape());
detail::internalBoundaryMultiArrayDist(labels, tmpArray,
dmax, array_border_is
_active);
transformMultiArray(tmpArray, dest, sqrt(Arg1()) - Param(offset
) );
}
else
{
// can work directly on the destination array
detail::internalBoundaryMultiArrayDist(labels, dest, dmax, arra
y_border_is_active);
transformMultiArray(dest, dest, sqrt(Arg1()) - Param(offset) );
}
}
}
//@} //@}
} //-- namespace vigra } //-- namespace vigra
#endif //-- VIGRA_MULTI_DISTANCE_HXX #endif //-- VIGRA_MULTI_DISTANCE_HXX
 End of changes. 32 change blocks. 
55 lines changed or deleted 491 lines changed or added


 multi_fft.hxx   multi_fft.hxx 
skipping to change at line 41 skipping to change at line 41
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MULTI_FFT_HXX #ifndef VIGRA_MULTI_FFT_HXX
#define VIGRA_MULTI_FFT_HXX #define VIGRA_MULTI_FFT_HXX
#include "fftw3.hxx" #include "fftw3.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "multi_math.hxx"
#include "navigator.hxx" #include "navigator.hxx"
#include "copyimage.hxx" #include "copyimage.hxx"
#include "threading.hxx"
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* Fourier Transform */ /* Fourier Transform */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup FourierTransform /** \addtogroup FourierTransform
skipping to change at line 169 skipping to change at line 171
template <unsigned int N, class T, class C> template <unsigned int N, class T, class C>
inline void moveDCToHalfspaceUpperLeft(MultiArrayView<N, T, C> a) inline void moveDCToHalfspaceUpperLeft(MultiArrayView<N, T, C> a)
{ {
detail::moveDCToUpperLeftImpl(a, 1); detail::moveDCToUpperLeftImpl(a, 1);
} }
namespace detail namespace detail
{ {
#ifndef VIGRA_SINGLE_THREADED
template <int DUMMY=0>
class FFTWLock
{
public:
threading::lock_guard<threading::mutex> guard_;
FFTWLock()
: guard_(plan_mutex_)
{}
static threading::mutex plan_mutex_;
};
template <int DUMMY>
threading::mutex FFTWLock<DUMMY>::plan_mutex_;
#else // VIGRA_SINGLE_THREADED
template <int DUMMY=0>
class FFTWLock
{
public:
FFTWLock()
{}
};
#endif // not VIGRA_SINGLE_THREADED
inline fftw_plan inline fftw_plan
fftwPlanCreate(unsigned int N, int* shape, fftwPlanCreate(unsigned int N, int* shape,
FFTWComplex<double> * in, int* instrides, int instep, FFTWComplex<double> * in, int* instrides, int instep,
FFTWComplex<double> * out, int* outstrides, int outstep, FFTWComplex<double> * out, int* outstrides, int outstep,
int sign, unsigned int planner_flags) int sign, unsigned int planner_flags)
{ {
return fftw_plan_many_dft(N, shape, 1, return fftw_plan_many_dft(N, shape, 1,
(fftw_complex *)in, instrides, instep, 0, (fftw_complex *)in, instrides, instep, 0,
(fftw_complex *)out, outstrides, outstep, 0, (fftw_complex *)out, outstrides, outstep, 0,
sign, planner_flags); sign, planner_flags);
skipping to change at line 367 skipping to change at line 400
{ {
fftwl_execute_dft_r2c(plan, in, (fftwl_complex *)out); fftwl_execute_dft_r2c(plan, in, (fftwl_complex *)out);
} }
inline void inline void
fftwPlanExecute(fftwl_plan plan, FFTWComplex<long double> * in, long doubl e * out) fftwPlanExecute(fftwl_plan plan, FFTWComplex<long double> * in, long doubl e * out)
{ {
fftwl_execute_dft_c2r(plan, (fftwl_complex *)in, out); fftwl_execute_dft_c2r(plan, (fftwl_complex *)in, out);
} }
inline template <int DUMMY>
int fftwPaddingSize(int s) struct FFTWPaddingSize
{ {
static const int size = 1330;
static const int evenSize = 1063;
static int goodSizes[size];
static int goodEvenSizes[evenSize];
static inline int find(int s)
{
if(s <= 0 || s >= goodSizes[size-1])
return s;
// find the smallest padding size that is at least as large as 's'
int * upperBound = std::upper_bound(goodSizes, goodSizes+size, s);
if(upperBound > goodSizes && upperBound[-1] == s)
return s;
else
return *upperBound;
}
static inline int findEven(int s)
{
if(s <= 0 || s >= goodEvenSizes[evenSize-1])
return s;
// find the smallest padding size that is at least as large as 's'
int * upperBound = std::upper_bound(goodEvenSizes, goodEvenSizes+ev
enSize, s);
if(upperBound > goodEvenSizes && upperBound[-1] == s)
return s;
else
return *upperBound;
}
};
// Image sizes where FFTW is fast. The list contains all // Image sizes where FFTW is fast. The list contains all
// numbers less than 100000 whose prime decomposition is of the form // numbers less than 100000 whose prime decomposition is of the form
// 2^a*3^b*5^c*7^d*11^e*13^f, where e+f is either 0 or 1, and the // 2^a*3^b*5^c*7^d*11^e*13^f, where e+f is either 0 or 1, and the
// other exponents are arbitrary // other exponents are arbitrary
static const int size = 1330; template <int DUMMY>
static int goodSizes[size] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1 int FFTWPaddingSize<DUMMY>::goodSizes[size] = {
3, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36, 39, 40, 42, 44, 45, 48, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36, 39, 40, 42, 44, 45, 48,
49, 50, 52, 54, 55, 56, 60, 63, 64, 65, 66, 70, 72, 75, 77, 78, 80, 81, 49, 50, 52, 54, 55, 56, 60, 63, 64, 65, 66, 70, 72, 75, 77, 78, 80, 81,
84, 88, 90, 91, 96, 98, 99, 100, 104, 105, 108, 110, 112, 117, 120, 125, 84, 88, 90, 91, 96, 98, 99, 100, 104, 105, 108, 110, 112, 117, 120, 125,
126, 128, 130, 132, 135, 140, 144, 147, 150, 154, 156, 160, 162, 16 5, 126, 128, 130, 132, 135, 140, 144, 147, 150, 154, 156, 160, 162, 16 5,
168, 175, 176, 180, 182, 189, 192, 195, 196, 198, 200, 208, 210, 21 6, 168, 175, 176, 180, 182, 189, 192, 195, 196, 198, 200, 208, 210, 21 6,
220, 224, 225, 231, 234, 240, 243, 245, 250, 252, 256, 260, 264, 27 0, 220, 224, 225, 231, 234, 240, 243, 245, 250, 252, 256, 260, 264, 27 0,
273, 275, 280, 288, 294, 297, 300, 308, 312, 315, 320, 324, 325, 33 0, 273, 275, 280, 288, 294, 297, 300, 308, 312, 315, 320, 324, 325, 33 0,
336, 343, 350, 351, 352, 360, 364, 375, 378, 384, 385, 390, 392, 39 6, 336, 343, 350, 351, 352, 360, 364, 375, 378, 384, 385, 390, 392, 39 6,
400, 405, 416, 420, 432, 440, 441, 448, 450, 455, 462, 468, 480, 48 6, 400, 405, 416, 420, 432, 440, 441, 448, 450, 455, 462, 468, 480, 48 6,
490, 495, 500, 504, 512, 520, 525, 528, 539, 540, 546, 550, 560, 56 7, 490, 495, 500, 504, 512, 520, 525, 528, 539, 540, 546, 550, 560, 56 7,
skipping to change at line 494 skipping to change at line 558
78000, 78125, 78400, 78624, 78732, 78750, 78848, 78975, 79200, 7923 3, 78000, 78125, 78400, 78624, 78732, 78750, 78848, 78975, 79200, 7923 3,
79380, 79625, 79872, 80000, 80190, 80262, 80640, 80850, 81000, 8125 0, 79380, 79625, 79872, 80000, 80190, 80262, 80640, 80850, 81000, 8125 0,
81536, 81648, 81900, 81920, 82320, 82500, 82944, 83160, 83200, 8334 9, 81536, 81648, 81900, 81920, 82320, 82500, 82944, 83160, 83200, 8334 9,
84000, 84035, 84240, 84375, 84480, 84672, 85050, 85293, 85536, 8575 0, 84000, 84035, 84240, 84375, 84480, 84672, 85050, 85293, 85536, 8575 0,
85995, 86016, 86240, 86400, 86436, 86625, 87318, 87360, 87480, 8750 0, 85995, 86016, 86240, 86400, 86436, 86625, 87318, 87360, 87480, 8750 0,
87750, 87808, 88000, 88200, 88452, 88704, 89100, 89180, 89600, 8985 6, 87750, 87808, 88000, 88200, 88452, 88704, 89100, 89180, 89600, 8985 6,
90000, 90112, 90552, 90720, 91000, 91125, 91728, 91854, 91875, 9216 0, 90000, 90112, 90552, 90720, 91000, 91125, 91728, 91854, 91875, 9216 0,
92400, 92610, 93184, 93312, 93555, 93600, 93639, 93750, 94080, 9432 5, 92400, 92610, 93184, 93312, 93555, 93600, 93639, 93750, 94080, 9432 5,
94500, 94770, 95040, 95256, 95550, 96000, 96040, 96228, 96250, 9676 8, 94500, 94770, 95040, 95256, 95550, 96000, 96040, 96228, 96250, 9676 8,
97020, 97200, 97500, 98000, 98280, 98304, 98415, 98560, 98784, 9900 0, 97020, 97200, 97500, 98000, 98280, 98304, 98415, 98560, 98784, 9900 0,
99225, 99792, 99840 }; 99225, 99792, 99840
};
if(s <= 0 || s >= goodSizes[size-1])
return s;
// find the smallest padding size that is at least as large as 's'
int * upperBound = std::upper_bound(goodSizes, goodSizes+size, s);
if(upperBound > goodSizes && upperBound[-1] == s)
return s;
else
return *upperBound;
}
inline template <int DUMMY>
int fftwEvenPaddingSize(int s) int FFTWPaddingSize<DUMMY>::goodEvenSizes[evenSize] = {
{ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,
// Image sizes where FFTW is fast. The list contains all even
// numbers less than 100000 whose prime decomposition is of the form
// 2^a*3^b*5^c*7^d*11^e*13^f, where a >= 1, e+f is either 0 or 1, and t
he
// other exponents are arbitrary
static const int size = 1063;
static int goodSizes[size] = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,
24, 26, 28, 30, 32, 36, 40, 42, 44, 48, 50, 52, 54, 56, 60, 64, 66, 70, 24, 26, 28, 30, 32, 36, 40, 42, 44, 48, 50, 52, 54, 56, 60, 64, 66, 70,
72, 78, 80, 84, 88, 90, 96, 98, 100, 104, 108, 110, 112, 120, 126, 128, 72, 78, 80, 84, 88, 90, 96, 98, 100, 104, 108, 110, 112, 120, 126, 128,
130, 132, 140, 144, 150, 154, 156, 160, 162, 168, 176, 180, 182, 19 2, 130, 132, 140, 144, 150, 154, 156, 160, 162, 168, 176, 180, 182, 19 2,
196, 198, 200, 208, 210, 216, 220, 224, 234, 240, 250, 252, 256, 26 0, 196, 198, 200, 208, 210, 216, 220, 224, 234, 240, 250, 252, 256, 26 0,
264, 270, 280, 288, 294, 300, 308, 312, 320, 324, 330, 336, 350, 35 2, 264, 270, 280, 288, 294, 300, 308, 312, 320, 324, 330, 336, 350, 35 2,
360, 364, 378, 384, 390, 392, 396, 400, 416, 420, 432, 440, 448, 45 0, 360, 364, 378, 384, 390, 392, 396, 400, 416, 420, 432, 440, 448, 45 0,
462, 468, 480, 486, 490, 500, 504, 512, 520, 528, 540, 546, 550, 56 0, 462, 468, 480, 486, 490, 500, 504, 512, 520, 528, 540, 546, 550, 56 0,
576, 588, 594, 600, 616, 624, 630, 640, 648, 650, 660, 672, 686, 70 0, 576, 588, 594, 600, 616, 624, 630, 640, 648, 650, 660, 672, 686, 70 0,
702, 704, 720, 728, 750, 756, 768, 770, 780, 784, 792, 800, 810, 83 2, 702, 704, 720, 728, 750, 756, 768, 770, 780, 784, 792, 800, 810, 83 2,
840, 864, 880, 882, 896, 900, 910, 924, 936, 960, 972, 980, 990, 10 00, 840, 864, 880, 882, 896, 900, 910, 924, 936, 960, 972, 980, 990, 10 00,
skipping to change at line 610 skipping to change at line 659
73500, 73710, 73728, 73920, 74088, 74250, 74844, 74880, 75000, 7526 4, 73500, 73710, 73728, 73920, 74088, 74250, 74844, 74880, 75000, 7526 4,
75460, 75600, 75816, 76032, 76440, 76800, 76832, 77000, 77616, 7776 0, 75460, 75600, 75816, 76032, 76440, 76800, 76832, 77000, 77616, 7776 0,
78000, 78400, 78624, 78732, 78750, 78848, 79200, 79380, 79872, 8000 0, 78000, 78400, 78624, 78732, 78750, 78848, 79200, 79380, 79872, 8000 0,
80190, 80262, 80640, 80850, 81000, 81250, 81536, 81648, 81900, 8192 0, 80190, 80262, 80640, 80850, 81000, 81250, 81536, 81648, 81900, 8192 0,
82320, 82500, 82944, 83160, 83200, 84000, 84240, 84480, 84672, 8505 0, 82320, 82500, 82944, 83160, 83200, 84000, 84240, 84480, 84672, 8505 0,
85536, 85750, 86016, 86240, 86400, 86436, 87318, 87360, 87480, 8750 0, 85536, 85750, 86016, 86240, 86400, 86436, 87318, 87360, 87480, 8750 0,
87750, 87808, 88000, 88200, 88452, 88704, 89100, 89180, 89600, 8985 6, 87750, 87808, 88000, 88200, 88452, 88704, 89100, 89180, 89600, 8985 6,
90000, 90112, 90552, 90720, 91000, 91728, 91854, 92160, 92400, 9261 0, 90000, 90112, 90552, 90720, 91000, 91728, 91854, 92160, 92400, 9261 0,
93184, 93312, 93600, 93750, 94080, 94500, 94770, 95040, 95256, 9555 0, 93184, 93312, 93600, 93750, 94080, 94500, 94770, 95040, 95256, 9555 0,
96000, 96040, 96228, 96250, 96768, 97020, 97200, 97500, 98000, 9828 0, 96000, 96040, 96228, 96250, 96768, 97020, 97200, 97500, 98000, 9828 0,
98304, 98560, 98784, 99000, 99792, 99840 }; 98304, 98560, 98784, 99000, 99792, 99840
};
if(s <= 0 || s >= goodSizes[size-1])
return s;
// find the smallest padding size that is at least as large as 's'
int * upperBound = std::upper_bound(goodSizes, goodSizes+size, s);
if(upperBound > goodSizes && upperBound[-1] == s)
return s;
else
return *upperBound;
}
template <int M> template <int M>
struct FFTEmbedKernel struct FFTEmbedKernel
{ {
template <unsigned int N, class Real, class C, class Shape> template <unsigned int N, class Real, class C, class Shape>
static void static void
exec(MultiArrayView<N, Real, C> & out, Shape const & kernelShape, exec(MultiArrayView<N, Real, C> & out, Shape const & kernelShape,
Shape & srcPoint, Shape & destPoint, bool copyIt) Shape & srcPoint, Shape & destPoint, bool copyIt)
{ {
for(srcPoint[M]=0; srcPoint[M]<kernelShape[M]; ++srcPoint[M]) for(srcPoint[M]=0; srcPoint[M]<kernelShape[M]; ++srcPoint[M])
skipping to change at line 734 skipping to change at line 774
} }
} }
} // namespace detail } // namespace detail
template <class T, int N> template <class T, int N>
TinyVector<T, N> TinyVector<T, N>
fftwBestPaddedShape(TinyVector<T, N> shape) fftwBestPaddedShape(TinyVector<T, N> shape)
{ {
for(unsigned int k=0; k<N; ++k) for(unsigned int k=0; k<N; ++k)
shape[k] = detail::fftwPaddingSize(shape[k]); shape[k] = detail::FFTWPaddingSize<0>::find(shape[k]);
return shape; return shape;
} }
template <class T, int N> template <class T, int N>
TinyVector<T, N> TinyVector<T, N>
fftwBestPaddedShapeR2C(TinyVector<T, N> shape) fftwBestPaddedShapeR2C(TinyVector<T, N> shape)
{ {
shape[0] = detail::fftwEvenPaddingSize(shape[0]); shape[0] = detail::FFTWPaddingSize<0>::findEven(shape[0]);
for(unsigned int k=1; k<N; ++k) for(unsigned int k=1; k<N; ++k)
shape[k] = detail::fftwPaddingSize(shape[k]); shape[k] = detail::FFTWPaddingSize<0>::find(shape[k]);
return shape; return shape;
} }
/** \brief Find frequency domain shape for a R2C Fourier transform. /** \brief Find frequency domain shape for a R2C Fourier transform.
When a real valued array is transformed to the frequency domain, about half of the When a real valued array is transformed to the frequency domain, about half of the
Fourier coefficients are redundant. The transform can be optimized as a <a href="http://www.fftw.org/doc/Multi_002dDimensional-DFTs-of-Real-Data.h tml">R2C Fourier coefficients are redundant. The transform can be optimized as a <a href="http://www.fftw.org/doc/Multi_002dDimensional-DFTs-of-Real-Data.h tml">R2C
transform</a> that doesn't compute and store the redundant coefficients . This function transform</a> that doesn't compute and store the redundant coefficients . This function
computes the appropriate frequency domain shape for a given shape in th e spatial domain. computes the appropriate frequency domain shape for a given shape in th e spatial domain.
It simply replaces <tt>shape[0]</tt> with <tt>shape[0] / 2 + 1</tt>. It simply replaces <tt>shape[0]</tt> with <tt>shape[0] / 2 + 1</tt>.
<b>\#include</b> \<vigra/multi_fft.hxx\> <b>\#include</b> \<vigra/multi_fft.hxx\><br/>
Namespace: vigra
*/ */
template <class T, int N> template <class T, int N>
TinyVector<T, N> TinyVector<T, N>
fftwCorrespondingShapeR2C(TinyVector<T, N> shape) fftwCorrespondingShapeR2C(TinyVector<T, N> shape)
{ {
shape[0] = shape[0] / 2 + 1; shape[0] = shape[0] / 2 + 1;
return shape; return shape;
} }
template <class T, int N> template <class T, int N>
skipping to change at line 920 skipping to change at line 961
sign = o.sign; sign = o.sign;
o.plan = 0; // act like std::auto_ptr o.plan = 0; // act like std::auto_ptr
} }
return *this; return *this;
} }
/** \brief Destructor. /** \brief Destructor.
*/ */
~FFTWPlan() ~FFTWPlan()
{ {
detail::FFTWLock<> lock;
detail::fftwPlanDestroy(plan); detail::fftwPlanDestroy(plan);
} }
/** \brief Init a complex-to-complex transform. /** \brief Init a complex-to-complex transform.
See the constructor with the same signature for details. See the constructor with the same signature for details.
*/ */
template <class C1, class C2> template <class C1, class C2>
void init(MultiArrayView<N, FFTWComplex<Real>, C1> in, void init(MultiArrayView<N, FFTWComplex<Real>, C1> in,
MultiArrayView<N, FFTWComplex<Real>, C2> out, MultiArrayView<N, FFTWComplex<Real>, C2> out,
skipping to change at line 1072 skipping to change at line 1114
newOStrides(outs.stride().begin(), outs.stride().end()), newOStrides(outs.stride().begin(), outs.stride().end()),
itotal(ins.shape().begin(), ins.shape().end()), itotal(ins.shape().begin(), ins.shape().end()),
ototal(outs.shape().begin(), outs.shape().end()); ototal(outs.shape().begin(), outs.shape().end());
for(unsigned int j=1; j<N; ++j) for(unsigned int j=1; j<N; ++j)
{ {
itotal[j] = ins.stride(j-1) / ins.stride(j); itotal[j] = ins.stride(j-1) / ins.stride(j);
ototal[j] = outs.stride(j-1) / outs.stride(j); ototal[j] = outs.stride(j-1) / outs.stride(j);
} }
PlanType newPlan = detail::fftwPlanCreate(N, newShape.begin(), {
ins.data(), itotal.begin(), ins.stride(N- detail::FFTWLock<> lock;
1), PlanType newPlan = detail::fftwPlanCreate(N, newShape.begin(),
outs.data(), ototal.begin(), outs.stride( ins.data(), itotal.begin(), ins.strid
N-1), e(N-1),
SIGN, planner_flags); outs.data(), ototal.begin(), outs.str
detail::fftwPlanDestroy(plan); ide(N-1),
plan = newPlan; SIGN, planner_flags);
detail::fftwPlanDestroy(plan);
plan = newPlan;
}
shape.swap(newShape); shape.swap(newShape);
instrides.swap(newIStrides); instrides.swap(newIStrides);
outstrides.swap(newOStrides); outstrides.swap(newOStrides);
sign = SIGN; sign = SIGN;
} }
template <unsigned int N, class Real> template <unsigned int N, class Real>
template <class MI, class MO> template <class MI, class MO>
void FFTWPlan<N, Real>::executeImpl(MI ins, MO outs) const void FFTWPlan<N, Real>::executeImpl(MI ins, MO outs) const
{ {
skipping to change at line 1411 skipping to change at line 1457
/** \brief Execute a plan to convolve a real array with a real kern el. /** \brief Execute a plan to convolve a real array with a real kern el.
The array shapes must be the same as in the corresponding init function The array shapes must be the same as in the corresponding init function
or constructor. However, execute() can be called several times on or constructor. However, execute() can be called several times on
the same plan, even with different arrays, as long as they have the appropriate the same plan, even with different arrays, as long as they have the appropriate
shapes. shapes.
*/ */
template <class C1, class C2, class C3> template <class C1, class C2, class C3>
void execute(MultiArrayView<N, Real, C1> in, void execute(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel, MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out); MultiArrayView<N, Real, C3> out)
{
executeImpl(in, kernel, out);
}
/** \brief Execute a plan to convolve a real array with a complex k ernel. /** \brief Execute a plan to convolve a real array with a complex k ernel.
The array shapes must be the same as in the corresponding init function The array shapes must be the same as in the corresponding init function
or constructor. However, execute() can be called several times on or constructor. However, execute() can be called several times on
the same plan, even with different arrays, as long as they have the appropriate the same plan, even with different arrays, as long as they have the appropriate
shapes. shapes.
*/ */
template <class C1, class C2, class C3> template <class C1, class C2, class C3>
void execute(MultiArrayView<N, Real, C1> in, void execute(MultiArrayView<N, Real, C1> in,
skipping to change at line 1478 skipping to change at line 1527
bool fourierKernel = IsSameType<KernelValue, Complex>::value; bool fourierKernel = IsSameType<KernelValue, Complex>::value;
vigra_precondition(realKernel || fourierKernel, vigra_precondition(realKernel || fourierKernel,
"FFTWConvolvePlan::executeMany(): kernels have unsuitable valu e_type."); "FFTWConvolvePlan::executeMany(): kernels have unsuitable valu e_type.");
vigra_precondition((IsSameType<OutValue, Real>::value), vigra_precondition((IsSameType<OutValue, Real>::value),
"FFTWConvolvePlan::executeMany(): outputs have unsuitable valu e_type."); "FFTWConvolvePlan::executeMany(): outputs have unsuitable valu e_type.");
executeManyImpl(in, kernels, kernelsEnd, outs, UseFourierKernel()); executeManyImpl(in, kernels, kernelsEnd, outs, UseFourierKernel());
} }
private: protected:
template <class KernelIterator, class OutIterator> template <class KernelIterator, class OutIterator>
Shape checkShapes(Shape in, Shape checkShapes(Shape in,
KernelIterator kernels, KernelIterator kernelsEnd, KernelIterator kernels, KernelIterator kernelsEnd,
OutIterator outs); OutIterator outs);
template <class KernelIterator, class OutIterator> template <class KernelIterator, class OutIterator>
Shape checkShapesFourier(Shape in, Shape checkShapesFourier(Shape in,
KernelIterator kernels, KernelIterator kernels End, KernelIterator kernels, KernelIterator kernels End,
OutIterator outs); OutIterator outs);
template <class KernelIterator, class OutIterator> template <class KernelIterator, class OutIterator>
Shape checkShapesComplex(Shape in, Shape checkShapesComplex(Shape in,
KernelIterator kernels, KernelIterator kernels End, KernelIterator kernels, KernelIterator kernels End,
OutIterator outs); OutIterator outs);
template <class C1, class C2, class C3>
void executeImpl(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out,
bool do_correlation=false);
template <class C1, class KernelIterator, class OutIterator> template <class C1, class KernelIterator, class OutIterator>
void void
executeManyImpl(MultiArrayView<N, Real, C1> in, executeManyImpl(MultiArrayView<N, Real, C1> in,
KernelIterator kernels, KernelIterator kernelsEnd, KernelIterator kernels, KernelIterator kernelsEnd,
OutIterator outs, VigraFalseType /* useFourierKernel*/) ; OutIterator outs, VigraFalseType /* useFourierKernel*/) ;
template <class C1, class KernelIterator, class OutIterator> template <class C1, class KernelIterator, class OutIterator>
void void
executeManyImpl(MultiArrayView<N, Real, C1> in, executeManyImpl(MultiArrayView<N, Real, C1> in,
KernelIterator kernels, KernelIterator kernelsEnd, KernelIterator kernels, KernelIterator kernelsEnd,
skipping to change at line 1603 skipping to change at line 1658
backward_plan = bplan; backward_plan = bplan;
fourierArray.swap(newFourierArray); fourierArray.swap(newFourierArray);
fourierKernel.swap(newFourierKernel); fourierKernel.swap(newFourierKernel);
} }
#ifndef DOXYGEN // doxygen documents these functions as free functions #ifndef DOXYGEN // doxygen documents these functions as free functions
template <unsigned int N, class Real> template <unsigned int N, class Real>
template <class C1, class C2, class C3> template <class C1, class C2, class C3>
void void
FFTWConvolvePlan<N, Real>::execute(MultiArrayView<N, Real, C1> in, FFTWConvolvePlan<N, Real>::executeImpl(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel, MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out) MultiArrayView<N, Real, C3> out,
bool do_correlation)
{ {
vigra_precondition(!useFourierKernel, vigra_precondition(!useFourierKernel,
"FFTWConvolvePlan::execute(): plan was generated for Fourier kernel, got spatial kernel."); "FFTWConvolvePlan::execute(): plan was generated for Fourier kernel, got spatial kernel.");
vigra_precondition(in.shape() == out.shape(), vigra_precondition(in.shape() == out.shape(),
"FFTWConvolvePlan::execute(): input and output must have the same s hape."); "FFTWConvolvePlan::execute(): input and output must have the same s hape.");
Shape paddedShape = fftwBestPaddedShapeR2C(in.shape() + kernel.shape() - Shape(1)), Shape paddedShape = fftwBestPaddedShapeR2C(in.shape() + kernel.shape() - Shape(1)),
diff = paddedShape - in.shape(), diff = paddedShape - in.shape(),
left = div(diff, MultiArrayIndex(2)), left = div(diff, MultiArrayIndex(2)),
skipping to change at line 1627 skipping to change at line 1683
vigra_precondition(paddedShape == realArray.shape(), vigra_precondition(paddedShape == realArray.shape(),
"FFTWConvolvePlan::execute(): shape mismatch between input and plan. "); "FFTWConvolvePlan::execute(): shape mismatch between input and plan. ");
detail::fftEmbedArray(in, realArray); detail::fftEmbedArray(in, realArray);
forward_plan.execute(realArray, fourierArray); forward_plan.execute(realArray, fourierArray);
detail::fftEmbedKernel(kernel, realKernel); detail::fftEmbedKernel(kernel, realKernel);
forward_plan.execute(realKernel, fourierKernel); forward_plan.execute(realKernel, fourierKernel);
fourierArray *= fourierKernel; if(do_correlation)
{
using namespace multi_math;
fourierArray *= conj(fourierKernel);
}
else
{
fourierArray *= fourierKernel;
}
backward_plan.execute(fourierArray, realArray); backward_plan.execute(fourierArray, realArray);
out = realArray.subarray(left, right); out = realArray.subarray(left, right);
} }
template <unsigned int N, class Real> template <unsigned int N, class Real>
template <class C1, class C2, class C3> template <class C1, class C2, class C3>
void void
FFTWConvolvePlan<N, Real>::execute(MultiArrayView<N, Real, C1> in, FFTWConvolvePlan<N, Real>::execute(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, FFTWComplex<Real>, C2 MultiArrayView<N, FFTWComplex<Real>, C2>
> kernel, kernel,
MultiArrayView<N, Real, C3> out) MultiArrayView<N, Real, C3> out)
{ {
vigra_precondition(useFourierKernel, vigra_precondition(useFourierKernel,
"FFTWConvolvePlan::execute(): plan was generated for spatial kernel, got Fourier kernel."); "FFTWConvolvePlan::execute(): plan was generated for spatial kernel, got Fourier kernel.");
vigra_precondition(in.shape() == out.shape(), vigra_precondition(in.shape() == out.shape(),
"FFTWConvolvePlan::execute(): input and output must have the same s hape."); "FFTWConvolvePlan::execute(): input and output must have the same s hape.");
vigra_precondition(kernel.shape() == fourierArray.shape(), vigra_precondition(kernel.shape() == fourierArray.shape(),
"FFTWConvolvePlan::execute(): shape mismatch between kernel and plan ."); "FFTWConvolvePlan::execute(): shape mismatch between kernel and plan .");
skipping to change at line 1922 skipping to change at line 1986
return kernelShape; return kernelShape;
} }
else else
{ {
return fftwBestPaddedShape(in + kernelShape - Shape(1)); return fftwBestPaddedShape(in + kernelShape - Shape(1));
} }
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWCorrelatePlan */
/* */
/********************************************************/
/** Like FFTWConvolvePlan, but performs correlation rather than convolution
.
See \ref vigra::FFTWConvolvePlan for details.
<b> Usage:</b>
<b>\#include</b> \<vigra/multi_fft.hxx\><br>
Namespace: vigra
\code
// convolve a real array with a real kernel
MultiArray<2, double> src(Shape2(w, h)), dest(Shape2(w, h));
MultiArray<2, double> spatial_kernel(Shape2(9, 9));
Gaussian<double> gauss(1.0);
for(int y=0; y<9; ++y)
for(int x=0; x<9; ++x)
spatial_kernel(x, y) = gauss(x-4.0)*gauss(y-4.0);
// create an optimized plan by measuring the speed of several algorithm va
riants
FFTWCorrelatePlan<2, double> plan(src, spatial_kernel, dest, FFTW_MEASURE)
;
plan.execute(src, spatial_kernel, dest);
\endcode
*/
template <unsigned int N, class Real>
class FFTWCorrelatePlan
: private FFTWConvolvePlan<N, Real>
{
typedef FFTWConvolvePlan<N, Real> BaseType;
public:
typedef typename MultiArrayShape<N>::type Shape;
/** \brief Create an empty plan.
The plan can be initialized later by one of the init() functions.
*/
FFTWCorrelatePlan()
: BaseType()
{}
/** \brief Create a plan to correlate a real array with a real kern
el.
The kernel must be defined in the spatial domain.
See \ref correlateFFT() for detailed information on required shape
s and internal padding.
\arg planner_flags must be a combination of the
<a href="http://www.fftw.org/doc/Planner-Flags.html">planner
flags</a> defined by the FFTW library. The default <tt>FFTW_ESTIMA
TE</tt> will guess
optimal algorithm settings or read them from pre-loaded
<a href="http://www.fftw.org/doc/Wisdom.html">"wisdom"</a>.
*/
template <class C1, class C2, class C3>
FFTWCorrelatePlan(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out,
unsigned int planner_flags = FFTW_ESTIMATE)
: BaseType(in, kernel, out, planner_flags)
{}
/** \brief Create a plan from just the shape information.
See \ref convolveFFT() for detailed information on required shapes
and internal padding.
\arg fourierDomainKernel determines if the kernel is defined in th
e spatial or
Fourier domain.
\arg planner_flags must be a combination of the
<a href="http://www.fftw.org/doc/Planner-Flags.html">planner
flags</a> defined by the FFTW library. The default <tt>FFTW_ESTIMA
TE</tt> will guess
optimal algorithm settings or read them from pre-loaded
<a href="http://www.fftw.org/doc/Wisdom.html">"wisdom"</a>.
*/
template <class C1, class C2, class C3>
FFTWCorrelatePlan(Shape inOut, Shape kernel,
bool useFourierKernel = false,
unsigned int planner_flags = FFTW_ESTIMATE)
: BaseType(inOut, kernel, false, planner_flags)
{}
/** \brief Init a plan to convolve a real array with a real kernel.
See the constructor with the same signature for details.
*/
template <class C1, class C2, class C3>
void init(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out,
unsigned int planner_flags = FFTW_ESTIMATE)
{
vigra_precondition(in.shape() == out.shape(),
"FFTWCorrelatePlan::init(): input and output mus
t have the same shape.");
BaseType::init(in.shape(), kernel.shape(), planner_flags);
}
/** \brief Execute a plan to correlate a real array with a real ker
nel.
The array shapes must be the same as in the corresponding init fun
ction
or constructor. However, execute() can be called several times on
the same plan, even with different arrays, as long as they have th
e appropriate
shapes.
*/
template <class C1, class C2, class C3>
void execute(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out)
{
BaseType::executeImpl(in, kernel, out, true);
}
};
/********************************************************/
/* */
/* fourierTransform */ /* fourierTransform */
/* */ /* */
/********************************************************/ /********************************************************/
template <unsigned int N, class Real, class C1, class C2> template <unsigned int N, class Real, class C1, class C2>
inline void inline void
fourierTransform(MultiArrayView<N, FFTWComplex<Real>, C1> in, fourierTransform(MultiArrayView<N, FFTWComplex<Real>, C1> in,
MultiArrayView<N, FFTWComplex<Real>, C2> out) MultiArrayView<N, FFTWComplex<Real>, C2> out)
{ {
FFTWPlan<N, Real>(in, out, FFTW_FORWARD).execute(in, out); FFTWPlan<N, Real>(in, out, FFTW_FORWARD).execute(in, out);
skipping to change at line 1996 skipping to change at line 2178
Thanks to the convolution theorem of Fourier theory, a convolution in t he spatial domain Thanks to the convolution theorem of Fourier theory, a convolution in t he spatial domain
is equivalent to a multiplication in the frequency domain. Thus, for ce rtain kernels is equivalent to a multiplication in the frequency domain. Thus, for ce rtain kernels
(especially large, non-separable ones), it is advantageous to perform t he convolution by first (especially large, non-separable ones), it is advantageous to perform t he convolution by first
transforming both array and kernel to the frequency domain, multiplying the frequency transforming both array and kernel to the frequency domain, multiplying the frequency
representations, and transforming the result back into the spatial doma in. representations, and transforming the result back into the spatial doma in.
Some kernels have a much simpler definition in the frequency domain, so that they are readily Some kernels have a much simpler definition in the frequency domain, so that they are readily
computed there directly, avoiding Fourier transformation of those kerne ls. computed there directly, avoiding Fourier transformation of those kerne ls.
The following functions implement various variants of FFT-based convolu tion: The following functions implement various variants of FFT-based convolu tion:
<DL> <DL>
<DT><b>convolveFFT</b><DD> Convolve a real-valued input array with <DT><b>convolveFFT</b><DD> Convolve a real-valued input array with a ke
a kernel such that the rnel such that the
result is also real-valued. That is, the kernel result is also real-valued. That is, the kernel is
is either provided either provided
as a real-valued array in the spatial domain, o as a real-valued array in the spatial domain, or as
r as a a
complex-valued array in the Fourier domain, usi complex-valued array in the Fourier domain, using t
ng the half-space format he half-space format
of the R2C Fourier transform (see below). of the R2C Fourier transform (see below).
<DT><b>convolveFFTMany</b><DD> Like <tt>convolveFFT</tt>, but you m <DT><b>convolveFFTMany</b><DD> Like <tt>convolveFFT</tt>, but you may p
ay provide many kernels at once rovide many kernels at once
(using an iterator pair specifying the kernel s (using an iterator pair specifying the kernel seque
equence). nce).
This has the advantage that the forward transfo This has the advantage that the forward transform o
rm of the input array needs f the input array needs
to be executed only once. to be executed only once.
<DT><b>convolveFFTComplex</b><DD> Convolve a complex-valued input a <DT><b>convolveFFTComplex</b><DD> Convolve a complex-valued input array
rray with a complex-valued kernel, with a complex-valued kernel,
resulting in a complex-valued output array. An resulting in a complex-valued output array. An addi
additional flag is used to tional flag is used to
specify whether the kernel is defined in the sp specify whether the kernel is defined in the spatia
atial or frequency domain. l or frequency domain.
<DT><b>convolveFFTComplexMany</b><DD> Like <tt>convolveFFTComplex</ <DT><b>convolveFFTComplexMany</b><DD> Like <tt>convolveFFTComplex</tt>,
tt>, but you may provide many kernels at once but you may provide many
(using an iterator pair specifying the kernel s kernels at once (using an iterator pair specifying
equence). the kernel sequence).
This has the advantage that the forward transfo This has the advantage that the forward transform o
rm of the input array needs f the input array needs
to be executed only once. to be executed only once.
</DL> </DL>
The output arrays must have the same shape as the input arrays. In the "Many" variants of the The output arrays must have the same shape as the input arrays. In the "Many" variants of the
convolution functions, the kernels must all have the same shape. convolution functions, the kernels must all have the same shape.
The origin of the kernel is always assumed to be in the center of the k ernel array (precisely, The origin of the kernel is always assumed to be in the center of the k ernel array (precisely,
at the point <tt>floor(kernel.shape() / 2.0)</tt>, except when the half -space format is used, see below). at the point <tt>floor(kernel.shape() / 2.0)</tt>, except when the half -space format is used, see below).
The function \ref moveDCToUpperLeft() will be called internally to alig n the kernel with the transformed The function \ref moveDCToUpperLeft() will be called internally to alig n the kernel with the transformed
input as appropriate. input as appropriate.
If a real input is combined with a real kernel, the kernel is automatic ally assumed to be defined If a real input is combined with a real kernel, the kernel is automatic ally assumed to be defined
skipping to change at line 2058 skipping to change at line 2240
of the kernel must be at the point of the kernel must be at the point
<tt>(0, floor(fourier_shape[0] / 2.0), ..., floor(fourier_shape[N-1] / 2.0))</tt> <tt>(0, floor(fourier_shape[0] / 2.0), ..., floor(fourier_shape[N-1] / 2.0))</tt>
(i.e. as in a regular kernel except for the first dimension). (i.e. as in a regular kernel except for the first dimension).
The <tt>Real</tt> type in the declarations can be <tt>double</tt>, <tt> float</tt>, and The <tt>Real</tt> type in the declarations can be <tt>double</tt>, <tt> float</tt>, and
<tt>long double</tt>. Your program must always link against <tt>libfftw 3</tt>. If you use <tt>long double</tt>. Your program must always link against <tt>libfftw 3</tt>. If you use
<tt>float</tt> or <tt>long double</tt> arrays, you must <i>additionally </i> link against <tt>float</tt> or <tt>long double</tt> arrays, you must <i>additionally </i> link against
<tt>libfftw3f</tt> and <tt>libfftw3l</tt> respectively. <tt>libfftw3f</tt> and <tt>libfftw3l</tt> respectively.
The Fourier transform functions internally create <a href="http://www.f ftw.org/doc/Using-Plans.html">FFTW plans</a> The Fourier transform functions internally create <a href="http://www.f ftw.org/doc/Using-Plans.html">FFTW plans</a>
which control the algorithm details. The plans are creates with the fla g <tt>FFTW_ESTIMATE</tt>, i.e. which control the algorithm details. The plans are created with the fla g <tt>FFTW_ESTIMATE</tt>, i.e.
optimal settings are guessed or read from saved "wisdom" files. If you need more control over planning, optimal settings are guessed or read from saved "wisdom" files. If you need more control over planning,
you can use the class \ref FFTWConvolvePlan. you can use the class \ref FFTWConvolvePlan.
See also \ref applyFourierFilter() for corresponding functionality on t he basis of the See also \ref applyFourierFilter() for corresponding functionality on t he basis of the
old image iterator interface. old image iterator interface.
<b> Declarations:</b> <b> Declarations:</b>
Real-valued convolution with kernel in the spatial domain: Real-valued convolution with kernel in the spatial domain:
\code \code
skipping to change at line 2234 skipping to change at line 2416
convolveFFTComplexMany(MultiArrayView<N, FFTWComplex<Real>, C1> in, convolveFFTComplexMany(MultiArrayView<N, FFTWComplex<Real>, C1> in,
KernelIterator kernels, KernelIterator kernelsEnd, KernelIterator kernels, KernelIterator kernelsEnd,
OutIterator outs, OutIterator outs,
bool fourierDomainKernel) bool fourierDomainKernel)
{ {
FFTWConvolvePlan<N, Real> plan; FFTWConvolvePlan<N, Real> plan;
plan.initMany(in, kernels, kernelsEnd, outs, fourierDomainKernel); plan.initMany(in, kernels, kernelsEnd, outs, fourierDomainKernel);
plan.executeMany(in, kernels, kernelsEnd, outs); plan.executeMany(in, kernels, kernelsEnd, outs);
} }
/********************************************************/
/* */
/* correlateFFT */
/* */
/********************************************************/
/** \brief Correlate an array with a kernel by means of the Fourier transfo
rm.
This function correlates a real-valued input array with a real-valued kern
el
such that the result is also real-valued. Thanks to the correlation theore
m of
Fourier theory, a correlation in the spatial domain is equivalent to a mul
tiplication
with the complex conjugate in the frequency domain. Thus, for
certain kernels (especially large, non-separable ones), it is advantageous
to perform the
correlation by first transforming both array and kernel to the frequency d
omain, multiplying
the frequency representations, and transforming the result back into the s
patial domain.
The output arrays must have the same shape as the input arrays.
See also \ref convolveFFT() for corresponding functionality.
<b> Declarations:</b>
\code
namespace vigra {
template <unsigned int N, class Real, class C1, class C2, class C3>
void
correlateFFT(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/multi_fft.hxx\><br>
Namespace: vigra
\code
// correlate real array with a template to find best matches
// (implicitly uses padding by at least 4 pixels)
MultiArray<2, double> src(Shape2(w, h)), dest(Shape2(w, h));
MultiArray<2, double> template(Shape2(9, 9));
template = ...;
correlateFFT(src, template, dest);
\endcode
*/
doxygen_overloaded_function(template <...> void correlateFFT)
template <unsigned int N, class Real, class C1, class C2, class C3>
void
correlateFFT(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, Real, C2> kernel,
MultiArrayView<N, Real, C3> out)
{
FFTWCorrelatePlan<N, Real>(in, kernel, out).execute(in, kernel, out);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_MULTI_FFT_HXX #endif // VIGRA_MULTI_FFT_HXX
 End of changes. 25 change blocks. 
90 lines changed or deleted 350 lines changed or added


 multi_impex.hxx   multi_impex.hxx 
skipping to change at line 51 skipping to change at line 51
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include "config.hxx" #include "config.hxx"
#include "basicimageview.hxx" #include "basicimageview.hxx"
#include "impex.hxx" #include "impex.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "multi_pointoperators.hxx" #include "multi_pointoperators.hxx"
#include "sifImport.hxx"
#ifdef _MSC_VER #ifdef _MSC_VER
# include <direct.h> # include <direct.h>
#else #else
# include <unistd.h> # include <unistd.h>
#endif #endif
namespace vigra { namespace vigra {
/** \addtogroup VolumeImpex Import/export of volume data. /** \addtogroup VolumeImpex Import/export of volume data.
*/ */
//@{ //@{
/** \brief Argument object for the function importVolume(). /** \brief Argument object for the function importVolume().
See \ref importVolume() for usage example. This object can be used See \ref importVolume() for usage example. This object can be used
to define the properties of a volume data set to be read from disk. to define the properties of a volume data set to be read from disk.
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b>\#include</b> \<vigra/multi_impex.hxx\><br> <b>\#include</b> \<vigra/multi_impex.hxx\> <br/>
Namespace: vigra Namespace: vigra
**/ **/
class VolumeImportInfo class VolumeImportInfo
{ {
public: public:
typedef ImageImportInfo::PixelType PixelType; typedef ImageImportInfo::PixelType PixelType;
/// type of volume size returned by shape() /// type of volume size returned by shape()
typedef MultiArrayShape<3>::type ShapeType; typedef MultiArrayShape<3>::type ShapeType;
/// provided for backwards-compatibility (deprecated) /// type of volume size returned by shape()
typedef ShapeType size_type; typedef ShapeType size_type;
/// 3D resolution type returned by resolution() /// 3D resolution type returned by resolution()
typedef TinyVector<float, 3> Resolution; typedef TinyVector<float, 3> Resolution;
/** Construct VolumeImportInfo from a single filename.
The \a filename (which may contain a path) can be interpreted i
n three different ways:
<ul>
<li>If the name refers to a file that contains volume data, the
header information
of this file is read. Two file formats are currently suppor
ted: Andor .SIF
and multi-page TIFF.
<li>If the name refers to a textfile, the constructor will atte
mpt to interpret the file
in the ".info" format to obtain the header information. The
volume data
are then expected to be located in an accompanying RAW file
. The ".info" file must
contain the following key-value pairs:
<UL>
<LI> name = [short descriptive name of the volume] (optiona
l)
<LI> filename = [absolute or relative path to raw voxel dat
a file] (required)
<li> description = [arbitrary description of the data set]
(optional)
<li> width = [positive integer] (required)
<li> height = [positive integer] (required)
<li> depth = [positive integer] (required)
<li> datatype = [ UINT8 | INT16 | UINT16 | INT32 | UINT32 |
FLOAT | DOUBLE ] (required)
</UL>
Lines starting with "#" are ignored. To read the data corre
ctly, the
value_type of the target MultiArray must match the datatype
stored in the file.
Only single-band files are currently supported.
<li>If the name refers to a 2D image file, the constructor will
attempt to decompose
the filename into the format <tt>base_name + slice_number +
name_extension</tt>.
If this decomposition succeeds, all images with the same ba
se_name and name_extension
will be considered as the slices of an image stack. Slice n
umbers need not be consecutive
(i.e. gaps are allowed) and will be interpreted according t
o their numerical order
(i.e. "009", "010", "011" are read in the same order as "9"
, "10", "11"). The number of images
found determines the depth of the volume, the remaining hea
der data are read from the given image.
</ul>
*/
VIGRA_EXPORT VolumeImportInfo(const std::string &filename); VIGRA_EXPORT VolumeImportInfo(const std::string &filename);
VIGRA_EXPORT VolumeImportInfo(const std::string &baseName, const std::s tring &extension);
/** Construct VolumeImportInfo for a stack of images.
The constructor will look for filenames of the form <tt>base_na
me + slice_number + name_extension</tt>.
All images conforming to this pattern will be considered as the
slices of an image stack.
Slice numbers need not be consecutive (i.e. gaps are allowed) a
nd will be interpreted according
to their numerical order (i.e. "009", "010", "011" are read in
the same order as "9", "10", "11").
The number of images found determines the depth of the volume,
the remaining header data are read
from the given image. \a name_base may contain a path.
*/
VIGRA_EXPORT VolumeImportInfo(const std::string &base_name, const std::
string &name_extension);
/** Get the shape of the volume.
*/
VIGRA_EXPORT ShapeType shape() const; VIGRA_EXPORT ShapeType shape() const;
/** Get width of the volume. /** Get width of the volume.
**/ **/
VIGRA_EXPORT MultiArrayIndex width() const; VIGRA_EXPORT MultiArrayIndex width() const;
/** Get height of the volume. /** Get height of the volume.
**/ **/
VIGRA_EXPORT MultiArrayIndex height() const; VIGRA_EXPORT MultiArrayIndex height() const;
skipping to change at line 120 skipping to change at line 165
* increments of the strided row resp. slice steps in the * increments of the strided row resp. slice steps in the
* volume. * volume.
* *
* EXAMPLES: (1.f, 1.f, 4.f) means that the slices are four * EXAMPLES: (1.f, 1.f, 4.f) means that the slices are four
* times thicker than the x/y resolution. * times thicker than the x/y resolution.
* (1.f, -1.f, 1.f) means that the volume coordinate system is * (1.f, -1.f, 1.f) means that the volume coordinate system is
* right-handed. * right-handed.
*/ */
VIGRA_EXPORT Resolution resolution() const; VIGRA_EXPORT Resolution resolution() const;
/** Query the pixel type of the image. /** Query the file type.
Possible values are: Possible values are:
<DL> <DL>
<DT>"MULTIPAGE"<DD> Multiple 2D images in a single file (curren
tly only supported by TIFF).
<DT>"SIF"<DD> <a href="http://www.andor.com">Andor Technology'
s</a> .sif format.
<DT>"RAW"<DD> Raw data file, accompanied by a .info file
<DT>"STACK"<DD> A numbered set of 2D image files, one per slice
of the volume.
</DL>
**/
VIGRA_EXPORT const char * getFileType() const;
/** Query the pixel type of the volume data.
Possible values are:
<DL>
<DT>"INT8"<DD> 8-bit signed integer (signed char)
<DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
<DT>"INT16"<DD> 16-bit signed integer (short) <DT>"INT16"<DD> 16-bit signed integer (short)
<DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short) <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
<DT>"INT32"<DD> 32-bit signed integer (long) <DT>"INT32"<DD> 32-bit signed integer (long)
<DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long) <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
<DT>"INT64"<DD> 64-bit signed integer (long long)
<DT>"UINT64"<DD> 64-bit unsigned integer (unsigned long long)
<DT>"FLOAT"<DD> 32-bit floating point (float) <DT>"FLOAT"<DD> 32-bit floating point (float)
<DT>"DOUBLE"<DD> 64-bit floating point (double) <DT>"DOUBLE"<DD> 64-bit floating point (double)
<DT>"UNKNOWN"<DD> any other type
</DL> </DL>
**/ **/
VIGRA_EXPORT const char * getPixelType() const; VIGRA_EXPORT const char * getPixelType() const;
/** Query the pixel type of the image. /** Query the pixel type of the volume data.
Same as getPixelType(), but the result is returned as a Same as getPixelType(), but the result is returned as a
ImageImportInfo::PixelType enum. This is useful to implement ImageImportInfo::PixelType enum. This is useful to implement
a switch() on the pixel type. a switch() on the pixel type.
Possible values are: Possible values are:
<DL> <DL>
<DT>UINT8<DD> 8-bit unsigned integer (unsigned char) <DT>UINT8<DD> 8-bit unsigned integer (unsigned char)
<DT>INT16<DD> 16-bit signed integer (short) <DT>INT16<DD> 16-bit signed integer (short)
<DT>UINT16<DD> 16-bit unsigned integer (unsigned short) <DT>UINT16<DD> 16-bit unsigned integer (unsigned short)
skipping to change at line 174 skipping to change at line 235
void importImpl(MultiArrayView <3, T, Stride> &volume) const; void importImpl(MultiArrayView <3, T, Stride> &volume) const;
protected: protected:
void getVolumeInfoFromFirstSlice(const std::string &filename); void getVolumeInfoFromFirstSlice(const std::string &filename);
size_type shape_; size_type shape_;
Resolution resolution_; Resolution resolution_;
//PixelType pixelType_; //PixelType pixelType_;
int numBands_; int numBands_;
std::string path_, name_, description_, pixelType_; std::string path_, name_, description_, fileType_, pixelType_;
std::string rawFilename_; std::string rawFilename_;
std::string baseName_, extension_; std::string baseName_, extension_;
std::vector<std::string> numbers_; std::vector<std::string> numbers_;
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* VolumeExportInfo */ /* VolumeExportInfo */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Argument object for the function exportVolume(). /** \brief Argument object for the function exportVolume().
See \ref exportVolume() for usage example. This object must be used See \ref exportVolume() for usage example. This object must be used
to define the properties of a volume to be written to disk. to define the properties of a volume to be written to disk.
<b>\#include</b> \<vigra/imageinfo.hxx\><br> <b>\#include</b> \<vigra/imageinfo.hxx\> <br/>
Namespace: vigra Namespace: vigra
**/ **/
class VolumeExportInfo class VolumeExportInfo
{ {
public: public:
/** Construct VolumeExportInfo object. /** Construct VolumeExportInfo object to output volume data as a mu
lti-page tiff.
The filename must refer to a TIFF file (extension '.tif' or '.t
iff'). This function
is only available when libtiff is installed.
**/
VIGRA_EXPORT VolumeExportInfo( const char * filename );
/** Construct VolumeExportInfo object to output volume data as an i
mage stack.
The volume will be stored in a by-slice manner, where the numbe r of slices The volume will be stored in a by-slice manner, where the numbe r of slices
equals the depth of the volume. The file names will be enumerat ed like equals the depth of the volume. The file names will be enumerat ed like
<tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext </tt> etc. <tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext </tt> etc.
(the actual number of zeros depends on the depth). If the targe t image type (the actual number of zeros depends on the depth). If the targe t image type
does not support the source voxel type, all slices will be mapp ed does not support the source voxel type, all slices will be mapp ed
simultaneously to the appropriate target range. simultaneously to the appropriate target range.
The file type will be guessed from the extension unless overrid den The file type will be guessed from the extension unless overrid den
by \ref setFileType(). Recognized extensions: '.bmp', '.gif', by \ref setFileType().
Recognized extensions: '.bmp', '.gif',
'.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras', '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras',
'.tif', '.tiff', '.xv', '.hdr'. '.tif', '.tiff', '.xv', '.hdr'.
JPEG support requires libjpeg, PNG support requires libpng, and JPEG support requires libjpeg, PNG support requires libpng, and
TIFF support requires libtiff. TIFF support requires libtiff.
If \a name_ext is an empty string, the data is written as a mul
ti-page tiff.
**/ **/
VIGRA_EXPORT VolumeExportInfo( const char * name_base, const char * nam e_ext ); VIGRA_EXPORT VolumeExportInfo( const char * name_base, const char * nam e_ext );
VIGRA_EXPORT ~VolumeExportInfo(); VIGRA_EXPORT ~VolumeExportInfo();
/** Set volume file name base. /** Set volume file name base.
**/ **/
VIGRA_EXPORT VolumeExportInfo & setFileNameBase(const char * name_base) ; VIGRA_EXPORT VolumeExportInfo & setFileNameBase(const char * name_base) ;
/** Set volume file name extension. /** Set volume file name extension.
The file type will be guessed from the extension unless overrid den The file type will be guessed from the extension unless overrid den
by \ref setFileType(). Recognized extensions: '.bmp', '.gif', by \ref setFileType(). Recognized extensions: '.bmp', '.gif',
'.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras', '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras',
'.tif', '.tiff', '.xv', '.hdr'. '.tif', '.tiff', '.xv', '.hdr'.
JPEG support requires libjpeg, PNG support requires libpng, and JPEG support requires libjpeg, PNG support requires libpng, and
TIFF support requires libtiff. TIFF support requires libtiff.
**/ **/
VIGRA_EXPORT VolumeExportInfo & setFileNameExt(const char * name_ext); VIGRA_EXPORT VolumeExportInfo & setFileNameExt(const char * name_ext);
VIGRA_EXPORT const char * getFileNameBase() const; VIGRA_EXPORT const char * getFileNameBase() const;
VIGRA_EXPORT const char * getFileNameExt() const; VIGRA_EXPORT const char * getFileNameExt() const;
/** Store volume as given file type. /** Store volume as given file type.
This will override any type guessed This will override any type guessed
skipping to change at line 252 skipping to change at line 327
compressed 24-bit color (only available if libjpeg is installed ). compressed 24-bit color (only available if libjpeg is installed ).
<DT>"PNG"<DD> Portable Network Graphic <DT>"PNG"<DD> Portable Network Graphic
(only available if libpng is installed). (only available if libpng is installed).
<DT>"PBM"<DD> Portable bitmap format (black and white). <DT>"PBM"<DD> Portable bitmap format (black and white).
<DT>"PGM"<DD> Portable graymap format (gray scale). <DT>"PGM"<DD> Portable graymap format (gray scale).
<DT>"PNM"<DD> Portable anymap. <DT>"PNM"<DD> Portable anymap.
<DT>"PPM"<DD> Portable pixmap format (color). <DT>"PPM"<DD> Portable pixmap format (color).
<DT>"SUN"<DD> SUN Rasterfile. <DT>"SUN"<DD> SUN Rasterfile.
<DT>"TIFF"<DD> Tagged Image File Format. <DT>"TIFF"<DD> Tagged Image File Format.
(only available if libtiff is installed.) (only available if libtiff is installed.)
<DT>"MULTIPAGE"<DD> Multi-page TIFF.
(only available if libtiff is installed.)
<DT>"VIFF"<DD> Khoros Visualization image file. <DT>"VIFF"<DD> Khoros Visualization image file.
</DL> </DL>
With the exception of TIFF, VIFF, PNG, and PNM all file types s tore With the exception of TIFF, VIFF, PNG, and PNM all file types s tore
1 byte (gray scale and mapped RGB) or 3 bytes (RGB) per only 1 byte (gray scale and mapped RGB) or 3 bytes (RGB) per
pixel. pixel.
PNG can store UInt8 and UInt16 values, and supports 1 and 3 cha nnel PNG can store UInt8 and UInt16 values, and supports 1 and 3 cha nnel
images. One additional alpha channel is also supported. images. One additional alpha channel is also supported.
PNM can store 1 and 3 channel images with UInt8, UInt16 and UIn t32 PNM can store 1 and 3 channel images with UInt8, UInt16 and UIn t32
values in each channel. values in each channel.
TIFF and VIFF are additionally able to store short and long TIFF and VIFF are additionally able to store short and long
integers (2 or 4 bytes) and real values (32 bit float and integers (2 or 4 bytes) and real values (32 bit float and
skipping to change at line 414 skipping to change at line 491
{ {
readVolumeImpl(d.begin(), shape, s, buffer, MetaInt<N-1>()); readVolumeImpl(d.begin(), shape, s, buffer, MetaInt<N-1>());
} }
} }
} // namespace detail } // namespace detail
template <class T, class Stride> template <class T, class Stride>
void VolumeImportInfo::importImpl(MultiArrayView <3, T, Stride> &volume) co nst void VolumeImportInfo::importImpl(MultiArrayView <3, T, Stride> &volume) co nst
{ {
vigra_precondition(this->shape() == volume.shape(), "importVolume(): Vo lume must be shaped according to VolumeImportInfo."); vigra_precondition(this->shape() == volume.shape(), "importVolume(): Ou tput array must be shaped according to VolumeImportInfo.");
if(rawFilename_.size()) if(fileType_ == "RAW")
{ {
std::string dirName, baseName; std::string dirName, baseName;
char oldCWD[2048]; char oldCWD[2048];
#ifdef _MSC_VER #ifdef _MSC_VER
if(_getcwd(oldCWD, 2048) == 0) if(_getcwd(oldCWD, 2048) == 0)
{ {
perror("getcwd"); perror("getcwd");
vigra_fail("VolumeImportInfo: Unable to query current directory (getcwd)."); vigra_fail("VolumeImportInfo: Unable to query current directory (getcwd).");
} }
skipping to change at line 465 skipping to change at line 542
if(_chdir(oldCWD)) if(_chdir(oldCWD))
perror("chdir"); perror("chdir");
#else #else
if(chdir(oldCWD)) if(chdir(oldCWD))
perror("chdir"); perror("chdir");
#endif #endif
vigra_postcondition( vigra_postcondition(
volume.shape() == shape(), "imported volume has wrong size"); volume.shape() == shape(), "imported volume has wrong size");
} }
else else if(fileType_ == "STACK")
{ {
for (unsigned int i = 0; i < numbers_.size(); ++i) for (unsigned int i = 0; i < numbers_.size(); ++i)
{ {
// build the filename // build the filename
std::string name = baseName_ + numbers_[i] + extension_; std::string filename = baseName_ + numbers_[i] + extension_;
// import the image // import the image
ImageImportInfo info (name.c_str ()); ImageImportInfo info (filename.c_str ());
// generate a basic image view to the current layer // generate a basic image view to the current layer
MultiArrayView <2, T, Stride> view (volume.bindOuter (i)); MultiArrayView <2, T, Stride> view (volume.bindOuter (i));
vigra_precondition(view.shape() == info.shape(), vigra_precondition(view.shape() == info.shape(),
"importVolume(): the images have inconsistent sizes."); "importVolume(): the images have inconsistent sizes.");
importImage (info, destImage(view)); importImage (info, destImage(view));
} }
} }
else if(fileType_ == "MULTIPAGE")
{
ImageImportInfo info(baseName_.c_str());
for(int k=0; k<info.numImages(); ++k)
{
info.setImageIndex(k);
importImage(info, volume.bindOuter(k));
}
}
// else if(fileType_ == "HDF5")
// {
// HDF5File file(baseName_, HDF5File::OpenReadOnly);
// file.read(extension_, volume);
// }
else if(fileType_ == "SIF")
{
SIFImportInfo infoSIF(baseName_.c_str());
readSIF(infoSIF, volume);
}
} }
VIGRA_EXPORT void findImageSequence(const std::string &name_base, VIGRA_EXPORT void findImageSequence(const std::string &name_base,
const std::string &name_ext, const std::string &name_ext,
std::vector<std::string> & numbers); std::vector<std::string> & numbers);
/********************************************************/ /********************************************************/
/* */ /* */
/* importVolume */ /* importVolume */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Function for importing a 3D volume. /** \brief Function for importing a 3D volume.
The data are expected to be stored in a by-slice manner, <b>Declarations: </b>
where the slices are enumerated from <tt>name_base+"[0-9]+"+name_ext</t
t>.
<tt>name_base</tt> may contain a path. All slice files with the same na
me base and
extension are considered part of the same volume. Slice numbers must be
non-negative,
but can otherwise start anywhere and need not be successive. Slices wil
l be read
in ascending numerical (not lexicographic) order. All slices must have
the
same size. The <tt>volume</tt> will be reshaped to match the count and
size of the slices found.
<b>\#include</b> \code
\<vigra/multi_impex.hxx\> namespace vigra {
// variant 1: read data specified by the given VolumeImportInfo obj
ect
template <class T, class Stride>
void
importVolume(VolumeImportInfo const & info,
MultiArrayView <3, T, Stride> &volume);
// variant 2: read data using a single filename, resize volume auto
matically
template <class T, class Allocator>
void
importVolume(MultiArray <3, T, Allocator> & volume,
const std::string &filename);
// variant 3: read data from an image stack, resize volume automati
cally
template <class T, class Allocator>
void
importVolume(MultiArray <3, T, Allocator> & volume,
const std::string &name_base,
const std::string &name_ext);
}
\endcode
Namespace: vigra Data can be read either from a single file containing 3D data (supporte
*/ d formats:
template <class T, class Allocator> Andor .SIF or multi-page TIFF), a ".info" text file which describes the
void importVolume (MultiArray <3, T, Allocator> & volume, contents of
const std::string &name_base, an accompanying raw data file, or a stack of 2D images (numbered accord
const std::string &name_ext) ing to the
{ scheme <tt>name_base+"[0-9]+"+name_extension</tt>) each representing a
VolumeImportInfo info(name_base, name_ext); slice of
the volume. The decision which of these possibilities applies is taken
in the
\ref vigra::VolumeImportInfo::VolumeImportInfo(const std::string &) "Vo
lumeImportInfo constructor",
see there for full details.
Variant 1 is the basic version of this function. Here, the info object
and a destination
array of approriate size must already be constructed. The other variant
s are just abbreviations
provided for your convenience:
\code
// variant 2 is equivalent to
VolumeImportInfo info(filename);
volume.reshape(info.shape()); volume.reshape(info.shape());
importVolume(info, volume); // call variant 1
info.importImpl(volume); // variant 3 is equivalent to
} VolumeImportInfo info(name_base, name_ext);
volume.reshape(info.shape());
/** \brief Function for importing a 3D volume. importVolume(info, volume); // call variant 1
\endcode
The data can be given in two ways: <b> Usage:</b>
<UL> <b>\#include</b> \<vigra/multi_impex.hxx\> <br/>
<LI> If the volume is stored in a by-slice manner (e.g. one image per s Namespace: vigra
lice),
the <tt>filename</tt> can refer to an arbitrary image from the set
. <tt>importVolume()</tt>
then assumes that the slices are enumerated like <tt>name_base+"[0
-9]+"+name_ext</tt>,
where <tt>name_base</tt>, the index, and <tt>name_ext</tt> are det
ermined automatically.
All slice files with the same name base and extension are consider
ed part of the same
volume. Slice numbers must be non-negative, but can otherwise star
t anywhere and need
not be successive. Slices will be read in ascending numerical (not
lexicographic) order.
All slices must have the same size.
<li> Otherwise, <tt>importVolume()</tt> will try to read <tt>filename</
tt> as an
info text file with the following key-value pairs:
<UL>
<LI> name = [short descriptive name of the volume] (optional)
<LI> filename = [absolute or relative path to raw voxel data file]
(required)
<li> gradfile = [absolute or relative path to gradient data file]
(currently ignored)
<li> description = [arbitrary description of the data set] (optio
nal)
<li> width = [positive integer] (required)
<li> height = [positive integer] (required)
<li> depth = [positive integer] (required)
<li> datatype = [UNSIGNED_CHAR | UNSIGNED_BYTE] (default: UNSIGNED
_CHAR)
</UL>
The voxel type is currently assumed to be binary compatible to the
<tt>value_type T</TT>
of the <tt>MuliArray</tt>. Lines starting with "#" are ignored.
</UL>
In either case, the <tt>volume</tt> will be reshaped to match the count \code
and // read data from a multi-page TIFF file, using variant 1
size of the slices found. VolumeImportInfo info("multipage.tif");
MultiArray<3, float> volume(info.shape());
importVolume(info, volume);
// read data from a stack of 2D png-images, using variant 1
VolumeImportInfo info("my_data", ".png"); // looks for files 'my_data0
.png', 'my_data1.png' etc.
MultiArray<3, float> volume(info.shape());
importVolume(info, volume);
\endcode
Notice that slice numbers in a stack need not be consecutive (i.e. gaps
are allowed) and
will be interpreted according to their numerical order (i.e. "009", "01
0", "011"
are read in the same order as "9", "10", "11"). The number of images
found determines the depth of the volume.
*/
doxygen_overloaded_function(template <...> void importVolume)
<b>\#include</b> template <class T, class Stride>
\<vigra/multi_impex.hxx\> void
importVolume(VolumeImportInfo const & info,
MultiArrayView <3, T, Stride> &volume)
{
info.importImpl(volume);
}
Namespace: vigra
*/
template <class T, class Allocator> template <class T, class Allocator>
void importVolume(MultiArray <3, T, Allocator> &volume, void
const std::string &filename) importVolume(MultiArray <3, T, Allocator> &volume,
const std::string &filename)
{ {
VolumeImportInfo info(filename); VolumeImportInfo info(filename);
volume.reshape(info.shape()); volume.reshape(info.shape());
info.importImpl(volume); info.importImpl(volume);
} }
/** \brief Function for importing a 3D volume. template <class T, class Allocator>
void importVolume (MultiArray <3, T, Allocator> & volume,
Read the volume data set <tt>info</tt> refers to. Explicit construction const std::string &name_base,
of the info object allows to allocate a <tt>volume</tt> object type who const std::string &name_ext)
se
<tt>value_type</tt> matches the voxel type of the stored data.
The <tt>volume</tt> will be reshaped to match the count and
size of the slices found.
<b>\#include</b>
\<vigra/multi_impex.hxx\>
Namespace: vigra
*/
template <class T, class Stride>
void importVolume(VolumeImportInfo const & info, MultiArrayView <3, T, Stri
de> &volume)
{ {
VolumeImportInfo info(name_base, name_ext);
volume.reshape(info.shape());
info.importImpl(volume); info.importImpl(volume);
} }
namespace detail { namespace detail {
template <class T> template <class T>
void setRangeMapping(std::string const & pixeltype, void setRangeMapping(std::string const & pixeltype,
FindMinMax<T> const & minmax, ImageExportInfo & info) FindMinMax<T> const & minmax, ImageExportInfo & info)
{ {
if(pixeltype == "UINT8") if(pixeltype == "UINT8")
skipping to change at line 668 skipping to change at line 775
} // namespace detail } // namespace detail
/********************************************************/ /********************************************************/
/* */ /* */
/* exportVolume */ /* exportVolume */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Function for exporting a 3D volume. /** \brief Function for exporting a 3D volume.
The volume is exported in a by-slice manner, where the number of slices <b> Declarations:</b>
equals
the depth of the volume. The file names will be enumerated like \code
<tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext</tt> et namespace vigra {
c. // variant 1: writa data as specified in the given VolumeExportInfo
(the actual number of zeros depends on the depth). If the target image object
type template <class T, class Tag>
does not support the source voxel type, all slices will be mapped simul void
taneously exportVolume (MultiArrayView <3, T, Tag> const & volume,
to the appropriate target range. const VolumeExportInfo & info);
// variant 2: write data to a multi-page TIFF file
template <class T, class Tag>
void
exportVolume (MultiArrayView <3, T, Tag> const & volume,
const std::string &filename);
// variant 3: write data to an image stack
template <class T, class Tag>
void
exportVolume (MultiArrayView <3, T, Tag> const & volume,
const std::string &name_base,
const std::string &name_ext);
}
\endcode
The volume can either be exported as a multi-page TIFF file (variant 2,
only available if
libtiff is installed), or as a stack of 2D images, one image per slice
(variant 3, files are named
according to the scheme <tt>name_base+"000"+name_ext</tt>, <tt>name_bas
e+"001"+name_ext</tt> etc.).
If the target image format does not support the source <tt>value_type</
tt>, all slices will
be mapped to the appropriate target range in the same way.
Variant 1 is the basic version of the function. It allows full control
over the export via
an already constructed \ref vigra::VolumeExportInfo object. The other t
wo are just abbreviations
that construct the VolumeExportInfo object internally.
<b>\#include</b> <b> Usage:</b>
\<vigra/multi_impex.hxx\>
<b>\#include</b> \<vigra/multi_impex.hxx\> <br/>
Namespace: vigra Namespace: vigra
\code
MultiArray<3, RGBValue<UInt8> > volume(shape);
... // fill in data
// export a stack named "my_data01.jpg", "my_data02.jpg" etc.
VolumeExportInfo info("my_data", ".jpg");
info.setCompression("JPEG QUALITY=95");
exportVolume(volume, info);
\endcode
*/ */
doxygen_overloaded_function(template <...> void exportVolume)
template <class T, class Tag> template <class T, class Tag>
void exportVolume (MultiArrayView <3, T, Tag> const & volume, void
const VolumeExportInfo & volinfo) exportVolume (MultiArrayView <3, T, Tag> const & volume,
const VolumeExportInfo & volinfo)
{ {
std::string name = std::string(volinfo.getFileNameBase()) + std::string if(volinfo.getFileType() == std::string("MULTIPAGE"))
(volinfo.getFileNameExt());
ImageExportInfo info(name.c_str());
info.setCompression(volinfo.getCompression());
info.setPixelType(volinfo.getPixelType());
detail::setRangeMapping(volume, info, typename NumericTraits<T>::isScal
ar());
const unsigned int depth = volume.shape (2);
int numlen = static_cast <int> (std::ceil (std::log10 ((double)depth)))
;
for (unsigned int i = 0; i < depth; ++i)
{ {
char const * mode = "w";
std::string compression = "LZW";
if(volinfo.getCompression() != std::string())
compression = volinfo.getCompression();
// build the filename for(MultiArrayIndex k=0; k<volume.shape(2); ++k)
std::stringstream stream; {
stream << std::setfill ('0') << std::setw (numlen) << i; ImageExportInfo info(volinfo.getFileNameBase(), mode);
std::string name_num; info.setFileType("TIFF");
stream >> name_num; info.setCompression(compression.c_str());
std::string name = std::string(volinfo.getFileNameBase()) + name_nu info.setPixelType(volinfo.getPixelType());
m + std::string(volinfo.getFileNameExt()); detail::setRangeMapping(volume, info, typename NumericTraits<T>
::isScalar());
MultiArrayView <2, T, Tag> view (volume.bindOuter (i)); exportImage(volume.bindOuter(k), info);
mode = "a";
// export the image }
info.setFileName(name.c_str ()); }
exportImage(srcImageRange(view), info); else
{
std::string name = std::string(volinfo.getFileNameBase()) + std::st
ring(volinfo.getFileNameExt());
ImageExportInfo info(name.c_str());
info.setCompression(volinfo.getCompression());
info.setPixelType(volinfo.getPixelType());
detail::setRangeMapping(volume, info, typename NumericTraits<T>::is
Scalar());
const unsigned int depth = volume.shape (2);
int numlen = static_cast <int> (std::ceil (std::log10 ((double)dept
h)));
for (unsigned int i = 0; i < depth; ++i)
{
// build the filename
std::stringstream stream;
stream << std::setfill ('0') << std::setw (numlen) << i;
std::string name_num;
stream >> name_num;
std::string sliceFilename =
std::string(volinfo.getFileNameBase()) +
name_num +
std::string(volinfo.getFileNameExt());
MultiArrayView <2, T, Tag> view (volume.bindOuter (i));
// export the image
info.setFileName(sliceFilename.c_str ());
exportImage(srcImageRange(view), info);
}
} }
} }
// for backward compatibility
template <class T, class Tag> template <class T, class Tag>
inline inline void
void exportVolume (MultiArrayView <3, T, Tag> const & volume, exportVolume (MultiArrayView <3, T, Tag> const & volume,
const std::string &name_base, const std::string &filename)
const std::string &name_ext) {
VolumeExportInfo volinfo(filename.c_str());
exportVolume(volume, volinfo);
}
template <class T, class Tag>
inline void
exportVolume (MultiArrayView <3, T, Tag> const & volume,
const std::string &name_base,
const std::string &name_ext)
{ {
VolumeExportInfo volinfo(name_base.c_str(), name_ext.c_str()); VolumeExportInfo volinfo(name_base.c_str(), name_ext.c_str());
exportVolume(volume, volinfo); exportVolume(volume, volinfo);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_MULTI_IMPEX_HXX #endif // VIGRA_MULTI_IMPEX_HXX
 End of changes. 51 change blocks. 
150 lines changed or deleted 357 lines changed or added


 multi_iterator.hxx   multi_iterator.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */ /* Copyright 2003-2012 by Gunnar Kedenburg and Ullrich Koethe */
/* */ /* */
/* This file is part of the VIGRA computer vision library. */ /* This file is part of the VIGRA computer vision library. */
/* ( Version 1.3.0, Sep 10 2004 ) */ /* ( Version 1.3.0, Sep 10 2004 ) */
/* The VIGRA Website is */ /* The VIGRA Website is */
/* http://hci.iwr.uni-heidelberg.de/vigra/ */ /* http://hci.iwr.uni-heidelberg.de/vigra/ */
/* Please direct questions, bug reports, and contributions to */ /* Please direct questions, bug reports, and contributions to */
/* ullrich.koethe@iwr.uni-heidelberg.de or */ /* ullrich.koethe@iwr.uni-heidelberg.de or */
/* vigra@informatik.uni-hamburg.de */ /* vigra@informatik.uni-hamburg.de */
/* */ /* */
/* Permission is hereby granted, free of charge, to any person */ /* Permission is hereby granted, free of charge, to any person */
skipping to change at line 41 skipping to change at line 41
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MULTI_ITERATOR_HXX #ifndef VIGRA_MULTI_ITERATOR_HXX
#define VIGRA_MULTI_ITERATOR_HXX #define VIGRA_MULTI_ITERATOR_HXX
#include <sys/types.h> #include <sys/types.h>
#include "tinyvector.hxx" #include "multi_fwd.hxx"
#include "iteratortags.hxx" #include "iteratortags.hxx"
#include "multi_iterator_coupled.hxx"
namespace vigra { namespace vigra {
template <unsigned int N, class T, /** \addtogroup MultiIteratorGroup
class REFERENCE = T &, class POINTER = T *> class MultiIterator; */
template <unsigned int N, class T, //@{
class REFERENCE = T &, class POINTER = T *> class StridedMultiIte
rator; /** \brief Iterate over a virtual array where each element contains its
coordinate.
MultiCoordinateIterator behaves like a read-only random access iter
ator.
It moves accross the given region of interest in scan-order (with t
he first
index changing most rapidly), and dereferencing the iterator return
s the
coordinate (i.e. multi-dimensional index) of the current array elem
ent.
The functionality is thus similar to a meshgrid in Matlab or numpy.
Internally, it is just a wrapper of a \ref CoupledScanOrderIterator
that
has been created without any array and whose reference type is not
a
\ref CoupledHandle, but the coordinate itself.
The iterator supports all functions listed in the STL documentation
for
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Ran
dom Access Iterators</a>.
<b>Usage:</b>
<b>\#include</b> \<vigra/multi_iterator.hxx\><br/>
Namespace: vigra
\code
MultiCoordinateIterator<3> i(Shape3(3,2,1)), end = i.getEndIterator
();
for(; i != end; ++i)
std::cout << *i << "\n";
// Output:
// (0, 0, 0)
// (1, 0, 0)
// (2, 0, 0)
// (0, 1, 0)
// (1, 1, 0)
// (2, 1, 0)
\endcode
*/
template<unsigned int N>
class MultiCoordinateIterator
: public CoupledScanOrderIterator<N>
{
public:
typedef CoupledScanOrderIterator<N> base_type;
typedef typename base_type::shape_type shape_type;
typedef typename base_type::difference_type difference_type;
typedef MultiCoordinateIterator iterator;
typedef std::random_access_iterator_tag iterator_category;
typedef typename base_type::value_type handle_type;
typedef typename handle_type::value_type value_type;
typedef typename handle_type::reference reference;
typedef typename handle_type::const_reference const_reference;
typedef typename handle_type::pointer pointer;
typedef typename handle_type::const_pointer const_pointer;
MultiCoordinateIterator()
: base_type(handle_type())
{}
explicit MultiCoordinateIterator(shape_type const & shape)
: base_type(handle_type(shape))
{}
explicit MultiCoordinateIterator(shape_type const & start, shape_type c
onst & end)
: base_type(handle_type(end))
{
this->restrictToSubarray(start, end);
}
template<class DirectedTag>
explicit MultiCoordinateIterator(GridGraph<N, DirectedTag> const & g)
: base_type(handle_type(g.shape()))
{}
template<class DirectedTag>
explicit MultiCoordinateIterator(GridGraph<N, DirectedTag> const & g, c
onst typename GridGraph<N, DirectedTag>::Node & node)
: base_type(handle_type(g.shape()))
{
if( isInside(g,node))
(*this)+=node;
else
*this=this->getEndIterator();
}
// dereferencing the iterator yields the coordinate object
// (used as vertex_descriptor)
reference operator*()
{
return this->template get<0>();
}
const_reference operator*() const
{
return this->template get<0>();
}
operator value_type() const
{
return *(*this);
}
pointer operator->()
{
return &this->template get<0>();
}
const_pointer operator->() const
{
return &this->template get<0>();
}
value_type operator[](MultiArrayIndex i) const
{
return *(MultiCoordinateIterator(*this) += i);
}
MultiCoordinateIterator & operator++()
{
base_type::operator++();
return *this;
}
MultiCoordinateIterator operator++(int)
{
MultiCoordinateIterator res(*this);
++*this;
return res;
}
MultiCoordinateIterator & operator+=(MultiArrayIndex i)
{
base_type::operator+=(i);
return *this;
}
MultiCoordinateIterator & operator+=(const shape_type &coordOffset)
{
base_type::operator+=(coordOffset);
return *this;
}
MultiCoordinateIterator & operator--()
{
base_type::operator--();
return *this;
}
MultiCoordinateIterator operator--(int)
{
MultiCoordinateIterator res(*this);
--*this;
return res;
}
MultiCoordinateIterator & operator-=(MultiArrayIndex i)
{
return operator+=(-i);
}
MultiCoordinateIterator & operator-=(const shape_type &coordOffset)
{
return operator+=(-coordOffset);
}
MultiCoordinateIterator getEndIterator() const
{
return MultiCoordinateIterator(base_type::getEndIterator());
}
MultiCoordinateIterator operator+(MultiArrayIndex d) const
{
return MultiCoordinateIterator(*this) += d;
}
MultiCoordinateIterator operator-(MultiArrayIndex d) const
{
return MultiCoordinateIterator(*this) -= d;
}
MultiCoordinateIterator operator+(const shape_type &coordOffset) const
{
return MultiCoordinateIterator(*this) += coordOffset;
}
MultiCoordinateIterator operator-(const shape_type &coordOffset) const
{
return MultiCoordinateIterator(*this) -= coordOffset;
}
MultiArrayIndex operator-(const MultiCoordinateIterator & other) const
{
return base_type::operator-(other);
}
protected:
MultiCoordinateIterator(base_type const & base)
: base_type(base)
{}
};
/** \brief Sequential iterator for MultiArrayView.
This iterator provides STL-compatible random access iterator functi
onality for arbitrary
\ref MultiArrayView instances, regardless of their shapes and strid
es. The
class uses an implementation that minimizes speed penalties that co
uld result from
non-trivial strides. The <i>scan-order</i> is defined such that dim
ensions are iterated
from front to back (first to last).
You normally construct instances of this class by calling \ref Mult
iArrayView::begin()
and \ref MultiArrayView::end().
The iterator supports all functions listed in the STL documentation
for
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Ran
dom Access Iterators</a>.
<b>\#include</b> \<vigra/multi_iterator.hxx\><br/>
Namespace: vigra
*/
template <unsigned int N, class V, class REFERENCE, class POINTER>
class StridedScanOrderIterator
: public CoupledIteratorType<N, V>::type
{
public:
typedef typename CoupledIteratorType<N, V>::type base_type;
typedef typename base_type::value_type handle_type;
typedef typename base_type::shape_type shape_type;
typedef typename base_type::difference_type difference_type;
typedef StridedScanOrderIterator iterator;
typedef std::random_access_iterator_tag iterator_category;
typedef typename detail::ResolveChunkedMemory<V>::type T;
typedef T value_type;
typedef REFERENCE reference;
typedef T const & const_reference;
typedef POINTER pointer;
typedef T const * const_pointer;
StridedScanOrderIterator()
: base_type()
{}
template <class S>
explicit StridedScanOrderIterator(MultiArrayView<N, T, S> const & view)
: base_type(createCoupledIterator(view))
{}
StridedScanOrderIterator(POINTER p, shape_type const & shape, shape_typ
e const & strides)
: base_type(createCoupledIterator(MultiArrayView<N, T, StridedArray
Tag>(shape, strides, const_cast<T *>(p))))
{}
StridedScanOrderIterator(handle_type const & handle)
: base_type(handle)
{}
reference operator*()
{
return this->template get<1>();
}
const_reference operator*() const
{
return this->template get<1>();
}
pointer operator->()
{
return &this->template get<1>();
}
const_pointer operator->() const
{
return &this->template get<1>();
}
reference operator[](MultiArrayIndex i)
{
return *(StridedScanOrderIterator(*this) += i);
}
const_reference operator[](MultiArrayIndex i) const
{
return *(StridedScanOrderIterator(*this) += i);
}
reference operator[](const shape_type& coordOffset)
{
return *(StridedScanOrderIterator(*this) += coordOffset);
}
const_reference operator[](const shape_type& coordOffset) const
{
return *(StridedScanOrderIterator(*this) += coordOffset);
}
StridedScanOrderIterator & operator++()
{
base_type::operator++();
return *this;
}
StridedScanOrderIterator operator++(int)
{
StridedScanOrderIterator res(*this);
++*this;
return res;
}
StridedScanOrderIterator & operator+=(MultiArrayIndex i)
{
base_type::operator+=(i);
return *this;
}
StridedScanOrderIterator & operator+=(const shape_type &coordOffset)
{
base_type::operator+=(coordOffset);
return *this;
}
StridedScanOrderIterator & operator--()
{
base_type::operator--();
return *this;
}
StridedScanOrderIterator operator--(int)
{
StridedScanOrderIterator res(*this);
--*this;
return res;
}
StridedScanOrderIterator & operator-=(MultiArrayIndex i)
{
return operator+=(-i);
}
StridedScanOrderIterator & operator-=(const shape_type &coordOffset)
{
return operator+=(-coordOffset);
}
StridedScanOrderIterator getEndIterator() const
{
return StridedScanOrderIterator(base_type::getEndIterator());
}
StridedScanOrderIterator operator+(MultiArrayIndex d) const
{
return StridedScanOrderIterator(*this) += d;
}
StridedScanOrderIterator operator-(MultiArrayIndex d) const
{
return StridedScanOrderIterator(*this) -= d;
}
MultiArrayIndex operator-(StridedScanOrderIterator const & other) const
{
return base_type::operator-(other);
}
StridedScanOrderIterator operator+(const shape_type &coordOffset) const
{
return StridedScanOrderIterator(*this) += coordOffset;
}
StridedScanOrderIterator operator-(const shape_type &coordOffset) const
{
return StridedScanOrderIterator(*this) -= coordOffset;
}
MultiArrayIndex index() const
{
return this->scanOrderIndex();
}
StridedScanOrderIterator &
restrictToSubarray(shape_type const & start, shape_type const & stop)
{
base_type::restrictToSubarray(start, stop);
return *this;
}
protected:
StridedScanOrderIterator(base_type const & base)
: base_type(base)
{}
};
//@}
/** \page MultiIteratorPage Multi-dimensional Array Iterators /** \page MultiIteratorPage Multi-dimensional Array Iterators
General iterators for arrays of arbitrary dimension. General iterators for arrays of arbitrary dimension.
<p> <p>
<UL style="list-style-image:url(documents/bullet.gif)"> <UL style="list-style-image:url(documents/bullet.gif)">
<LI> \ref vigra::MultiArrayShape <LI> \ref vigra::MultiArrayShape
<BR>&nbsp;&nbsp;&nbsp;<em>Difference type for \ref vigra::MultiArrayVi ew or \ref vigra::MultiIterator</em> <BR>&nbsp;&nbsp;&nbsp;<em>Difference type for \ref vigra::MultiArrayVi ew or \ref vigra::MultiIterator</em>
<LI> \ref vigra::MultiIterator <LI> \ref vigra::MultiIterator
<BR>&nbsp;&nbsp;&nbsp;<em>Iterator for unstrided \ref vigra::MultiArra yView</em> <BR>&nbsp;&nbsp;&nbsp;<em>Iterator for unstrided \ref vigra::MultiArra yView</em>
<LI> \ref vigra::StridedMultiIterator <LI> \ref vigra::StridedMultiIterator
<BR>&nbsp;&nbsp;&nbsp;<em>Iterator for strided \ref vigra::MultiArrayV iew</em> <BR>&nbsp;&nbsp;&nbsp;<em>Iterator for strided \ref vigra::MultiArrayV iew</em>
<LI> \ref vigra::StridedScanOrderIterator <LI> \ref vigra::StridedScanOrderIterator
skipping to change at line 336 skipping to change at line 727
<tr><td colspan=3> <tr><td colspan=3>
<tt>i, j</tt> are of type <tt>MultiIterator</tt><br> <tt>i, j</tt> are of type <tt>MultiIterator</tt><br>
<tt>d</tt> is of type <tt>MultiIterator::difference_type</tt> <tt>d</tt> is of type <tt>MultiIterator::difference_type</tt>
</td> </td>
</tr> </tr>
</table> </table>
</p> </p>
*/ */
/** \addtogroup MultiIteratorGroup Multi-dimensional Array Iterators /** \addtogroup MultiIteratorGroup
\brief General iterators for arrays of arbitrary dimension.
*/ */
//@{ //@{
/** Index type for a single dimension of a MultiArrayView or
MultiArray.
*/
typedef std::ptrdiff_t MultiArrayIndex;
/** Traits class for the difference type of all MultiIterator, MultiArr
ayView, and
MultiArray variants.
*/
template <unsigned int N>
class MultiArrayShape
{
public:
/** The difference type of all MultiIterator, MultiArrayView, and
MultiArray variants.
*/
typedef TinyVector<MultiArrayIndex, N> type;
};
typedef MultiArrayShape<1>::type Shape1; ///< shape type for MultiArray<1,
T>
typedef MultiArrayShape<2>::type Shape2; ///< shape type for MultiArray<2,
T>
typedef MultiArrayShape<3>::type Shape3; ///< shape type for MultiArray<3,
T>
typedef MultiArrayShape<4>::type Shape4; ///< shape type for MultiArray<4,
T>
typedef MultiArrayShape<5>::type Shape5; ///< shape type for MultiArray<5,
T>
template <class POINTER> template <class POINTER>
struct MultiIteratorStrideTraits struct MultiIteratorStrideTraits
{ {
typedef MultiArrayIndex stride_type; typedef MultiArrayIndex stride_type;
typedef const stride_type* stride_array_type; typedef const stride_type* stride_array_type;
typedef stride_array_type shape_array_type; typedef stride_array_type shape_array_type;
static stride_array_type shift(stride_array_type s, unsigned d) static stride_array_type shift(stride_array_type s, unsigned d)
{ {
return s + d; return s + d;
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIterator */ /* MultiIterator */
/* */ /* */
/********************************************************/ /********************************************************/
template <unsigned int N, class T, class REFERENCE, class POINTER>
class MultiIterator;
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIterator<1> */ /* MultiIterator<1> */
/* */ /* */
/********************************************************/ /********************************************************/
// //
template <class T, class REFERENCE, class POINTER> template <class T, class REFERENCE, class POINTER>
class MultiIterator<1, T, REFERENCE, POINTER> class MultiIterator<1, T, REFERENCE, POINTER>
{ {
skipping to change at line 779 skipping to change at line 1141
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIterator<N> */ /* MultiIterator<N> */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief A multi-dimensional hierarchical iterator to be used with /** \brief A multi-dimensional hierarchical iterator to be used with
\ref vigra::MultiArrayView if it is not strided. \ref vigra::MultiArrayView if it is not strided.
See \ref MultiIteratorPage for further documentation. See \ref MultiIteratorPage for further documentation.
<b>\#include</b> \<vigra/multi_iterator.hxx\>
Namespace: vigra <b>\#include</b> \<vigra/multi_iterator.hxx\> <br>
Namespace: vigra
*/ */
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
class MultiIterator class MultiIterator
#ifndef DOXYGEN // doxygen doesn't understand this inheritance #ifndef DOXYGEN // doxygen doesn't understand this inheritance
: public MultiIterator<N-1, T, REFERENCE, POINTER> : public MultiIterator<N-1, T, REFERENCE, POINTER>
#endif #endif
{ {
public: public:
/** the type of the parent in the inheritance hierarchy. /** the type of the parent in the inheritance hierarchy.
skipping to change at line 1147 skipping to change at line 1508
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* StridedMultiIterator */ /* StridedMultiIterator */
/* */ /* */
/********************************************************/ /********************************************************/
template <unsigned int N, class T, class REFERENCE, class POINTER>
class StridedMultiIterator;
/********************************************************/ /********************************************************/
/* */ /* */
/* StridedMultiIterator<1> */ /* StridedMultiIterator<1> */
/* */ /* */
/********************************************************/ /********************************************************/
// //
template <class T, class REFERENCE, class POINTER> template <class T, class REFERENCE, class POINTER>
class StridedMultiIterator<1, T, REFERENCE, POINTER> class StridedMultiIterator<1, T, REFERENCE, POINTER>
{ {
skipping to change at line 1545 skipping to change at line 1903
/********************************************************/ /********************************************************/
/* */ /* */
/* StridedMultiIterator<N> */ /* StridedMultiIterator<N> */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief A multi-dimensional hierarchical iterator to be used with /** \brief A multi-dimensional hierarchical iterator to be used with
\ref vigra::MultiArrayView if it is not strided. \ref vigra::MultiArrayView if it is not strided.
See \ref MultiIteratorPage for further documentation. See \ref MultiIteratorPage for further documentation.
<b>\#include</b> \<vigra/multi_iterator.hxx\>
Namespace: vigra <b>\#include</b> \<vigra/multi_iterator.hxx\> <br>
Namespace: vigra
*/ */
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
class StridedMultiIterator class StridedMultiIterator
#ifndef DOXYGEN // doxygen doesn't understand this inheritance #ifndef DOXYGEN // doxygen doesn't understand this inheritance
: public StridedMultiIterator<N-1, T, REFERENCE, POINTER> : public StridedMultiIterator<N-1, T, REFERENCE, POINTER>
#endif #endif
{ {
public: public:
/** the type of the parent in the inheritance hierarchy. /** the type of the parent in the inheritance hierarchy.
skipping to change at line 1906 skipping to change at line 2263
protected: protected:
difference_type difference_type
total_stride(typename multi_difference_type::const_iterator d) const total_stride(typename multi_difference_type::const_iterator d) const
{ {
return d[level]*this->m_stride[level] + base_type::total_stride(d); return d[level]*this->m_stride[level] + base_type::total_stride(d);
} }
}; };
namespace detail { //@}
template <int K>
struct CoordinateToScanOrder
{
template <int N>
static MultiArrayIndex
exec(const TinyVector <MultiArrayIndex, N> &shape,
const TinyVector <MultiArrayIndex, N> & coordinate)
{
return coordinate[N-K] + shape[N-K] * CoordinateToScanOrder<K-1>::e
xec(shape, coordinate);
}
};
template <>
struct CoordinateToScanOrder<1>
{
template <int N>
static MultiArrayIndex
exec(const TinyVector <MultiArrayIndex, N> & /*shape*/,
const TinyVector <MultiArrayIndex, N> & coordinate)
{
return coordinate[N-1];
}
};
template <unsigned int M>
struct MoveToScanOrderIndex
{
template <class Shape, class Ptr>
static void
exec(MultiArrayIndex newIndex, Shape const & shape,
Shape & point, Ptr & p, Shape const & strides)
{
enum { N = Shape::static_size };
MultiArrayIndex newPos = newIndex % shape[N-1-M];
p += (newPos - point[N-1-M]) * strides[N-1-M];
point[N-1-M] = newPos;
MoveToScanOrderIndex<M-1>::exec(newIndex / shape[N-1-M], shape, poi
nt, p, strides);
}
template <class Shape, class Ptr1, class Ptr2>
static void
exec(MultiArrayIndex newIndex, Shape const & shape, Shape & point,
Ptr1 & p1, Shape const & strides1, Ptr2 & p2, Shape const & stride
s2)
{
enum { N = Shape::static_size };
MultiArrayIndex newPos = newIndex % shape[N-1-M];
p1 += (newPos - point[N-1-M]) * strides1[N-1-M];
p2 += (newPos - point[N-1-M]) * strides2[N-1-M];
point[N-1-M] = newPos;
MoveToScanOrderIndex<M-1>::exec(newIndex / shape[N-1-M], shape, poi
nt,
p1, strides1, p2, strides2);
}
};
template <>
struct MoveToScanOrderIndex<0>
{
template <class Shape, class Ptr>
static void
exec(MultiArrayIndex newIndex, Shape const & shape,
Shape & point, Ptr & p, Shape const & strides)
{
enum { N = Shape::static_size };
MultiArrayIndex newPos = std::min(newIndex, shape[N-1]);
p += (newPos - point[N-1]) * strides[N-1];
point[N-1] = newPos;
}
template <class Shape, class Ptr1, class Ptr2>
static void
exec(MultiArrayIndex newIndex, Shape const & shape, Shape & point,
Ptr1 & p1, Shape const & strides1, Ptr2 & p2, Shape const & stride
s2)
{
enum { N = Shape::static_size };
MultiArrayIndex newPos = std::min(newIndex, shape[N-1]);
p1 += (newPos - point[N-1]) * strides1[N-1];
p2 += (newPos - point[N-1]) * strides2[N-1];
point[N-1] = newPos;
}
};
#if 0 // alternative implementation, may be faster on some machines
template <unsigned int M>
struct MoveToScanOrderIndex
{
template <class Shape, class Ptr>
static void
exec(MultiArrayIndex & newIndex, Shape const & shape,
Shape & point, Ptr & p, Shape const & strides, MultiArrayIndex sha
peStride = 1)
{
enum { N = Shape::static_size };
MoveToScanOrderIndex<M-1>::exec(newIndex, shape, point, p, strides,
shapeStride*shape[N-1-M]);
MultiArrayIndex newPos = newIndex / shapeStride;
p += (newPos - point[N-1-M]) * strides[N-1-M];
point[N-1-M] = newPos;
newIndex %= shapeStride;
}
template <class Shape, class Ptr1, class Ptr2>
static void
exec(MultiArrayIndex & newIndex, Shape const & shape, Shape & point,
Ptr1 & p1, Shape const & strides1, Ptr2 & p2, Shape const & stride
s2,
MultiArrayIndex shapeStride = 1)
{
enum { N = Shape::static_size };
MoveToScanOrderIndex<M-1>::exec(newIndex, shape, point,
p1, strides1, p2, strides2, shapeS
tride*shape[N-1-M]);
MultiArrayIndex newPos = newIndex / shapeStride;
p1 += (newPos - point[N-1-M]) * strides1[N-1-M];
p2 += (newPos - point[N-1-M]) * strides2[N-1-M];
point[N-1-M] = newPos;
newIndex %= shapeStride;
}
};
template <>
struct MoveToScanOrderIndex<0>
{
template <class Shape, class Ptr>
static void
exec(MultiArrayIndex & newIndex, Shape const & shape,
Shape & point, Ptr & p, Shape const & strides, MultiArrayIndex sha
peStride)
{
enum { N = Shape::static_size };
MultiArrayIndex newPos = newIndex / shapeStride;
p += (newPos - point[N-1]) * strides[N-1];
point[N-1] = newPos;
newIndex %= shapeStride;
}
template <class Shape, class Ptr1, class Ptr2>
static void
exec(MultiArrayIndex & newIndex, Shape const & shape, Shape & point,
Ptr1 & p1, Shape const & strides1, Ptr2 & p2, Shape const & stride
s2,
MultiArrayIndex shapeStride)
{
enum { N = Shape::static_size };
MultiArrayIndex newPos = newIndex / shapeStride;
p1 += (newPos - point[N-1]) * strides1[N-1];
p2 += (newPos - point[N-1]) * strides2[N-1];
point[N-1] = newPos;
newIndex %= shapeStride;
}
};
#endif
}
/** \brief Sequential iterator for MultiArrayView.
This iterator provides STL-compatible random access iterator functi
onality for arbitrary
\ref MultiArrayView instances, regardless of their shapes and strid
es. The
class uses an implementation that minimizes speed penalties that co
uld result from
non-trivial strides. The <i>scan-order</i> is defined such that dim
ensions are iterated
from front to back (first to last).
You normally construct instances of this class by calling \ref Mult
iArrayView::begin()
and \ref MultiArrayView::end().
The iterator supports all functions listed in the STL documentation
for
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Ran
dom Access Iterators</a>.
*/
template <unsigned int N, class T, class REFERENCE, class POINTER, unsigned
int M = N>
class StridedScanOrderIterator
#ifndef DOXYGEN // doxygen doesn't understand this inheritance
: protected StridedScanOrderIterator<N, T, REFERENCE, POINTER, M-1>
#endif
{
typedef StridedScanOrderIterator<N, T, REFERENCE, POINTER, M-1> base_ty
pe;
enum { level = M-1 };
public:
typedef typename base_type::value_type value_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::shape_type shape_type;
typedef MultiIteratorStrideTraits<POINTER> stride_traits;
typedef typename stride_traits::stride_type difference_type;
typedef typename stride_traits::stride_array_type difference_array_type
;
typedef StridedScanOrderIterator iterator;
typedef std::random_access_iterator_tag iterator_category;
StridedScanOrderIterator()
{}
StridedScanOrderIterator(pointer i,
shape_type const & shape, shape_type const & s
trides)
: base_type(i, shape, strides)
{}
StridedScanOrderIterator & operator++()
{
base_type::operator++();
if(this->point_[level-1] == this->shape_[level-1])
{
base_type::reset();
this->i_ += this->strides_[level];
++this->point_[level];
}
return *this;
}
StridedScanOrderIterator operator++(int)
{
StridedScanOrderIterator res(*this);
++*this;
return res;
}
StridedScanOrderIterator & operator+=(MultiArrayIndex i)
{
this->moveToScanOrderIndex(this->index_+i);
return *this;
}
//! overload to add a coord-tuple:
// it should be cheaper because the modulo-divisions are avoided
StridedScanOrderIterator & operator+=(const shape_type &coordOffset)
{
this->moveRelative(dot(coordOffset,this->strides_),
detail::CoordinateToScanOrder<N>::exec(this->shape_, coordOf
fset),
coordOffset);
return *this;
}
StridedScanOrderIterator & operator-=(const shape_type &coordOffset)
{
return operator+=(-coordOffset);
}
StridedScanOrderIterator & operator--()
{
base_type::operator--();
if(this->point_[level-1] == -1)
{
base_type::inverseReset();
this->i_ -= this->strides_[level];
--this->point_[level];
}
return *this;
}
StridedScanOrderIterator operator--(int)
{
StridedScanOrderIterator res(*this);
--*this;
return res;
}
StridedScanOrderIterator & operator-=(MultiArrayIndex i)
{
return operator+=(-i);
}
StridedScanOrderIterator getEndIterator() const
{
StridedScanOrderIterator res(*this);
res.moveToScanOrderIndex(prod(this->shape_));
return res;
}
bool atBorder() const
{
return base_type::atBorder() ||
this->point_[level] == 0 ||
this->point_[level] == this->shape_[level] - 1;
}
unsigned int neighborhoodType() const
{
unsigned int res = base_type::neighborhoodType();
if(this->point_[level] == 0)
res |= (1 << 2*level);
if(this->point_[level] == this->shape_[level]-1)
res |= (2 << 2*level);
return res;
}
StridedScanOrderIterator operator+(MultiArrayIndex d) const
{
return StridedScanOrderIterator(*this) += d;
}
StridedScanOrderIterator operator-(MultiArrayIndex d) const
{
return StridedScanOrderIterator(*this) -= d;
}
StridedScanOrderIterator operator+(const shape_type &coordOffset) const
{
return StridedScanOrderIterator(*this) += coordOffset;
}
StridedScanOrderIterator operator-(const shape_type &coordOffset) const
{
return StridedScanOrderIterator(*this) -= coordOffset;
}
MultiArrayIndex operator-(StridedScanOrderIterator const & r) const
{
return base_type::operator-(r);
}
bool operator==(StridedScanOrderIterator const & r)
{
return base_type::operator==(r);
}
bool operator!=(StridedScanOrderIterator const & r) const
{
return base_type::operator!=(r);
}
bool operator<(StridedScanOrderIterator const & r) const
{
return base_type::operator<(r);
}
bool operator<=(StridedScanOrderIterator const & r) const
{
return base_type::operator<=(r);
}
bool operator>(StridedScanOrderIterator const & r) const
{
return base_type::operator>(r);
}
bool operator>=(StridedScanOrderIterator const & r) const
{
return base_type::operator>=(r);
}
using base_type::point;
using base_type::shape;
using base_type::strides;
using base_type::ptr;
using base_type::index;
using base_type::operator*;
using base_type::operator->;
using base_type::operator[];
protected:
void reset()
{
this->i_ -= this->shape_[level]*this->strides_[level];
this->point_[level] = 0;
}
void inverseReset()
{
this->i_ += this->shape_[level]*this->strides_[level];
this->point_[level] = this->shape_[level]-1;
}
template <class Ptr> } // namespace vigra
void increment(Ptr & p2, shape_type const & strides2)
{
base_type::increment(p2, strides2);
if(this->point_[level-1] == this->shape_[level-1])
{
base_type::reset();
this->i_ += this->strides_[level];
p2 += strides2[level] - this->shape_[level-1]*strides2[level-1]
;
++this->point_[level];
}
}
template <class Ptr> namespace std {
void decrement(Ptr & p2, shape_type const & strides2)
{
base_type::decrement(p2, strides2);
if(this->point_[level-1] == -1)
{
base_type::inverseReset();
this->i_ -= this->strides_[level];
p2 -= strides2[level] - this->shape_[level-1]*strides2[level-1]
;
--this->point_[level];
}
}
StridedScanOrderIterator & moveRelative(const MultiArrayIndex &pointerO
ffset,
const MultiArrayIndex &indexOff
set,
const shape_type &coordOffset)
{
base_type::moveRelative(pointerOffset, indexOffset, coordOffset);
this->point_[level] += coordOffset[level];
return *this;
}
};
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
class StridedScanOrderIterator<N, T, REFERENCE, POINTER, 1> ostream & operator<<(ostream & o, vigra::StridedScanOrderIterator<N, T, REF ERENCE, POINTER> const & i)
{ {
enum { level = 0 }; o << *i;
return o;
public: }
typedef T value_type;
typedef POINTER pointer;
typedef T const * const_pointer;
typedef REFERENCE reference;
typedef T const & const_reference;
typedef typename MultiArrayShape<N>::type shape_type;
typedef MultiIteratorStrideTraits<POINTER> stride_traits;
typedef typename stride_traits::stride_type difference_type;
typedef typename stride_traits::stride_array_type difference_array_type
;
typedef StridedScanOrderIterator iterator;
typedef std::random_access_iterator_tag iterator_category;
StridedScanOrderIterator()
: i_((pointer)0),
index_(0)
{}
StridedScanOrderIterator(pointer i,
shape_type const & shape, shape_type const & s
trides)
: i_(i),
shape_(shape),
strides_(strides),
index_(0)
{}
StridedScanOrderIterator & operator++()
{
i_ += strides_[level];
++point_[level];
++index_;
return *this;
}
StridedScanOrderIterator operator++(int)
{
StridedScanOrderIterator res(*this);
++*this;
return res;
}
StridedScanOrderIterator & operator+=(MultiArrayIndex i)
{
this->moveToScanOrderIndex(index_+i);
return *this;
}
//! overload to add a coord-tuple:
StridedScanOrderIterator & operator+=(const shape_type &coordOffset)
{
this->moveRelative(dot(coordOffset,strides_),
detail::CoordinateToScanOrder<N>::exec(shape_, coordOffset),
coordOffset);
return *this;
}
StridedScanOrderIterator & operator-=(const shape_type &coordOffset)
{
return operator+=(-coordOffset);
}
StridedScanOrderIterator & operator--()
{
i_ -= strides_[level];
--point_[level];
--index_;
return *this;
}
StridedScanOrderIterator operator--(int)
{
StridedScanOrderIterator res(*this);
--this;
return res;
}
StridedScanOrderIterator & operator-=(MultiArrayIndex i)
{
return operator+=(-i);
}
reference operator*()
{
return *i_;
}
const_reference operator*() const
{
return *i_;
}
pointer operator->()
{
return i_;
}
const_pointer operator->() const
{
return i_;
}
pointer ptr()
{
return i_;
}
const_pointer ptr() const
{
return i_;
}
reference operator[](MultiArrayIndex i)
{
StridedScanOrderIterator t(*this);
t.moveToScanOrderIndex(index_+i);
return *t;
}
const_reference operator[](MultiArrayIndex i) const
{
StridedScanOrderIterator t(*this);
t.moveToScanOrderIndex(index_+i);
return *t;
}
StridedScanOrderIterator
operator+(MultiArrayIndex d) const
{
return StridedScanOrderIterator(*this) += d;
}
StridedScanOrderIterator
operator-(MultiArrayIndex d) const
{
return StridedScanOrderIterator(*this) -= d;
}
StridedScanOrderIterator operator+(const shape_type &coordOffset) const
{
return StridedScanOrderIterator(*this) += coordOffset;
}
StridedScanOrderIterator operator-(const shape_type &coordOffset) const
{
return StridedScanOrderIterator(*this) -= coordOffset;
}
MultiArrayIndex
operator-(StridedScanOrderIterator const & r) const
{
return index() - r.index();
}
bool
operator==(StridedScanOrderIterator const & r)
{
return index() == r.index();
}
bool
operator!=(StridedScanOrderIterator const & r) const
{
return index() != r.index();
}
bool
operator<(StridedScanOrderIterator const & r) const
{
return index() < r.index();
}
bool
operator<=(StridedScanOrderIterator const & r) const
{
return index() <= r.index();
}
bool
operator>(StridedScanOrderIterator const & r) const
{
return index() > r.index();
}
bool
operator>=(StridedScanOrderIterator const & r) const
{
return index() >= r.index();
}
bool atBorder() const
{
return point_[level] == 0 || point_[level] == shape_[level] - 1;
}
MultiArrayIndex index() const
{
return index_;
}
shape_type const & point() const
{
return point_;
}
shape_type const & shape() const
{
return shape_;
}
shape_type const & strides() const
{
return strides_;
}
StridedScanOrderIterator getEndIterator() const
{
StridedScanOrderIterator res(*this);
res.moveToScanOrderIndex(prod(shape_));
return res;
}
unsigned int neighborhoodType() const
{
unsigned int res = 0;
if(this->point_[level] == 0)
res |= 1;
if(this->point_[level] == this->shape_[level]-1)
res |= 2;
return res;
}
protected:
void reset()
{
i_ -= shape_[level]*strides_[level];
point_[level] = 0;
}
void inverseReset()
{
i_ += shape_[level]*strides_[level];
point_[level] = shape_[level] - 1;
}
void moveToScanOrderIndex(MultiArrayIndex newIndex)
{
index_ = newIndex;
detail::MoveToScanOrderIndex<N-1>::exec(newIndex, shape_, point_, i
_, strides_);
}
template <class Ptr>
void increment(Ptr & p2, shape_type const & strides2)
{
operator++();
p2 += strides2[level];
}
template <class Ptr>
void decrement(Ptr & p2, shape_type const & strides2)
{
operator--();
p2 -= strides2[level];
}
template <class Ptr>
void moveToScanOrderIndex(MultiArrayIndex newIndex, Ptr & p2, shape_typ
e const & strides2)
{
index_ = newIndex;
detail::MoveToScanOrderIndex<N-1>::exec(newIndex, shape_, point_, i
_, strides_, p2, strides2);
}
StridedScanOrderIterator & moveRelative(const MultiArrayIndex &pointerO
ffset,
const MultiArrayIndex &indexOff
set,
const shape_type &coordOffset)
{
point_[level] += coordOffset[level];
index_+= indexOffset;
i_ += pointerOffset;
return *this;
}
pointer i_;
shape_type point_, shape_, strides_;
MultiArrayIndex index_;
};
//@}
} // namespace vigra } // namespace std
#endif // VIGRA_MULTI_ITERATOR_HXX #endif // VIGRA_MULTI_ITERATOR_HXX
 End of changes. 19 change blocks. 
773 lines changed or deleted 434 lines changed or added


 multi_iterator_coupled.hxx   multi_iterator_coupled.hxx 
skipping to change at line 36 skipping to change at line 36
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef MULTI_ITERATOR_COUPLED_HXX_ #ifndef MULTI_ITERATOR_COUPLED_HXX
#define MULTI_ITERATOR_COUPLED_HXX_ #define MULTI_ITERATOR_COUPLED_HXX
#include "multi_fwd.hxx"
#include "multi_shape.hxx"
#include "multi_handle.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "multi_iterator.hxx"
namespace vigra { namespace vigra {
/** \addtogroup MultiIteratorGroup /** \addtogroup MultiIteratorGroup
*/ */
//@{ //@{
// FIXME: this should go into its separate header file, /********************************************************/
// together with the calculation of neighborhod offsets for Grid /* */
Graph /* CoupledScanOrderIterator<N> */
template <unsigned int N, unsigned int DIMENSION=N-1> /* */
struct NeighborhoodTypeImpl /********************************************************/
{
typedef typename MultiArrayShape<N>::type shape_type;
static unsigned int exec(shape_type const & point, shape_type const & s
hape)
{
unsigned int res = NeighborhoodTypeImpl<N, DIMENSION-1>::exec(point
, shape);
if(point[DIMENSION] == 0)
res |= (1 << 2*DIMENSION);
if(point[DIMENSION] == shape[DIMENSION]-1)
res |= (2 << 2*DIMENSION);
return res;
}
};
template <unsigned int N>
struct NeighborhoodTypeImpl<N, 0>
{
typedef typename MultiArrayShape<N>::type shape_type;
static const unsigned int DIMENSION = 0;
static unsigned int exec(shape_type const & point, shape_type const & s
hape)
{
unsigned int res = 0;
if(point[DIMENSION] == 0)
res |= (1 << 2*DIMENSION);
if(point[DIMENSION] == shape[DIMENSION]-1)
res |= (2 << 2*DIMENSION);
return res;
}
};
/**
Handle class, used by CoupledScanOrderIterator as the value type to si
multaneously itearate over multiple images.
*/
template <class T, class NEXT>
class CoupledHandle
: public NEXT
{
public:
typedef NEXT base_type;
typedef CoupledHandle<T, NEXT> self_type;
static const int index = NEXT::index + 1; // index of
this member of the chain
static const unsigned int dimensions = NEXT::dimensions;
typedef T value_type;
typedef T * pointer;
typedef T const * const_pointer;
typedef T & reference;
typedef T const & const_reference;
typedef typename base_type::shape_type shape_type;
CoupledHandle()
: base_type(),
pointer_(),
strides_()
{}
CoupledHandle(const_pointer p, shape_type const & strides, NEXT const &
next)
: base_type(next),
pointer_(const_cast<pointer>(p)),
strides_(strides)
{}
template <class Stride>
CoupledHandle(MultiArrayView<dimensions, T, Stride> const & v, NEXT con
st & next)
: base_type(next),
pointer_(const_cast<pointer>(v.data())),
strides_(v.stride())
{
vigra_precondition(v.shape() == this->shape(), "createCoupledIterat
or(): shape mismatch.");
}
template<int DIMENSION>
inline void increment()
{
pointer_ += strides_[DIMENSION];
base_type::template increment<DIMENSION>();
}
template<int DIMENSION>
inline void decrement()
{
pointer_ -= strides_[DIMENSION];
base_type::template decrement<DIMENSION>();
}
// TODO: test if making the above a default case of the this hurts perf
ormance
template<int DIMENSION>
inline void increment(MultiArrayIndex offset)
{
pointer_ += offset*strides_[DIMENSION];
base_type::template increment<DIMENSION>(offset);
}
template<int DIMENSION>
inline void decrement(MultiArrayIndex offset)
{
pointer_ -= offset*strides_[DIMENSION];
base_type::template decrement<DIMENSION>(offset);
}
void restrictToSubarray(shape_type const & start, shape_type const & en
d)
{
pointer_ += dot(start, strides_);
base_type::restrictToSubarray(start, end);
}
// ptr access
reference operator*()
{
return *pointer_;
}
const_reference operator*() const
{
return *pointer_;
}
pointer operator->()
{
return pointer_;
}
const_pointer operator->() const
{
return pointer_;
}
pointer ptr()
{
return pointer_;
}
const_pointer ptr() const
{
return pointer_;
}
shape_type const & strides() const
{
return strides_;
}
pointer pointer_;
shape_type strides_;
};
template <int N> template <class Iterator>
class CoupledHandle<TinyVector<MultiArrayIndex, N>, void> class CoupledDimensionProxy
: public Iterator
{ {
public: public:
static const int index = 0; // index of this member o typedef typename Iterator::value_type value_type;
f the chain typedef typename Iterator::difference_type difference_type;
static const unsigned int dimensions = N; typedef typename Iterator::reference reference;
typedef typename Iterator::const_reference const_reference;
typedef typename MultiArrayShape<N>::type value_type; typedef typename Iterator::pointer pointer;
typedef value_type const * pointer; typedef CoupledDimensionProxy iterator;
typedef value_type const * const_pointer; typedef std::random_access_iterator_tag iterator_category;
typedef value_type const & reference;
typedef value_type const & const_reference;
typedef value_type shape_type;
typedef CoupledHandle<value_type, void> self_type;
CoupledHandle()
: point_(),
shape_(),
scanOrderIndex_()
{}
CoupledHandle(value_type const & shape)
: point_(),
shape_(shape),
scanOrderIndex_()
{}
CoupledHandle(typename MultiArrayShape<N+1>::type const & shape)
: point_(),
shape_(shape.begin()),
scanOrderIndex_()
{}
template<int DIMENSION>
inline void increment()
{
++point_[DIMENSION];
}
template<int DIMENSION>
inline void decrement()
{
--point_[DIMENSION];
}
// TODO: test if making the above a default case of the this hurts perf
ormance
template<int DIMENSION>
inline void increment(MultiArrayIndex offset)
{
point_[DIMENSION] += offset;
}
template<int DIMENSION>
inline void decrement(MultiArrayIndex offset)
{
point_[DIMENSION] -= offset;
}
void restrictToSubarray(shape_type const & start, shape_type const & en
d)
{
point_ = shape_type();
shape_ = end - start;
scanOrderIndex_ = 0;
}
inline void incrementIndex()
{
++scanOrderIndex_;
}
inline void decrementIndex()
{
--scanOrderIndex_;
}
inline void incrementIndex(MultiArrayIndex offset)
{
scanOrderIndex_ += offset;
}
inline void decrementIndex(MultiArrayIndex offset)
{
scanOrderIndex_ -= offset;
}
// access
MultiArrayIndex scanOrderIndex() const
{
return scanOrderIndex_;
}
// access
const_reference point() const
{
return point_;
}
// access
const_reference shape() const
{
return shape_;
}
const_reference operator*() const
{
return point_;
}
const_pointer operator->() const static const int dimension = Iterator::dimension;
{
return &point_;
}
const_pointer ptr() const CoupledDimensionProxy & operator++()
{ {
return &point_; this->incDim(dimension);
} return *this;
unsigned int neighborhoodType() const
{
return NeighborhoodTypeImpl<N>::exec(point_, shape_);
} }
value_type point_, shape_; CoupledDimensionProxy operator++(int)
MultiArrayIndex scanOrderIndex_;
};
template <class T>
struct Multiband;
template <unsigned int N, class T, class StrideTag>
class MultiArrayView<N, Multiband<T>, StrideTag>
: public MultiArrayView<N, T, StrideTag>
{
public:
MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
: MultiArrayView<N, T, StrideTag>(v)
{}
};
template <class T, class NEXT>
class CoupledHandle<Multiband<T>, NEXT>
: public NEXT
{
public:
typedef NEXT base_type;
typedef CoupledHandle<Multiband<T>, NEXT> self_type;
static const int index = NEXT::index + 1; // in
dex of this member of the chain
static const unsigned int dimensions = NEXT::dimensions;
typedef MultiArrayView<1, T, StridedArrayTag> value_type;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef value_type & reference;
typedef value_type const & const_reference;
typedef typename base_type::shape_type shape_type;
CoupledHandle()
: base_type(),
view_(),
strides_()
{}
CoupledHandle(const_reference p, shape_type const & strides, NEXT const
& next)
: base_type(next),
view_(p),
strides_(strides)
{}
template <class Stride>
CoupledHandle(MultiArrayView<dimensions+1, Multiband<T>, Stride> const
& v, NEXT const & next)
: base_type(next),
view_(v.bindInner(shape_type())),
strides_(v.bindOuter(0).stride())
{ {
vigra_precondition(v.bindOuter(0).shape() == this->shape(), "create CoupledDimensionProxy ret(*this);
CoupledIterator(): shape mismatch."); this->incDim(dimension);
return ret;
} }
template<int DIMENSION> CoupledDimensionProxy & operator--()
inline void increment()
{ {
view_.unsafePtr() += strides_[DIMENSION]; this->decDim(dimension);
base_type::template increment<DIMENSION>(); return *this;
} }
template<int DIMENSION> CoupledDimensionProxy operator--(int)
inline void decrement()
{ {
view_.unsafePtr() -= strides_[DIMENSION]; CoupledDimensionProxy ret(*this);
base_type::template decrement<DIMENSION>(); this->decDim(dimension);
return ret;
} }
// TODO: test if making the above a default case of the this hurts perf CoupledDimensionProxy & operator+=(MultiArrayIndex d)
ormance
template<int DIMENSION>
inline void increment(MultiArrayIndex offset)
{ {
view_.unsafePtr() += offset*strides_[DIMENSION]; this->addDim(dimension, d);
base_type::template increment<DIMENSION>(offset); return *this;
} }
template<int DIMENSION> CoupledDimensionProxy & operator-=(MultiArrayIndex d)
inline void decrement(MultiArrayIndex offset)
{ {
view_.unsafePtr() -= offset*strides_[DIMENSION]; this->addDim(dimension, -d);
base_type::template decrement<DIMENSION>(offset); return *this;
} }
void restrictToSubarray(shape_type const & start, shape_type const & en d) value_type operator[](MultiArrayIndex d) const
{ {
view_.unsafePtr() += dot(start, strides_); return *(CoupledDimensionProxy(*this) += d);
base_type::restrictToSubarray(start, end);
} }
// ptr access CoupledDimensionProxy & operator=(MultiArrayIndex d)
reference operator*()
{ {
return view_; this->setDim(dimension, d);
return *this;
} }
const_reference operator*() const bool operator==(MultiArrayIndex d) const
{ {
return view_; return this->point(dimension) == d;
} }
pointer operator->() bool operator!=(MultiArrayIndex d) const
{ {
return &view_; return this->point(dimension) != d;
} }
const_pointer operator->() const bool operator<(MultiArrayIndex d) const
{ {
return &view_; return this->point(dimension) < d;
} }
pointer ptr() bool operator<=(MultiArrayIndex d) const
{ {
return &view_; return this->point(dimension) <= d;
} }
const_pointer ptr() const bool operator>(MultiArrayIndex d) const
{ {
return &view_; return this->point(dimension) > d;
} }
shape_type const & strides() const bool operator>=(MultiArrayIndex d) const
{ {
return strides_; return this->point(dimension) >= d;
} }
value_type view_;
shape_type strides_;
};
template <unsigned TARGET_INDEX>
struct Error__CoupledHandle_index_out_of_range;
namespace detail {
template <unsigned TARGET_INDEX, class Handle, bool isValid, unsigned int I
NDEX=Handle::index>
struct CoupledHandleCastImpl
{
typedef typename CoupledHandleCastImpl<TARGET_INDEX, typename Handle::b
ase_type, isValid>::type type;
};
template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX>
struct CoupledHandleCastImpl<TARGET_INDEX, Handle, false, INDEX>
{
typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> type;
};
template <unsigned TARGET_INDEX, class Handle>
struct CoupledHandleCastImpl<TARGET_INDEX, Handle, true, TARGET_INDEX>
{
typedef Handle type;
};
} // namespace detail
template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX=Handle::i
ndex>
struct CoupledHandleCast
: public detail::CoupledHandleCastImpl<TARGET_INDEX, Handle, (TARGET_INDEX
<= INDEX), INDEX>
{};
template <unsigned int TARGET_INDEX, class Handle>
typename CoupledHandleCast<TARGET_INDEX, Handle>::type &
cast(Handle & handle)
{
return handle;
};
template <unsigned int TARGET_INDEX, class Handle>
typename CoupledHandleCast<TARGET_INDEX, Handle>::type const &
cast(Handle const & handle)
{
return handle;
};
/** Returns reference to the element in the band of the handle with index
TARGET_INDEX.
*/
template <unsigned int TARGET_INDEX, class Handle>
typename CoupledHandleCast<TARGET_INDEX, Handle>::type::reference
get(Handle & handle)
{
return *cast<TARGET_INDEX>(handle);
};
/** Returns a constant reference to the element in the band of the handle
with index TARGET_INDEX.
*/
template <unsigned int TARGET_INDEX, class Handle>
typename CoupledHandleCast<TARGET_INDEX, Handle>::type::const_reference
get(Handle const & handle)
{
return *cast<TARGET_INDEX>(handle);
}; };
/********************************************************/
/* */
/* CoupledScanOrderIterator<N> */
/* */
/********************************************************/
/** \brief Iterate over multiple images simultaneously in scan order. /** \brief Iterate over multiple images simultaneously in scan order.
The value type of this iterator is an instance of the handle class Coup ledHandle. This allows to iterate over multiple arrays simultaneously. The coordinates can be accessed as a special band (index 0) in the handle. The scan-order is defined such that dimensions are iterated from front to back (first to last). The value type of this iterator is an instance of the handle class Coup ledHandle. This allows to iterate over multiple arrays simultaneously. The coordinates can be accessed as a special band (index 0) in the handle. The scan-order is defined such that dimensions are iterated from front to back (first to last).
Instances of this class are usually constructed by calling createCouple dIterator() . Instances of this class are usually constructed by calling createCouple dIterator() .
To get the type of a CoupledScanOrderIterator for arrays of a certain d imension and element types use CoupledIteratorType::type. To get the type of a CoupledScanOrderIterator for arrays of a certain d imension and element types use CoupledIteratorType::type.
The iterator supports all functions listed in the STL documentation for The iterator supports all functions listed in the STL documentation for
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Ran <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Ran
dom dom Access Iterators</a>.
Access Iterators</a>.
Example of use: Example of use:
\code \code
using namespace vigra; using namespace vigra;
MultiArray<2, double> image1(Shape2(5, 5)); MultiArray<2, double> image1(Shape2(5, 5));
MultiArray<2, double> image2(Shape2(5, 5)); MultiArray<2, double> image2(Shape2(5, 5));
// fill image with data ... // fill image with data ...
typedef CoupledIteratorType<2, double, double>::type Iterator; // the t ype of the CoupledScanOrderIterator typedef CoupledIteratorType<2, double, double>::type Iterator; // the t ype of the CoupledScanOrderIterator
skipping to change at line 557 skipping to change at line 185
std::cout << "coordinates: " << it.get<0>() << std::endl; std::cout << "coordinates: " << it.get<0>() << std::endl;
std::cout << "image1: " << it.get<1>() << std::endl; std::cout << "image1: " << it.get<1>() << std::endl;
std::cout << "image2: " << it.get<2>() << std::endl; std::cout << "image2: " << it.get<2>() << std::endl;
} }
//random access: //random access:
Iterator::value_type handle = start[15]; Iterator::value_type handle = start[15];
std::cout << "image1: " << get<1>(handle) << std::endl; std::cout << "image1: " << get<1>(handle) << std::endl;
\endcode \endcode
<b>\#include</b> \<vigra/multi_iterator_coupled.hxx\> <b>\#include</b> \<vigra/multi_iterator_coupled.hxx\> <br/>
Namespace: vigra
Namespace: vigra
*/ */
template <unsigned int N, template <unsigned int N,
class HANDLES, class HANDLES,
int DIMENSION = N-1> int DIMENSION> // NOTE: default template arguments are defined i n multi_fwd.hxx
class CoupledScanOrderIterator class CoupledScanOrderIterator
#ifndef DOXYGEN // doxygen doesn't understand this inheritance #ifndef DOXYGEN // doxygen doesn't understand this inheritance
: protected CoupledScanOrderIterator<N, HANDLES, DIMENSION-1> : public CoupledScanOrderIterator<N, HANDLES, DIMENSION-1>
#endif #endif
{ {
typedef CoupledScanOrderIterator<N, HANDLES, DIMENSION-1> base_type; typedef CoupledScanOrderIterator<N, HANDLES, DIMENSION-1> base_type;
static const int dimension = DIMENSION;
public: public:
static const int dimension = DIMENSION;
typedef typename MultiArrayShape<dimension+1>::type shape_type;
typedef MultiArrayIndex difference_type; typedef MultiArrayIndex difference_type;
typedef CoupledScanOrderIterator iterator; typedef CoupledScanOrderIterator iterator;
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category;
typedef typename base_type::value_type value_type; typedef typename base_type::value_type value_type;
#ifdef DOXYGEN #ifdef DOXYGEN
/** The type of the CoupledHandle. /** The type of the CoupledHandle.
*/ */
typedef HANDLES value_type; typedef HANDLES value_type;
#endif #endif
typedef typename base_type::shape_type shape_type;
typedef typename base_type::reference reference; typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference; // FIXME: do we need both? typedef typename base_type::const_reference const_reference; // FIXME: do we need both?
typedef typename base_type::pointer pointer; typedef typename base_type::pointer pointer;
typedef CoupledDimensionProxy<iterator> dimension_proxy;
CoupledScanOrderIterator(value_type const & handles = value_type()) explicit CoupledScanOrderIterator(value_type const & handles = value_ty pe())
: base_type(handles) : base_type(handles)
{} {}
value_type operator[](MultiArrayIndex i) const
{
return *(CoupledScanOrderIterator(*this) += i);
}
CoupledScanOrderIterator & operator++() CoupledScanOrderIterator & operator++()
{ {
base_type::operator++(); base_type::operator++();
if(this->point()[dimension-1] == this->shape()[dimension-1]) if(this->point()[dimension-1] == this->shape()[dimension-1])
{ {
base_type::reset(); resetAndIncrement();
this->handles_.template increment<dimension>();
} }
return *this; return *this;
} }
CoupledScanOrderIterator operator++(int) CoupledScanOrderIterator operator++(int)
{ {
CoupledScanOrderIterator res(*this); CoupledScanOrderIterator res(*this);
++*this; ++*this;
return res; return res;
} }
CoupledScanOrderIterator & operator+=(MultiArrayIndex i) CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
{ {
// FIXME: this looks very expensive base_type::operator+=(i);
shape_type coordOffset;
detail::ScanOrderToCoordinate<N>::exec(i+scanOrderIndex(), this->sh
ape(), coordOffset);
coordOffset -= point();
moveRelative(coordOffset);
this->handles_.scanOrderIndex_ += i;
return *this; return *this;
} }
CoupledScanOrderIterator & operator+=(const shape_type &coordOffset) CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
{ {
moveRelative(coordOffset); base_type::operator+=(coordOffset);
this->handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>:
:exec(this->shape(), coordOffset);
return *this; return *this;
} }
CoupledScanOrderIterator & operator--() CoupledScanOrderIterator & operator--()
{ {
base_type::operator--(); base_type::operator--();
if(this->point()[dimension-1] == -1) if(this->point()[dimension-1] == -1)
{ {
base_type::inverseReset(); resetAndDecrement();
this->handles_.template decrement<dimension>();
} }
return *this; return *this;
} }
CoupledScanOrderIterator operator--(int) CoupledScanOrderIterator operator--(int)
{ {
CoupledScanOrderIterator res(*this); CoupledScanOrderIterator res(*this);
--*this; --*this;
return res; return res;
} }
skipping to change at line 665 skipping to change at line 280
CoupledScanOrderIterator & operator-=(MultiArrayIndex i) CoupledScanOrderIterator & operator-=(MultiArrayIndex i)
{ {
return operator+=(-i); return operator+=(-i);
} }
CoupledScanOrderIterator & operator-=(const shape_type &coordOffset) CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
{ {
return operator+=(-coordOffset); return operator+=(-coordOffset);
} }
/** Returns CoupledScanOrderIterator pointing beyond the last element. /** Returns CoupledScanOrderIterator pointing beyond the last eleme
*/ nt.
*/
CoupledScanOrderIterator getEndIterator() const CoupledScanOrderIterator getEndIterator() const
{ {
return operator+(prod(this->shape())); return operator+(prod(this->shape()) - this->scanOrderIndex());
} }
CoupledScanOrderIterator operator+(MultiArrayIndex d) const CoupledScanOrderIterator operator+(MultiArrayIndex d) const
{ {
return CoupledScanOrderIterator(*this) += d; return CoupledScanOrderIterator(*this) += d;
} }
CoupledScanOrderIterator operator-(MultiArrayIndex d) const CoupledScanOrderIterator operator-(MultiArrayIndex d) const
{ {
return CoupledScanOrderIterator(*this) -= d; return CoupledScanOrderIterator(*this) -= d;
skipping to change at line 697 skipping to change at line 312
CoupledScanOrderIterator operator-(const shape_type &coordOffset) const CoupledScanOrderIterator operator-(const shape_type &coordOffset) const
{ {
return CoupledScanOrderIterator(*this) -= coordOffset; return CoupledScanOrderIterator(*this) -= coordOffset;
} }
MultiArrayIndex operator-(CoupledScanOrderIterator const & r) const MultiArrayIndex operator-(CoupledScanOrderIterator const & r) const
{ {
return base_type::operator-(r); return base_type::operator-(r);
} }
bool operator==(CoupledScanOrderIterator const & r) CoupledScanOrderIterator &
restrictToSubarray(shape_type const & start, shape_type const & end)
{ {
return base_type::operator==(r); base_type::restrictToSubarray(start, end);
} return *this;
bool operator!=(CoupledScanOrderIterator const & r) const
{
return base_type::operator!=(r);
}
bool operator<(CoupledScanOrderIterator const & r) const
{
return base_type::operator<(r);
}
bool operator<=(CoupledScanOrderIterator const & r) const
{
return base_type::operator<=(r);
}
bool operator>(CoupledScanOrderIterator const & r) const
{
return base_type::operator>(r);
} }
bool operator>=(CoupledScanOrderIterator const & r) const #ifdef DOXYGEN
{
return base_type::operator>=(r);
}
using base_type::operator*; /** Returns reference to the element in the band with index TARGET_
using base_type::point; INDEX.
using base_type::shape; */
using base_type::scanOrderIndex; template<unsigned int TARGET_INDEX>
using base_type::atBorder; typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
using base_type::neighborhoodType; get();
using base_type::get;
#ifdef DOXYGEN /** Returns constant reference to the element in the band with inde
x TARGET_INDEX.
*/
template<unsigned int TARGET_INDEX>
typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_refer
ence
get() const;
/** Returns reference to the element in the band with index TARGET_INDEX.
*/
template<unsigned int TARGET_INDEX>
typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
get()
{
return vigra::get<TARGET_INDEX>(handles_);
}
/** Returns constant reference to the element in the band with index TARG
ET_INDEX.
*/
template<unsigned int TARGET_INDEX>
typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_referen
ce
get() const
{
return vigra::get<TARGET_INDEX>(handles_);
}
#endif #endif
protected: protected:
// placing these functions out-of-line prevents MSVC
// from stupid optimizations
void resetAndIncrement();
void resetAndDecrement();
void reset() void reset()
{ {
this->handles_.template decrement<dimension>(this->shape()[dimensio n]); this->handles_.template decrement<dimension>(this->shape()[dimensio n]);
} }
void inverseReset() void inverseReset()
{ {
this->handles_.template increment<dimension>(this->shape()[dimensio n]); this->handles_.template increment<dimension>(this->shape()[dimensio n]);
} }
void moveRelative(typename value_type::shape_type const & coordOffset)
{
base_type::moveRelative(coordOffset);
this->handles_.template increment<dimension>(coordOffset[dimension]
);
}
}; };
template <unsigned int N, class HANDLES, int DIMENSION>
void CoupledScanOrderIterator<N, HANDLES, DIMENSION>::resetAndIncrement()
{
base_type::reset();
this->handles_.template increment<dimension>();
}
template <unsigned int N, class HANDLES, int DIMENSION>
void CoupledScanOrderIterator<N, HANDLES, DIMENSION>::resetAndDecrement()
{
base_type::inverseReset();
this->handles_.template decrement<dimension>();
}
template <unsigned int N, class HANDLES> template <unsigned int N, class HANDLES>
class CoupledScanOrderIterator<N, HANDLES, 0> class CoupledScanOrderIterator<N, HANDLES, 0>
{ {
static const int dimension = 0;
public: public:
static const int dimension = 0;
typedef CoupledScanOrderIterator<N, HANDLES, 0> self_type; typedef CoupledScanOrderIterator<N, HANDLES, 0> self_type;
typedef HANDLES value_type; typedef HANDLES value_type;
typedef MultiArrayIndex difference_type; typedef MultiArrayIndex difference_type;
typedef value_type & reference; typedef value_type & reference;
typedef value_type const & const_reference; typedef value_type const & const_reference;
typedef value_type * pointer; typedef value_type * pointer;
typedef typename MultiArrayShape<1>::type shape_type; typedef typename MultiArrayShape<N>::type shape_type;
typedef CoupledScanOrderIterator iterator; typedef CoupledScanOrderIterator iterator;
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category;
typedef CoupledDimensionProxy<iterator> dimension_proxy;
template <unsigned int TARGET_INDEX>
struct Reference
{
typedef typename CoupledHandleCast<TARGET_INDEX, HANDLES>::referenc
e type;
};
template <unsigned int TARGET_INDEX>
struct ConstReference
{
typedef typename CoupledHandleCast<TARGET_INDEX, HANDLES>::const_re
ference type;
};
CoupledScanOrderIterator(value_type const & handles = value_type()) explicit CoupledScanOrderIterator(value_type const & handles = value_ty
: handles_(handles) pe())
: handles_(handles),
strides_(detail::defaultStride(handles_.shape()))
{} {}
template <unsigned int DIM>
typename CoupledScanOrderIterator<N, HANDLES, DIM>::dimension_proxy &
dim()
{
typedef CoupledScanOrderIterator<N, HANDLES, DIM> Iter;
typedef typename Iter::dimension_proxy Proxy;
return static_cast<Proxy &>(static_cast<Iter &>(*this));
}
template <unsigned int DIM>
typename CoupledScanOrderIterator<N, HANDLES, DIM>::dimension_proxy con
st &
dim() const
{
typedef CoupledScanOrderIterator<N, HANDLES, DIM> Iter;
typedef typename Iter::dimension_proxy Proxy;
return static_cast<Proxy const &>(static_cast<Iter const &>(*this))
;
}
void incDim(int dim)
{
handles_.incDim(dim);
handles_.incrementIndex(strides_[dim]);
}
void decDim(int dim)
{
handles_.decDim(dim);
handles_.decrementIndex(strides_[dim]);
}
void addDim(int dim, MultiArrayIndex d)
{
handles_.addDim(dim, d);
handles_.incrementIndex(d*strides_[dim]);
}
void setDim(int dim, MultiArrayIndex d)
{
d -= point(dim);
handles_.addDim(dim, d);
handles_.incrementIndex(d*strides_[dim]);
}
void resetDim(int dim)
{
MultiArrayIndex d = -point(dim);
handles_.addDim(dim, d);
handles_.incrementIndex(d*strides_[dim]);
}
CoupledScanOrderIterator & operator++() CoupledScanOrderIterator & operator++()
{ {
handles_.template increment<dimension>(); handles_.template increment<dimension>();
handles_.incrementIndex(); handles_.incrementIndex();
return *this; return *this;
} }
CoupledScanOrderIterator operator++(int) CoupledScanOrderIterator operator++(int)
{ {
CoupledScanOrderIterator res(*this); CoupledScanOrderIterator res(*this);
++*this; ++*this;
return res; return res;
} }
CoupledScanOrderIterator & operator+=(MultiArrayIndex i) CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
{ {
// FIXME: this looks very expensive
shape_type coordOffset; shape_type coordOffset;
detail::ScanOrderToCoordinate<N>::exec(i, shape(), coordOffset); detail::ScanOrderToCoordinate<N>::exec(i+scanOrderIndex(), shape(),
moveRelative(coordOffset); coordOffset);
coordOffset -= point();
handles_.add(coordOffset);
handles_.scanOrderIndex_ += i; handles_.scanOrderIndex_ += i;
return *this; return *this;
} }
CoupledScanOrderIterator & operator+=(const shape_type &coordOffset) CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
{ {
moveRelative(coordOffset); handles_.add(coordOffset);
handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec( shape(), coordOffset); handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec( shape(), coordOffset);
return *this; return *this;
} }
CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
{
return operator+=(-coordOffset);
}
CoupledScanOrderIterator & operator--() CoupledScanOrderIterator & operator--()
{ {
handles_.template decrement<dimension>(); handles_.template decrement<dimension>();
handles_.decrementIndex(); handles_.decrementIndex();
return *this; return *this;
} }
CoupledScanOrderIterator operator--(int) CoupledScanOrderIterator operator--(int)
{ {
CoupledScanOrderIterator res(*this); CoupledScanOrderIterator res(*this);
--this; --this;
return res; return res;
} }
CoupledScanOrderIterator & operator-=(MultiArrayIndex i) CoupledScanOrderIterator & operator-=(MultiArrayIndex i)
{ {
return operator+=(-i); return operator+=(-i);
} }
CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
{
return operator+=(-coordOffset);
}
value_type operator[](MultiArrayIndex i) const value_type operator[](MultiArrayIndex i) const
{ {
return *(CoupledScanOrderIterator(*this) += i); return *(CoupledScanOrderIterator(*this) += i);
} }
value_type operator[](const shape_type& coordOffset) const
{
return *(CoupledScanOrderIterator(*this) += coordOffset);
}
CoupledScanOrderIterator CoupledScanOrderIterator
operator+(MultiArrayIndex d) const operator+(MultiArrayIndex d) const
{ {
return CoupledScanOrderIterator(*this) += d; return CoupledScanOrderIterator(*this) += d;
} }
CoupledScanOrderIterator CoupledScanOrderIterator
operator-(MultiArrayIndex d) const operator-(MultiArrayIndex d) const
{ {
return CoupledScanOrderIterator(*this) -= d; return CoupledScanOrderIterator(*this) -= d;
skipping to change at line 882 skipping to change at line 545
{ {
return CoupledScanOrderIterator(*this) -= coordOffset; return CoupledScanOrderIterator(*this) -= coordOffset;
} }
MultiArrayIndex MultiArrayIndex
operator-(CoupledScanOrderIterator const & r) const operator-(CoupledScanOrderIterator const & r) const
{ {
return scanOrderIndex() - r.scanOrderIndex(); return scanOrderIndex() - r.scanOrderIndex();
} }
bool bool operator==(CoupledScanOrderIterator const & r) const
operator==(CoupledScanOrderIterator const & r)
{ {
return scanOrderIndex() == r.scanOrderIndex(); return scanOrderIndex() == r.scanOrderIndex();
} }
bool bool operator!=(CoupledScanOrderIterator const & r) const
operator!=(CoupledScanOrderIterator const & r) const
{ {
return scanOrderIndex() != r.scanOrderIndex(); return scanOrderIndex() != r.scanOrderIndex();
} }
bool bool operator<(CoupledScanOrderIterator const & r) const
operator<(CoupledScanOrderIterator const & r) const
{ {
return scanOrderIndex() < r.scanOrderIndex(); return scanOrderIndex() < r.scanOrderIndex();
} }
bool bool operator<=(CoupledScanOrderIterator const & r) const
operator<=(CoupledScanOrderIterator const & r) const
{ {
return scanOrderIndex() <= r.scanOrderIndex(); return scanOrderIndex() <= r.scanOrderIndex();
} }
bool bool operator>(CoupledScanOrderIterator const & r) const
operator>(CoupledScanOrderIterator const & r) const
{ {
return scanOrderIndex() > r.scanOrderIndex(); return scanOrderIndex() > r.scanOrderIndex();
} }
bool bool operator>=(CoupledScanOrderIterator const & r) const
operator>=(CoupledScanOrderIterator const & r) const
{ {
return scanOrderIndex() >= r.scanOrderIndex(); return scanOrderIndex() >= r.scanOrderIndex();
} }
bool isValid() const
{
return handles_.scanOrderIndex() < prod(shape());
}
bool atEnd() const
{
return handles_.scanOrderIndex() >= prod(shape());
}
MultiArrayIndex scanOrderIndex() const MultiArrayIndex scanOrderIndex() const
{ {
return handles_.scanOrderIndex(); return handles_.scanOrderIndex();
} }
typename value_type::shape_type const & point() const shape_type const & coord() const
{ {
return handles_.point(); return handles_.point();
} }
typename value_type::shape_type const & shape() const MultiArrayIndex coord(unsigned int dim) const
{
return coord()[dim];
}
shape_type const & point() const
{
return handles_.point();
}
MultiArrayIndex point(unsigned int dim) const
{
return point()[dim];
}
shape_type const & shape() const
{ {
return handles_.shape(); return handles_.shape();
} }
MultiArrayIndex shape(unsigned int dim) const
{
return handles_.shape()[dim];
}
reference operator*() reference operator*()
{ {
return handles_; return handles_;
} }
const_reference operator*() const const_reference operator*() const
{ {
return handles_; return handles_;
} }
void restrictToSubarray(shape_type const & start, shape_type const & en CoupledScanOrderIterator &
d) const restrictToSubarray(shape_type const & start, shape_type const & end)
{ {
operator+=(-point()); operator+=(-point());
handles_.restricToSubarray(start, end); handles_.restrictToSubarray(start, end);
strides_ = detail::defaultStride(shape());
return *this;
} }
CoupledScanOrderIterator getEndIterator() const CoupledScanOrderIterator getEndIterator() const
{ {
return operator+(prod(shape())); return operator+(prod(shape())-scanOrderIndex());
} }
bool atBorder() const bool atBorder() const
{ {
return (handles_.neighborhoodType() != 0); return (handles_.borderType() != 0);
} }
unsigned int neighborhoodType() const unsigned int borderType() const
{ {
return handles_.neighborhoodType(); return handles_.borderType();
} }
template<unsigned int TARGET_INDEX> template<unsigned int TARGET_INDEX>
typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference typename Reference<TARGET_INDEX>::type
get() get()
{ {
return vigra::get<TARGET_INDEX>(handles_); return vigra::get<TARGET_INDEX>(handles_);
} }
template<unsigned int TARGET_INDEX> template<unsigned int TARGET_INDEX>
typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_refer ence typename ConstReference<TARGET_INDEX>::type
get() const get() const
{ {
return vigra::get<TARGET_INDEX>(handles_); return vigra::get<TARGET_INDEX>(handles_);
} }
protected: reference handles()
void reset()
{
handles_.template decrement<dimension>(shape()[dimension]);
}
void inverseReset()
{
handles_.template increment<dimension>(shape()[dimension]);
}
void moveRelative(typename value_type::shape_type const & coordOffset)
{ {
handles_.template increment<dimension>(coordOffset[dimension]); return handles_;
} }
value_type handles_; const_reference handles() const
};
template <unsigned int N, class List>
struct ComposeCoupledHandle;
template <unsigned int N, class T, class TAIL>
struct ComposeCoupledHandle<N, TypeList<T, TAIL> >
{
typedef typename ComposeCoupledHandle<N, TAIL>::type BaseType;
typedef typename MultiArrayShape<N>::type shape_type;
typedef CoupledHandle<T, BaseType> type;
template <class S>
type exec(MultiArrayView<N, T, S> const & m,
shape_type const & start, shape_type const & end,
BaseType const & base)
{ {
return type(m.subarray(start, end).data(), m.stride(), base); return handles_;
} }
template <class S> protected:
type exec(MultiArrayView<N, T, S> const & m, BaseType const & base) void reset()
{ {
return type(m.data(), m.stride(), base); handles_.template decrement<dimension>(shape()[dimension]);
} }
};
template <unsigned int N> void inverseReset()
struct ComposeCoupledHandle<N, void>
{
typedef typename MultiArrayShape<N>::type shape_type;
typedef CoupledHandle<shape_type, void> type;
type exec(shape_type const & shape)
{ {
return type(shape); handles_.template increment<dimension>(shape()[dimension]);
} }
type exec(shape_type const & start, shape_type const & end) value_type handles_;
{ shape_type strides_;
return type(end-start);
}
}; };
template <unsigned int N, class T1=void, class T2=void, class T3=void, clas template <unsigned int TARGET_INDEX,
s T4=void, class T5=void> unsigned int N,
struct CoupledHandleType class HANDLES,
int DIM>
typename CoupledScanOrderIterator<N, HANDLES, DIM>::template Reference<TARG
ET_INDEX>::type
get(CoupledScanOrderIterator<N, HANDLES, DIM> & i)
{ {
// reverse the order to get the desired index order return vigra::get<TARGET_INDEX>(*i);
typedef typename MakeTypeList<T5, T4, T3, T2, T1>::type TypeList; }
typedef typename ComposeCoupledHandle<N, TypeList>::type type;
};
template <unsigned int N, class T1, class T2, class T3, class T4, class T5> template <unsigned int TARGET_INDEX,
struct CoupledHandleType<N, Multiband<T1>, T2, T3, T4, T5> unsigned int N,
class HANDLES,
int DIM>
typename CoupledScanOrderIterator<N, HANDLES, DIM>::template ConstReference
<TARGET_INDEX>::type
get(CoupledScanOrderIterator<N, HANDLES, DIM> const & i)
{ {
// reverse the order to get the desired index order return vigra::get<TARGET_INDEX>(*i);
typedef typename MakeTypeList<T5, T4, T3, T2, Multiband<T1> >::type Typ }
eList;
typedef typename ComposeCoupledHandle<N-1, TypeList>::type type;
};
/** Helper class to easliy get the type of a CoupledScanOrderIterator (and corresponding CoupledHandle) for up to five arrays of dimension N with elem ent types T1,...,T5. /** Helper class to easliy get the type of a CoupledScanOrderIterator (and corresponding CoupledHandle) for up to five arrays of dimension N with elem ent types T1,...,T5.
*/ */
template <unsigned int N, class T1=void, class T2=void, class T3=void, clas s T4=void, class T5=void> template <unsigned int N, class T1=void, class T2=void, class T3=void, clas s T4=void, class T5=void>
struct CoupledIteratorType struct CoupledIteratorType
{ {
/** Type of the CoupledHandle.*/ /** Type of the CoupledHandle.*/
typedef typename CoupledHandleType<N, T1, T2, T3, T4, T5>::type HandleT ype; typedef typename CoupledHandleType<N, T1, T2, T3, T4, T5>::type HandleT ype;
/** Type of the CoupledScanOrderIterator.*/ /** Type of the CoupledScanOrderIterator.*/
typedef CoupledScanOrderIterator<HandleType::dimensions, HandleType> ty typedef CoupledScanOrderIterator<HandleType::dimensions, HandleType> It
pe; eratorType;
typedef IteratorType ty
pe;
}; };
/** Alias for \ref vigra::CoupledIteratorType (maybe easier to remember).
*/
template <unsigned int N, class T1=void, class T2=void, class T3=void, clas
s T4=void, class T5=void>
struct CoupledArrays
: public CoupledIteratorType<N, T1, T2, T3, T4, T5>
{};
/** Returns a CoupledScanOrderIterator from shape to iterate over coordinat es. /** Returns a CoupledScanOrderIterator from shape to iterate over coordinat es.
*/ */
template <int N> template <int N>
typename CoupledIteratorType<N>::type typename CoupledIteratorType<N>::type
createCoupledIterator(TinyVector<MultiArrayIndex, N> const & shape) createCoupledIterator(TinyVector<MultiArrayIndex, N> const & shape)
{ {
typedef typename CoupledHandleType<N>::type P0; typedef typename CoupledHandleType<N>::type P0;
typedef CoupledScanOrderIterator<N, P0> IteratorType; typedef CoupledScanOrderIterator<N, P0> IteratorType;
return IteratorType(P0(shape)); return IteratorType(P0(shape));
skipping to change at line 1189 skipping to change at line 855
typedef CoupledScanOrderIterator<P1::dimensions, P5> IteratorType; typedef CoupledScanOrderIterator<P1::dimensions, P5> IteratorType;
return IteratorType(P5(m5, return IteratorType(P5(m5,
P4(m4, P4(m4,
P3(m3, P3(m3,
P2(m2, P2(m2,
P1(m1, P1(m1,
P0(m1.shape()))))))); P0(m1.shape())))))));
} }
template <unsigned int N, class A, class B>
CoupledScanOrderIterator<N, typename ZipCoupledHandles<A, B>::type>
zip(CoupledScanOrderIterator<N, A> const & a, CoupledScanOrderIterator<N, B
> const & b)
{
vigra_precondition(a.shape() == b.shape() && a.scanOrderIndex() == b.sc
anOrderIndex(),
"zip(CoupledScanOrderIterator): iterators must have identical shap
e and position.");
typedef typename ZipCoupledHandles<A, B>::type Handle;
typedef CoupledScanOrderIterator<N, Handle> IteratorType;
return IteratorType(ZipCoupledHandles<A, B>::construct(*a, *b));
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* MULTI_ITERATOR_COUPLED_HXX_ */ namespace std {
template <unsigned int N, class HANDLES, int DIMENSION>
ostream & operator<<(ostream & o, vigra::CoupledScanOrderIterator<N, HANDLE
S, DIMENSION> const & i)
{
o << i.point();
return o;
}
} // namespace std
#endif /* MULTI_ITERATOR_COUPLED_HXX */
 End of changes. 111 change blocks. 
647 lines changed or deleted 309 lines changed or added


 multi_localminmax.hxx   multi_localminmax.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 1998-2010 by Ullrich Koethe */ /* Copyright 2012-2013 by Ullrich Koethe */
/* */ /* */
/* This file is part of the VIGRA computer vision library. */ /* This file is part of the VIGRA computer vision library. */
/* The VIGRA Website is */ /* The VIGRA Website is */
/* http://hci.iwr.uni-heidelberg.de/vigra/ */ /* http://hci.iwr.uni-heidelberg.de/vigra/ */
/* Please direct questions, bug reports, and contributions to */ /* Please direct questions, bug reports, and contributions to */
/* ullrich.koethe@iwr.uni-heidelberg.de or */ /* ullrich.koethe@iwr.uni-heidelberg.de or */
/* vigra@informatik.uni-hamburg.de */ /* vigra@informatik.uni-hamburg.de */
/* */ /* */
/* Permission is hereby granted, free of charge, to any person */ /* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */ /* obtaining a copy of this software and associated documentation */
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MULTI_LOCALMINMAX_HXX #ifndef VIGRA_MULTI_LOCALMINMAX_HXX
#define VIGRA_MULTI_LOCALMINMAX_HXX #define VIGRA_MULTI_LOCALMINMAX_HXX
#include <vector> #include <vector>
#include <functional> #include <functional>
#include "multi_array.hxx" #include "multi_array.hxx"
#include "localminmax.hxx" #include "localminmax.hxx"
#if 0 #include "multi_gridgraph.hxx"
#include "multi_labeling.hxx"
#include "metaprogramming.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail_local_minima{
template<class G>
struct NodeAtBorder{
template<class NODE_ITER>
static bool atBorder(const NODE_ITER & node ){
return false;
}
};
// direct neighborhood template<unsigned int DIM,class DTAG>
template <unsigned int M> struct NodeAtBorder< GridGraph<DIM,DTAG> >{
struct IsLocalExtremum2 template<class NODE_ITER>
{ static bool atBorder(const NODE_ITER & node ){
template <class T, class Shape, class Compare> return node.atBorder();
static bool exec(T * v, Shape const & stride, Compare const & compare) }
{ };
return compare(*v, *(v-stride[M])) &&
compare(*v, *(v+stride[M])) &&
IsLocalExtremum2<M-1>::exec(v, stride, compare);
}
template <class Shape, class T, class Compare>
static bool execAtBorder(Shape const & point, Shape const & shape,
T * v, Shape const & stride, Compare const & compare)
{
return (point[M] > 0 && compare(*v, *(v-stride[M]))) &&
(point[M] < shape[M]-1 && compare(*v, *(v+stride[M]))) &&
IsLocalExtremum2<M-1>::exec(point, shape, v, stride, compar
e);
}
}; };
template <> namespace boost_graph {
struct IsLocalExtremum2<0>
{
template <class T, class Shape, class Compare>
static bool exec(T * v, Shape const & stride, Compare const & compare)
{
return compare(*v, *(v-stride[0])) && compare(*v, *(v+stride[0]));
}
template <class Shape, class T, class Compare>
static bool execAtBorder(Shape const & point, Shape const & shape,
T * v, Shape const & stride, Compare const & compare)
{
return (point[0] > 0 && compare(*v, *(v-stride[0]))) &&
(point[0] < shape[0]-1 && compare(*v, *(v+stride[0])));
}
};
// indirect neighborhood // Attempt without LValue propmaps, using only the free functions
template <unsigned int M> // to access ReadablePropertyMap (input) and WritablePropertyMap (label)
struct IsLocalExtremum3 template <class Graph, class T1Map, class T2Map, class Compare>
unsigned int
localMinMaxGraph(Graph const &g,
T1Map const &src,
T2Map &dest,
typename property_traits<T2Map>::value_type marker,
typename property_traits<T1Map const>::value_type threshol
d,
Compare const &compare,
bool allowAtBorder = true)
{ {
template <class T, class Shape, class Compare> typedef typename graph_traits<Graph>::vertex_iterator graph_scanner;
static bool exec(T * v, Shape const & stride, Compare const & compare) typedef typename graph_traits<Graph>::adjacency_iterator neighbor_itera
{ tor;
return exec(v, v, stride, compare, true);
}
template <class T, class Shape, class Compare> typedef typename property_traits<T1Map const>::value_type T1;
static bool exec(T * v, T * u, Shape const & stride,
Compare const & compare, bool isCenter)
{
return IsLocalExtremum3<M-1>::exec(v, u-stride[M], stride, compare,
false) &&
IsLocalExtremum3<M-1>::exec(v, u, stride, compare, isCenter)
&&
IsLocalExtremum3<M-1>::exec(v, u+stride[M], stride, compare,
false);
}
template <class Shape, class T, class Compare> graph_scanner node, srcend;
static bool execAtBorder(Shape const & point, Shape const & shape, neighbor_iterator arc, nbend;
T * v, Shape const & stride, Compare const & compare)
{
return execAtBorder(point, shape, v, v, stride, compare, true);
}
template <class Shape, class T, class Compare> unsigned int count = 0;
static bool execAtBorder(Shape const & point, Shape const & shape, tie(node, srcend) = vertices(g);
T * v, T * u, Shape const & stride, for (; node != srcend; ++node)
Compare const & compare, bool isCenter)
{ {
return (point[M] > 0 && IsLocalExtremum3<M-1>::exec(v, u-stride[M], const T1 current = get(src, *node);
stride, compare, false)) &&
IsLocalExtremum3<M-1>::exec(point, shape, v, u, stride, com
pare, isCenter) &&
(point[M] < shape[M]-1 && IsLocalExtremum3<M-1>::exec(v, u+
stride[M], stride, compare, false));
}
};
template <> if (!compare(current, threshold))
struct IsLocalExtremum3<0> continue;
{
template <class T, class Shape, class Compare>
static bool exec(T * v, Shape const & stride, Compare const & compare)
{
return compare(*v, *(v-stride[0])) && compare(*v, *(v+stride[0]));
}
template <class T, class Shape, class Compare> if(!allowAtBorder && node.atBorder())
static bool exec(T * v, T * u, Shape const & stride, continue;
Compare const & compare, bool isCenter)
{
return compare(*v, *(u-stride[0])) &&
(!isCenter && compare(*v, *u)) &&
compare(*v, *(u+stride[0]));
}
template <class Shape, class T, class Compare> tie(arc, nbend) = adjacent_vertices(*node, g);
static bool execAtBorder(Shape const & point, Shape const & shape, for (;arc != nbend; ++arc)
T * v, Shape const & stride, Compare const & compare) if (!compare(current, get(src, *arc)))
{ break;
return (point[0] > 0 && compare(*v, *(v-stride[0]))) &&
(point[0] < shape[0]-1 && compare(*v, *(v+stride[0])));
}
template <class Shape, class T, class Compare> if (arc == nbend)
static bool execAtBorder(Shape const & point, Shape const & shape, {
T * v, T * u, Shape const & stride, put(dest, *node, marker);
Compare const & compare, bool isCenter) ++count;
{ }
return (point[M] > 0 && compare(*v, *(u-stride[0]))) &&
(!isCenter && compare(*v, *u)) &&
(point[M] < shape[M]-1 && compare(*v, *(u+stride[0])));
} }
}; return count;
}
template <unsigned int N, class T1, class C1, class T2, class C2, class Com } // namespace boost_graph
pare>
void
localMinMax(MultiArrayView<N, T1, C1> src,
MultiArrayView<N, T2, C2> dest,
T2 marker, unsigned int neighborhood,
T1 threshold,
Compare compare,
bool allowExtremaAtBorder = false)
{
typedef typename MultiArrayShape<N>::type Shape;
typedef MultiCoordinateNavigator<N> Navigator;
Shape shape = src.shape(), namespace lemon_graph {
unit = Shape(MultiArrayIndex(1));
vigra_precondition(shape == dest.shape(), template <class Graph, class T1Map, class T2Map, class Compare>
"localMinMax(): Shape mismatch between input and output."); unsigned int
vigra_precondition(neighborhood == 2*N || neighborhood == pow(3, N) - 1 localMinMaxGraph(Graph const &g,
, T1Map const &src,
"localMinMax(): Invalid neighborhood."); T2Map &dest,
typename T2Map::value_type marker,
typename T1Map::value_type threshold,
Compare const &compare,
bool allowAtBorder = true)
{
typedef typename Graph::NodeIt graph_scanner;
typedef typename Graph::OutArcIt neighbor_iterator;
if(allowExtremaAtBorder) unsigned int count = 0;
for (graph_scanner node(g); node != INVALID; ++node)
{ {
for(unsigned int d=0; d<N; ++d) typename T1Map::value_type current = src[*node];
{
Navigator nav(shape, d);
for(; nav.hasMore(); ++nav)
{
Shape i = nav.begin();
for(; i[d] < shape[d]; i[d] += shape[d]-1) if (!compare(current, threshold))
{ continue;
if(!compare(src[i], threshold))
continue;
if(neighborhood == 2*N)
{
if(IsLocalExtremum2<N>::execAtBorder(i, shape, &src
[i],
src.stride(),
compare))
dest[i] = marker;
}
else
{
if(IsLocalExtremum3<N>::execAtBorder(i, shape, &src
[i],
src.stride(),
compare))
dest[i] = marker;
}
}
}
}
}
src = src.subarray(unit, shape - unit); if(!allowAtBorder && vigra::detail_local_minima::NodeAtBorder<Graph
dest = dest.subarray(unit, shape - unit); >::atBorder(node))
shape = src.shape(); continue;
Navigator nav(shape, 0); neighbor_iterator arc(g, *node);
for(; nav.hasMore(); ++nav) for (; arc != INVALID; ++arc)
{ if (!compare(current, src[g.target(*arc)]))
Shape i = nav.begin(); break;
for(; i[0] < shape[0]; ++i[0]) if (arc == INVALID)
{ {
if(!compare(src[i], threshold)) dest[*node] = marker;
continue; ++count;
if(neighborhood == 2*N)
{
if(IsLocalExtremum2<N>::exec(&src[i], src.stride(), compare
))
dest[i] = marker;
}
else
{
if(IsLocalExtremum3<N>::exec(&src[i], src.stride(), compare
))
dest[i] = marker;
}
} }
} }
return count;
} }
template <class T1, class C1, class T2, class C2, template <class Graph, class T1Map, class T2Map, class Compare, class Equal
class Neighborhood, class Compare, class Equal> >
void unsigned int
extendLocalMinMax(MultiArrayView<3, T1, C1> src, extendedLocalMinMaxGraph(Graph const &g,
MultiArrayView<3, T2, C2> dest, T1Map const &src,
T2 marker, T2Map &dest,
Neighborhood neighborhood, typename T2Map::value_type marker,
Compare compare, Equal equal, typename T1Map::value_type threshold,
T1 threshold, Compare const &compare,
bool allowExtremaAtBorder = false) Equal const &equal,
bool allowAtBorder = true)
{ {
typedef typename MultiArrayView<3, T1, C1>::traverser SrcIterator; typename Graph::template NodeMap<unsigned int> regions(g);
typedef typename MultiArrayView<3, T2, C2>::traverser DestIterator;
typedef typename MultiArray<3, int>::traverser LabelIterator;
typedef MultiArrayShape<3>::type Shape;
Shape shape = src.shape();
MultiArrayIndex w = shape[0], h = shape[1], d = shape[2];
vigra_precondition(shape == dest.shape(),
"extendLocalMinMax(): Shape mismatch between input and output.");
MultiArray<3, int> labels(shape); int max_region_label = labelGraph(g, src, regions, equal);
int number_of_regions = labelVolume(srcMultiArrayRange(src), destMultiA
rray(labels),
neighborhood, equal);
// assume that a region is a extremum until the opposite is proved // assume that a region is a extremum until the opposite is proved
ArrayVector<unsigned char> isExtremum(number_of_regions+1, (unsigned ch std::vector<unsigned char> isExtremum(max_region_label+1, (unsigned cha
ar)1); r)1);
typedef typename Graph::NodeIt graph_scanner;
typedef typename Graph::OutArcIt neighbor_iterator;
SrcIterator zs = src.traverser_begin(); unsigned int count = max_region_label;
LabelIterator zl = labels.traverser_begin(); for (graph_scanner node(g); node != INVALID; ++node)
for(MultiArrayIndex z = 0; z != d; ++z, ++zs.dim2(), ++zl.dim2())
{ {
SrcIterator ys(zs); unsigned int label = regions[*node];
LabelIterator yl(zl);
for(MultiArrayIndex y = 0; y != h; ++y, ++ys.dim1(), ++yl.dim1()) if(!isExtremum[label])
{ continue;
SrcIterator xs(ys);
LabelIterator xl(yl);
for(MultiArrayIndex x = 0; x != w; ++x, ++xs.dim0(), ++xl.dim0( typename T1Map::value_type current = src[*node];
))
{
int lab = *xl;
T1 v = *xs;
if(isExtremum[lab] == 0) if (!compare(current, threshold) ||
continue; (!allowAtBorder && vigra::detail_local_minima::NodeAtBorder<Gr
aph>::atBorder(node) ))
if(!compare(v, threshold)) {
{ isExtremum[label] = 0;
// mark all regions that don't exceed the threshold as --count;
non-extremum continue;
isExtremum[lab] = 0;
continue;
}
AtVolumeBorder atBorder = isAtVolumeBorder(x, y, z, w, h, d
);
if(atBorder == NotAtBorder)
{
NeighborhoodCirculator<SrcIterator, Neighborhood> cs(xs
);
NeighborhoodCirculator<LabelIterator, Neighborhood> cl(
xl);
for(i=0; i<Neighborhood::DirectionCount; ++i, ++cs, ++c
l)
{
if(lab != *cl && compare(*cs,v))
{
isExtremum[lab] = 0;
break;
}
}
}
else
{
if(allowExtremaAtBorder)
{
RestrictedNeighborhoodCirculator<SrcIterator, Neigh
borhood>
cs(xs, a
tBorder), scend(cs);
do
{
if(lab != *(xl+cs.diff()) && compare(cs,v))
{
isExtremum[lab] = 0;
break;
}
}
while(++cs != scend);
}
else
{
isExtremum[lab] = 0;
}
}
}
} }
}
zl = labels.traverser_begin(); for (neighbor_iterator arc(g, *node); arc != INVALID; ++arc)
DestIterator zd = dest.traverser_begin();
for(MultiArrayIndex z = 0; z != d; ++z, ++zl.dim2(), ++zd.dim2())
{
LabelIterator yl(zl);
DestIterator yd(zd);
for(MultiArrayIndex y = 0; y != h; ++y, ++yl.dim1(), ++yd.dim1())
{ {
LabelIterator xl(yl); if (label != regions[g.target(*arc)] && compare(src[g.target(*a
DestIterator xd(yd); rc)], current))
for(MultiArrayIndex x = 0; x != w; ++x, ++xl.dim0(), ++xd.dim0(
))
{ {
if(isExtremum[*xl]) isExtremum[label] = 0;
*xd = marker; --count;
break;
} }
} }
} }
for (graph_scanner node(g); node != INVALID; ++node)
{
if(isExtremum[regions[*node]])
dest[*node] = marker;
}
return count;
} }
} // namespace detail } // namespace lemon_graph
/********************************************************/
/* */
/* localMinima */
/* */
/********************************************************/
// documentation is in localminmax.hxx template <unsigned int N, class T1, class C1,
template <unsigned int N, class T1, class C1, class T2, class C2> class T2, class C2,
void class Compare,
localMinima(MultiArrayView<N, T1, C1> src, class EqualityFunctor>
unsigned int
localMinMax(MultiArrayView<N, T1, C1> const & src,
MultiArrayView<N, T2, C2> dest, MultiArrayView<N, T2, C2> dest,
T1 threshold,
Compare const & compare,
EqualityFunctor const & equal,
LocalMinmaxOptions const & options = LocalMinmaxOptions()) LocalMinmaxOptions const & options = LocalMinmaxOptions())
{ {
T1 threshold = options.use_threshold vigra_precondition(src.shape() == dest.shape(),
? std::min(NumericTraits<T1>::max(), (T1)options "localMinMax(): shape mismatch between input and output.");
.thresh)
: NumericTraits<T1>::max(); NeighborhoodType neighborhood = DirectNeighborhood;
T2 marker = (T2)options.marker;
vigra_precondition(!options.allow_plateaus, if(options.neigh == 0 || options.neigh == 2*N)
"localMinima(): Option 'allowPlateaus' is not implemented for arbit neighborhood = DirectNeighborhood;
rary dimensions,\n" else if(options.neigh == 1 || options.neigh == MetaPow<3, N>::value - 1
" use extendedLocalMinima() for 2D and 3D problems.") )
; neighborhood = IndirectNeighborhood;
else
if(options.neigh == 0) vigra_precondition(false,
options.neigh = 2*N; "localMinMax(): option object specifies invalid neighborhood ty
if(options.neigh == 1) pe.");
options.neigh = pow(3, N) - 1;
T2 marker = (T2)options.marker;
detail::localMinMax(src, dest, marker, options.neigh, GridGraph<N, undirected_tag> graph(src.shape(), neighborhood);
threshold, std::less<T1>(), options.allow_at_border if(options.allow_plateaus)
); return lemon_graph::extendedLocalMinMaxGraph(graph, src, dest, mark
er, threshold,
compare, equal, options.allow_a
t_border);
else
return lemon_graph::localMinMaxGraph(graph, src, dest, marker, thre
shold,
compare, options.allow_at_bord
er);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* localMaxima */ /* localMinima */
/* */ /* */
/********************************************************/ /********************************************************/
// documentation is in localminmax.hxx // documentation is in localminmax.hxx
template <unsigned int N, class T1, class C1, class T2, class C2> template <unsigned int N, class T1, class C1, class T2, class C2>
void inline unsigned int
localMaxima(MultiArrayView<N, T1, C1> src, localMinima(MultiArrayView<N, T1, C1> const & src,
MultiArrayView<N, T2, C2> dest, MultiArrayView<N, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions()) LocalMinmaxOptions const & options = LocalMinmaxOptions())
{ {
T1 threshold = options.use_threshold T1 threshold = options.use_threshold
? std::max(NumericTraits<T1>::min(), (T1)options ? std::min(NumericTraits<T1>::max(), (T1)options
.thresh) .thresh)
: NumericTraits<T1>::min(); : NumericTraits<T1>::max();
T2 marker = (T2)options.marker; return localMinMax(src, dest, threshold, std::less<T1>(), std::equal_to
<T1>(), options);
vigra_precondition(!options.allow_plateaus,
"localMaxima(): Option 'allowPlateaus' is not implemented for arbit
rary dimensions,\n"
" use extendedLocalMinima() for 2D and 3D problems.")
;
if(options.neigh == 0)
options.neigh = 2*N;
if(options.neigh == 1)
options.neigh = pow(3, N) - 1;
detail::localMinMax(src, dest, marker, options.neigh,
threshold, std::greater<T1>(), options.allow_at_bor
der);
} }
/************************************************************************** template <unsigned int N, class T1, class S1,
/ class T2, class S2,
class EqualityFunctor>
/********************************************************/ inline unsigned int
/* */ extendedLocalMinima(MultiArrayView<N, T1, S1> const & src,
/* extendedLocalMinima */ MultiArrayView<N, T2, S2> dest,
/* */ EqualityFunctor const & equal,
/********************************************************/ LocalMinmaxOptions options = LocalMinmaxOptions())
// documentation is in localminmax.hxx
template <class T1, class C1, class T2, class C2,
class Neighborhood, class EqualityFunctor>
inline void
extendedLocalMinima(MultiArrayView<3, T1, C1> src,
MultiArrayView<3, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions
())
{ {
options.allowPlateaus();
T1 threshold = options.use_threshold T1 threshold = options.use_threshold
? std::min(NumericTraits<T1>::max(), (T1)options .thresh) ? std::min(NumericTraits<T1>::max(), (T1)options .thresh)
: NumericTraits<T1>::max(); : NumericTraits<T1>::max();
T2 marker = (T2)options.marker; return localMinMax(src, dest, threshold, std::less<T1>(), equal, option
s);
if(options.neigh == 0 || options.neigh == 6)
{
detail::extendedLocalMinMax(src, dest, marker, NeighborCode3DSix(),
threshold, std::less<T1>(), std::equal_
to<T1>(),
options.allow_at_border);
}
else if(options.neigh == 1 || options.neigh == 26)
{
detail::extendedLocalMinMax(src, dest, marker, NeighborCode3DTwenty
Six(),
threshold, std::less<T1>(), std::equal_
to<T1>(),
options.allow_at_border);
}
else
vigra_precondition(false,
"extendedLocalMinima(): Invalid neighborhood.");
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMaxima */ /* localMaxima */
/* */ /* */
/********************************************************/ /********************************************************/
// documentation is in localminmax.hxx // documentation is in localminmax.hxx
template <class T1, class C1, class T2, class C2, template <unsigned int N, class T1, class C1, class T2, class C2>
class Neighborhood, class EqualityFunctor> inline unsigned int
inline void localMaxima(MultiArrayView<N, T1, C1> const & src,
extendedLocalMaxima(MultiArrayView<3, T1, C1> src, MultiArrayView<N, T2, C2> dest,
MultiArrayView<3, T2, C2> dest, LocalMinmaxOptions const & options = LocalMinmaxOptions())
LocalMinmaxOptions const & options = LocalMinmaxOptions
())
{ {
T1 threshold = options.use_threshold T1 threshold = options.use_threshold
? std::max(NumericTraits<T1>::min(), (T1)options .thresh) ? std::max(NumericTraits<T1>::min(), (T1)options .thresh)
: NumericTraits<T1>::min(); : NumericTraits<T1>::min();
T2 marker = (T2)options.marker; return localMinMax(src, dest, threshold, std::greater<T1>(), std::equal
_to<T1>(), options);
}
if(options.neigh == 0 || options.neigh == 6) template <unsigned int N, class T1, class S1,
{ class T2, class S2,
detail::extendedLocalMinMax(src, dest, marker, NeighborCode3DSix(), class EqualityFunctor>
threshold, std::greater<T1>(), std::equ inline unsigned int
al_to<T1>(), extendedLocalMaxima(MultiArrayView<N, T1, S1> const & src,
options.allow_at_border); MultiArrayView<N, T2, S2> dest,
} EqualityFunctor const & equal,
else if(options.neigh == 1 || options.neigh == 26) LocalMinmaxOptions options = LocalMinmaxOptions())
{ {
detail::extendedLocalMinMax(src, dest, marker, NeighborCode3DTwenty options.allowPlateaus();
Six(), T1 threshold = options.use_threshold
threshold, std::greater<T1>(), std::equ ? std::max(NumericTraits<T1>::min(), (T1)options
al_to<T1>(), .thresh)
options.allow_at_border); : NumericTraits<T1>::min();
} return localMinMax(src, dest, threshold, std::greater<T1>(), equal, opt
else ions);
vigra_precondition(false,
"extendedLocalMaxima(): Invalid neighborhood.");
} }
} // namespace vigra } // namespace vigra
#endif
#endif // VIGRA_MULTI_LOCALMINMAX_HXX #endif // VIGRA_MULTI_LOCALMINMAX_HXX
 End of changes. 60 change blocks. 
411 lines changed or deleted 211 lines changed or added


 multi_math.hxx   multi_math.hxx 
skipping to change at line 347 skipping to change at line 347
result_type operator*() const result_type operator*() const
{ {
return f_(*o_); return f_(*o_);
} }
O o_; O o_;
F f_; F f_;
}; };
#define VIGRA_MULTIMATH_UNARY_OPERATOR(NAME, FCT, OPNAME, RESTYPE) \ #define VIGRA_MULTIMATH_UNARY_OPERATOR(NAME, FCT, OPNAME, RESTYPE) \
namespace detail { \ namespace math_detail { \
struct NAME \ struct NAME \
{ \ { \
template <class T> \ template <class T> \
struct Result \ struct Result \
{ \ { \
typedef RESTYPE type; \ typedef RESTYPE type; \
}; \ }; \
\ \
template <class T> \ template <class T> \
typename Result<T>::type \ typename Result<T>::type \
operator()(T const & t) const \ operator()(T const & t) const \
{ \ { \
return FCT(t); \ return FCT(t); \
} \ } \
}; \ }; \
} \ } \
\ \
template <unsigned int N, class T, class C> \ template <unsigned int N, class T, class C> \
MultiMathOperand<MultiMathUnaryOperator<MultiMathOperand<MultiArrayView<N, T, C> >, \ MultiMathOperand<MultiMathUnaryOperator<MultiMathOperand<MultiArrayView<N, T, C> >, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiArrayView<N, T, C> const & v) \ OPNAME(MultiArrayView<N, T, C> const & v) \
{ \ { \
typedef MultiMathOperand<MultiArrayView<N, T, C> > O; \ typedef MultiMathOperand<MultiArrayView<N, T, C> > O; \
typedef MultiMathUnaryOperator<O, detail::NAME> OP; \ typedef MultiMathUnaryOperator<O, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v)); \ return MultiMathOperand<OP>(OP(v)); \
} \ } \
\ \
template <unsigned int N, class T, class A> \ template <unsigned int N, class T, class A> \
MultiMathOperand<MultiMathUnaryOperator<MultiMathOperand<MultiArray<N, T, A > >, \ MultiMathOperand<MultiMathUnaryOperator<MultiMathOperand<MultiArray<N, T, A > >, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiArray<N, T, A> const & v) \ OPNAME(MultiArray<N, T, A> const & v) \
{ \ { \
typedef MultiMathOperand<MultiArray<N, T, A> > O; \ typedef MultiMathOperand<MultiArray<N, T, A> > O; \
typedef MultiMathUnaryOperator<O, detail::NAME> OP; \ typedef MultiMathUnaryOperator<O, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v)); \ return MultiMathOperand<OP>(OP(v)); \
} \ } \
\ \
template <class T> \ template <class T> \
MultiMathOperand<MultiMathUnaryOperator<MultiMathOperand<T>, \ MultiMathOperand<MultiMathUnaryOperator<MultiMathOperand<T>, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiMathOperand<T> const & v) \ OPNAME(MultiMathOperand<T> const & v) \
{ \ { \
typedef MultiMathOperand<T> O; \ typedef MultiMathOperand<T> O; \
typedef MultiMathUnaryOperator<O, detail::NAME> OP; \ typedef MultiMathUnaryOperator<O, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v)); \ return MultiMathOperand<OP>(OP(v)); \
} }
#define VIGRA_REALPROMOTE typename NumericTraits<T>::RealPromote #define VIGRA_REALPROMOTE typename NumericTraits<T>::RealPromote
#ifndef DOXYGEN // doxygen gets confused by these macros #ifndef DOXYGEN // doxygen gets confused by these macros
VIGRA_MULTIMATH_UNARY_OPERATOR(Negate, -, operator-, T) VIGRA_MULTIMATH_UNARY_OPERATOR(Negate, -, operator-, T)
VIGRA_MULTIMATH_UNARY_OPERATOR(Not, !, operator!, T) VIGRA_MULTIMATH_UNARY_OPERATOR(Not, !, operator!, T)
VIGRA_MULTIMATH_UNARY_OPERATOR(BitwiseNot, ~, operator~, T) VIGRA_MULTIMATH_UNARY_OPERATOR(BitwiseNot, ~, operator~, T)
skipping to change at line 509 skipping to change at line 509
F f_; F f_;
}; };
// In the sequel, the nested type 'MultiMathOperand<T>::AllowOverload' // In the sequel, the nested type 'MultiMathOperand<T>::AllowOverload'
// ensures that template functions only participate in overload // ensures that template functions only participate in overload
// resolution when this type is defined, i.e. when T is a number // resolution when this type is defined, i.e. when T is a number
// or array type. It thus prevents 'ambiguous overload' errors. // or array type. It thus prevents 'ambiguous overload' errors.
// //
#define VIGRA_MULTIMATH_BINARY_OPERATOR(NAME, FCT, OPNAME, SEP, RESTYPE) \ #define VIGRA_MULTIMATH_BINARY_OPERATOR(NAME, FCT, OPNAME, SEP, RESTYPE) \
\ \
namespace detail { \ namespace math_detail { \
struct NAME \ struct NAME \
{ \ { \
template <class T1, class T2> \ template <class T1, class T2> \
struct Result \ struct Result \
{ \ { \
typedef RESTYPE type; \ typedef RESTYPE type; \
}; \ }; \
\ \
template <class T1, class T2> \ template <class T1, class T2> \
typename Result<T1, T2>::type \ typename Result<T1, T2>::type \
operator()(T1 const & t1, T2 const & t2) const \ operator()(T1 const & t1, T2 const & t2) const \
{ \ { \
return FCT(t1 SEP t2); \ return FCT(t1 SEP t2); \
} \ } \
}; \ }; \
} \ } \
\ \
template <unsigned int N, class T1, class A1, class T2, class A2> \ template <unsigned int N, class T1, class A1, class T2, class A2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1> >, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1> >, \
MultiMathOperand<MultiArrayView<N, T2> >, \ MultiMathOperand<MultiArrayView<N, T2> >, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiArray<N, T1, A1> const & v1, MultiArray<N, T2, A2> const & v2) \ OPNAME(MultiArray<N, T1, A1> const & v1, MultiArray<N, T2, A2> const & v2) \
{ \ { \
typedef MultiMathOperand<MultiArrayView<N, T1> > O1; \ typedef MultiMathOperand<MultiArrayView<N, T1> > O1; \
typedef MultiMathOperand<MultiArrayView<N, T2> > O2; \ typedef MultiMathOperand<MultiArrayView<N, T2> > O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP((MultiArrayView<N, T1> const &)v1, (Mult iArrayView<N, T2> const &)v2)); \ return MultiMathOperand<OP>(OP((MultiArrayView<N, T1> const &)v1, (Mult iArrayView<N, T2> const &)v2)); \
} \ } \
\ \
template <unsigned int N, class T1, class C1, class T2, class C2> \ template <unsigned int N, class T1, class C1, class T2, class C2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1, C1> >, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1, C1> >, \
MultiMathOperand<MultiArrayView<N, T2, C2> >, \ MultiMathOperand<MultiArrayView<N, T2, C2> >, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiArrayView<N, T1, C1> const & v1, MultiArrayView<N, T2, C2> cons t & v2) \ OPNAME(MultiArrayView<N, T1, C1> const & v1, MultiArrayView<N, T2, C2> cons t & v2) \
{ \ { \
typedef MultiMathOperand<MultiArrayView<N, T1, C1> > O1; \ typedef MultiMathOperand<MultiArrayView<N, T1, C1> > O1; \
typedef MultiMathOperand<MultiArrayView<N, T2, C2> > O2; \ typedef MultiMathOperand<MultiArrayView<N, T2, C2> > O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <unsigned int N, class T1, class T2, class C2> \ template <unsigned int N, class T1, class T2, class C2> \
MultiMathOperand<MultiMathBinaryOperator<typename MultiMathOperand<T1>::All owOverload, \ MultiMathOperand<MultiMathBinaryOperator<typename MultiMathOperand<T1>::All owOverload, \
MultiMathOperand<MultiArrayView<N, T2, C2> >, \ MultiMathOperand<MultiArrayView<N, T2, C2> >, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(T1 const & v1, MultiArrayView<N, T2, C2> const & v2) \ OPNAME(T1 const & v1, MultiArrayView<N, T2, C2> const & v2) \
{ \ { \
typedef MultiMathOperand<T1> O1; \ typedef MultiMathOperand<T1> O1; \
typedef MultiMathOperand<MultiArrayView<N, T2, C2> > O2; \ typedef MultiMathOperand<MultiArrayView<N, T2, C2> > O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <unsigned int N, class T1, class C1, class T2> \ template <unsigned int N, class T1, class C1, class T2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1, C1> >, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1, C1> >, \
typename MultiMathOperand<T2>::All owOverload, \ typename MultiMathOperand<T2>::All owOverload, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiArrayView<N, T1, C1> const & v1, T2 const & v2) \ OPNAME(MultiArrayView<N, T1, C1> const & v1, T2 const & v2) \
{ \ { \
typedef MultiMathOperand<MultiArrayView<N, T1, C1> > O1; \ typedef MultiMathOperand<MultiArrayView<N, T1, C1> > O1; \
typedef MultiMathOperand<T2> O2; \ typedef MultiMathOperand<T2> O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <unsigned int N, class T1, class T2, class C2> \ template <unsigned int N, class T1, class T2, class C2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<T1>, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<T1>, \
MultiMathOperand<MultiArrayView<N, T2, C2> >, \ MultiMathOperand<MultiArrayView<N, T2, C2> >, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiMathOperand<T1> const & v1, MultiArrayView<N, T2, C2> const & v 2) \ OPNAME(MultiMathOperand<T1> const & v1, MultiArrayView<N, T2, C2> const & v 2) \
{ \ { \
typedef MultiMathOperand<T1> O1; \ typedef MultiMathOperand<T1> O1; \
typedef MultiMathOperand<MultiArrayView<N, T2, C2> > O2; \ typedef MultiMathOperand<MultiArrayView<N, T2, C2> > O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <unsigned int N, class T1, class C1, class T2> \ template <unsigned int N, class T1, class C1, class T2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1, C1> >, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<MultiArrayView<N, T1, C1> >, \
MultiMathOperand<T2>, \ MultiMathOperand<T2>, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiArrayView<N, T1, C1> const & v1, MultiMathOperand<T2> const & v 2) \ OPNAME(MultiArrayView<N, T1, C1> const & v1, MultiMathOperand<T2> const & v 2) \
{ \ { \
typedef MultiMathOperand<MultiArrayView<N, T1, C1> > O1; \ typedef MultiMathOperand<MultiArrayView<N, T1, C1> > O1; \
typedef MultiMathOperand<T2> O2; \ typedef MultiMathOperand<T2> O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <class T1, class T2> \ template <class T1, class T2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<T1>, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<T1>, \
MultiMathOperand<T2>, \ MultiMathOperand<T2>, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiMathOperand<T1> const & v1, MultiMathOperand<T2> const & v2) \ OPNAME(MultiMathOperand<T1> const & v1, MultiMathOperand<T2> const & v2) \
{ \ { \
typedef MultiMathOperand<T1> O1; \ typedef MultiMathOperand<T1> O1; \
typedef MultiMathOperand<T2> O2; \ typedef MultiMathOperand<T2> O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <class T1, class T2> \ template <class T1, class T2> \
MultiMathOperand<MultiMathBinaryOperator<typename MultiMathOperand<T1>::All owOverload, \ MultiMathOperand<MultiMathBinaryOperator<typename MultiMathOperand<T1>::All owOverload, \
MultiMathOperand<T2>, \ MultiMathOperand<T2>, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(T1 const & v1, MultiMathOperand<T2> const & v2) \ OPNAME(T1 const & v1, MultiMathOperand<T2> const & v2) \
{ \ { \
typedef MultiMathOperand<T1> O1; \ typedef MultiMathOperand<T1> O1; \
typedef MultiMathOperand<T2> O2; \ typedef MultiMathOperand<T2> O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} \ } \
\ \
template <class T1, class T2> \ template <class T1, class T2> \
MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<T1>, \ MultiMathOperand<MultiMathBinaryOperator<MultiMathOperand<T1>, \
typename MultiMathOperand<T2>::All owOverload, \ typename MultiMathOperand<T2>::All owOverload, \
detail::NAME> > \ math_detail::NAME> > \
OPNAME(MultiMathOperand<T1> const & v1, T2 const & v2) \ OPNAME(MultiMathOperand<T1> const & v1, T2 const & v2) \
{ \ { \
typedef MultiMathOperand<T1> O1; \ typedef MultiMathOperand<T1> O1; \
typedef MultiMathOperand<T2> O2; \ typedef MultiMathOperand<T2> O2; \
typedef MultiMathBinaryOperator<O1, O2, detail::NAME> OP; \ typedef MultiMathBinaryOperator<O1, O2, math_detail::NAME> OP; \
return MultiMathOperand<OP>(OP(v1, v2)); \ return MultiMathOperand<OP>(OP(v1, v2)); \
} }
#define VIGRA_NOTHING #define VIGRA_NOTHING
#define VIGRA_COMMA , #define VIGRA_COMMA ,
#define VIGRA_PROMOTE typename PromoteTraits<T1, T2>::Promote #define VIGRA_PROMOTE typename PromoteTraits<T1, T2>::Promote
#define VIGRA_REALPROMOTE typename PromoteTraits<typename NumericTraits<T1> ::RealPromote, \ #define VIGRA_REALPROMOTE typename PromoteTraits<typename NumericTraits<T1> ::RealPromote, \
typename NumericTraits<T2> ::RealPromote>::Promote typename NumericTraits<T2> ::RealPromote>::Promote
VIGRA_MULTIMATH_BINARY_OPERATOR(Plus, VIGRA_NOTHING, operator+, +, VIGRA_PR OMOTE) VIGRA_MULTIMATH_BINARY_OPERATOR(Plus, VIGRA_NOTHING, operator+, +, VIGRA_PR OMOTE)
skipping to change at line 674 skipping to change at line 674
VIGRA_MULTIMATH_BINARY_OPERATOR(Max, std::max, max, VIGRA_COMMA, VIGRA_PROM OTE) VIGRA_MULTIMATH_BINARY_OPERATOR(Max, std::max, max, VIGRA_COMMA, VIGRA_PROM OTE)
VIGRA_MULTIMATH_BINARY_OPERATOR(Minimum, std::min, minimum, VIGRA_COMMA, VI GRA_PROMOTE) VIGRA_MULTIMATH_BINARY_OPERATOR(Minimum, std::min, minimum, VIGRA_COMMA, VI GRA_PROMOTE)
VIGRA_MULTIMATH_BINARY_OPERATOR(Maximum, std::max, maximum, VIGRA_COMMA, VI GRA_PROMOTE) VIGRA_MULTIMATH_BINARY_OPERATOR(Maximum, std::max, maximum, VIGRA_COMMA, VI GRA_PROMOTE)
#undef VIGRA_NOTHING #undef VIGRA_NOTHING
#undef VIGRA_COMMA #undef VIGRA_COMMA
#undef VIGRA_PROMOTE #undef VIGRA_PROMOTE
#undef VIGRA_REALPROMOTE #undef VIGRA_REALPROMOTE
#undef VIGRA_MULTIMATH_BINARY_OPERATOR #undef VIGRA_MULTIMATH_BINARY_OPERATOR
namespace detail { namespace math_detail {
// We pass 'strideOrder' to the recursion in order to make sure // We pass 'strideOrder' to the recursion in order to make sure
// that the inner loop iterates over the output's major axis. // that the inner loop iterates over the output's major axis.
// Of course, this does not help when the RHS arrays are ordered // Of course, this does not help when the RHS arrays are ordered
// differently -- maybe it is better to find the most common order // differently -- maybe it is better to find the most common order
// among all arguments (both RHS and LHS)? // among all arguments (both RHS and LHS)?
// //
template <unsigned int N, class Assign> template <unsigned int N, class Assign>
struct MultiMathExec struct MultiMathExec
{ {
skipping to change at line 815 skipping to change at line 815
struct MultiMathReduceAny struct MultiMathReduceAny
{ {
template <class T, class Expression> template <class T, class Expression>
static void assign(T * data, Expression const & e) static void assign(T * data, Expression const & e)
{ {
*data = *data || (*e != NumericTraits<typename Expression::result_t ype>::zero()); *data = *data || (*e != NumericTraits<typename Expression::result_t ype>::zero());
} }
}; };
} // namespace detail } // namespace math_detail
template <class U, class T> template <class U, class T>
U U
sum(MultiMathOperand<T> const & v, U res = NumericTraits<U>::zero()) sum(MultiMathOperand<T> const & v, U res = NumericTraits<U>::zero())
{ {
static const int ndim = MultiMathOperand<T>::ndim; static const int ndim = MultiMathOperand<T>::ndim;
typename MultiArrayShape<ndim>::type shape; typename MultiArrayShape<ndim>::type shape;
v.checkShape(shape); v.checkShape(shape);
detail::MultiMathReduce<ndim, detail::MultiMathplusAssign>::exec(res, s hape, v); math_detail::MultiMathReduce<ndim, math_detail::MultiMathplusAssign>::e xec(res, shape, v);
return res; return res;
} }
template <class U, unsigned int N, class T, class S> template <class U, unsigned int N, class T, class S>
U U
sum(MultiArrayView<N, T, S> const & v, U res = NumericTraits<U>::zero()) sum(MultiArrayView<N, T, S> const & v, U res = NumericTraits<U>::zero())
{ {
return v.template sum<U>() + res; return v.template sum<U>() + res;
} }
template <class U, class T> template <class U, class T>
U U
product(MultiMathOperand<T> const & v, U res = NumericTraits<U>::one()) product(MultiMathOperand<T> const & v, U res = NumericTraits<U>::one())
{ {
static const int ndim = MultiMathOperand<T>::ndim; static const int ndim = MultiMathOperand<T>::ndim;
typename MultiArrayShape<ndim>::type shape; typename MultiArrayShape<ndim>::type shape;
v.checkShape(shape); v.checkShape(shape);
detail::MultiMathReduce<ndim, detail::MultiMathmultiplyAssign>::exec(re s, shape, v); math_detail::MultiMathReduce<ndim, math_detail::MultiMathmultiplyAssign >::exec(res, shape, v);
return res; return res;
} }
template <class U, unsigned int N, class T, class S> template <class U, unsigned int N, class T, class S>
U U
product(MultiArrayView<N, T, S> const & v, U res = NumericTraits<U>::one()) product(MultiArrayView<N, T, S> const & v, U res = NumericTraits<U>::one())
{ {
return v.template product<U>() * res; return v.template product<U>() * res;
} }
template <class T> template <class T>
bool bool
all(MultiMathOperand<T> const & v) all(MultiMathOperand<T> const & v)
{ {
static const int ndim = MultiMathOperand<T>::ndim; static const int ndim = MultiMathOperand<T>::ndim;
typename MultiArrayShape<ndim>::type shape; typename MultiArrayShape<ndim>::type shape;
v.checkShape(shape); v.checkShape(shape);
bool res = true; bool res = true;
detail::MultiMathReduce<ndim, detail::MultiMathReduceAll>::exec(res, sh ape, v); math_detail::MultiMathReduce<ndim, math_detail::MultiMathReduceAll>::ex ec(res, shape, v);
return res; return res;
} }
template <class T> template <class T>
bool bool
any(MultiMathOperand<T> const & v) any(MultiMathOperand<T> const & v)
{ {
static const int ndim = MultiMathOperand<T>::ndim; static const int ndim = MultiMathOperand<T>::ndim;
typename MultiArrayShape<ndim>::type shape; typename MultiArrayShape<ndim>::type shape;
v.checkShape(shape); v.checkShape(shape);
bool res = false; bool res = false;
detail::MultiMathReduce<ndim, detail::MultiMathReduceAny>::exec(res, sh ape, v); math_detail::MultiMathReduce<ndim, math_detail::MultiMathReduceAny>::ex ec(res, shape, v);
return res; return res;
} }
}} // namespace vigra::multi_math }} // namespace vigra::multi_math
#endif // VIGRA_MULTI_MATH_HXX #endif // VIGRA_MULTI_MATH_HXX
 End of changes. 32 change blocks. 
32 lines changed or deleted 32 lines changed or added


 multi_morphology.hxx   multi_morphology.hxx 
skipping to change at line 88 skipping to change at line 88
// threshold everything less than radius away from the edge // threshold everything less than radius away from the edge
double radius2 = radius * radius; double radius2 = radius * radius;
DestType foreground = dilation DestType foreground = dilation
? NumericTraits<DestType>::zero() ? NumericTraits<DestType>::zero()
: NumericTraits<DestType>::one(), : NumericTraits<DestType>::one(),
background = dilation background = dilation
? NumericTraits<DestType>::one() ? NumericTraits<DestType>::one()
: NumericTraits<DestType>::zero(); : NumericTraits<DestType>::zero();
transformMultiArray( tmpArray.traverser_begin(), shape, StandardVal ueAccessor<double>(), transformMultiArray( tmpArray.traverser_begin(), shape, StandardVal ueAccessor<double>(),
d, dest, d, dest,
ifThenElse( Arg1() >= Param(radius2), ifThenElse( Arg1() > Param(radius2),
Param(foreground), Param(backgroun d) ) ); Param(foreground), Param(backgroun d) ) );
} }
}; };
template <class DestType> template <class DestType>
struct MultiBinaryMorphologyImpl<DestType, DestType> struct MultiBinaryMorphologyImpl<DestType, DestType>
{ {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
static void static void
skipping to change at line 166 skipping to change at line 166
(i.e. NumericTrais<typename DestAccessor::value_type>::one()). (i.e. NumericTrais<typename DestAccessor::value_type>::one()).
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>siter == diter</t t> is allowed.
A temporary internal array is only allocated if working on the destinat ion A temporary internal array is only allocated if working on the destinat ion
array directly would cause overflow errors (that is if array directly would cause overflow errors (that is if
<tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredN orm(shape)</tt>, <tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredN orm(shape)</tt>,
i.e. the squared length of the image diagonal doesn't fit into the dest ination type). i.e. the squared length of the image diagonal doesn't fit into the dest ination type).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
multiBinaryErosion(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double radius);
}
\endcode
\deprecatedAPI{multiBinaryErosion}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiBinaryErosion(SrcIterator siter, SrcShape const & shape, SrcAc cessor src, multiBinaryErosion(SrcIterator siter, SrcShape const & shape, SrcAc cessor src,
DestIterator diter, DestAccessor dest, int radius); DestIterator diter, DestAccessor dest, int radius);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiBinaryErosion(triple<SrcIterator, SrcShape, SrcAccessor> const & source, multiBinaryErosion(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
int radius); int radius);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_morphology.hxx\> <b>\#include</b> \<vigra/multi_morphology.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, unsigned char> dest(shape); MultiArray<3, unsigned char> dest(shape);
... ...
// perform isotropic binary erosion // perform isotropic binary erosion
multiBinaryErosion(srcMultiArrayRange(source), destMultiArray(dest), 3) ; multiBinaryErosion(source, dest, 3);
\endcode \endcode
\see vigra::discErosion() \see vigra::discErosion(), vigra::multiGrayscaleErosion()
*/ */
doxygen_overloaded_function(template <...> void multiBinaryErosion) doxygen_overloaded_function(template <...> void multiBinaryErosion)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiBinaryErosion( SrcIterator s, SrcShape const & shape, SrcAccessor src, multiBinaryErosion( SrcIterator s, SrcShape const & shape, SrcAccessor src,
DestIterator d, DestAccessor dest, double radi us) DestIterator d, DestAccessor dest, double radi us)
{ {
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
skipping to change at line 233 skipping to change at line 247
detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape , src, d, dest, radius, false); detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape , src, d, dest, radius, false);
} }
else // work directly on the destination array else // work directly on the destination array
{ {
detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shap e, src, d, dest, radius, false); detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shap e, src, d, dest, radius, false);
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void multiBinaryErosion( multiBinaryErosion(triple<SrcIterator, SrcShape, SrcAccessor> const & sourc
triple<SrcIterator, SrcShape, SrcAccessor> const & source, e,
pair<DestIterator, DestAccessor> const & dest, double radius) pair<DestIterator, DestAccessor> const & dest, double ra
dius)
{ {
multiBinaryErosion( source.first, source.second, source.third, multiBinaryErosion( source.first, source.second, source.third,
dest.first, dest.second, radius ); dest.first, dest.second, radius );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
multiBinaryErosion(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double radius)
{
vigra_precondition(source.shape() == dest.shape(),
"multiBinaryErosion(): shape mismatch between input and output.");
multiBinaryErosion( srcMultiArrayRange(source),
destMultiArray(dest), radius );
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* multiBinaryDilation */ /* multiBinaryDilation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Binary dilation on multi-dimensional arrays. /** \brief Binary dilation on multi-dimensional arrays.
skipping to change at line 264 skipping to change at line 290
(i.e. NumericTrais<typename DestAccessor::value_type>::one()). (i.e. NumericTrais<typename DestAccessor::value_type>::one()).
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>siter == diter</t t> is allowed.
A temporary internal array is only allocated if working on the destinat ion A temporary internal array is only allocated if working on the destinat ion
array directly would cause overflow errors (that is if array directly would cause overflow errors (that is if
<tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredN orm(shape)</tt>, <tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredN orm(shape)</tt>,
i.e. the squared length of the image diagonal doesn't fit into the dest ination type). i.e. the squared length of the image diagonal doesn't fit into the dest ination type).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
multiBinaryDilation(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double radius);
}
\endcode
\deprecatedAPI{multiBinaryDilation}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiBinaryDilation(SrcIterator siter, SrcShape const & shape, SrcA ccessor src, multiBinaryDilation(SrcIterator siter, SrcShape const & shape, SrcA ccessor src,
DestIterator diter, DestAccessor dest, int radius); DestIterator diter, DestAccessor dest, int radius);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiBinaryDilation(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source, multiBinaryDilation(triple<SrcIterator, SrcShape, SrcAccessor> cons t & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
int radius); int radius);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_morphology.hxx\> <b>\#include</b> \<vigra/multi_morphology.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, unsigned char> dest(shape); MultiArray<3, unsigned char> dest(shape);
... ...
// perform isotropic binary erosion // perform isotropic binary erosion
multiBinaryDilation(srcMultiArrayRange(source), destMultiArray(dest), 3 ); multiBinaryDilation(source, dest, 3);
\endcode \endcode
\see vigra::discDilation() \see vigra::discDilation(), vigra::multiGrayscaleDilation()
*/ */
doxygen_overloaded_function(template <...> void multiBinaryDilation) doxygen_overloaded_function(template <...> void multiBinaryDilation)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiBinaryDilation( SrcIterator s, SrcShape const & shape, SrcAccessor src , multiBinaryDilation( SrcIterator s, SrcShape const & shape, SrcAccessor src ,
DestIterator d, DestAccessor dest, double radi us) DestIterator d, DestAccessor dest, double radi us)
{ {
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
skipping to change at line 331 skipping to change at line 371
detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape , src, d, dest, radius, true); detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape , src, d, dest, radius, true);
} }
else // work directly on the destination array else // work directly on the destination array
{ {
detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shap e, src, d, dest, radius, true); detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shap e, src, d, dest, radius, true);
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void multiBinaryDilation( multiBinaryDilation(triple<SrcIterator, SrcShape, SrcAccessor> const & sour
triple<SrcIterator, SrcShape, SrcAccessor> const & source, ce,
pair<DestIterator, DestAccessor> const & dest, double radius) pair<DestIterator, DestAccessor> const & dest, double r
adius)
{ {
multiBinaryDilation( source.first, source.second, source.third, multiBinaryDilation( source.first, source.second, source.third,
dest.first, dest.second, radius ); dest.first, dest.second, radius );
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
multiBinaryDilation(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double radius)
{
vigra_precondition(source.shape() == dest.shape(),
"multiBinaryDilation(): shape mismatch between input and output.");
multiBinaryDilation( srcMultiArrayRange(source),
destMultiArray(dest), radius );
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* multiGrayscaleErosion */ /* multiGrayscaleErosion */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Parabolic grayscale erosion on multi-dimensional arrays. /** \brief Parabolic grayscale erosion on multi-dimensional arrays.
This function applies a parabolic erosion operator with a given spread (sigma) on This function applies a parabolic erosion operator with a given spread (sigma) on
skipping to change at line 359 skipping to change at line 411
The input is a grayscale multi-dimensional array. The input is a grayscale multi-dimensional array.
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>siter == diter</t t> is allowed.
A full-sized internal array is only allocated if working on the destina tion A full-sized internal array is only allocated if working on the destina tion
array directly would cause overflow errors (i.e. if array directly would cause overflow errors (i.e. if
<tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M is the <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M is the
size of the largest dimension of the array. size of the largest dimension of the array.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
multiGrayscaleErosion(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma);
}
\endcode
\deprecatedAPI{multiGrayscaleErosion}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiGrayscaleErosion(SrcIterator siter, SrcShape const & shape, Sr cAccessor src, multiGrayscaleErosion(SrcIterator siter, SrcShape const & shape, Sr cAccessor src,
DestIterator diter, DestAccessor dest, double sigma); DestIterator diter, DestAccessor dest, double sigma);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiGrayscaleErosion(triple<SrcIterator, SrcShape, SrcAccessor> co nst & source, multiGrayscaleErosion(triple<SrcIterator, SrcShape, SrcAccessor> co nst & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double sigma); double sigma);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_morphology.hxx\> <b>\#include</b> \<vigra/multi_morphology.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, unsigned char> dest(shape); MultiArray<3, unsigned char> dest(shape);
... ...
// perform isotropic grayscale erosion // perform isotropic grayscale erosion
multiGrayscaleErosion(srcMultiArrayRange(source), destMultiArray(dest), 3.0); multiGrayscaleErosion(source, dest, 3.0);
\endcode \endcode
\see vigra::discErosion() \see vigra::discErosion(), vigra::multiBinaryErosion()
*/ */
doxygen_overloaded_function(template <...> void multiGrayscaleErosion) doxygen_overloaded_function(template <...> void multiGrayscaleErosion)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiGrayscaleErosion( SrcIterator s, SrcShape const & shape, SrcAccessor s rc, multiGrayscaleErosion( SrcIterator s, SrcShape const & shape, SrcAccessor s rc,
DestIterator d, DestAccessor dest, double sigma) DestIterator d, DestAccessor dest, double sigma)
{ {
typedef typename NumericTraits<typename DestAccessor::value_type>::Valu eType DestType; typedef typename NumericTraits<typename DestAccessor::value_type>::Valu eType DestType;
typedef typename NumericTraits<typename DestAccessor::value_type>::Prom ote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Prom ote TmpType;
DestType MaxValue = NumericTraits<DestType>::max(); DestType MaxValue = NumericTraits<DestType>::max();
enum { N = 1 + SrcIterator::level }; enum { N = 1 + SrcIterator::level };
// temporary array to hold the current line to enable in-place operatio n // temporary array to hold the current line to enable in-place operatio n
ArrayVector<TmpType> tmp( shape[0] ); ArrayVector<TmpType> tmp( shape[0] );
typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator;
int MaxDim = 0; int MaxDim = 0;
for( int i=0; i<N; i++) for( int i=0; i<N; i++)
if(MaxDim < shape[i]) MaxDim = shape[i]; if(MaxDim < shape[i]) MaxDim = shape[i];
using namespace vigra::functor; using namespace vigra::functor;
ArrayVector<double> sigmas(shape.size(), sigma); ArrayVector<double> sigmas(shape.size(), sigma);
// Allocate a new temporary array if the distances squared wouldn't fit // Allocate a new temporary array if the distances squared wouldn't fit
if(N*MaxDim*MaxDim > MaxValue) if(N*MaxDim*MaxDim > MaxValue)
skipping to change at line 450 skipping to change at line 513
} }
else else
{ {
detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest, sigmas ); detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest, sigmas );
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void multiGrayscaleErosion( multiGrayscaleErosion(triple<SrcIterator, SrcShape, SrcAccessor> const & so
triple<SrcIterator, SrcShape, SrcAccessor> const & source, urce,
pair<DestIterator, DestAccessor> const & dest, double sigma) pair<DestIterator, DestAccessor> const & dest, double
sigma)
{ {
multiGrayscaleErosion( source.first, source.second, source.third, multiGrayscaleErosion( source.first, source.second, source.third,
dest.first, dest.second, sigma); dest.first, dest.second, sigma);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
multiGrayscaleErosion(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma)
{
vigra_precondition(source.shape() == dest.shape(),
"multiGrayscaleErosion(): shape mismatch between input and output."
);
multiGrayscaleErosion( srcMultiArrayRange(source),
destMultiArray(dest), sigma);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* multiGrayscaleDilation */ /* multiGrayscaleDilation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Parabolic grayscale dilation on multi-dimensional arrays. /** \brief Parabolic grayscale dilation on multi-dimensional arrays.
This function applies a parabolic dilation operator with a given spread (sigma) on This function applies a parabolic dilation operator with a given spread (sigma) on
skipping to change at line 478 skipping to change at line 553
The input is a grayscale multi-dimensional array. The input is a grayscale multi-dimensional array.
This function may work in-place, which means that <tt>siter == diter</t t> is allowed. This function may work in-place, which means that <tt>siter == diter</t t> is allowed.
A full-sized internal array is only allocated if working on the destina tion A full-sized internal array is only allocated if working on the destina tion
array directly would cause overflow errors (i.e. if array directly would cause overflow errors (i.e. if
<tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M is the <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M is the
size of the largest dimension of the array. size of the largest dimension of the array.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
multiGrayscaleDilation(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma);
}
\endcode
\deprecatedAPI{multiGrayscaleDilation}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiGrayscaleDilation(SrcIterator siter, SrcShape const & shape, S rcAccessor src, multiGrayscaleDilation(SrcIterator siter, SrcShape const & shape, S rcAccessor src,
DestIterator diter, DestAccessor dest, double sigma); DestIterator diter, DestAccessor dest, double sigma);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
multiGrayscaleDilation(triple<SrcIterator, SrcShape, SrcAccessor> c onst & source, multiGrayscaleDilation(triple<SrcIterator, SrcShape, SrcAccessor> c onst & source,
pair<DestIterator, DestAccessor> const & dest, pair<DestIterator, DestAccessor> const & dest,
double sigma); double sigma);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_morphology.hxx\> <b>\#include</b> \<vigra/multi_morphology.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, unsigned char>::size_type shape(width, height, depth); Shape3 shape(width, height, depth);
MultiArray<3, unsigned char> source(shape); MultiArray<3, unsigned char> source(shape);
MultiArray<3, unsigned char> dest(shape); MultiArray<3, unsigned char> dest(shape);
... ...
// perform isotropic grayscale erosion // perform isotropic grayscale erosion
multiGrayscaleDilation(srcMultiArrayRange(source), destMultiArray(dest) , 3.0); multiGrayscaleDilation(source, dest, 3.0);
\endcode \endcode
\see vigra::discErosion() \see vigra::discDilation(), vigra::multiBinaryDilation()
*/ */
doxygen_overloaded_function(template <...> void multiGrayscaleDilation) doxygen_overloaded_function(template <...> void multiGrayscaleDilation)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void multiGrayscaleDilation( SrcIterator s, SrcShape const & shape, SrcAcce ssor src, void multiGrayscaleDilation( SrcIterator s, SrcShape const & shape, SrcAcce ssor src,
DestIterator d, DestAccessor dest, double sigm a) DestIterator d, DestAccessor dest, double sigm a)
{ {
typedef typename NumericTraits<typename DestAccessor::value_type>::Valu eType DestType; typedef typename NumericTraits<typename DestAccessor::value_type>::Valu eType DestType;
typedef typename NumericTraits<typename DestAccessor::value_type>::Prom ote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Prom ote TmpType;
DestType MinValue = NumericTraits<DestType>::min(); DestType MinValue = NumericTraits<DestType>::min();
DestType MaxValue = NumericTraits<DestType>::max(); DestType MaxValue = NumericTraits<DestType>::max();
enum { N = 1 + SrcIterator::level }; enum { N = 1 + SrcIterator::level };
// temporary array to hold the current line to enable in-place operatio n // temporary array to hold the current line to enable in-place operatio n
ArrayVector<TmpType> tmp( shape[0] ); ArrayVector<TmpType> tmp( shape[0] );
typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator;
int MaxDim = 0; int MaxDim = 0;
for( int i=0; i<N; i++) for( int i=0; i<N; i++)
if(MaxDim < shape[i]) MaxDim = shape[i]; if(MaxDim < shape[i]) MaxDim = shape[i];
using namespace vigra::functor; using namespace vigra::functor;
ArrayVector<double> sigmas(shape.size(), sigma); ArrayVector<double> sigmas(shape.size(), sigma);
// Allocate a new temporary array if the distances squared wouldn't fit // Allocate a new temporary array if the distances squared wouldn't fit
if(-N*MaxDim*MaxDim < MinValue || N*MaxDim*MaxDim > MaxValue) if(-N*MaxDim*MaxDim < MinValue || N*MaxDim*MaxDim > MaxValue)
skipping to change at line 568 skipping to change at line 654
} }
else else
{ {
detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest, sigmas, true ); detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest, sigmas, true );
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void multiGrayscaleDilation( multiGrayscaleDilation(triple<SrcIterator, SrcShape, SrcAccessor> const & s
triple<SrcIterator, SrcShape, SrcAccessor> const & source, ource,
pair<DestIterator, DestAccessor> const & dest, double sigma) pair<DestIterator, DestAccessor> const & dest, doubl
e sigma)
{ {
multiGrayscaleDilation( source.first, source.second, source.third, multiGrayscaleDilation( source.first, source.second, source.third,
dest.first, dest.second, sigma); dest.first, dest.second, sigma);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
multiGrayscaleDilation(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
double sigma)
{
vigra_precondition(source.shape() == dest.shape(),
"multiGrayscaleDilation(): shape mismatch between input and output.
");
multiGrayscaleDilation( srcMultiArrayRange(source),
destMultiArray(dest), sigma);
} }
//@} //@}
} //-- namespace vigra } //-- namespace vigra
#endif //-- VIGRA_MULTI_MORPHOLOGY_HXX #endif //-- VIGRA_MULTI_MORPHOLOGY_HXX
 End of changes. 39 change blocks. 
51 lines changed or deleted 159 lines changed or added


 multi_pointoperators.hxx   multi_pointoperators.hxx 
skipping to change at line 59 skipping to change at line 59
namespace vigra namespace vigra
{ {
/** \addtogroup MultiPointoperators Point operators for multi-dimensional a rrays. /** \addtogroup MultiPointoperators Point operators for multi-dimensional a rrays.
Copy, transform, and inspect arbitrary dimensional arrays which are rep resented Copy, transform, and inspect arbitrary dimensional arrays which are rep resented
by iterators compatible to \ref MultiIteratorPage. Note that are range is here by iterators compatible to \ref MultiIteratorPage. Note that are range is here
specified by a pair: an iterator referring to the first point of the ar ray specified by a pair: an iterator referring to the first point of the ar ray
and a shape object specifying the size of the (rectangular) ROI. and a shape object specifying the size of the (rectangular) ROI.
<b>\#include</b> \<vigra/multi_pointoperators.hxx\> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br/>
Namespace: vigra
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* initMultiArray */ /* initMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
template <class Iterator, class Shape, class Accessor, template <class Iterator, class Shape, class Accessor,
skipping to change at line 90 skipping to change at line 91
initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,
VALUETYPE const & v, MetaInt<N>) VALUETYPE const & v, MetaInt<N>)
{ {
Iterator send = s + shape[N]; Iterator send = s + shape[N];
for(; s < send; ++s) for(; s < send; ++s)
{ {
initMultiArrayImpl(s.begin(), shape, a, v, MetaInt<N-1>()); initMultiArrayImpl(s.begin(), shape, a, v, MetaInt<N-1>());
} }
} }
/** \brief Write a value to every pixel in a multi-dimensional array. /** \brief Write a value to every element in a multi-dimensional array.
This function can be used to init the array which must be represented b
y
a pair of iterators compatible to \ref vigra::MultiIterator.
It uses an accessor to access the data elements. Note that the iterator
range
must be specified by a shape object, because otherwise we could not con
trol
the range simultaneously in all dimensions (this is a necessary consequ
ence
of the \ref vigra::MultiIterator design).
The initial value can either be a constant of appropriate type (compati ble with The initial value can either be a constant of appropriate type (compati ble with
the destination's value_type), or a functor with compatible result_type . These two the destination's value_type), or a functor with compatible result_type . These two
cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt> cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>:: isInitializer</tt>
yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const </tt> reference, its
<tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>. <tt>operator()</tt> must be const, and its internal state may need to b e <tt>mutable</tt>.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T, class S, class VALUETYPE>
void
initMultiArray(MultiArrayView<N, T, S> s, VALUETYPE const & v);
template <unsigned int N, class T, class S, class FUNCTOR>
void
initMultiArray(MultiArrayView<N, T, S> s, FUNCTOR const & f);
}
\endcode
\deprecatedAPI{initMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Shape, class Accessor, class VALUET YPE> template <class Iterator, class Shape, class Accessor, class VALUET YPE>
void void
initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUET YPE const & v); initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUET YPE const & v);
template <class Iterator, class Shape, class Accessor, class FUNCTO R> template <class Iterator, class Shape, class Accessor, class FUNCTO R>
void void
initMultiArray(Iterator s, Shape const & shape, Accessor a, FUNCTO R const & f); initMultiArray(Iterator s, Shape const & shape, Accessor a, FUNCTO R const & f);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Shape, class Accessor, class VALUET YPE> template <class Iterator, class Shape, class Accessor, class VALUET YPE>
void void
initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETY PE const & v); initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETY PE const & v);
template <class Iterator, class Shape, class Accessor, class FUNCTO R> template <class Iterator, class Shape, class Accessor, class FUNCTO R>
void void
initMultiArray(triple<Iterator, Shape, Accessor> const & s, FUNCTOR const & f); initMultiArray(triple<Iterator, Shape, Accessor> const & s, FUNCTOR const & f);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, int> Array; MultiArray<3, unsigned int> array(Shape3(100, 200, 50));
Array array(Array::size_type(100, 200, 50));
// make an array of all ones
initMultiArray(array, 1);
// equivalent calls:
array = 1;
array.init(1);
// zero the array // fill the array with random numbers
vigra::initMultiArray(destMultiArrayRange(array), 0); #include <vigra/random.hxx>
initMultiArray(array, MersenneTwister());
\endcode \endcode
<b> Required Interface:</b> \deprecatedUsage{initMultiArray}
\code
MultiArray<3, int> array(Shape3(100, 200, 50));
// make an array of all twos
vigra::initMultiArray(destMultiArrayRange(array), 2);
\endcode
<b> Required Interface:</b>
The function accepts either a value that is copied into every destinati on element: The function accepts either a value that is copied into every destinati on element:
\code \code
MultiIterator begin; MultiIterator begin;
Accessor accessor; Accessor accessor;
VALUETYPE v; VALUETYPE v;
accessor.set(v, begin); accessor.set(v, begin);
\endcode \endcode
or a functor that is called (without argument) at every location, or a functor that is called (without argument) at every location,
and the result is written into the current element. Internally, and the result is written into the current element. Internally,
functors are recognized by the meta function functors are recognized by the meta function
<tt>FunctorTraits<FUNCTOR>::isInitializer</tt> yielding <tt>VigraTrueTy pe</tt>. <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> yielding <tt>VigraTrueTy pe</tt>.
Make sure that your functor correctly defines <tt>FunctorTraits</tt> be cause Make sure that your functor correctly defines <tt>FunctorTraits</tt> be cause
otherwise the code will not compile. otherwise the code will not compile.
\code \code
MultiIterator begin; MultiIterator begin;
Accessor accessor; Accessor accessor;
FUNCTOR f; FUNCTOR f;
assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTru eType)); assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTru eType));
accessor.set(f(), begin); accessor.set(f(), begin);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void initMultiArray) doxygen_overloaded_function(template <...> void initMultiArray)
template <class Iterator, class Shape, class Accessor, class VALUETYPE> template <class Iterator, class Shape, class Accessor, class VALUETYPE>
inline void inline void
initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUETYPE cons t & v) initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUETYPE cons t & v)
{ {
initMultiArrayImpl(s, shape, a, v, MetaInt<Iterator::level>()); initMultiArrayImpl(s, shape, a, v, MetaInt<Iterator::level>());
} }
template <class Iterator, class Shape, class Accessor, class VALUETYPE> template <class Iterator, class Shape, class Accessor, class VALUETYPE>
inline inline void
void
initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v) initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v)
{ {
initMultiArray(s.first, s.second, s.third, v); initMultiArrayImpl(s.first, s.second, s.third, v, MetaInt<Iterator::le
vel>());
}
template <unsigned int N, class T, class S, class VALUETYPE>
inline void
initMultiArray(MultiArrayView<N, T, S> s, VALUETYPE const & v)
{
initMultiArray(destMultiArrayRange(s), v);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* initMultiArrayBorder */ /* initMultiArrayBorder */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Write value to the specified border values in the array. /** \brief Write values to the specified border values in the array.
This functions is similar to \ref initMultiArray(), but it initializes
only
the array elements whose distance from any array border is at most \a b
order_width.
<b> Declarations:</b>
pass arbitrary-dimensional array views:
\code
namespace vigra {
// init equal borders on all array sides
template <unsigned int N, class T, class S,
class VALUETYPE>
void
initMultiArrayBorder( MultiArrayView<N, T, S> array,
MultiArrayIndex border_width, VALUETYPE const
& v);
template <unsigned int N, class T, class S,
class FUNCTOR>
void
initMultiArrayBorder( MultiArrayView<N, T, S> array,
MultiArrayIndex border_width, FUNCTOR const &
v);
// specify border width individually for all array sides
template <unsigned int N, class T, class S,
class VALUETYPE>
void
initMultiArrayBorder( MultiArrayView<N, T, S> array,
typename MultiArrayShape<N>::type const & low
er_border,
typename MultiArrayShape<N>::type const & upp
er_border,
VALUETYPE const & v);
}
\endcode
\deprecatedAPI{initMultiArrayBorder}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code
namespace vigra {
template <class Iterator, class Diff_type, class Accessor,
class VALUETYPE>
void
initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor
a,
MultiArrayIndex border_width, VALUETYPE const
& v);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class Iterator, class Diff_type, class Accessor,
class VALUETYPE>
inline void
initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiAr
ray,
MultiArrayIndex border_width, VALUETYPE const
& v);
}
\endcode
\deprecatedEnd
<b> Usage:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra
\code
MultiArray<3, unsigned int> array(Shape3(100, 200, 50));
int border_width = 5;
*/template <class Iterator, class Diff_type, class Accessor, class VALUETYP // init the array interior to 1, the border to 2
E> initMultiArray(array.subarray(Shape3(border_width), Shape3(-border_widt
inline void initMultiArrayBorder( Iterator upperleft, Diff_type shape, h)), 1);
Accessor a, int border_width, VALUETYPE initMultiArrayBorder(array, border_width, 2);
v) \endcode
*/
doxygen_overloaded_function(template <...> void initMultiArrayBorder)
template <class Iterator, class Diff_type, class Accessor,
class VALUETYPE>
void
initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
Diff_type lower_border, Diff_type upper_border,
VALUETYPE const & v)
{ {
Diff_type border(shape); for(unsigned int dim=0; dim<shape.size(); dim++)
for(unsigned int dim=0; dim<shape.size(); dim++){ {
border[dim] = (border_width > shape[dim]) ? shape[dim] : border_wid lower_border[dim] = (lower_border[dim] > shape[dim]) ? shape[dim] :
th; lower_border[dim];
upper_border[dim] = (upper_border[dim] > shape[dim]) ? shape[dim] :
upper_border[dim];
} }
for(unsigned int dim=0; dim<shape.size(); dim++){ for(unsigned int dim=0; dim<shape.size(); dim++)
Diff_type start(shape), {
Diff_type start,
offset(shape); offset(shape);
start = start-shape; offset[dim] = lower_border[dim];
offset[dim]=border[dim];
initMultiArray(upperleft+start, offset, a, v); initMultiArray(upperleft+start, offset, a, v);
start[dim]=shape[dim]-border[dim]; start[dim] = shape[dim] - upper_border[dim];
offset[dim] = upper_border[dim];
initMultiArray(upperleft+start, offset, a, v); initMultiArray(upperleft+start, offset, a, v);
} }
} }
template <class Iterator, class Diff_type, class Accessor, class VALUETYPE> template <class Iterator, class Diff_type, class Accessor,
inline void initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> mul class VALUETYPE>
tiArray, inline void
int border_width, VALUETYPE v) initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
MultiArrayIndex border_width, VALUETYPE const & v)
{
initMultiArrayBorder(upperleft, shape, a,
Diff_type(border_width), Diff_type(border_width),
v);
}
template <class Iterator, class Diff_type, class Accessor,
class VALUETYPE>
inline void
initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
MultiArrayIndex border_width, VALUETYPE const & v)
{ {
initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.th ird, border_width, v); initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.th ird, border_width, v);
} }
template <class Iterator, class Diff_type, class Accessor,
class VALUETYPE>
inline void
initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
Diff_type const & lower_border, Diff_type const & upp
er_border,
VALUETYPE const & v)
{
initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.th
ird,
lower_border, upper_border, v);
}
template <unsigned int N, class T, class S,
class VALUETYPE>
inline void
initMultiArrayBorder( MultiArrayView<N, T, S> array,
MultiArrayIndex border_width, VALUETYPE const & v)
{
initMultiArrayBorder(destMultiArrayRange(array), border_width, v);
}
template <unsigned int N, class T, class S,
class VALUETYPE>
inline void
initMultiArrayBorder( MultiArrayView<N, T, S> array,
typename MultiArrayShape<N>::type const & lower_borde
r,
typename MultiArrayShape<N>::type const & upper_borde
r,
VALUETYPE const & v)
{
initMultiArrayBorder(destMultiArrayRange(array), lower_border, upper_bo
rder, v);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* copyMultiArray */ /* copyMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor> class DestIterator, class DestShape, class DestAccessor>
void void
copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src, copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
skipping to change at line 300 skipping to change at line 445
The given row is automatically repeated for every row of the destin ation image. The given row is automatically repeated for every row of the destin ation image.
Again, type conversion os performed if necessary. Again, type conversion os performed if necessary.
</DL> </DL>
The arrays must be represented by The arrays must be represented by
iterators compatible with \ref vigra::MultiIterator, and the iteration range iterators compatible with \ref vigra::MultiIterator, and the iteration range
is specified by means of shape objects. If only the source shape is giv en is specified by means of shape objects. If only the source shape is giv en
the destination array is assumed to have the same shape, and standard m ode the destination array is assumed to have the same shape, and standard m ode
is applied. If two shapes are given, the size of corresponding dimensio ns is applied. If two shapes are given, the size of corresponding dimensio ns
must be either equal (standard copy), or the source length must be 1 must be either equal (standard copy), or the source length must be 1
(expanding copy). The function uses accessors to access the data elemen ts. (expanding copy).
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
copyMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest);
}
\endcode
\deprecatedAPI{copyMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
copyMultiArray(SrcIterator s, copyMultiArray(SrcIterator s,
SrcShape const & shape, SrcAccessor src, SrcShape const & shape, SrcAccessor src,
DestIterator d, DestAccessor dest); DestIterator d, DestAccessor dest);
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor> class DestIterator, class DestShape, class DestAccessor>
void void
copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src, copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
DestIterator d, DestShape const & dshape, DestAccess or dest); DestIterator d, DestShape const & dshape, DestAccess or dest);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & s rc, copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & s rc,
pair<DestIterator, DestAccessor> const & dest); pair<DestIterator, DestAccessor> const & dest);
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor> class DestIterator, class DestShape, class DestAccessor>
void void
copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & s rc, copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & s rc,
triple<DestIterator, DestShape, DestAccessor> const & dest); triple<DestIterator, DestShape, DestAccessor> const & dest);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage - Standard Mode:</b> <b> Usage - Standard Mode:</b>
\code \code
typedef vigra::MultiArray<3, int> Array; MultiArray<3, int> src(Shape3(100, 200, 50)),
Array src(Array::size_type(100, 200, 50)), dest(Shape3(100, 200, 50));
dest(Array::size_type(100, 200, 50));
... ...
vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArray(dest)); copyMultiArray(src, dest);
// equivalent to
dest = src;
// copy only the red channel (i.e. channl 0) of an RGB array
MultiArray<3, RGBValue<int> > rgb_src(Shape3(100, 200, 50));
copyMultiArray(rgb_src.bindElementChannel(0), dest);
// equivalent to
dest = rgb_src.bindElementChannel(0);
\endcode \endcode
<b> Usage - Expanding Mode:</b> <b> Usage - Expanding Mode:</b>
The source array is only 2D (it has depth 1). Thus, the destination The source array is effectively only a 2D image (it has a 3D shape, but
will contain 50 identical copies of this image. Note that the destinati 'depth' is a
on shape singleton dimension with length 1). Thus, the destination will contain
must be passed to the algorithm for the expansion to work, so we use 50 identical
<tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>. copies of this image:
\code \code
MultiArray<3, int> src(Shape2(100, 200)),
dest(Shape3(100, 200, 50));
...
copyMultiArray(src.insertSingletonDimension(2), dest);
// create an RGB image with three identical color bands
MultiArray<3, RGBValue<int> > rgb_dest(Shape2(100, 200));
copyMultiArray(src.insertSingletonDimension(2), rgb_dest.expandElements
(2));
\endcode
\deprecatedUsage{copyMultiArray}
\code
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array src(Array::size_type(100, 200, 1)), Array src(Array::size_type(100, 200, 50)),
dest(Array::size_type(100, 200, 50)); dest(Array::size_type(100, 200, 50));
... ...
vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArrayRange(dest )); vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArray(dest));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
MultiIterator src_begin, dest_begin; MultiIterator src_begin, dest_begin;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
dest_accessor.set(src_accessor(src_begin), dest_begin); dest_accessor.set(src_accessor(src_begin), dest_begin);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void copyMultiArray) doxygen_overloaded_function(template <...> void copyMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
copyMultiArray(SrcIterator s, copyMultiArray(SrcIterator s,
SrcShape const & shape, SrcAccessor src, SrcShape const & shape, SrcAccessor src,
DestIterator d, DestAccessor dest) DestIterator d, DestAccessor dest)
{ {
copyMultiArrayImpl(s, shape, src, d, shape, dest, MetaInt<SrcIterator:: level>()); copyMultiArrayImpl(s, shape, src, d, shape, dest, MetaInt<SrcIterator:: level>());
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
pair<DestIterator, DestAccessor> const & dest)
{
copyMultiArray(src.first, src.second, src.third, dest.first, dest.secon
d);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor> class DestIterator, class DestShape, class DestAccessor>
void void
copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src, copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
DestIterator d, DestShape const & dshape, DestAccessor dest) DestIterator d, DestShape const & dshape, DestAccessor dest)
{ {
vigra_precondition(sshape.size() == dshape.size(), vigra_precondition(sshape.size() == dshape.size(),
"copyMultiArray(): dimensionality of source and destination array d iffer"); "copyMultiArray(): dimensionality of source and destination array d iffer");
for(unsigned int i=0; i<sshape.size(); ++i) for(unsigned int i=0; i<sshape.size(); ++i)
vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i], vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
"copyMultiArray(): mismatch between source and destination shap es:\n" "copyMultiArray(): mismatch between source and destination shap es:\n"
"length of each source dimension must either be 1 or equal to t he corresponding " "length of each source dimension must either be 1 or equal to t he corresponding "
"destination length."); "destination length.");
copyMultiArrayImpl(s, sshape, src, d, dshape, dest, MetaInt<SrcIterator ::level>()); copyMultiArrayImpl(s, sshape, src, d, dshape, dest, MetaInt<SrcIterator ::level>());
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
pair<DestIterator, DestAccessor> const & dest)
{
copyMultiArray(src.first, src.second, src.third, dest.first, dest.secon
d);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor> class DestIterator, class DestShape, class DestAccessor>
inline void inline void
copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src, copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
triple<DestIterator, DestShape, DestAccessor> const & dest) triple<DestIterator, DestShape, DestAccessor> const & dest)
{ {
copyMultiArray(src.first, src.second, src.third, dest.first, dest.secon d, dest.third); copyMultiArray(src.first, src.second, src.third, dest.first, dest.secon d, dest.third);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
copyMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
for(int k=0; k<N; ++k)
vigra_precondition(source.shape(k) == dest.shape(k) || source.shape
(k) == 1 || 1 == dest.shape(k),
"copyMultiArray(): shape mismatch between input and output.");
if(source.shape() == dest.shape())
copyMultiArray(srcMultiArrayRange(source), destMultiArray(dest));
else
copyMultiArray(srcMultiArrayRange(source), destMultiArrayRange(dest
));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* transformMultiArray */ /* transformMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void void
skipping to change at line 559 skipping to change at line 751
vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i], vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
"transformMultiArray(): mismatch between source and destination shapes:\n" "transformMultiArray(): mismatch between source and destination shapes:\n"
"In 'expand'-mode, the length of each source dimension must eit her be 1\n" "In 'expand'-mode, the length of each source dimension must eit her be 1\n"
"or equal to the corresponding destination length."); "or equal to the corresponding destination length.");
transformMultiArrayExpandImpl(s, sshape, src, d, dshape, dest, transformMultiArrayExpandImpl(s, sshape, src, d, dshape, dest,
f, MetaInt<SrcIterator::level>()); f, MetaInt<SrcIterator::level>());
} }
/** \brief Transform a multi-dimensional array with a unary function or fun ctor. /** \brief Transform a multi-dimensional array with a unary function or fun ctor.
Note: The effect of this function can often be achieved in a simpler an
d
more readable way by means of \ref MultiMathModule "array experessions"
.
This function can be applied in three modes: This function can be applied in three modes:
<DL> <DL>
<DT><b>Standard Mode:</b> <DT><b>Standard Mode:</b>
<DD>If the source and destination arrays have the same size, <DD>If the source and destination arrays have the same size,
the transformation given by the functor is applied to every source the transformation given by the functor is applied to every source
element and the result written into the corresponding destination e lement. element and the result written into the corresponding destination e lement.
Unary functions, unary functors from the STL and the functors speci fically Unary functions, unary functors from the STL and the functors speci fically
defined in \ref TransformFunctor can be used in standard mode. defined in \ref TransformFunctor can be used in standard mode.
Creation of new functors is easiest by using \ref FunctorExpression s. Creation of new functors is easiest by using \ref FunctorExpression s.
skipping to change at line 588 skipping to change at line 783
<DT><b>Reducing Mode:</b> <DT><b>Reducing Mode:</b>
<DD>If the destination array has length 1 along some (or even all) dimensions, <DD>If the destination array has length 1 along some (or even all) dimensions,
the source values in these dimensions are reduced to single values by means the source values in these dimensions are reduced to single values by means
of a suitable functor (e.g. \ref vigra::ReduceFunctor), which suppo rts two of a suitable functor (e.g. \ref vigra::ReduceFunctor), which suppo rts two
function call operators: one function call operators: one
with a single argument to collect the values, and without argument to with a single argument to collect the values, and without argument to
obtain the final (reduced) result. This behavior is a multi-dimensi onal obtain the final (reduced) result. This behavior is a multi-dimensi onal
generalization of the C++ standard function <tt>std::accumulate()</ tt>. generalization of the C++ standard function <tt>std::accumulate()</ tt>.
</DL> </DL>
The arrays must be represented by The arrays must be represented by MultiArrayViews. If source and destin
iterators compatible with \ref vigra::MultiIterator, and the iteration ation shapes
range match, standard mode is applied. If the shapes differ, the size of corr
is specified by means of shape objects. If only the source shape is giv esponding
en dimensions must either be equal, or the source length must be 1
the destination array is assumed to have the same shape, and standard m
ode
is applied. If two shapes are given, the size of corresponding dimensio
ns
must be either equal (standard copy), or the source length must be 1
(expand mode), or the destination length must be 1 (reduce mode). Howev er, (expand mode), or the destination length must be 1 (reduce mode). Howev er,
reduction and expansion cannot be executed at the same time, so the lat ter reduction and expansion cannot be executed at the same time, so the lat ter
conditions are mutual exclusive, even if they apply to different dimens ions. conditions are mutual exclusive, even if they apply to different dimens ions.
The function uses accessors to access the data elements.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Functor>
void
transformMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest, Functor const &
f);
}
\endcode
\deprecatedAPI{transformMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
void void
transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAcces sor src, transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAcces sor src,
DestIterator d, DestAccessor dest, Functor cons t & f); DestIterator d, DestAccessor dest, Functor cons t & f);
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void void
transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAcce ssor src, transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAcce ssor src,
DestIterator d, DestShape const & dshape, DestA ccessor dest, DestIterator d, DestShape const & dshape, DestA ccessor dest,
Functor const & f); Functor const & f);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
void void
transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & src, transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & src,
pair<DestIterator, DestAccessor> const & dest, Functor const & f); pair<DestIterator, DestAccessor> const & dest, Functor const & f);
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void void
transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & src, transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons t & src,
triple<DestIterator, DestShape, DestAccessor> c onst & dest, triple<DestIterator, DestShape, DestAccessor> c onst & dest,
Functor const & f) Functor const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage - Standard Mode:</b> <b> Usage - Standard Mode:</b>
Source and destination array have the same size. Source and destination array have the same size.
\code \code
#include <cmath> // for sqrt() #include <cmath> // for sqrt()
typedef vigra::MultiArray<3, float> Array; MultiArray<3, float> src(Shape3(100, 200, 50)),
Array src(Array::size_type(100, 200, 50)), dest(Shape3(100, 200, 50));
dest(Array::size_type(100, 200, 50));
... ...
vigra::transformMultiArray(srcMultiArrayRange(src), transformMultiArray(src, dest, &std::sqrt );
destMultiArray(dest),
(float(*)(float))&std::sqrt );
\endcode \endcode
<b> Usage - Expand Mode:</b> <b> Usage - Expand Mode:</b>
The source array is only 2D (it has depth 1). Thus, the destination The source array is effectively only a 2D image(it has a 3D shape, but
will contain 50 identical copies of the transformed source array. depth is a singleton dimension
Note that the destination shape must be passed to the algorithm for with length 1). Thus, the destination will contain 50 identical copies
the expansion to work, so we use <tt>destMultiArrayRange()</tt> of the transformed source image.
rather than <tt>destMultiArray()</tt>.
\code \code
#include <cmath> // for sqrt() #include <cmath> // for sqrt()
typedef vigra::MultiArray<3, float> Array; MultiArray<3, float> src(Shape3(100, 200, 1)),
Array src(Array::size_type(100, 200, 1)), dest(Shape3(100, 200, 50));
dest(Array::size_type(100, 200, 50));
... ...
vigra::transformMultiArray(srcMultiArrayRange(src), transformMultiArray(src, dest, &std::sqrt );
destMultiArrayRange(dest),
(float(*)(float))&std::sqrt );
\endcode \endcode
<b> Usage - Reduce Mode:</b> <b> Usage - Reduce Mode:</b>
The destination array is only 1D (it's width and height are 1). The destination array is effectively only 1D (it's width and height are singleton dimensions).
Thus, it will contain accumulated data for every slice of the source vo lume Thus, it will contain accumulated data for every slice of the source vo lume
(or for every frame, if the source is interpreted as an image sequence) . (or for every frame, if the source is interpreted as an image sequence) .
In the example, we use the functor \ref vigra::FindAverage to calculate In the example, we use the functor \ref vigra::FindAverage to calculate
the average gray value of every slice. Note that the destination shape the average gray value of every slice.
must also be passed for the reduction to work, so we use
<tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>.
\code \code
typedef vigra::MultiArray<3, float> Array; MultiArray<3, float> src(Shape3(100, 200, 50)),
Array src(Array::size_type(100, 200, 50)), dest(Shape3(1, 1, 50));
dest(Array::size_type(1, 1, 50));
... ...
vigra::transformMultiArray(srcMultiArrayRange(src), transformMultiArray(src, dest,
destMultiArrayRange(dest), FindAverage<float>() );
vigra::FindAverage<float>() );
\endcode \endcode
Note that the functor must define the appropriate traits described belo w in order to be Note that the functor must define the appropriate traits described belo w in order to be
recognized as a reduce functor. This is most easily achieved by derivin g from recognized as a reduce functor. This is most easily achieved by derivin g from
<tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits). <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
<b> Required Interface:</b> \deprecatedUsage{transformMultiArray}
In standard and expand mode, the functor must be a model of UnaryFuncti
on
(i.e. support function call with one argument and a return value
<tt>res = functor(arg)</tt>):
\code \code
MultiIterator src_begin, src_end, dest_begin; #include <cmath> // for sqrt()
SrcAccessor src_accessor; typedef vigra::MultiArray<3, float> Array;
DestAccessor dest_accessor; Array src(Shape3(100, 200, 50)),
Functor functor; dest(Shape3(100, 200, 50));
...
vigra::transformMultiArray(srcMultiArrayRange(src),
destMultiArray(dest),
(float(*)(float))&std::sqrt );
dest_accessor.set(functor(src_accessor(src_begin)), dest_begin);
\endcode \endcode
\deprecatedEnd
<b> Required Interface:</b>
In standard and expand mode, the functor must be a model of UnaryFuncti
on
(i.e. support one-argument function call which accepts values of type
<tt>T1</tt> and a return value that is convertible into <tt>T2</tt>.
In reduce mode, it must be a model of UnaryAnalyser (i.e. support funct ion call In reduce mode, it must be a model of UnaryAnalyser (i.e. support funct ion call
with one argument and no return value <tt>functor(arg)</tt>) and Initia lizer with one argument and no return value <tt>functor(arg)</tt>) and Initia lizer
(i.e. support function call with no argument, but return value (i.e. support function call with no argument, but return value
<tt>res = functor()</tt>). Internally, such functors are recognized by the <tt>res = functor()</tt>). Internally, such functors are recognized by the
meta functions <tt>FunctorTraits<FUNCTOR>::isUnaryAnalyser</tt> and meta functions <tt>FunctorTraits<FUNCTOR>::isUnaryAnalyser</tt> and
<tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield
<tt>VigraTrueType</tt>. Make sure that your functor correctly defines <tt>VigraTrueType</tt>. Make sure that your functor correctly defines
<tt>FunctorTraits</tt> because otherwise reduce mode will not work. <tt>FunctorTraits</tt> because otherwise reduce mode will not work.
This is most easily achieved by deriving the functor from This is most easily achieved by deriving the functor from
<tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits). <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
In addition, the functor must be copy constructible in order to start e ach reduction In addition, the functor must be copy constructible in order to start e ach reduction
with a fresh functor. with a fresh functor.
\code \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
MultiIterator src_begin, src_end, dest_begin;
SrcAccessor src_accessor;
DestAccessor dest_accessor;
FUNCTOR initial_functor, functor(initial_functor);
assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTru
eType));
assert(typeid(FunctorTraits<FUNCTOR>::isUnaryAnalyser) == typeid(VigraT
rueType));
functor(src_accessor(src_begin));
dest_accessor.set(functor(), dest_begin);
\endcode
*/ */
doxygen_overloaded_function(template <...> void transformMultiArray) doxygen_overloaded_function(template <...> void transformMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
inline void inline void
transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src, transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
DestIterator d, DestAccessor dest, Functor const & f) DestIterator d, DestAccessor dest, Functor const & f)
{ {
transformMultiArrayExpandImpl(s, shape, src, d, shape, dest, transformMultiArrayExpandImpl(s, shape, src, d, shape, dest,
f, MetaInt<SrcIterator::level>()); f, MetaInt<SrcIterator::level>());
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Functor>
inline void
transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
pair<DestIterator, DestAccessor> const & dest, Functor const
& f)
{
transformMultiArray(src.first, src.second, src.third,
dest.first, dest.second, f);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void void
transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src , transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src ,
DestIterator d, DestShape const & dshape, DestAccessor dest, DestIterator d, DestShape const & dshape, DestAccessor dest,
Functor const & f) Functor const & f)
{ {
vigra_precondition(sshape.size() == dshape.size(), vigra_precondition(sshape.size() == dshape.size(),
"transformMultiArray(): dimensionality of source and destination ar ray differ"); "transformMultiArray(): dimensionality of source and destination ar ray differ");
typedef FunctorTraits<Functor> FT; typedef FunctorTraits<Functor> FT;
typedef typename typedef typename
And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::resu lt And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::resu lt
isAnalyserInitializer; isAnalyserInitializer;
transformMultiArrayImpl(s, sshape, src, d, dshape, dest, transformMultiArrayImpl(s, sshape, src, d, dshape, dest,
f, isAnalyserInitializer()); f, isAnalyserInitializer());
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor,
class Functor>
inline void
transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
pair<DestIterator, DestAccessor> const & dest, Functor
const & f)
{
transformMultiArray(src.first, src.second, src.third,
dest.first, dest.second, f);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
inline void inline void
transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src, transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
triple<DestIterator, DestShape, DestAccessor> const & dest, triple<DestIterator, DestShape, DestAccessor> const & dest,
Functor const & f) Functor const & f)
{ {
transformMultiArray(src.first, src.second, src.third, transformMultiArray(src.first, src.second, src.third,
dest.first, dest.second, dest.third, f); dest.first, dest.second, dest.third, f);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Functor>
inline void
transformMultiArrayImpl(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
Functor const & f, VigraFalseType)
{
if(source.shape() == dest.shape())
transformMultiArray(srcMultiArrayRange(source), destMultiArray(dest
), f);
else
transformMultiArray(srcMultiArrayRange(source), destMultiArrayRange
(dest), f);
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Functor>
inline void
transformMultiArrayImpl(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest,
Functor const & f, VigraTrueType)
{
transformMultiArray(srcMultiArrayRange(source), destMultiArrayRange(des
t), f);
}
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Functor>
inline void
transformMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest, Functor const & f)
{
for(unsigned int k=0; k<N; ++k)
vigra_precondition(source.shape(k) == dest.shape(k) || source.shape
(k) == 1 || 1 == dest.shape(k),
"transformMultiArray(): shape mismatch between input and output
.");
typedef FunctorTraits<Functor> FT;
typedef typename
And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::resu
lt
isAnalyserInitializer;
transformMultiArrayImpl(source, dest, f, isAnalyserInitializer());
}
/********************************************************/ /********************************************************/
/* */ /* */
/* combineTwoMultiArrays */ /* combineTwoMultiArrays */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
skipping to change at line 973 skipping to change at line 1196
"combineTwoMultiArrays(): mismatch between source and destinati on shapes:\n" "combineTwoMultiArrays(): mismatch between source and destinati on shapes:\n"
"In 'expand'-mode, the length of each source dimension must eit her be 1\n" "In 'expand'-mode, the length of each source dimension must eit her be 1\n"
"or equal to the corresponding destination length."); "or equal to the corresponding destination length.");
combineTwoMultiArraysExpandImpl(s1, sshape1, src1, s2, sshape2, src2, combineTwoMultiArraysExpandImpl(s1, sshape1, src1, s2, sshape2, src2,
d, dshape, dest, d, dshape, dest,
f, MetaInt<SrcIterator1::level>()); f, MetaInt<SrcIterator1::level>());
} }
/** \brief Combine two multi-dimensional arrays into one using a binary fun ction or functor. /** \brief Combine two multi-dimensional arrays into one using a binary fun ction or functor.
Note: The effect of this function can often be achieved in a simpler an
d
more readable way by means of \ref MultiMathModule "array experessions"
.
This function can be applied in three modes: This function can be applied in three modes:
<DL> <DL>
<DT><b>Standard Mode:</b> <DT><b>Standard Mode:</b>
<DD>If the source and destination arrays have the same size, <DD>If the source and destination arrays have the same size,
the transformation given by the functor is applied to every pair of the transformation given by the functor is applied to every pair of
corresponding source elements and the result written into the corre sponding corresponding source elements and the result written into the corre sponding
destination element. destination element.
Binary functions, binary functors from the STL and the functors spe cifically Binary functions, binary functors from the STL and the functors spe cifically
defined in \ref CombineFunctor can be used in standard mode. defined in \ref CombineFunctor can be used in standard mode.
skipping to change at line 1005 skipping to change at line 1231
The same functors as in standard mode can be applied. The same functors as in standard mode can be applied.
<DT><b>Reducing Mode:</b> <DT><b>Reducing Mode:</b>
<DD>If the destination array has length 1 along some (or even all) dimensions, <DD>If the destination array has length 1 along some (or even all) dimensions,
the source values in these dimensions are reduced to single values by means the source values in these dimensions are reduced to single values by means
of a suitable functor which supports two function call operators: o ne of a suitable functor which supports two function call operators: o ne
with two arguments to collect the values, and one without argument to with two arguments to collect the values, and one without argument to
obtain the final (reduced) result. This behavior is a multi-dimensi onal obtain the final (reduced) result. This behavior is a multi-dimensi onal
generalization of the C++ standard function <tt>std::accumulate()</ tt>. generalization of the C++ standard function <tt>std::accumulate()</ tt>.
</DL> </DL>
The arrays must be represented by The arrays must be represented by MultiArrayViews. If all shapes are id
iterators compatible with \ref vigra::MultiIterator, and the iteration entical,
range standard mode is applied. If the shapes differ, the size of correspondi
is specified by means of shape objects. If only a single source shape i ng dimensions
s given must either be equal, or the length of this dimension must be 1 in one
the destination array is assumed to have the same shape, and standard m or both source
ode arrays (expand mode), or the destination length must be 1 (reduce mode)
is applied. If three shapes are given, the size of corresponding dimens . However,
ions
must be either equal (standard copy), or the length of this dimension m
ust
be 1 in one or both source arrays
(expand mode), or the destination length must be 1 (reduce mode). Howev
er,
reduction and expansion cannot be executed at the same time, so the lat ter reduction and expansion cannot be executed at the same time, so the lat ter
conditions are mutual exclusive, even if they apply to different dimens ions. conditions are mutual exclusive, even if they apply to different dimens ions.
The function uses accessors to access the data elements.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T11, class S11,
class T12, class S12,
class T2, class S2,
class Functor>
void
combineTwoMultiArrays(MultiArrayView<N, T11, S11> const & source1,
MultiArrayView<N, T12, S12> const & source2,
MultiArrayView<N, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{combineTwoMultiArrays}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
void combineTwoMultiArrays( void combineTwoMultiArrays(
SrcIterator1 s1, SrcShape const & shape, SrcAccessor 1 src1, SrcIterator1 s1, SrcShape const & shape, SrcAccessor 1 src1,
SrcIterator2 s2, SrcAccessor2 src2, SrcIterator2 s2, SrcAccessor2 src2,
DestIterator d, DestAccessor dest, Functor const & f ); DestIterator d, DestAccessor dest, Functor const & f );
skipping to change at line 1046 skipping to change at line 1282
class SrcIterator2, class SrcShape2, class SrcAccessor2, class SrcIterator2, class SrcShape2, class SrcAccessor2,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void combineTwoMultiArrays( void combineTwoMultiArrays(
SrcIterator1 s1, SrcShape1 const & sshape1, SrcAcces sor1 src1, SrcIterator1 s1, SrcShape1 const & sshape1, SrcAcces sor1 src1,
SrcIterator2 s2, SrcShape2 const & sshape2, SrcAcces sor2 src2, SrcIterator2 s2, SrcShape2 const & sshape2, SrcAcces sor2 src2,
DestIterator d, DestShape const & dshape, DestAccess or dest, DestIterator d, DestShape const & dshape, DestAccess or dest,
Functor const & f); Functor const & f);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class DestIterator, class DestAccessor, class Functor> class DestIterator, class DestAccessor, class Functor>
void combineTwoMultiArrays( void combineTwoMultiArrays(
triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1, triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
pair<SrcIterator2, SrcAccessor2> const & src2, pair<SrcIterator2, SrcAccessor2> const & src2,
pair<DestIterator, DestAccessor> const & dest, Funct or const & f); pair<DestIterator, DestAccessor> const & dest, Funct or const & f);
skipping to change at line 1069 skipping to change at line 1304
class SrcIterator2, class SrcShape2, class SrcAccessor2, class SrcIterator2, class SrcShape2, class SrcAccessor2,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void combineTwoMultiArrays( void combineTwoMultiArrays(
triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1, triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2, triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
triple<DestIterator, DestShape, DestAccessor> const & dest, triple<DestIterator, DestShape, DestAccessor> const & dest,
Functor const & f); Functor const & f);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage - Standard Mode:</b> <b> Usage - Standard Mode:</b>
Source and destination arrays have the same size. Source and destination arrays have the same size.
\code \code
#include <functional> // for std::plus #include <functional> // for std::plus
typedef vigra::MultiArray<3, int> Array; MultiArray<3, int> src1(Shape3(100, 200, 50)),
Array src1(Array::size_type(100, 200, 50)), src2(Shape3(100, 200, 50)),
src2(Array::size_type(100, 200, 50)), dest(Shape3(100, 200, 50));
dest(Array::size_type(100, 200, 50));
... ...
vigra::combineTwoMultiArrays( combineTwoMultiArrays(src1, src2, dest,
srcMultiArrayRange(src1), std::plus<int>());
srcMultiArray(src2),
destMultiArray(dest),
std::plus<int>());
\endcode \endcode
<b> Usage - Expand Mode:</b> <b> Usage - Expand Mode:</b>
One source array is only 2D (it has depth 1). This image will be added One source array is effectively only a 2D image (it has depth 1). This
to every slice of the other source array, and the result image will be added
if written into the corresponding destination slice. Note that the shap to every slice of the other source array, and the result is written int
es o the
of all arrays must be passed to the algorithm, so we use corresponding destination slice.
<tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt>
rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
\code \code
#include <functional> // for std::plus #include <functional> // for std::plus
typedef vigra::MultiArray<3, int> Array; MultiArray<3, int> src1(Shape3(100, 200, 1)),
Array src1(Array::size_type(100, 200, 1)), src2(Shape3(100, 200, 50)),
src2(Array::size_type(100, 200, 50)), dest(Shape3(100, 200, 50));
dest(Array::size_type(100, 200, 50));
... ...
vigra::combineTwoMultiArrays( combineTwoMultiArrays(src1, src2, dest,
srcMultiArrayRange(src1), std::plus<int>());
srcMultiArray(src2),
destMultiArray(dest),
std::plus<int>());
\endcode \endcode
<b> Usage - Reduce Mode:</b> <b> Usage - Reduce Mode:</b>
The destination array is only 1D (it's width and height are 1). The destination array is only 1D (it's width and height are singleton d imensions).
Thus, it will contain accumulated data for every slice of the source vo lumes Thus, it will contain accumulated data for every slice of the source vo lumes
(or for every frame, if the sources are interpreted as image sequences) . (or for every frame, if the sources are interpreted as image sequences) .
In the example, we use \ref vigra::ReduceFunctor together with a functo r In the example, we use \ref vigra::ReduceFunctor together with a functo r
expression (see \ref FunctorExpressions) expression (see \ref FunctorExpressions) to calculate the total absolut
to calculate the total absolute difference of the gray values in every e difference
pair of of the gray values in every pair of source slices.
source slices. Note that the shapes of all arrays must be passed
to the algorithm in order for the reduction to work, so we use
<tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt>
rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
\code \code
#include <vigra/functorexpression.hxx> #include <vigra/functorexpression.hxx>
using namespace vigra::functor; using namespace vigra::functor;
typedef vigra::MultiArray<3, int> Array; MultiArray<3, int> src1(Shape3(100, 200, 50)),
Array src1(Array::size_type(100, 200, 50)), src2(Shape3(100, 200, 50)),
src2(Array::size_type(100, 200, 50)), dest(Shape3(1, 1, 50));
dest(Array::size_type(1, 1, 50));
... ...
vigra::combineTwoMultiArrays( combineTwoMultiArrays(src1, src2, dest,
srcMultiArrayRange(src1), reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) )
srcMultiArray(src2), ;
destMultiArray(dest), // Arg1() is the sum accumulated so far, initiali
reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) ); zed with 0
// Arg1() is the sum accumulated so far, initialized with 0
\endcode \endcode
Note that the functor must define the appropriate traits described belo w in order to be Note that the functor must define the appropriate traits described belo w in order to be
recognized as a reduce functor. This is most easily achieved by derivin g from recognized as a reduce functor. This is most easily achieved by derivin g from
<tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits). <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
<b> Required Interface:</b> \deprecatedUsage{combineTwoMultiArrays}
In standard and expand mode, the functor must be a model of BinaryFunct
ion
(i.e. support function call with two arguments and a return value
<tt>res = functor(arg1, arg2)</tt>):
\code \code
MultiIterator src1_begin, src2_begin, dest_begin; #include <functional> // for std::plus
SrcAccessor1 src1_accessor; typedef vigra::MultiArray<3, int> Array;
SrcAccessor2 src2_accessor; Array src1(Shape3(100, 200, 50)),
DestAccessor dest_accessor; src2(Shape3(100, 200, 50)),
dest(Shape3(100, 200, 50));
...
Functor functor; vigra::combineTwoMultiArrays(
srcMultiArrayRange(src1),
srcMultiArray(src2),
destMultiArray(dest),
std::plus<int>());
\endcode
\deprecatedEnd
dest_accessor.set( <b> Required Interface:</b>
functor(src1_accessor(src1_begin), src2_accessor(src2_begin)),
dest_begin);
\endcode In standard and expand mode, the functor must be a model of BinaryFunct
ion
(i.e. support function call with two arguments and a return value which
is convertible
into <tt>T2</tt>: <tt>T2 res = functor(arg1, arg2)</tt>):
In reduce mode, it must be a model of BinaryAnalyser (i.e. support func tion call In reduce mode, it must be a model of BinaryAnalyser (i.e. support func tion call
with two arguments and no return value <tt>functor(arg1, arg2)</tt>) an d Initializer with two arguments and no return value <tt>functor(arg1, arg2)</tt>) an d Initializer
(i.e. support function call with no argument, but return value (i.e. support function call with no argument, but return value
<tt>res = functor()</tt>). Internally, such functors are recognized by the <tt>res = functor()</tt>). Internally, such functors are recognized by the
meta functions <tt>FunctorTraits<FUNCTOR>::isBinaryAnalyser</tt> and meta functions <tt>FunctorTraits<FUNCTOR>::isBinaryAnalyser</tt> and
<tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield
<tt>VigraTrueType</tt>. Make sure that your functor correctly defines <tt>VigraTrueType</tt>. Make sure that your functor correctly defines
<tt>FunctorTraits</tt> because otherwise reduce mode will not work. <tt>FunctorTraits</tt> because otherwise reduce mode will not work.
This is most easily achieved by deriving the functor from This is most easily achieved by deriving the functor from
<tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits). <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
In addition, the functor must be copy constructible in order to start e ach reduction In addition, the functor must be copy constructible in order to start e ach reduction
with a fresh functor. with a fresh functor.
\code \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
MultiIterator src1_begin, src2_begin, dest_begin;
SrcAccessor1 src1_accessor;
SrcAccessor2 src2_accessor;
DestAccessor dest_accessor;
FUNCTOR initial_functor, functor(initial_functor);
assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTru
eType));
assert(typeid(FunctorTraits<FUNCTOR>::isBinaryAnalyser) == typeid(Vigra
TrueType));
functor(src1_accessor(src1_begin), src2_accessor(src2_begin));
dest_accessor.set(functor(), dest_begin);
\endcode
*/ */
doxygen_overloaded_function(template <...> void combineTwoMultiArrays) doxygen_overloaded_function(template <...> void combineTwoMultiArrays)
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
inline void inline void
combineTwoMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1, combineTwoMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
SrcIterator2 s2, SrcAccessor2 src2, SrcIterator2 s2, SrcAccessor2 src2,
DestIterator d, DestAccessor dest, Functor const & f) DestIterator d, DestAccessor dest, Functor const & f)
{ {
combineTwoMultiArraysExpandImpl(s1, shape, src1, s2, shape, src2, d, sh ape, dest, f, combineTwoMultiArraysExpandImpl(s1, shape, src1, s2, shape, src2, d, sh ape, dest, f,
MetaInt<SrcIterator1::level>()); MetaInt<SrcIterator1::level>());
} }
template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2,
class DestIterator, class DestAccessor, class Functor>
inline void
combineTwoMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const &
src1,
pair<SrcIterator2, SrcAccessor2> const & src2,
pair<DestIterator, DestAccessor> const & dest, Functor const
& f)
{
combineTwoMultiArrays(
src1.first, src1.second, src1.third,
src2.first, src2.second, dest.first, dest.second, f);
}
template <class SrcIterator1, class SrcShape1, class SrcAccessor1, template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
class SrcIterator2, class SrcShape2, class SrcAccessor2, class SrcIterator2, class SrcShape2, class SrcAccessor2,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
void void
combineTwoMultiArrays( combineTwoMultiArrays(
SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src 1, SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src 1,
SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src 2, SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src 2,
DestIterator d, DestShape const & dshape, DestAccessor dest, DestIterator d, DestShape const & dshape, DestAccessor dest,
Functor const & f) Functor const & f)
skipping to change at line 1254 skipping to change at line 1443
"combineTwoMultiArrays(): dimensionality of source and destination arrays differ"); "combineTwoMultiArrays(): dimensionality of source and destination arrays differ");
typedef FunctorTraits<Functor> FT; typedef FunctorTraits<Functor> FT;
typedef typename typedef typename
And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::res ult And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::res ult
isAnalyserInitializer; isAnalyserInitializer;
combineTwoMultiArraysImpl(s1, sshape1, src1, s2, sshape2, src2, d, dsha pe, dest, combineTwoMultiArraysImpl(s1, sshape1, src1, s2, sshape2, src2, d, dsha pe, dest,
f, isAnalyserInitializer()); f, isAnalyserInitializer());
} }
template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2,
class DestIterator, class DestAccessor, class Functor>
inline void
combineTwoMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const &
src1,
pair<SrcIterator2, SrcAccessor2> const & src2,
pair<DestIterator, DestAccessor> const & dest,
Functor const & f)
{
combineTwoMultiArrays(
src1.first, src1.second, src1.third,
src2.first, src2.second, dest.first, dest.second, f);
}
template <class SrcIterator1, class SrcShape1, class SrcAccessor1, template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
class SrcIterator2, class SrcShape2, class SrcAccessor2, class SrcIterator2, class SrcShape2, class SrcAccessor2,
class DestIterator, class DestShape, class DestAccessor, class DestIterator, class DestShape, class DestAccessor,
class Functor> class Functor>
inline void inline void
combineTwoMultiArrays( combineTwoMultiArrays(triple<SrcIterator1, SrcShape1, SrcAccessor1> const &
triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1, src1,
triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2, triple<SrcIterator2, SrcShape2, SrcAccessor2> const &
triple<DestIterator, DestShape, DestAccessor> const & dest, src2,
Functor const & f) triple<DestIterator, DestShape, DestAccessor> const &
dest,
Functor const & f)
{ {
combineTwoMultiArrays(src1.first, src1.second, src1.third, combineTwoMultiArrays(src1.first, src1.second, src1.third,
src2.first, src2.second, src2.third, src2.first, src2.second, src2.third,
dest.first, dest.second, dest.third, f); dest.first, dest.second, dest.third, f);
} }
template <unsigned int N, class T11, class S11,
class T12, class S12,
class T2, class S2,
class Functor>
inline void
combineTwoMultiArraysImpl(MultiArrayView<N, T11, S11> const & source1,
MultiArrayView<N, T12, S12> const & source2,
MultiArrayView<N, T2, S2> dest,
Functor const & f, VigraFalseType)
{
if(source1.shape() == source2.shape() && source1.shape() == dest.shape(
))
combineTwoMultiArrays(srcMultiArrayRange(source1),
srcMultiArray(source2), destMultiArray(dest),
f);
else
combineTwoMultiArrays(srcMultiArrayRange(source1),
srcMultiArrayRange(source2),
destMultiArrayRange(dest), f);
}
template <unsigned int N, class T11, class S11,
class T12, class S12,
class T2, class S2,
class Functor>
inline void
combineTwoMultiArraysImpl(MultiArrayView<N, T11, S11> const & source1,
MultiArrayView<N, T12, S12> const & source2,
MultiArrayView<N, T2, S2> dest,
Functor const & f, VigraTrueType)
{
combineTwoMultiArrays(srcMultiArrayRange(source1),
srcMultiArrayRange(source2),
destMultiArrayRange(dest), f);
}
template <unsigned int N, class T11, class S11,
class T12, class S12,
class T2, class S2,
class Functor>
inline void
combineTwoMultiArrays(MultiArrayView<N, T11, S11> const & source1,
MultiArrayView<N, T12, S12> const & source2,
MultiArrayView<N, T2, S2> dest,
Functor const & f)
{
for(unsigned int k=0; k<N; ++k)
vigra_precondition((source1.shape(k) == source2.shape(k) || source1
.shape(k) == 1 || 1 == source2.shape(k)) &&
(source1.shape(k) == dest.shape(k) || source1.sh
ape(k) == 1 || 1 == dest.shape(k)),
"combineTwoMultiArrays(): shape mismatch between inputs and/or
output.");
typedef FunctorTraits<Functor> FT;
typedef typename
And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::res
ult
isAnalyserInitializer;
combineTwoMultiArraysImpl(source1, source2, dest, f, isAnalyserInitiali
zer());
}
/********************************************************/ /********************************************************/
/* */ /* */
/* combineThreeMultiArrays */ /* combineThreeMultiArrays */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class SrcIterator3, class SrcAccessor3, class SrcIterator3, class SrcAccessor3,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
skipping to change at line 1314 skipping to change at line 1575
{ {
combineThreeMultiArraysImpl(s1.begin(), shape, src1, combineThreeMultiArraysImpl(s1.begin(), shape, src1,
s2.begin(), src2, s3.begin(), src3, d.beg in(), dest, s2.begin(), src2, s3.begin(), src3, d.beg in(), dest,
f, MetaInt<N-1>()); f, MetaInt<N-1>());
} }
} }
/** \brief Combine three multi-dimensional arrays into one using a /** \brief Combine three multi-dimensional arrays into one using a
ternary function or functor. ternary function or functor.
Note: The effect of this function can often be achieved in a simpler an
d
more readable way by means of \ref MultiMathModule "array experessions"
.
Except for the fact that it operates on three input arrays, this functi on is Except for the fact that it operates on three input arrays, this functi on is
identical to \ref combineTwoMultiArrays(). identical to the standard mode of \ref combineTwoMultiArrays() (reduce
and expand
modes are not supported).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T11, class S11,
class T12, class S12,
class T13, class S13,
class T2, class S2,
class Functor>
void
combineThreeMultiArrays(MultiArrayView<N, T11, S11> const & source1
,
MultiArrayView<N, T12, S12> const & source2
,
MultiArrayView<N, T13, S13> const & source3
,
MultiArrayView<N, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{combineThreeMultiArrays}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class SrcIterator3, class SrcAccessor3, class SrcIterator3, class SrcAccessor3,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
void void
combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, Sr cAccessor1 src1, combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, Sr cAccessor1 src1,
SrcIterator2 s2, SrcAccessor2 src2, SrcIterator2 s2, SrcAccessor2 src2,
SrcIterator3 s3, SrcAccessor3 src3, SrcIterator3 s3, SrcAccessor3 src3,
DestIterator d, DestAccessor dest, Functor const & f ); DestIterator d, DestAccessor dest, Functor const & f );
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class SrcIterator3, class SrcAccessor3, class SrcIterator3, class SrcAccessor3,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
inline void inline void
combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1 > const & src1, combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1 > const & src1,
pair<SrcIterator2, SrcAccessor2> const & src2, pair<SrcIterator2, SrcAccessor2> const & src2,
pair<SrcIterator3, SrcAccessor3> const & src3, pair<SrcIterator3, SrcAccessor3> const & src3,
pair<DestIterator, DestAccessor> const & dest, Funct or const & f); pair<DestIterator, DestAccessor> const & dest, Funct or const & f);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <vigra/functorexpression.hxx>
MultiArray<3, int> src1(Shape3(100, 200, 50)),
src2(Shape3(100, 200, 50)),
src3(Shape3(100, 200, 50)),
dest(Shape3(100, 200, 50));
...
using namespace vigra::functor; // activate VIGRA's lambda library
combineThreeMultiArrays(src1, src2, src3, dest,
Arg1()*exp(-abs(Arg2()-Arg3())));
\endcode
\deprecatedUsage{combineThreeMultiArrays}
\code
#include <functional> // for plus #include <functional> // for plus
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array src1(Array::size_type(100, 200, 50)), Array src1(Shape3(100, 200, 50)),
src2(Array::size_type(100, 200, 50)), src2(Shape3(100, 200, 50)),
src3(Array::size_type(100, 200, 50)), src3(Shape3(100, 200, 50)),
dest(Array::size_type(100, 200, 50)); dest(Shape3(100, 200, 50));
... ...
vigra::combineThreeMultiArrays( vigra::combineThreeMultiArrays(
srcMultiArrayRange(src1), srcMultiArrayRange(src1),
srcMultiArray(src2), srcMultiArray(src2),
srcMultiArray(src3), srcMultiArray(src3),
destMultiArray(dest), destMultiArray(dest),
SomeThreeArgumentFunctor()); SomeThreeArgumentFunctor());
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void combineThreeMultiArrays) doxygen_overloaded_function(template <...> void combineThreeMultiArrays)
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class SrcIterator3, class SrcAccessor3, class SrcIterator3, class SrcAccessor3,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
inline void inline void
combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccesso r1 src1, combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccesso r1 src1,
skipping to change at line 1399 skipping to change at line 1700
MetaInt<SrcIterator1::level>()); MetaInt<SrcIterator1::level>());
} }
template <class SrcIterator1, class SrcShape, class SrcAccessor1, template <class SrcIterator1, class SrcShape, class SrcAccessor1,
class SrcIterator2, class SrcAccessor2, class SrcIterator2, class SrcAccessor2,
class SrcIterator3, class SrcAccessor3, class SrcIterator3, class SrcAccessor3,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Functor> class Functor>
inline void inline void
combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1, combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
pair<SrcIterator2, SrcAccessor2> const & src2, pair<SrcIterator2, SrcAccessor2> const & src2,
pair<SrcIterator3, SrcAccessor3> const & src3, pair<SrcIterator3, SrcAccessor3> const & src3,
pair<DestIterator, DestAccessor> const & dest, Functor const pair<DestIterator, DestAccessor> const & dest, Func
& f) tor const & f)
{ {
combineThreeMultiArrays( combineThreeMultiArrays(
src1.first, src1.second, src1.third, src1.first, src1.second, src1.third,
src2.first, src2.second, src3.first, src3.second, dest.first, de st.second, f); src2.first, src2.second, src3.first, src3.second, dest.first, de st.second, f);
} }
template <unsigned int N, class T11, class S11,
class T12, class S12,
class T13, class S13,
class T2, class S2,
class Functor>
inline void
combineThreeMultiArrays(MultiArrayView<N, T11, S11> const & source1,
MultiArrayView<N, T12, S12> const & source2,
MultiArrayView<N, T13, S13> const & source3,
MultiArrayView<N, T2, S2> dest, Functor const & f)
{
vigra_precondition(source1.shape() == source2.shape() && source1.shape(
) == source3.shape() && source1.shape() == dest.shape(),
"combineThreeMultiArrays(): shape mismatch between inputs and/or ou
tput.");
combineThreeMultiArrays(
srcMultiArrayRange(source1),
srcMultiArray(source2), srcMultiArray(source3), destMultiArray(d
est), f);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectMultiArray */ /* inspectMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
template <class Iterator, class Shape, class Accessor, class Functor> template <class Iterator, class Shape, class Accessor, class Functor>
inline void inline void
inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, Functor & f, MetaInt<0>) inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, Functor & f, MetaInt<0>)
{ {
skipping to change at line 1437 skipping to change at line 1757
for(; s < send; ++s) for(; s < send; ++s)
{ {
inspectMultiArrayImpl(s.begin(), shape, a, f, MetaInt<N-1>()); inspectMultiArrayImpl(s.begin(), shape, a, f, MetaInt<N-1>());
} }
} }
/** \brief Call an analyzing functor at every element of a multi-dimensiona l array. /** \brief Call an analyzing functor at every element of a multi-dimensiona l array.
This function can be used to collect statistics of the array etc. This function can be used to collect statistics of the array etc.
The results must be stored in the functor, which serves as a return The results must be stored in the functor, which serves as a return
value. The arrays must be represented by value (therefore, it is passed to the function by reference). The array
iterators compatible with \ref vigra::MultiIterator. must be
The function uses an accessor to access the pixel data. Note that the i represented as a MultiArrayView.
terator range
must be specified by a shape object, because otherwise we could not con For many common statistics, the use of \ref vigra::acc::extractFeature
trol s() in combination with
the range simultaneously in all dimensions (this is a necessary consequ \ref FeatureAccumulators is more convenient.
ence
of the \ref vigra::MultiIterator design).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T, class S,
class Functor>
void
inspectMultiArray(MultiArrayView<N, T, S> const & s,
Functor & f);
}
\endcode
\deprecatedAPI{inspectMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Shape, class Accessor, class Functo r> template <class Iterator, class Shape, class Accessor, class Functo r>
void void
inspectMultiArray(Iterator s, Shape const & shape, Accessor a, Fun ctor & f); inspectMultiArray(Iterator s, Shape const & shape, Accessor a, Fun ctor & f);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class Iterator, class Shape, class Accessor, class Functo r> template <class Iterator, class Shape, class Accessor, class Functo r>
void void
inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Func tor & f); inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Func tor & f);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<3, int> array(Shape3(100, 200, 50));
... // fill array
// init functor
FindMinMax<int> minmax;
inspectMultiArray(array, minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max;
\endcode
The functor must support function call with one argument.
\deprecatedUsage{inspectMultiArray}
\code
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array array(Array::size_type(100, 200, 50)); Array array(Shape3(100, 200, 50));
// init functor // init functor
vigra::FindMinMax<int> minmax; vigra::FindMinMax<int> minmax;
vigra::inspectMultiArray(srcMultiArrayRange(array), minmax); vigra::inspectMultiArray(srcMultiArrayRange(array), minmax);
cout << "Min: " << minmax.min << " Max: " << minmax.max; cout << "Min: " << minmax.min << " Max: " << minmax.max;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
MultiIterator src_begin; MultiIterator src_begin;
Accessor accessor; Accessor accessor;
Functor functor; Functor functor;
functor(accessor(src_begin)); functor(accessor(src_begin));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void inspectMultiArray) doxygen_overloaded_function(template <...> void inspectMultiArray)
template <class Iterator, class Shape, class Accessor> template <class Iterator, class Shape, class Accessor>
struct inspectMultiArray_binder struct inspectMultiArray_binder
{ {
Iterator s; Iterator s;
const Shape & shape; const Shape & shape;
Accessor a; Accessor a;
inspectMultiArray_binder(Iterator s_, const Shape & shape_, Accessor a_ ) inspectMultiArray_binder(Iterator s_, const Shape & shape_, Accessor a_ )
skipping to change at line 1526 skipping to change at line 1869
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
template <class Iterator, class Shape, class Accessor, class Functor> template <class Iterator, class Shape, class Accessor, class Functor>
inline void inline void
inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f) inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f)
{ {
inspectMultiArray(s.first, s.second, s.third, f); inspectMultiArray(s.first, s.second, s.third, f);
} }
template <unsigned int N, class T, class S, class Functor>
inline void
inspectMultiArray(MultiArrayView<N, T, S> const & s, Functor & f)
{
inspectMultiArray(srcMultiArrayRange(s), f);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* inspectTwoMultiArrays */ /* inspectTwoMultiArrays */
/* */ /* */
/********************************************************/ /********************************************************/
template <class Iterator1, class Shape, class Accessor1, template <class Iterator1, class Shape, class Accessor1,
class Iterator2, class Accessor2, class Iterator2, class Accessor2,
class Functor> class Functor>
inline void inline void
skipping to change at line 1562 skipping to change at line 1912
for(; s1 < s1end; ++s1, ++s2) for(; s1 < s1end; ++s1, ++s2)
{ {
inspectTwoMultiArraysImpl(s1.begin(), shape, a1, inspectTwoMultiArraysImpl(s1.begin(), shape, a1,
s2.begin(), a2, f, MetaInt<N-1>()); s2.begin(), a2, f, MetaInt<N-1>());
} }
} }
/** \brief Call an analyzing functor at all corresponding elements of /** \brief Call an analyzing functor at all corresponding elements of
two multi-dimensional arrays. two multi-dimensional arrays.
This function can be used to collect statistics of the array etc. This function can be used to collect statistics over tow arrays.
For example, one can holde data, and the other region labels or weights
.
The results must be stored in the functor, which serves as a return The results must be stored in the functor, which serves as a return
value. The arrays must be represented by value (and is therefore passed by reference). The arrays must be repres
iterators compatible with \ref vigra::MultiIterator. ented by
The function uses an accessor to access the pixel data. Note that the i MultiArrayViews.
terator range
must be specified by a shape object, because otherwise we could not con For many common statistics, the use of \ref vigra::acc::extractFeature
trol s() in combination with
the range simultaneously in all dimensions (this is a necessary consequ \ref FeatureAccumulators is more convenient.
ence
of the \ref vigra::MultiIterator design).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Functor>
void
inspectTwoMultiArrays(MultiArrayView<N, T1, S1> const & s1,
MultiArrayView<N, T2, S2> const & s2,
Functor & f);
}
\endcode
\deprecatedAPI{inspectTwoMultiArrays}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class Iterator1, class Shape, class Accessor1, template <class Iterator1, class Shape, class Accessor1,
class Iterator2, class Accessor2, class Iterator2, class Accessor2,
class Functor> class Functor>
void void
inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1, inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
Iterator2 s2, Accessor2 a2, Functor & f); Iterator2 s2, Accessor2 a2, Functor & f);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class Iterator1, class Shape1, class Accessor1, template <class Iterator1, class Shape1, class Accessor1,
class Iterator2, class Accessor2, class Iterator2, class Accessor2,
class Functor> class Functor>
void void
inspectTwoMultiArrays(triple<Iterator1, Shape1, Accessor1> const & s1, inspectTwoMultiArrays(triple<Iterator1, Shape1, Accessor1> const & s1,
pair<Iterator2, Accessor2> const & s2, Functo r & f); pair<Iterator2, Accessor2> const & s2, Functo r & f);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_pointoperators.hxx\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, int> Array; MultiArray<3, int> array1(Shape3(100, 200, 50)),
Array array1(Array::size_type(100, 200, 50)), array2(Shape3(100, 200, 50));
array2(Array::size_type(100, 200, 50));
// init functor // init functor
SomeStatisticsFunctor stats(..); SomeStatisticsFunctor stats(..);
vigra::inspectTwoMultiArrays(srcMultiArrayRange(array1), srcMultiArray( inspectTwoMultiArrays(array1, array2, stats);
array2), stats);
\endcode \endcode
The functor must support function call with two arguments.
<b> Required Interface:</b> \deprecatedUsage{inspectTwoMultiArrays}
\code
MultiArray<3, int> array1(Shape3(100, 200, 50)),
array2(Shape3(100, 200, 50));
// init functor
SomeStatisticsFunctor stats(..);
vigra::inspectTwoMultiArrays(srcMultiArrayRange(array1), srcMultiArray(
array2), stats);
\endcode
<b> Required Interface:</b>
\code \code
MultiIterator src1_begin, src2_begin; MultiIterator src1_begin, src2_begin;
Accessor a1, a2; Accessor a1, a2;
Functor functor; Functor functor;
functor(a1(src1_begin), a2(src2_begin)); functor(a1(src1_begin), a2(src2_begin));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void inspectTwoMultiArrays) doxygen_overloaded_function(template <...> void inspectTwoMultiArrays)
template <class Iterator1, class Shape, class Accessor1, template <class Iterator1, class Shape, class Accessor1,
class Iterator2, class Accessor2> class Iterator2, class Accessor2>
struct inspectTwoMultiArrays_binder struct inspectTwoMultiArrays_binder
{ {
Iterator1 s1; Iterator1 s1;
const Shape & shape; const Shape & shape;
Accessor1 a1; Accessor1 a1;
skipping to change at line 1664 skipping to change at line 2036
{ {
inspectTwoMultiArrays_binder<Iterator1, Shape, Accessor1, inspectTwoMultiArrays_binder<Iterator1, Shape, Accessor1,
Iterator2, Accessor2> Iterator2, Accessor2>
g(s1, shape, a1, s2, a2); g(s1, shape, a1, s2, a2);
detail::extra_passes_select(g, f); detail::extra_passes_select(g, f);
} }
template <class Iterator1, class Shape, class Accessor1, template <class Iterator1, class Shape, class Accessor1,
class Iterator2, class Accessor2, class Iterator2, class Accessor2,
class Functor> class Functor>
inline inline void
void
inspectTwoMultiArrays(triple<Iterator1, Shape, Accessor1> const & s1, inspectTwoMultiArrays(triple<Iterator1, Shape, Accessor1> const & s1,
pair<Iterator2, Accessor2> const & s2, Functor & f) pair<Iterator2, Accessor2> const & s2, Functor & f)
{ {
inspectTwoMultiArrays(s1.first, s1.second, s1.third, inspectTwoMultiArrays(s1.first, s1.second, s1.third,
s2.first, s2.second, f); s2.first, s2.second, f);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Functor>
inline void
inspectTwoMultiArrays(MultiArrayView<N, T1, S1> const & s1,
MultiArrayView<N, T2, S2> const & s2, Functor & f)
{
vigra_precondition(s1.shape() == s2.shape(),
"inspectTwoMultiArrays(): shape mismatch between inputs.");
inspectTwoMultiArrays(srcMultiArrayRange(s1),
srcMultiArray(s2), f);
}
//@} //@}
} //-- namespace vigra } //-- namespace vigra
#endif //-- VIGRA_MULTI_POINTOPERATORS_H #endif //-- VIGRA_MULTI_POINTOPERATORS_H
 End of changes. 124 change blocks. 
327 lines changed or deleted 754 lines changed or added


 multi_resize.hxx   multi_resize.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MULTI_RESIZE_HXX #ifndef VIGRA_MULTI_RESIZE_HXX
#define VIGRA_MULTI_RESIZE_HXX #define VIGRA_MULTI_RESIZE_HXX
#include <vector> #include <vector>
#include "resizeimage.hxx" #include "resizeimage.hxx"
#include "navigator.hxx" #include "navigator.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
template <class SrcIterator, class Shape, class SrcAccessor, template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor, class Kernel> class DestIterator, class DestAccessor, class Kernel>
void void
internalResizeMultiArrayOneDimension( internalResizeMultiArrayOneDimension(
SrcIterator si, Shape const & sshape, SrcAccessor src , SrcIterator si, Shape const & sshape, SrcAccessor src ,
skipping to change at line 118 skipping to change at line 119
/***************************************************************/ /***************************************************************/
/* */ /* */
/* resizeMultiArraySplineInterpolation */ /* resizeMultiArraySplineInterpolation */
/* */ /* */
/***************************************************************/ /***************************************************************/
/** \brief Resize MultiArray using B-spline interpolation. /** \brief Resize MultiArray using B-spline interpolation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2,
class Kernel = BSpline<3, double> >
void
resizeMultiArraySplineInterpolation(MultiArrayView<N, T1, S1> const
& source,
MultiArrayView<N, T2, S2> dest,
Kernel const & spline = BSpline
<3, double>());
}
\endcode
\deprecatedAPI{resizeMultiArraySplineInterpolation}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class Shape, class SrcAccessor, template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Kernel = BSpline<3, double> > class Kernel = BSpline<3, double> >
void void
resizeMultiArraySplineInterpolation( resizeMultiArraySplineInterpolation(
SrcIterator si, Shape const & sshape, SrcAcce ssor src, SrcIterator si, Shape const & sshape, SrcAcce ssor src,
DestIterator di, Shape const & dshape, DestAc cessor dest, DestIterator di, Shape const & dshape, DestAc cessor dest,
Kernel const & spline = BSpline<3, double>()) ; Kernel const & spline = BSpline<3, double>()) ;
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class Shape, class SrcAccessor, template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Kernel = BSpline<3, double> > class Kernel = BSpline<3, double> >
void void
resizeMultiArraySplineInterpolation( resizeMultiArraySplineInterpolation(
triple<SrcIterator, Shape, SrcAccessor> src, triple<SrcIterator, Shape, SrcAccessor> src,
triple<DestIterator, Shape, DestAccessor> des t, triple<DestIterator, Shape, DestAccessor> des t,
Kernel const & spline = BSpline<3, double>()) ; Kernel const & spline = BSpline<3, double>()) ;
} }
\endcode \endcode
\deprecatedEnd
The function implements separable spline interpolation algorithm descri bed in The function implements separable spline interpolation algorithm descri bed in
M. Unser, A. Aldroubi, M. Eden, <i>"B-Spline Signal Processing"</i> M. Unser, A. Aldroubi, M. Eden, <i>"B-Spline Signal Processing"</i>
IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 821-833 (pa rt I), IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 821-833 (pa rt I),
pp. 834-848 (part II), 1993. pp. 834-848 (part II), 1993.
to obtain optimal interpolation quality and speed. You may pass the fun ction to obtain optimal interpolation quality and speed. You may pass the fun ction
a spline of arbitrary order (e.g. <TT>BSpline<ORDER, double></tt> or a spline of arbitrary order (e.g. <TT>BSpline<ORDER, double></tt> or
<TT>CatmullRomSpline<double></tt>). The default is a third order spline <TT>CatmullRomSpline<double></tt>). The default is a third order spline
skipping to change at line 174 skipping to change at line 189
accordingly. If the source image is larger than the destination, it accordingly. If the source image is larger than the destination, it
is smoothed (band limited) using a recursive is smoothed (band limited) using a recursive
exponential filter. The source value_type (SrcAccessor::value_type) mus t exponential filter. The source value_type (SrcAccessor::value_type) mus t
be a linear algebra, i.e. it must support addition, subtraction, be a linear algebra, i.e. it must support addition, subtraction,
and multiplication (+, -, *), multiplication with a scalar and multiplication (+, -, *), multiplication with a scalar
real number and \ref NumericTraits "NumericTraits". real number and \ref NumericTraits "NumericTraits".
The function uses accessors. The function uses accessors.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_resize.hxx\><br> <b>\#include</b> \<vigra/multi_resize.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<3, float> src(Shape3(5, 7, 10)),
dest(Shape3(9, 13, 19)); // double the size
// use default cubic spline interpolator
resizeMultiArraySplineInterpolation(src, dest);
// use linear interpolator
resizeMultiArraySplineInterpolation(src, dest, BSpline<1, double>());
\endcode
\deprecatedUsage{resizeMultiArraySplineInterpolation}
\code \code
typedef vigra::MultiArray<3, float>::difference_type Shape; vigra::MultiArray<3, float> src(Shape3(5, 7, 10)),
vigra::MultiArray<3, float> src(Shape(5, 7, 10)), dest(Shape3(9, 13, 19)); // double the size
dest(Shape(9, 13, 19)); // double the size
// use linear interpolator
vigra::resizeMultiArraySplineInterpolation(srcMultiArrayRange(src),
destMultiArrayRange(dest), BSpline<1, double>());
// use default cubic spline interpolator // use default cubic spline interpolator
vigra::resizeMultiArraySplineInterpolation( vigra::resizeMultiArraySplineInterpolation(
srcMultiArrayRange(src), srcMultiArrayRange(src),
destMultiArrayRange(dest)); destMultiArrayRange(dest));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
The source and destination iterators must be compatible with \ref vigra ::MultiIterator. The array value The source and destination iterators must be compatible with \ref vigra ::MultiIterator. The array value
types must be models of \ref LinearSpace. types must be models of \ref LinearSpace.
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void resizeMultiArraySplineInter polation) doxygen_overloaded_function(template <...> void resizeMultiArraySplineInter polation)
template <class SrcIterator, class Shape, class SrcAccessor, template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Kernel> class Kernel>
void void
resizeMultiArraySplineInterpolation( resizeMultiArraySplineInterpolation(
SrcIterator si, Shape const & sshape, SrcAccessor src , SrcIterator si, Shape const & sshape, SrcAccessor src ,
DestIterator di, Shape const & dshape, DestAccessor d est, DestIterator di, Shape const & dshape, DestAccessor d est,
Kernel const & spline) Kernel const & spline)
{ {
enum { N = 1 + SrcIterator::level }; enum { N = 1 + SrcIterator::level };
typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType;
typedef MultiArray<N, TmpType> TmpArray;
typedef typename AccessorTraits<TmpType>::default_accessor TmpAccessor; typedef typename AccessorTraits<TmpType>::default_accessor TmpAccessor;
if(N==1) if(N==1)
{ {
detail::internalResizeMultiArrayOneDimension(si, sshape, src, detail::internalResizeMultiArrayOneDimension(si, sshape, src,
di, dshape, dest, spline, 0); di, dshape, dest, spline, 0);
} }
else else
{ {
unsigned int d = 0; unsigned int d = 0;
skipping to change at line 241 skipping to change at line 269
detail::internalResizeMultiArrayOneDimension(tmp.traverser_begi n(), tmp.shape(), ta, detail::internalResizeMultiArrayOneDimension(tmp.traverser_begi n(), tmp.shape(), ta,
dtmp.traverser_begin(), tmpShape, ta, spl ine, d); dtmp.traverser_begin(), tmpShape, ta, spl ine, d);
dtmp.swap(tmp); dtmp.swap(tmp);
} }
detail::internalResizeMultiArrayOneDimension(tmp.traverser_begin(), tmp.shape(), ta, detail::internalResizeMultiArrayOneDimension(tmp.traverser_begin(), tmp.shape(), ta,
di, dshape, dest, spline, d); di, dshape, dest, spline, d);
} }
} }
template <class SrcIterator, class Shape, class SrcAccessor, template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
resizeMultiArraySplineInterpolation(
SrcIterator si, Shape const & sshape, SrcAccessor src
,
DestIterator di, Shape const & dshape, DestAccessor d
est)
{
resizeMultiArraySplineInterpolation(si, sshape, src, di, dshape, dest,
BSpline<3, double>());
}
template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Kernel> class Kernel>
inline void inline void
resizeMultiArraySplineInterpolation(triple<SrcIterator, Shape, SrcAccessor> src, resizeMultiArraySplineInterpolation(triple<SrcIterator, Shape, SrcAccessor> src,
triple<DestIterator, Shape, DestAccessor> dest, triple<DestIterator, Shape, DestAccesso
Kernel const & spline) r> dest,
Kernel const & spline)
{ {
resizeMultiArraySplineInterpolation(src.first, src.second, src.third, resizeMultiArraySplineInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third, spl ine); dest.first, dest.second, dest.third , spline);
} }
template <class SrcIterator, class Shape, class SrcAccessor, template <class SrcIterator, class Shape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
resizeMultiArraySplineInterpolation( resizeMultiArraySplineInterpolation(triple<SrcIterator, Shape, SrcAccessor>
SrcIterator si, Shape const & sshape, SrcAccessor src src,
, triple<DestIterator, Shape, DestAccesso
DestIterator di, Shape const & dshape, DestAccessor d r> dest)
est)
{ {
resizeMultiArraySplineInterpolation(si, sshape, src, di, dshape, dest, resizeMultiArraySplineInterpolation(src.first, src.second, src.third,
BSpline<3, double>()); dest.first, dest.second, dest.third
);
} }
template <class SrcIterator, class Shape, class SrcAccessor, template <unsigned int N, class T1, class S1,
class DestIterator, class DestAccessor> class T2, class S2,
class Kernel>
inline void inline void
resizeMultiArraySplineInterpolation(triple<SrcIterator, Shape, SrcAccessor> resizeMultiArraySplineInterpolation(MultiArrayView<N, T1, S1> const & sourc
src, e,
triple<DestIterator, Shape, DestAccessor> dest) MultiArrayView<N, T2, S2> dest,
Kernel const & spline)
{ {
resizeMultiArraySplineInterpolation(src.first, src.second, src.third, resizeMultiArraySplineInterpolation(srcMultiArrayRange(source),
dest.first, dest.second, dest.third); destMultiArrayRange(dest), spline);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
resizeMultiArraySplineInterpolation(MultiArrayView<N, T1, S1> const & sour
ce,
MultiArrayView<N, T2, S2> dest)
{
resizeMultiArraySplineInterpolation(srcMultiArrayRange(source),
destMultiArrayRange(dest));
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_MULTI_RESIZE_HXX #endif // VIGRA_MULTI_RESIZE_HXX
 End of changes. 19 change blocks. 
27 lines changed or deleted 84 lines changed or added


 multi_tensorutilities.hxx   multi_tensorutilities.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MULTI_TENSORUTILITIES_HXX #ifndef VIGRA_MULTI_TENSORUTILITIES_HXX
#define VIGRA_MULTI_TENSORUTILITIES_HXX #define VIGRA_MULTI_TENSORUTILITIES_HXX
#include <cmath> #include <cmath>
#include "utilities.hxx" #include "utilities.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "multi_shape.hxx"
#include "multi_pointoperators.hxx" #include "multi_pointoperators.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
template <int N, class ArgumentVector, class ResultVector> template <int N, class ArgumentVector, class ResultVector>
class OuterProductFunctor class OuterProductFunctor
{ {
public: public:
skipping to change at line 207 skipping to change at line 208
must be a vector of length N, whereas the output value_type mus be vect ors of length must be a vector of length N, whereas the output value_type mus be vect ors of length
N*(N-1)/2 which will represent the upper triangular part of the resulti ng (symmetric) N*(N-1)/2 which will represent the upper triangular part of the resulti ng (symmetric)
tensor. That is, for 2D arrays the output contains the elements tensor. That is, for 2D arrays the output contains the elements
<tt>[t11, t12 == t21, t22]</tt> in this order, whereas it contains the elements <tt>[t11, t12 == t21, t22]</tt> in this order, whereas it contains the elements
<tt>[t11, t12, t13, t22, t23, t33]</tt> for 3D arrays. <tt>[t11, t12, t13, t22, t23, t33]</tt> for 3D arrays.
Currently, <tt>N <= 3</tt> is required. Currently, <tt>N <= 3</tt> is required.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
vectorToTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest);
}
\endcode
\deprecatedAPI{vectorToTensorMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
vectorToTensorMultiArray(SrcIterator si, SrcShape const & shape, S rcAccessor src, vectorToTensorMultiArray(SrcIterator si, SrcShape const & shape, S rcAccessor src,
DestIterator di, DestAccessor dest); DestIterator di, DestAccessor dest);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
vectorToTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s, vectorToTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s,
pair<DestIterator, DestAccessor> d); pair<DestIterator, DestAccessor> d);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_tensorutilities.hxx\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, float> vol(shape); MultiArray<3, float> vol(shape);
MultiArray<3, TinyVector<float, 3> > gradient(shape); MultiArray<3, TinyVector<float, 3> > gradient(shape);
MultiArray<3, TinyVector<float, 6> > tensor(shape); MultiArray<3, TinyVector<float, 6> > tensor(shape);
gaussianGradientMultiArray(srcMultiArrayRange(vol), destMultiArray(grad gaussianGradientMultiArray(vol, gradient, 2.0);
ient), 2.0); vectorToTensorMultiArray(gradient, tensor);
vectorToTensorMultiArray(srcMultiArrayRange(gradient), destMultiArray(t
ensor));
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void vectorToTensorMultiArray) doxygen_overloaded_function(template <...> void vectorToTensorMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
vectorToTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess or src, vectorToTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess or src,
DestIterator di, DestAccessor dest) DestIterator di, DestAccessor dest)
{ {
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
skipping to change at line 279 skipping to change at line 292
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
vectorToTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s, vectorToTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> d)
{ {
vectorToTensorMultiArray(s.first, s.second, s.third, d.first, d.second) ; vectorToTensorMultiArray(s.first, s.second, s.third, d.first, d.second) ;
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
vectorToTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
vigra_precondition(source.shape() == dest.shape(),
"vectorToTensorMultiArray(): shape mismatch between input and outpu
t.");
vectorToTensorMultiArray(srcMultiArrayRange(source), destMultiArray(des
t));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* tensorTraceMultiArray */ /* tensorTraceMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the tensor trace for every element of a N-D tensor arr ay. /** \brief Calculate the tensor trace for every element of a N-D tensor arr ay.
This function turns a N-D tensor (whose value_type is a vector of lengt h N*(N+1)/2, This function turns a N-D tensor (whose value_type is a vector of lengt h N*(N+1)/2,
see \ref vectorToTensorMultiArray()) representing the upper triangular part of a see \ref vectorToTensorMultiArray()) representing the upper triangular part of a
symmetric tensor into a scalar array holding the tensor trace. symmetric tensor into a scalar array holding the tensor trace.
Currently, <tt>N <= 3</tt> is required. Currently, <tt>N <= 3</tt> is required.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
tensorTraceMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest);
}
\endcode
\deprecatedAPI{tensorTraceMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorTraceMultiArray(SrcIterator si, SrcShape const & shape, SrcA ccessor src, tensorTraceMultiArray(SrcIterator si, SrcShape const & shape, SrcA ccessor src,
DestIterator di, DestAccessor dest); DestIterator di, DestAccessor dest);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorTraceMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s, tensorTraceMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s,
pair<DestIterator, DestAccessor> d); pair<DestIterator, DestAccessor> d);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/multi_tensorutilities.hxx\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, float> vol(shape); MultiArray<3, float> vol(shape);
MultiArray<3, TinyVector<float, 6> > hessian(shape); MultiArray<3, TinyVector<float, 6> > hessian(shape);
MultiArray<3, float> trace(shape); MultiArray<3, float> trace(shape);
hessianOfGaussianMultiArray(srcMultiArrayRange(vol), destMultiArray(hes hessianOfGaussianMultiArray(vol, hessian, 2.0);
sian), 2.0); tensorTraceMultiArray(hessian, trace);
tensorTraceMultiArray(srcMultiArrayRange(hessian), destMultiArray(trace
));
\endcode \endcode
<b> Preconditions:</b>
<tt>N == 2</tt> or <tt>N == 3</tt>
*/ */
doxygen_overloaded_function(template <...> void tensorTraceMultiArray) doxygen_overloaded_function(template <...> void tensorTraceMultiArray)
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorTraceMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor src, tensorTraceMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor src,
DestIterator di, DestAccessor dest) DestIterator di, DestAccessor dest)
{ {
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
skipping to change at line 355 skipping to change at line 395
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
tensorTraceMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s, tensorTraceMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> d)
{ {
tensorTraceMultiArray(s.first, s.second, s.third, d.first, d.second); tensorTraceMultiArray(s.first, s.second, s.third, d.first, d.second);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
tensorTraceMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
vigra_precondition(source.shape() == dest.shape(),
"tensorTraceMultiArray(): shape mismatch between input and output."
);
tensorTraceMultiArray(srcMultiArrayRange(source), destMultiArray(dest))
;
}
/********************************************************/ /********************************************************/
/* */ /* */
/* tensorEigenvaluesMultiArray */ /* tensorEigenvaluesMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the tensor eigenvalues for every element of a N-D tens or array. /** \brief Calculate the tensor eigenvalues for every element of a N-D tens or array.
This function turns a N-D tensor (whose value_type is a vector of lengt h N*(N+1)/2, This function turns a N-D tensor (whose value_type is a vector of lengt h N*(N+1)/2,
see \ref vectorToTensorMultiArray()) representing the upper triangular part of a see \ref vectorToTensorMultiArray()) representing the upper triangular part of a
symmetric tensor into a vector-valued array holding the tensor eigenval ues (thus, symmetric tensor into a vector-valued array holding the tensor eigenval ues (thus,
the destination value_type must be vectors of length N). the destination value_type must be vectors of length N).
Currently, <tt>N <= 3</tt> is required. Currently, <tt>N <= 3</tt> is required.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
tensorEigenvaluesMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, T2, S2> dest);
}
\endcode
\deprecatedAPI{tensorEigenvaluesMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorEigenvaluesMultiArray(SrcIterator si, SrcShape const & shape , SrcAccessor src, tensorEigenvaluesMultiArray(SrcIterator si, SrcShape const & shape , SrcAccessor src,
DestIterator di, DestAccessor dest); DestIterator di, DestAccessor dest);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorEigenvaluesMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> s, tensorEigenvaluesMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> s,
pair<DestIterator, DestAccessor> d); pair<DestIterator, DestAccessor> d);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage (MultiArrayView API):</b>
<b>\#include</b> \<vigra/multi_tensorutilities.hxx\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, float> vol(shape); MultiArray<3, float> vol(shape);
MultiArray<3, TinyVector<float, 6> > hessian(shape); MultiArray<3, TinyVector<float, 6> > hessian(shape);
MultiArray<3, TinyVector<float, 3> > eigenvalues(shape); MultiArray<3, TinyVector<float, 3> > eigenvalues(shape);
hessianOfGaussianMultiArray(srcMultiArrayRange(vol), destMultiArray(hes hessianOfGaussianMultiArray(vol, hessian, 2.0);
sian), 2.0); tensorEigenvaluesMultiArray(hessian, eigenvalues);
tensorEigenvaluesMultiArray(srcMultiArrayRange(hessian), destMultiArray
(eigenvalues));
\endcode \endcode
<b> Preconditions:</b>
<tt>N == 2</tt> or <tt>N == 3</tt>
*/ */
doxygen_overloaded_function(template <...> void tensorEigenvaluesMultiArray ) doxygen_overloaded_function(template <...> void tensorEigenvaluesMultiArray )
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorEigenvaluesMultiArray(SrcIterator si, SrcShape const & shape, SrcAcc essor src, tensorEigenvaluesMultiArray(SrcIterator si, SrcShape const & shape, SrcAcc essor src,
DestIterator di, DestAccessor dest) DestIterator di, DestAccessor dest)
{ {
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
skipping to change at line 444 skipping to change at line 511
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
tensorEigenvaluesMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s, tensorEigenvaluesMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> d)
{ {
tensorEigenvaluesMultiArray(s.first, s.second, s.third, d.first, d.seco nd); tensorEigenvaluesMultiArray(s.first, s.second, s.third, d.first, d.seco nd);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
tensorEigenvaluesMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
vigra_precondition(source.shape() == dest.shape(),
"tensorEigenvaluesMultiArray(): shape mismatch between input and ou
tput.");
tensorEigenvaluesMultiArray(srcMultiArrayRange(source), destMultiArray(
dest));
}
/********************************************************/ /********************************************************/
/* */ /* */
/* tensorDeterminantMultiArray */ /* tensorDeterminantMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the tensor determinant for every element of a ND tenso r array. /** \brief Calculate the tensor determinant for every element of a ND tenso r array.
This function turns a N-D tensor (whose value_type is a vector of lengt h N*(N+1)/2, This function turns a N-D tensor (whose value_type is a vector of lengt h N*(N+1)/2,
see \ref vectorToTensorMultiArray()) representing the upper triangular part of a see \ref vectorToTensorMultiArray()) representing the upper triangular part of a
symmetric tensor into the a scalar array holding the tensor determinant . symmetric tensor into the a scalar array holding the tensor determinant .
Currently, <tt>N <= 3</tt> is required. Currently, <tt>N <= 3</tt> is required.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arbitrary-dimensional array views:
\code
namespace vigra {
template <unsigned int N, class T1, class S1,
class T2, class S2>
void
tensorDeterminantMultiArray(MultiArrayView<N, T1, S1> const & sourc
e,
MultiArrayView<N, T2, S2> dest);
}
\endcode
\deprecatedAPI{tensorDeterminantMultiArray}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorDeterminantMultiArray(SrcIterator si, SrcShape const & shape , SrcAccessor src, tensorDeterminantMultiArray(SrcIterator si, SrcShape const & shape , SrcAccessor src,
DestIterator di, DestAccessor dest); DestIterator di, DestAccessor dest);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorDeterminantMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> s, tensorDeterminantMultiArray(triple<SrcIterator, SrcShape, SrcAccess or> s,
pair<DestIterator, DestAccessor> d); pair<DestIterator, DestAccessor> d);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage (MultiArrayView API):</b>
<b>\#include</b> \<vigra/multi_tensorutilities.hxx\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<3, float> vol(shape); MultiArray<3, float> vol(shape);
MultiArray<3, TinyVector<float, 6> > hessian(shape); MultiArray<3, TinyVector<float, 6> > hessian(shape);
MultiArray<3, float> determinant(shape); MultiArray<3, float> determinant(shape);
hessianOfGaussianMultiArray(srcMultiArrayRange(vol), destMultiArray(hes hessianOfGaussianMultiArray(vol, hessian, 2.0);
sian), 2.0); tensorDeterminantMultiArray(hessian, determinant);
tensorDeterminantMultiArray(srcMultiArrayRange(hessian), destMultiArray
(determinant));
\endcode \endcode
<b> Preconditions:</b>
<tt>N == 2</tt> or <tt>N == 3</tt>
*/ */
doxygen_overloaded_function(template <...> void tensorDeterminantMultiArray ) doxygen_overloaded_function(template <...> void tensorDeterminantMultiArray )
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
tensorDeterminantMultiArray(SrcIterator si, SrcShape const & shape, SrcAcc essor src, tensorDeterminantMultiArray(SrcIterator si, SrcShape const & shape, SrcAcc essor src,
DestIterator di, DestAccessor dest) DestIterator di, DestAccessor dest)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
skipping to change at line 529 skipping to change at line 623
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
tensorDeterminantMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s, tensorDeterminantMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> s,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> d)
{ {
tensorDeterminantMultiArray(s.first, s.second, s.third, d.first, d.seco nd); tensorDeterminantMultiArray(s.first, s.second, s.third, d.first, d.seco nd);
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline void
tensorDeterminantMultiArray(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
vigra_precondition(source.shape() == dest.shape(),
"tensorDeterminantMultiArray(): shape mismatch between input and ou
tput.");
tensorDeterminantMultiArray(srcMultiArrayRange(source), destMultiArray(
dest));
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_MULTI_TENSORUTILITIES_HXX */ #endif /* VIGRA_MULTI_TENSORUTILITIES_HXX */
 End of changes. 35 change blocks. 
43 lines changed or deleted 150 lines changed or added


 navigator.hxx   navigator.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_NAVIGATOR_HXX #ifndef VIGRA_NAVIGATOR_HXX
#define VIGRA_NAVIGATOR_HXX #define VIGRA_NAVIGATOR_HXX
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiArrayNavigator */ /* MultiArrayNavigator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief A navigator that provides access to the 1D subranges of an /** \brief A navigator that provides access to the 1D subranges of an
n-dimensional range given by a \ref vigra::MultiIterator and an nD shap e. n-dimensional range given by a \ref vigra::MultiIterator and an nD shap e.
skipping to change at line 181 skipping to change at line 183
enum { level = 0 }; enum { level = 0 };
typedef typename MULTI_ITERATOR::multi_difference_type shape_type; typedef typename MULTI_ITERATOR::multi_difference_type shape_type;
typedef typename MULTI_ITERATOR::iterator iterator; typedef typename MULTI_ITERATOR::iterator iterator;
MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & shape, unsigned int inner_dimension) MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & shape, unsigned int inner_dimension)
: start_(), stop_(shape), point_(start_), : start_(), stop_(shape), point_(start_),
inner_dimension_(inner_dimension), inner_dimension_(inner_dimension),
inner_shape_(stop_[inner_dimension] - start_[inner_dimension]), inner_shape_(stop_[inner_dimension] - start_[inner_dimension]),
i_(i + start_) i_(i + start_)
{ {
stop_[inner_dimension] = start_[inner_dimension] + 1; if(stop_[inner_dimension] > start_[inner_dimension])
stop_[inner_dimension] = start_[inner_dimension] + 1;
} }
MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & start, shape_type const & stop, MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & start, shape_type const & stop,
unsigned int inner_dimension) unsigned int inner_dimension)
: start_(start), stop_(stop), point_(start_), : start_(start), stop_(stop), point_(start_),
inner_dimension_(inner_dimension), inner_dimension_(inner_dimension),
inner_shape_(stop_[inner_dimension] - start_[inner_dimension]), inner_shape_(stop_[inner_dimension] - start_[inner_dimension]),
i_(i + start_) i_(i + start_)
{ {
stop_[inner_dimension] = start_[inner_dimension] + 1; if(stop_[inner_dimension] > start_[inner_dimension])
stop_[inner_dimension] = start_[inner_dimension] + 1;
} }
void operator++() void operator++()
{ {
++point_[level]; ++point_[level];
++i_.template dim<level>(); ++i_.template dim<level>();
} }
void operator++(int) void operator++(int)
{ {
 End of changes. 3 change blocks. 
2 lines changed or deleted 6 lines changed or added


 noise_normalization.hxx   noise_normalization.hxx 
skipping to change at line 51 skipping to change at line 51
#include "stdimage.hxx" #include "stdimage.hxx"
#include "transformimage.hxx" #include "transformimage.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
#include "localminmax.hxx" #include "localminmax.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "linear_solve.hxx" #include "linear_solve.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "static_assert.hxx" #include "static_assert.hxx"
#include "multi_shape.hxx"
#include <algorithm> #include <algorithm>
namespace vigra { namespace vigra {
/** \addtogroup NoiseNormalization Noise Normalization /** \addtogroup NoiseNormalization Noise Normalization
Estimate noise with intensity-dependent variance and transform it into additive Gaussian noise. Estimate noise with intensity-dependent variance and transform it into additive Gaussian noise.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
skipping to change at line 74 skipping to change at line 76
/********************************************************/ /********************************************************/
/** \brief Pass options to one of the noise normalization functions. /** \brief Pass options to one of the noise normalization functions.
<tt>NoiseNormalizationOptions</tt> is an argument object that holds va rious optional <tt>NoiseNormalizationOptions</tt> is an argument object that holds va rious optional
parameters used by the noise normalization functions. If a parameter is not explicitly parameters used by the noise normalization functions. If a parameter is not explicitly
set, a suitable default will be used. set, a suitable default will be used.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(w,h); MultiArray<2, float> src(w,h);
std::vector<vigra::TinyVector<double, 2> > result; std::vector<TinyVector<double, 2> > result;
... ...
vigra::noiseVarianceEstimation(srcImageRange(src), result, noiseVarianceEstimation(src, result,
vigra::NoiseNormalizationOptions().window NoiseNormalizationOptions().windowRadius(9).noi
Radius(9).noiseVarianceInitialGuess(25.0)); seVarianceInitialGuess(25.0));
\endcode \endcode
*/ */
class NoiseNormalizationOptions class NoiseNormalizationOptions
{ {
public: public:
/** Initialize all options with default values. /** Initialize all options with default values.
*/ */
NoiseNormalizationOptions() NoiseNormalizationOptions()
: window_radius(6), : window_radius(6),
skipping to change at line 547 skipping to change at line 549
void void
findHomogeneousRegionsFoerstner( findHomogeneousRegionsFoerstner(
SrcIterator sul, SrcIterator slr, SrcAccessor src, SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
unsigned int windowRadius = 6, double homogeneityThreshold = 40.0) unsigned int windowRadius = 6, double homogeneityThreshold = 40.0)
{ {
using namespace vigra::functor; using namespace vigra::functor;
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType;
typedef BasicImage<TmpType> TmpImage;
BImage btmp(w, h); BImage btmp(w, h);
transformImage(srcIterRange(sul, slr, src), destImage(btmp), transformImage(srcIterRange(sul, slr, src), destImage(btmp),
ifThenElse(Arg1() <= Param(homogeneityThreshold), Param (1), Param(0))); ifThenElse(Arg1() <= Param(homogeneityThreshold), Param (1), Param(0)));
// Erosion // Erosion
discErosion(srcImageRange(btmp), destIter(dul, dest), windowRadius); discErosion(srcImageRange(btmp), destIter(dul, dest), windowRadius);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
skipping to change at line 977 skipping to change at line 976
i.e. so that intensity changes due to edges do not bias the estimate. T he source value type i.e. so that intensity changes due to edges do not bias the estimate. T he source value type
(<TT>SrcAccessor::value_type</TT>) must be a scalar type which is conve rtible to <tt>double</tt>. (<TT>SrcAccessor::value_type</TT>) must be a scalar type which is conve rtible to <tt>double</tt>.
The result is written into the \a result sequence, whose <tt>value_type </tt> must be constructible The result is written into the \a result sequence, whose <tt>value_type </tt> must be constructible
from two <tt>double</tt> values. The following options can be set via t he \a options object from two <tt>double</tt> values. The following options can be set via t he \a options object
(see \ref vigra::NoiseNormalizationOptions for details):<br><br> (see \ref vigra::NoiseNormalizationOptions for details):<br><br>
<tt>useGradient</tt>, <tt>windowRadius</tt>, <tt>noiseEstimationQuantil e</tt>, <tt>noiseVarianceInitialGuess</tt> <tt>useGradient</tt>, <tt>windowRadius</tt>, <tt>noiseEstimationQuantil e</tt>, <tt>noiseVarianceInitialGuess</tt>
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1, class BackInsertable>
void
noiseVarianceEstimation(MultiArrayView<2, T1, S1> const & src,
BackInsertable & result,
NoiseNormalizationOptions const & options =
NoiseNormalizationOptions());
}
\endcode
\deprecatedAPI{noiseVarianceEstimation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcA ccessor src, void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcA ccessor src,
BackInsertable & result, BackInsertable & result,
NoiseNormalizationOptions const & opti ons = NoiseNormalizationOptions()); NoiseNormalizationOptions const & opti ons = NoiseNormalizationOptions());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAc cessor> src, void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
BackInsertable & result, BackInsertable & result,
NoiseNormalizationOptions const & opti ons = NoiseNormalizationOptions()); NoiseNormalizationOptions const & opti ons = NoiseNormalizationOptions());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h);
std::vector<TinyVector<double, 2> > result;
...
noiseVarianceEstimation(src, result,
NoiseNormalizationOptions().windowRadius(9).noi
seVarianceInitialGuess(25.0));
// print the intensity / variance pairs found
for(int k=0; k<result.size(); ++k)
std::cout << "Intensity: " << result[k][0] << ", estimated variance
: " << result[k][1] << std::endl;
\endcode
\deprecatedUsage{noiseVarianceEstimation}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
std::vector<vigra::TinyVector<double, 2> > result; std::vector<vigra::TinyVector<double, 2> > result;
... ...
vigra::noiseVarianceEstimation(srcImageRange(src), result, vigra::noiseVarianceEstimation(srcImageRange(src), result,
vigra::NoiseNormalizationOptions().window Radius(9).noiseVarianceInitialGuess(25.0)); vigra::NoiseNormalizationOptions().window Radius(9).noiseVarianceInitialGuess(25.0));
// print the intensity / variance pairs found // print the intensity / variance pairs found
for(int k=0; k<result.size(); ++k) for(int k=0; k<result.size(); ++k)
std::cout << "Intensity: " << result[k][0] << ", estimated variance : " << result[k][1] << std::endl; std::cout << "Intensity: " << result[k][0] << ", estimated variance : " << result[k][1] << std::endl;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator upperleft, lowerright; SrcIterator upperleft, lowerright;
SrcAccessor src; SrcAccessor src;
typedef SrcAccessor::value_type SrcType; typedef SrcAccessor::value_type SrcType;
typedef NumericTraits<SrcType>::isScalar isScalar; typedef NumericTraits<SrcType>::isScalar isScalar;
assert(isScalar::asBool == true); assert(isScalar::asBool == true);
double value = src(uperleft); double value = src(uperleft);
BackInsertable result; BackInsertable result;
typedef BackInsertable::value_type ResultType; typedef BackInsertable::value_type ResultType;
double intensity, variance; double intensity, variance;
result.push_back(ResultType(intensity, variance)); result.push_back(ResultType(intensity, variance));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void noiseVarianceEstimation) doxygen_overloaded_function(template <...> void noiseVarianceEstimation)
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline inline
void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcAccessor src, void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
BackInsertable & result, BackInsertable & result,
NoiseNormalizationOptions const & options = Nois eNormalizationOptions()) NoiseNormalizationOptions const & options = Nois eNormalizationOptions())
{ {
typedef typename BackInsertable::value_type ResultType;
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
typedef typename NumericTraits<SrcType>::isScalar isScalar; typedef typename NumericTraits<SrcType>::isScalar isScalar;
VIGRA_STATIC_ASSERT(( VIGRA_STATIC_ASSERT((
noiseVarianceEstimation_can_only_work_on_scalar_images<(isScalar::a sBool)>)); noiseVarianceEstimation_can_only_work_on_scalar_images<(isScalar::a sBool)>));
detail::noiseVarianceEstimationImpl(sul, slr, src, result, options); detail::noiseVarianceEstimationImpl(sul, slr, src, result, options);
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline inline void
void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAccessor> noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
src, BackInsertable & result,
BackInsertable & result, NoiseNormalizationOptions const & options = NoiseNo
NoiseNormalizationOptions const & options = Nois rmalizationOptions())
eNormalizationOptions())
{ {
noiseVarianceEstimation(src.first, src.second, src.third, result, optio ns); noiseVarianceEstimation(src.first, src.second, src.third, result, optio ns);
} }
template <class T1, class S1, class BackInsertable>
inline void
noiseVarianceEstimation(MultiArrayView<2, T1, S1> const & src,
BackInsertable & result,
NoiseNormalizationOptions const & options = NoiseNo
rmalizationOptions())
{
noiseVarianceEstimation(srcImageRange(src), result, options);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* noiseVarianceClustering */ /* noiseVarianceClustering */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Determine the noise variance as a function of the image intensit y and cluster the results. /** \brief Determine the noise variance as a function of the image intensit y and cluster the results.
This operator first calls \ref noiseVarianceEstimation() to obtain a se quence of intensity/variance pairs, This operator first calls \ref noiseVarianceEstimation() to obtain a se quence of intensity/variance pairs,
which are then clustered using the median cut algorithm. Then the clust er centers (i.e. average variance vs. which are then clustered using the median cut algorithm. Then the clust er centers (i.e. average variance vs.
average intensity) are determined and returned in the \a result sequenc e. average intensity) are determined and returned in the \a result sequenc e.
In addition to the options valid for \ref noiseVarianceEstimation(), th e following options can be set via In addition to the options valid for \ref noiseVarianceEstimation(), th e following options can be set via
the \a options object (see \ref vigra::NoiseNormalizationOptions for de tails):<br><br> the \a options object (see \ref vigra::NoiseNormalizationOptions for de tails):<br><br>
<tt>clusterCount</tt>, <tt>averagingQuantile</tt> <tt>clusterCount</tt>, <tt>averagingQuantile</tt>
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1, class BackInsertable>
void
noiseVarianceClustering(MultiArrayView<2, T1, S1> const & src,
BackInsertable & result,
NoiseNormalizationOptions const & options =
NoiseNormalizationOptions());
}
\endcode
\deprecatedAPI{noiseVarianceClustering}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcA ccessor src, void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcA ccessor src,
BackInsertable & result, BackInsertable & result,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); NoiseNormalizationOptions const & options = NoiseNormalizationOptions());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAc cessor> src, void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
BackInsertable & result, BackInsertable & result,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); NoiseNormalizationOptions const & options = NoiseNormalizationOptions());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h);
std::vector<TinyVector<double, 2> > result;
...
noiseVarianceClustering(src, result,
NoiseNormalizationOptions().windowRadius(9).noi
seVarianceInitialGuess(25.0).
clusterCount(15));
// print the intensity / variance pairs representing the cluster center
s
for(int k=0; k<result.size(); ++k)
std::cout << "Cluster: " << k << ", intensity: " << result[k][0] <<
", estimated variance: " << result[k][1] << std::endl;
\endcode
\deprecatedUsage{noiseVarianceClustering}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
std::vector<vigra::TinyVector<double, 2> > result; std::vector<vigra::TinyVector<double, 2> > result;
... ...
vigra::noiseVarianceClustering(srcImageRange(src), result, vigra::noiseVarianceClustering(srcImageRange(src), result,
vigra::NoiseNormalizationOptions().window Radius(9).noiseVarianceInitialGuess(25.0). vigra::NoiseNormalizationOptions().window Radius(9).noiseVarianceInitialGuess(25.0).
clusterCount(15)); clusterCount(15));
// print the intensity / variance pairs representing the cluster center s // print the intensity / variance pairs representing the cluster center s
for(int k=0; k<result.size(); ++k) for(int k=0; k<result.size(); ++k)
std::cout << "Cluster: " << k << ", intensity: " << result[k][0] << ", estimated variance: " << result[k][1] << std::endl; std::cout << "Cluster: " << k << ", intensity: " << result[k][0] << ", estimated variance: " << result[k][1] << std::endl;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
same as \ref noiseVarianceEstimation() same as \ref noiseVarianceEstimation()
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void noiseVarianceClustering) doxygen_overloaded_function(template <...> void noiseVarianceClustering)
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline inline
void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcAccessor src, void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcAccessor src,
BackInsertable & result, BackInsertable & result,
NoiseNormalizationOptions const & options = Nois eNormalizationOptions()) NoiseNormalizationOptions const & options = Nois eNormalizationOptions())
{ {
ArrayVector<TinyVector<double, 2> > variance; ArrayVector<TinyVector<double, 2> > variance;
noiseVarianceEstimation(sul, slr, src, variance, options); noiseVarianceEstimation(sul, slr, src, variance, options);
detail::noiseVarianceClusteringImpl(variance, result, options.cluster_c ount, options.averaging_quantile); detail::noiseVarianceClusteringImpl(variance, result, options.cluster_c ount, options.averaging_quantile);
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline inline void
void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAccessor> noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAccessor> src,
src, BackInsertable & result,
BackInsertable & result, NoiseNormalizationOptions const & options = NoiseNo
NoiseNormalizationOptions const & options = Nois rmalizationOptions())
eNormalizationOptions())
{ {
noiseVarianceClustering(src.first, src.second, src.third, result, optio ns); noiseVarianceClustering(src.first, src.second, src.third, result, optio ns);
} }
template <class T1, class S1, class BackInsertable>
inline void
noiseVarianceClustering(MultiArrayView<2, T1, S1> const & src,
BackInsertable & result,
NoiseNormalizationOptions const & options = NoiseNo
rmalizationOptions())
{
noiseVarianceClustering(srcImageRange(src), result, options);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* nonparametricNoiseNormalization */ /* nonparametricNoiseNormalization */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Noise normalization by means of an estimated non-parametric nois e model. /** \brief Noise normalization by means of an estimated non-parametric nois e model.
The original image is assumed to be corrupted by noise whose variance d epends on the intensity in an unknown way. The original image is assumed to be corrupted by noise whose variance d epends on the intensity in an unknown way.
The present functions first calls \ref noiseVarianceClustering() to obt ain a sequence of intensity/variance pairs The present functions first calls \ref noiseVarianceClustering() to obt ain a sequence of intensity/variance pairs
skipping to change at line 1171 skipping to change at line 1238
The inverted formula defines a pixel-wise intensity transformation whos e application turns the original image The inverted formula defines a pixel-wise intensity transformation whos e application turns the original image
into one that is corrupted by additive Gaussian noise with unit varianc e. Most subsequent algorithms will be able into one that is corrupted by additive Gaussian noise with unit varianc e. Most subsequent algorithms will be able
to handle this type of noise much better than the original noise. to handle this type of noise much better than the original noise.
RGB and other multiband images will be processed one band at a time. Th e function returns <tt>true</tt> on success. RGB and other multiband images will be processed one band at a time. Th e function returns <tt>true</tt> on success.
Noise normalization will fail if the original image does not contain su fficiently homogeneous regions that Noise normalization will fail if the original image does not contain su fficiently homogeneous regions that
allow robust estimation of the noise variance. allow robust estimation of the noise variance.
The \a options object may use all options described in \ref vigra::Nois eNormalizationOptions. The \a options object may use all options described in \ref vigra::Nois eNormalizationOptions.
The function returns <tt>false</tt> if the noise estimation failed, so
that no normalization could be performed.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
bool
nonparametricNoiseNormalization(MultiArrayView<2, T1, S1> const & s
rc,
MultiArrayView<2, T2, S2> dest,
NoiseNormalizationOptions const & o
ptions = NoiseNormalizationOptions());
}
\endcode
\deprecatedAPI{nonparametricNoiseNormalization}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
bool nonparametricNoiseNormalization(SrcIterator sul, SrcIterator s lr, SrcAccessor src, bool nonparametricNoiseNormalization(SrcIterator sul, SrcIterator s lr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
NoiseNormalizationOptions cons t & options = NoiseNormalizationOptions()); NoiseNormalizationOptions cons t & options = NoiseNormalizationOptions());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterato r, SrcAccessor> src, bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterato r, SrcAccessor> src,
pair<DestIterator, DestAccesso r> dest, pair<DestIterator, DestAccesso r> dest,
NoiseNormalizationOptions cons t & options = NoiseNormalizationOptions()); NoiseNormalizationOptions cons t & options = NoiseNormalizationOptions());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, RGBValue<float> > src(w,h), dest(w, h);
...
nonparametricNoiseNormalization(src, dest,
NoiseNormalizationOptions().windowRadiu
s(9).noiseVarianceInitialGuess(25.0).
clusterCount(15));
\endcode
\deprecatedUsage{nonparametricNoiseNormalization}
\code
vigra::BRGBImage src(w,h), dest(w, h); vigra::BRGBImage src(w,h), dest(w, h);
... ...
vigra::nonparametricNoiseNormalization(srcImageRange(src), destImage(de st), vigra::nonparametricNoiseNormalization(srcImageRange(src), destImage(de st),
vigra::NoiseNormalizationOptions ().windowRadius(9).noiseVarianceInitialGuess(25.0). vigra::NoiseNormalizationOptions ().windowRadius(9).noiseVarianceInitialGuess(25.0).
clusterCount(15)); clusterCount(15));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
same as \ref noiseVarianceEstimation() same as \ref noiseVarianceEstimation()
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> bool nonparametricNoiseNormaliza tion) doxygen_overloaded_function(template <...> bool nonparametricNoiseNormaliza tion)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline bool inline bool
nonparametricNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccess or src, nonparametricNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccess or src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) NoiseNormalizationOptions const & options = NoiseNormalizationOptions())
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
return detail::nonparametricNoiseNormalizationImpl(sul, slr, src, dul, dest, options, return detail::nonparametricNoiseNormalizationImpl(sul, slr, src, dul, dest, options,
typename NumericTraits<SrcType>::i sScalar()); typename NumericTraits<SrcType>::i sScalar());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline bool
bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAc nonparametricNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccesso
cessor> src, r> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
NoiseNormalizationOptions const & opti NoiseNormalizationOptions const & options =
ons = NoiseNormalizationOptions()) NoiseNormalizationOptions())
{ {
return nonparametricNoiseNormalization(src.first, src.second, src.third , dest.first, dest.second, options); return nonparametricNoiseNormalization(src.first, src.second, src.third , dest.first, dest.second, options);
} }
template <class T1, class S1,
class T2, class S2>
inline bool
nonparametricNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
NoiseNormalizationOptions const & options =
NoiseNormalizationOptions())
{
vigra_precondition(src.shape() == dest.shape(),
"nonparametricNoiseNormalization(): shape mismatch between input an
d output.");
return nonparametricNoiseNormalization(srcImageRange(src), destImage(de
st), options);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* quadraticNoiseNormalization */ /* quadraticNoiseNormalization */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Noise normalization by means of an estimated quadratic noise mod el. /** \brief Noise normalization by means of an estimated or given quadratic noise model.
This function works in the same way as \ref nonparametricNoiseNormaliza This function works like \ref nonparametricNoiseNormalization() excapt
tion() with the exception of the that the model for the
model for the dependency between intensity and noise variance: it assum dependency between intensity and noise variance is assumed to be a
es that this dependency is a quadratic function rather than a piecewise linear function. If the data
quadratic function rather than a piecewise linear function. If the quad conform to the quadratic model,
ratic model is applicable, it leads this leads to a somewhat smoother transformation. The function returns
to a somewhat smoother transformation. <tt>false</tt> if the noise
estimation failed, so that no normalization could be performed.
In the second variant of the function, the parameters of the quadratic
model are not estimated,
but explicitly given according to:
\code
variance = a0 + a1 * intensity + a2 * sq(intensity)
\endcode
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
// estimate and apply a quadratic noise model
template <class T1, class S1,
class T2, class S2>
bool
quadraticNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
NoiseNormalizationOptions const & optio
ns = NoiseNormalizationOptions());
// apply a given quadratic noise model
template <class T1, class S1,
class T2, class S2>
void
quadraticNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double a0, double a1, double a2);
}
\endcode
\deprecatedAPI{quadraticNoiseNormalization}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
// estimate and apply a quadratic noise model
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
bool quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, bool quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor des t, DestIterator dul, DestAccessor des t,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); NoiseNormalizationOptions const & options = NoiseNormalizationOptions());
// apply a given quadratic noise model
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr,
SrcAccessor src,
DestIterator dul, DestAccessor des
t,
double a0, double a1, double a2);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// estimate and apply a quadratic noise model
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, S rcAccessor> src, bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, S rcAccessor> src,
pair<DestIterator, DestAccessor> d est, pair<DestIterator, DestAccessor> d est,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); NoiseNormalizationOptions const & options = NoiseNormalizationOptions());
// apply a given quadratic noise model
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, S
rcAccessor> src,
pair<DestIterator, DestAccessor> d
est,
double a0, double a1, double a2);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, RGBValue<float> > src(w,h), dest(w, h);
...
// estimate the noise model and apply it to normalize the noise varianc
e
bool success = quadraticNoiseNormalization(src, dest,
NoiseNormalizationOptions().windowRadius(9)
.noiseVarianceInitialGuess(25.0).
clusterCount(15));
vigra_postcondition(success, "quadraticNoiseNormalization(): Unable to
estimate noise model.");
// apply a pre-computed noise model
quadraticNoiseNormalization(src, dest, 100, 0.02, 1e-6);
\endcode
\deprecatedUsage{quadraticNoiseNormalization}
\code
vigra::BRGBImage src(w,h), dest(w, h); vigra::BRGBImage src(w,h), dest(w, h);
... ...
// estimate the noise model and apply it to normalize the noise varianc e
vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest), vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest),
vigra::NoiseNormalizationOptions().w indowRadius(9).noiseVarianceInitialGuess(25.0). vigra::NoiseNormalizationOptions().w indowRadius(9).noiseVarianceInitialGuess(25.0).
clusterCount(15)); clusterCount(15));
// apply a pre-computed noise model
vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest),
100, 0.02, 1e-6);
\endcode \endcode
\deprecatedEnd
<b> Required Interface:</b> <b> Required Interface:</b>
same as \ref noiseVarianceEstimation() The source value type must be convertible to <tt>double</tt> or must be
a vector whose elements
are convertible to <tt>double</tt>. Likewise, the destination type must
be assignable from <tt>double</tt>
or a vector whose elements are assignable from <tt>double</tt>.
*/ */
doxygen_overloaded_function(template <...> bool quadraticNoiseNormalization ) doxygen_overloaded_function(template <...> bool quadraticNoiseNormalization )
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline bool inline bool
quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor s rc, quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor s rc,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions const & options)
NoiseNormalizationOptions())
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
return detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest , options, return detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest , options,
typename NumericTraits<SrcType>::i sScalar()); typename NumericTraits<SrcType>::i sScalar());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline bool
bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccess quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> s
or> src, rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
NoiseNormalizationOptions const & opti NoiseNormalizationOptions const & options = Noi
ons = NoiseNormalizationOptions()) seNormalizationOptions())
{ {
return quadraticNoiseNormalization(src.first, src.second, src.third, de st.first, dest.second, options); return quadraticNoiseNormalization(src.first, src.second, src.third, de st.first, dest.second, options);
} }
template <class T1, class S1,
class T2, class S2>
inline bool
quadraticNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
NoiseNormalizationOptions const & options = Noi
seNormalizationOptions())
{
vigra_precondition(src.shape() == dest.shape(),
"quadraticNoiseNormalization(): shape mismatch between input and ou
tput.");
return quadraticNoiseNormalization(srcImageRange(src), destImage(dest),
options);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* quadraticNoiseNormalization */ /* quadraticNoiseNormalization */
/* (variant) */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Noise normalization by means of a given quadratic noise model.
This function works similar to \ref nonparametricNoiseNormalization() w
ith the exception that the
functional dependency of the noise variance from the intensity is given
(by a quadratic function)
rather than estimated:
\code
variance = a0 + a1 * intensity + a2 * sq(intensity)
\endcode
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr,
SrcAccessor src,
DestIterator dul, DestAccessor des
t,
double a0, double a1, double a2);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, S
rcAccessor> src,
pair<DestIterator, DestAccessor> de
st,
double a0, double a1, double a2);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra
\code
vigra::BRGBImage src(w,h), dest(w, h);
...
vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest),
100, 0.02, 1e-6);
\endcode
<b> Required Interface:</b>
The source value type must be convertible to <tt>double</tt> or must be
a vector whose elements
are convertible to <tt>double</tt>. Likewise, the destination type must
be assignable from <tt>double</tt>
or a vector whose elements are assignable from <tt>double</tt>.
*/
doxygen_overloaded_function(template <...> void quadraticNoiseNormalization
)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor s rc, quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor s rc,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
double a0, double a1, double a2) double a0, double a1, double a2)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a 1, a2, detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a 1, a2,
typename NumericTraits<SrcType>::i sScalar()); typename NumericTraits<SrcType>::i sScalar());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccess quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> s
or> src, rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double a0, double a1, double a2) double a0, double a1, double a2)
{ {
quadraticNoiseNormalization(src.first, src.second, src.third, dest.firs t, dest.second, a0, a1, a2); quadraticNoiseNormalization(src.first, src.second, src.third, dest.firs t, dest.second, a0, a1, a2);
} }
template <class T1, class S1,
class T2, class S2>
inline void
quadraticNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double a0, double a1, double a2)
{
vigra_precondition(src.shape() == dest.shape(),
"quadraticNoiseNormalization(): shape mismatch between input and ou
tput.");
quadraticNoiseNormalization(srcImageRange(src), destImage(dest), a0, a1
, a2);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* linearNoiseNormalization */ /* linearNoiseNormalization */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Noise normalization by means of an estimated linear noise model. /** \brief Noise normalization by means of an estimated or given linear noi se model.
This function works in the same way as \ref nonparametricNoiseNormaliza This function works like \ref nonparametricNoiseNormalization() excapt
tion() with the exception of the that the model for the
model for the dependency between intensity and noise variance: it assum dependency between intensity and noise variance is assumed to be a
es that this dependency is a linear function rather than a piecewise linear function. If the data co
linear function rather than a piecewise linear function. If the linear nform to the linear model,
model is applicable, it leads this leads to a very simple transformation which is similar to the fami
to a very simple transformation which is similar to the familiar gamma liar gamma correction.
correction. The function returns <tt>false</tt> if the noise estimation failed, so
that no
normalization could be performed.
In the second variant of the function, the parameters of the linear mod
el are not estimated,
but explicitly given according to:
\code
variance = a0 + a1 * intensity
\endcode
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// estimate and apply a linear noise model
template <class T1, class S1,
class T2, class S2>
bool
linearNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
NoiseNormalizationOptions const & options
= NoiseNormalizationOptions());
// apply a given linear noise model
template <class T1, class S1,
class T2, class S2>
void
linearNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double a0, double a1);
}
\endcode
\deprecatedAPI{linearNoiseNormalization}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// estimate and apply a linear noise model
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
bool linearNoiseNormalization(SrcIterator sul, SrcIterator slr, Src Accessor src, bool linearNoiseNormalization(SrcIterator sul, SrcIterator slr, Src Accessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
NoiseNormalizationOptions const & opt ions = NoiseNormalizationOptions()); NoiseNormalizationOptions const & opt ions = NoiseNormalizationOptions());
// apply a given linear noise model
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, Src
Accessor src,
DestIterator dul, DestAccessor dest,
double a0, double a1);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// estimate and apply a linear noise model
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcA ccessor> src, bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcA ccessor> src,
pair<DestIterator, DestAccessor> dest , pair<DestIterator, DestAccessor> dest ,
NoiseNormalizationOptions const & opt ions = NoiseNormalizationOptions()); NoiseNormalizationOptions const & opt ions = NoiseNormalizationOptions());
// apply a given linear noise model
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcA
ccessor> src,
pair<DestIterator, DestAccessor> dest
,
double a0, double a1);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BRGBImage src(w,h), dest(w, h); vigra::BRGBImage src(w,h), dest(w, h);
... ...
// estimate the noise model and apply it to normalize the noise varianc
e
bool success = linearNoiseNormalization(src, dest,
NoiseNormalizationOptions().windowRadius(9).no
iseVarianceInitialGuess(25.0).
clusterCount(15));
vigra_postcondition(success, "linearNoiseNormalization(): Unable to est
imate noise model.");
// apply a pre-computed noise model
linearNoiseNormalization(src, dest, 100, 0.02);
\endcode
\deprecatedUsage{linearNoiseNormalization}
\code
vigra::BRGBImage src(w,h), dest(w, h);
...
// estimate the noise model and apply it to normalize the noise varianc
e
vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest), vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest),
vigra::NoiseNormalizationOptions().wind owRadius(9).noiseVarianceInitialGuess(25.0). vigra::NoiseNormalizationOptions().wind owRadius(9).noiseVarianceInitialGuess(25.0).
clusterCount(15)); clusterCount(15));
// apply a pre-computed noise model
vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest),
100, 0.02);
\endcode \endcode
\deprecatedEnd
<b> Required Interface:</b> <b> Required Interface:</b>
same as \ref noiseVarianceEstimation() The source value type must be convertible to <tt>double</tt> or must be
a vector whose elements
are convertible to <tt>double</tt>. Likewise, the destination type must
be assignable from <tt>double</tt>
or a vector whose elements are assignable from <tt>double</tt>.
*/ */
doxygen_overloaded_function(template <...> bool linearNoiseNormalization) doxygen_overloaded_function(template <...> bool linearNoiseNormalization)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline bool inline bool
linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) NoiseNormalizationOptions const & options = NoiseNormalizationOptions())
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
return detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, o ptions, return detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, o ptions,
typename NumericTraits<SrcType>::i sScalar()); typename NumericTraits<SrcType>::i sScalar());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline bool
bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src,
src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, NoiseNormalizationOptions const & options = NoiseN
NoiseNormalizationOptions const & opti ormalizationOptions())
ons = NoiseNormalizationOptions())
{ {
return linearNoiseNormalization(src.first, src.second, src.third, dest. first, dest.second, options); return linearNoiseNormalization(src.first, src.second, src.third, dest. first, dest.second, options);
} }
template <class T1, class S1,
class T2, class S2>
inline bool
linearNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
NoiseNormalizationOptions const & options = NoiseN
ormalizationOptions())
{
vigra_precondition(src.shape() == dest.shape(),
"linearNoiseNormalization(): shape mismatch between input and outpu
t.");
return linearNoiseNormalization(srcImageRange(src), destImage(dest), op
tions);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* linearNoiseNormalization */ /* linearNoiseNormalization */
/* (variant) */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Noise normalization by means of a given linear noise model.
This function works similar to \ref nonparametricNoiseNormalization() w
ith the exception that the
functional dependency of the noise variance from the intensity is given
(as a linear function)
rather than estimated:
\code
variance = a0 + a1 * intensity
\endcode
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, Src
Accessor src,
DestIterator dul, DestAccessor dest,
double a0, double a1);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcA
ccessor> src,
pair<DestIterator, DestAccessor> dest
,
double a0, double a1);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra
\code
vigra::BRGBImage src(w,h), dest(w, h);
...
vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest),
100, 0.02);
\endcode
<b> Required Interface:</b>
The source value type must be convertible to <tt>double</tt> or must be
a vector whose elements
are convertible to <tt>double</tt>. Likewise, the destination type must
be assignable from <tt>double</tt>
or a vector whose elements are assignable from <tt>double</tt>.
*/
doxygen_overloaded_function(template <...> void linearNoiseNormalization)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
double a0, double a1) double a0, double a1)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a1, detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a1,
typename NumericTraits<SrcType>::i sScalar()); typename NumericTraits<SrcType>::i sScalar());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src,
src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, double a0, double a1)
double a0, double a1)
{ {
linearNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, a0, a1); linearNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, a0, a1);
} }
template <class T1, class S1,
class T2, class S2>
inline void
linearNoiseNormalization(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double a0, double a1)
{
vigra_precondition(src.shape() == dest.shape(),
"linearNoiseNormalization(): shape mismatch between input and outpu
t.");
linearNoiseNormalization(srcImageRange(src), destImage(dest), a0, a1);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_NOISE_NORMALIZATION_HXX #endif // VIGRA_NOISE_NORMALIZATION_HXX
 End of changes. 79 change blocks. 
220 lines changed or deleted 425 lines changed or added


 nonlineardiffusion.hxx   nonlineardiffusion.hxx 
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_NONLINEARDIFFUSION_HXX #ifndef VIGRA_NONLINEARDIFFUSION_HXX
#define VIGRA_NONLINEARDIFFUSION_HXX #define VIGRA_NONLINEARDIFFUSION_HXX
#include <vector> #include <vector>
#include "stdimage.hxx" #include "stdimage.hxx"
#include "stdimagefunctions.hxx" #include "stdimagefunctions.hxx"
#include "imageiteratoradapter.hxx" #include "imageiteratoradapter.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class CoeffIterator, class DestIterator> class CoeffIterator, class DestIterator>
void internalNonlinearDiffusionDiagonalSolver( void internalNonlinearDiffusionDiagonalSolver(
SrcIterator sbegin, SrcIterator send, SrcAccessor sa, SrcIterator sbegin, SrcIterator send, SrcAccessor sa,
CoeffIterator diag, CoeffIterator upper, CoeffIterator lower, CoeffIterator diag, CoeffIterator upper, CoeffIterator lower,
DestIterator dbegin) DestIterator dbegin)
{ {
skipping to change at line 90 skipping to change at line 91
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class WeightIterator, class WeightAccessor, class WeightIterator, class WeightAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void internalNonlinearDiffusionAOSStep( void internalNonlinearDiffusionAOSStep(
SrcIterator sul, SrcIterator slr, SrcAccessor as, SrcIterator sul, SrcIterator slr, SrcAccessor as,
WeightIterator wul, WeightAccessor aw, WeightIterator wul, WeightAccessor aw,
DestIterator dul, DestAccessor ad, double timestep) DestIterator dul, DestAccessor ad, double timestep)
{ {
// use traits to determine SumType as to prevent possible overflow // use traits to determine SumType as to prevent possible overflow
typedef typename typedef typename
NumericTraits<typename DestAccessor::value_type>::RealPromote
DestType;
typedef typename
NumericTraits<typename WeightAccessor::value_type>::RealPromote NumericTraits<typename WeightAccessor::value_type>::RealPromote
WeightType; WeightType;
// calculate width and height of the image // calculate width and height of the image
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
int d = (w < h) ? h : w; int d = (w < h) ? h : w;
std::vector<WeightType> lower(d), std::vector<WeightType> lower(d),
diag(d), diag(d),
skipping to change at line 212 skipping to change at line 209
\left( g(|\nabla u|) \left( g(|\nabla u|)
\frac{\partial}{\partial x} u \frac{\partial}{\partial x} u
\right) \right)
\f] \f]
where <em> t</em> is the time, <b> x</b> is the location vector, where <em> t</em> is the time, <b> x</b> is the location vector,
<em> u(</em><b> x</b><em> , t)</em> is the smoothed image at time <em> t</em>, and <em> u(</em><b> x</b><em> , t)</em> is the smoothed image at time <em> t</em>, and
<em> g(.)</em> is the location dependent diffusivity. At time zero, the image <em> g(.)</em> is the location dependent diffusivity. At time zero, the image
<em> u(</em><b> x</b><em> , 0)</em> is simply the original image. The t ime is <em> u(</em><b> x</b><em> , 0)</em> is simply the original image. The t ime is
proportional to the square of the scale parameter: \f$t = s^2\f$. proportional to the square of the scale parameter: \f$t = s^2\f$.
The diffusion The diffusion equation is solved iteratively according
equation is solved iteratively according
to the Additive Operator Splitting Scheme (AOS) from to the Additive Operator Splitting Scheme (AOS) from
J. Weickert: <em>"Recursive Separable Schemes for Nonlinear Diffusion J. Weickert: <em>"Recursive Separable Schemes for Nonlinear Diffusion
Filters"</em>, Filters"</em>,
in: B. ter Haar Romeny, L. Florack, J. Koenderingk, M. Viergever (eds.) : in: B. ter Haar Romeny, L. Florack, J. Koenderingk, M. Viergever (eds.) :
1st Intl. Conf. on Scale-Space Theory in Computer Vision 1997, 1st Intl. Conf. on Scale-Space Theory in Computer Vision 1997,
Springer LNCS 1252 Springer LNCS 1252
<TT>DiffusivityFunctor</TT> implements the gradient dependent local dif fusivity. <TT>DiffusivityFunctor</TT> implements the gradient-dependent local dif fusivity.
It is passed It is passed
as an argument to \ref gradientBasedTransform(). The return value must be as an argument to \ref gradientBasedTransform(). The return value must be
between 0 and 1 and determines the weight a pixel gets when between 0 and 1 and determines the weight a pixel gets when
its neighbors are smoothed. Weickert recommends the use of the diffusiv ity its neighbors are smoothed. Weickert recommends the use of the diffusiv ity
implemented by class \ref DiffusivityFunctor. It's also possible to use implemented by class \ref DiffusivityFunctor. It's also possible to use
other functors, for example one that always returns 1, in which case other functors, for example one that always returns 1, in which case
we obtain the solution to the linear diffusion equation, i.e. we obtain the solution to the linear diffusion equation, i.e.
Gaussian convolution. Gaussian convolution.
The source value type must be a The source value type must be a
skipping to change at line 245 skipping to change at line 241
scalar field over wich the source value type's linear space is defined. scalar field over wich the source value type's linear space is defined.
In addition to <TT>nonlinearDiffusion()</TT>, there is an algorithm In addition to <TT>nonlinearDiffusion()</TT>, there is an algorithm
<TT>nonlinearDiffusionExplicit()</TT> which implements the Explicit Sch eme <TT>nonlinearDiffusionExplicit()</TT> which implements the Explicit Sch eme
described in the above article. Both algorithms have the same interface , described in the above article. Both algorithms have the same interface ,
but the explicit scheme gives slightly more accurate approximations of but the explicit scheme gives slightly more accurate approximations of
the diffusion process at the cost of much slower processing. the diffusion process at the cost of much slower processing.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class DiffusivityFunc>
void
nonlinearDiffusion(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DiffusivityFunc const & weight, double scale);
template <class T1, class S1,
class T2, class S2,
class DiffusivityFunc>
void
nonlinearDiffusionExplicit(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DiffusivityFunc const & weight, double s
cale);
}
\endcode
\deprecatedAPI{nonlinearDiffusion}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DiffusivityFunctor> class DiffusivityFunctor>
void nonlinearDiffusion(SrcIterator sul, SrcIterator slr, SrcAccess or as, void nonlinearDiffusion(SrcIterator sul, SrcIterator slr, SrcAccess or as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
DiffusivityFunctor const & weight, double s cale); DiffusivityFunctor const & weight, double s cale);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DiffusivityFunctor> class DiffusivityFunctor>
void nonlinearDiffusion( void nonlinearDiffusion(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DiffusivityFunctor const & weight, double scale); DiffusivityFunctor const & weight, double scale);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/nonlineardiffusion.hxx\> <b>\#include</b> \<vigra/nonlineardiffusion.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), dest(w,h);
float edge_threshold, scale;
...
nonlinearDiffusion(src, dest,
DiffusivityFunctor<float>(edge_threshold), scale);
\endcode
\deprecatedUsage{nonlinearDiffusion}
\code \code
FImage src(w,h), dest(w,h); FImage src(w,h), dest(w,h);
float edge_threshold, scale; float edge_threshold, scale;
... ...
nonlinearDiffusion(srcImageRange(src), destImage(dest), nonlinearDiffusion(srcImageRange(src), destImage(dest),
DiffusivityFunctor<float>(edge_threshold), scale); DiffusivityFunctor<float>(edge_threshold), scale);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
<ul> <ul>
<li> <TT>SrcIterator</TT> and <TT>DestIterator</TT> are models of Image Iterator <li> <TT>SrcIterator</TT> and <TT>DestIterator</TT> are models of Image Iterator
<li> <TT>SrcAccessor</TT> and <TT>DestAccessor</TT> are models of Stand ardAccessor <li> <TT>SrcAccessor</TT> and <TT>DestAccessor</TT> are models of Stand ardAccessor
<li> <TT>SrcAccessor::value_type</TT> is a linear space <li> <TT>SrcAccessor::value_type</TT> is a linear space
<li> <TT>DiffusivityFunctor</TT> conforms to the requirements of <li> <TT>DiffusivityFunctor</TT> conforms to the requirements of
\ref gradientBasedTransform(). Its range is between 0 and 1. \ref gradientBasedTransform(). Its range is between 0 and 1.
<li> <TT>DiffusivityFunctor::value_type</TT> is an algebraic field <li> <TT>DiffusivityFunctor::value_type</TT> is an algebraic field
</ul> </ul>
\deprecatedEnd
<b> Precondition:</b> <b> Precondition:</b>
<TT>scale > 0</TT> <TT>scale > 0</TT>
\see vigra::DiffusivityFunctor
*/ */
doxygen_overloaded_function(template <...> void nonlinearDiffusion) doxygen_overloaded_function(template <...> void nonlinearDiffusion)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DiffusivityFunc> class DiffusivityFunc>
void nonlinearDiffusion(SrcIterator sul, SrcIterator slr, SrcAccessor as, void nonlinearDiffusion(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
DiffusivityFunc const & weight, double scale) DiffusivityFunc const & weight, double scale)
{ {
vigra_precondition(scale > 0.0, "nonlinearDiffusion(): scale must be > 0"); vigra_precondition(scale > 0.0, "nonlinearDiffusion(): scale must be > 0");
double total_time = scale*scale/2.0; double total_time = scale*scale/2.0;
static const double time_step = 5.0; const double time_step = 5.0;
int number_of_steps = (int)(total_time / time_step); int number_of_steps = (int)(total_time / time_step);
double rest_time = total_time - time_step * number_of_steps; double rest_time = total_time - time_step * number_of_steps;
Size2D size(slr.x - sul.x, slr.y - sul.y); Size2D size(slr.x - sul.x, slr.y - sul.y);
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote NumericTraits<typename SrcAccessor::value_type>::RealPromote
TmpType; TmpType;
typedef typename DiffusivityFunc::value_type WeightType; typedef typename DiffusivityFunc::value_type WeightType;
skipping to change at line 354 skipping to change at line 382
std::swap(s1, s2); std::swap(s1, s2);
} }
copyImage(s1, s1+size, a, dul, ad); copyImage(s1, s1+size, a, dul, ad);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DiffusivityFunc> class DiffusivityFunc>
inline inline void
void nonlinearDiffusion( nonlinearDiffusion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, DiffusivityFunc const & weight, double scale)
DiffusivityFunc const & weight, double scale)
{ {
nonlinearDiffusion(src.first, src.second, src.third, nonlinearDiffusion(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
weight, scale); weight, scale);
} }
template <class T1, class S1,
class T2, class S2,
class DiffusivityFunc>
inline void
nonlinearDiffusion(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DiffusivityFunc const & weight, double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"nonlinearDiffusion(): shape mismatch between input and output.");
nonlinearDiffusion(srcImageRange(src),
destImage(dest),
weight, scale);
}
/********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class WeightIterator, class WeightAccessor, class WeightIterator, class WeightAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void internalNonlinearDiffusionExplicitStep( void internalNonlinearDiffusionExplicitStep(
SrcIterator sul, SrcIterator slr, SrcAccessor as, SrcIterator sul, SrcIterator slr, SrcAccessor as,
WeightIterator wul, WeightAccessor aw, WeightIterator wul, WeightAccessor aw,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double time_step) double time_step)
{ {
// use traits to determine SumType as to prevent possible overflow // use traits to determine SumType as to prevent possible overflow
skipping to change at line 389 skipping to change at line 433
typedef typename typedef typename
NumericTraits<typename WeightAccessor::value_type>::RealPromote NumericTraits<typename WeightAccessor::value_type>::RealPromote
WeightType; WeightType;
// calculate width and height of the image // calculate width and height of the image
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
int x,y; int x,y;
static const Diff2D left(-1, 0); const Diff2D left(-1, 0);
static const Diff2D right(1, 0); const Diff2D right(1, 0);
static const Diff2D top(0, -1); const Diff2D top(0, -1);
static const Diff2D bottom(0, 1); const Diff2D bottom(0, 1);
WeightType gt, gb, gl, gr, g0; WeightType gt, gb, gl, gr, g0;
WeightType one = NumericTraits<WeightType>::one(); WeightType one = NumericTraits<WeightType>::one();
SumType sum; SumType sum;
time_step /= 2.0; time_step /= 2.0;
// create y iterators // create y iterators
SrcIterator ys = sul; SrcIterator ys = sul;
WeightIterator yw = wul; WeightIterator yw = wul;
skipping to change at line 556 skipping to change at line 600
sum = g0 * as(xs); sum = g0 * as(xs);
sum += gt * as(xs, top); sum += gt * as(xs, top);
sum += gb * as(xs, top); sum += gb * as(xs, top);
sum += gl * as(xs, left); sum += gl * as(xs, left);
sum += gr * as(xs, left); sum += gr * as(xs, left);
ad.set(sum, xd); ad.set(sum, xd);
} }
/** \brief Perform edge-preserving smoothing at the given scale using an ex
plicit scheme.
See \ref nonlinearDiffusion().
*/
doxygen_overloaded_function(template <...> void nonlinearDiffusionExplicit)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DiffusivityFunc> class DiffusivityFunc>
void nonlinearDiffusionExplicit(SrcIterator sul, SrcIterator slr, SrcAccess or as, void nonlinearDiffusionExplicit(SrcIterator sul, SrcIterator slr, SrcAccess or as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
DiffusivityFunc const & weight, double scale) DiffusivityFunc const & weight, double scale)
{ {
vigra_precondition(scale > 0.0, "nonlinearDiffusionExplicit(): scale mu st be > 0"); vigra_precondition(scale > 0.0, "nonlinearDiffusionExplicit(): scale mu st be > 0");
double total_time = scale*scale/2.0; double total_time = scale*scale/2.0;
static const double time_step = 0.25; const double time_step = 0.25;
int number_of_steps = total_time / time_step; int number_of_steps = total_time / time_step;
double rest_time = total_time - time_step * number_of_steps; double rest_time = total_time - time_step * number_of_steps;
Size2D size(slr.x - sul.x, slr.y - sul.y); Size2D size(slr.x - sul.x, slr.y - sul.y);
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote NumericTraits<typename SrcAccessor::value_type>::RealPromote
TmpType; TmpType;
typedef typename DiffusivityFunc::value_type WeightType; typedef typename DiffusivityFunc::value_type WeightType;
skipping to change at line 608 skipping to change at line 658
swap(s1, s2); swap(s1, s2);
} }
copyImage(s1, s1+size, a, dul, ad); copyImage(s1, s1+size, a, dul, ad);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DiffusivityFunc> class DiffusivityFunc>
inline inline void
void nonlinearDiffusionExplicit( nonlinearDiffusionExplicit(triple<SrcIterator, SrcIterator, SrcAccessor> sr
triple<SrcIterator, SrcIterator, SrcAccessor> src, c,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DiffusivityFunc const & weight, double scale) DiffusivityFunc const & weight, double scale)
{ {
nonlinearDiffusionExplicit(src.first, src.second, src.third, nonlinearDiffusionExplicit(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
weight, scale); weight, scale);
}
template <class T1, class S1,
class T2, class S2,
class DiffusivityFunc>
inline void
nonlinearDiffusionExplicit(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
DiffusivityFunc const & weight, double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"nonlinearDiffusionExplicit(): shape mismatch between input and out
put.");
nonlinearDiffusionExplicit(srcImageRange(src),
destImage(dest),
weight, scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* DiffusivityFunctor */ /* DiffusivityFunctor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Diffusivity functor for non-linear diffusion. /** \brief Diffusivity functor for non-linear diffusion.
 End of changes. 24 change blocks. 
34 lines changed or deleted 102 lines changed or added


 numerictraits.hxx   numerictraits.hxx 
skipping to change at line 84 skipping to change at line 84
NumericTraits are implemented as template specializations of one NumericTraits are implemented as template specializations of one
arithmetic type, while PromoteTraits are specialized for a pair of arithmetic type, while PromoteTraits are specialized for a pair of
arithmetic types that shall be combined in one operation. arithmetic types that shall be combined in one operation.
*/ */
/** \page NumericTraits template<> struct NumericTraits<ArithmeticType> /** \page NumericTraits template<> struct NumericTraits<ArithmeticType>
Unary traits for promotion, conversion, creation of arithmetic objects. Unary traits for promotion, conversion, creation of arithmetic objects.
<b>\#include</b> <b>\#include</b> \<vigra/numerictraits.hxx\>
\<vigra/numerictraits.hxx\>
This traits class is used derive important properties of This traits class is used derive important properties of
an arithmetic type. Consider the following algorithm: an arithmetic type. Consider the following algorithm:
\code \code
// calculate the sum of a sequence of bytes // calculate the sum of a sequence of bytes
int sumBytes(unsigned char * begin, unsigned char * end) int sumBytes(unsigned char * begin, unsigned char * end)
{ {
int result = 0; int result = 0;
for(; begin != end; ++begin) result += *begin; for(; begin != end; ++begin) result += *begin;
skipping to change at line 313 skipping to change at line 312
<tr><td> <tr><td>
<b> <TT>typedef ... isComplex;</TT></b> <b> <TT>typedef ... isComplex;</TT></b>
</td><td> </td><td>
VigraTrueType if <TT>ArithmeticType</TT> is a complex number, VigraTrueType if <TT>ArithmeticType</TT> is a complex number,
VigraFalseType otherwise VigraFalseType otherwise
</td></tr> </td></tr>
<tr><td> <tr><td>
</table> </table>
NumericTraits for the built-in types are defined in <b>\#include</b> NumericTraits for the built-in types are defined in <b>\#include</b> \<
\<vigra/numerictraits.hxx\> vigra/numerictraits.hxx\>
Namespace: vigra Namespace: vigra
*/ */
/** \page PromoteTraits template<> struct PromoteTraits<ArithmeticType1, Ar ithmeticType2> /** \page PromoteTraits template<> struct PromoteTraits<ArithmeticType1, Ar ithmeticType2>
Binary traits for promotion of arithmetic objects. Binary traits for promotion of arithmetic objects.
<b>\#include</b> <b>\#include</b> \<vigra/numerictraits.hxx\>
\<vigra/numerictraits.hxx\>
This traits class is used to determine the appropriate result type This traits class is used to determine the appropriate result type
of arithmetic expressions which depend of two arguments. Consider of arithmetic expressions which depend of two arguments. Consider
the following function: the following function:
\code \code
template <class T> template <class T>
T min(T t1, T t2) T min(T t1, T t2)
{ {
return (t1 < t2) ? t1 : t2; return (t1 < t2) ? t1 : t2;
skipping to change at line 376 skipping to change at line 373
</td></tr> </td></tr>
<tr><td> <tr><td>
<b> <TT>static Promote toPromote(ArithmeticType1 v);</TT></b> <b> <TT>static Promote toPromote(ArithmeticType1 v);</TT></b>
<b> <TT>static Promote toPromote(ArithmeticType2 v);</TT></b> <b> <TT>static Promote toPromote(ArithmeticType2 v);</TT></b>
</td><td> </td><td>
convert to <TT>Promote</TT> type convert to <TT>Promote</TT> type
</td></tr> </td></tr>
</table> </table>
PromoteTraits for the built-in types are defined in <b>\#include</b> PromoteTraits for the built-in types are defined in <b>\#include</b> \<
\<vigra/numerictraits.hxx\> vigra/numerictraits.hxx\>
Namespace: vigra Namespace: vigra
*/ */
/** \page SquareRootTraits template<> struct SquareRootTraits<ArithmeticTyp e> /** \page SquareRootTraits template<> struct SquareRootTraits<ArithmeticTyp e>
Unary traits for the calculation of the square root of arithmetic objec ts. Unary traits for the calculation of the square root of arithmetic objec ts.
<b>\#include</b> <b>\#include</b> \<vigra/numerictraits.hxx\>
\<vigra/numerictraits.hxx\>
This traits class is used to determine appropriate argument and result types This traits class is used to determine appropriate argument and result types
for the function sqrt(). These traits are typically used like this: for the function sqrt(). These traits are typically used like this:
\code \code
ArithmeticType t = ...; ArithmeticType t = ...;
SquareRootTraits<ArithmeticType>::SquareRootResult r = SquareRootTraits<ArithmeticType>::SquareRootResult r =
sqrt((SquareRootTraits<ArithmeticType>::SquareRootArgument)t); sqrt((SquareRootTraits<ArithmeticType>::SquareRootArgument)t);
\endcode \endcode
skipping to change at line 422 skipping to change at line 417
</td><td> </td><td>
required argument type for srqt(), i.e. <tt>sqrt((SquareRootArg ument)x)</tt> required argument type for srqt(), i.e. <tt>sqrt((SquareRootArg ument)x)</tt>
</td></tr> </td></tr>
<tr><td> <tr><td>
<b> <TT>typedef ... SquareRootResult;</TT></b> <b> <TT>typedef ... SquareRootResult;</TT></b>
</td><td> </td><td>
result of <tt>sqrt((SquareRootArgument)x)</tt> result of <tt>sqrt((SquareRootArgument)x)</tt>
</td></tr> </td></tr>
</table> </table>
NormTraits for the built-in types are defined in <b>\#include</b> NormTraits for the built-in types are defined in <b>\#include</b> \<vig
\<vigra/numerictraits.hxx\> ra/numerictraits.hxx\>
Namespace: vigra Namespace: vigra
*/ */
/** \page NormTraits template<> struct NormTraits<ArithmeticType> /** \page NormTraits template<> struct NormTraits<ArithmeticType>
Unary traits for the calculation of the norm and squared norm of arithm etic objects. Unary traits for the calculation of the norm and squared norm of arithm etic objects.
<b>\#include</b> <b>\#include</b> \<vigra/numerictraits.hxx\>
\<vigra/numerictraits.hxx\>
This traits class is used to determine appropriate result types This traits class is used to determine appropriate result types
for the functions norm() and squaredNorm(). These functions are always for the functions norm() and squaredNorm(). These functions are always
declared like this (where <tt>ArithmeticType</tt> is a type that suppor ts a norm): declared like this (where <tt>ArithmeticType</tt> is a type that suppor ts a norm):
\code \code
NormTraits<ArithmeticType>::NormType norm(ArithmeticType const & t); NormTraits<ArithmeticType>::NormType norm(ArithmeticType const & t);
NormTraits<ArithmeticType>::SquaredNormType squaredNorm(ArithmeticType const & t); NormTraits<ArithmeticType>::SquaredNormType squaredNorm(ArithmeticType const & t);
\endcode \endcode
skipping to change at line 465 skipping to change at line 458
result of <tt>squaredNorm(ArithmeticType)</tt> result of <tt>squaredNorm(ArithmeticType)</tt>
</td></tr> </td></tr>
<tr><td> <tr><td>
<b> <TT>typedef ... NormType;</TT></b> <b> <TT>typedef ... NormType;</TT></b>
</td><td> </td><td>
result of <tt>norm(ArithmeticType)</tt><br> result of <tt>norm(ArithmeticType)</tt><br>
Usually equal to <tt>SquareRootTraits<SquaredNormType>::SquareR ootResult</tt> Usually equal to <tt>SquareRootTraits<SquaredNormType>::SquareR ootResult</tt>
</td></tr> </td></tr>
</table> </table>
NormTraits for the built-in types are defined in <b>\#include</b> NormTraits for the built-in types are defined in <b>\#include</b> \<vig
\<vigra/numerictraits.hxx\> ra/numerictraits.hxx\>
Namespace: vigra Namespace: vigra
*/ */
namespace vigra { namespace vigra {
namespace detail { namespace detail {
template <typename s, typename t> template <typename s, typename t>
inline static t clamp_integer_to_unsigned(s value, t maximum) { inline static t clamp_integer_to_unsigned(s value, t maximum) {
return return
value <= s() ? value <= s() ?
 End of changes. 8 change blocks. 
16 lines changed or deleted 12 lines changed or added


 numpy_array.hxx   numpy_array.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_NUMPY_ARRAY_HXX #ifndef VIGRA_NUMPY_ARRAY_HXX
#define VIGRA_NUMPY_ARRAY_HXX #define VIGRA_NUMPY_ARRAY_HXX
#ifndef NPY_NO_DEPRECATED_API
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include <Python.h> #include <Python.h>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <numpy/arrayobject.h> #include <numpy/arrayobject.h>
#include "multi_array.hxx" #include "multi_array.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "python_utility.hxx" #include "python_utility.hxx"
#include "numpy_array_traits.hxx" #include "numpy_array_traits.hxx"
#include "numpy_array_taggedshape.hxx" #include "numpy_array_taggedshape.hxx"
// NumPy function called by NumPy’s import_array() macro (and our import_ vigranumpy() below) // NumPy function called by NumPy's import_array() macro (and our import_vi granumpy() below)
int _import_array(); int _import_array();
namespace vigra { namespace vigra {
static inline void import_vigranumpy() static inline void import_vigranumpy()
{ {
// roughly equivalent to import_array(): // roughly equivalent to import_array():
if(_import_array() < 0) if(_import_array() < 0)
pythonToCppException(0); pythonToCppException(0);
// in addition, import vigra.vigranumpycore: // Import vigra to activate the numpy array converters, but ensure that
python_ptr module(PyImport_ImportModule("vigra.vigranumpycore"), python // cyclic imports (from within vigra itself) are avoided.
_ptr::keep_count); char const * load_vigra =
pythonToCppException(module); "import sys\n"
"if not sys.modules.has_key('vigra.vigranumpycore'):\n"
" import vigra\n";
pythonToCppException(PyRun_SimpleString(load_vigra) == 0);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* MultibandVectorAccessor */ /* MultibandVectorAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
template <class T> template <class T>
class MultibandVectorAccessor class MultibandVectorAccessor
skipping to change at line 147 skipping to change at line 155
/********************************************************/ /********************************************************/
template <class TYPECODE> // pseudo-template to avoid inline expansion of t he function template <class TYPECODE> // pseudo-template to avoid inline expansion of t he function
// will always be NPY_TYPES // will always be NPY_TYPES
PyObject * PyObject *
constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init, constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init,
python_ptr arraytype = python_ptr()); python_ptr arraytype = python_ptr());
/********************************************************/ /********************************************************/
template <class Shape>
void numpyParseSlicing(Shape const & shape, PyObject * idx, Shape & start,
Shape & stop)
{
int N = shape.size();
for(int k=0; k<N; ++k)
{
start[k] = 0;
stop[k] = shape[k];
}
python_ptr index(idx);
if(!PySequence_Check(index))
{
index = python_ptr(PyTuple_Pack(1, index.ptr()), python_ptr::new_no
nzero_reference);
}
int lindex = PyTuple_Size(index);
int kindex = 0;
for(; kindex<lindex; ++kindex)
{
if(PyTuple_GET_ITEM((PyTupleObject *)index.ptr(), kindex) == Py_Ell
ipsis)
break;
}
if(kindex == lindex && lindex < N)
{
python_ptr ellipsis = python_ptr(PyTuple_Pack(1, Py_Ellipsis), pyth
on_ptr::new_nonzero_reference);
index = python_ptr(PySequence_Concat(index, ellipsis), python_ptr::
new_nonzero_reference);
++lindex;
}
kindex = 0;
for(int k=0; k < N; ++k)
{
PyObject * item = PyTuple_GET_ITEM((PyTupleObject *)index.ptr(), ki
ndex);
if(PyInt_Check(item))
{
MultiArrayIndex i = PyInt_AsLong(item);
start[k] = i;
if(start[k] < 0)
start[k] += shape[k];
stop[k] = start[k];
++kindex;
}
else if(PySlice_Check(item))
{
Py_ssize_t sstart, sstop, step;
if(PySlice_GetIndices((PySliceObject *)item, shape[k], &sstart,
&sstop, &step) != 0)
pythonToCppException(0);
vigra_precondition(step == 1,
"numpyParseSlicing(): only unit steps are supported.");
start[k] = sstart;
stop[k] = sstop;
++kindex;
}
else if(item == Py_Ellipsis)
{
if(lindex == N)
++kindex;
else
++lindex;
}
else
{
vigra_precondition(false,
"numpyParseSlicing(): unsupported index object.");
}
}
}
/********************************************************/
/* */ /* */
/* NumpyAnyArray */ /* NumpyAnyArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** Wrapper class for a Python array. /** Wrapper class for a Python array.
This class stores a reference-counted pointer to an Python numpy array object, This class stores a reference-counted pointer to an Python numpy array object,
i.e. an object where <tt>PyArray_Check(object)</tt> returns true (in Py thon, the i.e. an object where <tt>PyArray_Check(object)</tt> returns true (in Py thon, the
object is then a subclass of <tt>numpy.ndarray</tt>). This class is mai nly used object is then a subclass of <tt>numpy.ndarray</tt>). This class is mai nly used
skipping to change at line 281 skipping to change at line 358
return *this; return *this;
} }
/** /**
Returns the number of dimensions of this array, or 0 if Returns the number of dimensions of this array, or 0 if
hasData() is false. hasData() is false.
*/ */
MultiArrayIndex ndim() const MultiArrayIndex ndim() const
{ {
if(hasData()) if(hasData())
return PyArray_NDIM(pyObject()); return PyArray_NDIM(pyArray());
return 0; return 0;
} }
/** /**
Returns the number of spatial dimensions of this array, or 0 if Returns the number of spatial dimensions of this array, or 0 if
hasData() is false. If the enclosed Python array does not define hasData() is false. If the enclosed Python array does not define
the attribute spatialDimensions, ndim() is returned. the attribute spatialDimensions, ndim() is returned.
*/ */
MultiArrayIndex spatialDimensions() const MultiArrayIndex spatialDimensions() const
{ {
skipping to change at line 325 skipping to change at line 402
return pythonGetAttr(pyObject(), "innerNonchannelIndex", ndim()); return pythonGetAttr(pyObject(), "innerNonchannelIndex", ndim());
} }
/** /**
Returns the shape of this array. The size of Returns the shape of this array. The size of
the returned shape equals ndim(). the returned shape equals ndim().
*/ */
difference_type shape() const difference_type shape() const
{ {
if(hasData()) if(hasData())
return difference_type(PyArray_DIMS(pyObject()), PyArray_DIMS(p yObject()) + ndim()); return difference_type(PyArray_DIMS(pyArray()), PyArray_DIMS(py Array()) + ndim());
return difference_type(); return difference_type();
} }
/** Compute the ordering of the strides of this array. /** Compute the ordering of the strides of this array.
The result is describes the current permutation of the axes rel ative The result is describes the current permutation of the axes rel ative
to an ascending stride order. to an ascending stride order.
*/ */
difference_type strideOrdering() const difference_type strideOrdering() const
{ {
if(!hasData()) if(!hasData())
return difference_type(); return difference_type();
MultiArrayIndex N = ndim(); MultiArrayIndex N = ndim();
difference_type stride(PyArray_STRIDES(pyObject()), PyArray_STRIDES (pyObject()) + N), difference_type stride(PyArray_STRIDES(pyArray()), PyArray_STRIDES( pyArray()) + N),
permutation(N); permutation(N);
for(MultiArrayIndex k=0; k<N; ++k) for(MultiArrayIndex k=0; k<N; ++k)
permutation[k] = k; permutation[k] = k;
for(MultiArrayIndex k=0; k<N-1; ++k) for(MultiArrayIndex k=0; k<N-1; ++k)
{ {
MultiArrayIndex smallest = k; MultiArrayIndex smallest = k;
for(MultiArrayIndex j=k+1; j<N; ++j) for(MultiArrayIndex j=k+1; j<N; ++j)
{ {
if(stride[j] < stride[smallest]) if(stride[j] < stride[smallest])
smallest = j; smallest = j;
skipping to change at line 391 skipping to change at line 468
// return res; // return res;
// } // }
/** /**
Returns the value type of the elements in this array, or -1 Returns the value type of the elements in this array, or -1
when hasData() is false. when hasData() is false.
*/ */
int dtype() const int dtype() const
{ {
if(hasData()) if(hasData())
return PyArray_DESCR(pyObject())->type_num; return PyArray_DESCR(pyArray())->type_num;
return -1; return -1;
} }
/** /**
Constructs a slicing from the given shape objects and calls '__get
item__'.
*/
template <class Shape>
NumpyAnyArray
getitem(Shape start, Shape stop) const
{
unsigned int size = ndim();
vigra_precondition(start.size() == size && stop.size() == size,
"NumpyAnyArray::getitem(): shape has wrong dimension.");
difference_type s(this->shape());
python_ptr index(PyTuple_New(size), python_ptr::new_nonzero_referen
ce);
for(unsigned int k=0; k<size; ++k)
{
if(start[k] < 0)
start[k] += s[k];
if(stop[k] < 0)
stop[k] += s[k];
vigra_precondition(0 <= start[k] && start[k] <= stop[k] && stop
[k] <= s[k],
"NumpyAnyArray::getitem(): slice out of bounds.");
PyObject * item = 0;
if(start[k] == stop[k])
{
item = PyInt_FromLong(start[k]);
}
else
{
python_ptr s0(PyInt_FromLong(start[k]), python_ptr::new_non
zero_reference);
python_ptr s1(PyInt_FromLong(stop[k]), python_ptr::new_nonz
ero_reference);
item = PySlice_New(s0, s1, 0);
}
pythonToCppException(item);
PyTuple_SET_ITEM((PyTupleObject *)index.ptr(), k, item); // ste
als reference to item
}
python_ptr func(PyString_FromString("__getitem__"), python_ptr::new
_nonzero_reference);
python_ptr res(PyObject_CallMethodObjArgs(pyObject(), func.ptr(), i
ndex.ptr(), NULL),
python_ptr::new_nonzero_reference);
return NumpyAnyArray(res.ptr());
}
/**
* Return the AxisTags of this array or a NULL pointer when the att ribute * Return the AxisTags of this array or a NULL pointer when the att ribute
'axistags' is missing in the Python object or this array has no data. 'axistags' is missing in the Python object or this array has no data.
*/ */
python_ptr axistags() const python_ptr axistags() const
{ {
static python_ptr key(PyString_FromString("axistags"), python_ptr::
keep_count);
python_ptr axistags; python_ptr axistags;
if(pyObject()) if(pyObject())
{ {
python_ptr key(PyString_FromString("axistags"), python_ptr::kee p_count);
axistags.reset(PyObject_GetAttr(pyObject(), key), python_ptr::k eep_count); axistags.reset(PyObject_GetAttr(pyObject(), key), python_ptr::k eep_count);
if(!axistags) if(!axistags)
PyErr_Clear(); PyErr_Clear();
} }
return axistags; return axistags;
} }
/** /**
* Return a borrowed reference to the internal PyArrayObject. * Return a borrowed reference to the internal PyArrayObject.
*/ */
skipping to change at line 558 skipping to change at line 677
// FIXME: reimplement in terms of TaggedShape? // FIXME: reimplement in terms of TaggedShape?
template <class TINY_VECTOR> template <class TINY_VECTOR>
inline inline
python_ptr constructNumpyArrayFromData( python_ptr constructNumpyArrayFromData(
TINY_VECTOR const & shape, npy_intp *strides, TINY_VECTOR const & shape, npy_intp *strides,
NPY_TYPES typeCode, void *data) NPY_TYPES typeCode, void *data)
{ {
ArrayVector<npy_intp> pyShape(shape.begin(), shape.end()); ArrayVector<npy_intp> pyShape(shape.begin(), shape.end());
#ifndef NPY_ARRAY_WRITEABLE
# define NPY_ARRAY_WRITEABLE NPY_WRITEABLE // old API compatibility
#endif
python_ptr array(PyArray_New(&PyArray_Type, shape.size(), pyShape.begin (), python_ptr array(PyArray_New(&PyArray_Type, shape.size(), pyShape.begin (),
typeCode, strides, data, 0, NPY_WRITEABLE, 0), typeCode, strides, data, 0, NPY_ARRAY_WRIT EABLE, 0),
python_ptr::keep_count); python_ptr::keep_count);
pythonToCppException(array); pythonToCppException(array);
return array; return array;
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* NumpyArray */ /* NumpyArray */
/* */ /* */
skipping to change at line 1117 skipping to change at line 1240
{ {
if(NumpyAnyArray::hasData()) if(NumpyAnyArray::hasData())
{ {
permutation_type permute; permutation_type permute;
ArrayTraits::permutationToSetupOrder(this->pyArray_, permute); ArrayTraits::permutationToSetupOrder(this->pyArray_, permute);
vigra_precondition(abs((int)permute.size() - actual_dimension) <= 1 , vigra_precondition(abs((int)permute.size() - actual_dimension) <= 1 ,
"NumpyArray::setupArrayView(): got array of incompatible shape (should never happen)."); "NumpyArray::setupArrayView(): got array of incompatible shape (should never happen).");
applyPermutation(permute.begin(), permute.end(), applyPermutation(permute.begin(), permute.end(),
pyArray()->dimensions, this->m_shape.begin()); PyArray_DIMS(pyArray()), this->m_shape.begin());
applyPermutation(permute.begin(), permute.end(), applyPermutation(permute.begin(), permute.end(),
pyArray()->strides, this->m_stride.begin()); PyArray_STRIDES(pyArray()), this->m_stride.begin() );
if((int)permute.size() == actual_dimension - 1) if((int)permute.size() == actual_dimension - 1)
{ {
this->m_shape[actual_dimension-1] = 1; this->m_shape[actual_dimension-1] = 1;
this->m_stride[actual_dimension-1] = sizeof(value_type); this->m_stride[actual_dimension-1] = sizeof(value_type);
} }
this->m_stride /= sizeof(value_type); this->m_stride /= sizeof(value_type);
this->m_ptr = reinterpret_cast<pointer>(pyArray()->data); this->m_ptr = reinterpret_cast<pointer>(PyArray_DATA(pyArray()));
vigra_precondition(this->checkInnerStride(Stride()), vigra_precondition(this->checkInnerStride(Stride()),
"NumpyArray<..., UnstridedArrayTag>::setupArrayView(): First di mension of given array is not unstrided (should never happen)."); "NumpyArray<..., UnstridedArrayTag>::setupArrayView(): First di mension of given array is not unstrided (should never happen).");
} }
else else
{ {
this->m_ptr = 0; this->m_ptr = 0;
} }
} }
skipping to change at line 1188 skipping to change at line 1311
} }
template <class PixelType, class Stride> template <class PixelType, class Stride>
inline triple< StridedImageIterator<PixelType>, inline triple< StridedImageIterator<PixelType>,
StridedImageIterator<PixelType>, StridedImageIterator<PixelType>,
MultibandVectorAccessor<PixelType> > MultibandVectorAccessor<PixelType> >
destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img) destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img)
{ {
StridedImageIterator<PixelType> StridedImageIterator<PixelType>
ul(img.data(), 1, img.stride(0), img.stride(1)); ul(img.data(), 1, img.stride(0), img.stride(1));
typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
return triple<StridedImageIterator<PixelType>, return triple<StridedImageIterator<PixelType>,
StridedImageIterator<PixelType>, StridedImageIterator<PixelType>,
MultibandVectorAccessor<PixelType> > MultibandVectorAccessor<PixelType> >
(ul, ul + Size2D(img.shape(0), img.shape(1)), (ul, ul + Size2D(img.shape(0), img.shape(1)),
MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2))); MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
} }
template <class PixelType, class Stride> template <class PixelType, class Stride>
inline pair< StridedImageIterator<PixelType>, inline pair< StridedImageIterator<PixelType>,
MultibandVectorAccessor<PixelType> > MultibandVectorAccessor<PixelType> >
skipping to change at line 1214 skipping to change at line 1336
(ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2) )); (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2) ));
} }
template <class PixelType, class Stride> template <class PixelType, class Stride>
inline pair< ConstStridedImageIterator<PixelType>, inline pair< ConstStridedImageIterator<PixelType>,
MultibandVectorAccessor<PixelType> > MultibandVectorAccessor<PixelType> >
maskImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img) maskImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
{ {
ConstStridedImageIterator<PixelType> ConstStridedImageIterator<PixelType>
ul(img.data(), 1, img.stride(0), img.stride(1)); ul(img.data(), 1, img.stride(0), img.stride(1));
typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccess or<PixelType> > return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccess or<PixelType> >
(ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2) )); (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2) ));
} }
} // namespace vigra } // namespace vigra
#endif // VIGRA_NUMPY_ARRAY_HXX #endif // VIGRA_NUMPY_ARRAY_HXX
 End of changes. 18 change blocks. 
18 lines changed or deleted 152 lines changed or added


 numpy_array_converters.hxx   numpy_array_converters.hxx 
skipping to change at line 221 skipping to change at line 221
\ \
template <class T1, \ template <class T1, \
class T2 = void, \ class T2 = void, \
class T3 = void, \ class T3 = void, \
class T4 = void, \ class T4 = void, \
class T5 = void, \ class T5 = void, \
class T6 = void, \ class T6 = void, \
class T7 = void, \ class T7 = void, \
class T8 = void, \ class T8 = void, \
class T9 = void, \ class T9 = void, \
class T10 = void> \ class T10 = void, \
class T11 = void, \
class T12 = void> \
struct functor_name \ struct functor_name \
: public boost::python::TypeList<typename functor_name##Impl<T1>::type, \ : public boost::python::TypeList<typename functor_name##Impl<T1>::type, \
boost::python::TypeList<typename functor_name##Impl<T2>::type, \ boost::python::TypeList<typename functor_name##Impl<T2>::type, \
boost::python::TypeList<typename functor_name##Impl<T3>::type, \ boost::python::TypeList<typename functor_name##Impl<T3>::type, \
boost::python::TypeList<typename functor_name##Impl<T4>::type, \ boost::python::TypeList<typename functor_name##Impl<T4>::type, \
boost::python::TypeList<typename functor_name##Impl<T5>::type, \ boost::python::TypeList<typename functor_name##Impl<T5>::type, \
boost::python::TypeList<typename functor_name##Impl<T6>::type, \ boost::python::TypeList<typename functor_name##Impl<T6>::type, \
boost::python::TypeList<typename functor_name##Impl<T7>::type, \ boost::python::TypeList<typename functor_name##Impl<T7>::type, \
boost::python::TypeList<typename functor_name##Impl<T8>::type, \ boost::python::TypeList<typename functor_name##Impl<T8>::type, \
boost::python::TypeList<typename functor_name##Impl<T9>::type, \ boost::python::TypeList<typename functor_name##Impl<T9>::type, \
boost::python::TypeList<typename functor_name##Impl<T10>::type, \ boost::python::TypeList<typename functor_name##Impl<T10>::type, \
boost::python::TypeList<void, void> > > > > > > > > > > \ boost::python::TypeList<typename functor_name##Impl<T11>::type, \
boost::python::TypeList<typename functor_name##Impl<T12>::type, \
boost::python::TypeList<void, void> > > > > > > > > > > > > \
{}; {};
template <class Head, class Tail> template <class Head, class Tail>
struct TypeList struct TypeList
{ {
typedef Head head; typedef Head head;
typedef Tail tail; typedef Tail tail;
}; };
// in the sequel, the doc string is only registered with the last // in the sequel, the doc string is only registered with the last
 End of changes. 2 change blocks. 
2 lines changed or deleted 6 lines changed or added


 numpy_array_taggedshape.hxx   numpy_array_taggedshape.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_NUMPY_ARRAY_TAGGEDSHAPE_HXX #ifndef VIGRA_NUMPY_ARRAY_TAGGEDSHAPE_HXX
#define VIGRA_NUMPY_ARRAY_TAGGEDSHAPE_HXX #define VIGRA_NUMPY_ARRAY_TAGGEDSHAPE_HXX
#ifndef NPY_NO_DEPRECATED_API
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include <string> #include <string>
#include "array_vector.hxx" #include "array_vector.hxx"
#include "python_utility.hxx" #include "python_utility.hxx"
#include "axistags.hxx" #include "axistags.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
inline inline
skipping to change at line 573 skipping to change at line 577
{ {
// FIXME: add some checks? // FIXME: add some checks?
channelAxis = last; channelAxis = last;
return *this; return *this;
} }
// transposeShape() means: only shape and resolution are transposed, no t the axis keys // transposeShape() means: only shape and resolution are transposed, no t the axis keys
template <class U, int N> template <class U, int N>
TaggedShape & transposeShape(TinyVector<U, N> const & p) TaggedShape & transposeShape(TinyVector<U, N> const & p)
{ {
int ntags = axistags.size(); if(axistags)
ArrayVector<npy_intp> permute = axistags.permutationToNormalOrder() {
; int ntags = axistags.size();
ArrayVector<npy_intp> permute = axistags.permutationToNormalOrd
int tstart = (axistags.channelIndex(ntags) < ntags) er();
? 1
: 0;
int sstart = (channelAxis == first)
? 1
: 0;
int ndim = ntags - tstart;
vigra_precondition(N == ndim,
"TaggedShape.transposeShape(): size mismatch.");
PyAxisTags newAxistags(axistags.axistags); // force copy int tstart = (axistags.channelIndex(ntags) < ntags)
for(int k=0; k<ndim; ++k) ? 1
: 0;
int sstart = (channelAxis == first)
? 1
: 0;
int ndim = ntags - tstart;
vigra_precondition(N == ndim,
"TaggedShape.transposeShape(): size mismatch.");
PyAxisTags newAxistags(axistags.axistags); // force copy
for(int k=0; k<ndim; ++k)
{
original_shape[k+sstart] = shape[p[k]+sstart];
newAxistags.setResolution(permute[k+tstart], axistags.resol
ution(permute[p[k]+tstart]));
}
axistags = newAxistags;
}
else
{ {
original_shape[k+sstart] = shape[p[k]+sstart]; for(int k=0; k<N; ++k)
newAxistags.setResolution(permute[k+tstart], axistags.resolutio {
n(permute[p[k]+tstart])); original_shape[k] = shape[p[k]];
}
} }
shape = original_shape; shape = original_shape;
axistags = newAxistags;
return *this; return *this;
} }
TaggedShape & toFrequencyDomain(int sign = 1) TaggedShape & toFrequencyDomain(int sign = 1)
{ {
int ntags = axistags.size(); if(axistags)
{
ArrayVector<npy_intp> permute = axistags.permutationToNormalOrder() int ntags = axistags.size();
;
int tstart = (axistags.channelIndex(ntags) < ntags) ArrayVector<npy_intp> permute = axistags.permutationToNormalOrd
? 1 er();
: 0;
int sstart = (channelAxis == first)
? 1
: 0;
int send = (channelAxis == last)
? (int)size()-1
: (int)size();
int size = send - sstart;
for(int k=0; k<size; ++k) int tstart = (axistags.channelIndex(ntags) < ntags)
{ ? 1
axistags.toFrequencyDomain(permute[k+tstart], shape[k+sstart], : 0;
sign); int sstart = (channelAxis == first)
? 1
: 0;
int send = (channelAxis == last)
? (int)size()-1
: (int)size();
int size = send - sstart;
for(int k=0; k<size; ++k)
{
axistags.toFrequencyDomain(permute[k+tstart], shape[k+sstar
t], sign);
}
} }
return *this; return *this;
} }
bool hasChannelAxis() const
{
return channelAxis !=none;
}
TaggedShape & fromFrequencyDomain() TaggedShape & fromFrequencyDomain()
{ {
return toFrequencyDomain(-1); return toFrequencyDomain(-1);
} }
bool compatible(TaggedShape const & other) const bool compatible(TaggedShape const & other) const
{ {
if(channelCount() != other.channelCount()) if(channelCount() != other.channelCount())
return false; return false;
 End of changes. 10 change blocks. 
39 lines changed or deleted 60 lines changed or added


 numpy_array_traits.hxx   numpy_array_traits.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_NUMPY_ARRAY_TRAITS_HXX #ifndef VIGRA_NUMPY_ARRAY_TRAITS_HXX
#define VIGRA_NUMPY_ARRAY_TRAITS_HXX #define VIGRA_NUMPY_ARRAY_TRAITS_HXX
#ifndef NPY_NO_DEPRECATED_API
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "numpy_array_taggedshape.hxx" #include "numpy_array_taggedshape.hxx"
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* Singleband and Multiband */
/* */
/********************************************************/
template <class T>
struct Singleband // the resulting NumpyArray has no explicit channel axis
// (i.e. the number of channels is implicitly one)
{
typedef T value_type;
};
template <class T>
struct Multiband // the last axis is explicitly designated as channel axis
{
typedef T value_type;
};
template<class T>
struct NumericTraits<Singleband<T> >
: public NumericTraits<T>
{};
template<class T>
struct NumericTraits<Multiband<T> >
{
typedef Multiband<T> Type;
/*
typedef int Promote;
typedef unsigned int UnsignedPromote;
typedef double RealPromote;
typedef std::complex<RealPromote> ComplexPromote;
*/
typedef Type ValueType;
typedef typename NumericTraits<T>::isIntegral isIntegral;
typedef VigraFalseType isScalar;
typedef typename NumericTraits<T>::isSigned isSigned;
typedef typename NumericTraits<T>::isSigned isOrdered;
typedef typename NumericTraits<T>::isSigned isComplex;
/*
static signed char zero() { return 0; }
static signed char one() { return 1; }
static signed char nonZero() { return 1; }
static signed char min() { return SCHAR_MIN; }
static signed char max() { return SCHAR_MAX; }
#ifdef NO_INLINE_STATIC_CONST_DEFINITION
enum { minConst = SCHAR_MIN, maxConst = SCHAR_MIN };
#else
static const signed char minConst = SCHAR_MIN;
static const signed char maxConst = SCHAR_MIN;
#endif
static Promote toPromote(signed char v) { return v; }
static RealPromote toRealPromote(signed char v) { return v; }
static signed char fromPromote(Promote v) {
return ((v < SCHAR_MIN) ? SCHAR_MIN : (v > SCHAR_MAX) ? SCHAR_MAX :
v);
}
static signed char fromRealPromote(RealPromote v) {
return ((v < 0.0)
? ((v < (RealPromote)SCHAR_MIN)
? SCHAR_MIN
: static_cast<signed char>(v - 0.5))
: (v > (RealPromote)SCHAR_MAX)
? SCHAR_MAX
: static_cast<signed char>(v + 0.5));
}
*/
};
/********************************************************/
/* */
/* NumpyArrayValuetypeTraits */ /* NumpyArrayValuetypeTraits */
/* */ /* */
/********************************************************/ /********************************************************/
template<class ValueType> template<class ValueType>
struct ERROR_NumpyArrayValuetypeTraits_not_specialized_for_ { }; struct ERROR_NumpyArrayValuetypeTraits_not_specialized_for_ { };
template<class ValueType> template<class ValueType>
struct NumpyArrayValuetypeTraits struct NumpyArrayValuetypeTraits
{ {
skipping to change at line 161 skipping to change at line 92
template<class ValueType> template<class ValueType>
ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> NumpyArrayV aluetypeTraits<ValueType>::typeCode; ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> NumpyArrayV aluetypeTraits<ValueType>::typeCode;
#define VIGRA_NUMPY_VALUETYPE_TRAITS(type, typeID, numpyTypeName, impexType Name) \ #define VIGRA_NUMPY_VALUETYPE_TRAITS(type, typeID, numpyTypeName, impexType Name) \
template <> \ template <> \
struct NumpyArrayValuetypeTraits<type > \ struct NumpyArrayValuetypeTraits<type > \
{ \ { \
static bool isValuetypeCompatible(PyArrayObject const * obj) /* obj mus t not be NULL */ \ static bool isValuetypeCompatible(PyArrayObject const * obj) /* obj mus t not be NULL */ \
{ \ { \
return PyArray_EquivTypenums(typeID, PyArray_DESCR((PyObject *)obj) return PyArray_EquivTypenums(typeID, PyArray_DESCR((PyArrayObject *
->type_num) && \ )obj)->type_num) && \
PyArray_ITEMSIZE((PyObject *)obj) == sizeof(type); \ PyArray_ITEMSIZE((PyArrayObject *)obj) == sizeof(type); \
} \ } \
\ \
static NPY_TYPES const typeCode = typeID; \ static NPY_TYPES const typeCode = typeID; \
\ \
static std::string typeName() \ static std::string typeName() \
{ \ { \
return #numpyTypeName; \ return #numpyTypeName; \
} \ } \
\ \
static std::string typeNameImpex() \ static std::string typeNameImpex() \
skipping to change at line 262 skipping to change at line 193
return obj && PyArray_Check(obj); return obj && PyArray_Check(obj);
} }
static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not be NULL */ static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not be NULL */
{ {
return ValuetypeTraits::isValuetypeCompatible(obj); return ValuetypeTraits::isValuetypeCompatible(obj);
} }
static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */
{ {
PyObject * obj = (PyObject *)array; int ndim = PyArray_NDIM(array);
int ndim = PyArray_NDIM(obj);
return ndim == N; return ndim == N;
} }
// The '*Compatible' functions are called whenever a NumpyArray is to b e constructed // The '*Compatible' functions are called whenever a NumpyArray is to b e constructed
// from a Python numpy.ndarray to check whether types and memory layout are // from a Python numpy.ndarray to check whether types and memory layout are
// compatible. During overload resolution, boost::python iterates throu gh the list // compatible. During overload resolution, boost::python iterates throu gh the list
// of overloads and invokes the first function where all arguments pass this check. // of overloads and invokes the first function where all arguments pass this check.
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */ static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */
{ {
skipping to change at line 369 skipping to change at line 299
template<unsigned int N, class T> template<unsigned int N, class T>
struct NumpyArrayTraits<N, T, UnstridedArrayTag> struct NumpyArrayTraits<N, T, UnstridedArrayTag>
: public NumpyArrayTraits<N, T, StridedArrayTag> : public NumpyArrayTraits<N, T, StridedArrayTag>
{ {
typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType; typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits; typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */
{ {
PyObject * obj = (PyObject *)array; PyObject * obj = (PyObject *)array;
int ndim = PyArray_NDIM(obj); int ndim = PyArray_NDIM(array);
long channelIndex = pythonGetAttr(obj, "channelIndex", ndim); long channelIndex = pythonGetAttr(obj, "channelIndex", ndim);
long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim); long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim);
npy_intp * strides = PyArray_STRIDES(obj); npy_intp * strides = PyArray_STRIDES(array);
if(channelIndex < ndim) if(channelIndex < ndim)
{ {
// When we have a channel axis, it will become the innermost di mension // When we have a channel axis, it will become the innermost di mension
return (ndim == N && strides[channelIndex] == sizeof(T)); return (ndim == N && strides[channelIndex] == sizeof(T));
} }
else if(majorIndex < ndim) else if(majorIndex < ndim)
{ {
// When we have axistags, but no channel axis, the major spatia l // When we have axistags, but no channel axis, the major spatia l
// axis will be the innermost dimension // axis will be the innermost dimension
skipping to change at line 410 skipping to change at line 340
template<unsigned int N, class T> template<unsigned int N, class T>
struct NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> struct NumpyArrayTraits<N, Singleband<T>, StridedArrayTag>
: public NumpyArrayTraits<N, T, StridedArrayTag> : public NumpyArrayTraits<N, T, StridedArrayTag>
{ {
typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType; typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits; typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */
{ {
PyObject * obj = (PyObject *)array; PyObject * obj = (PyObject *)array;
int ndim = PyArray_NDIM(obj); int ndim = PyArray_NDIM(array);
long channelIndex = pythonGetAttr(obj, "channelIndex", ndim); long channelIndex = pythonGetAttr(obj, "channelIndex", ndim);
// If we have no channel axis (because either we don't have axistag s, // If we have no channel axis (because either we don't have axistag s,
// or the tags do not contain a channel axis), ndim must match. // or the tags do not contain a channel axis), ndim must match.
if(channelIndex == ndim) if(channelIndex == ndim)
return ndim == N; return ndim == N;
// Otherwise, the channel axis must be a singleton axis that we can drop. // Otherwise, the channel axis must be a singleton axis that we can drop.
return ndim == N+1 && PyArray_DIM(obj, channelIndex) == 1; return ndim == N+1 && PyArray_DIM(array, channelIndex) == 1;
} }
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */ static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */
{ {
return isShapeCompatible(obj) && BaseType::isValuetypeCompatible(ob j); return isShapeCompatible(obj) && BaseType::isValuetypeCompatible(ob j);
} }
template <class U> template <class U>
static TaggedShape taggedShape(TinyVector<U, N> const & shape, PyAxisTa gs axistags) static TaggedShape taggedShape(TinyVector<U, N> const & shape, PyAxisTa gs axistags)
{ {
skipping to change at line 505 skipping to change at line 435
struct NumpyArrayTraits<N, Singleband<T>, UnstridedArrayTag> struct NumpyArrayTraits<N, Singleband<T>, UnstridedArrayTag>
: public NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> : public NumpyArrayTraits<N, Singleband<T>, StridedArrayTag>
{ {
typedef NumpyArrayTraits<N, T, UnstridedArrayTag> UnstridedTraits; typedef NumpyArrayTraits<N, T, UnstridedArrayTag> UnstridedTraits;
typedef NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> BaseType; typedef NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits; typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */
{ {
PyObject * obj = (PyObject *)array; PyObject * obj = (PyObject *)array;
int ndim = PyArray_NDIM(obj); int ndim = PyArray_NDIM(array);
long channelIndex = pythonGetAttr(obj, "channelIndex", ndim); long channelIndex = pythonGetAttr(obj, "channelIndex", ndim);
long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim); long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim);
npy_intp * strides = PyArray_STRIDES(obj); npy_intp * strides = PyArray_STRIDES(array);
// If we have no axistags, ndim must match, and axis 0 must be unst rided. // If we have no axistags, ndim must match, and axis 0 must be unst rided.
if(majorIndex == ndim) if(majorIndex == ndim)
return N == ndim && strides[0] == sizeof(T); return N == ndim && strides[0] == sizeof(T);
// If we have axistags, but no channel axis, ndim must match, // If we have axistags, but no channel axis, ndim must match,
// and the major non-channel axis must be unstrided. // and the major non-channel axis must be unstrided.
if(channelIndex == ndim) if(channelIndex == ndim)
return N == ndim && strides[majorIndex] == sizeof(T); return N == ndim && strides[majorIndex] == sizeof(T);
// Otherwise, the channel axis must be a singleton axis that we can drop, // Otherwise, the channel axis must be a singleton axis that we can drop,
// and the major non-channel axis must be unstrided. // and the major non-channel axis must be unstrided.
return ndim == N+1 && PyArray_DIM(obj, channelIndex) == 1 && return ndim == N+1 && PyArray_DIM(array, channelIndex) == 1 &&
strides[majorIndex] == sizeof(T); strides[majorIndex] == sizeof(T);
} }
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */ static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */
{ {
return isShapeCompatible(obj) && BaseType::isValuetypeCompatible(ob j); return isShapeCompatible(obj) && BaseType::isValuetypeCompatible(ob j);
} }
}; };
/********************************************************/ /********************************************************/
skipping to change at line 543 skipping to change at line 473
template<unsigned int N, class T> template<unsigned int N, class T>
struct NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> struct NumpyArrayTraits<N, Multiband<T>, StridedArrayTag>
: public NumpyArrayTraits<N, T, StridedArrayTag> : public NumpyArrayTraits<N, T, StridedArrayTag>
{ {
typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType; typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits; typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */
{ {
PyObject * obj = (PyObject*)array; PyObject * obj = (PyObject*)array;
int ndim = PyArray_NDIM(obj); int ndim = PyArray_NDIM(array);
long channelIndex = pythonGetAttr(obj, "channelIndex", ndim); long channelIndex = pythonGetAttr(obj, "channelIndex", ndim);
long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim); long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim);
if(channelIndex < ndim) if(channelIndex < ndim)
{ {
// When we have a channel axis, ndim must match. // When we have a channel axis, ndim must match.
return ndim == N; return ndim == N;
} }
else if(majorIndex < ndim) else if(majorIndex < ndim)
{ {
skipping to change at line 678 skipping to change at line 608
template<unsigned int N, class T> template<unsigned int N, class T>
struct NumpyArrayTraits<N, Multiband<T>, UnstridedArrayTag> struct NumpyArrayTraits<N, Multiband<T>, UnstridedArrayTag>
: public NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> : public NumpyArrayTraits<N, Multiband<T>, StridedArrayTag>
{ {
typedef NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> BaseType; typedef NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits; typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */
{ {
PyObject * obj = (PyObject *)array; PyObject * obj = (PyObject *)array;
int ndim = PyArray_NDIM(obj); int ndim = PyArray_NDIM(array);
long channelIndex = pythonGetAttr(obj, "channelIndex", ndim); long channelIndex = pythonGetAttr(obj, "channelIndex", ndim);
long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim); long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim);
npy_intp * strides = PyArray_STRIDES(obj); npy_intp * strides = PyArray_STRIDES(array);
if(channelIndex < ndim) if(channelIndex < ndim)
{ {
// When we have a channel axis, ndim must match, and the major non-channel // When we have a channel axis, ndim must match, and the major non-channel
// axis must be unstrided. // axis must be unstrided.
return ndim == N && strides[majorIndex] == sizeof(T); return ndim == N && strides[majorIndex] == sizeof(T);
} }
else if(majorIndex < ndim) else if(majorIndex < ndim)
{ {
// When we have axistags, but no channel axis, we will add a // When we have axistags, but no channel axis, we will add a
skipping to change at line 734 skipping to change at line 664
static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not be NULL */ static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not be NULL */
{ {
return ValuetypeTraits::isValuetypeCompatible(obj); return ValuetypeTraits::isValuetypeCompatible(obj);
} }
static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* array must not be NULL */
{ {
PyObject * obj = (PyObject *)array; PyObject * obj = (PyObject *)array;
// We need an extra channel axis. // We need an extra channel axis.
if(PyArray_NDIM(obj) != N+1) if(PyArray_NDIM(array) != N+1)
return false; return false;
// When there are no axistags, we assume that the last axis represe nts the channels. // When there are no axistags, we assume that the last axis represe nts the channels.
long channelIndex = pythonGetAttr(obj, "channelIndex", N); long channelIndex = pythonGetAttr(obj, "channelIndex", N);
npy_intp * strides = PyArray_STRIDES(obj); npy_intp * strides = PyArray_STRIDES(array);
return PyArray_DIM(obj, channelIndex) == M && strides[channelIndex] == sizeof(T); return PyArray_DIM(array, channelIndex) == M && strides[channelInde x] == sizeof(T);
} }
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */ static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */
{ {
return isShapeCompatible(obj) && ValuetypeTraits::isValuetypeCompat ible(obj); return isShapeCompatible(obj) && ValuetypeTraits::isValuetypeCompat ible(obj);
} }
template <class U> template <class U>
static TaggedShape taggedShape(TinyVector<U, N> const & shape, PyAxisTa gs axistags) static TaggedShape taggedShape(TinyVector<U, N> const & shape, PyAxisTa gs axistags)
{ {
skipping to change at line 836 skipping to change at line 766
struct NumpyArrayTraits<N, TinyVector<T, M>, UnstridedArrayTag> struct NumpyArrayTraits<N, TinyVector<T, M>, UnstridedArrayTag>
: public NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> : public NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag>
{ {
typedef NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> BaseType ; typedef NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> BaseType ;
typedef typename BaseType::value_type value_type; typedef typename BaseType::value_type value_type;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits; typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */ static bool isShapeCompatible(PyArrayObject * array) /* obj must not be NULL */
{ {
PyObject * obj = (PyObject *)array; PyObject * obj = (PyObject *)array;
int ndim = PyArray_NDIM(obj); int ndim = PyArray_NDIM(array);
// We need an extra channel axis. // We need an extra channel axis.
if(ndim != N+1) if(ndim != N+1)
return false; return false;
long channelIndex = pythonGetAttr(obj, "channelIndex", ndim); long channelIndex = pythonGetAttr(obj, "channelIndex", ndim);
long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim); long majorIndex = pythonGetAttr(obj, "innerNonchannelIndex", ndim);
npy_intp * strides = PyArray_STRIDES(obj); npy_intp * strides = PyArray_STRIDES(array);
if(majorIndex < ndim) if(majorIndex < ndim)
{ {
// We have axistags, but no channel axis => cannot be a TinyVec tor image // We have axistags, but no channel axis => cannot be a TinyVec tor image
if(channelIndex == ndim) if(channelIndex == ndim)
return false; return false;
// We have an explicit channel axis => shapes and strides must match // We have an explicit channel axis => shapes and strides must match
return PyArray_DIM(obj, channelIndex) == M && return PyArray_DIM(array, channelIndex) == M &&
strides[channelIndex] == sizeof(T) && strides[channelIndex] == sizeof(T) &&
strides[majorIndex] == sizeof(TinyVector<T, M>); strides[majorIndex] == sizeof(TinyVector<T, M>);
} }
else else
{ {
// we have no axistags => we assume that the channel axis is la st // we have no axistags => we assume that the channel axis is la st
return PyArray_DIM(obj, N) == M && return PyArray_DIM(array, N) == M &&
strides[N] == sizeof(T) && strides[N] == sizeof(T) &&
strides[0] == sizeof(TinyVector<T, M>); strides[0] == sizeof(TinyVector<T, M>);
} }
} }
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */ static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b e NULL */
{ {
return isShapeCompatible(obj) && BaseType::isValuetypeCompatible(ob j); return isShapeCompatible(obj) && BaseType::isValuetypeCompatible(ob j);
} }
}; };
 End of changes. 22 change blocks. 
96 lines changed or deleted 25 lines changed or added


 orientedtensorfilters.hxx   orientedtensorfilters.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_ORIENTEDTENSORFILTERS_HXX #ifndef VIGRA_ORIENTEDTENSORFILTERS_HXX
#define VIGRA_ORIENTEDTENSORFILTERS_HXX #define VIGRA_ORIENTEDTENSORFILTERS_HXX
#include <cmath> #include <cmath>
#include "utilities.hxx" #include "utilities.hxx"
#include "initimage.hxx" #include "initimage.hxx"
#include "stdconvolution.hxx" #include "stdconvolution.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup TensorImaging Tensor Image Processing /** \addtogroup TensorImaging Tensor Image Processing
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* hourGlassFilter */ /* hourGlassFilter */
skipping to change at line 86 skipping to change at line 87
continuations of a local edge element. The parameter <tt>sigma</tt> det ermines continuations of a local edge element. The parameter <tt>sigma</tt> det ermines
the radius of the hourglass (i.e. how far the influence of the edge ele ment the radius of the hourglass (i.e. how far the influence of the edge ele ment
reaches), and <tt>rho</tt> controls its opening angle (i.e. how narrow the reaches), and <tt>rho</tt> controls its opening angle (i.e. how narrow the
edge orientation os followed). Recommended values are <tt>sigma = 1.4</ tt> edge orientation os followed). Recommended values are <tt>sigma = 1.4</ tt>
(or, more generally, two to three times the scale of the gradient opera tor (or, more generally, two to three times the scale of the gradient opera tor
used in the first step), and <tt>rho = 0.4</tt> which corresponds to an used in the first step), and <tt>rho = 0.4</tt> which corresponds to an
opening angle of 22.5 degrees to either side of the edge. opening angle of 22.5 degrees to either side of the edge.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
hourGlassFilter(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigma, double rho);
}
\endcode
\deprecatedAPI{hourGlassFilter}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src, void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
double sigma, double rho); double sigma, double rho);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void hourGlassFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s, void hourGlassFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
pair<DestIterator, DestAccessor> d, pair<DestIterator, DestAccessor> d,
double sigma, double rho); double sigma, double rho);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/orientedtensorfilters.hxx\> <b>\#include</b> \<vigra/orientedtensorfilters.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> img(w,h);
MultiArray<2, TinyVector<float, 2> > gradient(w,h);
MultiArray<2, TinyVector<float, 3> > tensor(w,h), smoothedTensor(w,h);
gaussianGradient(img, gradient, 1.0);
vectorToTensor(gradient, tensor);
hourGlassFilter(tensor, smoothedTensor, 2.0, 0.4);
\endcode
\deprecatedUsage{hourGlassFilter}
\code \code
FImage img(w,h); FImage img(w,h);
FVector2Image gradient(w,h); FVector2Image gradient(w,h);
FVector3Image tensor(w,h), smoothedTensor(w,h); FVector3Image tensor(w,h), smoothedTensor(w,h);
gaussianGradient(srcImageRange(img), destImage(gradient), 1.0); gaussianGradient(srcImageRange(img), destImage(gradient), 1.0);
vectorToTensor(srcImageRange(gradient), destImage(tensor)); vectorToTensor(srcImageRange(gradient), destImage(tensor));
hourGlassFilter(srcImageRange(tensor), destImage(smoothedTensor), 2.0, 0.4); hourGlassFilter(srcImageRange(tensor), destImage(smoothedTensor), 2.0, 0.4);
\endcode \endcode
\deprecatedEnd
\see vectorToTensor() \see vectorToTensor()
*/ */
doxygen_overloaded_function(template <...> void hourGlassFilter) doxygen_overloaded_function(template <...> void hourGlassFilter)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src, void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
double sigma, double rho) double sigma, double rho)
skipping to change at line 193 skipping to change at line 220
norm * VIGRA_CSTD::exp(sigma2*r2 + r ho2*q*q/p/p); norm * VIGRA_CSTD::exp(sigma2*r2 + r ho2*q*q/p/p);
dest.set(dest(dw) + kernel*src(s), dw); dest.set(dest(dw) + kernel*src(s), dw);
} }
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void hourGlassFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s, hourGlassFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
pair<DestIterator, DestAccessor> d, pair<DestIterator, DestAccessor> d,
double sigma, double rho) double sigma, double rho)
{ {
hourGlassFilter(s.first, s.second, s.third, d.first, d.second, sigma, r ho); hourGlassFilter(s.first, s.second, s.third, d.first, d.second, sigma, r ho);
} }
template <class T1, class S1,
class T2, class S2>
inline void
hourGlassFilter(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigma, double rho)
{
vigra_precondition(src.shape() == dest.shape(),
"hourGlassFilter(): shape mismatch between input and output.");
hourGlassFilter(srcImageRange(src), destImage(dest), sigma, rho);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* ellipticGaussian */ /* ellipticGaussian */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void ellipticGaussian(SrcIterator sul, SrcIterator slr, SrcAccessor src, void ellipticGaussian(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
skipping to change at line 269 skipping to change at line 308
double kernel = norm * VIGRA_CSTD::exp(sigmax2*p*p + si gmin2*q*q); double kernel = norm * VIGRA_CSTD::exp(sigmax2*p*p + si gmin2*q*q);
dest.set(dest(dw) + kernel*src(s), dw); dest.set(dest(dw) + kernel*src(s), dw);
} }
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void ellipticGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> s, ellipticGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> d, pair<DestIterator, DestAccessor> dest,
double sigmax, double sigmin) double sigmax, double sigmin)
{ {
ellipticGaussian(s.first, s.second, s.third, d.first, d.second, sigmax, ellipticGaussian(src.first, src.second, src.third, dest.first, dest.sec
sigmin); ond, sigmax, sigmin);
}
template <class T1, class S1,
class T2, class S2>
inline void
ellipticGaussian(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigmax, double sigmin)
{
vigra_precondition(src.shape() == dest.shape(),
"ellipticGaussian(): shape mismatch between input and output.");
ellipticGaussian(srcImageRange(src), destImage(dest), sigmax, sigmin);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* kernels for orientedTrigonometricFilter */ /* kernels for orientedTrigonometricFilter */
/* */ /* */
/********************************************************/ /********************************************************/
class FoerstnerKernelBase class FoerstnerKernelBase
{ {
skipping to change at line 564 skipping to change at line 615
dest.set(dest(d, dd) + kernel(dd.x, dd.y, v) * t, d, dd ); dest.set(dest(d, dd) + kernel(dd.x, dd.y, v) * t, d, dd );
} }
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Kernel> class Kernel>
inline inline void
void orientedTrigonometricFilter(triple<SrcIterator, SrcIterator, SrcAccess orientedTrigonometricFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s
or> s, rc,
pair<DestIterator, DestAccessor> d, pair<DestIterator, DestAccessor> dest,
Kernel const & kernel) Kernel const & kernel)
{ {
orientedTrigonometricFilter(s.first, s.second, s.third, d.first, d.seco orientedTrigonometricFilter(src.first, src.second, src.third, dest.firs
nd, kernel); t, dest.second, kernel);
}
template <class T1, class S1,
class T2, class S2,
class Kernel>
inline void
orientedTrigonometricFilter(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel const & kernel)
{
vigra_precondition(src.shape() == dest.shape(),
"orientedTrigonometricFilter(): shape mismatch between input and ou
tput.");
orientedTrigonometricFilter(srcImageRange(src), destImage(dest), kernel
);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_ORIENTEDTENSORFILTERS_HXX */ #endif /* VIGRA_ORIENTEDTENSORFILTERS_HXX */
 End of changes. 13 change blocks. 
20 lines changed or deleted 86 lines changed or added


 pixelneighborhood.hxx   pixelneighborhood.hxx 
skipping to change at line 193 skipping to change at line 193
South, ///< &nbsp; South, ///< &nbsp;
DirectionCount, ///< &nbsp; DirectionCount, ///< &nbsp;
CausalFirst = North, ///< &nbsp; CausalFirst = North, ///< &nbsp;
CausalLast = West, ///< &nbsp; CausalLast = West, ///< &nbsp;
AntiCausalFirst = South, ///< &nbsp; AntiCausalFirst = South, ///< &nbsp;
AntiCausalLast = East, ///< &nbsp; AntiCausalLast = East, ///< &nbsp;
InitialDirection = East, InitialDirection = East,
OppositeDirPrefix = 1, OppositeDirPrefix = 1,
OppositeOffset = West OppositeOffset = West
}; };
template <int DUMMY>
struct StaticData
{
static unsigned int b[];
static unsigned int c[];
static Direction bd[11][4];
static Diff2D d[];
static Diff2D rd[][4];
};
static unsigned int directionBit(Direction d) static unsigned int directionBit(Direction d)
{ {
static unsigned int b[] = {1 << East, return StaticData<0>::b[d];
1 << North,
1 << West,
1 << South };
return b[d];
}; };
/** The number of valid neighbors if the current center is at the i mage border. /** The number of valid neighbors if the current center is at the i mage border.
*/ */
static unsigned int nearBorderDirectionCount(AtImageBorder b) static unsigned int nearBorderDirectionCount(AtImageBorder b)
{ {
static unsigned int c[] = { 4, 3, 3, 0, 3, 2, 2, 0, 3, 2, 2}; return StaticData<0>::c[b];
return c[b];
} }
/** The valid direction codes when the center is at the image borde r. /** The valid direction codes when the center is at the image borde r.
\a index must be in the range <tt>0...nearBorderDirectionCount( b)-1</tt>. \a index must be in the range <tt>0...nearBorderDirectionCount( b)-1</tt>.
*/ */
static Direction nearBorderDirections(AtImageBorder b, int index) static Direction nearBorderDirections(AtImageBorder b, int index)
{ {
static Direction c[11][4] = { return StaticData<0>::bd[b][index];
{ East, North, West, South},
{ North, West, South, Error},
{ East, North, South, Error},
{ Error, Error, Error, Error},
{ East, West, South, Error},
{ West, South, Error, Error},
{ East, South, Error, Error},
{ Error, Error, Error, Error},
{ East, North, West, Error},
{ North, West, Error, Error},
{ East, North, Error, Error}
};
return c[b][index];
} }
/** Transform direction code into corresponding Diff2D offset. /** Transform direction code into corresponding Diff2D offset.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & diff(Direction code) static Diff2D const & diff(Direction code)
{ {
static Diff2D d[] = { return StaticData<0>::d[code];
Diff2D(1, 0), Diff2D(0, -1), Diff2D(-1, 0), Diff2D(0, 1)
};
return d[code];
} }
/** Equivalent to <tt>diff(static_cast<Direction>(code))</tt>. /** Equivalent to <tt>diff(static_cast<Direction>(code))</tt>.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & diff(int code) { return diff(static_cast<Directio n>(code)); } static Diff2D const & diff(int code) { return diff(static_cast<Directio n>(code)); }
/** Get the relative offset from one neighbor to the other. /** Get the relative offset from one neighbor to the other.
For example, <tt>relativeDiff(East, West) == Diff2D(-2,0)</tt>. For example, <tt>relativeDiff(East, West) == Diff2D(-2,0)</tt>.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & relativeDiff(Direction fromCode, Direction toCode ) static Diff2D const & relativeDiff(Direction fromCode, Direction toCode )
{ {
static Diff2D d[][4] = { return StaticData<0>::rd[fromCode][toCode];
{ Diff2D(0, 0), Diff2D(-1, -1), Diff2D(-2, 0), Diff2D(-1, 1) },
{ Diff2D(1, 1), Diff2D(0, 0), Diff2D(-1, 1), Diff2D(0, 2) },
{ Diff2D(2, 0), Diff2D(1, -1), Diff2D(0, 0), Diff2D(1, 1) },
{ Diff2D(1, -1), Diff2D(0, -2), Diff2D(-1, -1), Diff2D(0, 0) }
};
return d[fromCode][toCode];
} }
/** Equivalent to relativeDiff(static_cast<Direction>(fromCode), st atic_cast<Direction>(toCode)). /** Equivalent to relativeDiff(static_cast<Direction>(fromCode), st atic_cast<Direction>(toCode)).
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & relativeDiff(int fromCode, int toCode) static Diff2D const & relativeDiff(int fromCode, int toCode)
{ {
return relativeDiff(static_cast<Direction>(fromCode), static_cast<D irection>(toCode)); return relativeDiff(static_cast<Direction>(fromCode), static_cast<D irection>(toCode));
} }
skipping to change at line 351 skipping to change at line 333
static const Direction North = NeighborCode::North; /**< Export NeighborCode::North to namespace FourNeighborhood */ static const Direction North = NeighborCode::North; /**< Export NeighborCode::North to namespace FourNeighborhood */
static const Direction West = NeighborCode::West; /**< Export NeighborCode::West to namespace FourNeighborhood */ static const Direction West = NeighborCode::West; /**< Export NeighborCode::West to namespace FourNeighborhood */
static const Direction South = NeighborCode::South; /**< Export NeighborCode::South to namespace FourNeighborhood */ static const Direction South = NeighborCode::South; /**< Export NeighborCode::South to namespace FourNeighborhood */
static const Direction DirectionCount = NeighborCode::DirectionCount; /**< Export NeighborCode::DirectionCount to namespace FourNeighborhood */ static const Direction DirectionCount = NeighborCode::DirectionCount; /**< Export NeighborCode::DirectionCount to namespace FourNeighborhood */
inline Diff2D const & east() { return NeighborCode::diff(East); } /**< Offset to the east neighbor */ inline Diff2D const & east() { return NeighborCode::diff(East); } /**< Offset to the east neighbor */
inline Diff2D const & north() { return NeighborCode::diff(North); } /**< Offset to the north neighbor */ inline Diff2D const & north() { return NeighborCode::diff(North); } /**< Offset to the north neighbor */
inline Diff2D const & west() { return NeighborCode::diff(West); } /**< Offset to the west neighbor */ inline Diff2D const & west() { return NeighborCode::diff(West); } /**< Offset to the west neighbor */
inline Diff2D const & south() { return NeighborCode::diff(South); } /**< Offset to the south neighbor */ inline Diff2D const & south() { return NeighborCode::diff(South); } /**< Offset to the south neighbor */
template <int DUMMY>
unsigned int NeighborCode::StaticData<DUMMY>::b[] = {1 << East,
1 << North,
1 << West,
1 << South };
template <int DUMMY>
unsigned int NeighborCode::StaticData<DUMMY>::c[] = { 4, 3, 3, 0, 3, 2, 2,
0, 3, 2, 2};
template <int DUMMY>
Direction NeighborCode::StaticData<DUMMY>::bd[11][4] = {
{ East, North, West, South},
{ North, West, South, Error},
{ East, North, South, Error},
{ Error, Error, Error, Error},
{ East, West, South, Error},
{ West, South, Error, Error},
{ East, South, Error, Error},
{ Error, Error, Error, Error},
{ East, North, West, Error},
{ North, West, Error, Error},
{ East, North, Error, Error}
};
template <int DUMMY>
Diff2D NeighborCode::StaticData<DUMMY>::d[] = {
Diff2D(1, 0), Diff2D(0, -1), Diff2D(-1, 0), Diff2D(0, 1)
};
template <int DUMMY>
Diff2D NeighborCode::StaticData<DUMMY>::rd[][4] = {
{ Diff2D(0, 0), Diff2D(-1, -1), Diff2D(-2, 0), Diff2D(-1, 1) },
{ Diff2D(1, 1), Diff2D(0, 0), Diff2D(-1, 1), Diff2D(0, 2) },
{ Diff2D(2, 0), Diff2D(1, -1), Diff2D(0, 0), Diff2D(1, 1) },
{ Diff2D(1, -1), Diff2D(0, -2), Diff2D(-1, -1), Diff2D(0, 0) }
};
} // namespace FourNeighborhood } // namespace FourNeighborhood
/** Export \ref vigra::FourNeighborhood::NeighborCode into the scope of namespace vigra. /** Export \ref vigra::FourNeighborhood::NeighborCode into the scope of namespace vigra.
*/ */
typedef FourNeighborhood::NeighborCode FourNeighborCode; typedef FourNeighborhood::NeighborCode FourNeighborCode;
/********************************************************/ /********************************************************/
/* */ /* */
/* EightNeighborhood */ /* EightNeighborhood */
/* */ /* */
skipping to change at line 431 skipping to change at line 450
CausalFirst = NorthEast, ///< &nbsp; CausalFirst = NorthEast, ///< &nbsp;
CausalLast = West, ///< &nbsp; CausalLast = West, ///< &nbsp;
AntiCausalFirst = SouthWest, ///< &nbsp; AntiCausalFirst = SouthWest, ///< &nbsp;
AntiCausalLast = East, ///< &nbsp; AntiCausalLast = East, ///< &nbsp;
InitialDirection = East, InitialDirection = East,
OppositeDirPrefix = 1, OppositeDirPrefix = 1,
OppositeOffset = West OppositeOffset = West
}; };
template <int DUMMY>
struct StaticData
{
static unsigned int b[];
static unsigned int c[];
static Direction bd[11][8];
static Diff2D d[];
static Diff2D rd[][8];
};
static unsigned int directionBit(Direction d) static unsigned int directionBit(Direction d)
{ {
static unsigned int b[] = {1 << East, return StaticData<0>::b[d];
1 << NorthEast,
1 << North,
1 << NorthWest,
1 << West,
1 << SouthWest,
1 << South,
1 << SouthEast};
return b[d];
}; };
/** The number of valid neighbors if the current center is at the i mage border. /** The number of valid neighbors if the current center is at the i mage border.
*/ */
static unsigned int nearBorderDirectionCount(AtImageBorder b) static unsigned int nearBorderDirectionCount(AtImageBorder b)
{ {
static unsigned int c[] = { 8, 5, 5, 0, 5, 3, 3, 0, 5, 3, 3}; return StaticData<0>::c[b];
return c[b];
} }
/** The valid direction codes when the center is at the image borde r. /** The valid direction codes when the center is at the image borde r.
\a index must be in the range <tt>0...nearBorderDirectionCount( b)-1</tt>. \a index must be in the range <tt>0...nearBorderDirectionCount( b)-1</tt>.
*/ */
static Direction nearBorderDirections(AtImageBorder b, int index) static Direction nearBorderDirections(AtImageBorder b, int index)
{ {
static Direction c[11][8] = { return StaticData<0>::bd[b][index];
{ East, NorthEast, North, NorthWest, West, SouthWest, South
, SouthEast},
{ North, NorthWest, West, SouthWest, South, Error, Error, E
rror},
{ East, NorthEast, North, South, SouthEast, Error, Error, E
rror},
{ Error, Error, Error, Error, Error, Error, Error, Error},
{ East, West, SouthWest, South, SouthEast, Error, Error, Er
ror},
{ West, SouthWest, South, Error, Error, Error, Error, Error
},
{ East, South, SouthEast, Error, Error, Error, Error, Error
},
{ Error, Error, Error, Error, Error, Error, Error, Error},
{ East, NorthEast, North, NorthWest, West, Error, Error, Er
ror},
{ North, NorthWest, West, Error, Error, Error, Error, Error
},
{ East, NorthEast, North, Error, Error, Error, Error, Error
}
};
return c[b][index];
} }
/** Transform direction code into corresponding Diff2D offset. /** Transform direction code into corresponding Diff2D offset.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & diff(Direction code) static Diff2D const & diff(Direction code)
{ {
static Diff2D d[] = { return StaticData<0>::d[code];
Diff2D(1, 0), Diff2D(1, -1), Diff2D(0, -1), Diff2D(-1, -1),
Diff2D(-1, 0), Diff2D(-1, 1), Diff2D(0, 1), Diff2D(1, 1)
};
return d[code];
} }
/** Equivalent to diff(static_cast<Direction>(code)). /** Equivalent to diff(static_cast<Direction>(code)).
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & diff(int code) { return diff(static_cast<Directio n>(code)); } static Diff2D const & diff(int code) { return diff(static_cast<Directio n>(code)); }
/** Get the relative offset from one neighbor to the other. /** Get the relative offset from one neighbor to the other.
For example, <tt>relativeDiff(East, West) == Diff2D(-2,0)</tt>. For example, <tt>relativeDiff(East, West) == Diff2D(-2,0)</tt>.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & relativeDiff(Direction fromCode, Direction toCode ) static Diff2D const & relativeDiff(Direction fromCode, Direction toCode )
{ {
static Diff2D d[][8] = { return StaticData<0>::rd[fromCode][toCode];
{ Diff2D(0, 0), Diff2D(0, -1), Diff2D(-1, -1), Diff2D(-2, -1),
Diff2D(-2, 0), Diff2D(-2, 1), Diff2D(-1, 1), Diff2D(0, 1) },
{ Diff2D(0, 1), Diff2D(0, 0), Diff2D(-1, 0), Diff2D(-2, 0),
Diff2D(-2, 1), Diff2D(-2, 2), Diff2D(-1, 2), Diff2D(0, 2) },
{ Diff2D(1, 1), Diff2D(1, 0), Diff2D(0, 0), Diff2D(-1, 0),
Diff2D(-1, 1), Diff2D(-1, 2), Diff2D(0, 2), Diff2D(1, 2) },
{ Diff2D(2, 1), Diff2D(2, 0), Diff2D(1, 0), Diff2D(0, 0),
Diff2D(0, 1), Diff2D(0, 2), Diff2D(1, 2), Diff2D(2, 2) },
{ Diff2D(2, 0), Diff2D(2, -1), Diff2D(1, -1), Diff2D(0, -1),
Diff2D(0, 0), Diff2D(0, 1), Diff2D(1, 1), Diff2D(2, 1) },
{ Diff2D(2, -1), Diff2D(2, -2), Diff2D(1, -2), Diff2D(0, -2),
Diff2D(0, -1), Diff2D(0, 0), Diff2D(1, 0), Diff2D(2, 0) },
{ Diff2D(1, -1), Diff2D(1, -2), Diff2D(0, -2), Diff2D(-1, -2),
Diff2D(-1, -1), Diff2D(-1, 0), Diff2D(0, 0), Diff2D(1, 0) },
{ Diff2D(0, -1), Diff2D(0, -2), Diff2D(-1, -2), Diff2D(-2, -2),
Diff2D(-2, -1), Diff2D(-2, 0), Diff2D(-1, 0), Diff2D(0, 0) }
};
return d[fromCode][toCode];
} }
/** Equivalent to relativeDiff(static_cast<Direction>(fromCode), st atic_cast<Direction>(toCode)). /** Equivalent to relativeDiff(static_cast<Direction>(fromCode), st atic_cast<Direction>(toCode)).
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff2D const & relativeDiff(int fromCode, int toCode) static Diff2D const & relativeDiff(int fromCode, int toCode)
{ {
return relativeDiff(static_cast<Direction>(fromCode), static_cast<D irection>(toCode)); return relativeDiff(static_cast<Direction>(fromCode), static_cast<D irection>(toCode));
} }
skipping to change at line 639 skipping to change at line 623
inline Diff2D const & east() { return NeighborCode::diff(East); } /**< Offset to the east neighbor */ inline Diff2D const & east() { return NeighborCode::diff(East); } /**< Offset to the east neighbor */
inline Diff2D const & northEast() { return NeighborCode::diff(NorthEast); } /**< Offset to the northEast neighbor */ inline Diff2D const & northEast() { return NeighborCode::diff(NorthEast); } /**< Offset to the northEast neighbor */
inline Diff2D const & north() { return NeighborCode::diff(North); } /**< Offset to the north neighbor */ inline Diff2D const & north() { return NeighborCode::diff(North); } /**< Offset to the north neighbor */
inline Diff2D const & northWest() { return NeighborCode::diff(NorthWest); } /**< Offset to the northWest neighbor */ inline Diff2D const & northWest() { return NeighborCode::diff(NorthWest); } /**< Offset to the northWest neighbor */
inline Diff2D const & west() { return NeighborCode::diff(West); } /**< Offset to the west neighbor */ inline Diff2D const & west() { return NeighborCode::diff(West); } /**< Offset to the west neighbor */
inline Diff2D const & southWest() { return NeighborCode::diff(SouthWest); } /**< Offset to the southWest neighbor */ inline Diff2D const & southWest() { return NeighborCode::diff(SouthWest); } /**< Offset to the southWest neighbor */
inline Diff2D const & south() { return NeighborCode::diff(South); } /**< Offset to the south neighbor */ inline Diff2D const & south() { return NeighborCode::diff(South); } /**< Offset to the south neighbor */
inline Diff2D const & southEast() { return NeighborCode::diff(SouthEast); } /**< Offset to the southEast neighbor */ inline Diff2D const & southEast() { return NeighborCode::diff(SouthEast); } /**< Offset to the southEast neighbor */
template <int DUMMY>
unsigned int NeighborCode::StaticData<DUMMY>::b[] = {
1 << East,
1 << NorthEast,
1 << North,
1 << NorthWest,
1 << West,
1 << SouthWest,
1 << South,
1 << SouthEast};
template <int DUMMY>
unsigned int NeighborCode::StaticData<DUMMY>::c[] = { 8, 5, 5, 0, 5, 3, 3,
0, 5, 3, 3};
template <int DUMMY>
Direction NeighborCode::StaticData<DUMMY>::bd[11][8] = {
{ East, NorthEast, North, NorthWest, West, SouthWest, South
, SouthEast},
{ North, NorthWest, West, SouthWest, South, Error, Error, E
rror},
{ East, NorthEast, North, South, SouthEast, Error, Error, E
rror},
{ Error, Error, Error, Error, Error, Error, Error, Error},
{ East, West, SouthWest, South, SouthEast, Error, Error, Er
ror},
{ West, SouthWest, South, Error, Error, Error, Error, Error
},
{ East, South, SouthEast, Error, Error, Error, Error, Error
},
{ Error, Error, Error, Error, Error, Error, Error, Error},
{ East, NorthEast, North, NorthWest, West, Error, Error, Er
ror},
{ North, NorthWest, West, Error, Error, Error, Error, Error
},
{ East, NorthEast, North, Error, Error, Error, Error, Error
}
};
template <int DUMMY>
Diff2D NeighborCode::StaticData<DUMMY>::d[] = {
Diff2D(1, 0), Diff2D(1, -1), Diff2D(0, -1), Diff2D(-1, -1),
Diff2D(-1, 0), Diff2D(-1, 1), Diff2D(0, 1), Diff2D(1, 1)
};
template <int DUMMY>
Diff2D NeighborCode::StaticData<DUMMY>::rd[][8] = {
{ Diff2D(0, 0), Diff2D(0, -1), Diff2D(-1, -1), Diff2D(-2, -1),
Diff2D(-2, 0), Diff2D(-2, 1), Diff2D(-1, 1), Diff2D(0, 1) },
{ Diff2D(0, 1), Diff2D(0, 0), Diff2D(-1, 0), Diff2D(-2, 0),
Diff2D(-2, 1), Diff2D(-2, 2), Diff2D(-1, 2), Diff2D(0, 2) },
{ Diff2D(1, 1), Diff2D(1, 0), Diff2D(0, 0), Diff2D(-1, 0),
Diff2D(-1, 1), Diff2D(-1, 2), Diff2D(0, 2), Diff2D(1, 2) },
{ Diff2D(2, 1), Diff2D(2, 0), Diff2D(1, 0), Diff2D(0, 0),
Diff2D(0, 1), Diff2D(0, 2), Diff2D(1, 2), Diff2D(2, 2) },
{ Diff2D(2, 0), Diff2D(2, -1), Diff2D(1, -1), Diff2D(0, -1),
Diff2D(0, 0), Diff2D(0, 1), Diff2D(1, 1), Diff2D(2, 1) },
{ Diff2D(2, -1), Diff2D(2, -2), Diff2D(1, -2), Diff2D(0, -2),
Diff2D(0, -1), Diff2D(0, 0), Diff2D(1, 0), Diff2D(2, 0) },
{ Diff2D(1, -1), Diff2D(1, -2), Diff2D(0, -2), Diff2D(-1, -2),
Diff2D(-1, -1), Diff2D(-1, 0), Diff2D(0, 0), Diff2D(1, 0) },
{ Diff2D(0, -1), Diff2D(0, -2), Diff2D(-1, -2), Diff2D(-2, -2),
Diff2D(-2, -1), Diff2D(-2, 0), Diff2D(-1, 0), Diff2D(0, 0) }
};
} // namespace EightNeighborhood } // namespace EightNeighborhood
/** Export \ref vigra::EightNeighborhood::NeighborCode into the scope o f namespace vigra. /** Export \ref vigra::EightNeighborhood::NeighborCode into the scope o f namespace vigra.
*/ */
typedef EightNeighborhood::NeighborCode EightNeighborCode; typedef EightNeighborhood::NeighborCode EightNeighborCode;
/********************************************************/ /********************************************************/
/* */ /* */
/* NeighborOffsetCirculator */ /* NeighborOffsetCirculator */
/* */ /* */
skipping to change at line 1037 skipping to change at line 1076
*/ */
typedef typename NEIGHBOROFFSETCIRCULATOR::difference_type difference_t ype; typedef typename NEIGHBOROFFSETCIRCULATOR::difference_type difference_t ype;
/** the circulator tag (random_access_circulator_tag) /** the circulator tag (random_access_circulator_tag)
*/ */
typedef typename NEIGHBOROFFSETCIRCULATOR::iterator_category iterator_c ategory; typedef typename NEIGHBOROFFSETCIRCULATOR::iterator_category iterator_c ategory;
/** Construct circulator with given <tt>center</tt> pixel, pointing to the neighbor /** Construct circulator with given <tt>center</tt> pixel, pointing to the neighbor
at the given direction <tt>d</tt>. at the given direction <tt>d</tt>.
*/ */
NeighborhoodCirculator(IMAGEITERATOR const & center = IMAGEITERATOR(), NeighborhoodCirculator(IMAGEITERATOR const & aCenter = IMAGEITERATOR(),
Direction d = NEIGHBOROFFSETCIRCULATOR::InitialD irection) Direction d = NEIGHBOROFFSETCIRCULATOR::InitialD irection)
: IMAGEITERATOR(center), neighborCode_(d) : IMAGEITERATOR(aCenter), neighborCode_(d)
{ {
IMAGEITERATOR::operator+=(neighborCode_.diff()); IMAGEITERATOR::operator+=(neighborCode_.diff());
} }
/** pre-increment */ /** pre-increment */
NeighborhoodCirculator & operator++() NeighborhoodCirculator & operator++()
{ {
return operator+=(1); return operator+=(1);
} }
 End of changes. 16 change blocks. 
95 lines changed or deleted 136 lines changed or added


 polygon.hxx   polygon.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_POLYGON_HXX #ifndef VIGRA_POLYGON_HXX
#define VIGRA_POLYGON_HXX #define VIGRA_POLYGON_HXX
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
#include <iterator> #include <iterator>
#include <algorithm> #include <algorithm>
#include "config.hxx" #include "config.hxx"
#include "error.hxx" #include "error.hxx"
#include "tinyvector.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "gaussians.hxx"
#include "splines.hxx"
#include "linear_solve.hxx"
namespace vigra { namespace vigra {
/** \addtogroup MathFunctions
*/
//@{
namespace detail { namespace detail {
template < class Point > template < class Point >
bool sortPoints(Point const & p1, Point const & p2) bool pointYXOrdering(Point const & p1, Point const & p2)
{ {
return (p1[0]<p2[0]) || (p1[0] == p2[0] && p1[1] < p2[1]); return (p1[1]<p2[1]) || (p1[1] == p2[1] && p1[0] < p2[0]);
} }
template < class Point > template < class Point >
bool orderedClockwise(const Point &O, const Point &A, const Point &B) bool orderedClockwise(const Point &O, const Point &A, const Point &B)
{ {
return (A[0] - O[0]) * (B[1] - O[1]) - (A[1] - O[1]) * (B[0] - O[0]) <= 0; return (A[0] - O[0]) * (B[1] - O[1]) - (A[1] - O[1]) * (B[0] - O[0]) <= 0;
} }
} // namespace detail } // namespace detail
/** \addtogroup Geometry
*/
//@{
/** Polygons in two and higher dimenions.
*/
template<class POINT=TinyVector<double, 2> >
class Polygon
: protected ArrayVector<POINT>
{
public:
typedef ArrayVector<POINT> Base;
typedef POINT Point;
typedef typename Base::value_type value_type;
typedef typename Base::reference reference;
typedef typename Base::const_reference const_reference;
typedef typename Base::pointer pointer;
typedef typename Base::const_pointer const_pointer;
typedef typename Base::iterator iterator;
typedef typename Base::const_iterator const_iterator;
typedef typename Base::reverse_iterator reverse_iterator;
typedef typename Base::const_reverse_iterator const_reverse_iterator;
typedef typename Base::size_type size_type;
typedef typename Base::difference_type difference_type;
typedef typename POINT::value_type coordinate_type;
using Base::size;
using Base::empty;
using Base::begin;
using Base::end;
using Base::cbegin;
using Base::cend;
using Base::rbegin;
using Base::rend;
using Base::crbegin;
using Base::crend;
// use default copy constructor
Polygon()
: length_(0.0),
lengthValid_(false),
partialArea_(0.0),
partialAreaValid_(false)
{}
Polygon(size_type n)
: Base(n, Point()),
lengthValid_(false),
partialAreaValid_(false)
{}
template <class InputIterator>
Polygon(InputIterator b, InputIterator e)
: Base(b, e),
lengthValid_(false),
partialAreaValid_(false)
{}
void clear()
{
invalidateProperties();
Base::clear();
}
void invalidateProperties()
{
lengthValid_ = false;
partialAreaValid_ = false;
}
double length() const
{
if(!lengthValid_)
{
length_ = 0.0;
for(unsigned int i = 1; i < size(); ++i)
length_ += ((*this)[i] - (*this)[i-1]).magnitude();
lengthValid_ = true;
}
return length_;
}
double partialArea() const
{
if(!partialAreaValid_)
{
partialArea_ = 0.0;
for(unsigned int i = 1; i < size(); ++i)
partialArea_ += ((*this)[i][0]*(*this)[i-1][1] -
(*this)[i][1]*(*this)[i-1][0]);
partialArea_ *= 0.5;
partialAreaValid_ = true;
}
return partialArea_;
}
double area() const
{
vigra_precondition(closed(),
"Polygon::area() requires polygon to be closed!"
);
return abs(partialArea());
}
/// Returns true iff the last and first points are equal or the pol
ygon is empty.
bool closed() const
{
return size() <= 1 || back() == front();
}
/** Linearly interpolate at <tt>offset</tt> between knots
<tt>index</tt> and <tt>index+1</tt>.
Preconditions: <tt>0 <= index < size()-1</tt> and <tt>0 <= offs
et <= 1</tt>.
*/
Point interpolate(unsigned int index, double offset) const
{
if(index < size() - 1)
return (1.0 - offset) * (*this)[index] + offset * (*this)[index
+1];
else
return (*this)[index];
}
/**
* Tests whether the given point lies within this polygon.
* Requires that this polygon is closed.
* Points which lie directly on the polylines or coincide with a kn
ot
* are considered inside (this behavior is consistent with fillPoly
gon()).
* Parameter \a tolerance (interpreted as an absolute error bound)
* controls the numerical accuracy of this test.
*/
bool contains(const_reference point, coordinate_type tolerance) const;
bool contains(const_reference point) const
{
return contains(point, 2.0*NumericTraits<coordinate_type>::epsilon(
));
}
void push_back(const_reference v)
{
if(size())
{
if(lengthValid_)
length_ += (v - back()).magnitude();
if(partialAreaValid_)
partialArea_ += 0.5*(v[0]*back()[1] - v[1]*back()[0]);
}
push_back_unsafe(v);
}
void push_back_unsafe(const_reference v)
{
Base::push_back(v);
}
void extend(const Polygon &other)
{
if(!other.size())
return;
const_iterator otherBegin(other.begin());
if(size())
{
if(*otherBegin == Base::back())
{
// don't copy first pixel
++otherBegin;
}
else
{
if(lengthValid_)
length_ += (other.front() - Base::back()).magnitude();
if(partialAreaValid_)
partialArea_ += (other.front()[0]*Base::back()[1] -
other.front()[1]*Base::back()[0]);
}
}
if(lengthValid_)
length_ += other.length();
if(partialAreaValid_)
partialArea_ += other.partialArea();
Base::insert(Base::end(), otherBegin, other.end());
}
void setPoint(unsigned int pos, const_reference x)
{
invalidateProperties();
Base::operator[](pos) = x;
}
// doesn't call invalidateProperties()
void setPointUnsafe(unsigned int pos, const_reference x)
{
Base::operator[](pos) = x;
}
// alternative, but it will also invalidate if the caller only read
s
// reads the return value.
// reference operator[](unsigned int pos)
// {
// invalidateProperties();
// return Base::operator[](pos);
// }
const_reference operator[](unsigned int pos) const
{
return Base::operator[](pos);
}
const_reference front() const
{
return Base::front();
}
const_reference back() const
{
return Base::back();
}
iterator begin()
{
invalidateProperties();
return Base::begin();
}
iterator end()
{
invalidateProperties();
return Base::end();
}
reverse_iterator rbegin()
{
invalidateProperties();
return Base::rbegin();
}
reverse_iterator rend()
{
invalidateProperties();
return Base::rend();
}
void erase(iterator pos)
{
invalidateProperties();
Base::erase(pos);
}
void erase(iterator pos, iterator end)
{
invalidateProperties();
Base::erase(pos, end);
}
iterator insert(iterator pos, const_reference x)
{
invalidateProperties();
return Base::insert(pos, x);
}
template <class InputIterator>
iterator insert(iterator pos, InputIterator i, InputIterator end)
{
invalidateProperties();
return Base::insert(pos, i, end);
}
Polygon split(unsigned int pos)
{
Polygon result;
if(pos == 0)
{
swap(result);
}
else if(pos < size())
{
result.insert(result.begin(), begin() + pos, end());
erase(begin() + pos, end());
}
return result;
}
template <class Sequence>
void arcLengthList(Sequence & arcLengths) const
{
double length = 0.0;
arcLengths.push_back(0.0);
for(unsigned int i = 1; i < size(); ++i)
{
length += ((*this)[i] - (*this)[i-1]).magnitude();
arcLengths.push_back(length);
}
}
/** Find the point on the polygon that corresponds to the given qua
ntile.
\a quantile must be in <tt>[0.0, 1.0]</tt>. The result of this
function
can be used as input to <tt>interpolate()</tt>. For example,
the following code computes the point in the middle of the poly
gon:
\code
double c = poly.arcLengthQuantile(0.5);
Point center = poly.interpolate((int)floor(c), c - floor(c));
\endcode
*/
double arcLengthQuantile(double quantile) const
{
vigra_precondition(this->size() > 0,
"Polygon:.arcLengthQuantile(): polygon is empty.");
if(quantile == 0.0 || this->size() == 1)
return 0.0;
if(quantile == 1.0)
return this->size() - 1.0;
vigra_precondition(0.0 < quantile && quantile < 1.0,
"Polygon:.arcLengthQuantile(): quantile must be between 0 and 1
.");
ArrayVector<double> arcLength;
arcLength.reserve(this->size());
arcLengthList(arcLength);
double length = quantile*arcLength.back();
unsigned int k=0;
for(; k<this->size(); ++k)
if(arcLength[k] >= length)
break;
--k;
return k + (length - arcLength[k]) / (arcLength[k+1] - arcLength[k]
);
}
void swap(Polygon &rhs)
{
Base::swap(rhs);
std::swap(length_, rhs.length_);
std::swap(lengthValid_, rhs.lengthValid_);
std::swap(partialArea_, rhs.partialArea_);
std::swap(partialAreaValid_, rhs.partialAreaValid_);
}
void reverse()
{
std::reverse(Base::begin(), Base::end());
if(partialAreaValid_)
partialArea_ = -partialArea_;
}
POINT nearestPoint(const_reference p) const;
Polygon & operator+=(POINT const & offset)
{
if(!closed())
partialAreaValid_ = false;
for(unsigned int i = 0; i < size(); ++i)
Base::operator[](i) += offset;
return *this;
}
Polygon & operator-=(POINT const & offset)
{
if(!closed())
partialAreaValid_ = false;
for(unsigned int i = 0; i < size(); ++i)
Base::operator[](i) -= offset;
return *this;
}
Polygon & operator*=(double scale)
{
partialArea_ *= sq(scale);
length_ *= scale;
for(unsigned int i = 0; i < size(); ++i)
Base::operator[](i) *= scale;
return *this;
}
Polygon & operator/=(double scale)
{
partialArea_ /= sq(scale);
length_ /= scale;
for(unsigned int i = 0; i < size(); ++i)
Base::operator[](i) /= scale;
return *this;
}
bool operator==(Polygon const & rhs) const
{
if(size() != rhs.size())
return false;
for(size_type k=0; k<size(); ++k)
if((*this)[k] != rhs[k])
return false;
return true;
}
bool operator!=(Polygon const & rhs) const
{
return !((*this) == rhs);
}
protected:
mutable double length_;
mutable bool lengthValid_;
mutable double partialArea_;
mutable bool partialAreaValid_;
};
template <class POINT>
POINT Polygon<POINT>::nearestPoint(const_reference p) const
{
double dist = NumericTraits<double>::max();
POINT r;
for(unsigned int k=1; k<size(); ++k)
{
POINT dp = (*this)[k] - (*this)[k-1];
POINT dc = p - (*this)[k-1];
double t = dot(dp, dc);
if(t != 0.0)
t /= squaredNorm(dp);
if(t > 1.0)
{
double d = norm((*this)[k]-p);
if (d < dist)
{
dist = d;
r = (*this)[k];
}
}
else if(t < 0.0)
{
double d = norm((*this)[k-1]-p);
if (d < dist)
{
dist = d;
r = (*this)[k-1];
}
}
else
{
POINT pp = (*this)[k-1] + t*dp;
double d = norm(pp-p);
if (d < dist)
{
dist = d;
r = pp;
}
}
}
return r;
}
template <class POINT>
bool
Polygon<POINT>::contains(const_reference point,
coordinate_type tolerance) const
{
typedef typename Polygon<POINT>::Base Base;
vigra_precondition(closed(),
"Polygon::contains() requires polygon to be closed!"
);
// NOTE: the following code is very similar to detail::createScanInterv
als()
// to ensure consistent results.
Polygon p = (*this) - point; // shift the polygon so that we only need
to test
// for intersections with scanline 0
int n = p.size();
for(int k=0; k<n; ++k)
if(closeAtTolerance(p[k][1], 0.0, tolerance))
((Base&)p)[k][1] = 0.0;
int result = 0;
bool drop_next_start_point = false;
int first_point_maybe_dropped = -1;
for(int k=0; k<n-1; ++k)
{
Point const & p1 = p[k];
Point const & p2 = p[k+1];
if(p1[1] == p2[1]) // ignore horizontal lines
continue;
double t = (p2[0] - p1[0]) / (p2[1] - p1[1]);
double y, yend, dy;
if(p1[1] < p2[1])
{
y = ceil(p1[1]);
yend = floor(p2[1]);
dy = 1.0;
}
else
{
y = floor(p1[1]);
yend = ceil(p2[1]);
dy = -1.0;
}
if(yend != p2[1])
yend += dy;
if(drop_next_start_point)
{
y += dy;
drop_next_start_point = false;
}
if(first_point_maybe_dropped == -1)
{
if(y == 0.0 && p1[0] - p1[1]*t < 0.0)
first_point_maybe_dropped = 1;
else
first_point_maybe_dropped = 0;
}
if(y*dy <= 0.0 && yend*dy > 0.0) // intersects scanline 0
{
double x = p1[0] - p1[1]*t;
if(closeAtTolerance(x, 0.0, tolerance))
return true;
if(x < 0.0)
++result;
}
else if(p2[1] == 0.0) // degenerate case
{
int j = (k+2)%n;
bool convex = detail::orderedClockwise(p1, p2, p[j]);
if(convex)
{
double x = p2[0] - p2[1]*t;
if(closeAtTolerance(x, 0.0, tolerance))
return true;
if(x < 0.0)
++result;
}
for(; j != k+1; j = (j+1)%n)
{
double bend = dy*(p[j][1] - yend);
if(bend == 0.0)
continue;
// Drop startpoint of next segment when the polygon after a
convex
// degenerate knot eventually crosses the scanline, or when
it
// returns to the original side of the scanline after a con
cave
// degenerate knot.
if((convex && bend > 0.0) || (!convex && bend < 0.0))
drop_next_start_point = true;
break;
}
}
}
if(drop_next_start_point && first_point_maybe_dropped == 1)
--result;
return (result % 2) != 0;
}
template <class POINT>
inline Polygon<POINT> round(Polygon<POINT> const & p)
{
Polygon<POINT> result(p.size());
for(unsigned int i = 0; i < p.size(); ++i)
{
result.setPointUnsafe(i, round(p[i]));
}
return result;
}
template <class POINT>
inline Polygon<TinyVector<std::ptrdiff_t, 2> > roundi(Polygon<POINT> const
& p)
{
Polygon<TinyVector<std::ptrdiff_t, 2> > result(p.size());
for(unsigned int i = 0; i < p.size(); ++i)
{
result.setPointUnsafe(i,roundi(p[i]));
}
return result;
}
template <class POINT>
inline Polygon<POINT>
operator+(Polygon<POINT> const & p, POINT const & offset)
{
return Polygon<POINT>(p) += offset;
}
template <class POINT>
inline Polygon<POINT>
operator+(POINT const & offset, Polygon<POINT> const & p)
{
return Polygon<POINT>(p) += offset;
}
template <class POINT>
inline Polygon<POINT>
operator-(Polygon<POINT> const & p)
{
Polygon<POINT> result(p.size());
for(unsigned int i = 0; i < p.size(); ++i)
result.setPointUnsafe(i, -p[i]);
return result;
}
template <class POINT>
inline Polygon<POINT>
operator-(Polygon<POINT> const & p, POINT const & offset)
{
return Polygon<POINT>(p) -= offset;
}
template <class POINT>
inline Polygon<POINT>
operator*(Polygon<POINT> const & p, double scale)
{
return Polygon<POINT>(p) *= scale;
}
template <class POINT>
inline Polygon<POINT>
operator*(double scale, Polygon<POINT> const & p)
{
return Polygon<POINT>(p) *= scale;
}
template <class POINT>
inline Polygon<POINT>
operator/(Polygon<POINT> const & p, double scale)
{
return Polygon<POINT>(p) /= scale;
}
template <class POINT>
inline Polygon<POINT>
transpose(Polygon<POINT> const & p)
{
Polygon<POINT> result(p.size());
for(unsigned int i = 0; i < p.size(); ++i)
{
result.setPointUnsafe(i, POINT(p[i][1], p[i][0]));
}
return result;
}
template <class POINT>
inline Polygon<POINT>
reverse(Polygon<POINT> const & p)
{
Polygon<POINT> result(p);
result.reverse();
return result;
}
template<class Point>
Point centroid(const Polygon<Point> &polygon)
{
vigra_precondition(polygon.closed(),
"centroid() expects a closed polygon");
double a = 0.0;
TinyVector<double, 2> result;
for(unsigned int i = 1; i < polygon.size(); ++i)
{
double pa = (polygon[i-1][0]*polygon[i][1] -
polygon[i-1][1]*polygon[i][0]);
a += pa;
result += (polygon[i-1] + polygon[i])*pa;
}
return result / (3.0*a);
}
} // namespace vigra
/********************************************************************/
namespace std {
template<class T>
void swap(vigra::Polygon<T> &a, vigra::Polygon<T> &b)
{
a.swap(b);
}
} // namespace std
/********************************************************************/
namespace vigra {
/** \brief Create a polygon from the interpixel contour of a labeled region
.
The point \a anchor_point must be in the region whose contour we want t
o extract,
and must be adjacent to the contour. The algorithm uses the 'left hand
on the wall'
algorithm to trace the connected component whose label equals the label
of the
\a anchor_point. The contour is returned in \a countour_points as a clo
sed polygon
that circles the region counter-clockwise in the image coordinate syste
m (i.e. the
coordinate system where x points to the right and y points downwards).
Since the
resulting polygon represents the interpixel contour, all points will ha
ve one integer
and one half-integer coordinate.
*/
template<class T, class S, class PointArray>
void
extractContour(MultiArrayView<2, T, S> const &label_image,
Shape2 const & anchor_point,
PointArray & contour_points)
{
typedef typename PointArray::value_type Point;
Shape2 step[4] = { Shape2(0, -1), Shape2(1, 0), Shape2(0, 1), Shape2(-1
, 0) };
Point contour_offsets[4] = { Point(-0.5, 0), Point(0, -0.5), Point(0.5,
0), Point(0, 0.5) };
T foreground = label_image[anchor_point];
int direction;
Shape2 position;
// find a position outside the object from which we place the hand
for(direction = 3; direction >= 0; --direction)
{
position = anchor_point + step[(direction + 1) % 4];
if(!label_image.isInside(position) || label_image[position] != fore
ground)
break;
}
vigra_precondition(direction >= 0,
"extractContour(): the anchor point must be at the region border.")
;
int initial_direction = direction;
Shape2 initial_position = position;
// go around the object
do
{
contour_points.push_back(position + contour_offsets[direction]);
Shape2 next_position = position + step[direction];
if(label_image.isInside(next_position) &&
label_image[next_position] == foreground)
{
// we have bumped into a wall => turn right to touch the wall a
gain
direction = (direction + 1) % 4;
}
else
{
position = next_position;
int next_direction = (direction + 3) % 4;
next_position += step[next_direction];
if(!label_image.isInside(next_position) ||
label_image[next_position] != foreground)
{
// we have lost the wall => turn left and move forward to t
ouch the wall again
direction = next_direction;
position = next_position;
}
}
}
while (position != initial_position || direction != initial_direction);
contour_points.push_back(contour_points.front()); // make it a closed p
olygon
}
/** \brief Compute convex hull of a 2D polygon. /** \brief Compute convex hull of a 2D polygon.
The input array \a points contains a (not necessarily ordered) set of 2 D points The input array \a points contains a (not necessarily ordered) set of 2 D points
whose convex hull is to be computed. The array's <tt>value_type</tt> (i .e. the point type) whose convex hull is to be computed. The array's <tt>value_type</tt> (i .e. the point type)
must be compatible with std::vector (in particular, it must support ind exing, must be compatible with std::vector (in particular, it must support ind exing,
copying, and have <tt>size() == 2</tt>). The points of the convex hull will be appended copying, and have <tt>size() == 2</tt>). The points of the convex hull will be appended
to the output array \a convex_hull (which must support <tt>std::back_in serter(convex_hull)</tt>). to the output array \a convex_hull (which must support <tt>std::back_in serter(convex_hull)</tt>).
Since the convex hull is a closed polygon, the first and last point of the output will Since the convex hull is a closed polygon, the first and last point of the output will
be the same (i.e. the first point will simply be inserted at the end ag ain). The points be the same (i.e. the first point will simply be inserted at the end ag ain). The points
of the convex hull will be ordered counter-clockwise, starting with the leftmost point of the convex hull will be ordered counter-clockwise, starting with the leftmost point
skipping to change at line 91 skipping to change at line 845
template<class PointArray1, class PointArray2> template<class PointArray1, class PointArray2>
void convexHull(const PointArray1 &points, PointArray2 & convex_hull) void convexHull(const PointArray1 &points, PointArray2 & convex_hull)
{ {
vigra_precondition(points.size() >= 2, vigra_precondition(points.size() >= 2,
"convexHull(): at least two input points are needed. "); "convexHull(): at least two input points are needed. ");
vigra_precondition(points[0].size() == 2, vigra_precondition(points[0].size() == 2,
"convexHull(): 2-dimensional points required."); "convexHull(): 2-dimensional points required.");
typedef typename PointArray1::value_type Point; typedef typename PointArray1::value_type Point;
ArrayVector<Point> ordered(points.begin(), points.end()); typename PointArray1::const_iterator begin = points.begin();
std::sort(ordered.begin(), ordered.end(), detail::sortPoints<Point>); if(points.front() == points.back()) // closed polygon
++begin; // => remove redundant start point
ArrayVector<Point> ordered(begin, points.end());
std::sort(ordered.begin(), ordered.end(), detail::pointYXOrdering<Point
>);
ArrayVector<Point> H; ArrayVector<Point> H;
int n = points.size(), k=0; int n = ordered.size(), k=0;
// Build lower hull // Build lower hull
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
while (k >= 2 && detail::orderedClockwise(H[k-2], H[k-1], ordered[i ])) while (k >= 2 && detail::orderedClockwise(H[k-2], H[k-1], ordered[i ]))
{ {
H.pop_back(); H.pop_back();
--k; --k;
} }
H.push_back(ordered[i]); H.push_back(ordered[i]);
skipping to change at line 122 skipping to change at line 879
{ {
while (k >= t && detail::orderedClockwise(H[k-2], H[k-1], ordered[i ])) while (k >= t && detail::orderedClockwise(H[k-2], H[k-1], ordered[i ]))
{ {
H.pop_back(); H.pop_back();
--k; --k;
} }
H.push_back(ordered[i]); H.push_back(ordered[i]);
++k; ++k;
} }
std::copy(H.begin(), H.begin()+k, std::back_inserter(convex_hull)); for(int i=k-1; i>=0; --i)
convex_hull.push_back(H[i]);
} }
/********************************************************************/
/* */
/* polygon drawing */
/* */
/********************************************************************/
namespace detail {
/*
* Find and sort all intersection points of the polygon with scanlines.
* Polygons are considered as closed set, i.e. pixels on the polygon
* contour are included. The function handles degenerate cases (i.e.
* knots on scanlines) correctly.
*/
template<class Point, class Array>
void createScanIntervals(Polygon<Point> const &p, Array & result)
{
bool drop_next_start_point = false;
int n = p.size();
for(int k=0; k<n-1; ++k)
{
Point const & p1 = p[k];
Point const & p2 = p[k+1];
if(p1[1] == p2[1]) // ignore horizontal lines
continue;
double t = (p2[0] - p1[0]) / (p2[1] - p1[1]);
double y, yend, dy;
if(p1[1] < p2[1])
{
y = ceil(p1[1]);
yend = floor(p2[1]);
dy = 1.0;
}
else
{
y = floor(p1[1]);
yend = ceil(p2[1]);
dy = -1.0;
}
if(yend != p2[1]) // in general don't include the segment's endpoin
t
yend += dy; // (since it is also the start point of the next
segment)
if(drop_next_start_point) // handle degeneracy from previous iterat
ion
{
y += dy;
drop_next_start_point = false;
}
for(; (y-yend)*dy < 0.0; y += dy) // compute scanline intersection
s
{
double x = p1[0] + (y - p1[1])*t;
result.push_back(Point(x,y));
}
if(yend == p2[1]) // degenerate case: p2 is exactly on a scanline (
yend is integer)
{
int j = (k+2)%n;
bool convex = detail::orderedClockwise(p1, p2, p[j]);
if(convex) // include the segment's endpoint p2 when it is a co
nvex knot
{
result.push_back(p2);
}
for(; j != k+1; j = (j+1)%n)
{
double bend = dy*(p[j][1] - yend);
if(bend == 0.0)
continue;
// Drop startpoint of next segment when the polygon after a
convex
// degenerate knot eventually crosses the scanline, or when
it
// returns to the original side of the scanline after a con
cave
// degenerate knot.
if((convex && bend > 0.0) || (!convex && bend < 0.0))
drop_next_start_point = true;
break;
}
}
}
if(drop_next_start_point)
result.erase(result.begin());
vigra_invariant((result.size() & 1) == 0,
"createScanIntervals(): internal error - should return an even numb
er of points.");
sort(result.begin(), result.end(), pointYXOrdering<Point>);
}
} // namespace detail
template<class Point, class FUNCTOR>
bool
inspectPolygon(Polygon<Point> const &p,
FUNCTOR const & f)
{
vigra_precondition(p.closed(),
"inspectPolygon(): polygon must be closed (i.e. first point == last
point).");
std::vector<Point> scan_intervals;
detail::createScanIntervals(p, scan_intervals);
for(unsigned int k=0; k < scan_intervals.size(); k+=2)
{
Shape2 p((MultiArrayIndex)ceil(scan_intervals[k][0]),
(MultiArrayIndex)scan_intervals[k][1]);
MultiArrayIndex xend = (MultiArrayIndex)floor(scan_intervals[k+1][0
]) + 1;
for(; p[0] < xend; ++p[0])
if(!f(p))
return false;
}
return true;
}
/** \brief Render closed polygon \a p into the image \a output_image.
All pixels on the polygon's contour and in its interior are
set to the given \a value. Parts of the polygon outside the image
region are clipped. The function uses a robust X-intersection array
algorithm that is able to handle all corner cases (concave and
self-intersecting polygons, knots on integer coordinates).
*/
template<class Point, class T, class S, class Value>
void fillPolygon(Polygon<Point> const &p,
MultiArrayView<2, T, S> &output_image,
Value value)
{
vigra_precondition(p.closed(),
"fillPolygon(): polygon must be closed (i.e. first point == last po
int).");
std::vector<Point> scan_intervals;
detail::createScanIntervals(p, scan_intervals);
for(unsigned int k=0; k < scan_intervals.size(); k+=2)
{
MultiArrayIndex x = (MultiArrayIndex)ceil(scan_intervals[k][0]),
y = (MultiArrayIndex)scan_intervals[k][1],
xend = (MultiArrayIndex)floor(scan_intervals[k+1][0
]) + 1;
vigra_invariant(y == scan_intervals[k+1][1],
"fillPolygon(): internal error - scan interval should have same
y value.");
// clipping
if(y < 0)
continue;
if(y >= output_image.shape(1))
break;
if(x < 0)
x = 0;
if(xend > output_image.shape(0))
xend = output_image.shape(0);
// drawing
for(; x < xend; ++x)
output_image(x,y) = value;
}
}
#if 0
// the following sophisticated polygon resampling functions have no tests y
et
/********************************************************************/
template<bool useMaxStep, class PointIterator, class TargetArray>
void simplifyPolygonHelper(
const PointIterator &polyBegin, const PointIterator &polyEnd,
TargetArray &simple, double epsilon,
double maxStep2 = vigra::NumericTraits<double>::max())
{
if(polyEnd - polyBegin <= 2)
return; // no splitpoint necessary / possible
PointIterator splitPos(polyEnd), lastPoint(polyEnd);
--lastPoint;
double maxDist = epsilon;
// calculate normal of straight end point connection
typename TargetArray::value_type
straight(*lastPoint - *polyBegin);
double straightLength2 = straight.squaredMagnitude();
// search splitpoint
if(straightLength2 > 1e-16)
{
typename TargetArray::value_type
normal(straight[1], -straight[0]);
normal /= std::sqrt(straightLength2);
// iterate over points *between* first and last point:
PointIterator it(polyBegin);
for(++it; it != lastPoint; ++it)
{
double dist = fabs(dot(*it - *polyBegin, normal));
if(dist > maxDist)
{
splitPos = it;
maxDist = dist;
}
}
}
else
{
// start- and end-points identical?! -> look for most distant point
PointIterator it(polyBegin);
for(++it; it != lastPoint; ++it)
{
double dist = (*it - *polyBegin).magnitude();
if(dist > maxDist)
{
splitPos = it;
maxDist = dist;
}
}
}
if(useMaxStep && (straightLength2 > maxStep2) && (splitPos == polyEnd))
{
PointIterator it(polyBegin);
++it;
double bestD2D = std::fabs((*it - *polyBegin).squaredMagnitude()
- (*it - *lastPoint).squaredMagnitude())
;
splitPos = it;
for(++it; it != lastPoint; ++it)
{
double dist2Diff = std::fabs((*it - *polyBegin).squaredMagnitud
e()
- (*it - *lastPoint).squaredMagnit
ude());
if(dist2Diff < bestD2D)
{
bestD2D = dist2Diff;
splitPos = it;
}
}
}
if(splitPos != polyEnd)
{
simplifyPolygonHelper<useMaxStep>(
polyBegin, splitPos + 1, simple, epsilon, maxStep2);
simple.push_back(*splitPos);
simplifyPolygonHelper<useMaxStep>(
splitPos, polyEnd, simple, epsilon, maxStep2);
}
}
template<class PointArray>
void simplifyPolygon(
const PointArray &poly, PointArray &simple, double epsilon)
{
simple.push_back(poly[0]);
simplifyPolygonHelper<false>(poly.begin(), poly.end(), simple, epsilon)
;
simple.push_back(poly[poly.size()-1]);
}
template<class PointArray>
void simplifyPolygon(
const PointArray &poly, PointArray &simple, double epsilon, double maxS
tep)
{
simple.push_back(poly[0]);
simplifyPolygonHelper<true>(poly.begin(), poly.end(),
simple, epsilon, maxStep*maxStep);
simple.push_back(poly[poly.size()-1]);
}
/********************************************************************/
namespace detail {
template <class Point>
Point digitalLineIntersection(TinyVector<double, 3> const & l1, TinyVector<
double, 3> const & l2)
{
double d = l1[0]*l2[1] - l1[1]*l2[0];
return Point((l1[1]*l2[2] - l1[2]*l2[1]) / d, (l1[2]*l2[0] - l1[0]*l2[2
]) / d);
}
} // namespace detail
template<class PointArray>
void simplifyPolygonDigitalLine(
const PointArray &poly, PointArray &simple, int connectivity)
{
typedef typename PointArray::value_type Point;
int size = poly.size();
if(size <= 2)
{
simple = poly;
return;
}
vigra_precondition(connectivity == 4 || connectivity == 8,
"simplifyPolygonDigitalLine(): connectivity must be 4 or 8.");
bool isOpenPolygon = poly[size-1] != poly[0];
ArrayVector<TinyVector<double, 3> > lines;
Point l1 = poly[0],
r1 = l1,
l2 = poly[1],
r2 = l2;
double a = l2[1] - l1[1],
b = l1[0] - l2[0],
c = -a*l2[0] - b*l2[1];
for(int k=2; k < size; ++k)
{
double ab = (connectivity == 4)
? std::fabs(a) + std::fabs(b)
: std::max(std::fabs(a), std::fabs(b));
double d = a*poly[k][0] + b*poly[k][1] + c;
if(d < -1.0 || d > ab)
{
// finish current segment
c = (c - a*r2[0] - b*r2[1]) / 2.0;
lines.push_back(TinyVector<double, 3>(a, b, c));
// initialize new segment
l1 = poly[k-1];
r1 = l1;
l2 = poly[k];
r2 = l2;
a = l2[1] - l1[1];
b = l1[0] - l2[0];
c = -a*l2[0] - b*l2[1];
}
else if(d <= 0.0)
{
l2 = poly[k];
if(d < 0.0)
{
r1 = r2;
a = l2[1] - l1[1];
b = l1[0] - l2[0];
c = -a*l2[0] - b*l2[1];
}
}
else if(d >= ab - 1.0)
{
r2 = poly[k];
if(d > ab - 1.0)
{
l1 = l2;
a = r2[1] - r1[1];
b = r1[0] - r2[0];
c = -a*l2[0] - b*l2[1];
}
}
}
c = (c - a*r2[0] - b*r2[1]) / 2.0;
lines.push_back(TinyVector<double, 3>(a, b, c));
int segments = lines.size();
if(isOpenPolygon)
simple.push_back(poly[0]);
else
simple.push_back(detail::digitalLineIntersection<Point>(lines[0], l
ines[segments-1]));
for(int k=1; k<segments; ++k)
simple.push_back(detail::digitalLineIntersection<Point>(lines[k-1],
lines[k]));
if(isOpenPolygon)
simple.push_back(poly[size-1]);
else
simple.push_back(detail::digitalLineIntersection<Point>(lines[0], l
ines[segments-1]));
}
/********************************************************************/
template<class PointArray>
void resamplePolygon(
const PointArray &poly, PointArray &simple, double desiredPointDistance
)
{
typedef typename PointArray::value_type Point;
int size = poly.size();
bool isOpenPolygon = !poly.closed();
ArrayVector<double> arcLength;
poly.arcLengthList(arcLength);
int segmentCount = int(std::ceil(arcLength[size-1] / desiredPointDistan
ce));
if(segmentCount < 2)
{
simple.push_back(poly[0]);
if(!isOpenPolygon)
{
Point p = poly[1];
double dist = (p - poly[0]).magnitude();
for(int k=2; k < size-1; ++k)
{
double d = (poly[k] - poly[0]).magnitude();
if(d > dist)
{
dist = d;
p = poly[k];
}
}
simple.push_back(p);
}
simple.push_back(poly[size-1]);
return;
}
for(int k=0; k<size; ++k)
arcLength[k] *= segmentCount / arcLength[size-1];
ArrayVector<Point> integrals(segmentCount+1, Point(0.0, 0.0));
Point p1 = poly[0];
double t1 = 0.0;
int l = 1;
for(int k=1; k<size; ++k)
{
double d = arcLength[k];
while(d >= l && l <= segmentCount)
{
double t2 = 1.0;
double dt = t2 - t1;
Point p2 = poly.interpolate(k-1, (l - arcLength[k-1]) / (d - ar
cLength[k-1]));
Point sum1 = 0.5 * dt * (p1 + p2);
Point sumt = dt / 6.0 * (p1*(2.0*t1+t2) + p2*(t1+2.0*t2));
integrals[l-1] += sum1 - sumt;
integrals[l] += sumt;
if(isOpenPolygon && l==1)
{
integrals[0] += poly[0] - integrals[1];
}
p1 = p2;
t1 = 0.0;
++l;
if(isOpenPolygon && l==segmentCount)
{
integrals[segmentCount] += integrals[segmentCount-1];
}
}
if(d < l && l <= segmentCount)
{
double t2 = std::fmod(d, 1.0);
double dt = t2 - t1;
Point p2 = poly[k];
Point sum1 = 0.5 * dt * (p1 + p2);
Point sumt = dt / 6.0 * (p1*(2.0*t1+t2) + p2*(t1+2.0*t2));
integrals[l-1] += sum1 - sumt;
integrals[l] += sumt;
p1 = p2;
t1 = t2;
}
}
if(isOpenPolygon)
{
integrals[segmentCount] += poly[size-1] - integrals[segmentCount-1]
;
integrals[1] -= integrals[0] / 6.0;
integrals[segmentCount-1] -= integrals[segmentCount] / 6.0;
ArrayVector<double> g(segmentCount);
double b = 2.0 / 3.0;
simple.push_back(poly[0]);
simple.push_back(integrals[1] / b);
for(int k=2; k<segmentCount; ++k)
{
g[k] = 1.0 / 6.0 / b;
b = 2.0 / 3.0 - g[k] / 6.0;
simple.push_back((integrals[k] - simple[k-1] / 6.0) / b);
}
for(int k = segmentCount-2; k >= 1; --k)
{
simple[k] -= g[k+1] * simple[k+1];
}
simple.push_back(poly[size-1]);
}
else
{
integrals[0] += integrals[segmentCount];
int initializationSteps = std::min(segmentCount, 5);
ArrayVector<Point> p(segmentCount+2*initializationSteps);
double b = 0.6220084679281461,
g = 0.26794919243112275;
p[0] = integrals[0] / b;
for(int k=1; k<segmentCount+2*initializationSteps; ++k)
{
p[k] = (integrals[k % segmentCount] - p[k-1] / 6.0) / b;
}
for(int k = segmentCount+2*initializationSteps-2; k >= initializati
onSteps; --k)
{
p[k] -= g * p[k+1];
}
for(int k=segmentCount; k<segmentCount+initializationSteps; ++k)
simple.push_back(p[k]);
for(int k=initializationSteps; k<=segmentCount; ++k)
simple.push_back(p[k]);
}
}
/********************************************************************/
template<class PointArray>
void resamplePolygonLinearInterpolation(
const PointArray &poly, PointArray &simple, double desiredPointDistance
)
{
int size = poly.size();
if(size <= 2)
{
simple = poly;
return;
}
ArrayVector<double> arcLengths;
poly.arcLengthList(arcLengths);
int steps = int(std::ceil(arcLengths[size-1] / desiredPointDistance));
double newStep = arcLengths[size-1] / steps;
simple.push_back(poly[0]);
int l = 1;
for(int k=1; k<steps; ++k)
{
double currentArcLength = k*newStep;
for(; l < size; ++l)
{
if(arcLengths[l] >= currentArcLength)
break;
}
double o = (arcLengths[l] - currentArcLength) / (arcLengths[l] - ar
cLengths[l-1]);
simple.push_back(o*poly[l-1] + (1.0-o)*poly[l]);
}
simple.push_back(poly[size-1]);
}
/********************************************************************/
template<class PointArray>
void resamplePolygonExponentialFilter(
const PointArray &poly, PointArray &simple, double scale, double desire
dPointDistance)
{
int size = poly.size();
if(size <= 2)
{
simple = poly;
return;
}
bool isOpenPolygon = !poly.closed();
typedef typename PointArray::value_type Point;
ArrayVector<Point> pforward(size), pbackward(size);
ArrayVector<double> wforward(size), wbackward(size), weights(size-1);
for(int k=0; k < size - 1; ++k)
weights[k] = std::exp(-(poly[k] - poly[k+1]).magnitude()/scale);
// init recursion with cyclic boundary conditions
Point p = poly[0];
double w = 1.0;
for(int k=1; k < size; ++k)
{
p = poly[k] + weights[k-1]*p;
w = 1.0 + weights[k-1]*w;
}
pforward[0] = p;
wforward[0] = w;
p = poly[size-1];
w = 1.0;
for(int k=size-2; k>=0; --k)
{
p = poly[k] + weights[k]*p;
w = 1.0 + weights[k]*w;
}
pbackward[size-1] = p;
wbackward[size-1] = w;
if(isOpenPolygon)
{
// change initialization into anti-reflective boundary conditions f
or open polygons
std::swap(wbackward[size-1], wforward[0]);
std::swap(pbackward[size-1], pforward[0]);
pforward[0] = 2.0*wforward[0]*poly[0] - pforward[0];
pbackward[size-1] = 2.0*wbackward[size-1]*poly[size-1] - pbackward[
size-1];
}
// forward and backward pass of the recursive filter
for(int k=1; k < size; ++k)
{
pforward[k] = poly[k] + weights[k-1]*pforward[k-1];
wforward[k] = 1.0 + weights[k-1]*wforward[k-1];
}
for(int k=size-2; k >= 0; --k)
{
pbackward[k] = poly[k] + weights[k]*pbackward[k+1];
wbackward[k] = 1.0 + weights[k]*wbackward[k+1];
}
// measure the arc length of the new polygon (after possible shrinkage)
p = (pforward[0]+weights[0]*pbackward[1]) / (wforward[0] + weights[0]*w
backward[1]);
simple.push_back(p);
Point pend = isOpenPolygon
? (weights[size-2]*pforward[size-2]+pbackward[size-1]) /
(weights[size-2]*wforward[size-2] + wbackward[size-1])
: p;
ArrayVector<double> arcLength;
double length = 0.0;
arcLength.push_back(length);
for(int k=1; k<size-1; ++k)
{
Point pc = (pforward[k]+weights[k]*pbackward[k+1]) / (wforward[k] +
weights[k]*wbackward[k+1]);
length += (pc - p).magnitude();
arcLength.push_back(length);
p = pc;
}
length += (p-pend).magnitude();
arcLength.push_back(length);
// alternative: use the arc lenth of the original polygon
// poly.arcLengthList(arcLength);
int steps = int(std::floor(arcLength[size-1] / desiredPointDistance+0.5
));
double newStep = arcLength[size-1] / steps;
int l = 1;
for(int k=1; k < steps; ++k)
{
double currentArcLength = k*newStep;
for(; l < size; ++l)
{
if(arcLength[l] >= currentArcLength)
break;
}
double w = weights[l-1];
double o = (arcLength[l] - currentArcLength) / (arcLength[l] - arcL
ength[l-1]);
double wl = std::pow(w, 1.0-o);
double wr = std::pow(w, o);
simple.push_back((wl*pforward[l-1]+wr*pbackward[l]) / (wl*wforward[
l-1] + wr*wbackward[l]));
}
simple.push_back(pend);
}
/********************************************************************/
namespace detail {
template<class ArcLengthList, class PointList>
typename PointList::value_type
singleGaussianConvolvePolygonReflective(
const ArcLengthList &arcLengthList,
const PointList &pointList,
int i, double arcLengthPos,
const Gaussian<double> &g)
{
typedef typename PointList::value_type ValueType;
ValueType sum(vigra::NumericTraits<ValueType>::zero());
double norm = 0.0;
int size = arcLengthList.size(),
lastIndex = size - 1;
double reflectLength = 2.0*arcLengthList[lastIndex];
ValueType reflectPoint = 2.0*pointList[lastIndex];
for(int j = i; true; ++j)
{
int k = (j > lastIndex)
? 2*lastIndex - j
: j;
double pos = arcLengthList[k];
ValueType point = pointList[k];
if(j > lastIndex)
{
pos = reflectLength - pos;
point = reflectPoint - point;
}
double diff = pos - arcLengthPos;
if(diff > g.radius())
break;
double w(g(diff));
sum += w*point;
norm += w;
}
reflectPoint = 2.0*pointList[0];
for(int j = i - 1; true; --j)
{
int k = std::abs(j);
double pos = arcLengthList[k];
ValueType point = pointList[k];
if(j < 0)
{
pos = -pos;
point = reflectPoint - point;
}
double diff = pos - arcLengthPos;
if(diff < -g.radius())
break;
double w(g(diff));
sum += w*point;
norm += w;
}
return sum / norm;
}
template<class ArcLengthList, class PointList>
typename PointList::value_type
singleGaussianConvolvePolygonCyclic(
const ArcLengthList &arcLengthList,
const PointList &pointList,
int i, double arcLengthPos,
const Gaussian<double> &g)
{
typedef typename PointList::value_type ValueType;
ValueType sum(vigra::NumericTraits<ValueType>::zero());
double norm = 0.0;
int size = arcLengthList.size() - 1,
lastIndex = size - 1;
double totalLength = arcLengthList[size];
for(int j = i; true; ++j)
{
int k = j % size;
double pos = j > lastIndex
? arcLengthList[k] + totalLength
: arcLengthList[k];
ValueType point = pointList[k];
double diff = pos - arcLengthPos;
if(diff > g.radius())
break;
double w(g(diff));
sum += w*point;
norm += w;
}
for(int j = i - 1; true; --j)
{
int k = (j + size) % size;
double pos = j < 0
? arcLengthList[k] - totalLength
: arcLengthList[k];
ValueType point = pointList[k];
double diff = pos - arcLengthPos;
if(diff < -g.radius())
break;
double w(g(diff));
sum += w*point;
norm += w;
}
return sum / norm;
}
} // namespace detail
template<class PointArray>
void resamplePolygonGaussianFilter(
const PointArray &poly, PointArray &simple, double scale, double desire
dPointDistance)
{
int size = poly.size();
if(size <= 2)
{
simple = poly;
return;
}
ArrayVector<double> arcLengths;
poly.arcLengthList(arcLengths);
Gaussian<double> g(scale);
vigra_precondition(arcLengths[size-1] > g.radius(),
"resamplePolygonGaussianFilter(): Filter longer than polygon.");
bool isOpenPolygon = !poly.closed();
int steps = int(std::ceil(arcLengths[size-1] / desiredPointDistance));
double newStep = arcLengths[size-1] / steps;
int l = 0;
for(int k=0; k<steps; ++k)
{
double currentArcLength = k*newStep;
for(; l < size; ++l)
{
if(arcLengths[l] >= currentArcLength)
break;
}
if(isOpenPolygon)
simple.push_back(detail::singleGaussianConvolvePolygonReflectiv
e(arcLengths, poly, l, currentArcLength, g));
else
simple.push_back(detail::singleGaussianConvolvePolygonCyclic(ar
cLengths, poly, l, currentArcLength, g));
}
if(isOpenPolygon)
simple.push_back(detail::singleGaussianConvolvePolygonReflective(ar
cLengths, poly, size-1, arcLengths[size-1], g));
else
simple.push_back(simple[0]);
}
/********************************************************************/
namespace detail {
template<class Point>
Point spline3Integral(Point const & p1, Point const & p2, double t1, double
t2)
{
StaticPolynomial<5, double> p[2];
p[0][0] = p[1][0] = 0.0;
if(t1 >= 1.0)
{
return (t1 - t2) / 120.0 *
(p1 * (-80.0 + t1*(80.0 + 2.0*t2*(t2 - 10.0) + t1*(3.0*t2 -
30.0 + 4.0*t1)) + t2*(40.0 + t2*(t2 - 10.0))) +
p2 * (-80.0 + t1*(40.0 + t2*(3.0*t2 - 20.0) + t1*(2.0*t2 -
10.0 + t1)) + t2*(80.0 + t2*(4.0*t2 - 30.0))));
}
else
{
return (t2 - t1) / 120.0 *
(p1 * (40.0 + t1*(2.0*t2*(3.0*t2 - 10.0) + t1*(9.0*t2 - 30.0
+ 12.0*t1)) + t2*t2*(3.0*t2 - 10.0)) +
p2 * (40.0 + t1*(t2*(9.0*t2 - 20.0) + t1*(6.0*t2 - 10.0 + 3
.0*t1)) + t2*t2*(12.0*t2 - 30.0)));
}
}
template<class ArcLengthList, class PointList>
typename PointList::value_type
singleSpline3ConvolvePolygon(
const ArcLengthList &arcLengthList,
const PointList &pointList,
int left, int center, int right)
{
typedef typename PointList::value_type ValueType;
ValueType sum(vigra::NumericTraits<ValueType>::zero());
double arcLengthPos = arcLengthList[center];
for(int j = center + 1; j <= right; ++j)
{
double t1 = arcLengthList[j-1] - arcLengthPos,
t2 = arcLengthList[j] - arcLengthPos;
sum += spline3Integral(pointList[j-1], pointList[j], t1, t2);
}
for(int j = center - 1; j >= left; --j)
{
double t1 = arcLengthPos - arcLengthList[j+1],
t2 = arcLengthPos - arcLengthList[j];
sum -= spline3Integral(-pointList[j+1], -pointList[j], t1, t2);
}
return sum;
}
} // namespace detail
template<class PointArray>
void polygonSplineControlPoints(
const PointArray &poly, PointArray &splinePoints, int segmentCount)
{
typedef typename PointArray::value_type Point;
int size = poly.size();
vigra_precondition(size >= 4,
"polygonSplineControlPoints(): Polygon must have at least 4 points.
");
bool isOpenPolygon = !poly.closed();
ArrayVector<double> arcLength;
poly.arcLengthList(arcLength);
double totalLength = segmentCount / arcLength[size-1];
for(int k=0; k<size; ++k)
arcLength[k] *= totalLength;
PointArray augmentedPoly;
augmentedPoly.push_back(poly[0]);
ArrayVector<double> augmentedArcLength;
augmentedArcLength.push_back(0.0);
ArrayVector<int> splineIndices(segmentCount + 1);
splineIndices[0] = 0;
int l = 1;
for(int k=1; k<size-1; ++k)
{
double d = arcLength[k];
while(d > l)
{
augmentedPoly.push_back(poly.interpolate(k-1, (l - arcLength[k-
1]) / (d - arcLength[k-1])));
augmentedArcLength.push_back(l);
splineIndices[l] = augmentedPoly.size()-1;
++l;
}
augmentedPoly.push_back(poly[k]);
augmentedArcLength.push_back(d);
if(d == l)
{
splineIndices[l] = augmentedPoly.size()-1;
++l;
}
}
augmentedPoly.push_back(poly[size-1]);
augmentedArcLength.push_back(segmentCount);
splineIndices[segmentCount] = augmentedPoly.size()-1;
size = augmentedPoly.size();
ArrayVector<Point> integrals(segmentCount+1);
if(isOpenPolygon)
{
integrals[0] = augmentedPoly[0];
PointArray reflectedPoly;
Point reflectPoint = 2.0*poly[0];
ArrayVector<double> reflectedArcLength;
for(int k=-splineIndices[1]; k <= splineIndices[3]; ++k)
{
if(k < 0)
{
reflectedPoly.push_back(reflectPoint - augmentedPoly[-k]);
reflectedArcLength.push_back(-augmentedArcLength[-k]);
}
else
{
reflectedPoly.push_back(augmentedPoly[k]);
reflectedArcLength.push_back(augmentedArcLength[k]);
}
}
integrals[1] = detail::singleSpline3ConvolvePolygon(reflectedArcLen
gth, reflectedPoly,
0, 2*splineIndices[1], splineIndices[1]
+ splineIndices[3]);
reflectPoint = 2.0*augmentedPoly[size-1];
for(int k=size-2; k>=splineIndices[segmentCount-1]; --k)
{
augmentedPoly.push_back(reflectPoint - augmentedPoly[k]);
augmentedArcLength.push_back(2.0*segmentCount - augmentedArcLen
gth[k]);
}
integrals[segmentCount-1] = detail::singleSpline3ConvolvePolygon(au
gmentedArcLength, augmentedPoly,
splineIndices[segmentCount-3], splineIndices[segmentCount-1]
,
2*splineIndices[segmentCount] - splineIndices[segmentCount-1
]);
integrals[segmentCount] = augmentedPoly[size-1];
}
else
{
PointArray wrappedPoly;
ArrayVector<double> wrappedArcLength;
for(int k=splineIndices[segmentCount-1]; k < splineIndices[segmentC
ount]; ++k)
{
wrappedPoly.push_back(augmentedPoly[k]);
wrappedArcLength.push_back(augmentedArcLength[k] - segmentCount
);
}
int indexShift = wrappedPoly.size();
for(int k=0; k <= splineIndices[3]; ++k)
{
wrappedPoly.push_back(augmentedPoly[k]);
wrappedArcLength.push_back(augmentedArcLength[k]);
}
integrals[1] = detail::singleSpline3ConvolvePolygon(wrappedArcLengt
h, wrappedPoly,
0, splineIndices[1] + indexShift, splineIndice
s[3] + indexShift);
for(int k=1; k <= splineIndices[2]; ++k)
{
augmentedPoly.push_back(augmentedPoly[k]);
augmentedArcLength.push_back(segmentCount + augmentedArcLength[
k]);
}
integrals[segmentCount-1] = detail::singleSpline3ConvolvePolygon(au
gmentedArcLength, augmentedPoly,
splineIndices[segmentCount-3], splineIndices[segmentCount-1]
,
splineIndices[segmentCount] + splineIndices[1]);
integrals[0] = detail::singleSpline3ConvolvePolygon(augmentedArcLen
gth, augmentedPoly,
splineIndices[segmentCount-2], splineIndices[segmentCount],
splineIndices[segmentCount] + splineIndices[2]);
}
for(int k=2; k <= segmentCount-2; ++k)
integrals[k] = detail::singleSpline3ConvolvePolygon(augmentedArcLen
gth, augmentedPoly,
splineIndices[k-2], splineIndices[k], s
plineIndices[k+2]);
BSpline<7, double> spline7;
if(isOpenPolygon)
{
int solutionSize = segmentCount + 1;
Matrix<double> m(solutionSize, solutionSize),
rhs(solutionSize, 2),
solution(solutionSize, 2);
for(int k=0; k<solutionSize; ++k)
{
for(int l=-3; l<=3; ++l)
{
if(k + l < 0)
{
m(k, 0) += 2.0*spline7(l);
m(k, abs(k+l)) -= spline7(l);
}
else if(k + l >= solutionSize)
{
m(k, solutionSize - 1) += 2.0*spline7(l);
m(k, 2*solutionSize - k - l - 2) -= spline7(l);
}
else
m(k,k+l) += spline7(l);
}
rhs(k, 0) = integrals[k][0];
rhs(k, 1) = integrals[k][1];
}
linearSolve(m, rhs, solution);
for(int k=0; k<solutionSize; ++k)
{
splinePoints.push_back(Point(solution(k,0), solution(k,1)));
}
splinePoints.push_back(2.0*splinePoints[solutionSize-1] - splinePoi
nts[solutionSize-2]);
splinePoints.insert(splinePoints.begin(), 2.0*splinePoints[0] - spl
inePoints[1]);
}
else
{
int solutionSize = segmentCount;
Matrix<double> m(solutionSize, solutionSize),
rhs(solutionSize, 2),
solution(solutionSize, 2);
for(int k=0; k<solutionSize; ++k)
{
for(int l=-3; l<=3; ++l)
m(k, (k+l+solutionSize) % solutionSize) = spline7(l);
rhs(k, 0) = integrals[k][0];
rhs(k, 1) = integrals[k][1];
}
linearSolve(m, rhs, solution);
for(int k=0; k<solutionSize; ++k)
{
splinePoints.push_back(Point(solution(k,0), solution(k,1)));
}
splinePoints.push_back(splinePoints[0]);
}
}
#endif
//@} //@}
} // namespace vigra } // namespace vigra
namespace std {
template <class T>
ostream & operator<<(ostream & s, vigra::Polygon<T> const & a)
{
for(std::size_t k=0; k<a.size()-1; ++k)
s << a[k] << ", ";
if(a.size())
s << a.back();
return s;
}
} // namespace std
#endif /* VIGRA_POLYGON_HXX */ #endif /* VIGRA_POLYGON_HXX */
 End of changes. 11 change blocks. 
10 lines changed or deleted 1915 lines changed or added


 polynomial.hxx   polynomial.hxx 
skipping to change at line 758 skipping to change at line 758
typename POLYNOMIAL::value_type centroid = -p[p.order()-1] / N / p[p.or der()]; typename POLYNOMIAL::value_type centroid = -p[p.order()-1] / N / p[p.or der()];
double dist = VIGRA_CSTD::pow(std::abs(p(centroid) / p[p.order()]), 1.0 / N); double dist = VIGRA_CSTD::pow(std::abs(p(centroid) / p[p.order()]), 1.0 / N);
return centroid + dist; return centroid + dist;
} }
template <class POLYNOMIAL, class Complex> template <class POLYNOMIAL, class Complex>
int laguerre1Root(POLYNOMIAL const & p, Complex & x, unsigned int multiplic ity) int laguerre1Root(POLYNOMIAL const & p, Complex & x, unsigned int multiplic ity)
{ {
typedef typename NumericTraits<Complex>::ValueType Real; typedef typename NumericTraits<Complex>::ValueType Real;
static double frac[] = {0.0, 0.5, 0.25, 0.75, 0.13, 0.38, 0.62, 0.88, 1 .0}; double frac[] = {0.0, 0.5, 0.25, 0.75, 0.13, 0.38, 0.62, 0.88, 1.0};
int maxiter = 80, int maxiter = 80,
count; count;
double N = p.order(); double N = p.order();
double eps = p.epsilon(), double eps = p.epsilon(),
eps2 = VIGRA_CSTD::sqrt(eps); eps2 = VIGRA_CSTD::sqrt(eps);
if(multiplicity == 0) if(multiplicity == 0)
x = laguerreStartingGuess(p); x = laguerreStartingGuess(p);
bool mayTryDerivative = true; // try derivative for multiple roots bool mayTryDerivative = true; // try derivative for multiple roots
skipping to change at line 919 skipping to change at line 919
\code \code
namespace vigra { namespace vigra {
template <class POLYNOMIAL, class VECTOR> template <class POLYNOMIAL, class VECTOR>
bool bool
polynomialRoots(POLYNOMIAL const & poriginal, VECTOR & roots, bool polishRoots = true); polynomialRoots(POLYNOMIAL const & poriginal, VECTOR & roots, bool polishRoots = true);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/polynomial.hxx\><br> <b>\#include</b> \<vigra/polynomial.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// encode the polynomial x^4 - 1 // encode the polynomial x^4 - 1
Polynomial<double> poly(4); Polynomial<double> poly(4);
poly[0] = -1.0; poly[0] = -1.0;
poly[4] = 1.0; poly[4] = 1.0;
ArrayVector<std::complex<double> > roots; ArrayVector<std::complex<double> > roots;
polynomialRoots(poly, roots); polynomialRoots(poly, roots);
\endcode \endcode
\see polynomialRootsEigenvalueMethod() \see polynomialRootsEigenvalueMethod()
*/ */
template <class POLYNOMIAL, class VECTOR> template <class POLYNOMIAL, class VECTOR>
bool polynomialRoots(POLYNOMIAL const & poriginal, VECTOR & roots, bool pol ishRoots) bool polynomialRoots(POLYNOMIAL const & poriginal, VECTOR & roots, bool pol ishRoots)
{ {
typedef typename POLYNOMIAL::value_type T;
typedef typename POLYNOMIAL::Real Real; typedef typename POLYNOMIAL::Real Real;
typedef typename POLYNOMIAL::Complex Complex; typedef typename POLYNOMIAL::Complex Complex;
typedef typename POLYNOMIAL::ComplexPolynomial WorkPolynomial; typedef typename POLYNOMIAL::ComplexPolynomial WorkPolynomial;
double eps = poriginal.epsilon(); double eps = poriginal.epsilon();
WorkPolynomial p(poriginal.begin(), poriginal.order(), eps); WorkPolynomial p(poriginal.begin(), poriginal.order(), eps);
p.minimizeOrder(); p.minimizeOrder();
if(p.order() == 0) if(p.order() == 0)
return true; return true;
skipping to change at line 1056 skipping to change at line 1055
\code \code
namespace vigra { namespace vigra {
template <class POLYNOMIAL, class VECTOR> template <class POLYNOMIAL, class VECTOR>
bool bool
polynomialRealRoots(POLYNOMIAL const & p, VECTOR & roots, bool poli shRoots = true); polynomialRealRoots(POLYNOMIAL const & p, VECTOR & roots, bool poli shRoots = true);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/polynomial.hxx\><br> <b>\#include</b> \<vigra/polynomial.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// encode the polynomial x^4 - 1 // encode the polynomial x^4 - 1
Polynomial<double> poly(4); Polynomial<double> poly(4);
poly[0] = -1.0; poly[0] = -1.0;
poly[4] = 1.0; poly[4] = 1.0;
ArrayVector<double> roots; ArrayVector<double> roots;
polynomialRealRoots(poly, roots); polynomialRealRoots(poly, roots);
\endcode \endcode
 End of changes. 4 change blocks. 
6 lines changed or deleted 5 lines changed or added


 project2ellipse.hxx   project2ellipse.hxx 
skipping to change at line 48 skipping to change at line 48
#ifndef VIGRA_PROJECT2ELLIPSE_HXX #ifndef VIGRA_PROJECT2ELLIPSE_HXX
#define VIGRA_PROJECT2ELLIPSE_HXX #define VIGRA_PROJECT2ELLIPSE_HXX
#include <iostream> #include <iostream>
namespace vigra{ namespace vigra{
namespace detail{ namespace detail{
//------------------------------------------------------------------------- -- //------------------------------------------------------------------------- --
void projectEllipse2D_FirstQuad (double &vx, double &vy, double a, double b , const double eps, const int iter_max){ inline void projectEllipse2D_FirstQuad (double &vx, double &vy, double a, d ouble b, const double eps, const int iter_max){
double t=0,tmin,tmax,d1,d2,f,x1,y1,l; double t=0,tmin,tmax,d1,d2,f,x1,y1,l;
int i; int i;
tmax=std::max(2*a*vx,2*b*vy); tmax=std::max(2*a*vx,2*b*vy);
tmin=-b*b; tmin=-b*b;
d1=a*vx/(tmax+a*a); d1=a*vx/(tmax+a*a);
d2=b*vy/(tmax+b*b); d2=b*vy/(tmax+b*b);
f=d1*d1+d2*d2-1; f=d1*d1+d2*d2-1;
for (i=0;i<iter_max;i++){ for (i=0;i<iter_max;i++){
skipping to change at line 86 skipping to change at line 86
} }
d1=vx; d1=vx;
d2=vy; d2=vy;
vx=a*a*vx/(t+a*a); vx=a*a*vx/(t+a*a);
vy=b*b*vy/(t+b*b); vy=b*b*vy/(t+b*b);
d1 = vx - d1; d1 = vx - d1;
d2 = vy - d2; d2 = vy - d2;
return; return;
} }
void projectEllipse2D(double &vx, double &vy, const double _a,const double _b,const double eps,const int max_iter){ inline void projectEllipse2D(double &vx, double &vy, const double _a,const double _b,const double eps,const int max_iter){
//double err; //double err;
double a=_a,b=_b; double a=_a,b=_b;
//check if inside ellipse //check if inside ellipse
if (((vx/a)*(vx/a)+(vy/b)*(vy/b))<=1){ if (((vx/a)*(vx/a)+(vy/b)*(vy/b))<=1){
return; return;
} }
// special case of a circle // special case of a circle
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 python_utility.hxx   python_utility.hxx 
skipping to change at line 87 skipping to change at line 87
PyObject * ptr_; PyObject * ptr_;
public: public:
typedef PyObject element_type; typedef PyObject element_type;
typedef PyObject value_type; typedef PyObject value_type;
typedef PyObject * pointer; typedef PyObject * pointer;
typedef PyObject & reference; typedef PyObject & reference;
enum refcount_policy { increment_count, borrowed_reference = increment_ count, enum refcount_policy { increment_count, borrowed_reference = increment_ count,
keep_count, new_reference = keep_count }; keep_count, new_reference = keep_count, new_nonz ero_reference };
explicit python_ptr(pointer p = 0, refcount_policy rp = increment_count ) explicit python_ptr(pointer p = 0, refcount_policy rp = increment_count )
: ptr_( p ) : ptr_( p )
{ {
if(rp == increment_count) if(rp == increment_count)
{ {
Py_XINCREF(ptr_); Py_XINCREF(ptr_);
} }
else if(rp == new_nonzero_reference)
{
pythonToCppException(p);
}
} }
python_ptr(python_ptr const & p) python_ptr(python_ptr const & p)
: ptr_(p.ptr_) : ptr_(p.ptr_)
{ {
Py_XINCREF(ptr_); Py_XINCREF(ptr_);
} }
python_ptr & operator=(pointer p) python_ptr & operator=(pointer p)
{ {
skipping to change at line 129 skipping to change at line 133
} }
void reset(pointer p = 0, refcount_policy rp = increment_count) void reset(pointer p = 0, refcount_policy rp = increment_count)
{ {
if(p == ptr_) if(p == ptr_)
return; return;
if(rp == increment_count) if(rp == increment_count)
{ {
Py_XINCREF(p); Py_XINCREF(p);
} }
else if(rp == new_nonzero_reference)
{
pythonToCppException(p);
}
Py_XDECREF(ptr_); Py_XDECREF(ptr_);
ptr_ = p; ptr_ = p;
} }
pointer release(bool return_borrowed_reference = false) pointer release(bool return_borrowed_reference = false)
{ {
pointer p = ptr_; pointer p = ptr_;
ptr_ = 0; ptr_ = 0;
if(return_borrowed_reference) if(return_borrowed_reference)
{ {
 End of changes. 3 change blocks. 
1 lines changed or deleted 9 lines changed or added


 quadprog.hxx   quadprog.hxx 
skipping to change at line 101 skipping to change at line 101
//@{ //@{
/** Solve Quadratic Programming Problem. /** Solve Quadratic Programming Problem.
The quadraticProgramming() function implements the algorithm described in The quadraticProgramming() function implements the algorithm described in
D. Goldfarb, A. Idnani: <i>"A numerically stable dual method for solvi ng D. Goldfarb, A. Idnani: <i>"A numerically stable dual method for solvi ng
strictly convex quadratic programs"</i>, Mathematical Prog ramming 27:1-33, 1983. strictly convex quadratic programs"</i>, Mathematical Prog ramming 27:1-33, 1983.
for the solution of (convex) quadratic programming problems by means o f a primal-dual method. for the solution of (convex) quadratic programming problems by means o f a primal-dual method.
<b>\#include</b> \<vigra/quadprog.hxx\> <b>\#include</b> \<vigra/quadprog.hxx\> <br/>
Namespaces: vigra Namespaces: vigra
<b>Declaration:</b> <b>Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template <class T, class C1, class C2, class C3, class C4, class C 5, class C6, class C7> template <class T, class C1, class C2, class C3, class C4, class C 5, class C6, class C7>
T T
quadraticProgramming(MultiArrayView<2, T, C1> const & GG, MultiArr ayView<2, T, C2> const & g, quadraticProgramming(MultiArrayView<2, T, C1> const & GG, MultiArr ayView<2, T, C2> const & g,
MultiArrayView<2, T, C3> const & CE, MultiArr ayView<2, T, C4> const & ce, MultiArrayView<2, T, C3> const & CE, MultiArr ayView<2, T, C4> const & ce,
MultiArrayView<2, T, C5> const & CI, MultiArr ayView<2, T, C6> const & ci, MultiArrayView<2, T, C5> const & CI, MultiArr ayView<2, T, C6> const & ci,
skipping to change at line 134 skipping to change at line 134
Matrix <b>G</b> G must be symmetric positive definite, and matrix <b>C </b><sub>E</sub> must have full row rank. Matrix <b>G</b> G must be symmetric positive definite, and matrix <b>C </b><sub>E</sub> must have full row rank.
Matrix and vector dimensions must be as follows: Matrix and vector dimensions must be as follows:
<ul> <ul>
<li> <b>G</b>: [n * n], <b>g</b>: [n * 1] <li> <b>G</b>: [n * n], <b>g</b>: [n * 1]
<li> <b>C</b><sub>E</sub>: [me * n], <b>c</b><sub>e</sub>: [me * 1] <li> <b>C</b><sub>E</sub>: [me * n], <b>c</b><sub>e</sub>: [me * 1]
<li> <b>C</b><sub>I</sub>: [mi * n], <b>c</b><sub>i</sub>: [mi * 1] <li> <b>C</b><sub>I</sub>: [mi * n], <b>c</b><sub>i</sub>: [mi * 1]
<li> <b>x</b>: [n * 1] <li> <b>x</b>: [n * 1]
</ul> </ul>
The function writes the optimal solution into the vector \a x and retu rns the cost of this solution. The function writes the optimal solution into the vector \a x and retu rns the cost of this solution.
If the problem is infeasible, std::numeric_limits::infinity() is retur ned. In this case If the problem is infeasible, <tt>std::numeric_limits::infinity()</tt> is returned. In this case
the value of vector \a x is undefined. the value of vector \a x is undefined.
<b>Usage:</b> <b>Usage:</b>
Minimize <tt> f = 0.5 * x'*G*x + g'*x </tt> subject to <tt> -1 &lt;= x &lt;= 1</tt>. Minimize <tt> f = 0.5 * x'*G*x + g'*x </tt> subject to <tt> -1 &lt;= x &lt;= 1</tt>.
The solution is <tt> x' = [1.0, 0.5, -1.0] </tt> with <tt> f = -22.625 </tt>. The solution is <tt> x' = [1.0, 0.5, -1.0] </tt> with <tt> f = -22.625 </tt>.
\code \code
double Gdata[] = {13.0, 12.0, -2.0, double Gdata[] = {13.0, 12.0, -2.0,
12.0, 17.0, 6.0, 12.0, 17.0, 6.0,
-2.0, 6.0, 12.0}; -2.0, 6.0, 12.0};
skipping to change at line 167 skipping to change at line 167
Matrix<double> G(3,3, Gdata), Matrix<double> G(3,3, Gdata),
g(3,1, gdata), g(3,1, gdata),
CE, // empty since there are no equality c onstraints CE, // empty since there are no equality c onstraints
ce, // likewise ce, // likewise
CI(7,3, CIdata), CI(7,3, CIdata),
ci(7,1, cidata), ci(7,1, cidata),
x(3,1); x(3,1);
double f = quadraticProgramming(G, g, CE, ce, CI, ci, x); double f = quadraticProgramming(G, g, CE, ce, CI, ci, x);
\endcode \endcode
This algorithm can also be used to solve non-negative least squares pr
oblems
(see \ref nonnegativeLeastSquares() for an alternative algorithm). Con
sider the
problem to minimize <tt> f = (A*x - b)' * (A*x - b) </tt> subject to <
tt> x &gt;= 0</tt>.
Expanding the product in the objective gives <tt>f = x'*A'*A*x - 2*b'*
A*x + b'*b</tt>.
This is equivalent to the problem of minimizing <tt>fn = 0.5 * x'*G*x
+ g'*x</tt> with
<tt>G = A'*A</tt> and <tt>g = -A'*b</tt> (the constant term <tt>b'*b</
tt> has no
effect on the optimal solution and can be dropped). The following code
computes the
solution <tt>x' = [18.4493, 0, 4.50725]</tt>:
\code
double A_data[] = {
1, -3, 2,
-3, 10, -5,
2, -5, 6
};
double b_data[] = {
27,
-78,
64
};
Matrix<double> A(3, 3, A_data),
b(3, 1, b_data),
G = transpose(A)*A,
g = -(transpose(A)*b),
CE, // empty since there are no equality constrai
nts
ce, // likewise
CI = identityMatrix<double>(3), // constrain all ele
ments of x
ci(3, 1, 0.0), // ... to be non-neg
ative
x(3, 1);
quadraticProgramming(G, g, CE, ce, CI, ci, x);
\endcode
*/ */
doxygen_overloaded_function(template <...> unsigned int quadraticProgrammin
g)
template <class T, class C1, class C2, class C3, class C4, class C5, class C6, class C7> template <class T, class C1, class C2, class C3, class C4, class C5, class C6, class C7>
T T
quadraticProgramming(MultiArrayView<2, T, C1> const & G, MultiArrayView<2, T, C2> const & g, quadraticProgramming(MultiArrayView<2, T, C1> const & G, MultiArrayView<2, T, C2> const & g,
MultiArrayView<2, T, C3> const & CE, MultiArrayView<2, T, C4 > const & ce, MultiArrayView<2, T, C3> const & CE, MultiArrayView<2, T, C4 > const & ce,
MultiArrayView<2, T, C5> const & CI, MultiArrayView<2, T, C6 > const & ci, MultiArrayView<2, T, C5> const & CI, MultiArrayView<2, T, C6 > const & ci,
MultiArrayView<2, T, C7> & x) MultiArrayView<2, T, C7> & x)
{ {
using namespace linalg; using namespace linalg;
typedef typename MultiArrayShape<2>::type Shape; typedef typename MultiArrayShape<2>::type Shape;
 End of changes. 4 change blocks. 
3 lines changed or deleted 50 lines changed or added


 random.hxx   random.hxx 
skipping to change at line 51 skipping to change at line 51
#include "array_vector.hxx" #include "array_vector.hxx"
#include <ctime> #include <ctime>
// includes to get the current process and thread IDs // includes to get the current process and thread IDs
// to be used for automated seeding // to be used for automated seeding
#ifdef _MSC_VER #ifdef _MSC_VER
#include <vigra/windows.h> // for GetCurrentProcessId() and GetCurrentTh readId() #include <vigra/windows.h> // for GetCurrentProcessId() and GetCurrentTh readId()
#endif #endif
#if __linux__ #ifdef __linux__
#include <unistd.h> // for getpid() #include <unistd.h> // for getpid()
#include <sys/syscall.h> // for SYS_gettid #include <sys/syscall.h> // for SYS_gettid
#endif #endif
#if __APPLE__ #ifdef __APPLE__
#include <unistd.h> // for getpid() #include <unistd.h> // for getpid()
#include <sys/syscall.h> // SYS_thread_selfid #include <sys/syscall.h> // SYS_thread_selfid
#include <AvailabilityMacros.h> // to check if we are on MacOS 10.6 or later #include <AvailabilityMacros.h> // to check if we are on MacOS 10.6 or later
#endif #endif
namespace vigra { namespace vigra {
enum RandomSeedTag { RandomSeed }; enum RandomSeedTag { RandomSeed };
namespace detail { namespace detail {
skipping to change at line 87 skipping to change at line 87
for(UInt32 i=1; i<RandomState<EngineTag>::N; ++i) for(UInt32 i=1; i<RandomState<EngineTag>::N; ++i)
{ {
engine.state_[i] = 1812433253U * (engine.state_[i-1] ^ (engine.stat e_[i-1] >> 30)) + i; engine.state_[i] = 1812433253U * (engine.state_[i-1] ^ (engine.stat e_[i-1] >> 30)) + i;
} }
} }
template <class Iterator, RandomEngineTag EngineTag> template <class Iterator, RandomEngineTag EngineTag>
void seed(Iterator init, UInt32 key_length, RandomState<EngineTag> & engine ) void seed(Iterator init, UInt32 key_length, RandomState<EngineTag> & engine )
{ {
const UInt32 N = RandomState<EngineTag>::N; const UInt32 N = RandomState<EngineTag>::N;
int k = (int)std::max(N, key_length); int k = static_cast<int>(std::max(N, key_length));
UInt32 i = 1, j = 0; UInt32 i = 1, j = 0;
Iterator data = init; Iterator data = init;
for (; k; --k) for (; k; --k)
{ {
engine.state_[i] = (engine.state_[i] ^ ((engine.state_[i-1] ^ (engi ne.state_[i-1] >> 30)) * 1664525U)) engine.state_[i] = (engine.state_[i] ^ ((engine.state_[i-1] ^ (engi ne.state_[i-1] >> 30)) * 1664525U))
+ *data + j; /* non linear */ + *data + j; /* non linear */
++i; ++j; ++data; ++i; ++j; ++data;
if (i >= N) if (i >= N)
{ {
skipping to change at line 129 skipping to change at line 129
engine.state_[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */ engine.state_[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */
} }
template <RandomEngineTag EngineTag> template <RandomEngineTag EngineTag>
void seed(RandomSeedTag, RandomState<EngineTag> & engine) void seed(RandomSeedTag, RandomState<EngineTag> & engine)
{ {
static UInt32 globalCount = 0; static UInt32 globalCount = 0;
ArrayVector<UInt32> seedData; ArrayVector<UInt32> seedData;
seedData.push_back((UInt32)time(0)); seedData.push_back(static_cast<UInt32>(time(0)));
seedData.push_back((UInt32)clock()); seedData.push_back(static_cast<UInt32>(clock()));
seedData.push_back(++globalCount); seedData.push_back(++globalCount);
std::size_t ptr((char*)&engine - (char*)0); std::size_t ptr((char*)&engine - (char*)0);
seedData.push_back((UInt32)(ptr & 0xffffffff)); seedData.push_back(static_cast<UInt32>((ptr & 0xffffffff)));
seedData.push_back((UInt32)(ptr >> 32)); static const UInt32 shift = sizeof(ptr) > 4 ? 32 : 16;
seedData.push_back(static_cast<UInt32>((ptr >> shift)));
#ifdef _MSC_VER #ifdef _MSC_VER
seedData.push_back((UInt32)GetCurrentProcessId()); seedData.push_back(static_cast<UInt32>(GetCurrentProcessId()));
seedData.push_back((UInt32)GetCurrentThreadId()); seedData.push_back(static_cast<UInt32>(GetCurrentThreadId()));
#endif #endif
#ifdef __linux__ #ifdef __linux__
seedData.push_back((UInt32)getpid()); seedData.push_back(static_cast<UInt32>(getpid()));
# ifdef SYS_gettid # ifdef SYS_gettid
seedData.push_back((UInt32)syscall(SYS_gettid)); seedData.push_back(static_cast<UInt32>(syscall(SYS_gettid)));
# endif # endif
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
seedData.push_back((UInt32)getpid()); seedData.push_back(static_cast<UInt32>(getpid()));
#if defined(SYS_thread_selfid) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_O S_X_VERSION_10_6) #if defined(SYS_thread_selfid) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_O S_X_VERSION_10_6)
// SYS_thread_selfid was introduced in MacOS 10.6 // SYS_thread_selfid was introduced in MacOS 10.6
seedData.push_back((UInt32)syscall(SYS_thread_selfid)); seedData.push_back(static_cast<UInt32>(syscall(SYS_thread_selfid)));
#endif #endif
#endif #endif
seed(seedData.begin(), seedData.size(), engine); seed(seedData.begin(), seedData.size(), engine);
} }
/* Tempered twister TT800 by M. Matsumoto */ /* Tempered twister TT800 by M. Matsumoto */
template<> template<>
struct RandomState<TT800> struct RandomState<TT800>
{ {
skipping to change at line 331 skipping to change at line 332
<li> <tt>RandomTT800</tt>: (default) The Tempered Twister, a simpler pr edecessor of the Mersenne Twister with period length 2<sup>800</sup>. <li> <tt>RandomTT800</tt>: (default) The Tempered Twister, a simpler pr edecessor of the Mersenne Twister with period length 2<sup>800</sup>.
</ul> </ul>
Both generators have been designed by <a href="http://www.math.sci.hiro shima-u.ac.jp/~m-mat/eindex.html">Makoto Matsumoto</a>. Both generators have been designed by <a href="http://www.math.sci.hiro shima-u.ac.jp/~m-mat/eindex.html">Makoto Matsumoto</a>.
<b>Traits defined:</b> <b>Traits defined:</b>
\verbatim FunctorTraits<RandomNumberGenerator<Engine> >::isInitializer \endverbatim \verbatim FunctorTraits<RandomNumberGenerator<Engine> >::isInitializer \endverbatim
is true (<tt>VigraTrueType</tt>). is true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = detail::RandomState<detail::TT800> > template <class Engine = detail::RandomState<detail::MT19937> >
class RandomNumberGenerator class RandomNumberGenerator
: public Engine : public Engine
{ {
mutable double normalCached_; mutable double normalCached_;
mutable bool normalCachedValid_; mutable bool normalCachedValid_;
public: public:
/** Create a new random generator object with standard seed. /** Create a new random generator object with standard seed.
skipping to change at line 370 skipping to change at line 371
RandomNumberGenerator(RandomSeedTag) RandomNumberGenerator(RandomSeedTag)
: normalCached_(0.0), : normalCached_(0.0),
normalCachedValid_(false) normalCachedValid_(false)
{ {
this->seedImpl(RandomSeed); this->seedImpl(RandomSeed);
} }
/** Create a new random generator object from the given seed. /** Create a new random generator object from the given seed.
The same seed will always produce identical random sequences. The same seed will always produce identical random sequences.
If \a ignoreSeed is <tt>true</tt>, the given seed is ignored,
and the generator is seeded randomly (as if it was constructed
with <tt>RandomNumberGenerator<>(RandomSeed)</tt>). This allows
you to switch between random and deterministic seeding at
run-time.
*/ */
RandomNumberGenerator(UInt32 theSeed) RandomNumberGenerator(UInt32 theSeed, bool ignoreSeed=false)
: normalCached_(0.0), : normalCached_(0.0),
normalCachedValid_(false) normalCachedValid_(false)
{ {
this->seedImpl(theSeed); if(ignoreSeed)
this->seedImpl(RandomSeed);
else
this->seedImpl(theSeed);
} }
/** Create a new random generator object from the given seed sequen ce. /** Create a new random generator object from the given seed sequen ce.
Longer seed sequences lead to better initialization in the sens e that the generator's Longer seed sequences lead to better initialization in the sens e that the generator's
state space is covered much better than is possible with 32-bit seeds alone. state space is covered much better than is possible with 32-bit seeds alone.
*/ */
template<class Iterator> template<class Iterator>
RandomNumberGenerator(Iterator init, UInt32 length) RandomNumberGenerator(Iterator init, UInt32 length)
: normalCached_(0.0), : normalCached_(0.0),
skipping to change at line 412 skipping to change at line 421
*/ */
void seed(RandomSeedTag) void seed(RandomSeedTag)
{ {
this->seedImpl(RandomSeed); this->seedImpl(RandomSeed);
normalCachedValid_ = false; normalCachedValid_ = false;
} }
/** Re-initialize the random generator object from the given seed. /** Re-initialize the random generator object from the given seed.
The same seed will always produce identical random sequences. The same seed will always produce identical random sequences.
If \a ignoreSeed is <tt>true</tt>, the given seed is ignored,
and the generator is seeded randomly (as if <tt>seed(RandomSeed
)</tt>
was called). This allows you to switch between random and deter
ministic
seeding at run-time.
*/ */
void seed(UInt32 theSeed) void seed(UInt32 theSeed, bool ignoreSeed=false)
{ {
this->seedImpl(theSeed); if(ignoreSeed)
this->seedImpl(RandomSeed);
else
this->seedImpl(theSeed);
normalCachedValid_ = false; normalCachedValid_ = false;
} }
/** Re-initialize the random generator object from the given seed s equence. /** Re-initialize the random generator object from the given seed s equence.
Longer seed sequences lead to better initialization in the sens e that the generator's Longer seed sequences lead to better initialization in the sens e that the generator's
state space is covered much better than is possible with 32-bit seeds alone. state space is covered much better than is possible with 32-bit seeds alone.
*/ */
template<class Iterator> template<class Iterator>
void seed(Iterator init, UInt32 length) void seed(Iterator init, UInt32 length)
skipping to change at line 507 skipping to change at line 523
return ( (this->get() >> 5) * 67108864.0 + (this->get() >> 6)) * (1 .0/9007199254740992.0); return ( (this->get() >> 5) * 67108864.0 + (this->get() >> 6)) * (1 .0/9007199254740992.0);
} }
/** Return a uniformly distributed double-precision random number i n [0.0, 1.0]. /** Return a uniformly distributed double-precision random number i n [0.0, 1.0].
That is, 0.0 &lt;= i &lt;= 1.0. This number is computed by <tt> uniformInt()</tt> / (2<sup>32</sup> - 1), That is, 0.0 &lt;= i &lt;= 1.0. This number is computed by <tt> uniformInt()</tt> / (2<sup>32</sup> - 1),
so it has effectively only 32 random bits. so it has effectively only 32 random bits.
*/ */
double uniform() const double uniform() const
{ {
return (double)this->get() / 4294967295.0; return static_cast<double>(this->get()) / 4294967295.0;
} }
/** Return a uniformly distributed double-precision random number i n [lower, upper]. /** Return a uniformly distributed double-precision random number i n [lower, upper].
That is, <tt>lower</tt> &lt;= i &lt;= <tt>upper</tt>. This numb er is computed That is, <tt>lower</tt> &lt;= i &lt;= <tt>upper</tt>. This numb er is computed
from <tt>uniform()</tt>, so it has effectively only 32 random b its. from <tt>uniform()</tt>, so it has effectively only 32 random b its.
*/ */
double uniform(double lower, double upper) const double uniform(double lower, double upper) const
{ {
vigra_precondition(lower < upper, vigra_precondition(lower < upper,
skipping to change at line 547 skipping to change at line 563
return normal()*stddev + mean; return normal()*stddev + mean;
} }
/** Access the global (program-wide) instance of the present random number generator. /** Access the global (program-wide) instance of the present random number generator.
Normally, you will create a local generator by one of the const ructor calls. But sometimes Normally, you will create a local generator by one of the const ructor calls. But sometimes
it is useful to have all program parts access the same generato r. it is useful to have all program parts access the same generato r.
*/ */
static RandomNumberGenerator & global() static RandomNumberGenerator & global()
{ {
static RandomNumberGenerator generator; return global_;
return generator;
} }
static UInt32 factorForUniformInt(UInt32 range) static UInt32 factorForUniformInt(UInt32 range)
{ {
return (range > 2147483648U || range == 0) return (range > 2147483648U || range == 0)
? 1 ? 1
: 2*(2147483648U / ceilPower2(range)); : 2*(2147483648U / ceilPower2(range));
} }
static RandomNumberGenerator global_;
}; };
template <class Engine> template <class Engine>
RandomNumberGenerator<Engine> RandomNumberGenerator<Engine>::global_(Random
Seed);
template <class Engine>
double RandomNumberGenerator<Engine>::normal() const double RandomNumberGenerator<Engine>::normal() const
{ {
if(normalCachedValid_) if(normalCachedValid_)
{ {
normalCachedValid_ = false; normalCachedValid_ = false;
return normalCached_; return normalCached_;
} }
else else
{ {
double x1, x2, w; double x1, x2, w;
skipping to change at line 589 skipping to change at line 609
normalCached_ = x2 * w; normalCached_ = x2 * w;
normalCachedValid_ = true; normalCachedValid_ = true;
return x1 * w; return x1 * w;
} }
} }
/** Shorthand for the TT800 random number generator class. /** Shorthand for the TT800 random number generator class.
*/ */
typedef RandomNumberGenerator<> RandomTT800; typedef RandomNumberGenerator<detail::RandomState<detail::TT800> > RandomT T800;
/** Shorthand for the TT800 random number generator class (same as Rand omTT800). /** Shorthand for the TT800 random number generator class (same as Rand omTT800).
*/ */
typedef RandomNumberGenerator<> TemperedTwister; typedef RandomNumberGenerator<detail::RandomState<detail::TT800> > Tempere dTwister;
/** Shorthand for the MT19937 random number generator class. /** Shorthand for the MT19937 random number generator class.
*/ */
typedef RandomNumberGenerator<detail::RandomState<detail::MT19937> > Random MT19937; typedef RandomNumberGenerator<detail::RandomState<detail::MT19937> > Random MT19937;
/** Shorthand for the MT19937 random number generator class (same as Ra ndomMT19937). /** Shorthand for the MT19937 random number generator class (same as Ra ndomMT19937).
*/ */
typedef RandomNumberGenerator<detail::RandomState<detail::MT19937> > Mersen neTwister; typedef RandomNumberGenerator<detail::RandomState<detail::MT19937> > Mersen neTwister;
/** Access the global (program-wide) instance of the TT800 random numbe r generator. /** Access the global (program-wide) instance of the TT800 random numbe r generator.
skipping to change at line 641 skipping to change at line 661
<tt>Engine</tt> (usually <tt>RandomTT800</tt> or <tt>RandomMT19937</tt> ) <tt>Engine</tt> (usually <tt>RandomTT800</tt> or <tt>RandomMT19937</tt> )
in an STL-compatible interface. in an STL-compatible interface.
<b>Traits defined:</b> <b>Traits defined:</b>
\verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize r \endverbatim \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize r \endverbatim
and and
\verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isUnaryFunct or \endverbatim \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isUnaryFunct or \endverbatim
are true (<tt>VigraTrueType</tt>). are true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = RandomTT800> template <class Engine = MersenneTwister>
class UniformIntRandomFunctor class UniformIntRandomFunctor
{ {
UInt32 lower_, difference_, factor_; UInt32 lower_, difference_, factor_;
Engine const & generator_; Engine const & generator_;
bool useLowBits_; bool useLowBits_;
public: public:
typedef UInt32 argument_type; ///< STL required functor argument type typedef UInt32 argument_type; ///< STL required functor argument type
typedef UInt32 result_type; ///< STL required functor result type typedef UInt32 result_type; ///< STL required functor result type
skipping to change at line 748 skipping to change at line 768
This functor encapsulates the function <tt>uniform()</tt> of the given random number This functor encapsulates the function <tt>uniform()</tt> of the given random number
<tt>Engine</tt> (usually <tt>RandomTT800</tt> or <tt>RandomMT19937</tt> ) <tt>Engine</tt> (usually <tt>RandomTT800</tt> or <tt>RandomMT19937</tt> )
in an STL-compatible interface. in an STL-compatible interface.
<b>Traits defined:</b> <b>Traits defined:</b>
\verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize r \endverbatim \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize r \endverbatim
is true (<tt>VigraTrueType</tt>). is true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = RandomTT800> template <class Engine = MersenneTwister>
class UniformRandomFunctor class UniformRandomFunctor
{ {
double offset_, scale_; double offset_, scale_;
Engine const & generator_; Engine const & generator_;
public: public:
typedef double result_type; ///< STL required functor result type typedef double result_type; ///< STL required functor result type
/** Create functor for uniform random double-precision numbers in t he range [0.0, 1.0] /** Create functor for uniform random double-precision numbers in t he range [0.0, 1.0]
skipping to change at line 820 skipping to change at line 840
This functor encapsulates the function <tt>normal()</tt> of the given r andom number This functor encapsulates the function <tt>normal()</tt> of the given r andom number
<tt>Engine</tt> (usually <tt>RandomTT800</tt> or <tt>RandomMT19937</tt> ) <tt>Engine</tt> (usually <tt>RandomTT800</tt> or <tt>RandomMT19937</tt> )
in an STL-compatible interface. in an STL-compatible interface.
<b>Traits defined:</b> <b>Traits defined:</b>
\verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize r \endverbatim \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize r \endverbatim
is true (<tt>VigraTrueType</tt>). is true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = RandomTT800> template <class Engine = MersenneTwister>
class NormalRandomFunctor class NormalRandomFunctor
{ {
double mean_, stddev_; double mean_, stddev_;
Engine const & generator_; Engine const & generator_;
public: public:
typedef double result_type; ///< STL required functor result type typedef double result_type; ///< STL required functor result type
/** Create functor for standard normal random numbers /** Create functor for standard normal random numbers
 End of changes. 26 change blocks. 
26 lines changed or deleted 49 lines changed or added


 random_forest.hxx   random_forest.hxx 
skipping to change at line 90 skipping to change at line 90
{ {
SamplerOptions return_opt; SamplerOptions return_opt;
return_opt.withReplacement(RF_opt.sample_with_replacement_); return_opt.withReplacement(RF_opt.sample_with_replacement_);
return_opt.stratified(RF_opt.stratification_method_ == RF_EQUAL); return_opt.stratified(RF_opt.stratification_method_ == RF_EQUAL);
return return_opt; return return_opt;
} }
}//namespace detail }//namespace detail
/** Random Forest class /** Random Forest class
* *
* \tparam <PrprocessorTag = ClassificationTag> Class used to preprocess * \tparam <LabelType = double> Type used for predicted labels.
* \tparam <PreprocessorTag = ClassificationTag> Class used to preprocess
* the input while learning and predicting. Currently Available: * the input while learning and predicting. Currently Available:
* ClassificationTag and RegressionTag. It is recommended to use * ClassificationTag and RegressionTag. It is recommended to use
* Splitfunctor::Preprocessor_t while using custom splitfunctors * Splitfunctor::Preprocessor_t while using custom splitfunctors
* as they may need the data to be in a different format. * as they may need the data to be in a different format.
* \sa Preprocessor * \sa Preprocessor
* *
* simple usage for classification (regression is not yet supported): * Simple usage for classification (regression is not yet supported):
* look at RandomForest::learn() as well as RandomForestOptions() for addi tional * look at RandomForest::learn() as well as RandomForestOptions() for addi tional
* options. * options.
* *
* \code * \code
* using namespace vigra; * using namespace vigra;
* using namespace rf; * using namespace rf;
* typedef xxx feature_t; \\ replace xxx with whichever type * typedef xxx feature_t; \\ replace xxx with whichever type
* typedef yyy label_t; \\ likewise * typedef yyy label_t; \\ likewise
* *
* // allocate the training data * // allocate the training data
* MultiArrayView<2, feature_t> f = get_training_features(); * MultiArrayView<2, feature_t> f = get_training_features();
* MultiArrayView<2, label_t> l = get_training_labels(); * MultiArrayView<2, label_t> l = get_training_labels();
* *
* RandomForest<> rf; * RandomForest<label_t> rf;
* *
* // construct visitor to calculate out-of-bag error * // construct visitor to calculate out-of-bag error
* visitors::OOB_Error oob_v; * visitors::OOB_Error oob_v;
* *
* // perform training * // perform training
* rf.learn(f, l, visitors::create_visitor(oob_v)); * rf.learn(f, l, visitors::create_visitor(oob_v));
* *
* std::cout << "the out-of-bag error is: " << oob_v.oob_breiman << "\n"; * std::cout << "the out-of-bag error is: " << oob_v.oob_breiman << "\n";
* *
* // get features for new data to be used for prediction * // get features for new data to be used for prediction
* MultiArrayView<2, feature_t> pf = get_features(); * MultiArrayView<2, feature_t> pf = get_features();
* *
* // allocate space for the response (pf.shape(0) is the number of sample s) * // allocate space for the response (pf.shape(0) is the number of sample s)
* MultiArrayView<2, label_t> prediction(pf.shape(0), 1); * MultiArrayView<2, label_t> prediction(pf.shape(0), 1);
* MultiArrayView<2, double> prob(pf.shape(0), rf.class_count()); * MultiArrayView<2, double> prob(pf.shape(0), rf.class_count());
* *
* // perform prediction on new data * // perform prediction on new data
* rf.predict_labels(pf, prediction); * rf.predictLabels(pf, prediction);
* rf.predict_probabilities(pf, prob); * rf.predictProbabilities(pf, prob);
* *
* \endcode * \endcode
* *
* Additional information such as Variable Importance measures are accesse d * Additional information such as Variable Importance measures are accesse d
* via Visitors defined in rf::visitors. * via Visitors defined in rf::visitors.
* Have a look at rf::split for other splitting methods. * Have a look at rf::split for other splitting methods.
* *
*/ */
template <class LabelType = double , class PreprocessorTag = Classification Tag > template <class LabelType = double , class PreprocessorTag = Classification Tag >
class RandomForest class RandomForest
skipping to change at line 154 skipping to change at line 155
//public typedefs //public typedefs
typedef RandomForestOptions Options_t; typedef RandomForestOptions Options_t;
typedef detail::DecisionTree DecisionTree_t; typedef detail::DecisionTree DecisionTree_t;
typedef ProblemSpec<LabelType> ProblemSpec_t; typedef ProblemSpec<LabelType> ProblemSpec_t;
typedef GiniSplit Default_Split_t; typedef GiniSplit Default_Split_t;
typedef EarlyStoppStd Default_Stop_t; typedef EarlyStoppStd Default_Stop_t;
typedef rf::visitors::StopVisiting Default_Visitor_t; typedef rf::visitors::StopVisiting Default_Visitor_t;
typedef DT_StackEntry<ArrayVectorView<Int32>::iterator> typedef DT_StackEntry<ArrayVectorView<Int32>::iterator>
StackEntry_t; StackEntry_t;
typedef LabelType LabelT; typedef LabelType LabelT;
protected:
/** optimisation for predictLabels
* */
mutable MultiArray<2, double> garbage_prediction_;
public:
//problem independent data. //problem independent data.
Options_t options_; Options_t options_;
//problem dependent data members - is only set if //problem dependent data members - is only set if
//a copy constructor, some sort of import //a copy constructor, some sort of import
//function or the learn function is called //function or the learn function is called
ArrayVector<DecisionTree_t> trees_; ArrayVector<DecisionTree_t> trees_;
ProblemSpec_t ext_param_; ProblemSpec_t ext_param_;
/*mutable ArrayVector<int> tree_indices_;*/ /*mutable ArrayVector<int> tree_indices_;*/
rf::visitors::OnlineLearnVisitor online_visitor_; rf::visitors::OnlineLearnVisitor online_visitor_;
skipping to change at line 288 skipping to change at line 282
"Random forest has been trained! Call reset()" "Random forest has been trained! Call reset()"
"before specifying new extrinsic parameters."); "before specifying new extrinsic parameters.");
} }
/**\brief access random forest options /**\brief access random forest options
* *
* \return random forest options * \return random forest options
*/ */
Options_t & set_options() Options_t & set_options()
{ {
return options; return options_;
} }
/**\brief access const random forest options /**\brief access const random forest options
* *
* \return const Option_t * \return const Option_t
*/ */
Options_t const & options() const Options_t const & options() const
{ {
return options_; return options_;
} }
skipping to change at line 428 skipping to change at line 422
* response. Current split functors assume D to * response. Current split functors assume D to
* be 1 and ignore any additional columns. * be 1 and ignore any additional columns.
* This is not enforced to allow future support * This is not enforced to allow future support
* for uncertain labels, label independent strata etc. * for uncertain labels, label independent strata etc.
* The Preprocessor specified during construction * The Preprocessor specified during construction
* should be able to handle features and labels * should be able to handle features and labels
* features and the labels. * features and the labels.
* see also: SplitFunctor, Preprocessing * see also: SplitFunctor, Preprocessing
* *
* \param visitor visitor which is to be applied after each split, * \param visitor visitor which is to be applied after each split,
* tree and at the end. Use rf_default for using * tree and at the end. Use rf_default() for using
* default value. (No Visitors) * default value. (No Visitors)
* see also: rf::visitors * see also: rf::visitors
* \param split split functor to be used to calculate each split * \param split split functor to be used to calculate each split
* use rf_default() for using default value. (GiniSpli t) * use rf_default() for using default value. (GiniSpli t)
* see also: rf::split * see also: rf::split
* \param stop * \param stop
* predicate to be used to calculate each split * predicate to be used to calculate each split
* use rf_default() for using default value. (EarlySto ppStd) * use rf_default() for using default value. (EarlySto ppStd)
* \param random RandomNumberGenerator to be used. Use * \param random RandomNumberGenerator to be used. Use
* rf_default() to use default value.(RandomMT19337) * rf_default() to use default value.(RandomMT19337)
skipping to change at line 571 skipping to change at line 565
LabelType predictLabel(MultiArrayView<2, U, C> const & features, LabelType predictLabel(MultiArrayView<2, U, C> const & features,
ArrayVectorView<double> prior) const; ArrayVectorView<double> prior) const;
/** \brief predict multiple labels with given features /** \brief predict multiple labels with given features
* *
* \param features: a n by featureCount matrix containing * \param features: a n by featureCount matrix containing
* data point to be predicted (this only works in * data point to be predicted (this only works in
* classification setting) * classification setting)
* \param labels: a n by 1 matrix passed by reference to store * \param labels: a n by 1 matrix passed by reference to store
* output. * output.
*
* If the input contains an NaN value, an precondition exception is thr
own.
*/ */
template <class U, class C1, class T, class C2> template <class U, class C1, class T, class C2>
void predictLabels(MultiArrayView<2, U, C1>const & features, void predictLabels(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & labels) const MultiArrayView<2, T, C2> & labels) const
{ {
vigra_precondition(features.shape(0) == labels.shape(0), vigra_precondition(features.shape(0) == labels.shape(0),
"RandomForest::predictLabels(): Label array has wrong size."); "RandomForest::predictLabels(): Label array has wrong size.");
for(int k=0; k<features.shape(0); ++k) for(int k=0; k<features.shape(0); ++k)
{
vigra_precondition(!detail::contains_nan(rowVector(features, k)
),
"RandomForest::predictLabels(): NaN in feature matrix.");
labels(k,0) = detail::RequiresExplicitCast<T>::cast(predictLabe l(rowVector(features, k), rf_default())); labels(k,0) = detail::RequiresExplicitCast<T>::cast(predictLabe l(rowVector(features, k), rf_default()));
}
}
/** \brief predict multiple labels with given features
*
* \param features: a n by featureCount matrix containing
* data point to be predicted (this only works in
* classification setting)
* \param labels: a n by 1 matrix passed by reference to store
* output.
* \param nanLabel: label to be returned for the row of the input that
* contain an NaN value.
*/
template <class U, class C1, class T, class C2>
void predictLabels(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & labels,
LabelType nanLabel) const
{
vigra_precondition(features.shape(0) == labels.shape(0),
"RandomForest::predictLabels(): Label array has wrong size.");
for(int k=0; k<features.shape(0); ++k)
{
if(detail::contains_nan(rowVector(features, k)))
labels(k,0) = nanLabel;
else
labels(k,0) = detail::RequiresExplicitCast<T>::cast(predict
Label(rowVector(features, k), rf_default()));
}
} }
/** \brief predict multiple labels with given features
*
* \param features: a n by featureCount matrix containing
* data point to be predicted (this only works in
* classification setting)
* \param labels: a n by 1 matrix passed by reference to store
* output.
* \param stop: an early stopping criterion.
*/
template <class U, class C1, class T, class C2, class Stop> template <class U, class C1, class T, class C2, class Stop>
void predictLabels(MultiArrayView<2, U, C1>const & features, void predictLabels(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & labels, MultiArrayView<2, T, C2> & labels,
Stop & stop) const Stop & stop) const
{ {
vigra_precondition(features.shape(0) == labels.shape(0), vigra_precondition(features.shape(0) == labels.shape(0),
"RandomForest::predictLabels(): Label array has wrong size."); "RandomForest::predictLabels(): Label array has wrong size.");
for(int k=0; k<features.shape(0); ++k) for(int k=0; k<features.shape(0); ++k)
labels(k,0) = detail::RequiresExplicitCast<T>::cast(predictLabe l(rowVector(features, k), stop)); labels(k,0) = detail::RequiresExplicitCast<T>::cast(predictLabe l(rowVector(features, k), stop));
} }
/** \brief predict the class probabilities for multiple labels /** \brief predict the class probabilities for multiple labels
* *
* \param features same as above * \param features same as above
* \param prob a n x class_count_ matrix. passed by reference to * \param prob a n x class_count_ matrix. passed by reference to
* save class probabilities * save class probabilities
* \param stop earlystopping criterion * \param stop earlystopping criterion
* \sa EarlyStopping * \sa EarlyStopping
When a row of the feature array contains an NaN, the corresponding
instance
cannot belong to any of the classes. The corresponding row in the p
robability
array will therefore contain all zeros.
*/ */
template <class U, class C1, class T, class C2, class Stop> template <class U, class C1, class T, class C2, class Stop>
void predictProbabilities(MultiArrayView<2, U, C1>const & features, void predictProbabilities(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & prob, MultiArrayView<2, T, C2> & prob,
Stop & stop) const ; Stop & stop) const ;
template <class T1,class T2, class C> template <class T1,class T2, class C>
void predictProbabilities(OnlinePredictionSet<T1> & predictionSet, void predictProbabilities(OnlinePredictionSet<T1> & predictionSet,
MultiArrayView<2, T2, C> & prob); MultiArrayView<2, T2, C> & prob);
/** \brief predict the class probabilities for multiple labels /** \brief predict the class probabilities for multiple labels
skipping to change at line 673 skipping to change at line 712
typename RF_CHOOSER(Split_t)::type split typename RF_CHOOSER(Split_t)::type split
= RF_CHOOSER(Split_t)::choose(split_, default_split); = RF_CHOOSER(Split_t)::choose(split_, default_split);
rf::visitors::StopVisiting stopvisiting; rf::visitors::StopVisiting stopvisiting;
typedef rf::visitors::detail::VisitorNode typedef rf::visitors::detail::VisitorNode
<rf::visitors::OnlineLearnVisitor, <rf::visitors::OnlineLearnVisitor,
typename RF_CHOOSER(Visitor_t)::type> typename RF_CHOOSER(Visitor_t)::type>
IntermedVis; IntermedVis;
IntermedVis IntermedVis
visitor(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, st opvisiting)); visitor(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, st opvisiting));
#undef RF_CHOOSER #undef RF_CHOOSER
vigra_precondition(options_.prepare_online_learning_,"onlineLearn: onli ne learning must be enabled on RandomForest construction");
// Preprocess the data to get something the split functor can work // Preprocess the data to get something the split functor can work
// with. Also fill the ext_param structure by preprocessing // with. Also fill the ext_param structure by preprocessing
// option parameters that could only be completely evaluated // option parameters that could only be completely evaluated
// when the training data is known. // when the training data is known.
ext_param_.class_count_=0; ext_param_.class_count_=0;
Preprocessor_t preprocessor( features, response, Preprocessor_t preprocessor( features, response,
options_, ext_param_); options_, ext_param_);
// Make stl compatible random functor. // Make stl compatible random functor.
skipping to change at line 696 skipping to change at line 736
split.set_external_parameters(ext_param_); split.set_external_parameters(ext_param_);
stop.set_external_parameters(ext_param_); stop.set_external_parameters(ext_param_);
//Create poisson samples //Create poisson samples
PoissonSampler<RandomTT800> poisson_sampler(1.0,vigra::Int32(new_start_ index),vigra::Int32(ext_param().row_count_)); PoissonSampler<RandomTT800> poisson_sampler(1.0,vigra::Int32(new_start_ index),vigra::Int32(ext_param().row_count_));
//TODO: visitors for online learning //TODO: visitors for online learning
//visitor.visit_at_beginning(*this, preprocessor); //visitor.visit_at_beginning(*this, preprocessor);
// THE MAIN EFFING RF LOOP - YEAY DUDE! // THE MAIN EFFING RF LOOP - YEAY DUDE!
for(int ii = 0; ii < (int)trees_.size(); ++ii) for(int ii = 0; ii < static_cast<int>(trees_.size()); ++ii)
{ {
online_visitor_.tree_id=ii; online_visitor_.tree_id=ii;
poisson_sampler.sample(); poisson_sampler.sample();
std::map<int,int> leaf_parents; std::map<int,int> leaf_parents;
leaf_parents.clear(); leaf_parents.clear();
//Get all the leaf nodes for that sample //Get all the leaf nodes for that sample
for(int s=0;s<poisson_sampler.numOfSamples();++s) for(int s=0;s<poisson_sampler.numOfSamples();++s)
{ {
int sample=poisson_sampler[s]; int sample=poisson_sampler[s];
online_visitor_.current_label=preprocessor.response()(sample,0) ; online_visitor_.current_label=preprocessor.response()(sample,0) ;
skipping to change at line 832 skipping to change at line 872
stop.set_external_parameters(ext_param_); stop.set_external_parameters(ext_param_);
/**\todo replace this crappy class out. It uses function pointers. /**\todo replace this crappy class out. It uses function pointers.
* and is making code slower according to me. * and is making code slower according to me.
* Comment from Nathan: This is copied from Rahul, so me=Rahul * Comment from Nathan: This is copied from Rahul, so me=Rahul
*/ */
Sampler<Random_t > sampler(preprocessor.strata().begin(), Sampler<Random_t > sampler(preprocessor.strata().begin(),
preprocessor.strata().end(), preprocessor.strata().end(),
detail::make_sampler_opt(options_) detail::make_sampler_opt(options_)
.sampleSize(ext_param().actual_msam ple_), .sampleSize(ext_param().actual_msam ple_),
random); &random);
//initialize First region/node/stack entry //initialize First region/node/stack entry
sampler sampler
.sample(); .sample();
StackEntry_t StackEntry_t
first_stack_entry( sampler.sampledIndices().begin(), first_stack_entry( sampler.sampledIndices().begin(),
sampler.sampledIndices().end(), sampler.sampledIndices().end(),
ext_param_.class_count_); ext_param_.class_count_);
first_stack_entry first_stack_entry
.set_oob_range( sampler.oobIndices().begin(), .set_oob_range( sampler.oobIndices().begin(),
skipping to change at line 895 skipping to change at line 935
// See rf_preprocessing.hxx for more info on this // See rf_preprocessing.hxx for more info on this
typedef Processor<PreprocessorTag,LabelType, U, C1, U2, C2> Preprocesso r_t; typedef Processor<PreprocessorTag,LabelType, U, C1, U2, C2> Preprocesso r_t;
vigra_precondition(features.shape(0) == response.shape(0), vigra_precondition(features.shape(0) == response.shape(0),
"RandomForest::learn(): shape mismatch between features and respons e."); "RandomForest::learn(): shape mismatch between features and respons e.");
// default values and initialization // default values and initialization
// Value Chooser chooses second argument as value if first argument // Value Chooser chooses second argument as value if first argument
// is of type RF_DEFAULT. (thanks to template magic - don't care about // is of type RF_DEFAULT. (thanks to template magic - don't care about
// it - just smile and wave. // it - just smile and wave).
#define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_> #define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_>
Default_Stop_t default_stop(options_); Default_Stop_t default_stop(options_);
typename RF_CHOOSER(Stop_t)::type stop typename RF_CHOOSER(Stop_t)::type stop
= RF_CHOOSER(Stop_t)::choose(stop_, default_stop); = RF_CHOOSER(Stop_t)::choose(stop_, default_stop);
Default_Split_t default_split; Default_Split_t default_split;
typename RF_CHOOSER(Split_t)::type split typename RF_CHOOSER(Split_t)::type split
= RF_CHOOSER(Split_t)::choose(split_, default_split); = RF_CHOOSER(Split_t)::choose(split_, default_split);
rf::visitors::StopVisiting stopvisiting; rf::visitors::StopVisiting stopvisiting;
typedef rf::visitors::detail::VisitorNode< typedef rf::visitors::detail::VisitorNode<
skipping to change at line 937 skipping to change at line 977
split.set_external_parameters(ext_param_); split.set_external_parameters(ext_param_);
stop.set_external_parameters(ext_param_); stop.set_external_parameters(ext_param_);
//initialize trees. //initialize trees.
trees_.resize(options_.tree_count_ , DecisionTree_t(ext_param_)); trees_.resize(options_.tree_count_ , DecisionTree_t(ext_param_));
Sampler<Random_t > sampler(preprocessor.strata().begin(), Sampler<Random_t > sampler(preprocessor.strata().begin(),
preprocessor.strata().end(), preprocessor.strata().end(),
detail::make_sampler_opt(options_) detail::make_sampler_opt(options_)
.sampleSize(ext_param().actual_msam ple_), .sampleSize(ext_param().actual_msam ple_),
random); &random);
visitor.visit_at_beginning(*this, preprocessor); visitor.visit_at_beginning(*this, preprocessor);
// THE MAIN EFFING RF LOOP - YEAY DUDE! // THE MAIN EFFING RF LOOP - YEAY DUDE!
for(int ii = 0; ii < (int)trees_.size(); ++ii) for(int ii = 0; ii < static_cast<int>(trees_.size()); ++ii)
{ {
//initialize First region/node/stack entry //initialize First region/node/stack entry
sampler sampler
.sample(); .sample();
StackEntry_t StackEntry_t
first_stack_entry( sampler.sampledIndices().begin(), first_stack_entry( sampler.sampledIndices().begin(),
sampler.sampledIndices().end(), sampler.sampledIndices().end(),
ext_param_.class_count_); ext_param_.class_count_);
first_stack_entry first_stack_entry
.set_oob_range( sampler.oobIndices().begin(), .set_oob_range( sampler.oobIndices().begin(),
skipping to change at line 986 skipping to change at line 1026
template <class U, class C, class Stop> template <class U, class C, class Stop>
LabelType RandomForest<LabelType, Tag> LabelType RandomForest<LabelType, Tag>
::predictLabel(MultiArrayView<2, U, C> const & features, Stop & stop) c onst ::predictLabel(MultiArrayView<2, U, C> const & features, Stop & stop) c onst
{ {
vigra_precondition(columnCount(features) >= ext_param_.column_count_, vigra_precondition(columnCount(features) >= ext_param_.column_count_,
"RandomForestn::predictLabel():" "RandomForestn::predictLabel():"
" Too few columns in feature matrix."); " Too few columns in feature matrix.");
vigra_precondition(rowCount(features) == 1, vigra_precondition(rowCount(features) == 1,
"RandomForestn::predictLabel():" "RandomForestn::predictLabel():"
" Feature matrix must have a singlerow."); " Feature matrix must have a singlerow.");
typedef MultiArrayShape<2>::type Shp; MultiArray<2, double> probabilities(Shape2(1, ext_param_.class_count_),
garbage_prediction_.reshape(Shp(1, ext_param_.class_count_), 0.0); 0.0);
LabelType d; LabelType d;
predictProbabilities(features, garbage_prediction_, stop); predictProbabilities(features, probabilities, stop);
ext_param_.to_classlabel(argMax(garbage_prediction_), d); ext_param_.to_classlabel(argMax(probabilities), d);
return d; return d;
} }
//Same thing as above with priors for each label !!! //Same thing as above with priors for each label !!!
template <class LabelType, class PreprocessorTag> template <class LabelType, class PreprocessorTag>
template <class U, class C> template <class U, class C>
LabelType RandomForest<LabelType, PreprocessorTag> LabelType RandomForest<LabelType, PreprocessorTag>
::predictLabel( MultiArrayView<2, U, C> const & features, ::predictLabel( MultiArrayView<2, U, C> const & features,
ArrayVectorView<double> priors) const ArrayVectorView<double> priors) const
{ {
skipping to change at line 1035 skipping to change at line 1074
vigra_precondition(rowCount(predictionSet.features) == rowCount(prob), vigra_precondition(rowCount(predictionSet.features) == rowCount(prob),
"RandomFroest::predictProbabilities():" "RandomFroest::predictProbabilities():"
" Feature matrix and probability matrix size mismatc h."); " Feature matrix and probability matrix size mismatc h.");
// num of features must be bigger than num of features in Random forest training // num of features must be bigger than num of features in Random forest training
// but why bigger? // but why bigger?
vigra_precondition( columnCount(predictionSet.features) >= ext_param_.c olumn_count_, vigra_precondition( columnCount(predictionSet.features) >= ext_param_.c olumn_count_,
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Too few columns in feature matrix."); " Too few columns in feature matrix.");
vigra_precondition( columnCount(prob) vigra_precondition( columnCount(prob)
== (MultiArrayIndex)ext_param_.class_count_, == static_cast<MultiArrayIndex>(ext_param_.class_co unt_),
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Probability matrix must have as many columns as there are classes." ); " Probability matrix must have as many columns as there are classes." );
prob.init(0.0); prob.init(0.0);
//store total weights //store total weights
std::vector<T1> totalWeights(predictionSet.indices[0].size(),0.0); std::vector<T1> totalWeights(predictionSet.indices[0].size(),0.0);
//Go through all trees //Go through all trees
int set_id=-1; int set_id=-1;
for(int k=0; k<options_.tree_count_; ++k) for(int k=0; k<options_.tree_count_; ++k)
{ {
set_id=(set_id+1) % predictionSet.indices[0].size(); set_id=(set_id+1) % predictionSet.indices[0].size();
skipping to change at line 1074 skipping to change at line 1113
if(trees_[k].isLeafNode(trees_[k].topology_[index])) if(trees_[k].isLeafNode(trees_[k].topology_[index]))
{ {
ArrayVector<double>::iterator weights=Node<e_ConstProbNode> (trees_[k].topology_, ArrayVector<double>::iterator weights=Node<e_ConstProbNode> (trees_[k].topology_,
trees_[k].parameters_, trees_[k].parameters_,
index).prob_begin(); index).prob_begin();
for(int i=range->start;i!=range->end;++i) for(int i=range->start;i!=range->end;++i)
{ {
//update votecount. //update votecount.
for(int l=0; l<ext_param_.class_count_; ++l) for(int l=0; l<ext_param_.class_count_; ++l)
{ {
prob(predictionSet.indices[set_id][i], l) += (T2)we ights[l]; prob(predictionSet.indices[set_id][i], l) += static _cast<T2>(weights[l]);
//every weight in totalWeight. //every weight in totalWeight.
totalWeights[predictionSet.indices[set_id][i]] += ( T1)weights[l]; totalWeights[predictionSet.indices[set_id][i]] += s tatic_cast<T1>(weights[l]);
} }
} }
} }
else else
{ {
if(trees_[k].topology_[index]!=i_ThresholdNode) if(trees_[k].topology_[index]!=i_ThresholdNode)
{ {
throw std::runtime_error("predicting with online predic tion sets is only supported for RFs with threshold nodes"); throw std::runtime_error("predicting with online predic tion sets is only supported for RFs with threshold nodes");
} }
skipping to change at line 1178 skipping to change at line 1217
vigra_precondition(rowCount(features) == rowCount(prob), vigra_precondition(rowCount(features) == rowCount(prob),
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Feature matrix and probability matrix size mismatch."); " Feature matrix and probability matrix size mismatch.");
// num of features must be bigger than num of features in Random forest training // num of features must be bigger than num of features in Random forest training
// but why bigger? // but why bigger?
vigra_precondition( columnCount(features) >= ext_param_.column_count_, vigra_precondition( columnCount(features) >= ext_param_.column_count_,
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Too few columns in feature matrix."); " Too few columns in feature matrix.");
vigra_precondition( columnCount(prob) vigra_precondition( columnCount(prob)
== (MultiArrayIndex)ext_param_.class_count_, == static_cast<MultiArrayIndex>(ext_param_.class_co unt_),
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Probability matrix must have as many columns as there are classes." ); " Probability matrix must have as many columns as there are classes." );
#define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_> #define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_>
Default_Stop_t default_stop(options_); Default_Stop_t default_stop(options_);
typename RF_CHOOSER(Stop_t)::type & stop typename RF_CHOOSER(Stop_t)::type & stop
= RF_CHOOSER(Stop_t)::choose(stop_, default_stop); = RF_CHOOSER(Stop_t)::choose(stop_, default_stop);
#undef RF_CHOOSER #undef RF_CHOOSER
stop.set_external_parameters(ext_param_, tree_count()); stop.set_external_parameters(ext_param_, tree_count());
prob.init(NumericTraits<T>::zero()); prob.init(NumericTraits<T>::zero());
skipping to change at line 1200 skipping to change at line 1239
* - we wanted the order of the trees to be randomized * - we wanted the order of the trees to be randomized
if(tree_indices_.size() != 0) if(tree_indices_.size() != 0)
{ {
std::random_shuffle(tree_indices_.begin(), std::random_shuffle(tree_indices_.begin(),
tree_indices_.end()); tree_indices_.end());
} }
*/ */
//Classify for each row. //Classify for each row.
for(int row=0; row < rowCount(features); ++row) for(int row=0; row < rowCount(features); ++row)
{ {
MultiArrayView<2, U, StridedArrayTag> currentRow(rowVector(features
, row));
// when the features contain an NaN, the instance doesn't belong to
any class
// => indicate this by returning a zero probability array.
if(detail::contains_nan(currentRow))
{
rowVector(prob, row).init(0.0);
continue;
}
ArrayVector<double>::const_iterator weights; ArrayVector<double>::const_iterator weights;
//totalWeight == totalVoteCount! //totalWeight == totalVoteCount!
double totalWeight = 0.0; double totalWeight = 0.0;
//Let each tree classify... //Let each tree classify...
for(int k=0; k<options_.tree_count_; ++k) for(int k=0; k<options_.tree_count_; ++k)
{ {
//get weights predicted by single tree //get weights predicted by single tree
weights = trees_[k /*tree_indices_[k]*/].predict(rowVector(feat ures, row)); weights = trees_[k /*tree_indices_[k]*/].predict(currentRow);
//update votecount. //update votecount.
int weighted = options_.predict_weighted_; int weighted = options_.predict_weighted_;
for(int l=0; l<ext_param_.class_count_; ++l) for(int l=0; l<ext_param_.class_count_; ++l)
{ {
double cur_w = weights[l] * (weighted * (*(weights-1)) double cur_w = weights[l] * (weighted * (*(weights-1))
+ (1-weighted)); + (1-weighted));
prob(row, l) += (T)cur_w; prob(row, l) += static_cast<T>(cur_w);
//every weight in totalWeight. //every weight in totalWeight.
totalWeight += cur_w; totalWeight += cur_w;
} }
if(stop.after_prediction(weights, if(stop.after_prediction(weights,
k, k,
rowVector(prob, row), rowVector(prob, row),
totalWeight)) totalWeight))
{ {
break; break;
} }
skipping to change at line 1258 skipping to change at line 1307
vigra_precondition(rowCount(features) == rowCount(prob), vigra_precondition(rowCount(features) == rowCount(prob),
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Feature matrix and probability matrix size mismatch."); " Feature matrix and probability matrix size mismatch.");
// num of features must be bigger than num of features in Random forest training // num of features must be bigger than num of features in Random forest training
// but why bigger? // but why bigger?
vigra_precondition( columnCount(features) >= ext_param_.column_count_, vigra_precondition( columnCount(features) >= ext_param_.column_count_,
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Too few columns in feature matrix."); " Too few columns in feature matrix.");
vigra_precondition( columnCount(prob) vigra_precondition( columnCount(prob)
== (MultiArrayIndex)ext_param_.class_count_, == static_cast<MultiArrayIndex>(ext_param_.class_co unt_),
"RandomForestn::predictProbabilities():" "RandomForestn::predictProbabilities():"
" Probability matrix must have as many columns as there are classes." ); " Probability matrix must have as many columns as there are classes." );
#define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_> #define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_>
prob.init(NumericTraits<T>::zero()); prob.init(NumericTraits<T>::zero());
/* This code was originally there for testing early stopping /* This code was originally there for testing early stopping
* - we wanted the order of the trees to be randomized * - we wanted the order of the trees to be randomized
if(tree_indices_.size() != 0) if(tree_indices_.size() != 0)
{ {
std::random_shuffle(tree_indices_.begin(), std::random_shuffle(tree_indices_.begin(),
skipping to change at line 1292 skipping to change at line 1341
{ {
//get weights predicted by single tree //get weights predicted by single tree
weights = trees_[k /*tree_indices_[k]*/].predict(rowVector(feat ures, row)); weights = trees_[k /*tree_indices_[k]*/].predict(rowVector(feat ures, row));
//update votecount. //update votecount.
int weighted = options_.predict_weighted_; int weighted = options_.predict_weighted_;
for(int l=0; l<ext_param_.class_count_; ++l) for(int l=0; l<ext_param_.class_count_; ++l)
{ {
double cur_w = weights[l] * (weighted * (*(weights-1)) double cur_w = weights[l] * (weighted * (*(weights-1))
+ (1-weighted)); + (1-weighted));
prob(row, l) += (T)cur_w; prob(row, l) += static_cast<T>(cur_w);
//every weight in totalWeight. //every weight in totalWeight.
totalWeight += cur_w; totalWeight += cur_w;
} }
} }
} }
prob/= options_.tree_count_; prob/= options_.tree_count_;
} }
//@} //@}
 End of changes. 29 change blocks. 
31 lines changed or deleted 88 lines changed or added


 random_forest_hdf5_impex.hxx   random_forest_hdf5_impex.hxx 
skipping to change at line 227 skipping to change at line 227
*/ */
template<class T, class Tag> template<class T, class Tag>
void rf_export_HDF5(const RandomForest<T, Tag> & rf, void rf_export_HDF5(const RandomForest<T, Tag> & rf,
const std::string & filename, const std::string & filename,
const std::string & pathname = "") const std::string & pathname = "")
{ {
HDF5File h5context(filename , HDF5File::Open); HDF5File h5context(filename , HDF5File::Open);
rf_export_HDF5(rf, h5context, pathname); rf_export_HDF5(rf, h5context, pathname);
} }
/** \brief Save a random forest to an HDF5 file specified by its id
The random forest is saved as a set of HDF5 datasets, groups, and
attributes below a certain HDF5 group (default: root). No additional da
ta
should be stored in that group.
\warning In case the underlying HDF5 library used by Vigra is not
exactly the same library used to open the file with the given id, this
method will lead to crashes.
\param rf Random forest object to be exported
\param outf_id HDF5 file id
\param pathname If empty or not supplied, save the random forest to the
root group of the HDF5 file. Otherwise, save to a
new-created group specified by the path name (relative
to the root group).
*/
template<class T, class Tag>
void rf_export_HDF5(const RandomForest<T, Tag> & rf,
hid_t outf_id,
const std::string & pathname = "")
{
HDF5HandleShared fileHandle(outf_id, NULL, "");
HDF5File h5context(fileHandle, pathname);
rf_export_HDF5(rf, h5context);
}
/** \brief Read a random forest from an HDF5File object's specified group. /** \brief Read a random forest from an HDF5File object's specified group.
The random forest is read from a certain HDF5 group (default: current g roup The random forest is read from a certain HDF5 group (default: current g roup
of the HDF5File object) as a set of HDF5 datasets, groups, and of the HDF5File object) as a set of HDF5 datasets, groups, and
attributes. No additional data should be present in that group. attributes. No additional data should be present in that group.
\param rf Random forest object to be imported \param rf Random forest object to be imported
\param h5context HDF5File object to use \param h5context HDF5File object to use
\param pathname If empty or not supplied, read from the random forest \param pathname If empty or not supplied, read from the random forest
from the current group of the HDF5File object. Otherwi se, from the current group of the HDF5File object. Otherwi se,
skipping to change at line 264 skipping to change at line 291
h5context.readAttribute(rf_hdf5_version_group, rf_hdf5_version_tag, h5context.readAttribute(rf_hdf5_version_group, rf_hdf5_version_tag,
read_version); read_version);
vigra_precondition(read_version <= rf_hdf5_version, vigra_precondition(read_version <= rf_hdf5_version,
"rf_import_HDF5(): unexpected file format version ."); "rf_import_HDF5(): unexpected file format version .");
} }
// get serialized options // get serialized options
detail::options_import_HDF5(h5context, rf.options_, rf_hdf5_options); detail::options_import_HDF5(h5context, rf.options_, rf_hdf5_options);
// get external parameters // get external parameters
detail::problemspec_import_HDF5(h5context, rf.ext_param_, detail::problemspec_import_HDF5(h5context, rf.ext_param_,
rf_hdf5_ext_param); rf_hdf5_ext_param);
rf.trees_.clear();
// get all groups in base path // get all groups in base path
// no check for the rf_hdf5_tree prefix... // no check for the rf_hdf5_tree prefix...
std::vector<std::string> names = h5context.ls(); std::vector<std::string> names = h5context.ls();
std::vector<std::string>::const_iterator j; std::vector<std::string>::const_iterator j;
for (j = names.begin(); j != names.end(); ++j) for (j = names.begin(); j != names.end(); ++j)
{ {
if ((*j->rbegin() == '/') && (*j->begin() != '_')) // skip the abov e if ((*j->rbegin() == '/') && (*j->begin() != '_')) // skip the abov e
{ {
rf.trees_.push_back(detail::DecisionTree(rf.ext_param_)); rf.trees_.push_back(detail::DecisionTree(rf.ext_param_));
detail::dt_import_HDF5(h5context, rf.trees_.back(), *j); detail::dt_import_HDF5(h5context, rf.trees_.back(), *j);
skipping to change at line 299 skipping to change at line 327
\param pathname If empty or not supplied, read from the random forest \param pathname If empty or not supplied, read from the random forest
from the current group of the HDF5 file. Otherwise, from the current group of the HDF5 file. Otherwise,
use the group specified by the path name, which may use the group specified by the path name, which may
be either relative or absolute. be either relative or absolute.
*/ */
template<class T, class Tag> template<class T, class Tag>
bool rf_import_HDF5(RandomForest<T, Tag> & rf, bool rf_import_HDF5(RandomForest<T, Tag> & rf,
const std::string & filename, const std::string & filename,
const std::string & pathname = "") const std::string & pathname = "")
{ {
HDF5File h5context(filename, HDF5File::Open); HDF5File h5context(filename, HDF5File::OpenReadOnly);
return rf_import_HDF5(rf, h5context, pathname); return rf_import_HDF5(rf, h5context, pathname);
} }
/** \brief Read a random forest from an HDF5 file specified by its id.
The random forest is read from a certain HDF5 group (default: root grou
p
of the HDF5 file) as a set of HDF5 datasets, groups, and attributes.
No additional data should be present in that group.
\warning In case the underlying HDF5 library used by Vigra is not
exactly the same library used to open the file with the given id, this
method will lead to crashes.
\param rf Random forest object to be imported
\param inf_id HDF5 file id
\param pathname If empty or not supplied, read from the random forest
from the current group of the HDF5 file. Otherwise,
use the group specified by the path name, which may
be either relative or absolute.
*/
template<class T, class Tag>
bool rf_import_HDF5(RandomForest<T, Tag> & rf,
hid_t inf_id,
const std::string & pathname = "")
{
HDF5HandleShared fileHandle(inf_id, NULL, "");
HDF5File h5context(fileHandle, pathname, true);
return rf_import_HDF5(rf, h5context);
}
} // namespace vigra } // namespace vigra
#endif // VIGRA_RANDOM_FOREST_HDF5_IMPEX_HXX #endif // VIGRA_RANDOM_FOREST_HDF5_IMPEX_HXX
 End of changes. 4 change blocks. 
1 lines changed or deleted 58 lines changed or added


 rational.hxx   rational.hxx 
skipping to change at line 70 skipping to change at line 70
/** \addtogroup MathFunctions Mathematical Functions /** \addtogroup MathFunctions Mathematical Functions
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* gcd */ /* gcd */
/* */ /* */
/********************************************************/ /********************************************************/
/*! Calculate the greatest common divisor. /** Calculate the greatest common divisor.
This function works for arbitrary integer types, including user-defined This function works for arbitrary integer types, including user-defined
(e.g. infinite precision) ones. (e.g. infinite precision) ones.
<b>\#include</b> \<vigra/rational.hxx\><br> <b>\#include</b> \<vigra/rational.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <typename IntType> template <typename IntType>
IntType gcd(IntType n, IntType m) IntType gcd(IntType n, IntType m)
{ {
skipping to change at line 111 skipping to change at line 111
m %= n; m %= n;
} }
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* lcm */ /* lcm */
/* */ /* */
/********************************************************/ /********************************************************/
/*! Calculate the lowest common multiple. /** Calculate the lowest common multiple.
This function works for arbitrary integer types, including user-defined This function works for arbitrary integer types, including user-defined
(e.g. infinite precision) ones. (e.g. infinite precision) ones.
<b>\#include</b> \<vigra/rational.hxx\><br> <b>\#include</b> \<vigra/rational.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <typename IntType> template <typename IntType>
IntType lcm(IntType n, IntType m) IntType lcm(IntType n, IntType m)
{ {
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 recursiveconvolution.hxx   recursiveconvolution.hxx 
skipping to change at line 46 skipping to change at line 46
#ifndef VIGRA_RECURSIVECONVOLUTION_HXX #ifndef VIGRA_RECURSIVECONVOLUTION_HXX
#define VIGRA_RECURSIVECONVOLUTION_HXX #define VIGRA_RECURSIVECONVOLUTION_HXX
#include <cmath> #include <cmath>
#include <vector> #include <vector>
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "imageiteratoradapter.hxx" #include "imageiteratoradapter.hxx"
#include "bordertreatment.hxx" #include "bordertreatment.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* Recursive convolution functions */ /* Recursive convolution functions */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup RecursiveConvolution Recursive convolution functions /** \addtogroup RecursiveConvolution Recursive convolution functions
skipping to change at line 125 skipping to change at line 126
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vector<float> src, dest; vector<float> src, dest;
... ...
vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor; DefaultAccessor<vector<float>::iterator, float> FAccessor;
vigra::recursiveFilterLine(src.begin(), src.end(), FAccessor(), recursiveFilterLine(src.begin(), src.end(), FAccessor(),
dest.begin(), FAccessor(), dest.begin(), FAccessor(),
0.5, BORDER_TREATMENT_REFLECT); 0.5, BORDER_TREATMENT_REFLECT);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
RandomAccessIterator is, isend; RandomAccessIterator is, isend;
RandomAccessIterator id; RandomAccessIterator id;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is ); NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is );
double d; double d;
s = s + s; s = s + s;
s = d * s; s = d * s;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id); NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
-1 < b < 1 -1 < b < 1
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void recursiveFilterLine) doxygen_overloaded_function(template <...> void recursiveFilterLine)
skipping to change at line 273 skipping to change at line 273
if(border == BORDER_TREATMENT_CLIP) if(border == BORDER_TREATMENT_CLIP)
{ {
// correction factors for b // correction factors for b
double bright = b; double bright = b;
double bleft = VIGRA_CSTD::pow(b, w); double bleft = VIGRA_CSTD::pow(b, w);
for(x=w-1; x>=0; --x, --is, --id) for(x=w-1; x>=0; --x, --is, --id)
{ {
TempType f = TempType(b * old); TempType f = TempType(b * old);
old = as(is) + f; old = as(is) + f;
double norm = (1.0 - b) / (1.0 + b - bleft - bright); norm = (1.0 - b) / (1.0 + b - bleft - bright);
bleft /= b; bleft /= b;
bright *= b; bright *= b;
ad.set(norm * (line[x] + f), id); ad.set(norm * (line[x] + f), id);
} }
} }
else if(border == BORDER_TREATMENT_AVOID) else if(border == BORDER_TREATMENT_AVOID)
{ {
for(x=w-1; x >= kernelw; --x, --is, --id) for(x=w-1; x >= kernelw; --x, --is, --id)
{ {
TempType f = TempType(b * old); TempType f = TempType(b * old);
skipping to change at line 316 skipping to change at line 316
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as, void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
DestIterator id, DestAccessor ad, double b1, doubl e b2) DestIterator id, DestAccessor ad, double b1, doubl e b2)
{ {
int w = isend - is; int w = isend - is;
int x; int x;
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote TempTy pe; NumericTraits<typename SrcAccessor::value_type>::RealPromote TempTy pe;
typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
// speichert den Ergebnis der linkseitigen Filterung. // speichert den Ergebnis der linkseitigen Filterung.
std::vector<TempType> vline(w+1); std::vector<TempType> vline(w+1);
typename std::vector<TempType>::iterator line = vline.begin(); typename std::vector<TempType>::iterator line = vline.begin();
double norm = 1.0 - b1 - b2; double norm = 1.0 - b1 - b2;
double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2); double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2);
double norm2 = norm * norm; double norm2 = norm * norm;
// init left side of filter // init left side of filter
skipping to change at line 429 skipping to change at line 428
DestAccessor dest_accessor; DestAccessor dest_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is ); NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is );
double d; double d;
s = s + s; s = s + s;
s = d * s; s = d * s;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id); NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
0 <= sigma (absolute values are used for negative sigma) 0 <= sigma (absolute values are used for negative sigma)
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void recursiveGaussianFilterLine ) doxygen_overloaded_function(template <...> void recursiveGaussianFilterLine )
skipping to change at line 468 skipping to change at line 466
int w = isend - is; int w = isend - is;
vigra_precondition(w >= 4, vigra_precondition(w >= 4,
"recursiveGaussianFilterLine(): line must have at least length 4.") ; "recursiveGaussianFilterLine(): line must have at least length 4.") ;
int kernelw = std::min(w-4, (int)(4.0*sigma)); int kernelw = std::min(w-4, (int)(4.0*sigma));
int x; int x;
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote TempTy pe; NumericTraits<typename SrcAccessor::value_type>::RealPromote TempTy pe;
typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
// speichert das Ergebnis der linkseitigen Filterung. // speichert das Ergebnis der linkseitigen Filterung.
std::vector<TempType> yforward(w); std::vector<TempType> yforward(w);
std::vector<TempType> ybackward(w, 0.0); std::vector<TempType> ybackward(w, 0.0);
// initialise the filter for reflective boundary conditions // initialise the filter for reflective boundary conditions
for(x=kernelw; x>=0; --x) for(x=kernelw; x>=0; --x)
{ {
ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is , x) + (b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3])); ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is , x) + (b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
skipping to change at line 570 skipping to change at line 567
DestAccessor dest_accessor; DestAccessor dest_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is ); NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is );
double d; double d;
s = s + s; s = s + s;
s = d * s; s = d * s;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id); NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void recursiveSmoothLine) doxygen_overloaded_function(template <...> void recursiveSmoothLine)
skipping to change at line 657 skipping to change at line 653
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is ); NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is );
double d; double d;
s = s + s; s = s + s;
s = -s; s = -s;
s = d * s; s = d * s;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id); NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void recursiveFirstDerivativeLin e) doxygen_overloaded_function(template <...> void recursiveFirstDerivativeLin e)
skipping to change at line 776 skipping to change at line 771
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is ); NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is );
double d; double d;
s = s + s; s = s + s;
s = s - s; s = s - s;
s = d * s; s = d * s;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id); NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
scale > 0 scale > 0
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void recursiveSecondDerivativeLi ne) doxygen_overloaded_function(template <...> void recursiveSecondDerivativeLi ne)
skipping to change at line 851 skipping to change at line 845
/********************************************************/ /********************************************************/
/** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) i n x direction. /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) i n x direction.
It calls \ref recursiveFilterLine() for every row of the It calls \ref recursiveFilterLine() for every row of the
image. See \ref recursiveFilterLine() for more information about image. See \ref recursiveFilterLine() for more information about
required interfaces and vigra_preconditions. required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// first order filter
template <class T1, class S1,
class T2, class S2>
void
recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b, BorderTreatmentMode border);
// second order filter
template <class T1, class S1,
class T2, class S2>
void
recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b1, double b2);
}
\endcode
\deprecatedAPI{recursiveFilterX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// first order filter // first order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterX(SrcImageIterator supperleft, void recursiveFilterX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as , SrcImageIterator slowerright, SrcAccessor as ,
DestImageIterator dupperleft, DestAccessor a d, DestImageIterator dupperleft, DestAccessor a d,
double b, BorderTreatmentMode border); double b, BorderTreatmentMode border);
// second order filter // second order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterX(SrcImageIterator supperleft, void recursiveFilterX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as , SrcImageIterator slowerright, SrcAccessor as ,
DestImageIterator dupperleft, DestAccessor a d, DestImageIterator dupperleft, DestAccessor a d,
double b1, double b2); double b1, double b2);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// first order filter // first order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterX( void recursiveFilterX(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double b, BorderTreatmentMode border); double b, BorderTreatmentMode border);
// second order filter // second order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterX( void recursiveFilterX(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double b1, double b2); double b1, double b2);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
// apply a first-order filter to the x-axis
recursiveFilterX(src, dest, 0.5, BORDER_TREATMENT_REFLECT);
\endcode
\deprecatedUsage{recursiveFilterX}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), vigra::recursiveFilterX(srcImageRange(src), destImage(dest),
0.5, BORDER_TREATMENT_REFLECT); 0.5, BORDER_TREATMENT_REFLECT);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveFilterX) doxygen_overloaded_function(template <...> void recursiveFilterX)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterX(SrcImageIterator supperleft, void recursiveFilterX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double b, BorderTreatmentMode border) double b, BorderTreatmentMode border)
{ {
skipping to change at line 935 skipping to change at line 959
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r(); typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r();
recursiveFilterLine(rs, rs+w, as, recursiveFilterLine(rs, rs+w, as,
rd, ad, rd, ad,
b, border); b, border);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveFilterX( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr
pair<DestImageIterator, DestAccessor> dest, c,
double b, BorderTreatmentMode border) pair<DestImageIterator, DestAccessor> dest,
double b, BorderTreatmentMode border)
{ {
recursiveFilterX(src.first, src.second, src.third, recursiveFilterX(src.first, src.second, src.third,
dest.first, dest.second, b, border); dest.first, dest.second, b, border);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b, BorderTreatmentMode border)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveFilterX(): shape mismatch between input and output.");
recursiveFilterX(srcImageRange(src),
destImage(dest), b, border);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveFilterX (2nd order) */ /* recursiveFilterX (2nd order) */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
skipping to change at line 975 skipping to change at line 1012
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r(); typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r();
recursiveFilterLine(rs, rs+w, as, recursiveFilterLine(rs, rs+w, as,
rd, ad, rd, ad,
b1, b2); b1, b2);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveFilterX( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr
pair<DestImageIterator, DestAccessor> dest, c,
double b1, double b2) pair<DestImageIterator, DestAccessor> dest,
double b1, double b2)
{ {
recursiveFilterX(src.first, src.second, src.third, recursiveFilterX(src.first, src.second, src.third,
dest.first, dest.second, b1, b2); dest.first, dest.second, b1, b2);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b1, double b2)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveFilterX(): shape mismatch between input and output.");
recursiveFilterX(srcImageRange(src),
destImage(dest), b1, b2);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveGaussianFilterX */ /* recursiveGaussianFilterX */
/* */ /* */
/********************************************************/ /********************************************************/
// AUTHOR: Sebastian Boppel // AUTHOR: Sebastian Boppel
/** \brief Compute 1 dimensional recursive approximation of Gaussian smooth ing in y direction. /** \brief Compute 1 dimensional recursive approximation of Gaussian smooth ing in y direction.
It calls \ref recursiveGaussianFilterLine() for every column of the It calls \ref recursiveGaussianFilterLine() for every column of the
image. See \ref recursiveGaussianFilterLine() for more information abou t image. See \ref recursiveGaussianFilterLine() for more information abou t
required interfaces and vigra_preconditions. required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveGaussianFilterX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigma);
}
\endcode
\deprecatedAPI{recursiveGaussianFilterX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageItera tor slowerright, SrcAccessor as, recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageItera tor slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double sigma); double sigma);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest , pair<DestImageIterator, DestAccessor> dest ,
double sigma); double sigma);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveGaussianFilterX(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveGaussianFilterX}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3. 0); vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3. 0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveGaussianFilterX) doxygen_overloaded_function(template <...> void recursiveGaussianFilterX)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slow erright, SrcAccessor as, recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slow erright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double sigma) double sigma)
{ {
skipping to change at line 1074 skipping to change at line 1144
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void inline void
recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAcce ssor> src, recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAcce ssor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double sigma) double sigma)
{ {
recursiveGaussianFilterX(src.first, src.second, src.third, recursiveGaussianFilterX(src.first, src.second, src.third,
dest.first, dest.second, sigma); dest.first, dest.second, sigma);
} }
template <class T1, class S1,
class T2, class S2>
inline void
recursiveGaussianFilterX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigma)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveGaussianFilterX(): shape mismatch between input and outpu
t.");
recursiveGaussianFilterX(srcImageRange(src),
destImage(dest), sigma);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveSmoothX */ /* recursiveSmoothX */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Performs 1 dimensional recursive smoothing in x direction. /** \brief Performs 1 dimensional recursive smoothing in x direction.
It calls \ref recursiveSmoothLine() for every row of the It calls \ref recursiveSmoothLine() for every row of the
image. See \ref recursiveSmoothLine() for more information about image. See \ref recursiveSmoothLine() for more information about
required interfaces and vigra_preconditions. required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveSmoothX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{recursiveSmoothX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSmoothX(SrcImageIterator supperleft, void recursiveSmoothX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSmoothX( void recursiveSmoothX(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveSmoothX(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveGaussianFilterX}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0); vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveSmoothX) doxygen_overloaded_function(template <...> void recursiveSmoothX)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSmoothX(SrcImageIterator supperleft, void recursiveSmoothX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 1153 skipping to change at line 1256
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r(); typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r();
recursiveSmoothLine(rs, rs+w, as, recursiveSmoothLine(rs, rs+w, as,
rd, ad, rd, ad,
scale); scale);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveSmoothX( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveSmoothX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr
pair<DestImageIterator, DestAccessor> dest, c,
double scale) pair<DestImageIterator, DestAccessor> dest,
double scale)
{ {
recursiveSmoothX(src.first, src.second, src.third, recursiveSmoothX(src.first, src.second, src.third,
dest. first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveSmoothX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveSmoothX(): shape mismatch between input and output.");
recursiveSmoothX(srcImageRange(src),
destImage(dest), scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveFilterY */ /* recursiveFilterY */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) i n y direction. /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) i n y direction.
It calls \ref recursiveFilterLine() for every column of the It calls \ref recursiveFilterLine() for every column of the
image. See \ref recursiveFilterLine() for more information about image. See \ref recursiveFilterLine() for more information about
required interfaces and vigra_preconditions. required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
// first order filter
template <class T1, class S1,
class T2, class S2>
void
recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b, BorderTreatmentMode border);
// second order filter
template <class T1, class S1,
class T2, class S2>
void
recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b1, double b2);
}
\endcode
\deprecatedAPI{recursiveFilterY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
// first order filter // first order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterY(SrcImageIterator supperleft, void recursiveFilterY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as , SrcImageIterator slowerright, SrcAccessor as ,
DestImageIterator dupperleft, DestAccessor a d, DestImageIterator dupperleft, DestAccessor a d,
double b, BorderTreatmentMode border); double b, BorderTreatmentMode border);
// second order filter // second order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterY(SrcImageIterator supperleft, void recursiveFilterY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as , SrcImageIterator slowerright, SrcAccessor as ,
DestImageIterator dupperleft, DestAccessor a d, DestImageIterator dupperleft, DestAccessor a d,
double b1, double b2); double b1, double b2);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
// first order filter // first order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterY( void recursiveFilterY(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double b, BorderTreatmentMode border); double b, BorderTreatmentMode border);
// second order filter // second order filter
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterY( void recursiveFilterY(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double b1, double b2); double b1, double b2);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
// apply a second-order filter to the y-axis
recursiveFilterY(src, dest, -0.6, -0.06);
\endcode
\deprecatedUsage{recursiveFilterY}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.0 6); vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.0 6);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveFilterY) doxygen_overloaded_function(template <...> void recursiveFilterY)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFilterY(SrcImageIterator supperleft, void recursiveFilterY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double b, BorderTreatmentMode border) double b, BorderTreatmentMode border)
{ {
skipping to change at line 1259 skipping to change at line 1405
typename DestImageIterator::column_iterator cd = dupperleft.columnI terator(); typename DestImageIterator::column_iterator cd = dupperleft.columnI terator();
recursiveFilterLine(cs, cs+h, as, recursiveFilterLine(cs, cs+h, as,
cd, ad, cd, ad,
b, border); b, border);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveFilterY( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr
pair<DestImageIterator, DestAccessor> dest, c,
double b, BorderTreatmentMode border) pair<DestImageIterator, DestAccessor> dest,
double b, BorderTreatmentMode border)
{ {
recursiveFilterY(src.first, src.second, src.third, recursiveFilterY(src.first, src.second, src.third,
dest.first, dest.second, b, border); dest.first, dest.second, b, border);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b, BorderTreatmentMode border)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveFilterY(): shape mismatch between input and output.");
recursiveFilterY(srcImageRange(src),
destImage(dest), b, border);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveFilterY (2nd order) */ /* recursiveFilterY (2nd order) */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
skipping to change at line 1299 skipping to change at line 1458
typename DestImageIterator::column_iterator cd = dupperleft.columnI terator(); typename DestImageIterator::column_iterator cd = dupperleft.columnI terator();
recursiveFilterLine(cs, cs+h, as, recursiveFilterLine(cs, cs+h, as,
cd, ad, cd, ad,
b1, b2); b1, b2);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveFilterY( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr
pair<DestImageIterator, DestAccessor> dest, c,
double b1, double b2) pair<DestImageIterator, DestAccessor> dest,
double b1, double b2)
{ {
recursiveFilterY(src.first, src.second, src.third, recursiveFilterY(src.first, src.second, src.third,
dest.first, dest.second, b1, b2); dest.first, dest.second, b1, b2);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double b1, double b2)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveFilterY(): shape mismatch between input and output.");
recursiveFilterY(srcImageRange(src),
destImage(dest), b1, b2);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveGaussianFilterY */ /* recursiveGaussianFilterY */
/* */ /* */
/********************************************************/ /********************************************************/
// AUTHOR: Sebastian Boppel // AUTHOR: Sebastian Boppel
/** \brief Compute 1 dimensional recursive approximation of Gaussian smooth ing in y direction. /** \brief Compute 1 dimensional recursive approximation of Gaussian smooth ing in y direction.
It calls \ref recursiveGaussianFilterLine() for every column of the It calls \ref recursiveGaussianFilterLine() for every column of the
image. See \ref recursiveGaussianFilterLine() for more information abou t image. See \ref recursiveGaussianFilterLine() for more information abou t
required interfaces and vigra_preconditions. required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveGaussianFilterY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigma);
}
\endcode
\deprecatedAPI{recursiveGaussianFilterY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageItera tor slowerright, SrcAccessor as, recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageItera tor slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double sigma); double sigma);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest , pair<DestImageIterator, DestAccessor> dest ,
double sigma); double sigma);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveGaussianFilterY(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveGaussianFilterY}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3. 0); vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3. 0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveGaussianFilterY) doxygen_overloaded_function(template <...> void recursiveGaussianFilterY)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slow erright, SrcAccessor as, recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slow erright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double sigma) double sigma)
{ {
skipping to change at line 1398 skipping to change at line 1590
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void inline void
recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAcce ssor> src, recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAcce ssor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double sigma) double sigma)
{ {
recursiveGaussianFilterY(src.first, src.second, src.third, recursiveGaussianFilterY(src.first, src.second, src.third,
dest.first, dest.second, sigma); dest.first, dest.second, sigma);
} }
template <class T1, class S1,
class T2, class S2>
inline void
recursiveGaussianFilterY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double sigma)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveGaussianFilterY(): shape mismatch between input and outpu
t.");
recursiveGaussianFilterY(srcImageRange(src),
destImage(dest), sigma);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveSmoothY */ /* recursiveSmoothY */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Performs 1 dimensional recursive smoothing in y direction. /** \brief Performs 1 dimensional recursive smoothing in y direction.
It calls \ref recursiveSmoothLine() for every column of the It calls \ref recursiveSmoothLine() for every column of the
image. See \ref recursiveSmoothLine() for more information about image. See \ref recursiveSmoothLine() for more information about
required interfaces and vigra_preconditions. required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveSmoothY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{recursiveSmoothY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSmoothY(SrcImageIterator supperleft, void recursiveSmoothY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSmoothY( void recursiveSmoothY(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveSmoothY(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveSmoothY}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0); vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveSmoothY) doxygen_overloaded_function(template <...> void recursiveSmoothY)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSmoothY(SrcImageIterator supperleft, void recursiveSmoothY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 1477 skipping to change at line 1702
typename DestImageIterator::column_iterator cd = dupperleft.columnI terator(); typename DestImageIterator::column_iterator cd = dupperleft.columnI terator();
recursiveSmoothLine(cs, cs+h, as, recursiveSmoothLine(cs, cs+h, as,
cd, ad, cd, ad,
scale); scale);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveSmoothY( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveSmoothY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr
pair<DestImageIterator, DestAccessor> dest, c,
double scale) pair<DestImageIterator, DestAccessor> dest,
double scale)
{ {
recursiveSmoothY(src.first, src.second, src.third, recursiveSmoothY(src.first, src.second, src.third,
dest. first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveSmoothY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveSmoothY(): shape mismatch between input and output.");
recursiveSmoothY(srcImageRange(src),
destImage(dest), scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveFirstDerivativeX */ /* recursiveFirstDerivativeX */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Recursively calculates the 1 dimensional first derivative in x /** \brief Recursively calculates the 1 dimensional first derivative in x
direction. direction.
It calls \ref recursiveFirstDerivativeLine() for every It calls \ref recursiveFirstDerivativeLine() for every
row of the image. See \ref recursiveFirstDerivativeLine() for more row of the image. See \ref recursiveFirstDerivativeLine() for more
information about required interfaces and vigra_preconditions. information about required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveFirstDerivativeX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{recursiveFirstDerivativeX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFirstDerivativeX(SrcImageIterator supperleft, void recursiveFirstDerivativeX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFirstDerivativeX( void recursiveFirstDerivativeX(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveFirstDerivativeX(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveFirstDerivativeX}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3 .0); vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3 .0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveFirstDerivativeX) doxygen_overloaded_function(template <...> void recursiveFirstDerivativeX)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFirstDerivativeX(SrcImageIterator supperleft, void recursiveFirstDerivativeX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 1566 skipping to change at line 1824
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r(); typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r();
recursiveFirstDerivativeLine(rs, rs+w, as, recursiveFirstDerivativeLine(rs, rs+w, as,
rd, ad, rd, ad,
scale); scale);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveFirstDerivativeX( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveFirstDerivativeX(triple<SrcImageIterator, SrcImageIterator, SrcAcc
pair<DestImageIterator, DestAccessor> dest, essor> src,
double scale) pair<DestImageIterator, DestAccessor> dest,
double scale)
{ {
recursiveFirstDerivativeX(src.first, src.second, src.third, recursiveFirstDerivativeX(src.first, src.second, src.third,
dest. first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveFirstDerivativeX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveFirstDerivativeX(): shape mismatch between input and outp
ut.");
recursiveFirstDerivativeX(srcImageRange(src),
destImage(dest), scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveFirstDerivativeY */ /* recursiveFirstDerivativeY */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Recursively calculates the 1 dimensional first derivative in y /** \brief Recursively calculates the 1 dimensional first derivative in y
direction. direction.
It calls \ref recursiveFirstDerivativeLine() for every It calls \ref recursiveFirstDerivativeLine() for every
column of the image. See \ref recursiveFirstDerivativeLine() for more column of the image. See \ref recursiveFirstDerivativeLine() for more
information about required interfaces and vigra_preconditions. information about required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveFirstDerivativeY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{recursiveFirstDerivativeY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFirstDerivativeY(SrcImageIterator supperleft, void recursiveFirstDerivativeY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFirstDerivativeY( void recursiveFirstDerivativeY(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveFirstDerivativeY(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveFirstDerivativeY}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3 .0); vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3 .0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveFirstDerivativeY) doxygen_overloaded_function(template <...> void recursiveFirstDerivativeY)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveFirstDerivativeY(SrcImageIterator supperleft, void recursiveFirstDerivativeY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 1655 skipping to change at line 1946
typename DestImageIterator::column_iterator cd = dupperleft.columnI terator(); typename DestImageIterator::column_iterator cd = dupperleft.columnI terator();
recursiveFirstDerivativeLine(cs, cs+h, as, recursiveFirstDerivativeLine(cs, cs+h, as,
cd, ad, cd, ad,
scale); scale);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveFirstDerivativeY( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveFirstDerivativeY(triple<SrcImageIterator, SrcImageIterator, SrcAcc
pair<DestImageIterator, DestAccessor> dest, essor> src,
double scale) pair<DestImageIterator, DestAccessor> dest,
double scale)
{ {
recursiveFirstDerivativeY(src.first, src.second, src.third, recursiveFirstDerivativeY(src.first, src.second, src.third,
dest. first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveFirstDerivativeY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveFirstDerivativeY(): shape mismatch between input and outp
ut.");
recursiveFirstDerivativeY(srcImageRange(src),
destImage(dest), scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveSecondDerivativeX */ /* recursiveSecondDerivativeX */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Recursively calculates the 1 dimensional second derivative in x /** \brief Recursively calculates the 1 dimensional second derivative in x
direction. direction.
It calls \ref recursiveSecondDerivativeLine() for every It calls \ref recursiveSecondDerivativeLine() for every
row of the image. See \ref recursiveSecondDerivativeLine() for more row of the image. See \ref recursiveSecondDerivativeLine() for more
information about required interfaces and vigra_preconditions. information about required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveSecondDerivativeX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{recursiveSecondDerivativeX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSecondDerivativeX(SrcImageIterator supperleft, void recursiveSecondDerivativeX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSecondDerivativeX( void recursiveSecondDerivativeX(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveSecondDerivativeX(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveSecondDerivativeX}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0); vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveSecondDerivativeX) doxygen_overloaded_function(template <...> void recursiveSecondDerivativeX)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSecondDerivativeX(SrcImageIterator supperleft, void recursiveSecondDerivativeX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 1744 skipping to change at line 2068
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r(); typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r();
recursiveSecondDerivativeLine(rs, rs+w, as, recursiveSecondDerivativeLine(rs, rs+w, as,
rd, ad, rd, ad,
scale); scale);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveSecondDerivativeX( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveSecondDerivativeX(triple<SrcImageIterator, SrcImageIterator, SrcAc
pair<DestImageIterator, DestAccessor> dest, cessor> src,
double scale) pair<DestImageIterator, DestAccessor> dest,
double scale)
{ {
recursiveSecondDerivativeX(src.first, src.second, src.third, recursiveSecondDerivativeX(src.first, src.second, src.third,
dest. first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveSecondDerivativeX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveSecondDerivativeX(): shape mismatch between input and out
put.");
recursiveSecondDerivativeX(srcImageRange(src),
destImage(dest), scale);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveSecondDerivativeY */ /* recursiveSecondDerivativeY */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Recursively calculates the 1 dimensional second derivative in y /** \brief Recursively calculates the 1 dimensional second derivative in y
direction. direction.
It calls \ref recursiveSecondDerivativeLine() for every It calls \ref recursiveSecondDerivativeLine() for every
column of the image. See \ref recursiveSecondDerivativeLine() for more column of the image. See \ref recursiveSecondDerivativeLine() for more
information about required interfaces and vigra_preconditions. information about required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
recursiveSecondDerivativeY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{recursiveSecondDerivativeY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSecondDerivativeY(SrcImageIterator supperleft, void recursiveSecondDerivativeY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSecondDerivativeY( void recursiveSecondDerivativeY(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
recursiveSecondDerivativeY(src, dest, 3.0);
\endcode
\deprecatedUsage{recursiveSecondDerivativeY}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0); vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void recursiveSecondDerivativeY) doxygen_overloaded_function(template <...> void recursiveSecondDerivativeY)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void recursiveSecondDerivativeY(SrcImageIterator supperleft, void recursiveSecondDerivativeY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor as, SrcImageIterator slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad, DestImageIterator dupperleft, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 1833 skipping to change at line 2190
typename DestImageIterator::column_iterator cd = dupperleft.columnI terator(); typename DestImageIterator::column_iterator cd = dupperleft.columnI terator();
recursiveSecondDerivativeLine(cs, cs+h, as, recursiveSecondDerivativeLine(cs, cs+h, as,
cd, ad, cd, ad,
scale); scale);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void recursiveSecondDerivativeY( inline void
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, recursiveSecondDerivativeY(triple<SrcImageIterator, SrcImageIterator, SrcAc
pair<DestImageIterator, DestAccessor> dest, cessor> src,
double scale) pair<DestImageIterator, DestAccessor> dest,
double scale)
{ {
recursiveSecondDerivativeY(src.first, src.second, src.third, recursiveSecondDerivativeY(src.first, src.second, src.third,
dest. first, dest.second, scale); dest.first, dest.second, scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
recursiveSecondDerivativeY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"recursiveSecondDerivativeY(): shape mismatch between input and out
put.");
recursiveSecondDerivativeY(srcImageRange(src),
destImage(dest), scale);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_RECURSIVECONVOLUTION_HXX #endif // VIGRA_RECURSIVECONVOLUTION_HXX
 End of changes. 96 change blocks. 
105 lines changed or deleted 491 lines changed or added


 regression.hxx   regression.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 2008 by Ullrich Koethe */ /* Copyright 2008-2013 by Ullrich Koethe */
/* */ /* */
/* This file is part of the VIGRA computer vision library. */ /* This file is part of the VIGRA computer vision library. */
/* The VIGRA Website is */ /* The VIGRA Website is */
/* http://hci.iwr.uni-heidelberg.de/vigra/ */ /* http://hci.iwr.uni-heidelberg.de/vigra/ */
/* Please direct questions, bug reports, and contributions to */ /* Please direct questions, bug reports, and contributions to */
/* ullrich.koethe@iwr.uni-heidelberg.de or */ /* ullrich.koethe@iwr.uni-heidelberg.de or */
/* vigra@informatik.uni-hamburg.de */ /* vigra@informatik.uni-hamburg.de */
/* */ /* */
/* Permission is hereby granted, free of charge, to any person */ /* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */ /* obtaining a copy of this software and associated documentation */
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_REGRESSION_HXX #ifndef VIGRA_REGRESSION_HXX
#define VIGRA_REGRESSION_HXX #define VIGRA_REGRESSION_HXX
#include "matrix.hxx" #include "matrix.hxx"
#include "linear_solve.hxx" #include "linear_solve.hxx"
#include "singular_value_decomposition.hxx" #include "singular_value_decomposition.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "autodiff.hxx"
namespace vigra namespace vigra
{ {
namespace linalg namespace linalg
{ {
/** \addtogroup Optimization Optimization and Regression /** \addtogroup Optimization Optimization and Regression
*/ */
//@{ //@{
skipping to change at line 73 skipping to change at line 74
When \a b is a matrix with <tt>k</tt> columns, \a x must also have When \a b is a matrix with <tt>k</tt> columns, \a x must also have
<tt>k</tt> columns, which will contain the solutions for the corresp onding columns of <tt>k</tt> columns, which will contain the solutions for the corresp onding columns of
\a b. Note that all matrices must already have the correct shape. \a b. Note that all matrices must already have the correct shape.
This function is just another name for \ref linearSolve(), perhaps This function is just another name for \ref linearSolve(), perhaps
leading to more readable code when \a A is a rectangular matrix. It returns leading to more readable code when \a A is a rectangular matrix. It returns
<tt>false</tt> when the rank of \a A is less than <tt>n</tt>. <tt>false</tt> when the rank of \a A is less than <tt>n</tt>.
See \ref linearSolve() for more documentation. See \ref linearSolve() for more documentation.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
inline bool inline bool
leastSquares(MultiArrayView<2, T, C1> const & A, leastSquares(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> &x , MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> &x ,
std::string method = "QR") std::string method = "QR")
{ {
return linearSolve(A, b, x, method); return linearSolve(A, b, x, method);
} }
skipping to change at line 115 skipping to change at line 116
where the square root of \a weights is just taken element-wise. where the square root of \a weights is just taken element-wise.
When \a b is a matrix with <tt>k</tt> columns, \a x must also have When \a b is a matrix with <tt>k</tt> columns, \a x must also have
<tt>k</tt> columns, which will contain the solutions for the corresp onding columns of <tt>k</tt> columns, which will contain the solutions for the corresp onding columns of
\a b. Note that all matrices must already have the correct shape. \a b. Note that all matrices must already have the correct shape.
The function returns The function returns
<tt>false</tt> when the rank of the weighted matrix \a A is less tha n <tt>n</tt>. <tt>false</tt> when the rank of the weighted matrix \a A is less tha n <tt>n</tt>.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3, class C4> template <class T, class C1, class C2, class C3, class C4>
bool bool
weightedLeastSquares(MultiArrayView<2, T, C1> const & A, weightedLeastSquares(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> co nst &weights, MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> co nst &weights,
MultiArrayView<2, T, C4> &x, std::string method = "QR") MultiArrayView<2, T, C4> &x, std::string method = "QR")
{ {
typedef T Real;
const unsigned int rows = rowCount(A); const unsigned int rows = rowCount(A);
const unsigned int cols = columnCount(A); const unsigned int cols = columnCount(A);
const unsigned int rhsCount = columnCount(b); const unsigned int rhsCount = columnCount(b);
vigra_precondition(rows >= cols, vigra_precondition(rows >= cols,
"weightedLeastSquares(): Input matrix A must be rectangular with row Count >= columnCount."); "weightedLeastSquares(): Input matrix A must be rectangular with row Count >= columnCount.");
vigra_precondition(rowCount(b) == rows, vigra_precondition(rowCount(b) == rows,
"weightedLeastSquares(): Shape mismatch between matrices A and b."); "weightedLeastSquares(): Shape mismatch between matrices A and b.");
vigra_precondition(rowCount(b) == rowCount(weights) && columnCount(weig hts) == 1, vigra_precondition(rowCount(b) == rowCount(weights) && columnCount(weig hts) == 1,
"weightedLeastSquares(): Weight matrix has wrong shape."); "weightedLeastSquares(): Weight matrix has wrong shape.");
vigra_precondition(rowCount(x) == cols && columnCount(x) == rhsCount, vigra_precondition(rowCount(x) == cols && columnCount(x) == rhsCount,
skipping to change at line 175 skipping to change at line 174
This is implemented by means of \ref singularValueDecomposition(). This is implemented by means of \ref singularValueDecomposition().
When \a b is a matrix with <tt>k</tt> columns, \a x must also have When \a b is a matrix with <tt>k</tt> columns, \a x must also have
<tt>k</tt> columns, which will contain the solutions for the corresp onding columns of <tt>k</tt> columns, which will contain the solutions for the corresp onding columns of
\a b. Note that all matrices must already have the correct shape. \a b. Note that all matrices must already have the correct shape.
The function returns <tt>false</tt> if the rank of \a A is less than <tt>n</tt> The function returns <tt>false</tt> if the rank of \a A is less than <tt>n</tt>
and <tt>lambda == 0.0</tt>. and <tt>lambda == 0.0</tt>.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
bool bool
ridgeRegression(MultiArrayView<2, T, C1> const & A, ridgeRegression(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> &x, double lambda) MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> &x, double lambda)
{ {
typedef T Real;
const unsigned int rows = rowCount(A); const unsigned int rows = rowCount(A);
const unsigned int cols = columnCount(A); const unsigned int cols = columnCount(A);
const unsigned int rhsCount = columnCount(b); const unsigned int rhsCount = columnCount(b);
vigra_precondition(rows >= cols, vigra_precondition(rows >= cols,
"ridgeRegression(): Input matrix A must be rectangular with rowCount >= columnCount."); "ridgeRegression(): Input matrix A must be rectangular with rowCount >= columnCount.");
vigra_precondition(rowCount(b) == rows, vigra_precondition(rowCount(b) == rows,
"ridgeRegression(): Shape mismatch between matrices A and b."); "ridgeRegression(): Shape mismatch between matrices A and b.");
vigra_precondition(rowCount(x) == cols && columnCount(x) == rhsCount, vigra_precondition(rowCount(x) == cols && columnCount(x) == rhsCount,
"ridgeRegression(): Result matrix x has wrong shape."); "ridgeRegression(): Result matrix x has wrong shape.");
vigra_precondition(lambda >= 0.0, vigra_precondition(lambda >= 0.0,
skipping to change at line 248 skipping to change at line 245
where the square root of \a weights is just taken element-wise. Thi s solution is where the square root of \a weights is just taken element-wise. Thi s solution is
computed by means of \ref singularValueDecomposition(). computed by means of \ref singularValueDecomposition().
When \a b is a matrix with <tt>k</tt> columns, \a x must also have When \a b is a matrix with <tt>k</tt> columns, \a x must also have
<tt>k</tt> columns, which will contain the solutions for the corresp onding columns of <tt>k</tt> columns, which will contain the solutions for the corresp onding columns of
\a b. Note that all matrices must already have the correct shape. \a b. Note that all matrices must already have the correct shape.
The function returns <tt>false</tt> if the rank of \a A is less than <tt>n</tt> The function returns <tt>false</tt> if the rank of \a A is less than <tt>n</tt>
and <tt>lambda == 0.0</tt>. and <tt>lambda == 0.0</tt>.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3, class C4> template <class T, class C1, class C2, class C3, class C4>
bool bool
weightedRidgeRegression(MultiArrayView<2, T, C1> const & A, weightedRidgeRegression(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> co nst &weights, MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> co nst &weights,
MultiArrayView<2, T, C4> &x, double lambda) MultiArrayView<2, T, C4> &x, double lambda)
{ {
typedef T Real;
const unsigned int rows = rowCount(A); const unsigned int rows = rowCount(A);
const unsigned int cols = columnCount(A); const unsigned int cols = columnCount(A);
const unsigned int rhsCount = columnCount(b); const unsigned int rhsCount = columnCount(b);
vigra_precondition(rows >= cols, vigra_precondition(rows >= cols,
"weightedRidgeRegression(): Input matrix A must be rectangular with rowCount >= columnCount."); "weightedRidgeRegression(): Input matrix A must be rectangular with rowCount >= columnCount.");
vigra_precondition(rowCount(b) == rows, vigra_precondition(rowCount(b) == rows,
"weightedRidgeRegression(): Shape mismatch between matrices A and b. "); "weightedRidgeRegression(): Shape mismatch between matrices A and b. ");
vigra_precondition(rowCount(b) == rowCount(weights) && columnCount(weig hts) == 1, vigra_precondition(rowCount(b) == rowCount(weights) && columnCount(weig hts) == 1,
"weightedRidgeRegression(): Weight matrix has wrong shape."); "weightedRidgeRegression(): Weight matrix has wrong shape.");
vigra_precondition(rowCount(x) == cols && columnCount(x) == rhsCount, vigra_precondition(rowCount(x) == cols && columnCount(x) == rhsCount,
skipping to change at line 302 skipping to change at line 297
is implemented so that the \ref singularValueDecomposition() has to be executed only once. is implemented so that the \ref singularValueDecomposition() has to be executed only once.
\a lambda must be an array conforming to the <tt>std::vector</tt> in terface, i.e. must \a lambda must be an array conforming to the <tt>std::vector</tt> in terface, i.e. must
support <tt>lambda.size()</tt> and <tt>lambda[k]</tt>. The columns o f the matrix \a x support <tt>lambda.size()</tt> and <tt>lambda[k]</tt>. The columns o f the matrix \a x
will contain the solutions for the corresponding lambda, so the num ber of columns of will contain the solutions for the corresponding lambda, so the num ber of columns of
the matrix \a x must be equal to <tt>lambda.size()</tt>, and \a b mu st be a columns vector, the matrix \a x must be equal to <tt>lambda.size()</tt>, and \a b mu st be a columns vector,
i.e. cannot contain several right hand sides at once. i.e. cannot contain several right hand sides at once.
The function returns <tt>false</tt> when the matrix \a A is rank def icient. If this The function returns <tt>false</tt> when the matrix \a A is rank def icient. If this
happens, and one of the lambdas is zero, the corresponding column of \a x will be skipped. happens, and one of the lambdas is zero, the corresponding column of \a x will be skipped.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3, class Array> template <class T, class C1, class C2, class C3, class Array>
bool bool
ridgeRegressionSeries(MultiArrayView<2, T, C1> const & A, ridgeRegressionSeries(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> &x, A rray const & lambda) MultiArrayView<2, T, C2> const &b, MultiArrayView<2, T, C3> &x, A rray const & lambda)
{ {
typedef T Real;
const unsigned int rows = rowCount(A); const unsigned int rows = rowCount(A);
const unsigned int cols = columnCount(A); const unsigned int cols = columnCount(A);
const unsigned int lambdaCount = lambda.size(); const unsigned int lambdaCount = lambda.size();
vigra_precondition(rows >= cols, vigra_precondition(rows >= cols,
"ridgeRegressionSeries(): Input matrix A must be rectangular with ro wCount >= columnCount."); "ridgeRegressionSeries(): Input matrix A must be rectangular with ro wCount >= columnCount.");
vigra_precondition(rowCount(b) == rows && columnCount(b) == 1, vigra_precondition(rowCount(b) == rows && columnCount(b) == 1,
"ridgeRegressionSeries(): Shape mismatch between matrices A and b.") ; "ridgeRegressionSeries(): Shape mismatch between matrices A and b.") ;
vigra_precondition(rowCount(x) == cols && columnCount(x) == lambdaCount , vigra_precondition(rowCount(x) == cols && columnCount(x) == lambdaCount ,
"ridgeRegressionSeries(): Result matrix x has wrong shape."); "ridgeRegressionSeries(): Result matrix x has wrong shape.");
skipping to change at line 346 skipping to change at line 339
continue; continue;
for(unsigned int k=0; k<cols; ++k) for(unsigned int k=0; k<cols; ++k)
xt(k,0) = xl(k,0) * s(k,0) / (sq(s(k,0)) + lambda[i]); xt(k,0) = xl(k,0) * s(k,0) / (sq(s(k,0)) + lambda[i]);
columnVector(x, i) = v*xt; columnVector(x, i) = v*xt;
} }
return (rank == n); return (rank == n);
} }
/** \brief Pass options to leastAngleRegression(). /** \brief Pass options to leastAngleRegression().
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
class LeastAngleRegressionOptions class LeastAngleRegressionOptions
{ {
public: public:
enum Mode { LARS, LASSO, NNLASSO }; enum Mode { LARS, LASSO, NNLASSO };
/** Initialize all options with default values. /** Initialize all options with default values.
*/ */
LeastAngleRegressionOptions() LeastAngleRegressionOptions()
: max_solution_count(0), : max_solution_count(0),
skipping to change at line 372 skipping to change at line 365
/** Maximum number of solutions to be computed. /** Maximum number of solutions to be computed.
If \a n is 0 (the default), the number of solutions is determin ed by the length If \a n is 0 (the default), the number of solutions is determin ed by the length
of the solution array. Otherwise, the minimum of maxSolutionCou nt() and that of the solution array. Otherwise, the minimum of maxSolutionCou nt() and that
length is taken.<br> length is taken.<br>
Default: 0 (use length of solution array) Default: 0 (use length of solution array)
*/ */
LeastAngleRegressionOptions & maxSolutionCount(unsigned int n) LeastAngleRegressionOptions & maxSolutionCount(unsigned int n)
{ {
max_solution_count = (int)n; max_solution_count = static_cast<int>(n);
return *this; return *this;
} }
/** Set the mode of the algorithm. /** Set the mode of the algorithm.
Mode must be one of "lars", "lasso", "nnlasso". The function ju st calls Mode must be one of "lars", "lasso", "nnlasso". The function ju st calls
the member function of the corresponding name to set the mode. the member function of the corresponding name to set the mode.
Default: "lasso" Default: "lasso"
*/ */
skipping to change at line 521 skipping to change at line 514
if(maxSolutionCount == 0) if(maxSolutionCount == 0)
maxSolutionCount = lasso_modification maxSolutionCount = lasso_modification
? 10*maxRank ? 10*maxRank
: maxRank; : maxRank;
bool needToRemoveColumn = false; bool needToRemoveColumn = false;
MultiArrayIndex columnToBeAdded = 0, columnToBeRemoved = 0; MultiArrayIndex columnToBeAdded = 0, columnToBeRemoved = 0;
MultiArrayIndex currentSolutionCount = 0; MultiArrayIndex currentSolutionCount = 0;
while(currentSolutionCount < maxSolutionCount) while(currentSolutionCount < maxSolutionCount)
{ {
//ColumnSet activeSet = d.columnPermutation.subarray(0, (unsigned i //ColumnSet activeSet = d.columnPermutation.subarray(0, static_cast
nt)d.activeSetSize); <unsigned int>(d.activeSetSize));
ColumnSet inactiveSet = d.columnPermutation.subarray((unsigned int) ColumnSet inactiveSet = d.columnPermutation.subarray(static_cast<un
d.activeSetSize, (unsigned int)cols); signed int>(d.activeSetSize), static_cast<unsigned int>(cols));
// find next dimension to be activated // find next dimension to be activated
Matrix<T> cLARS = transpose(d.A) * (d.b - d.lars_prediction), // correlation with LARS residual Matrix<T> cLARS = transpose(d.A) * (d.b - d.lars_prediction), // correlation with LARS residual
cLSQ = transpose(d.A) * (d.b - d.next_lsq_prediction); // correlation with LSQ residual cLSQ = transpose(d.A) * (d.b - d.next_lsq_prediction); // correlation with LSQ residual
// In theory, all vectors in the active set should have the same co rrelation C, and // In theory, all vectors in the active set should have the same co rrelation C, and
// the correlation of all others should not exceed this. In practic e, we may find the // the correlation of all others should not exceed this. In practic e, we may find the
// maximum correlation in any variable due to tiny numerical inaccu racies. Therefore, we // maximum correlation in any variable due to tiny numerical inaccu racies. Therefore, we
// determine C from the entire set of variables. // determine C from the entire set of variables.
MultiArrayIndex cmaxIndex = enforce_positive MultiArrayIndex cmaxIndex = enforce_positive
skipping to change at line 611 skipping to change at line 604
activeSets.push_back(typename Array1::value_type(d.columnPermutatio n.begin(), d.columnPermutation.begin()+d.activeSetSize)); activeSets.push_back(typename Array1::value_type(d.columnPermutatio n.begin(), d.columnPermutation.begin()+d.activeSetSize));
if(lsq_solutions != 0) if(lsq_solutions != 0)
{ {
if(enforce_positive) if(enforce_positive)
{ {
ArrayVector<Matrix<T> > nnresults; ArrayVector<Matrix<T> > nnresults;
ArrayVector<ArrayVector<MultiArrayIndex> > nnactiveSets; ArrayVector<ArrayVector<MultiArrayIndex> > nnactiveSets;
LarsData<T, C1, C2> nnd(d, d.activeSetSize); LarsData<T, C1, C2> nnd(d, d.activeSetSize);
leastAngleRegressionMainLoop(nnd, nnactiveSets, &nnresults, (Array3*)0, leastAngleRegressionMainLoop(nnd, nnactiveSets, &nnresults, static_cast<Array3*>(0),
LeastAngleRegressionOptions(). leastSquaresSolutions(false).nnlasso()); LeastAngleRegressionOptions(). leastSquaresSolutions(false).nnlasso());
//Matrix<T> nnlsq_solution(d.activeSetSize, 1); //Matrix<T> nnlsq_solution(d.activeSetSize, 1);
typename Array2::value_type nnlsq_solution(Shape(d.activeSe tSize, 1)); typename Array2::value_type nnlsq_solution(Shape(d.activeSe tSize, 1));
for(unsigned int k=0; k<nnactiveSets.back().size(); ++k) for(unsigned int k=0; k<nnactiveSets.back().size(); ++k)
{ {
nnlsq_solution(nnactiveSets.back()[k],0) = nnresults.ba ck()[k]; nnlsq_solution(nnactiveSets.back()[k],0) = nnresults.ba ck()[k];
} }
//lsq_solutions->push_back(nnlsq_solution); //lsq_solutions->push_back(nnlsq_solution);
lsq_solutions->push_back(typename Array3::value_type()); lsq_solutions->push_back(typename Array3::value_type());
lsq_solutions->back() = nnlsq_solution; lsq_solutions->back() = nnlsq_solution;
skipping to change at line 691 skipping to change at line 684
Subarray qtbactive = d.qtb.subarray(Shape(0,0), Shape(d.activeSetSi ze, 1)); Subarray qtbactive = d.qtb.subarray(Shape(0,0), Shape(d.activeSetSi ze, 1));
Subarray next_lsq_solution_view = d.next_lsq_solution.subarray(Shap e(0,0), Shape(d.activeSetSize, 1)); Subarray next_lsq_solution_view = d.next_lsq_solution.subarray(Shap e(0,0), Shape(d.activeSetSize, 1));
linearSolveUpperTriangular(Ractive, qtbactive, next_lsq_solution_vi ew); linearSolveUpperTriangular(Ractive, qtbactive, next_lsq_solution_vi ew);
// compute the LSQ prediction of the new active set // compute the LSQ prediction of the new active set
d.next_lsq_prediction.init(0.0); d.next_lsq_prediction.init(0.0);
for(MultiArrayIndex k=0; k<d.activeSetSize; ++k) for(MultiArrayIndex k=0; k<d.activeSetSize; ++k)
d.next_lsq_prediction += next_lsq_solution_view(k,0)*columnVect or(d.A, d.columnPermutation[k]); d.next_lsq_prediction += next_lsq_solution_view(k,0)*columnVect or(d.A, d.columnPermutation[k]);
} }
return (unsigned int)currentSolutionCount; return static_cast<unsigned int>(currentSolutionCount);
} }
template <class T, class C1, class C2, class Array1, class Array2> template <class T, class C1, class C2, class Array1, class Array2>
unsigned int unsigned int
leastAngleRegressionImpl(MultiArrayView<2, T, C1> const & A, MultiArrayView <2, T, C2> const &b, leastAngleRegressionImpl(MultiArrayView<2, T, C1> const & A, MultiArrayView <2, T, C2> const &b,
Array1 & activeSets, Array2 * lasso_solutions, Arr ay2 * lsq_solutions, Array1 & activeSets, Array2 * lasso_solutions, Arr ay2 * lsq_solutions,
LeastAngleRegressionOptions const & options) LeastAngleRegressionOptions const & options)
{ {
using namespace vigra::functor; using namespace vigra::functor;
skipping to change at line 732 skipping to change at line 725
detail::qrColumnHouseholderStep(0, d.R, d.qtb); detail::qrColumnHouseholderStep(0, d.R, d.qtb);
d.next_lsq_solution(0,0) = d.qtb(0,0) / d.R(0,0); d.next_lsq_solution(0,0) = d.qtb(0,0) / d.R(0,0);
d.next_lsq_prediction = d.next_lsq_solution(0,0) * columnVector(A, d.co lumnPermutation[0]); d.next_lsq_prediction = d.next_lsq_solution(0,0) * columnVector(A, d.co lumnPermutation[0]);
d.searchVector = d.next_lsq_solution(0,0) * columnVector(A, d.columnPer mutation[0]); d.searchVector = d.next_lsq_solution(0,0) * columnVector(A, d.columnPer mutation[0]);
return leastAngleRegressionMainLoop(d, activeSets, lasso_solutions, lsq _solutions, options); return leastAngleRegressionMainLoop(d, activeSets, lasso_solutions, lsq _solutions, options);
} }
} // namespace detail } // namespace detail
/** Least Angle Regression. /** Least Angle Regression.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
<b> Declarations:</b> <b> Declarations:</b>
\code \code
namespace vigra { namespace vigra {
namespace linalg { namespace linalg {
// compute either LASSO or least squares solutions // compute either LASSO or least squares solutions
template <class T, class C1, class C2, class Array1, class Array2> template <class T, class C1, class C2, class Array1, class Arra
unsigned int y2>
leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray unsigned int
View<2, T, C2> const &b, leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiA
Array1 & activeSets, Array2 & solutions, rrayView<2, T, C2> const &b,
LeastAngleRegressionOptions const & options = Array1 & activeSets, Array2 & solutions,
LeastAngleRegressionOptions()); LeastAngleRegressionOptions const & options = LeastAng
leRegressionOptions());
// compute LASSO and least squares solutions
template <class T, class C1, class C2, class Array1, class Array2> // compute LASSO and least squares solutions
unsigned int template <class T, class C1, class C2, class Array1, class Arra
leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray y2>
View<2, T, C2> const &b, unsigned int
Array1 & activeSets, Array2 & lasso_solutions, leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiA
Array2 & lsq_solutions, rrayView<2, T, C2> const &b,
LeastAngleRegressionOptions const & options = Array1 & activeSets, Array2 & lasso_solutions, Array2
LeastAngleRegressionOptions()); & lsq_solutions,
} LeastAngleRegressionOptions const & options = LeastAng
using linalg::leastAngleRegression; leRegressionOptions());
} }
\endcode using linalg::leastAngleRegression;
}
\endcode
This function implements Least Angle Regression (LARS) as described in This function implements Least Angle Regression (LARS) as described in
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
B.Efron, T.Hastie, I.Johnstone, and R.Tibshirani: <i>"Least Angle Re gression"</i>, B.Efron, T.Hastie, I.Johnstone, and R.Tibshirani: <i>"Least Angle Re gression"</i>,
Annals of Statistics 32(2):407-499, 2004. Annals of Statistics 32(2):407-499, 2004.
It is an efficient algorithm to solve the L1-regularized least squar es (LASSO) problem It is an efficient algorithm to solve the L1-regularized least squar es (LASSO) problem
\f[ \tilde \textrm{\bf x} = \textrm{argmin} \f[ \tilde \textrm{\bf x} = \textrm{argmin}
skipping to change at line 781 skipping to change at line 774
\f] \f]
and the L1-regularized non-negative least squares (NN-LASSO) problem and the L1-regularized non-negative least squares (NN-LASSO) problem
\f[ \tilde \textrm{\bf x} = \textrm{argmin} \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right|\right|_2^2 \f[ \tilde \textrm{\bf x} = \textrm{argmin} \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right|\right|_2^2
\textrm{ subject to } \left|\left|\textrm{\bf x}\right|\right|_1 \le s \textrm{ and } \textrm{\bf x}\ge \textrm{\bf 0} \textrm{ subject to } \left|\left|\textrm{\bf x}\right|\right|_1 \le s \textrm{ and } \textrm{\bf x}\ge \textrm{\bf 0}
\f] \f]
where \a A is a matrix with <tt>m</tt> rows and <tt>n</tt> columns ( often with <tt>m \< n</tt>), where \a A is a matrix with <tt>m</tt> rows and <tt>n</tt> columns ( often with <tt>m \< n</tt>),
\a b a vector of length <tt>m</tt>, and a regularization parameter s \>= 0.0. \a b a vector of length <tt>m</tt>, and a regularization parameter s \>= 0.0.
L1-regularization has the desirable effect that it causes the soluti L1-regularization has the desirable effect that it causes the soluti
on \a x to be sparse, i.e. only on <b>x</b> to be sparse, i.e. only
the most important variables (called the <em>active set</em>) have n the most important elements in <b>x</b> (called the <em>active set</
on-zero values. The em>) have non-zero values. The
key insight of the LARS algorithm is the following: When the solutio key insight of the LARS algorithm is the following: When the solutio
n vector is considered n vector <b>x</b> is considered
as a function of the regularization parameter s, then <b>x</b>(s) is a piecewise as a function of the regularization parameter s, then <b>x</b>(s) is a piecewise
linear function, i.e. a polyline in n-dimensional space. The knots o linear function, i.e. a polyline in n-dimensional space. The knots o
f the polyline f the polyline <b>x</b>(s)
occur precisely at those values of s where one variable enters or le are located precisely at those values of s where one variable enters
aves the active set, or leaves the active set
and can be efficiently computed. and can be efficiently computed.
Therefore, leastAngleRegression() returns the entire solution path a s a sequence of knot points, starting Therefore, leastAngleRegression() returns the entire solution path a s a sequence of knot points, starting
at \f$\textrm{\bf x}(s=0)\f$ (where the only feasible solution is ob viously <b>x</b> = 0) and ending at at \f$\textrm{\bf x}(s=0)\f$ (where the only feasible solution is ob viously <b>x</b> = 0) and ending at
\f$\textrm{\bf x}(s=\infty)\f$ (where the solution becomes the ordin ary least squares solution). Actually, \f$\textrm{\bf x}(s=\infty)\f$ (where the solution becomes the ordin ary least squares solution). Actually,
the initial null solution is not explicitly returned, i.e. the seque nce starts at the first non-zero the initial null solution is not explicitly returned, i.e. the seque nce starts at the first non-zero
solution with one variable in the active set. The function leastAngl eRegression() returns the number solution with one variable in the active set. The function leastAngl eRegression() returns the number
of solutions( i.e. knot points) computed. of solutions (i.e. knot points) computed.
The sequences of active sets and corresponding variable weights are returned in \a activeSets and The sequences of active sets and corresponding variable weights are returned in \a activeSets and
\a solutions respectively. That is, <tt>activeSets[i]</tt> is an \re f vigra::ArrayVector "ArrayVector\<int\>" \a solutions respectively. That is, <tt>activeSets[i]</tt> is an \re f vigra::ArrayVector "ArrayVector\<int\>"
containing the indices of the variables that are active at the i-th knot, and <tt>solutions</tt> is a containing the indices of the variables that are active at the i-th knot, and <tt>solutions</tt> is a
\ref vigra::linalg::Matrix "Matrix\<T\>" containing the weights of t hose variables, in the same order (see \ref vigra::linalg::Matrix "Matrix\<T\>" containing the weights of t hose variables, in the same order (see
example below). Variables not contained in <tt>activeSets[i]</tt> ar e zero at this solution. example below). Variables not contained in <tt>activeSets[i]</tt> ar e zero at this solution.
The behavior of the algorithm can be adapted by \ref vigra::linalg:: LeastAngleRegressionOptions The behavior of the algorithm can be adapted by \ref vigra::linalg:: LeastAngleRegressionOptions
"LeastAngleRegressionOptions": "LeastAngleRegressionOptions":
<DL> <DL>
skipping to change at line 884 skipping to change at line 877
*/ */
doxygen_overloaded_function(template <...> unsigned int leastAngleRegressio n) doxygen_overloaded_function(template <...> unsigned int leastAngleRegressio n)
template <class T, class C1, class C2, class Array1, class Array2> template <class T, class C1, class C2, class Array1, class Array2>
inline unsigned int inline unsigned int
leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> const &b, leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> const &b,
Array1 & activeSets, Array2 & solutions, Array1 & activeSets, Array2 & solutions,
LeastAngleRegressionOptions const & options = LeastAng leRegressionOptions()) LeastAngleRegressionOptions const & options = LeastAng leRegressionOptions())
{ {
if(options.least_squares_solutions) if(options.least_squares_solutions)
return detail::leastAngleRegressionImpl(A, b, activeSets, (Array2*) 0, &solutions, options); return detail::leastAngleRegressionImpl(A, b, activeSets, static_ca st<Array2*>(0), &solutions, options);
else else
return detail::leastAngleRegressionImpl(A, b, activeSets, &solution s, (Array2*)0, options); return detail::leastAngleRegressionImpl(A, b, activeSets, &solution s, static_cast<Array2*>(0), options);
} }
template <class T, class C1, class C2, class Array1, class Array2> template <class T, class C1, class C2, class Array1, class Array2>
inline unsigned int inline unsigned int
leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> const &b, leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> const &b,
Array1 & activeSets, Array2 & lasso_solutions, Array2 & lsq_solutions, Array1 & activeSets, Array2 & lasso_solutions, Array2 & lsq_solutions,
LeastAngleRegressionOptions const & options = LeastAng leRegressionOptions()) LeastAngleRegressionOptions const & options = LeastAng leRegressionOptions())
{ {
return detail::leastAngleRegressionImpl(A, b, activeSets, &lasso_soluti ons, &lsq_solutions, options); return detail::leastAngleRegressionImpl(A, b, activeSets, &lasso_soluti ons, &lsq_solutions, options);
} }
/** Non-negative Least Squares Regression. /** Non-negative Least Squares Regression.
Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wi
h <tt>m \>= n</tt>), th <tt>m \>= n</tt>),
and a column vector \a b of length <tt>m</tt> rows, this function co and a column vector \a b of length <tt>m</tt> rows, this function c
mputes omputes
a column vector \a x of length <tt>n</tt> with <b>non-negative entri a column vector \a x of length <tt>n</tt> with <b>non-negative entr
es</b> that solves the optimization problem ies</b> that solves the optimization problem
\f[ \tilde \textrm{\bf x} = \textrm{argmin} \f[ \tilde \textrm{\bf x} = \textrm{argmin}
\left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\righ \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\rig
t|\right|_2^2 ht|\right|_2^2
\textrm{ subject to } \textrm{\bf x} \ge \textrm{\bf 0} \textrm{ subject to } \textrm{\bf x} \ge \textrm{\bf 0}
\f] \f]
Both \a b and \a x must be column vectors (i.e. matrices with <tt>1< Both \a b and \a x must be column vectors (i.e. matrices with <tt>1
/tt> column). </tt> column).
Note that all matrices must already have the correct shape. The solu Note that all matrices must already have the correct shape. The sol
tion is computed by means ution is computed by means
of \ref leastAngleRegression() with non-negativity constraint. of \ref leastAngleRegression() with non-negativity constraint.
<b>\#include</b> \<vigra/regression.hxx\> <b>\#include</b> \<vigra/regression.hxx\><br/>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/
<b> Declarations:</b>
\code
namespace vigra {
namespace linalg {
template <class T, class C1, class C2, class C3>
void
nonnegativeLeastSquares(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b,
MultiArrayView<2, T, C3> &x);
}
using linalg::nonnegativeLeastSquares;
}
\endcode
*/
doxygen_overloaded_function(template <...> unsigned int nonnegativeLeastSqu
ares)
template <class T, class C1, class C2, class C3> template <class T, class C1, class C2, class C3>
inline void inline void
nonnegativeLeastSquares(MultiArrayView<2, T, C1> const & A, nonnegativeLeastSquares(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> const &b, MultiArrayView<2 , T, C3> &x) MultiArrayView<2, T, C2> const &b, MultiArrayView<2 , T, C3> &x)
{ {
vigra_precondition(columnCount(A) == rowCount(x) && rowCount(A) == rowC ount(b), vigra_precondition(columnCount(A) == rowCount(x) && rowCount(A) == rowC ount(b),
"nonnegativeLeastSquares(): Matrix shape mismatch."); "nonnegativeLeastSquares(): Matrix shape mismatch.");
vigra_precondition(columnCount(b) == 1 && columnCount(x) == 1, vigra_precondition(columnCount(b) == 1 && columnCount(x) == 1,
"nonnegativeLeastSquares(): RHS and solution must be vectors (i.e. columnCount == 1)."); "nonnegativeLeastSquares(): RHS and solution must be vectors (i.e. columnCount == 1).");
skipping to change at line 950 skipping to change at line 960
using linalg::leastSquares; using linalg::leastSquares;
using linalg::weightedLeastSquares; using linalg::weightedLeastSquares;
using linalg::ridgeRegression; using linalg::ridgeRegression;
using linalg::weightedRidgeRegression; using linalg::weightedRidgeRegression;
using linalg::ridgeRegressionSeries; using linalg::ridgeRegressionSeries;
using linalg::nonnegativeLeastSquares; using linalg::nonnegativeLeastSquares;
using linalg::leastAngleRegression; using linalg::leastAngleRegression;
using linalg::LeastAngleRegressionOptions; using linalg::LeastAngleRegressionOptions;
namespace detail {
template <class T, class S>
inline T
getRow(MultiArrayView<1, T, S> const & a, MultiArrayIndex i)
{
return a(i);
}
template <class T, class S>
inline MultiArrayView<1, T>
getRow(MultiArrayView<2, T, S> const & a, MultiArrayIndex i)
{
return a.bindInner(i);
}
} // namespace detail
/** \addtogroup Optimization
*/
//@{
/** \brief Pass options to nonlinearLeastSquares().
<b>\#include</b> \<vigra/regression.hxx\>
Namespace: vigra
*/
class NonlinearLSQOptions
{
public:
double epsilon, lambda, tau;
int max_iter;
/** \brief Initialize options with default values.
*/
NonlinearLSQOptions()
: epsilon(0.0),
lambda(0.1),
tau(1.4),
max_iter(50)
{}
/** \brief Set minimum relative improvement in residual.
The algorithm stops when the relative improvement in residuals
between consecutive iterations is less than this value.
Default: 0 (i.e. choose tolerance automatically, will be 10*eps
ilon of the numeric type)
*/
NonlinearLSQOptions & tolerance(double eps)
{
epsilon = eps;
return *this;
}
/** \brief Set maximum number of iterations.
Default: 50
*/
NonlinearLSQOptions & maxIterations(int iter)
{
max_iter = iter;
return *this;
}
/** \brief Set damping parameters for Levenberg-Marquardt algorithm
.
\a lambda determines by how much the diagonal is emphasized, an
d \a v is
the factor by which lambda will be increased if more damping is
needed
for convergence
(see <a href="http://en.wikipedia.org/wiki/Levenberg%E2%80%93Ma
rquardt_algorithm">Wikipedia</a>
for more explanations).
Default: lambda = 0.1, v = 1.4
*/
NonlinearLSQOptions & dampingParamters(double lambda, double v)
{
vigra_precondition(lambda > 0.0 && v > 0.0,
"NonlinearLSQOptions::dampingParamters(): parameters must be po
sitive.");
this->lambda = lambda;
tau = v;
return *this;
}
};
template <unsigned int D, class T, class S1, class S2,
class U, int N,
class Functor>
T
nonlinearLeastSquaresImpl(MultiArrayView<D, T, S1> const & features,
MultiArrayView<1, T, S2> const & response,
TinyVector<U, N> & p,
Functor model,
NonlinearLSQOptions const & options)
{
vigra_precondition(features.shape(0) == response.shape(0),
"nonlinearLeastSquares(): shape mismatch between fea
tures and response.");
double t = options.tau, l = options.lambda; // initial damping paramet
ers
double epsilonT = NumericTraits<T>::epsilon()*10.0,
epsilonU = NumericTraits<U>::epsilon()*10.0,
epsilon = options.epsilon <= 0.0
? std::max(epsilonT, epsilonU)
: options.epsilon;
linalg::Matrix<T> jj(N,N); // outer product of the Jacobian
TinyVector<U, N> jr, dp;
T residual = 0.0;
bool didStep = true;
for(int iter=0; iter<options.max_iter; ++iter)
{
if(didStep)
{
// update the residual and Jacobian
residual = 0.0;
jr = 0.0;
jj = 0.0;
for(int i=0; i<features.shape(0); ++i)
{
autodiff::DualVector<U, N> res = model(detail::getRow(featu
res, i), autodiff::dualMatrix(p));
T r = response(i) - res.v;
jr += r * res.d;
jj += outer(res.d);
residual += sq(r);
}
}
// perform a damped gradient step
linalg::Matrix<T> djj(jj);
djj.diagonal() *= 1.0 + l;
linearSolve(djj, jr, dp);
TinyVector<U, N> p_new = p + dp;
// compute the new residual
T residual_new = 0.0;
for(int i=0; i<features.shape(0); ++i)
{
residual_new += sq(response(i) - model(detail::getRow(features,
i), p_new));
}
if(residual_new < residual)
{
// accept the step
p = p_new;
if(std::abs((residual - residual_new) / residual) < epsilon)
return residual_new;
// try less damping in the next iteration
l /= t;
didStep = true;
}
else
{
// reject the step und use more damping in the next iteration
l *= t;
didStep = false;
}
}
return residual;
}
/********************************************************/
/* */
/* nonlinearLeastSquares */
/* */
/********************************************************/
/** \brief Fit a non-linear model to given data by minimizing least squares
loss.
<b> Declarations:</b>
\code
namespace vigra {
// variant 1: optimize a univariate model ('x' is a 1D array of sca
lar data points)
template <class T, class S1, class S2,
class U, int N,
class Functor>
T
nonlinearLeastSquares(MultiArrayView<1, T, S1> const & x,
MultiArrayView<1, T, S2> const & y,
TinyVector<U, N> & model_parameters,
Functor model,
NonlinearLSQOptions const & options = Nonline
arLSQOptions());
// variant 2: optimize a multivariate model ('x' is a 2D array of v
ector-valued data points)
template <class T, class S1, class S2,
class U, int N,
class Functor>
T
nonlinearLeastSquares(MultiArrayView<2, T, S1> const & x,
MultiArrayView<1, T, S2> const & y,
TinyVector<U, N> & model_parameters,
Functor model,
NonlinearLSQOptions const & options = Nonline
arLSQOptions());
}
\endcode
This function implements the
<a href="http://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algor
ithm">Levenberg-Marquardt algorithm</a>
to fit a non-linear model to given data. The model depends on a vector
of
parameters <b>p</b> which are to be choosen such that the least-squares
residual
between the data and the model's predictions is minimized according to
the objective function:
\f[ \tilde \textrm{\bf p} = \textrm{argmin}_{\textrm{\bf p}} \sum_i \le
ft( y_i - f(\textrm{\bf x}_i; \textrm{\bf p}) \right)^2
\f]
where \f$f(\textrm{\bf x}; \textrm{\bf p})\f$ is the model to be optimi
zed
(with arguments \f$\textrm{\bf x}\f$ and parameters \f$\textrm{\bf p}\f
$), and
\f$(\textrm{\bf x}_i; y_i)\f$ are the feature/response pairs of the giv
en data.
Since the model is non-linear (otherwise, you should use ordinary \ref
leastSquares()),
it must be linearized in terms of a first-order Taylor expansion, and t
he optimal
parameters <b>p</b> have to be determined iteratively. In order for the
iterations to
converge to the desired solution, a good initial guess on <b>p</b> is r
equired.
The model must be specified by a functor which takes one of the followi
ng forms:
\code
typedef double DataType; // type of your data samples, may be any num
eric type
static const int N = ...; // number of model parameters
// variant 1: the features x are scalars
struct UnivariateModel
{
template <class T>
T operator()(DataType x, TinyVector<T, N> const & p) const { ... }
};
// variant 2: the features x are vectors
struct MultivariateModel
{
template <class T>
T operator()(MultiArrayView<1, DataType> const & x, TinyVector<T, N
> const & p) const { ... }
};
\endcode
Each call to the functor's <tt>operator()</tt> computes the model's pre
diction for a single data
point. The current model parameters are specified in a TinyVector of ap
propriate length.
The type <tt>T</tt> must be templated: normally, it is the same as <tt>
DataType</tt>, but
the nonlinearLeastSquares() function will temporarily replace it with a
special number type
that supports <a href="http://en.wikipedia.org/wiki/Automatic_different
iation">automatic differentiation</a>
(see \ref vigra::autodiff::DualVector). In this way, the derivatives ne
eded in the model's Taylor
expansion can be computed automatically.
When the model is univariate (has a single scalar argument), the sample
s must be passed to
nonlinearLeastSquares() in a pair 'x', 'y' of 1D <tt>MultiArrayView</tt
>s (variant 1).
When the model is multivariate (has a vector-valued argument), the 'x'
input must
be a 2D <tt>MultiArrayView</tt> (variant 2) whose rows represent a sing
le data sample
(i.e. the number of columns corresponds to the length of the model's ar
gument vector).
The number of rows in 'x' defines the number of data samples and must m
atch the length
of array 'y'.
The <tt>TinyVector</tt> 'model_parameters' holds the initial guess for
the model parameters and
will be overwritten by the optimal values found by the algorithm. The a
lgorithm's internal behavior
can be controlled by customizing the option object \ref vigra::Nonlinea
rLSQOptions.
The function returns the residual sum of squared errors of the final so
lution.
<b> Usage:</b>
<b>\#include</b> \<vigra/regression.hxx\><br>
Namespace: vigra
Suppose that we want to fit a centered Gaussian function of the form
\f[ f(x ; a, s, b) = a \exp\left(-\frac{x^2}{2 s^2}\right) + b \f]
to noisy data \f$(x_i, y_i)\f$, i.e. we want to find parameters a, s, b
such that
the residual \f$\sum_i \left(y_i - f(x_i; a,s,b)\right)^2\f$ is minimiz
ed.
The model parameters are placed in a <tt>TinyVector<T, 3></tt> <b>p</b>
according to the rules<br/>
<tt>p[0] <=> a</tt>, <tt>p[1] <=> s</tt> and <tt>p[2] <=> b</tt>.<br/>
The following
functor computes the model's prediction for a single data point <tt>x</
tt>:
\code
struct GaussianModel
{
template <class T>
T operator()(double x, TinyVector<T, 3> const & p) const
{
return p[0] * exp(-0.5 * sq(x / p[1])) + p[2];
}
};
\endcode
Now we can find optimal values for the parameters like this:
\code
int size = ...; // number of data points
MultiArray<1, double> x(size), y(size);
... // fill the data arrays
TinyVector<double, 3> p(2.0, 1.0, 0.5); // your initial guess of the p
arameters
// (will be overwritten with t
he optimal values)
double residual = nonlinearLeastSquares(x, y, p, GaussianModel());
std::cout << "Model parameters: a=" << p[0] << ", s=" << p[1] << ", b="
<< p[2] << " (residual: " << residual << ")\n";
\endcode
*/
doxygen_overloaded_function(template <...> void nonlinearLeastSquares)
template <class T, class S1, class S2,
class U, int N,
class Functor>
inline T
nonlinearLeastSquares(MultiArrayView<1, T, S1> const & features,
MultiArrayView<1, T, S2> const & response,
TinyVector<U, N> & p,
Functor model,
NonlinearLSQOptions const & options = NonlinearLSQOpt
ions())
{
return nonlinearLeastSquaresImpl(features, response, p, model, options)
;
}
template <class T, class S1, class S2,
class U, int N,
class Functor>
inline T
nonlinearLeastSquares(MultiArrayView<2, T, S1> const & features,
MultiArrayView<1, T, S2> const & response,
TinyVector<U, N> & p,
Functor model,
NonlinearLSQOptions const & options = NonlinearLSQOpt
ions())
{
return nonlinearLeastSquaresImpl(features, response, p, model, options)
;
}
//@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_REGRESSION_HXX #endif // VIGRA_REGRESSION_HXX
 End of changes. 32 change blocks. 
89 lines changed or deleted 487 lines changed or added


 resampling_convolution.hxx   resampling_convolution.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_RESAMPLING_CONVOLUTION_HXX #define VIGRA_RESAMPLING_CONVOLUTION_HXX
#include <cmath> #include <cmath>
#include "stdimage.hxx" #include "stdimage.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "rational.hxx" #include "rational.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "transformimage.hxx" #include "transformimage.hxx"
#include "imagecontainer.hxx" #include "imagecontainer.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
namespace resampling_detail namespace resampling_detail
{ {
struct MapTargetToSourceCoordinate struct MapTargetToSourceCoordinate
{ {
MapTargetToSourceCoordinate(Rational<int> const & samplingRatio, MapTargetToSourceCoordinate(Rational<int> const & samplingRatio,
Rational<int> const & offset) Rational<int> const & offset)
skipping to change at line 250 skipping to change at line 251
/********************************************************/ /********************************************************/
/** \brief Performs a 1-dimensional resampling convolution of the source si gnal using the given /** \brief Performs a 1-dimensional resampling convolution of the source si gnal using the given
set of kernels. set of kernels.
This function is mainly used internally: It is called for each dimensio n of a This function is mainly used internally: It is called for each dimensio n of a
higher dimensional array in order to perform a separable resize operati on. higher dimensional array in order to perform a separable resize operati on.
<b> Declaration:</b> <b> Declaration:</b>
<b>\#include</b> \<vigra/resampling_convolution.hxx\> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br/>
Namespace: vigra
\code \code
namespace vigra { namespace vigra {
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class KernelArray, class KernelArray,
class Functor> class Functor>
void void
resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src, resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src,
DestIter d, DestIter dend, DestAcc dest, DestIter d, DestIter dend, DestAcc dest,
skipping to change at line 357 skipping to change at line 359
void void
createResamplingKernels(Kernel const & kernel, createResamplingKernels(Kernel const & kernel,
MapCoordinate const & mapCoordinate, KernelArray & kernels) MapCoordinate const & mapCoordinate, KernelArray & kernels)
{ {
for(unsigned int idest = 0; idest < kernels.size(); ++idest) for(unsigned int idest = 0; idest < kernels.size(); ++idest)
{ {
int isrc = mapCoordinate(idest); int isrc = mapCoordinate(idest);
double idsrc = mapCoordinate.toDouble(idest); double idsrc = mapCoordinate.toDouble(idest);
double offset = idsrc - isrc; double offset = idsrc - isrc;
double radius = kernel.radius(); double radius = kernel.radius();
int left = int(ceil(-radius - offset)); int left = std::min(0, int(ceil(-radius - offset)));
int right = int(floor(radius - offset)); int right = std::max(0, int(floor(radius - offset)));
kernels[idest].initExplicitly(left, right); kernels[idest].initExplicitly(left, right);
double x = left + offset; double x = left + offset;
for(int i = left; i <= right; ++i, ++x) for(int i = left; i <= right; ++i, ++x)
kernels[idest][i] = kernel(x); kernels[idest][i] = kernel(x);
kernels[idest].normalize(1.0, kernel.derivativeOrder(), offset); kernels[idest].normalize(1.0, kernel.derivativeOrder(), offset);
} }
} }
/** \brief Apply a resampling filter in the x-direction. /** \brief Apply a resampling filter in the x-direction.
skipping to change at line 389 skipping to change at line 391
The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vi gra::Rational The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vi gra::Rational
in order to avoid rounding errors in this transformation. It is require d that for all in order to avoid rounding errors in this transformation. It is require d that for all
pixels of the target image, <tt>xsource</tt> remains within the range o f the source pixels of the target image, <tt>xsource</tt> remains within the range o f the source
image (i.e. <tt>0 <= xsource <= sourceWidth-1</tt>. Since <tt>xsource</ tt> is image (i.e. <tt>0 <= xsource <= sourceWidth-1</tt>. Since <tt>xsource</ tt> is
in general not an integer, the <tt>kernel</tt> must be a functor that c an be accessed at in general not an integer, the <tt>kernel</tt> must be a functor that c an be accessed at
arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt> arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt>
which specifies the support (non-zero interval) of the kernel. VIGRA al ready which specifies the support (non-zero interval) of the kernel. VIGRA al ready
provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline
\ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The funct ion \ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The funct ion
\ref resizeImageSplineInterpolation() is implemented by means resamplin gConvolveX() and \ref resizeImageSplineInterpolation() is implemented by means of resamp lingConvolveX() and
resamplingConvolveY(). resamplingConvolveY().
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Kernel>
void
resamplingConvolveX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<i
nt> const & offset);
}
\endcode
\deprecatedAPI{resamplingConvolveX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class Kernel> class Kernel>
void void
resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src, resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src,
DestIter dul, DestIter dlr, DestAcc dest, DestIter dul, DestIter dlr, DestAcc dest,
Kernel const & kernel, Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<i nt> const & offset); Rational<int> const & samplingRatio, Rational<i nt> const & offset);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class Kernel> class Kernel>
void void
resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src, resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src,
triple<DestIter, DestIter, DestAcc> dest, triple<DestIter, DestIter, DestAcc> dest,
Kernel const & kernel, Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<i nt> const & offset); Rational<int> const & samplingRatio, Rational<i nt> const & offset);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/resampling_convolution.hxx\> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br/>
Namespace: vigra
\code \code
Rational<int> ratio(2), offset(0); Rational<int> ratio(2), offset(0);
MultiArray<2, float> src(w,h),
dest(rational_cast<int>(ratio*w), h);
float sigma = 2.0;
Gaussian<float> smooth(sigma);
...
// simultaneously enlarge and smooth source image
resamplingConvolveX(src, dest,
smooth, ratio, offset);
\endcode
\deprecatedUsage{resamplingConvolveX}
\code
Rational<int> ratio(2), offset(0);
FImage src(w,h), FImage src(w,h),
dest(rational_cast<int>(ratio*w), h); dest(rational_cast<int>(ratio*w), h);
float sigma = 2.0; float sigma = 2.0;
Gaussian<float> smooth(sigma); Gaussian<float> smooth(sigma);
... ...
// simultaneously enlarge and smooth source image // simultaneously enlarge and smooth source image
resamplingConvolveX(srcImageRange(src), destImageRange(dest), resamplingConvolveX(srcImageRange(src), destImageRange(dest),
smooth, ratio, offset); smooth, ratio, offset);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
Kernel kernel; Kernel kernel;
int kernelRadius = kernel.radius(); int kernelRadius = kernel.radius();
double x = ...; // must be <= radius() double x = ...; // must be <= radius()
double value = kernel(x); double value = kernel(x);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void resamplingConvolveX) doxygen_overloaded_function(template <...> void resamplingConvolveX)
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class Kernel> class Kernel>
void void
resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src, resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src,
DestIter dul, DestIter dlr, DestAcc dest, DestIter dul, DestIter dlr, DestAcc dest,
Kernel const & kernel, Kernel const & kernel,
skipping to change at line 499 skipping to change at line 532
resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src, resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src,
triple<DestIter, DestIter, DestAcc> dest, triple<DestIter, DestIter, DestAcc> dest,
Kernel const & kernel, Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<int> cons t & offset) Rational<int> const & samplingRatio, Rational<int> cons t & offset)
{ {
resamplingConvolveX(src.first, src.second, src.third, resamplingConvolveX(src.first, src.second, src.third,
dest.first, dest.second, dest.third, dest.first, dest.second, dest.third,
kernel, samplingRatio, offset); kernel, samplingRatio, offset);
} }
template <class T1, class S1,
class T2, class S2,
class Kernel>
inline void
resamplingConvolveX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<int> cons
t & offset)
{
resamplingConvolveX(srcImageRange(src),
destImageRange(dest),
kernel, samplingRatio, offset);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* resamplingConvolveY */ /* resamplingConvolveY */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply a resampling filter in the y-direction. /** \brief Apply a resampling filter in the y-direction.
This function implements a convolution operation in y-direction This function implements a convolution operation in y-direction
(i.e. applies a 1D filter to every column) where the height of the sour ce (i.e. applies a 1D filter to every column) where the height of the sour ce
skipping to change at line 526 skipping to change at line 573
The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vi gra::Rational The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vi gra::Rational
in order to avoid rounding errors in this transformation. It is require d that for all in order to avoid rounding errors in this transformation. It is require d that for all
pixels of the target image, <tt>ysource</tt> remains within the range o f the source pixels of the target image, <tt>ysource</tt> remains within the range o f the source
image (i.e. <tt>0 <= ysource <= sourceHeight-1</tt>. Since <tt>ysource< /tt> is image (i.e. <tt>0 <= ysource <= sourceHeight-1</tt>. Since <tt>ysource< /tt> is
in general not an integer, the <tt>kernel</tt> must be a functor that c an be accessed at in general not an integer, the <tt>kernel</tt> must be a functor that c an be accessed at
arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt> arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt>
which specifies the support (non-zero interval) of the kernel. VIGRA al ready which specifies the support (non-zero interval) of the kernel. VIGRA al ready
provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline
\ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The funct ion \ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The funct ion
\ref resizeImageSplineInterpolation() is implemented by means resamplin gConvolveX() and \ref resizeImageSplineInterpolation() is implemented by means of resamp lingConvolveX() and
resamplingConvolveY(). resamplingConvolveY().
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Kernel>
void
resamplingConvolveY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<i
nt> const & offset);
}
\endcode
\deprecatedAPI{resamplingConvolveY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class Kernel> class Kernel>
void void
resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src, resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src,
DestIter dul, DestIter dlr, DestAcc dest, DestIter dul, DestIter dlr, DestAcc dest,
Kernel const & kernel, Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<i nt> const & offset); Rational<int> const & samplingRatio, Rational<i nt> const & offset);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class Kernel> class Kernel>
void void
resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src, resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src,
triple<DestIter, DestIter, DestAcc> dest, triple<DestIter, DestIter, DestAcc> dest,
Kernel const & kernel, Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<i nt> const & offset); Rational<int> const & samplingRatio, Rational<i nt> const & offset);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/resampling_convolution.hxx\> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br/>
Namespace: vigra
\code
Rational<int> ratio(2), offset(0);
MultiArray<2, float> src(w,h),
dest(w, rational_cast<int>(ratio*h));
float sigma = 2.0;
Gaussian<float> smooth(sigma);
...
// simultaneously enlarge and smooth source image
resamplingConvolveY(src, dest,
smooth, ratio, offset);
\endcode
\deprecatedUsage{resamplingConvolveY}
\code \code
Rational<int> ratio(2), offset(0); Rational<int> ratio(2), offset(0);
FImage src(w,h), FImage src(w,h),
dest(w, rational_cast<int>(ratio*h)); dest(w, rational_cast<int>(ratio*h));
float sigma = 2.0; float sigma = 2.0;
Gaussian<float> smooth(sigma); Gaussian<float> smooth(sigma);
... ...
// simultaneously enlarge and smooth source image // simultaneously enlarge and smooth source image
resamplingConvolveY(srcImageRange(src), destImageRange(dest), resamplingConvolveY(srcImageRange(src), destImageRange(dest),
smooth, ratio, offset); smooth, ratio, offset);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
Kernel kernel; Kernel kernel;
int kernelRadius = kernel.radius(); int kernelRadius = kernel.radius();
double y = ...; // must be <= radius() double y = ...; // must be <= radius()
double value = kernel(y); double value = kernel(y);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void resamplingConvolveY) doxygen_overloaded_function(template <...> void resamplingConvolveY)
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAcc,
class DestIter, class DestAcc, class DestIter, class DestAcc,
class Kernel> class Kernel>
void void
resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src, resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src,
DestIter dul, DestIter dlr, DestAcc dest, DestIter dul, DestIter dlr, DestAcc dest,
Kernel const & kernel, Kernel const & kernel,
skipping to change at line 623 skipping to change at line 701
for(; sul.x < slr.x; ++sul.x, ++dul.x) for(; sul.x < slr.x; ++sul.x, ++dul.x)
{ {
typename SrcIter::column_iterator sc = sul.columnIterator(); typename SrcIter::column_iterator sc = sul.columnIterator();
typename DestIter::column_iterator dc = dul.columnIterator(); typename DestIter::column_iterator dc = dul.columnIterator();
resamplingConvolveLine(sc, sc+hold, src, dc, dc+hnew, dest, resamplingConvolveLine(sc, sc+hold, src, dc, dc+hnew, dest,
kernels, mapCoordinate); kernels, mapCoordinate);
} }
} }
template <class SrcIter, class SrcAcc, template <class SrcIter, class SrcAccessor,
class DestIter, class DestAcc, class DestIter, class DestAccessor,
class Kernel> class Kernel>
inline void inline void
resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src, resamplingConvolveY(triple<SrcIter, SrcIter, SrcAccessor> src,
triple<DestIter, DestIter, DestAcc> dest, triple<DestIter, DestIter, DestAccessor> dest,
Kernel const & kernel, Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<int> cons t & offset) Rational<int> const & samplingRatio, Rational<int> cons t & offset)
{ {
resamplingConvolveY(src.first, src.second, src.third, resamplingConvolveY(src.first, src.second, src.third,
dest.first, dest.second, dest.third, dest.first, dest.second, dest.third,
kernel, samplingRatio, offset); kernel, samplingRatio, offset);
} }
template <class T1, class S1,
class T2, class S2,
class Kernel>
inline void
resamplingConvolveY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel const & kernel,
Rational<int> const & samplingRatio, Rational<int> cons
t & offset)
{
resamplingConvolveY(srcImageRange(src),
destImageRange(dest),
kernel, samplingRatio, offset);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* resamplingConvolveImage */ /* resamplingConvolveImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply two separable resampling filters successively, the first i n x-direction, /** \brief Apply two separable resampling filters successively, the first i n x-direction,
the second in y-direction. the second in y-direction.
This function is a shorthand for the concatenation of a call to This function is a shorthand for the concatenation of a call to
\ref resamplingConvolveX() and \ref resamplingConvolveY() \ref resamplingConvolveX() and \ref resamplingConvolveY()
with the given kernels. See there for detailed documentation. with the given kernels. See there for detailed documentation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class KernelX, class KernelY>
void
resamplingConvolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
KernelX const & kx,
Rational<int> const & samplingRatioX, Ratio
nal<int> const & offsetX,
KernelY const & ky,
Rational<int> const & samplingRatioY, Ratio
nal<int> const & offsetY);
}
\endcode
\deprecatedAPI{resamplingConvolveImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelX, class KernelY> class KernelX, class KernelY>
void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAc cessor src, void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAc cessor src,
DestIterator dul, DestIterator dlr, DestAccessor dest, DestIterator dul, DestIterator dlr, DestAccessor dest,
KernelX const & kx, KernelX const & kx,
Rational<int> const & samplingRatioX, Rational<i nt> const & offsetX, Rational<int> const & samplingRatioX, Rational<i nt> const & offsetX,
KernelY const & ky, KernelY const & ky,
Rational<int> const & samplingRatioY, Rational<i nt> const & offsetY); Rational<int> const & samplingRatioY, Rational<i nt> const & offsetY);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelX, class KernelY> class KernelX, class KernelY>
void void
resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccesso r> src, resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
triple<DestIterator, DestIterator, DestAccessor> dest, triple<DestIterator, DestIterator, DestAccessor> dest,
KernelX const & kx, KernelX const & kx,
Rational<int> const & samplingRatioX, Rational<i nt> const & offsetX, Rational<int> const & samplingRatioX, Rational<i nt> const & offsetX,
KernelY const & ky, KernelY const & ky,
Rational<int> const & samplingRatioY, Rational<i nt> const & offsetY); Rational<int> const & samplingRatioY, Rational<i nt> const & offsetY);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/resampling_convolution.hxx\> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br/>
Namespace: vigra
\code \code
Rational<int> xratio(2), yratio(3), offset(0); Rational<int> xratio(2), yratio(3), offset(0);
FImage src(w,h), MultiArray<2, float> src(w,h),
dest(rational_cast<int>(xratio*w), rational_cast<int>(yratio*h)) dest(rational_cast<int>(xratio*w), rational_cast<i
; nt>(yratio*h));
float sigma = 2.0; float sigma = 2.0;
Gaussian<float> smooth(sigma); Gaussian<float> smooth(sigma);
... ...
// simultaneously enlarge and smooth source image // simultaneously enlarge and smooth source image
resamplingConvolveImage(srcImageRange(src), destImageRange(dest), resamplingConvolveImage(src, dest,
smooth, xratio, offset, smooth, xratio, offset,
smooth, yratio, offset); smooth, yratio, offset);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void resamplingConvolveImage) doxygen_overloaded_function(template <...> void resamplingConvolveImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelX, class KernelY> class KernelX, class KernelY>
void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAccessor s rc, void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAccessor s rc,
DestIterator dul, DestIterator dlr, DestAccessor dest, DestIterator dul, DestIterator dlr, DestAccessor dest,
KernelX const & kx, KernelX const & kx,
Rational<int> const & samplingRatioX, Rational<int> cons t & offsetX, Rational<int> const & samplingRatioX, Rational<int> cons t & offsetX,
skipping to change at line 736 skipping to change at line 844
resamplingConvolveY(srcImageRange(tmp), resamplingConvolveY(srcImageRange(tmp),
destIterRange(dul, dlr, dest), destIterRange(dul, dlr, dest),
ky, samplingRatioY, offsetY); ky, samplingRatioY, offsetY);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelX, class KernelY> class KernelX, class KernelY>
inline void inline void
resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<DestIterator, DestIterator, DestAccessor> dest, triple<DestIterator, DestIterator, DestAccessor> de
KernelX const & kx, st,
Rational<int> const & samplingRatioX, Rational<int> cons KernelX const & kx,
t & offsetX, Rational<int> const & samplingRatioX, Rational<int>
KernelY const & ky, const & offsetX,
Rational<int> const & samplingRatioY, Rational<int> cons KernelY const & ky,
t & offsetY) Rational<int> const & samplingRatioY, Rational<int>
const & offsetY)
{ {
resamplingConvolveImage(src.first, src.second, src.third, resamplingConvolveImage(src.first, src.second, src.third,
dest.first, dest.second, dest.third, dest.first, dest.second, dest.third,
kx, samplingRatioX, offsetX, kx, samplingRatioX, offsetX,
ky, samplingRatioY, offsetY); ky, samplingRatioY, offsetY);
} }
template <class T1, class S1,
class T2, class S2,
class KernelX, class KernelY>
inline void
resamplingConvolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
KernelX const & kx,
Rational<int> const & samplingRatioX, Rational<int>
const & offsetX,
KernelY const & ky,
Rational<int> const & samplingRatioY, Rational<int>
const & offsetY)
{
resamplingConvolveImage(srcImageRange(src),
destImageRange(dest),
kx, samplingRatioX, offsetX,
ky, samplingRatioY, offsetY);
}
/** \brief Two-fold down-sampling for image pyramid construction. /** \brief Two-fold down-sampling for image pyramid construction.
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/resampling_convolution.hxx\><br> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcA ccessor src, void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcA ccessor src,
DestIterator dul, DestIterator dlr, De stAccessor dest, DestIterator dul, DestIterator dlr, De stAccessor dest,
double centerValue = 0.4); double centerValue = 0.4);
} }
\endcode \endcode
\deprecatedAPI{pyramidReduceBurtFilter}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcA
ccessor src,
DestIterator dul, DestIterator dlr, De
stAccessor dest,
double centerValue = 0.4);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void pyramidReduceBurtFilter(triple<SrcIterator, SrcIterator, SrcAc cessor> src, void pyramidReduceBurtFilter(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
triple<DestIterator, DestIterator, Des tAccessor> dest, triple<DestIterator, DestIterator, Des tAccessor> dest,
double centerValue = 0.4); double centerValue = 0.4);
} }
\endcode \endcode
\deprecatedEnd
use a \ref vigra::ImagePyramid : use a \ref vigra::ImagePyramid :
\code \code
namespace vigra { namespace vigra {
template <class Image, class Alloc> template <class Image, class Alloc>
void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
double centerValue = 0.4); double centerValue = 0.4);
} }
\endcode \endcode
*/ */
skipping to change at line 880 skipping to change at line 1017
/** \brief Two-fold up-sampling for image pyramid reconstruction. /** \brief Two-fold up-sampling for image pyramid reconstruction.
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<vigra/resampling_convolution.hxx\><br> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcA ccessor src, void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcA ccessor src,
DestIterator dul, DestIterator dlr, De stAccessor dest, DestIterator dul, DestIterator dlr, De stAccessor dest,
double centerValue = 0.4); double centerValue = 0.4);
} }
\endcode \endcode
\deprecatedAPI{pyramidExpandBurtFilter}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcA
ccessor src,
DestIterator dul, DestIterator dlr, De
stAccessor dest,
double centerValue = 0.4);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void pyramidExpandBurtFilter(triple<SrcIterator, SrcIterator, SrcAc cessor> src, void pyramidExpandBurtFilter(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
triple<DestIterator, DestIterator, Des tAccessor> dest, triple<DestIterator, DestIterator, Des tAccessor> dest,
double centerValue = 0.4); double centerValue = 0.4);
} }
\endcode \endcode
\deprecatedEnd
use a \ref vigra::ImagePyramid : use a \ref vigra::ImagePyramid :
\code \code
namespace vigra { namespace vigra {
template <class Image, class Alloc> template <class Image, class Alloc>
void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
double centerValue = 0.4); double centerValue = 0.4);
} }
\endcode \endcode
*/ */
skipping to change at line 1003 skipping to change at line 1152
} }
/** \brief Create a Laplacian pyramid. /** \brief Create a Laplacian pyramid.
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b>\#include</b> \<vigra/resampling_convolution.hxx\><br> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class Image, class Alloc> template <class Image, class Alloc>
inline inline void
void pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int f pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLe
romLevel, int toLevel, vel, int toLevel,
double centerValue = 0.4) double centerValue = 0.4)
{ {
using namespace functor; using namespace functor;
pyramidReduceBurtFilter(pyramid, fromLevel, toLevel, centerValue); pyramidReduceBurtFilter(pyramid, fromLevel, toLevel, centerValue);
for(int i=fromLevel; i < toLevel; ++i) for(int i=fromLevel; i < toLevel; ++i)
{ {
typename ImagePyramid<Image, Alloc>::value_type tmpImage(pyramid[i] .size()); typename ImagePyramid<Image, Alloc>::value_type tmpImage(pyramid[i] .size());
pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange (tmpImage), centerValue); pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange (tmpImage), centerValue);
combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), des tImage(pyramid[i]), combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), des tImage(pyramid[i]),
Arg1() - Arg2()); Arg1() - Arg2());
skipping to change at line 1027 skipping to change at line 1176
} }
/** \brief Reconstruct a Laplacian pyramid. /** \brief Reconstruct a Laplacian pyramid.
Sorry, no \ref detailedDocumentation() available yet. Sorry, no \ref detailedDocumentation() available yet.
<b>\#include</b> \<vigra/resampling_convolution.hxx\><br> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class Image, class Alloc> template <class Image, class Alloc>
inline inline void
void pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int f pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLe
romLevel, int toLevel, vel, int toLevel,
double centerValue = 0.4) double centerValue = 0.4)
{ {
using namespace functor; using namespace functor;
vigra_precondition(fromLevel > toLevel, vigra_precondition(fromLevel > toLevel,
"pyramidExpandBurtLaplacian(): fromLevel must be larger than toLevel ."); "pyramidExpandBurtLaplacian(): fromLevel must be larger than toLevel .");
vigra_precondition(pyramid.lowestLevel() <= toLevel && fromLevel <= pyr amid.highestLevel(), vigra_precondition(pyramid.lowestLevel() <= toLevel && fromLevel <= pyr amid.highestLevel(),
"pyramidExpandBurtLaplacian(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive)."); "pyramidExpandBurtLaplacian(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive).");
for(int i=fromLevel-1; i >= toLevel; --i) for(int i=fromLevel-1; i >= toLevel; --i)
{ {
 End of changes. 43 change blocks. 
45 lines changed or deleted 207 lines changed or added


 resizeimage.hxx   resizeimage.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_RESIZEIMAGE_HXX #define VIGRA_RESIZEIMAGE_HXX
#include <vector> #include <vector>
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "recursiveconvolution.hxx" #include "recursiveconvolution.hxx"
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "resampling_convolution.hxx" #include "resampling_convolution.hxx"
#include "splines.hxx" #include "splines.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/*****************************************************************/ /*****************************************************************/
/* */ /* */
/* CoscotFunction */ /* CoscotFunction */
/* */ /* */
/*****************************************************************/ /*****************************************************************/
/*! The Coscot interpolation function. /** The Coscot interpolation function.
Implements the Coscot interpolation function proposed by Maria Magnusso n Seger Implements the Coscot interpolation function proposed by Maria Magnusso n Seger
(maria@isy.liu.se) in the context of tomographic reconstruction. It pro vides a fast (maria@isy.liu.se) in the context of tomographic reconstruction. It pro vides a fast
transition between the pass- and stop-bands and minimal ripple outside the transition transition between the pass- and stop-bands and minimal ripple outside the transition
region. Both properties are important for this application and can be t uned by the parameters region. Both properties are important for this application and can be t uned by the parameters
<i>m</i> and <i>h</i> (with defaults 3 and 0.5). The function is define d by <i>m</i> and <i>h</i> (with defaults 3 and 0.5). The function is define d by
\f[ f_{m,h}(x) = \left\{ \begin{array}{ll} \f[ f_{m,h}(x) = \left\{ \begin{array}{ll}
\frac{1}{2m}\sin(\pi x)\cot(\pi x / (2 m ))(h + (1-h)\cos(\pi x/m)) & |x| \leq m \\ \frac{1}{2m}\sin(\pi x)\cot(\pi x / (2 m ))(h + (1-h)\cos(\pi x/m)) & |x| \leq m \\
0 & \mbox{otherwise} 0 & \mbox{otherwise}
skipping to change at line 132 skipping to change at line 133
/** Derivative order of the function: always 0. /** Derivative order of the function: always 0.
*/ */
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return 0; } { return 0; }
/** Prefilter coefficients for compatibility with \ref vigra::BSpli ne. /** Prefilter coefficients for compatibility with \ref vigra::BSpli ne.
(array has zero length, since prefiltering is not necessary). (array has zero length, since prefiltering is not necessary).
*/ */
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> b; return prefilterCoefficients_;
return b;
} }
protected: protected:
static ArrayVector<double> prefilterCoefficients_;
unsigned int m_; unsigned int m_;
double h_; double h_;
}; };
template <class T>
ArrayVector<double> CoscotFunction<T>::prefilterCoefficients_;
/** \addtogroup GeometricTransformations Geometric Transformations /** \addtogroup GeometricTransformations Geometric Transformations
Zoom up and down by repeating pixels, or using various interpolation sc hemes. Zoom up and down by repeating pixels, or using various interpolation sc hemes.
See also: \ref resamplingConvolveImage(), \ref resampleImage(), \ref re sizeMultiArraySplineInterpolation() See also: \ref resamplingConvolveImage(), \ref resampleImage(), \ref re sizeMultiArraySplineInterpolation()
<b>\#include</b> \<vigra/stdimagefunctions.hxx\><br> <b>\#include</b> \<vigra/stdimagefunctions.hxx\><br>
<b>or</b><br> <b>or</b><br>
<b>\#include</b> \<vigra/resizeimage.hxx\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
*/ */
//@{ //@{
skipping to change at line 199 skipping to change at line 202
/** \brief Resize image by repeating the nearest pixel values. /** \brief Resize image by repeating the nearest pixel values.
This algorithm is very fast and does not require any arithmetic on This algorithm is very fast and does not require any arithmetic on
the pixel types. the pixel types.
The range of both the input and output images (resp. regions) must The range of both the input and output images (resp. regions) must
be given. Both images must have a size of at least 2x2 pixels. The be given. Both images must have a size of at least 2x2 pixels. The
scaling factors are then calculated accordingly. Destination scaling factors are then calculated accordingly. Destination
pixels are directly copied from the appropriate source pixels. pixels are directly copied from the appropriate source pixels.
The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
resizeImageNoInterpolation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest);
}
\endcode
\deprecatedAPI{resizeImageNoInterpolation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
resizeImageNoInterpolation( resizeImageNoInterpolation(
SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa, SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa,
DestImageIterator id, DestImageIterator idend, DestAccessor d a) DestImageIterator id, DestImageIterator idend, DestAccessor d a)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
resizeImageNoInterpolation( resizeImageNoInterpolation(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
triple<DestImageIterator, DestImageIterator, DestAccessor> de st) triple<DestImageIterator, DestImageIterator, DestAccessor> de st)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/resizeimage.hxx\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, unsigned char> src(w, h);
MultiArray<2, float> dest(w_new, h_new);
resizeImageNoInterpolation(src, dest);
\endcode
\deprecatedUsage{resizeImageNoInterpolation}
\code \code
vigra::resizeImageNoInterpolation( vigra::resizeImageNoInterpolation(
src.upperLeft(), src.lowerRight(), src.accessor(), src.upperLeft(), src.lowerRight(), src.accessor(),
dest.upperLeft(), dest.lowerRight(), dest.accessor()); dest.upperLeft(), dest.lowerRight(), dest.accessor());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft, src_lowerright; DestImageIterator dest_upperleft, src_lowerright;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
dest_accessor.set(src_accessor(src_upperleft), dest_upperleft); dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code Source and destination must have at least 2 pixels along each axis.
src_lowerright.x - src_upperleft.x > 1
src_lowerright.y - src_upperleft.y > 1
dest_lowerright.x - dest_upperleft.x > 1
dest_lowerright.y - dest_upperleft.y > 1
\endcode
*/ */
doxygen_overloaded_function(template <...> void resizeImageNoInterpolation) doxygen_overloaded_function(template <...> void resizeImageNoInterpolation)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageNoInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa , resizeImageNoInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa ,
DestIterator id, DestIterator idend, DestAccessor da) DestIterator id, DestIterator idend, DestAccessor da)
{ {
int w = iend.x - is.x; int w = iend.x - is.x;
skipping to change at line 311 skipping to change at line 325
{ {
typename DestIterator::row_iterator rd = id.rowIterator(); typename DestIterator::row_iterator rd = id.rowIterator();
typename TmpImageIterator::row_iterator rt = yt.rowIterator(); typename TmpImageIterator::row_iterator rt = yt.rowIterator();
resizeLineNoInterpolation(rt, rt + w, tmp.accessor(), rd, rd + wnew , da); resizeLineNoInterpolation(rt, rt + w, tmp.accessor(), rd, rd + wnew , da);
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void
resizeImageNoInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> sr c, resizeImageNoInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> sr c,
triple<DestIterator, DestIterator, DestAccessor> dest) triple<DestIterator, DestIterator, DestAccessor> dest)
{ {
resizeImageNoInterpolation(src.first, src.second, src.third, resizeImageNoInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third); dest.first, dest.second, dest.third);
}
template <class T1, class S1,
class T2, class S2>
inline void
resizeImageNoInterpolation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{
resizeImageNoInterpolation(srcImageRange(src),
destImageRange(dest));
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* resizeLineLinearInterpolation */ /* resizeLineLinearInterpolation */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
skipping to change at line 383 skipping to change at line 406
obtain a good compromise between quality and speed. obtain a good compromise between quality and speed.
The range must of both the input and output images (resp. regions) The range must of both the input and output images (resp. regions)
must be given. Both images must have a size of at must be given. Both images must have a size of at
least 2x2. The scaling factors are then calculated least 2x2. The scaling factors are then calculated
accordingly. If the source image is larger than the destination, it accordingly. If the source image is larger than the destination, it
is smoothed (band limited) using a recursive is smoothed (band limited) using a recursive
exponential filter. The source value_type (SrcAccessor::value_type) mus t exponential filter. The source value_type (SrcAccessor::value_type) mus t
be a linear space, i.e. it must support addition, multiplication be a linear space, i.e. it must support addition, multiplication
with a scalar real number and \ref NumericTraits "NumericTraits". with a scalar real number and \ref NumericTraits "NumericTraits".
The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
resizeImageLinearInterpolation(MultiArrayView<2, T1, S1> const & sr
c,
MultiArrayView<2, T2, S2> dest);
}
\endcode
\deprecatedAPI{resizeImageLinearInterpolation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
resizeImageLinearInterpolation( resizeImageLinearInterpolation(
SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa, SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa,
DestImageIterator id, DestImageIterator idend, DestAccessor d a) DestImageIterator id, DestImageIterator idend, DestAccessor d a)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void void
resizeImageLinearInterpolation( resizeImageLinearInterpolation(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
triple<DestImageIterator, DestImageIterator, DestAccessor> de st) triple<DestImageIterator, DestImageIterator, DestAccessor> de st)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/resizeimage.hxx\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, unsigned char> src(w, h);
MultiArray<2, float> dest(w_new, h_new);
resizeImageLinearInterpolation(src, dest);
\endcode
\deprecatedUsage{resizeImageLinearInterpolation}
\code \code
vigra::resizeImageLinearInterpolation( vigra::resizeImageLinearInterpolation(
src.upperLeft(), src.lowerRight(), src.accessor(), src.upperLeft(), src.lowerRight(), src.accessor(),
dest.upperLeft(), dest.lowerRight(), dest.accessor()); dest.upperLeft(), dest.lowerRight(), dest.accessor());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft, src_lowerright; DestImageIterator dest_upperleft, src_lowerright;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote NumericTraits<SrcAccessor::value_type>::RealPromote
u = src_accessor(src_upperleft), u = src_accessor(src_upperleft),
v = src_accessor(src_upperleft, 1); v = src_accessor(src_upperleft, 1);
double d; double d;
u = d * v; u = d * v;
u = u + v; u = u + v;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(u), NumericTraits<DestAccessor::value_type>::fromRealPromote(u),
dest_upperleft); dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code Source and destination must have at least 2 pixels along each axis.
src_lowerright.x - src_upperleft.x > 1
src_lowerright.y - src_upperleft.y > 1
dest_lowerright.x - dest_upperleft.x > 1
dest_lowerright.y - dest_upperleft.y > 1
\endcode
*/ */
doxygen_overloaded_function(template <...> void resizeImageLinearInterpolat ion) doxygen_overloaded_function(template <...> void resizeImageLinearInterpolat ion)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageLinearInterpolation(SrcIterator is, SrcIterator iend, SrcAccesso r sa, resizeImageLinearInterpolation(SrcIterator is, SrcIterator iend, SrcAccesso r sa,
DestIterator id, DestIterator idend, DestAccessor da) DestIterator id, DestIterator idend, DestAccessor da)
{ {
int w = iend.x - is.x; int w = iend.x - is.x;
skipping to change at line 537 skipping to change at line 572
else else
{ {
resizeLineLinearInterpolation(rt, rt + w, tmp.accessor(), resizeLineLinearInterpolation(rt, rt + w, tmp.accessor(),
rd, rd + wnew, da); rd, rd + wnew, da);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void
resizeImageLinearInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor > src, resizeImageLinearInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor > src,
triple<DestIterator, DestIterator, DestAcces sor> dest) triple<DestIterator, DestIterator, DestAcces sor> dest)
{ {
resizeImageLinearInterpolation(src.first, src.second, src.third, resizeImageLinearInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third); dest.first, dest.second, dest.third);
} }
template <class T1, class S1,
class T2, class S2>
inline void
resizeImageLinearInterpolation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{
resizeImageLinearInterpolation(srcImageRange(src),
destImageRange(dest));
}
/***************************************************************/ /***************************************************************/
/* */ /* */
/* resizeImageSplineInterpolation */ /* resizeImageSplineInterpolation */
/* */ /* */
/***************************************************************/ /***************************************************************/
/** \brief Resize image using B-spline interpolation. /** \brief Resize image using B-spline interpolation.
The function implements separable spline interpolation algorithm descri bed in The function implements separable spline interpolation algorithm descri bed in
skipping to change at line 582 skipping to change at line 626
accordingly. If the source image is larger than the destination, it accordingly. If the source image is larger than the destination, it
is smoothed (band limited) using a recursive is smoothed (band limited) using a recursive
exponential filter. The source value_type (SrcAccessor::value_type) mus t exponential filter. The source value_type (SrcAccessor::value_type) mus t
be a linear algebra, i.e. it must support addition, subtraction, be a linear algebra, i.e. it must support addition, subtraction,
and multiplication (+, -, *), multiplication with a scalar and multiplication (+, -, *), multiplication with a scalar
real number and \ref NumericTraits "NumericTraits". real number and \ref NumericTraits "NumericTraits".
The function uses accessors. The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class SPLINE>
void
resizeImageSplineInterpolation(MultiArrayView<2, T1, S1> const & sr
c,
MultiArrayView<2, T2, S2> dest,
SPLINE const & spline = BSpline<3, d
ouble>());
}
\endcode
\deprecatedAPI{resizeImageSplineInterpolation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class SPLINE> class SPLINE>
void void
resizeImageSplineInterpolation( resizeImageSplineInterpolation(
SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa, SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa,
DestImageIterator id, DestImageIterator idend, DestAccessor d a, DestImageIterator id, DestImageIterator idend, DestAccessor d a,
SPLINE spline = BSpline<3, double>()) SPLINE spline = BSpline<3, double>())
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class SPLINE> class SPLINE>
void void
resizeImageSplineInterpolation( resizeImageSplineInterpolation(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
triple<DestImageIterator, DestImageIterator, DestAccessor> de st, triple<DestImageIterator, DestImageIterator, DestAccessor> de st,
SPLINE spline = BSpline<3, double>()) SPLINE spline = BSpline<3, double>())
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/resizeimage.hxx\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w, h);
MultiArray<2, float> dest(w_new, h_new);
// use default cubic spline interpolator
resizeImageSplineInterpolation(src, dest);
// use 5th-order spline interpolator
resizeImageSplineInterpolation(src, dest, BSpline<5, double>());
\endcode
\deprecatedUsage{resizeImageSplineInterpolation}
\code
vigra::resizeImageSplineInterpolation( vigra::resizeImageSplineInterpolation(
src.upperLeft(), src.lowerRight(), src.accessor(), src.upperLeft(), src.lowerRight(), src.accessor(),
dest.upperLeft(), dest.lowerRight(), dest.accessor()); dest.upperLeft(), dest.lowerRight(), dest.accessor());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft, src_lowerright; DestImageIterator dest_upperleft, src_lowerright;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote NumericTraits<SrcAccessor::value_type>::RealPromote
u = src_accessor(src_upperleft), u = src_accessor(src_upperleft),
v = src_accessor(src_upperleft, 1); v = src_accessor(src_upperleft, 1);
skipping to change at line 648 skipping to change at line 716
u = u - v; u = u - v;
u = u * v; u = u * v;
u += v; u += v;
u -= v; u -= v;
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(u), NumericTraits<DestAccessor::value_type>::fromRealPromote(u),
dest_upperleft); dest_upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code Source and destination must have at least 2 pixels along each axis.
src_lowerright.x - src_upperleft.x > 3
src_lowerright.y - src_upperleft.y > 3
dest_lowerright.x - dest_upperleft.x > 1
dest_lowerright.y - dest_upperleft.y > 1
\endcode
*/ */
doxygen_overloaded_function(template <...> void resizeImageSplineInterpolat ion) doxygen_overloaded_function(template <...> void resizeImageSplineInterpolat ion)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class SPLINE> class SPLINE>
void void
resizeImageSplineInterpolation( resizeImageSplineInterpolation(
SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc, SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_a cc, DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_a cc,
skipping to change at line 810 skipping to change at line 873
line_tmp, line.accessor(), (double)widt h_old/width_new/scale); line_tmp, line.accessor(), (double)widt h_old/width_new/scale);
} }
resamplingConvolveLine(line_tmp, line_tmp + width_old, line.acc essor(), resamplingConvolveLine(line_tmp, line_tmp + width_old, line.acc essor(),
r_dest, r_dest + width_new, dest_acc, r_dest, r_dest + width_new, dest_acc,
kernels, xmapCoordinate); kernels, xmapCoordinate);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class SPLINE>
inline
void
resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor
> src,
triple<DestIterator, DestIterator, DestAccessor> dest
,
SPLINE const & spline)
{
resizeImageSplineInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third, spl
ine);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccesso r sa, resizeImageSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccesso r sa,
DestIterator id, DestIterator idend, DestAccessor da) DestIterator id, DestIterator idend, DestAccessor da)
{ {
resizeImageSplineInterpolation(is, iend, sa, id, idend, da, BSpline<3, double>()); resizeImageSplineInterpolation(is, iend, sa, id, idend, da, BSpline<3, double>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class SPLINE>
inline void
resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor
> src,
triple<DestIterator, DestIterator, DestAcces
sor> dest,
SPLINE const & spline)
{
resizeImageSplineInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third, spl
ine);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void
resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor > src, resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor > src,
triple<DestIterator, DestIterator, DestAccessor> dest ) triple<DestIterator, DestIterator, DestAcces sor> dest)
{ {
resizeImageSplineInterpolation(src.first, src.second, src.third, resizeImageSplineInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third); dest.first, dest.second, dest.third);
} }
template <class T1, class S1,
class T2, class S2,
class SPLINE>
inline void
resizeImageSplineInterpolation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
SPLINE const & spline)
{
resizeImageSplineInterpolation(srcImageRange(src),
destImageRange(dest), spline);
}
template <class T1, class S1,
class T2, class S2>
inline void
resizeImageSplineInterpolation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{
resizeImageSplineInterpolation(srcImageRange(src),
destImageRange(dest));
}
/*****************************************************************/ /*****************************************************************/
/* */ /* */
/* resizeImageCatmullRomInterpolation */ /* resizeImageCatmullRomInterpolation */
/* */ /* */
/*****************************************************************/ /*****************************************************************/
/** \brief Resize image using the Catmull/Rom interpolation function. /** \brief Resize image using the Catmull/Rom interpolation function.
The function calls like \ref resizeImageSplineInterpolation() with The function calls like \ref resizeImageSplineInterpolation() with
\ref vigra::CatmullRomSpline as an interpolation kernel. \ref vigra::CatmullRomSpline as an interpolation kernel.
The interpolated function has one continuous derivative. The interpolated function has one continuous derivative.
(See \ref resizeImageSplineInterpolation() for more documentation) (See \ref resizeImageSplineInterpolation() for more documentation)
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
resizeImageCatmullRomInterpolation(MultiArrayView<2, T1, S1> const
& src,
MultiArrayView<2, T2, S2> dest);
}
\endcode
\deprecatedAPI{resizeImageCatmullRomInterpolation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageCatmullRomInterpolation(SrcIterator src_iter, SrcIterato r src_iter_end, SrcAccessor src_acc, resizeImageCatmullRomInterpolation(SrcIterator src_iter, SrcIterato r src_iter_end, SrcAccessor src_acc,
DestIterator dest_iter, DestIterator dest_ite r_end, DestAccessor dest_acc); DestIterator dest_iter, DestIterator dest_ite r_end, DestAccessor dest_acc);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageCatmullRomInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src, resizeImageCatmullRomInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<DestIterator, DestIterator, DestAccess or> dest); triple<DestIterator, DestIterator, DestAccess or> dest);
} }
\endcode \endcode
\deprecatedEnd
<b>\#include</b> \<vigra/resizeimage.hxx\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, unsigned char> src(w, h);
MultiArray<2, float> dest(w_new, h_new);
resizeImageCatmullRomInterpolation(src, dest);
\endcode
*/ */
doxygen_overloaded_function(template <...> void resizeImageCatmullRomInterp olation) doxygen_overloaded_function(template <...> void resizeImageCatmullRomInterp olation)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline void
resizeImageCatmullRomInterpolation(SrcIterator src_iter, SrcIterator src_it er_end, SrcAccessor src_acc, resizeImageCatmullRomInterpolation(SrcIterator src_iter, SrcIterator src_it er_end, SrcAccessor src_acc,
DestIterator dest_iter, DestIterator dest_iter_end, D estAccessor dest_acc) DestIterator dest_iter, DestIterator dest_iter_end, D estAccessor dest_acc)
{ {
resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_it er, dest_iter_end, dest_acc, resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_it er, dest_iter_end, dest_acc,
CatmullRomSpline<double>()); CatmullRomSpline<double>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void
resizeImageCatmullRomInterpolation(triple<SrcIterator, SrcIterator, SrcAcce ssor> src, resizeImageCatmullRomInterpolation(triple<SrcIterator, SrcIterator, SrcAcce ssor> src,
triple<DestIterator, DestIterator, DestAccessor> dest ) triple<DestIterator, DestIterator, DestA ccessor> dest)
{ {
resizeImageCatmullRomInterpolation(src.first, src.second, src.third, resizeImageCatmullRomInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third); dest.first, dest.second, dest.third)
} ;
#if 0
/*****************************************************************/
/* */
/* resizeImageCubicInterpolation */
/* */
/*****************************************************************/
/** \brief Resize image using the cardinal B-spline interpolation function.
The function calls like \ref resizeImageSplineInterpolation() with
\ref vigra::BSpline<3, double> and prefiltering as an interpolation ker
nel.
The interpolated function has two continuous derivatives.
(See \ref resizeImageSplineInterpolation() for more documentation)
<b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra
*/
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void
resizeImageCubicInterpolation(SrcIterator src_iter, SrcIterator src_iter_en
d, SrcAccessor src_acc,
DestIterator dest_iter, DestIterator dest_iter_end, D
estAccessor dest_acc)
{
resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_it
er, dest_iter_end, dest_acc,
BSpline<3, double>());
} }
template <class SrcIterator, class SrcAccessor, template <class T1, class S1,
class DestIterator, class DestAccessor> class T2, class S2>
inline inline void
void resizeImageCatmullRomInterpolation(MultiArrayView<2, T1, S1> const & src,
resizeImageCubicInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> MultiArrayView<2, T2, S2> dest)
src,
triple<DestIterator, DestIterator, DestAccessor> dest
)
{ {
resizeImageCubicInterpolation(src.first, src.second, src.third, resizeImageCatmullRomInterpolation(srcImageRange(src),
dest.first, dest.second, dest.third); destImageRange(dest));
} }
#endif
/*****************************************************************/ /*****************************************************************/
/* */ /* */
/* resizeImageCoscotInterpolation */ /* resizeImageCoscotInterpolation */
/* */ /* */
/*****************************************************************/ /*****************************************************************/
/** \brief Resize image using the Coscot interpolation function. /** \brief Resize image using the Coscot interpolation function.
The function calls \ref resizeImageSplineInterpolation() with The function calls \ref resizeImageSplineInterpolation() with
\ref vigra::CoscotFunction as an interpolation kernel. \ref vigra::CoscotFunction as an interpolation kernel.
The interpolated function has one continuous derivative. The interpolated function has one continuous derivative.
(See \ref resizeImageSplineInterpolation() for more documentation) (See \ref resizeImageSplineInterpolation() for more documentation)
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
resizeImageCoscotInterpolation(MultiArrayView<2, T1, S1> const & sr
c,
MultiArrayView<2, T2, S2> dest);
}
\endcode
\deprecatedAPI{resizeImageCoscotInterpolation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageCoscotInterpolation(SrcIterator src_iter, SrcIterator sr c_iter_end, SrcAccessor src_acc, resizeImageCoscotInterpolation(SrcIterator src_iter, SrcIterator sr c_iter_end, SrcAccessor src_acc,
DestIterator dest_iter, DestIterator dest_ite r_end, DestAccessor dest_acc); DestIterator dest_iter, DestIterator dest_ite r_end, DestAccessor dest_acc);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageCoscotInterpolation(triple<SrcIterator, SrcIterator, Src Accessor> src, resizeImageCoscotInterpolation(triple<SrcIterator, SrcIterator, Src Accessor> src,
triple<DestIterator, DestIterator, DestAccess or> dest); triple<DestIterator, DestIterator, DestAccess or> dest);
} }
\endcode \endcode
\deprecatedEnd
<b>\#include</b> \<vigra/resizeimage.hxx\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code
MultiArray<2, unsigned char> src(w, h);
MultiArray<2, float> dest(w_new, h_new);
resizeImageCoscotInterpolation(src, dest);
\endcode
*/ */
doxygen_overloaded_function(template <...> void resizeImageCoscotInterpolat ion) doxygen_overloaded_function(template <...> void resizeImageCoscotInterpolat ion)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageCoscotInterpolation(SrcIterator src_iter, SrcIterator src_iter_e nd, SrcAccessor src_acc, resizeImageCoscotInterpolation(SrcIterator src_iter, SrcIterator src_iter_e nd, SrcAccessor src_acc,
DestIterator dest_iter, DestIterator dest_iter_end, D estAccessor dest_acc) DestIterator dest_iter, DestIterator dest_iter_end, D estAccessor dest_acc)
{ {
resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_it er, dest_iter_end, dest_acc, resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_it er, dest_iter_end, dest_acc,
CoscotFunction<double>()); CoscotFunction<double>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void
resizeImageCoscotInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor > src, resizeImageCoscotInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor > src,
triple<DestIterator, DestIterator, DestAccessor> dest ) triple<DestIterator, DestIterator, DestAcces sor> dest)
{ {
resizeImageCoscotInterpolation(src.first, src.second, src.third, resizeImageCoscotInterpolation(src.first, src.second, src.third,
dest.first, dest.second, dest.third); dest.first, dest.second, dest.third);
} }
#if 0 // old version of the spline interpolation algorithm template <class T1, class S1,
class T2, class S2>
/********************************************************/ inline void
/* */ resizeImageCoscotInterpolation(MultiArrayView<2, T1, S1> const & src,
/* resizeCalculateSplineCoefficients */ MultiArrayView<2, T2, S2> dest)
/* (internally used by resize functions) */
/* */
/********************************************************/
template <class SrcIterator, class SrcAccessor, class VALUETYPE>
void
resizeCalculateSplineCoefficients(SrcIterator i1, SrcIterator iend,
SrcAccessor a, VALUETYPE * i2)
{
int n = iend - i1;
if(n <= 0) return;
VALUETYPE zero = NumericTraits<VALUETYPE>::zero();
VALUETYPE two = 2.0 * NumericTraits<VALUETYPE>::one();
VALUETYPE half = 0.5 * NumericTraits<VALUETYPE>::one();
*i2 = zero;
if(n == 1) return;
std::vector<VALUETYPE> vec(n);
typename std::vector<VALUETYPE>::iterator u = vec.begin();
*u = zero;
for(++i1, ++i2, ++u, --iend; i1 != iend; ++i1, ++i2, ++u)
{
VALUETYPE p = 0.5 * i2[-1] + two;
*i2 = half / p;
*u = 3.0 *(a(i1,1) - 2.0 * a(i1) + a(i1, -1)) - 0.5 * u[-1] / p;
}
*i2 = zero;
for(--i2, --u; u != vec; --u, --i2)
{
*i2 = *i2 * i2[1] + *u;
}
}
/********************************************************/
/* */
/* resizeImageInternalSplineGradient */
/* */
/********************************************************/
template <class SrcIterator, class SrcAccessor,
class DoubleIterator, class TempIterator, class DestIterator>
void
resizeImageInternalSplineGradient(SrcIterator in, SrcIterator inend, SrcAcc
essor sa,
DoubleIterator tmp, TempIterator r, DestIterator i
d)
{
int w = inend - in;
int x;
typedef typename SrcAccessor::value_type SRCVT;
typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
// calculate border derivatives
SrcIterator xs = in;
TMPTYPE p0 = -11.0/6.0 * sa(xs); ++xs;
p0 += 3.0 * sa(xs); ++xs;
p0 += -1.5 * sa(xs); ++xs;
p0 += 1.0/3.0 * sa(xs);
xs = in + w-1;
TMPTYPE pw = 11.0/6.0 * sa(xs); --xs;
pw += -3.0 * sa(xs); --xs;
pw += 1.5 * sa(xs); --xs;
pw += -1.0/3.0 * sa(xs);
xs = in + 2;
SrcIterator xs1 = in;
for(x=1; x<w-1; ++x, ++xs, ++xs1)
{
r[x] = 3.0 * (sa(xs) - sa(xs1));
}
r[1] -= p0;
r[w-2] -= pw;
double q = 0.25;
id[0] = p0;
id[w-1] = pw;
id[1] = 0.25 * r[1];
for(x=2; x<w-1; ++x)
{
tmp[x] = q;
q = 1.0 / (4.0 - q);
id[x] = q * (r[x] - id[x-1]);
}
for(x=w-3; x>=1; --x)
{
id[x] -= tmp[x+1]*id[x+1];
}
}
/********************************************************/
/* */
/* resizeImageInternalSplineInterpolation */
/* */
/********************************************************/
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void
resizeImageInternalSplineInterpolation(SrcIterator is, SrcIterator iend, Sr
cAccessor sa,
DestIterator id, DestIterator idend, DestAccessor da)
{
int w = iend.x - is.x;
int h = iend.y - is.y;
int wnew = idend.x - id.x;
int hnew = idend.y - id.y;
typedef typename SrcAccessor::value_type SRCVT;
typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
typedef
NumericTraits<typename DestAccessor::value_type> DestTraits;
BasicImage<TMPTYPE> dx(w,h);
BasicImage<TMPTYPE> dy(w,h);
BasicImage<TMPTYPE> dxy(w,h);
BasicImage<TMPTYPE> W(4,4), W1(4,4);
std::vector<TMPTYPE> R(w > h ? w : h);
std::vector<double> tmp(w > h ? w : h);
typename BasicImage<TMPTYPE>::Accessor ta;
SrcIterator in = is;
TMPITER idx = dx.upperLeft();
TMPITER idy = dy.upperLeft();
TMPITER idxy = dxy.upperLeft();
typename std::vector<TMPTYPE>::iterator r = R.begin();
typename std::vector<double>::iterator it = tmp.begin();
double ig[] = { 1.0, 0.0, -3.0, 2.0,
0.0, 1.0, -2.0, 1.0,
0.0, 0.0, 3.0, -2.0,
0.0, 0.0, -1.0, 1.0 };
int x, y, i, j, k;
// calculate x derivatives
for(y=0; y<h; ++y, ++in.y, ++idx.y)
{
typename SrcIterator::row_iterator sr = in.rowIterator();
typename TMPITER::row_iterator dr = idx.rowIterator();
resizeImageInternalSplineGradient(sr, sr+w, sa,
it, r, dr);
}
in = is;
// calculate y derivatives
for(x=0; x<w; ++x, ++in.x, ++idy.x)
{
typename SrcIterator::column_iterator sc = in.columnIterator();
typename TMPITER::column_iterator dc = idy.columnIterator();
resizeImageInternalSplineGradient(sc, sc+h, sa,
it, r, dc);
}
in = is;
idy = dy.upperLeft();
// calculate mixed derivatives
for(y=0; y<h; ++y, ++idy.y, ++idxy.y)
{
typename TMPITER::row_iterator sr = idy.rowIterator();
typename TMPITER::row_iterator dr = idxy.rowIterator();
resizeImageInternalSplineGradient(sr, sr+w, ta,
it, r, dr);
}
double du = (double)(w-1) / (wnew-1);
double dv = (double)(h-1) / (hnew-1);
double ov = 0.0;
int oy = 0;
int yy = oy;
DestIterator xxd = id, yyd = id;
static Diff2D down(0,1), right(1,0), downright(1,1);
for(y=0; y<h-1; ++y, ++in.y, ov -= 1.0)
{
if(y < h-2 && ov >= 1.0) continue;
int y1 = y+1;
double v = ov;
double ou = 0.0;
int ox = 0;
int xx = ox;
SrcIterator xs = in;
for(x=0; x<w-1; ++x, ++xs.x, ou -= 1.0)
{
if(x < w-2 && ou >= 1.0) continue;
int x1 = x+1;
double u = ou;
DestIterator xd = id + Diff2D(ox,oy);
W[0][0] = sa(xs);
W[0][1] = dy(x, y);
W[0][2] = sa(xs, down);
W[0][3] = dy(x, y1);
W[1][0] = dx(x, y);
W[1][1] = dxy(x, y);
W[1][2] = dx(x, y1);
W[1][3] = dxy(x, y1);
W[2][0] = sa(xs, right);
W[2][1] = dy(x1,y);
W[2][2] = sa(xs, downright);
W[2][3] = dy(x1, y1);
W[3][0] = dx(x1, y);
W[3][1] = dxy(x1, y);
W[3][2] = dx(x1, y1);
W[3][3] = dxy(x1, y1);
for(i=0; i<4; ++i)
{
for(j=0; j<4; ++j)
{
W1[j][i] = ig[j] * W[0][i];
for(k=1; k<4; ++k)
{
W1[j][i] += ig[j+4*k] * W[k][i];
}
}
}
for(i=0; i<4; ++i)
{
for(j=0; j<4; ++j)
{
W[j][i] = ig[i] * W1[j][0];
for(k=1; k<4; ++k)
{
W[j][i] += ig[4*k+i] * W1[j][k];
}
}
}
TMPTYPE a1,a2,a3,a4;
yyd = xd;
for(v=ov, yy=oy; v<1.0; v+=dv, ++yyd.y, ++yy)
{
a1 = W[0][0] + v * (W[0][1] +
v * (W[0][2] + v * W[0][3]));
a2 = W[1][0] + v * (W[1][1] +
v * (W[1][2] + v * W[1][3]));
a3 = W[2][0] + v * (W[2][1] +
v * (W[2][2] + v * W[2][3]));
a4 = W[3][0] + v * (W[3][1] +
v * (W[3][2] + v * W[3][3]));
xxd = yyd;
for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
{
da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (
a3 + u * a4))), xxd);
}
if(xx == wnew-1)
{
da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4),
xxd);
}
}
if(yy == hnew-1)
{
a1 = W[0][0] + W[0][1] + W[0][2] + W[0][3];
a2 = W[1][0] + W[1][1] + W[1][2] + W[1][3];
a3 = W[2][0] + W[2][1] + W[2][2] + W[2][3];
a4 = W[3][0] + W[3][1] + W[3][2] + W[3][3];
DestIterator xxd = yyd;
for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
{
da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (
a3 + u * a4))), xxd);
}
if(xx == wnew-1)
{
da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4),
xxd);
}
}
ou = u;
ox = xx;
}
ov = v;
oy = yy;
}
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void
resizeImageSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccesso
r sa,
DestIterator id, DestIterator idend, DestAccessor da)
{
int w = iend.x - is.x;
int h = iend.y - is.y;
int wnew = idend.x - id.x;
int hnew = idend.y - id.y;
vigra_precondition((w > 3) && (h > 3),
"resizeImageSplineInterpolation(): "
"Source image too small.\n");
vigra_precondition((wnew > 1) && (hnew > 1),
"resizeImageSplineInterpolation(): "
"Destination image too small.\n");
double scale = 2.0;
if(wnew < w || hnew < h)
{
typedef typename SrcAccessor::value_type SRCVT;
typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
BasicImage<TMPTYPE> t(w,h);
TMPITER it = t.upperLeft();
if(wnew < w)
{
recursiveSmoothX(is, iend, sa,
it, t.accessor(), (double)w/wnew/scale);
if(hnew < h)
{
recursiveSmoothY(it, t.lowerRight(), t.accessor(),
it, t.accessor(), (double)h/hnew/scale);
}
}
else
{
recursiveSmoothY(is, iend, sa,
it, t.accessor(), (double)h/hnew/scale);
}
resizeImageInternalSplineInterpolation(it, t.lowerRight(), t.access
or(),
id, idend, da);
}
else
{
resizeImageInternalSplineInterpolation(is, iend, sa, id, idend, da)
;
}
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline
void
resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor
> src,
triple<DestIterator, DestIterator, DestAccessor> dest
)
{ {
resizeImageSplineInterpolation(src.first, src.second, src.third, resizeImageCoscotInterpolation(srcImageRange(src),
dest.first, dest.second, dest.third); destImageRange(dest));
} }
#endif // old algorithm version
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_RESIZEIMAGE_HXX #endif // VIGRA_RESIZEIMAGE_HXX
 End of changes. 62 change blocks. 
508 lines changed or deleted 218 lines changed or added


 rf_algorithm.hxx   rf_algorithm.hxx 
skipping to change at line 35 skipping to change at line 35
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_RF_ALGORITHM_HXX
#define VIGRA_RF_ALGORITHM_HXX #define VIGRA_RF_ALGORITHM_HXX
#include <vector> #include <vector>
#include "splices.hxx" #include "splices.hxx"
#include <queue> #include <queue>
#include <fstream> #include <fstream>
namespace vigra namespace vigra
{ {
namespace rf namespace rf
{ {
/** This namespace contains all algorithms developed for feature /** This namespace contains all algorithms developed for feature
skipping to change at line 162 skipping to change at line 162
class ErrorRateCallBack> class ErrorRateCallBack>
bool init(FeatureT const & all_features, bool init(FeatureT const & all_features,
ResponseT const & response, ResponseT const & response,
Iter b, Iter b,
Iter e, Iter e,
ErrorRateCallBack errorcallback) ErrorRateCallBack errorcallback)
{ {
bool ret_ = init(all_features, response, errorcallback); bool ret_ = init(all_features, response, errorcallback);
if(!ret_) if(!ret_)
return false; return false;
vigra_precondition(std::distance(b, e) == (std::ptrdiff_t)selected. size(), vigra_precondition(std::distance(b, e) == static_cast<std::ptrdiff_ t>(selected.size()),
"Number of features in ranking != number of feat ures matrix"); "Number of features in ranking != number of feat ures matrix");
std::copy(b, e, selected.begin()); std::copy(b, e, selected.begin());
return true; return true;
} }
template<class FeatureT, template<class FeatureT,
class ResponseT, class ResponseT,
class Iter> class Iter>
bool init(FeatureT const & all_features, bool init(FeatureT const & all_features,
ResponseT const & response, ResponseT const & response,
skipping to change at line 301 skipping to change at line 301
{ {
VariableSelectionResult::FeatureList_t & selected = result.sele cted; VariableSelectionResult::FeatureList_t & selected = result.sele cted;
VariableSelectionResult::ErrorList_t & errors = result.e rrors; VariableSelectionResult::ErrorList_t & errors = result.e rrors;
VariableSelectionResult::Pivot_t & pivot = result.pivo t; VariableSelectionResult::Pivot_t & pivot = result.pivo t;
int featureCount = features.shape(1); int featureCount = features.shape(1);
// initialize result struct if in use for the first time // initialize result struct if in use for the first time
if(!result.init(features, response, errorcallback)) if(!result.init(features, response, errorcallback))
{ {
//result is being reused just ensure that the number of features is //result is being reused just ensure that the number of features is
//the same. //the same.
vigra_precondition((int)selected.size() == featureCount, vigra_precondition(static_cast<int>(selected.size()) == featureCoun t,
"forward_selection(): Number of features in Feat ure " "forward_selection(): Number of features in Feat ure "
"matrix and number of features in previously use d " "matrix and number of features in previously use d "
"result struct mismatch!"); "result struct mismatch!");
} }
int not_selected_size = std::distance(pivot, selected.end()); int not_selected_size = std::distance(pivot, selected.end());
while(not_selected_size > 1) while(not_selected_size > 1)
{ {
std::vector<double> current_errors; std::vector<double> current_errors;
VariableSelectionResult::Pivot_t next = pivot; VariableSelectionResult::Pivot_t next = pivot;
skipping to change at line 402 skipping to change at line 402
int featureCount = features.shape(1); int featureCount = features.shape(1);
VariableSelectionResult::FeatureList_t & selected = result.sele cted; VariableSelectionResult::FeatureList_t & selected = result.sele cted;
VariableSelectionResult::ErrorList_t & errors = result.e rrors; VariableSelectionResult::ErrorList_t & errors = result.e rrors;
VariableSelectionResult::Pivot_t & pivot = result.pivo t; VariableSelectionResult::Pivot_t & pivot = result.pivo t;
// initialize result struct if in use for the first time // initialize result struct if in use for the first time
if(!result.init(features, response, errorcallback)) if(!result.init(features, response, errorcallback))
{ {
//result is being reused just ensure that the number of features is //result is being reused just ensure that the number of features is
//the same. //the same.
vigra_precondition((int)selected.size() == featureCount, vigra_precondition(static_cast<int>(selected.size()) == featureCoun t,
"backward_elimination(): Number of features in F eature " "backward_elimination(): Number of features in F eature "
"matrix and number of features in previously use d " "matrix and number of features in previously use d "
"result struct mismatch!"); "result struct mismatch!");
} }
pivot = selected.end() - 1; pivot = selected.end() - 1;
int selected_size = std::distance(selected.begin(), pivot); int selected_size = std::distance(selected.begin(), pivot);
while(selected_size > 1) while(selected_size > 1)
{ {
VariableSelectionResult::Pivot_t next = selected.begin(); VariableSelectionResult::Pivot_t next = selected.begin();
skipping to change at line 498 skipping to change at line 498
{ {
VariableSelectionResult::FeatureList_t & selected = result.sele cted; VariableSelectionResult::FeatureList_t & selected = result.sele cted;
VariableSelectionResult::ErrorList_t & errors = result.e rrors; VariableSelectionResult::ErrorList_t & errors = result.e rrors;
VariableSelectionResult::Pivot_t & iter = result.pivot ; VariableSelectionResult::Pivot_t & iter = result.pivot ;
int featureCount = features.shape(1); int featureCount = features.shape(1);
// initialize result struct if in use for the first time // initialize result struct if in use for the first time
if(!result.init(features, response, errorcallback)) if(!result.init(features, response, errorcallback))
{ {
//result is being reused just ensure that the number of features is //result is being reused just ensure that the number of features is
//the same. //the same.
vigra_precondition((int)selected.size() == featureCount, vigra_precondition(static_cast<int>(selected.size()) == featureCoun t,
"forward_selection(): Number of features in Feat ure " "forward_selection(): Number of features in Feat ure "
"matrix and number of features in previously use d " "matrix and number of features in previously use d "
"result struct mismatch!"); "result struct mismatch!");
} }
int ii = 0; int ii = 0;
for(; iter != selected.end(); ++iter) for(; iter != selected.end(); ++iter)
{ {
++ii; ++ii;
MultiArray<2, double> cur_feats; MultiArray<2, double> cur_feats;
skipping to change at line 725 skipping to change at line 725
#endif #endif
/**Perform single linkage clustering /**Perform single linkage clustering
* \param distance distance matrix used. \sa CorrelationVisitor * \param distance distance matrix used. \sa CorrelationVisitor
*/ */
template<class T, class C> template<class T, class C>
void cluster(MultiArrayView<2, T, C> distance) void cluster(MultiArrayView<2, T, C> distance)
{ {
MultiArray<2, T> dist(distance); MultiArray<2, T> dist(distance);
std::vector<std::pair<int, int> > addr; std::vector<std::pair<int, int> > addr;
typedef std::pair<int, int> Entry;
int index = 0; int index = 0;
for(int ii = 0; ii < distance.shape(0); ++ii) for(int ii = 0; ii < distance.shape(0); ++ii)
{ {
addr.push_back(std::make_pair(topology_.size(), ii)); addr.push_back(std::make_pair(topology_.size(), ii));
ClusterNode leaf(1, topology_, parameters_); ClusterNode leaf(1, topology_, parameters_);
leaf.set_index(index); leaf.set_index(index);
++index; ++index;
leaf.columns_begin()[0] = ii; leaf.columns_begin()[0] = ii;
} }
skipping to change at line 814 skipping to change at line 813
{ {
parent.child(1) = (addr.begin()+ii_min)->first; parent.child(1) = (addr.begin()+ii_min)->first;
parent.child(0) = (addr.begin()+jj_min)->first; parent.child(0) = (addr.begin()+jj_min)->first;
(addr.begin()+jj_min)->first = cur_addr; (addr.begin()+jj_min)->first = cur_addr;
ii_keep = jj_min; ii_keep = jj_min;
to_desc = (addr.begin()+ii_min)->second; to_desc = (addr.begin()+ii_min)->second;
addr.erase(addr.begin()+ii_min); addr.erase(addr.begin()+ii_min);
} }
//update distances; //update distances;
for(int jj = 0 ; jj < (int)addr.size(); ++jj) for(int jj = 0 ; jj < static_cast<int>(addr.size()); ++jj)
{ {
if(jj == ii_keep) if(jj == ii_keep)
continue; continue;
double bla = dist_func( double bla = dist_func(
dist(to_desc, (addr.begin()+jj)->second), dist(to_desc, (addr.begin()+jj)->second),
dist((addr.begin()+ii_keep)->second, dist((addr.begin()+ii_keep)->second,
(addr.begin()+jj)->second)); (addr.begin()+jj)->second));
dist((addr.begin()+ii_keep)->second, dist((addr.begin()+ii_keep)->second,
(addr.begin()+jj)->second) = bla; (addr.begin()+jj)->second) = bla;
skipping to change at line 1319 skipping to change at line 1318
for(int ii = 0; ii < in.size(); ++ii) for(int ii = 0; ii < in.size(); ++ii)
mymap[in[ii]] = ii; mymap[in[ii]] = ii;
for(std::map<double, int>::reverse_iterator iter = mymap.rbegin(); iter != mymap.rend(); ++iter) for(std::map<double, int>::reverse_iterator iter = mymap.rbegin(); iter != mymap.rend(); ++iter)
{ {
out.push_back(iter->second); out.push_back(iter->second);
} }
} }
}//namespace algorithms }//namespace algorithms
}//namespace rf }//namespace rf
}//namespace vigra }//namespace vigra
#endif //VIGRA_RF_ALGORITHM_HXX
 End of changes. 9 change blocks. 
7 lines changed or deleted 6 lines changed or added


 rf_common.hxx   rf_common.hxx 
skipping to change at line 286 skipping to change at line 286
PUSH(0); PUSH(0);
} }
PUSH(tree_count_); PUSH(tree_count_);
PUSH(min_split_node_size_); PUSH(min_split_node_size_);
PUSH(predict_weighted_); PUSH(predict_weighted_);
#undef PUSH #undef PUSH
} }
void make_from_map(map_type & in) // -> const: .operator[] -> .find void make_from_map(map_type & in) // -> const: .operator[] -> .find
{ {
typedef MultiArrayShape<2>::type Shp;
#define PULL(item_, type_) item_ = type_(in[#item_][0]); #define PULL(item_, type_) item_ = type_(in[#item_][0]);
#define PULLBOOL(item_, type_) item_ = type_(in[#item_][0] > 0); #define PULLBOOL(item_, type_) item_ = type_(in[#item_][0] > 0);
PULL(training_set_proportion_,double); PULL(training_set_proportion_,double);
PULL(training_set_size_, int); PULL(training_set_size_, int);
PULL(mtry_, int); PULL(mtry_, int);
PULL(tree_count_, int); PULL(tree_count_, int);
PULL(min_split_node_size_, int); PULL(min_split_node_size_, int);
PULLBOOL(sample_with_replacement_, bool); PULLBOOL(sample_with_replacement_, bool);
PULLBOOL(prepare_online_learning_, bool); PULLBOOL(prepare_online_learning_, bool);
PULLBOOL(predict_weighted_, bool); PULLBOOL(predict_weighted_, bool);
skipping to change at line 311 skipping to change at line 310
PULL(mtry_switch_, (RF_OptionTag)(int)); PULL(mtry_switch_, (RF_OptionTag)(int));
/*don't pull*/ /*don't pull*/
//PULL(mtry_func_!=0, int); //PULL(mtry_func_!=0, int);
//PULL(training_set_func,int); //PULL(training_set_func,int);
#undef PULL #undef PULL
#undef PULLBOOL #undef PULLBOOL
} }
void make_map(map_type & in) const void make_map(map_type & in) const
{ {
typedef MultiArrayShape<2>::type Shp;
#define PUSH(item_, type_) in[#item_] = double_array(1, double(item _)); #define PUSH(item_, type_) in[#item_] = double_array(1, double(item _));
#define PUSHFUNC(item_, type_) in[#item_] = double_array(1, double( item_!=0)); #define PUSHFUNC(item_, type_) in[#item_] = double_array(1, double( item_!=0));
PUSH(training_set_proportion_,double); PUSH(training_set_proportion_,double);
PUSH(training_set_size_, int); PUSH(training_set_size_, int);
PUSH(mtry_, int); PUSH(mtry_, int);
PUSH(tree_count_, int); PUSH(tree_count_, int);
PUSH(min_split_node_size_, int); PUSH(min_split_node_size_, int);
PUSH(sample_with_replacement_, bool); PUSH(sample_with_replacement_, bool);
PUSH(prepare_online_learning_, bool); PUSH(prepare_online_learning_, bool);
PUSH(predict_weighted_, bool); PUSH(predict_weighted_, bool);
skipping to change at line 681 skipping to change at line 679
return result; return result;
} }
bool operator!=(ProblemSpec & rhs) bool operator!=(ProblemSpec & rhs)
{ {
return !(*this == rhs); return !(*this == rhs);
} }
size_t serialized_size() const size_t serialized_size() const
{ {
return 9 + class_count_ *int(is_weighted_+1); return 10 + class_count_ *int(is_weighted_+1);
} }
template<class Iter> template<class Iter>
void unserialize(Iter const & begin, Iter const & end) void unserialize(Iter const & begin, Iter const & end)
{ {
Iter iter = begin; Iter iter = begin;
vigra_precondition(end - begin >= 9, vigra_precondition(end - begin >= 10,
"ProblemSpec::unserialize():" "ProblemSpec::unserialize():"
"wrong number of parameters"); "wrong number of parameters");
#define PULL(item_, type_) item_ = type_(*iter); ++iter; #define PULL(item_, type_) item_ = type_(*iter); ++iter;
PULL(column_count_,int); PULL(column_count_,int);
PULL(class_count_, int); PULL(class_count_, int);
vigra_precondition(end - begin >= 9 + class_count_, vigra_precondition(end - begin >= 10 + class_count_,
"ProblemSpec::unserialize(): 1"); "ProblemSpec::unserialize(): 1");
PULL(row_count_, int); PULL(row_count_, int);
PULL(actual_mtry_,int); PULL(actual_mtry_,int);
PULL(actual_msample_, int); PULL(actual_msample_, int);
PULL(problem_type_, Problem_t); PULL(problem_type_, Problem_t);
PULL(is_weighted_, int); PULL(is_weighted_, int);
PULL(used_, int); PULL(used_, int);
PULL(precision_, double); PULL(precision_, double);
PULL(response_size_, int); PULL(response_size_, int);
if(is_weighted_) if(is_weighted_)
{ {
vigra_precondition(end - begin == 9 + 2*class_count_, vigra_precondition(end - begin == 10 + 2*class_count_,
"ProblemSpec::unserialize(): 2"); "ProblemSpec::unserialize(): 2");
class_weights_.insert(class_weights_.end(), class_weights_.insert(class_weights_.end(),
iter, iter,
iter + class_count_); iter + class_count_);
iter += class_count_; iter += class_count_;
} }
classes.insert(classes.end(), iter, end); classes.insert(classes.end(), iter, end);
#undef PULL #undef PULL
} }
skipping to change at line 751 skipping to change at line 749
iter += class_count_; iter += class_count_;
} }
std::copy(classes.begin(), std::copy(classes.begin(),
classes.end(), classes.end(),
iter); iter);
#undef PUSH #undef PUSH
} }
void make_from_map(map_type & in) // -> const: .operator[] -> .find void make_from_map(map_type & in) // -> const: .operator[] -> .find
{ {
typedef MultiArrayShape<2>::type Shp;
#define PULL(item_, type_) item_ = type_(in[#item_][0]); #define PULL(item_, type_) item_ = type_(in[#item_][0]);
PULL(column_count_,int); PULL(column_count_,int);
PULL(class_count_, int); PULL(class_count_, int);
PULL(row_count_, int); PULL(row_count_, int);
PULL(actual_mtry_,int); PULL(actual_mtry_,int);
PULL(actual_msample_, int); PULL(actual_msample_, int);
PULL(problem_type_, (Problem_t)int); PULL(problem_type_, (Problem_t)int);
PULL(is_weighted_, int); PULL(is_weighted_, int);
PULL(used_, int); PULL(used_, int);
PULL(precision_, double); PULL(precision_, double);
PULL(response_size_, int); PULL(response_size_, int);
class_weights_ = in["class_weights_"]; class_weights_ = in["class_weights_"];
#undef PUSH #undef PULL
} }
void make_map(map_type & in) const void make_map(map_type & in) const
{ {
typedef MultiArrayShape<2>::type Shp;
#define PUSH(item_) in[#item_] = double_array(1, double(item_)); #define PUSH(item_) in[#item_] = double_array(1, double(item_));
PUSH(column_count_); PUSH(column_count_);
PUSH(class_count_) PUSH(class_count_)
PUSH(row_count_); PUSH(row_count_);
PUSH(actual_mtry_); PUSH(actual_mtry_);
PUSH(actual_msample_); PUSH(actual_msample_);
PUSH(problem_type_); PUSH(problem_type_);
PUSH(is_weighted_); PUSH(is_weighted_);
PUSH(used_); PUSH(used_);
PUSH(precision_); PUSH(precision_);
skipping to change at line 812 skipping to change at line 808
return *this; return *this;
} }
/**\brief supply with class labels - /**\brief supply with class labels -
* *
* the preprocessor will not calculate the labels needed in this case. * the preprocessor will not calculate the labels needed in this case.
*/ */
template<class C_Iter> template<class C_Iter>
ProblemSpec & classes_(C_Iter begin, C_Iter end) ProblemSpec & classes_(C_Iter begin, C_Iter end)
{ {
classes.clear();
int size = end-begin; int size = end-begin;
for(int k=0; k<size; ++k, ++begin) for(int k=0; k<size; ++k, ++begin)
classes.push_back(detail::RequiresExplicitCast<LabelType>::cast (*begin)); classes.push_back(detail::RequiresExplicitCast<LabelType>::cast (*begin));
class_count_ = size; class_count_ = size;
return *this; return *this;
} }
/** \brief supply with class weights - /** \brief supply with class weights -
* *
* this is the only case where you would really have to * this is the only case where you would really have to
* create a ProblemSpec object. * create a ProblemSpec object.
*/ */
template<class W_Iter> template<class W_Iter>
ProblemSpec & class_weights(W_Iter begin, W_Iter end) ProblemSpec & class_weights(W_Iter begin, W_Iter end)
{ {
class_weights_.clear();
class_weights_.insert(class_weights_.end(), begin, end); class_weights_.insert(class_weights_.end(), begin, end);
is_weighted_ = true; is_weighted_ = true;
return *this; return *this;
} }
void clear() void clear()
{ {
used_ = false; used_ = false;
classes.clear(); classes.clear();
class_weights_.clear(); class_weights_.clear();
 End of changes. 11 change blocks. 
9 lines changed or deleted 7 lines changed or added


 rf_earlystopping.hxx   rf_earlystopping.hxx 
#ifndef RF_EARLY_STOPPING_P_HXX #ifndef RF_EARLY_STOPPING_P_HXX
#define RF_EARLY_STOPPING_P_HXX #define RF_EARLY_STOPPING_P_HXX
#include <cmath> #include <cmath>
#include <stdexcept>
#include "rf_common.hxx" #include "rf_common.hxx"
namespace vigra namespace vigra
{ {
#if 0 #if 0
namespace es_detail namespace es_detail
{ {
template<class T> template<class T>
T power(T const & in, int n) T power(T const & in, int n)
skipping to change at line 301 skipping to change at line 302
*/ */
ArrayVector<double> depths; ArrayVector<double> depths;
double binomial(int N, int k, double p) double binomial(int N, int k, double p)
{ {
// return n_choose_k(N, k) * es_detail::power(p, k) *es_detail::powe r(1 - p, N-k); // return n_choose_k(N, k) * es_detail::power(p, k) *es_detail::powe r(1 - p, N-k);
return n_choose_k(N, k) * std::pow(p, k) * std::pow(1 - p, N-k); return n_choose_k(N, k) * std::pow(p, k) * std::pow(1 - p, N-k);
} }
template<class WeightIter, class T, class C> template<class WeightIter, class T, class C>
bool after_prediction(WeightIter iter, int k, MultiArrayView<2, T, C> bool after_prediction(WeightIter iter, int k,
prob, double totalCt) MultiArrayView<2, T, C> const &prob, double totalCt)
{ {
if(k == SB::tree_count_ -1) if(k == SB::tree_count_ -1)
{ {
depths.push_back(double(k+1)/double(SB::tree_count_)); depths.push_back(double(k+1)/double(SB::tree_count_));
return false; return false;
} }
if(k < 10) if(k < 10)
{ {
return false; return false;
} }
skipping to change at line 411 skipping to change at line 413
if(p >= 1-alpha_) if(p >= 1-alpha_)
{ {
depths.push_back(double(k+1)/double(SB::tree_count_)); depths.push_back(double(k+1)/double(SB::tree_count_));
return true; return true;
} }
return false; return false;
} }
}; };
class DepthAndSizeStopping: public StopBase
{
public:
int max_depth_;
int min_size_;
int max_depth_reached; //for debug maximum reached depth
DepthAndSizeStopping()
: max_depth_(NumericTraits<int>::max()), min_size_(0)
{}
/** Constructor DepthAndSize Criterion
* Stop growing the tree if a certain depth or size is reached or make
a
* leaf if the node is smaller than a certain size. Note this is checke
d
* before the split so it is still possible that smaller leafs are crea
ted
*/
DepthAndSizeStopping(int depth, int size) :
max_depth_(depth <= 0 ? NumericTraits<int>::max() : depth),
min_size_(size)
{}
template<class T>
void set_external_parameters(ProblemSpec<T> const &,
int tree_count = 0, bool /* is_weighted_ */= false)
{}
template<class Region>
bool operator()(Region& region)
{
if (region.depth() > max_depth_)
throw std::runtime_error("violation in the stopping criterion");
return (region.depth() >= max_depth_) || (region.size() < min_size_
) ;
}
template<class WeightIter, class T, class C>
bool after_prediction(WeightIter, int /* k */,
MultiArrayView<2, T, C> const &/* prob */, double /* totalCt */
)
{
return true;
}
};
} //namespace vigra; } //namespace vigra;
#endif //RF_EARLY_STOPPING_P_HXX #endif //RF_EARLY_STOPPING_P_HXX
 End of changes. 3 change blocks. 
2 lines changed or deleted 54 lines changed or added


 rf_preprocessing.hxx   rf_preprocessing.hxx 
skipping to change at line 40 skipping to change at line 40
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_RF_PREPROCESSING_HXX #ifndef VIGRA_RF_PREPROCESSING_HXX
#define VIGRA_RF_PREPROCESSING_HXX #define VIGRA_RF_PREPROCESSING_HXX
#include <limits> #include <limits>
#include <vigra/mathutil.hxx>
#include "rf_common.hxx" #include "rf_common.hxx"
namespace vigra namespace vigra
{ {
/** Class used while preprocessing (currently used only during learn) /** Class used while preprocessing (currently used only during learn)
* *
* This class is internally used by the Random Forest learn function. * This class is internally used by the Random Forest learn function.
* Different split functors may need to process the data in different manne rs * Different split functors may need to process the data in different manne rs
* (i.e., regression labels that should not be touched and classification * (i.e., regression labels that should not be touched and classification
skipping to change at line 110 skipping to change at line 111
} }
// set correct value for msample // set correct value for msample
switch(options.training_set_calc_switch_) switch(options.training_set_calc_switch_)
{ {
case RF_CONST: case RF_CONST:
ext_param.actual_msample_ = ext_param.actual_msample_ =
options.training_set_size_; options.training_set_size_;
break; break;
case RF_PROPORTIONAL: case RF_PROPORTIONAL:
ext_param.actual_msample_ = ext_param.actual_msample_ =
(int)std::ceil( options.training_set_proportion_ * static_cast<int>(std::ceil(options.training_set_proport
ext_param.row_count_); ion_ *
ext_param.row_count_));
break; break;
case RF_FUNCTION: case RF_FUNCTION:
ext_param.actual_msample_ = ext_param.actual_msample_ =
options.training_set_func_(ext_param.row_count_); options.training_set_func_(ext_param.row_count_);
break; break;
default: default:
vigra_precondition(1!= 1, "unexpected error"); vigra_precondition(1!= 1, "unexpected error");
} }
} }
/* Returns true if MultiArray contains NaNs /* Returns true if MultiArray contains NaNs
*/ */
template<unsigned int N, class T, class C> template<unsigned int N, class T, class C>
bool contains_nan(MultiArrayView<N, T, C> const & in) bool contains_nan(MultiArrayView<N, T, C> const & in)
{ {
for(int ii = 0; ii < in.size(); ++ii) typedef typename MultiArrayView<N, T, C>::const_iterator Iter;
if(in[ii] != in[ii]) Iter i = in.begin(), end = in.end();
for(; i != end; ++i)
if(isnan(NumericTraits<T>::toRealPromote(*i)))
return true; return true;
return false; return false;
} }
/* Returns true if MultiArray contains Infs /* Returns true if MultiArray contains Infs
*/ */
template<unsigned int N, class T, class C> template<unsigned int N, class T, class C>
bool contains_inf(MultiArrayView<N, T, C> const & in) bool contains_inf(MultiArrayView<N, T, C> const & in)
{ {
if(!std::numeric_limits<T>::has_infinity) if(!std::numeric_limits<T>::has_infinity)
return false; return false;
for(int ii = 0; ii < in.size(); ++ii) typedef typename MultiArrayView<N, T, C>::const_iterator Iter;
if(in[ii] == std::numeric_limits<T>::infinity()) Iter i = in.begin(), end = in.end();
for(; i != end; ++i)
if(abs(*i) == std::numeric_limits<T>::infinity())
return true; return true;
return false; return false;
} }
} // namespace detail } // namespace detail
/** Preprocessor used during Classification /** Preprocessor used during Classification
* *
* This class converts the labels int Integral labels which are used by the * This class converts the labels int Integral labels which are used by the
* standard split functor to address memory in the node objects. * standard split functor to address memory in the node objects.
*/ */
skipping to change at line 174 skipping to change at line 179
MultiArrayView<2, LabelInt> strata_; MultiArrayView<2, LabelInt> strata_;
template<class T> template<class T>
Processor(MultiArrayView<2, T1, C1>const & features, Processor(MultiArrayView<2, T1, C1>const & features,
MultiArrayView<2, T2, C2>const & response, MultiArrayView<2, T2, C2>const & response,
RandomForestOptions &options, RandomForestOptions &options,
ProblemSpec<T> &ext_param) ProblemSpec<T> &ext_param)
: :
features_( features) // do not touch the features. features_( features) // do not touch the features.
{ {
vigra_precondition(!detail::contains_nan(features), "Processor(): F vigra_precondition(!detail::contains_nan(features), "RandomForest()
eature Matrix " : Feature matrix "
"Contains NaNs") "contains NaNs")
; ;
vigra_precondition(!detail::contains_nan(response), "Processor(): R vigra_precondition(!detail::contains_nan(response), "RandomForest()
esponse " : Response "
"Contains NaNs") "contains NaNs")
; ;
vigra_precondition(!detail::contains_inf(features), "Processor(): F vigra_precondition(!detail::contains_inf(features), "RandomForest()
eature Matrix " : Feature matrix "
"Contains inf"); "contains inf");
vigra_precondition(!detail::contains_inf(response), "Processor(): R vigra_precondition(!detail::contains_inf(response), "RandomForest()
esponse " : Response "
"Contains inf"); "contains inf");
// set some of the problem specific parameters // set some of the problem specific parameters
ext_param.column_count_ = features.shape(1); ext_param.column_count_ = features.shape(1);
ext_param.row_count_ = features.shape(0); ext_param.row_count_ = features.shape(0);
ext_param.problem_type_ = CLASSIFICATION; ext_param.problem_type_ = CLASSIFICATION;
ext_param.used_ = true; ext_param.used_ = true;
intLabels_.reshape(response.shape()); intLabels_.reshape(response.shape());
//get the class labels //get the class labels
if(ext_param.class_count_ == 0) if(ext_param.class_count_ == 0)
{ {
skipping to change at line 204 skipping to change at line 209
std::set<T2> labelToInt; std::set<T2> labelToInt;
for(MultiArrayIndex k = 0; k < features.shape(0); ++k) for(MultiArrayIndex k = 0; k < features.shape(0); ++k)
labelToInt.insert(response(k,0)); labelToInt.insert(response(k,0));
std::vector<T2> tmp_(labelToInt.begin(), labelToInt.end()); std::vector<T2> tmp_(labelToInt.begin(), labelToInt.end());
ext_param.classes_(tmp_.begin(), tmp_.end()); ext_param.classes_(tmp_.begin(), tmp_.end());
} }
for(MultiArrayIndex k = 0; k < features.shape(0); ++k) for(MultiArrayIndex k = 0; k < features.shape(0); ++k)
{ {
if(std::find(ext_param.classes.begin(), ext_param.classes.end() , response(k,0)) == ext_param.classes.end()) if(std::find(ext_param.classes.begin(), ext_param.classes.end() , response(k,0)) == ext_param.classes.end())
{ {
throw std::runtime_error("unknown label type"); throw std::runtime_error("RandomForest(): invalid label in training data.");
} }
else else
intLabels_(k, 0) = std::find(ext_param.classes.begin(), ext _param.classes.end(), response(k,0)) intLabels_(k, 0) = std::find(ext_param.classes.begin(), ext _param.classes.end(), response(k,0))
- ext_param.classes.begin(); - ext_param.classes.begin();
} }
// set class weights // set class weights
if(ext_param.class_weights_.size() == 0) if(ext_param.class_weights_.size() == 0)
{ {
ArrayVector<T2> ArrayVector<T2>
tmp((std::size_t)ext_param.class_count_, tmp(static_cast<std::size_t>(ext_param.class_count_),
NumericTraits<T2>::one()); NumericTraits<T2>::one());
ext_param.class_weights(tmp.begin(), tmp.end()); ext_param.class_weights(tmp.begin(), tmp.end());
} }
// set mtry and msample // set mtry and msample
detail::fill_external_parameters(options, ext_param); detail::fill_external_parameters(options, ext_param);
// set strata // set strata
strata_ = intLabels_; strata_ = intLabels_;
skipping to change at line 236 skipping to change at line 241
/** Access the processed features /** Access the processed features
*/ */
MultiArrayView<2, T1, C1>const & features() MultiArrayView<2, T1, C1>const & features()
{ {
return features_; return features_;
} }
/** Access processed labels /** Access processed labels
*/ */
MultiArrayView<2, LabelInt>& response() MultiArrayView<2, LabelInt> response()
{ {
return intLabels_; return MultiArrayView<2, LabelInt>(intLabels_);
} }
/** Access processed strata /** Access processed strata
*/ */
ArrayVectorView < LabelInt> strata() ArrayVectorView < LabelInt> strata()
{ {
return ArrayVectorView<LabelInt>(intLabels_.size(), intLabels_.data ()); return ArrayVectorView<LabelInt>(intLabels_.size(), intLabels_.data ());
} }
/** Access strata fraction sized - not used currently /** Access strata fraction sized - not used currently
 End of changes. 9 change blocks. 
24 lines changed or deleted 30 lines changed or added


 rf_region.hxx   rf_region.hxx 
skipping to change at line 114 skipping to change at line 114
size_ = oob_size_ = 0; size_ = oob_size_ = 0;
leftParent = DecisionTreeNoParent; leftParent = DecisionTreeNoParent;
rightParent = DecisionTreeNoParent; rightParent = DecisionTreeNoParent;
classCountsIsValid = false; classCountsIsValid = false;
} }
bool isPure() bool isPure()
{ {
int num = 0; int num = 0;
for(int ii = 0; ii < (int)classCounts().size(); ++ii) for(int ii = 0; ii < static_cast<int>(classCounts().size()); ++ii)
{ {
num += classCounts()[ii] > 0; num += classCounts()[ii] > 0;
} }
return num <= 1; return num <= 1;
} }
int& operator[](int i) int& operator[](int i)
{ {
return *(begin_+i); return *(begin_+i);
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 rf_ridge_split.hxx   rf_ridge_split.hxx 
skipping to change at line 134 skipping to change at line 134
template<class T, class C, class T2, class C2, class Region, class Rand om> template<class T, class C, class T2, class C2, class Region, class Rand om>
int findBestSplit(MultiArrayView<2, T, C> features, int findBestSplit(MultiArrayView<2, T, C> features,
MultiArrayView<2, T2, C2> multiClassLabels, MultiArrayView<2, T2, C2> multiClassLabels,
Region & region, Region & region,
ArrayVector<Region>& childRegions, ArrayVector<Region>& childRegions,
Random & randint) Random & randint)
{ {
//std::cerr << "Split called" << std::endl; //std::cerr << "Split called" << std::endl;
typedef typename Region::IndexIterator IndexIterator;
typedef typename MultiArrayView <2, T, C>::difference_type fShape; typedef typename MultiArrayView <2, T, C>::difference_type fShape;
typedef typename MultiArrayView <2, T2, C2>::difference_type lShape; typedef typename MultiArrayView <2, T2, C2>::difference_type lShape;
typedef typename MultiArrayView <2, double>::difference_type dShape; typedef typename MultiArrayView <2, double>::difference_type dShape;
// calculate things that haven't been calculated yet. // calculate things that haven't been calculated yet.
// std::cout << "start" << std::endl; // std::cout << "start" << std::endl;
if(std::accumulate(region.classCounts().begin(), if(std::accumulate(region.classCounts().begin(),
region.classCounts().end(), 0) != region.size()) region.classCounts().end(), 0) != region.size())
{ {
RandomForestClassCounter< MultiArrayView<2,T2, C2>, RandomForestClassCounter< MultiArrayView<2,T2, C2>,
skipping to change at line 166 skipping to change at line 165
// select columns to be tried. // select columns to be tried.
for(int ii = 0; ii < SB::ext_param_.actual_mtry_; ++ii) for(int ii = 0; ii < SB::ext_param_.actual_mtry_; ++ii)
std::swap(splitColumns[ii], std::swap(splitColumns[ii],
splitColumns[ii+ randint(features.shape(1) - ii)]); splitColumns[ii+ randint(features.shape(1) - ii)]);
//do implicit binary case //do implicit binary case
MultiArray<2, T2> labels(lShape(multiClassLabels.shape(0),1)); MultiArray<2, T2> labels(lShape(multiClassLabels.shape(0),1));
//number of classes should be >1, otherwise makeTerminalNode would ha ve been called //number of classes should be >1, otherwise makeTerminalNode would ha ve been called
int nNumClasses=0; int nNumClasses=0;
for(int n=0; n<(int)region.classCounts().size(); n++) for(int n=0; n<static_cast<int>(region.classCounts().size()); n++)
nNumClasses+=((region.classCounts()[n]>0) ? 1:0); nNumClasses+=((region.classCounts()[n]>0) ? 1:0);
//convert to binary case //convert to binary case
if(nNumClasses>2) if(nNumClasses>2)
{ {
int nMaxClass=0; int nMaxClass=0;
int nMaxClassCounts=0; int nMaxClassCounts=0;
for(int n=0; n<(int)region.classCounts().size(); n++) for(int n=0; n<static_cast<int>(region.classCounts().size()); n++)
{ {
//this should occur in any case: //this should occur in any case:
//we had more than two non-zero classes in order to get here //we had more than two non-zero classes in order to get here
if(region.classCounts()[n]>nMaxClassCounts) if(region.classCounts()[n]>nMaxClassCounts)
{ {
nMaxClassCounts=region.classCounts()[n]; nMaxClassCounts=region.classCounts()[n];
nMaxClass=n; nMaxClass=n;
} }
} }
 End of changes. 3 change blocks. 
3 lines changed or deleted 2 lines changed or added


 rf_split.hxx   rf_split.hxx 
skipping to change at line 165 skipping to change at line 165
CompileTimeError SplitFunctor__findBestSplit_member_was_not_defined ; CompileTimeError SplitFunctor__findBestSplit_member_was_not_defined ;
#endif #endif
return 0; return 0;
} }
/** Default action for creating a terminal Node. /** Default action for creating a terminal Node.
sets the Class probability of the remaining region according to sets the Class probability of the remaining region according to
the class histogram the class histogram
**/ **/
template<class T, class C, class T2,class C2, class Region, class Rando m> template<class T, class C, class T2,class C2, class Region, class Rando m>
int makeTerminalNode(MultiArrayView<2, T, C> features, int makeTerminalNode(MultiArrayView<2, T, C> /* features */,
MultiArrayView<2, T2, C2> labels, MultiArrayView<2, T2, C2> /* labels */,
Region & region, Region & region,
Random randint) Random /* randint */)
{ {
Node<e_ConstProbNode> ret(t_data, p_data); Node<e_ConstProbNode> ret(t_data, p_data);
node_ = ret; node_ = ret;
if(ext_param_.class_weights_.size() != region.classCounts().size()) if(ext_param_.class_weights_.size() != region.classCounts().size())
{ {
std::copy(region.classCounts().begin(), std::copy(region.classCounts().begin(),
region.classCounts().end(), region.classCounts().end(),
ret.prob_begin()); ret.prob_begin());
} }
else else
skipping to change at line 1080 skipping to change at line 1080
childRegions[1].classCounts() = bgfunc.bestCurrentCounts[1] ; childRegions[1].classCounts() = bgfunc.bestCurrentCounts[1] ;
childRegions[0].classCountsIsValid = true; childRegions[0].classCountsIsValid = true;
childRegions[1].classCountsIsValid = true; childRegions[1].classCountsIsValid = true;
bestSplitIndex = k; bestSplitIndex = k;
num2try = SB::ext_param_.actual_mtry_; num2try = SB::ext_param_.actual_mtry_;
} }
} }
//std::cerr << current_min_gini << "curr " << region_gini_ << std:: endl; //std::cerr << current_min_gini << "curr " << region_gini_ << std:: endl;
// did not find any suitable split // did not find any suitable split
// FIXME: this is wrong: sometimes we must execute bad splits to ma
ke progress,
// especially near the root.
if(closeAtTolerance(current_min_gini, region_gini_)) if(closeAtTolerance(current_min_gini, region_gini_))
return this->makeTerminalNode(features, labels, region, randin t); return this->makeTerminalNode(features, labels, region, randin t);
//create a Node for output //create a Node for output
Node<i_ThresholdNode> node(SB::t_data, SB::p_data); Node<i_ThresholdNode> node(SB::t_data, SB::p_data);
SB::node_ = node; SB::node_ = node;
node.threshold() = min_thresholds_[bestSplitIndex]; node.threshold() = min_thresholds_[bestSplitIndex];
node.column() = splitColumns[bestSplitIndex]; node.column() = splitColumns[bestSplitIndex];
// partition the range according to the best dimension // partition the range according to the best dimension
 End of changes. 2 change blocks. 
4 lines changed or deleted 7 lines changed or added


 rf_visitors.hxx   rf_visitors.hxx 
skipping to change at line 160 skipping to change at line 160
/** do something after each tree has been learned /** do something after each tree has been learned
* *
* \param rf reference to the random forest object that called t his * \param rf reference to the random forest object that called t his
* visitor * visitor
* \param pr reference to the preprocessor that processed the in put * \param pr reference to the preprocessor that processed the in put
* \param sm reference to the sampler object * \param sm reference to the sampler object
* \param st reference to the first stack entry * \param st reference to the first stack entry
* \param index index of current tree * \param index index of current tree
*/ */
template<class RF, class PR, class SM, class ST> template<class RF, class PR, class SM, class ST>
void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index) void visit_after_tree(RF & rf, PR & pr, SM & sm, ST & st, int index)
{} {}
/** do something after all trees have been learned /** do something after all trees have been learned
* *
* \param rf reference to the random forest object that called t his * \param rf reference to the random forest object that called t his
* visitor * visitor
* \param pr reference to the preprocessor that processed the in put * \param pr reference to the preprocessor that processed the in put
*/ */
template<class RF, class PR> template<class RF, class PR>
void visit_at_end(RF const & rf, PR const & pr) void visit_at_end(RF const & rf, PR const & pr)
skipping to change at line 196 skipping to change at line 196
* \param index index in the topology_ array we currently are at * \param index index in the topology_ array we currently are at
* \param node_t type of node we have (will be e_.... - ) * \param node_t type of node we have (will be e_.... - )
* \param features feature matrix * \param features feature matrix
* \sa NodeTags; * \sa NodeTags;
* *
* you can create the node by using a switch on node_tag and using the * you can create the node by using a switch on node_tag and using the
* corresponding Node objects. Or - if you do not care about the type * corresponding Node objects. Or - if you do not care about the type
* use the NodeBase class. * use the NodeBase class.
*/ */
template<class TR, class IntT, class TopT,class Feat> template<class TR, class IntT, class TopT,class Feat>
void visit_external_node(TR & tr, IntT index, TopT node_t,Feat & featur es) void visit_external_node(TR & tr, IntT index, TopT node_t, Feat & featu res)
{} {}
/** do something when visiting a internal node after it has been learne d /** do something when visiting a internal node after it has been learne d
* *
* \sa visit_external_node * \sa visit_external_node
*/ */
template<class TR, class IntT, class TopT,class Feat> template<class TR, class IntT, class TopT,class Feat>
void visit_internal_node(TR & tr, IntT index, TopT node_t,Feat & featur es) void visit_internal_node(TR & /* tr */, IntT /* index */, TopT /* node_ t */, Feat & /* features */)
{} {}
/** return a double value. The value of the first /** return a double value. The value of the first
* visitor encountered that has a return value is returned with the * visitor encountered that has a return value is returned with the
* RandomForest::learn() method - or -1.0 if no return value visitor * RandomForest::learn() method - or -1.0 if no return value visitor
* existed. This functionality basically only exists so that the * existed. This functionality basically only exists so that the
* OOB - visitor can return the oob error rate like in the old version * OOB - visitor can return the oob error rate like in the old version
* of the random forest. * of the random forest.
*/ */
double return_val() double return_val()
skipping to change at line 606 skipping to change at line 606
//map for linear index of index_lists //map for linear index of index_lists
std::map<int,int> exterior_to_index; std::map<int,int> exterior_to_index;
}; };
//All trees //All trees
std::vector<TreeOnlineInformation> trees_online_information; std::vector<TreeOnlineInformation> trees_online_information;
/** Initialize, set the number of trees /** Initialize, set the number of trees
*/ */
template<class RF,class PR> template<class RF,class PR>
void visit_at_beginning(RF & rf,const PR & pr) void visit_at_beginning(RF & rf,const PR & /* pr */)
{ {
tree_id=0; tree_id=0;
trees_online_information.resize(rf.options_.tree_count_); trees_online_information.resize(rf.options_.tree_count_);
} }
/** Reset a tree /** Reset a tree
*/ */
void reset_tree(int tree_id) void reset_tree(int tree_id)
{ {
trees_online_information[tree_id].mag_distributions.clear(); trees_online_information[tree_id].mag_distributions.clear();
trees_online_information[tree_id].index_lists.clear(); trees_online_information[tree_id].index_lists.clear();
trees_online_information[tree_id].interior_to_index.clear(); trees_online_information[tree_id].interior_to_index.clear();
trees_online_information[tree_id].exterior_to_index.clear(); trees_online_information[tree_id].exterior_to_index.clear();
} }
/** simply increase the tree count /** simply increase the tree count
*/ */
template<class RF, class PR, class SM, class ST> template<class RF, class PR, class SM, class ST>
void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index) void visit_after_tree(RF & /* rf */, PR & /* pr */, SM & /* sm */, ST & /* st */, int /* index */)
{ {
tree_id++; tree_id++;
} }
template<class Tree, class Split, class Region, class Feature_t, class Label_t> template<class Tree, class Split, class Region, class Feature_t, class Label_t>
void visit_after_split( Tree & tree, void visit_after_split( Tree & tree,
Split & split, Split & split,
Region & parent, Region & parent,
Region & leftChild, Region & leftChild,
Region & rightChild, Region & rightChild,
Feature_t & features, Feature_t & features,
Label_t & labels) Label_t & /* labels */)
{ {
int linear_index; int linear_index;
int addr=tree.topology_.size(); int addr=tree.topology_.size();
if(split.createNode().typeID() == i_ThresholdNode) if(split.createNode().typeID() == i_ThresholdNode)
{ {
if(adjust_thresholds) if(adjust_thresholds)
{ {
//Store marginal distribution //Store marginal distribution
linear_index=trees_online_information[tree_id].mag_distribu tions.size(); linear_index=trees_online_information[tree_id].mag_distribu tions.size();
trees_online_information[tree_id].interior_to_index[addr]=l inear_index; trees_online_information[tree_id].interior_to_index[addr]=l inear_index;
skipping to change at line 782 skipping to change at line 782
totalOobCount(0) totalOobCount(0)
{} {}
bool has_value() bool has_value()
{ {
return true; return true;
} }
/** does the basic calculation per tree*/ /** does the basic calculation per tree*/
template<class RF, class PR, class SM, class ST> template<class RF, class PR, class SM, class ST>
void visit_after_tree( RF& rf, PR & pr, SM & sm, ST & st, int index ) void visit_after_tree(RF & rf, PR & pr, SM & sm, ST & st, int index)
{ {
//do the first time called. //do the first time called.
if(int(oobCount.size()) != rf.ext_param_.row_count_) if(int(oobCount.size()) != rf.ext_param_.row_count_)
{ {
oobCount.resize(rf.ext_param_.row_count_, 0); oobCount.resize(rf.ext_param_.row_count_, 0);
oobErrorCount.resize(rf.ext_param_.row_count_, 0); oobErrorCount.resize(rf.ext_param_.row_count_, 0);
} }
// go through the samples // go through the samples
for(int l = 0; l < rf.ext_param_.row_count_; ++l) for(int l = 0; l < rf.ext_param_.row_count_; ++l)
{ {
skipping to change at line 814 skipping to change at line 814
} }
} }
/** Does the normalisation /** Does the normalisation
*/ */
template<class RF, class PR> template<class RF, class PR>
void visit_at_end(RF & rf, PR & pr) void visit_at_end(RF & rf, PR & pr)
{ {
// do some normalisation // do some normalisation
for(int l=0; l < (int)rf.ext_param_.row_count_; ++l) for(int l=0; l < static_cast<int>(rf.ext_param_.row_count_); ++l)
{ {
if(oobCount[l]) if(oobCount[l])
{ {
oobError += double(oobErrorCount[l]) / oobCount[l]; oobError += double(oobErrorCount[l]) / oobCount[l];
++totalOobCount; ++totalOobCount;
} }
} }
oobError/=totalOobCount; oobError/=totalOobCount;
} }
skipping to change at line 974 skipping to change at line 974
} }
/** Normalise variable importance after the number of trees is known. /** Normalise variable importance after the number of trees is known.
*/ */
template<class RF, class PR> template<class RF, class PR>
void visit_at_end(RF & rf, PR & pr) void visit_at_end(RF & rf, PR & pr)
{ {
// ullis original metric and breiman style stuff // ullis original metric and breiman style stuff
int totalOobCount =0; int totalOobCount =0;
int breimanstyle = 0; int breimanstyle = 0;
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll) for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll )
{ {
if(oobCount[ll]) if(oobCount[ll])
{ {
if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0)) if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0))
++breimanstyle; ++breimanstyle;
++totalOobCount; ++totalOobCount;
} }
} }
oob_breiman = double(breimanstyle)/totalOobCount; oob_breiman = double(breimanstyle)/totalOobCount;
} }
skipping to change at line 1136 skipping to change at line 1136
{ {
// update number of wrong oob samples in this tree. // update number of wrong oob samples in this tree.
++wrong_oob; ++wrong_oob;
// update number of trees in which current sample is wr ong oob // update number of trees in which current sample is wr ong oob
++oobErrorCount[ll]; ++oobErrorCount[ll];
} }
} }
} }
int breimanstyle = 0; int breimanstyle = 0;
int totalOobCount = 0; int totalOobCount = 0;
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll) for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll )
{ {
if(oobCount[ll]) if(oobCount[ll])
{ {
if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0)) if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0))
++breimanstyle; ++breimanstyle;
++totalOobCount; ++totalOobCount;
if(oobroc_per_tree.shape(2) == 1) if(oobroc_per_tree.shape(2) == 1)
{ {
oobroc_per_tree(pr.response()(ll,0), argMax(rowVector(p rob_oob, ll)),0 ,index)++; oobroc_per_tree(pr.response()(ll,0), argMax(rowVector(p rob_oob, ll)),0 ,index)++;
} }
} }
} }
if(oobroc_per_tree.shape(2) == 1) if(oobroc_per_tree.shape(2) == 1)
oobroc_per_tree.bindOuter(index)/=totalOobCount; oobroc_per_tree.bindOuter(index)/=totalOobCount;
if(oobroc_per_tree.shape(2) > 1) if(oobroc_per_tree.shape(2) > 1)
{ {
MultiArrayView<3, double> current_roc MultiArrayView<3, double> current_roc
= oobroc_per_tree.bindOuter(index); = oobroc_per_tree.bindOuter(index);
for(int gg = 0; gg < current_roc.shape(2); ++gg) for(int gg = 0; gg < current_roc.shape(2); ++gg)
{ {
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll) for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count _); ++ll)
{ {
if(oobCount[ll]) if(oobCount[ll])
{ {
int pred = prob_oob(ll, 1) > (double(gg)/double(cur rent_roc.shape(2)))? int pred = prob_oob(ll, 1) > (double(gg)/double(cur rent_roc.shape(2)))?
1 : 0; 1 : 0;
current_roc(pr.response()(ll, 0), pred, gg)+= 1; current_roc(pr.response()(ll, 0), pred, gg)+= 1;
} }
} }
current_roc.bindOuter(gg)/= totalOobCount; current_roc.bindOuter(gg)/= totalOobCount;
} }
skipping to change at line 1183 skipping to change at line 1183
/** Normalise variable importance after the number of trees is known. /** Normalise variable importance after the number of trees is known.
*/ */
template<class RF, class PR> template<class RF, class PR>
void visit_at_end(RF & rf, PR & pr) void visit_at_end(RF & rf, PR & pr)
{ {
// ullis original metric and breiman style stuff // ullis original metric and breiman style stuff
oob_per_tree2 = 0; oob_per_tree2 = 0;
int totalOobCount =0; int totalOobCount =0;
int breimanstyle = 0; int breimanstyle = 0;
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll) for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll )
{ {
if(oobCount[ll]) if(oobCount[ll])
{ {
if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0)) if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0))
++breimanstyle; ++breimanstyle;
oob_per_tree2 += double(oobErrorCount[ll]) / oobCount[ll]; oob_per_tree2 += double(oobErrorCount[ll]) / oobCount[ll];
++totalOobCount; ++totalOobCount;
} }
} }
oob_per_tree2 /= totalOobCount; oob_per_tree2 /= totalOobCount;
skipping to change at line 1247 skipping to change at line 1247
#ifdef HasHDF5 #ifdef HasHDF5
void save(std::string filename, std::string prefix) void save(std::string filename, std::string prefix)
{ {
prefix = "variable_importance_" + prefix; prefix = "variable_importance_" + prefix;
writeHDF5(filename.c_str(), writeHDF5(filename.c_str(),
prefix.c_str(), prefix.c_str(),
variable_importance_); variable_importance_);
} }
#endif #endif
/** Constructor /* Constructor
* \param rep_cnt (defautl: 10) how often should * \param rep_cnt (defautl: 10) how often should
* the permutation take place. Set to 1 to make calculation faster (but * the permutation take place. Set to 1 to make calculation faster (but
* possibly more instable) * possibly more instable)
*/ */
VariableImportanceVisitor(int rep_cnt = 10) VariableImportanceVisitor(int rep_cnt = 10)
: repetition_count_(rep_cnt) : repetition_count_(rep_cnt)
{} {}
/** calculates impurity decrease based variable importance after every /** calculates impurity decrease based variable importance after every
* split. * split.
*/ */
template<class Tree, class Split, class Region, class Feature_t, class Label_t> template<class Tree, class Split, class Region, class Feature_t, class Label_t>
void visit_after_split( Tree & tree, void visit_after_split( Tree & tree,
Split & split, Split & split,
Region & parent, Region & /* parent */,
Region & leftChild, Region & /* leftChild */,
Region & rightChild, Region & /* rightChild */,
Feature_t & features, Feature_t & /* features */,
Label_t & labels) Label_t & /* labels */)
{ {
//resize to right size when called the first time //resize to right size when called the first time
Int32 const class_count = tree.ext_param_.class_count_; Int32 const class_count = tree.ext_param_.class_count_;
Int32 const column_count = tree.ext_param_.column_count_; Int32 const column_count = tree.ext_param_.column_count_;
if(variable_importance_.size() == 0) if(variable_importance_.size() == 0)
{ {
variable_importance_ variable_importance_
.reshape(MultiArrayShape<2>::type(column_count, .reshape(MultiArrayShape<2>::type(column_count,
skipping to change at line 1296 skipping to change at line 1296
} }
} }
/**compute permutation based var imp. /**compute permutation based var imp.
* (Only an Array of size oob_sample_count x 1 is created. * (Only an Array of size oob_sample_count x 1 is created.
* - apposed to oob_sample_count x feature_count in the other method. * - apposed to oob_sample_count x feature_count in the other method.
* *
* \sa FieldProxy * \sa FieldProxy
*/ */
template<class RF, class PR, class SM, class ST> template<class RF, class PR, class SM, class ST>
void after_tree_ip_impl(RF& rf, PR & pr, SM & sm, ST & st, int index) void after_tree_ip_impl(RF& rf, PR & pr, SM & sm, ST & /* st */, int i ndex)
{ {
typedef MultiArrayShape<2>::type Shp_t; typedef MultiArrayShape<2>::type Shp_t;
Int32 column_count = rf.ext_param_.column_count_; Int32 column_count = rf.ext_param_.column_count_;
Int32 class_count = rf.ext_param_.class_count_; Int32 class_count = rf.ext_param_.class_count_;
/* This solution saves memory uptake but not multithreading /* This solution saves memory uptake but not multithreading
* compatible * compatible
*/ */
// remove the const cast on the features (yep , I know what I am // remove the const cast on the features (yep , I know what I am
// doing here.) data is not destroyed. // doing here.) data is not destroyed.
skipping to change at line 1423 skipping to change at line 1423
*/ */
template<class RF, class PR, class SM, class ST> template<class RF, class PR, class SM, class ST>
void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index) void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index)
{ {
after_tree_ip_impl(rf, pr, sm, st, index); after_tree_ip_impl(rf, pr, sm, st, index);
} }
/** Normalise variable importance after the number of trees is known. /** Normalise variable importance after the number of trees is known.
*/ */
template<class RF, class PR> template<class RF, class PR>
void visit_at_end(RF & rf, PR & pr) void visit_at_end(RF & rf, PR & /* pr */)
{ {
variable_importance_ /= rf.trees_.size(); variable_importance_ /= rf.trees_.size();
} }
}; };
/** Verbose output /** Verbose output
*/ */
class RandomForestProgressVisitor : public VisitorBase { class RandomForestProgressVisitor : public VisitorBase {
public: public:
RandomForestProgressVisitor() : VisitorBase() {} RandomForestProgressVisitor() : VisitorBase() {}
skipping to change at line 1519 skipping to change at line 1519
tmp += prefix;\ tmp += prefix;\
vigra::writeToHDF5File(file.c_str(), tmp.c_str(), NAME); vigra::writeToHDF5File(file.c_str(), tmp.c_str(), NAME);
VAR_WRITE(gini_missc); VAR_WRITE(gini_missc);
VAR_WRITE(corr_noise); VAR_WRITE(corr_noise);
VAR_WRITE(distance); VAR_WRITE(distance);
VAR_WRITE(similarity); VAR_WRITE(similarity);
vigra::writeToHDF5File(file.c_str(), "nChoices", MultiArrayView<2, int>(MultiArrayShape<2>::type(numChoices.size(),1), numChoices.data())); vigra::writeToHDF5File(file.c_str(), "nChoices", MultiArrayView<2, int>(MultiArrayShape<2>::type(numChoices.size(),1), numChoices.data()));
#undef VAR_WRITE #undef VAR_WRITE
*/ */
} }
template<class RF, class PR> template<class RF, class PR>
void visit_at_beginning(RF const & rf, PR & pr) void visit_at_beginning(RF const & rf, PR & pr)
{ {
typedef MultiArrayShape<2>::type Shp; typedef MultiArrayShape<2>::type Shp;
int n = rf.ext_param_.column_count_; int n = rf.ext_param_.column_count_;
gini_missc.reshape(Shp(n +1,n+ 1)); gini_missc.reshape(Shp(n +1,n+ 1));
corr_noise.reshape(Shp(n + 1, 10)); corr_noise.reshape(Shp(n + 1, 10));
corr_l.reshape(Shp(n +1, 10)); corr_l.reshape(Shp(n +1, 10));
noise.reshape(Shp(pr.features().shape(0), 10)); noise.reshape(Shp(pr.features().shape(0), 10));
noise_l.reshape(Shp(pr.features().shape(0), 10)); noise_l.reshape(Shp(pr.features().shape(0), 10));
RandomMT19937 random(RandomSeed); RandomMT19937 random(RandomSeed);
 End of changes. 19 change blocks. 
23 lines changed or deleted 24 lines changed or added


 rgbvalue.hxx   rgbvalue.hxx 
skipping to change at line 388 skipping to change at line 388
inline inline
bool bool
operator!=(RGBValue<V1, RIDX1, GIDX1, BIDX1> const & l, operator!=(RGBValue<V1, RIDX1, GIDX1, BIDX1> const & l,
RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r) RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r)
{ {
return (l.red() != r.red()) || return (l.red() != r.red()) ||
(l.green() != r.green()) || (l.green() != r.green()) ||
(l.blue() != r.blue()); (l.blue() != r.blue());
} }
template <class V, unsigned int RIDX1, unsigned int GIDX1, unsigned int BID
X1,
unsigned int RIDX2, unsigned int GIDX2, unsigned int BID
X2>
inline
bool
closeAtTolerance(RGBValue<V, RIDX1, GIDX1, BIDX1> const & l,
RGBValue<V, RIDX2, GIDX2, BIDX2> const & r,
V epsilon = NumericTraits<V>::epsilon())
{
return closeAtTolerance(l.red(), r.red(), epsilon) &&
closeAtTolerance(l.green(), r.green(), epsilon) &&
closeAtTolerance(l.blue(), r.blue(), epsilon);
}
//@} //@}
/********************************************************/ /********************************************************/
/* */ /* */
/* RGBValue-Traits */ /* RGBValue-Traits */
/* */ /* */
/********************************************************/ /********************************************************/
/** \page RGBValueTraits Numeric and Promote Traits of RGBValue /** \page RGBValueTraits Numeric and Promote Traits of RGBValue
The numeric and promote traits for RGBValues follow The numeric and promote traits for RGBValues follow
 End of changes. 1 change blocks. 
0 lines changed or deleted 15 lines changed or added


 sampling.hxx   sampling.hxx 
skipping to change at line 240 skipping to change at line 240
template<class Random = MersenneTwister > template<class Random = MersenneTwister >
class Sampler class Sampler
{ {
public: public:
/** Internal type of the indices. /** Internal type of the indices.
Currently, 64-bit indices are not supported because this Currently, 64-bit indices are not supported because this
requires extension of the random number generator classes. requires extension of the random number generator classes.
*/ */
typedef Int32 IndexType; typedef Int32 IndexType;
typedef ArrayVector <IndexType> IndexArrayType; typedef ArrayVector<IndexType> IndexArrayType;
/** Type of the array view object that is returned by /** Type of the array view object that is returned by
sampledIndices() and oobIndices(). sampledIndices() and oobIndices().
*/ */
typedef ArrayVectorView <IndexType> IndexArrayViewType; typedef ArrayVectorView <IndexType> IndexArrayViewType;
private: private:
typedef std::map<IndexType, IndexArrayType> StrataIndicesType; typedef std::map<IndexType, IndexArrayType> StrataIndicesType;
typedef std::map<IndexType, int> StrataSizesType; typedef std::map<IndexType, int> StrataSizesType;
typedef ArrayVector <bool> IsUsedArrayType; typedef ArrayVector<bool> IsUsedArrayType;
typedef ArrayVectorView <bool> IsUsedArrayViewType; typedef ArrayVectorView<bool> IsUsedArrayViewType;
static const int oobInvalid = -1; static const int oobInvalid = -1;
int total_count_, sample_size_; int total_count_, sample_size_;
mutable int current_oob_count_; mutable int current_oob_count_;
StrataIndicesType strata_indices_; StrataIndicesType strata_indices_;
StrataSizesType strata_sample_size_; StrataSizesType strata_sample_size_;
IndexArrayType current_sample_; IndexArrayType current_sample_;
mutable IndexArrayType current_oob_sample_; mutable IndexArrayType current_oob_sample_;
IsUsedArrayType is_used_; IsUsedArrayType is_used_;
Random const & random_; Random default_random_;
SamplerOptions options_; Random const & random_;
SamplerOptions options_;
void initStrataCount() void initStrataCount()
{ {
// compute how many samples to take from each stratum // compute how many samples to take from each stratum
// (may be unequal if sample_size_ is not a multiple of strataCount ()) // (may be unequal if sample_size_ is not a multiple of strataCount ())
int strata_sample_size = (int)std::ceil(double(sample_size_) / stra taCount()); int strata_sample_size = static_cast<int>(std::ceil(double(sample_s ize_) / strataCount()));
int strata_total_count = strata_sample_size * strataCount(); int strata_total_count = strata_sample_size * strataCount();
for(StrataIndicesType::iterator i = strata_indices_.begin(); for(StrataIndicesType::iterator i = strata_indices_.begin();
i != strata_indices_.end(); ++i) i != strata_indices_.end(); ++i)
{ {
if(strata_total_count > sample_size_) if(strata_total_count > sample_size_)
{ {
strata_sample_size_[i->first] = strata_sample_size - 1; strata_sample_size_[i->first] = strata_sample_size - 1;
--strata_total_count; --strata_total_count;
} }
skipping to change at line 296 skipping to change at line 297
public: public:
/** Create a sampler for \a totalCount data objects. /** Create a sampler for \a totalCount data objects.
In each invocation of <tt>sample()</tt> below, it will sample In each invocation of <tt>sample()</tt> below, it will sample
indices according to the options passed. If no options are give n, indices according to the options passed. If no options are give n,
<tt>totalCount</tt> indices will be drawn with replacement. <tt>totalCount</tt> indices will be drawn with replacement.
*/ */
Sampler(UInt32 totalCount, SamplerOptions const & opt = SamplerOptions( ), Sampler(UInt32 totalCount, SamplerOptions const & opt = SamplerOptions( ),
Random const & rnd = Random(RandomSeed)) Random const * rnd = 0)
: total_count_(totalCount), : total_count_(totalCount),
sample_size_(opt.sample_size == 0 sample_size_(opt.sample_size == 0
? (int)(std::ceil(total_count_ * opt.sample_propor ? static_cast<int>((std::ceil(total_count_ * opt.sample_
tion)) proportion)))
: opt.sample_size), : opt.sample_size),
current_oob_count_(oobInvalid), current_oob_count_(oobInvalid),
current_sample_(sample_size_), current_sample_(sample_size_),
current_oob_sample_(total_count_), current_oob_sample_(total_count_),
is_used_(total_count_), is_used_(total_count_),
random_(rnd), default_random_(RandomSeed),
random_(rnd ? *rnd : default_random_),
options_(opt) options_(opt)
{ {
vigra_precondition(opt.sample_with_replacement || sample_size_ <= t otal_count_, vigra_precondition(opt.sample_with_replacement || sample_size_ <= t otal_count_,
"Sampler(): Cannot draw without replacement when data size is sma ller than sample count."); "Sampler(): Cannot draw without replacement when data size is sma ller than sample count.");
vigra_precondition(!opt.stratified_sampling, vigra_precondition(!opt.stratified_sampling,
"Sampler(): Stratified sampling requested, but no strata given.") ; "Sampler(): Stratified sampling requested, but no strata given.") ;
// initialize a single stratum containing all data // initialize a single stratum containing all data
strata_indices_[0].resize(total_count_); strata_indices_[0].resize(total_count_);
skipping to change at line 335 skipping to change at line 337
<tt>strataBegin</tt> and <tt>strataEnd</tt> must refer to a seq uence <tt>strataBegin</tt> and <tt>strataEnd</tt> must refer to a seq uence
which specifies for each sample the stratum it belongs to. The which specifies for each sample the stratum it belongs to. The
total number of data objects will be set to <tt>strataEnd - str ataBegin</tt>. total number of data objects will be set to <tt>strataEnd - str ataBegin</tt>.
Equally many samples (subject to rounding) will be drawn from e ach stratum, Equally many samples (subject to rounding) will be drawn from e ach stratum,
unless the option object explicitly requests unstratified sampl ing, unless the option object explicitly requests unstratified sampl ing,
in which case the strata are ignored. in which case the strata are ignored.
*/ */
template <class Iterator> template <class Iterator>
Sampler(Iterator strataBegin, Iterator strataEnd, SamplerOptions const & opt = SamplerOptions(), Sampler(Iterator strataBegin, Iterator strataEnd, SamplerOptions const & opt = SamplerOptions(),
Random const & rnd = Random(RandomSeed)) Random const * rnd = 0)
: total_count_(strataEnd - strataBegin), : total_count_(strataEnd - strataBegin),
sample_size_(opt.sample_size == 0 sample_size_(opt.sample_size == 0
? (int)(std::ceil(total_count_ * opt.sample_propor ? static_cast<int>((std::ceil(total_count_ * opt.sample_
tion)) proportion)))
: opt.sample_size), : opt.sample_size),
current_oob_count_(oobInvalid), current_oob_count_(oobInvalid),
current_sample_(sample_size_), current_sample_(sample_size_),
current_oob_sample_(total_count_), current_oob_sample_(total_count_),
is_used_(total_count_), is_used_(total_count_),
random_(rnd), default_random_(RandomSeed),
random_(rnd ? *rnd : default_random_),
options_(opt) options_(opt)
{ {
vigra_precondition(opt.sample_with_replacement || sample_size_ <= t otal_count_, vigra_precondition(opt.sample_with_replacement || sample_size_ <= t otal_count_,
"Sampler(): Cannot draw without replacement when data size is sma ller than sample count."); "Sampler(): Cannot draw without replacement when data size is sma ller than sample count.");
// copy the strata indices // copy the strata indices
if(opt.stratified_sampling) if(opt.stratified_sampling)
{ {
for(int i = 0; strataBegin != strataEnd; ++i, ++strataBegin) for(int i = 0; strataBegin != strataEnd; ++i, ++strataBegin)
{ {
strata_indices_[*strataBegin].push_back(i); strata_indices_[*strataBegin].push_back(i);
} }
} }
else else
{ {
strata_indices_[0].resize(total_count_); strata_indices_[0].resize(total_count_);
for(int i=0; i<total_count_; ++i) for(int i=0; i<total_count_; ++i)
strata_indices_[0][i] = i; strata_indices_[0][i] = i;
} }
vigra_precondition(sample_size_ >= (int)strata_indices_.size(), vigra_precondition(sample_size_ >= static_cast<int>(strata_indices_ .size()),
"Sampler(): Requested sample count must be at least as large as the number of strata."); "Sampler(): Requested sample count must be at least as large as the number of strata.");
initStrataCount(); initStrataCount();
//this is screwing up the random forest tests. //this is screwing up the random forest tests.
//sample(); //sample();
} }
/** Return the k-th index in the current sample. /** Return the k-th index in the current sample.
*/ */
IndexType operator[](int k) const IndexType operator[](int k) const
skipping to change at line 476 skipping to change at line 479
if(options_.sample_with_replacement) if(options_.sample_with_replacement)
{ {
//Go thru all strata //Go thru all strata
int j = 0; int j = 0;
StrataIndicesType::iterator iter; StrataIndicesType::iterator iter;
for(iter = strata_indices_.begin(); iter != strata_indices_.end(); ++iter) for(iter = strata_indices_.begin(); iter != strata_indices_.end(); ++iter)
{ {
// do sampling with replacement in each strata and copy data. // do sampling with replacement in each strata and copy data.
int stratum_size = iter->second.size(); int stratum_size = iter->second.size();
for(int i = 0; i < (int)strata_sample_size_[iter->first]; ++i, ++j) for(int i = 0; i < static_cast<int>(strata_sample_size_[iter->f irst]); ++i, ++j)
{ {
current_sample_[j] = iter->second[random_.uniformInt(stratu m_size)]; current_sample_[j] = iter->second[random_.uniformInt(stratu m_size)];
is_used_[current_sample_[j]] = true; is_used_[current_sample_[j]] = true;
} }
} }
} }
else else
{ {
//Go thru all strata //Go thru all strata
int j = 0; int j = 0;
StrataIndicesType::iterator iter; StrataIndicesType::iterator iter;
for(iter = strata_indices_.begin(); iter != strata_indices_.end(); ++iter) for(iter = strata_indices_.begin(); iter != strata_indices_.end(); ++iter)
{ {
// do sampling without replacement in each strata and copy data . // do sampling without replacement in each strata and copy data .
int stratum_size = iter->second.size(); int stratum_size = iter->second.size();
for(int i = 0; i < (int)strata_sample_size_[iter->first]; ++i, ++j) for(int i = 0; i < static_cast<int>(strata_sample_size_[iter->f irst]); ++i, ++j)
{ {
std::swap(iter->second[i], iter->second[i+ random_.uniformI nt(stratum_size - i)]); std::swap(iter->second[i], iter->second[i+ random_.uniformI nt(stratum_size - i)]);
current_sample_[j] = iter->second[i]; current_sample_[j] = iter->second[i];
is_used_[current_sample_[j]] = true; is_used_[current_sample_[j]] = true;
} }
} }
} }
} }
template<class Random =RandomTT800 > template<class Random =RandomTT800 >
 End of changes. 13 change blocks. 
31 lines changed or deleted 34 lines changed or added


 seededregiongrowing.hxx   seededregiongrowing.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_SEEDEDREGIONGROWING_HXX #define VIGRA_SEEDEDREGIONGROWING_HXX
#include <vector> #include <vector>
#include <stack> #include <stack>
#include <queue> #include <queue>
#include "utilities.hxx" #include "utilities.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "stdimagefunctions.hxx" #include "stdimagefunctions.hxx"
#include "pixelneighborhood.hxx" #include "pixelneighborhood.hxx"
#include "bucket_queue.hxx" #include "bucket_queue.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
template <class COST> template <class COST>
class SeedRgPixel class SeedRgPixel
{ {
public: public:
Point2D location_, nearest_; Point2D location_, nearest_;
skipping to change at line 187 skipping to change at line 188
CompleteGrow = 0, CompleteGrow = 0,
KeepContours = 1, KeepContours = 1,
StopAtThreshold = 2, StopAtThreshold = 2,
SRGWatershedLabel = -1 SRGWatershedLabel = -1
}; };
/** \brief Region Segmentation by means of Seeded Region Growing. /** \brief Region Segmentation by means of Seeded Region Growing.
This algorithm implements seeded region growing as described in This algorithm implements seeded region growing as described in
R. Adams, L. Bischof: "<em> Seeded Region Growing</em>", IEEE Trans. on Pattern R. Adams, L. Bischof: <em>"Seeded Region Growing"</em>, IEEE Trans. on Pattern
Analysis and Maschine Intelligence, vol 16, no 6, 1994, and Analysis and Maschine Intelligence, vol 16, no 6, 1994, and
Ullrich K&ouml;the: Ullrich K&ouml;the:
<em><a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe/papers/ind ex.php#cite_primary_segmentation">Primary Image Segmentation</a></em>, <em><a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe/papers/ind ex.php#cite_primary_segmentation">Primary Image Segmentation</a></em>,
in: G. Sagerer, S. in: G. Sagerer, S.
Posch, F. Kummert (eds.): Mustererkennung 1995, Proc. 17. DAGM-Symposiu m, Posch, F. Kummert (eds.): Mustererkennung 1995, Proc. 17. DAGM-Symposiu m,
Springer 1995 Springer 1995
The seed image is a partly segmented image which contains uniquely The seed image is a partly segmented image which contains uniquely
labeled regions (the seeds) and unlabeled pixels (the candidates, label 0). labeled regions (the seeds) and unlabeled pixels (the candidates, label 0).
skipping to change at line 274 skipping to change at line 275
region growing is aborted, and all voxels not yet assigned to a region remain unlabeled. region growing is aborted, and all voxels not yet assigned to a region remain unlabeled.
In some cases, the cost only depends on the feature value of the curren t In some cases, the cost only depends on the feature value of the curren t
pixel. Then the update operation will simply be a no-op, and the <TT>co st()</TT> pixel. Then the update operation will simply be a no-op, and the <TT>co st()</TT>
function returns its argument. This behavior is implemented by the function returns its argument. This behavior is implemented by the
\ref SeedRgDirectValueFunctor. With <tt>SRGType == KeepContours</tt>, \ref SeedRgDirectValueFunctor. With <tt>SRGType == KeepContours</tt>,
this is equivalent to the watershed algorithm. this is equivalent to the watershed algorithm.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray, class Neighborhood>
TS
seededRegionGrowing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TS, AS> const & seeds,
MultiArrayView<2, T2, S2> labels,
RegionStatisticsArray & stats,
SRGType srgType = Com
pleteGrow,
Neighborhood n = FourNeigh
borCode(),
double max_cost = Nu
mericTraits<double>::max());
}
\endcode
\deprecatedAPI{seededRegionGrowing}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
typename SeedAccessor::value_type typename SeedAccessor::value_type
seededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccess or as, seededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccess or as,
SeedImageIterator seedsul, SeedAccessor aseeds, SeedImageIterator seedsul, SeedAccessor aseeds,
DestIterator destul, DestAccessor ad, DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType = CompleteGrow, SRGType srgType = CompleteGrow,
Neighborhood neighborhood = FourNeighborCode(), Neighborhood neighborhood = FourNeighborCode(),
double max_cost = NumericTraits<double>::max()) ; double max_cost = NumericTraits<double>::max()) ;
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
typename SeedAccessor::value_type typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<SeedImageIterator, SeedAccessor> seeds, pair<SeedImageIterator, SeedAccessor> seeds,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType = CompleteGrow, SRGType srgType = CompleteGrow,
Neighborhood neighborhood = FourNeighborCode(), Neighborhood neighborhood = FourNeighborCode(),
double max_cost = NumericTraits<double>::max()) ; double max_cost = NumericTraits<double>::max()) ;
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/seededregiongrowing.hxx\><br> <b>\#include</b> \<vigra/seededregiongrowing.hxx\><br>
Namespace: vigra Namespace: vigra
Example: implementation of the voronoi tesselation Example: implementation of the voronoi tesselation
\code \code
MultiArray<2, int> points(w,h);
MultiArray<2, float> dist(x,y);
int max_region_label = 100;
// throw in some random points:
for(int i = 1; i <= max_region_label; ++i)
points(w * rand() / RAND_MAX , h * rand() / RAND_MAX) = i;
// calculate Euclidean distance transform
distanceTransform(points, dist, 2);
// init statistics functor
ArrayOfRegionStatistics<SeedRgDirectValueFunctor<float> > stats(max_re
gion_label);
// find voronoi region of each point (the point image is overwritten wi
th the
// voronoi region labels)
seededRegionGrowing(dist, points, points, stats);
\endcode
\deprecatedUsage{seededRegionGrowing}
\code
vigra::BImage points(w,h); vigra::BImage points(w,h);
vigra::FImage dist(x,y); vigra::FImage dist(x,y);
// empty edge image // empty edge image
points = 0; points = 0;
dist = 0; dist = 0;
int max_region_label = 100; int max_region_label = 100;
// throw in some random points: // throw in some random points:
skipping to change at line 342 skipping to change at line 384
vigra::distanceTransform(srcImageRange(points), destImage(dist), 2); vigra::distanceTransform(srcImageRange(points), destImage(dist), 2);
// init statistics functor // init statistics functor
vigra::ArrayOfRegionStatistics<vigra::SeedRgDirectValueFunctor<float> > vigra::ArrayOfRegionStatistics<vigra::SeedRgDirectValueFunctor<float> >
stats(max_region_label); stats(max_region_label);
// find voronoi region of each point // find voronoi region of each point
vigra:: seededRegionGrowing(srcImageRange(dist), srcImage(points), vigra:: seededRegionGrowing(srcImageRange(dist), srcImage(points),
destImage(points), stats); destImage(points), stats);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
SeedImageIterator seed_upperleft; SeedImageIterator seed_upperleft;
DestIterator dest_upperleft; DestIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
SeedAccessor seed_accessor; SeedAccessor seed_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
RegionStatisticsArray stats; RegionStatisticsArray stats;
skipping to change at line 369 skipping to change at line 409
// compare costs // compare costs
cost < cost; cost < cost;
// update statistics // update statistics
stats[seed_accessor(seed_upperleft)](src_accessor(src_upperleft)); stats[seed_accessor(seed_upperleft)](src_accessor(src_upperleft));
// set result // set result
dest_accessor.set(seed_accessor(seed_upperleft), dest_upperleft); dest_accessor.set(seed_accessor(seed_upperleft), dest_upperleft);
\endcode \endcode
\deprecatedEnd
Further requirements are determined by the <TT>RegionStatisticsArray</T T>. Further requirements are determined by the <TT>RegionStatisticsArray</T T>.
*/ */
doxygen_overloaded_function(template <...> void seededRegionGrowing) doxygen_overloaded_function(template <...> void seededRegionGrowing)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
typename SeedAccessor::value_type typename SeedAccessor::value_type
skipping to change at line 446 skipping to change at line 487
CostType cost = stats[cneighbor].cost(as(isx)); CostType cost = stats[cneighbor].cost(as(isx));
Pixel * pixel = Pixel * pixel =
allocator.create(pos, pos+Neighborhood::diff((D irection)i), cost, count++, cneighbor); allocator.create(pos, pos+Neighborhood::diff((D irection)i), cost, count++, cneighbor);
pheap.push(pixel); pheap.push(pixel);
} }
} }
} }
else else
{ {
vigra_precondition((LabelType)*irx <= stats.maxRegionLabel( ), vigra_precondition((LabelType)*irx <= (LabelType)stats.maxR egionLabel(),
"seededRegionGrowing(): Largest label exceeds size of R egionStatisticsArray."); "seededRegionGrowing(): Largest label exceeds size of R egionStatisticsArray.");
if(maxRegionLabel < *irx) if(maxRegionLabel < *irx)
maxRegionLabel = *irx; maxRegionLabel = *irx;
} }
} }
} }
// perform region growing // perform region growing
while(pheap.size() != 0) while(pheap.size() != 0)
{ {
skipping to change at line 591 skipping to change at line 632
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
inline typename SeedAccessor::value_type inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1, seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType, SRGType srgType,
Neighborhood n, Neighborhood n,
double max_cost) double max_cost = NumericTraits<double>::max())
{ {
return seededRegionGrowing(img1.first, img1.second, img1.third, return seededRegionGrowing(img1.first, img1.second, img1.third,
img3.first, img3.second, img3.first, img3.second,
img4.first, img4.second, img4.first, img4.second,
stats, srgType, n, max_cost); stats, srgType, n, max_cost);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood>
inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
pair<SeedImageIterator, SeedAccessor> img3,
pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats,
SRGType srgType,
Neighborhood n)
{
return seededRegionGrowing(img1.first, img1.second, img1.third,
img3.first, img3.second,
img4.first, img4.second,
stats, srgType, n, NumericTraits<double>::m
ax());
}
template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor,
class DestIterator, class DestAccessor,
class RegionStatisticsArray> class RegionStatisticsArray>
inline typename SeedAccessor::value_type inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1, seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType) SRGType srgType)
{ {
return seededRegionGrowing(img1.first, img1.second, img1.third, return seededRegionGrowing(img1.first, img1.second, img1.third,
img3.first, img3.second, img3.first, img3.second,
skipping to change at line 650 skipping to change at line 673
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats) RegionStatisticsArray & stats)
{ {
return seededRegionGrowing(img1.first, img1.second, img1.third, return seededRegionGrowing(img1.first, img1.second, img1.third,
img3.first, img3.second, img3.first, img3.second,
img4.first, img4.second, img4.first, img4.second,
stats, CompleteGrow); stats, CompleteGrow);
} }
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray, class Neighborhood>
inline TS
seededRegionGrowing(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, TS, AS> const & img3,
MultiArrayView<2, T2, S2> img4,
RegionStatisticsArray & stats,
SRGType srgType,
Neighborhood n,
double max_cost = NumericTraits<double>::max())
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing(): shape mismatch between input and output.");
return seededRegionGrowing(srcImageRange(img1),
srcImage(img3),
destImage(img4),
stats, srgType, n, max_cost);
}
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray>
inline TS
seededRegionGrowing(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, TS, AS> const & img3,
MultiArrayView<2, T2, S2> img4,
RegionStatisticsArray & stats,
SRGType srgType)
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing(): shape mismatch between input and output.");
return seededRegionGrowing(srcImageRange(img1),
srcImage(img3),
destImage(img4),
stats, srgType, FourNeighborCode());
}
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray>
inline TS
seededRegionGrowing(MultiArrayView<2, T1, S1> const & img1,
MultiArrayView<2, TS, AS> const & img3,
MultiArrayView<2, T2, S2> img4,
RegionStatisticsArray & stats)
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing(): shape mismatch between input and output.");
return seededRegionGrowing(srcImageRange(img1),
srcImage(img3),
destImage(img4),
stats, CompleteGrow);
}
/********************************************************/
/* */
/* fastSeededRegionGrowing */
/* */
/********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
typename DestAccessor::value_type typename DestAccessor::value_type
fastSeededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccessor a s, fastSeededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccessor a s,
DestIterator destul, DestAccessor ad, DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType, SRGType srgType,
Neighborhood, Neighborhood,
double max_cost, double max_cost,
skipping to change at line 834 skipping to change at line 921
inline typename DestAccessor::value_type inline typename DestAccessor::value_type
fastSeededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src, fastSeededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType, SRGType srgType,
Neighborhood n, Neighborhood n,
double max_cost, double max_cost,
std::ptrdiff_t bucket_count = 256) std::ptrdiff_t bucket_count = 256)
{ {
return fastSeededRegionGrowing(src.first, src.second, src.third, return fastSeededRegionGrowing(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
stats, srgType, n, max_cost, bucket_cou stats, srgType, n, max_cost, bucket_coun
nt); t);
}
template <class T1, class S1,
class T2, class S2,
class RegionStatisticsArray, class Neighborhood>
inline T2
fastSeededRegionGrowing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
RegionStatisticsArray & stats,
SRGType srgType,
Neighborhood n,
double max_cost,
std::ptrdiff_t bucket_count = 256)
{
vigra_precondition(src.shape() == dest.shape(),
"fastSeededRegionGrowing(): shape mismatch between input and output
.");
return fastSeededRegionGrowing(srcImageRange(src),
destImage(dest),
stats, srgType, n, max_cost, bucket_coun
t);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* SeedRgDirectValueFunctor */ /* SeedRgDirectValueFunctor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Statistics functor to be used for seeded region growing. /** \brief Statistics functor to be used for seeded region growing.
This functor can be used if the cost of a candidate during This functor can be used if the cost of a candidate during
\ref seededRegionGrowing() is equal to the feature value of that \ref seededRegionGrowing() is equal to the feature value of that
candidate and does not depend on properties of the region it is going t o candidate and does not depend on properties of the region it is going t o
be merged with. be merged with.
<b>\#include</b> \<vigra/seededregiongrowing.hxx\><br> <b>\#include</b> \<vigra/seededregiongrowing.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Required Interface:</b>
no requirements
*/ */
template <class Value> template <class Value>
class SeedRgDirectValueFunctor class SeedRgDirectValueFunctor
{ {
public: public:
/** the functor's argument type /** the functor's argument type
*/ */
typedef Value argument_type; typedef Value argument_type;
/** the functor's result type (unused, only necessary for /** the functor's result type (unused, only necessary for
 End of changes. 15 change blocks. 
33 lines changed or deleted 141 lines changed or added


 seededregiongrowing3d.hxx   seededregiongrowing3d.hxx 
skipping to change at line 47 skipping to change at line 47
#ifndef VIGRA_SEEDEDREGIONGROWING_3D_HXX #ifndef VIGRA_SEEDEDREGIONGROWING_3D_HXX
#define VIGRA_SEEDEDREGIONGROWING_3D_HXX #define VIGRA_SEEDEDREGIONGROWING_3D_HXX
#include <vector> #include <vector>
#include <stack> #include <stack>
#include <queue> #include <queue>
#include "utilities.hxx" #include "utilities.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "stdimagefunctions.hxx" #include "stdimagefunctions.hxx"
#include "seededregiongrowing.hxx" #include "seededregiongrowing.hxx"
#include "multi_shape.hxx"
#include "multi_pointoperators.hxx" #include "multi_pointoperators.hxx"
#include "voxelneighborhood.hxx" #include "voxelneighborhood.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
template <class COST, class Diff_type> template <class COST, class Diff_type>
class SeedRgVoxel class SeedRgVoxel
{ {
skipping to change at line 253 skipping to change at line 254
<tt>max_cost</tt> value (which defaults to <tt>NumericTraits<double>::m ax()</tt>), <tt>max_cost</tt> value (which defaults to <tt>NumericTraits<double>::m ax()</tt>),
region growing is aborted, and all voxels not yet assigned to a region remain unlabeled. region growing is aborted, and all voxels not yet assigned to a region remain unlabeled.
In some cases, the cost only depends on the feature value of the curren t In some cases, the cost only depends on the feature value of the curren t
voxel. Then the update operation will simply be a no-op, and the <TT>co st()</TT> voxel. Then the update operation will simply be a no-op, and the <TT>co st()</TT>
function returns its argument. This behavior is implemented by the function returns its argument. This behavior is implemented by the
\ref SeedRgDirectValueFunctor. \ref SeedRgDirectValueFunctor.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 3D array views:
\code
namespace vigra {
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray, class Neighborhood>
void
seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & src,
MultiArrayView<3, TS, AS> const & seeds,
MultiArrayView<3, T2, S2> labels,
RegionStatisticsArray & stats,
SRGType srgType = C
ompleteGrow,
Neighborhood neighborhoo
d = NeighborCode3DSix(),
double max_cost =
NumericTraits<double>::max());
}
\endcode
\deprecatedAPI{seededRegionGrowing3D}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class Shape, class SrcAccessor, template <class SrcImageIterator, class Shape, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
void void
seededRegionGrowing3D(SrcImageIterator srcul, Shape shape, SrcAcces sor as, seededRegionGrowing3D(SrcImageIterator srcul, Shape shape, SrcAcces sor as,
SeedImageIterator seedsul, SeedAccessor aseed s, SeedImageIterator seedsul, SeedAccessor aseed s,
DestImageIterator destul, DestAccessor ad, DestImageIterator destul, DestAccessor ad,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType = CompleteGrow, SRGType srgType = CompleteGrow,
Neighborhood neighborhood = NeighborCode3DSix (), Neighborhood neighborhood = NeighborCode3DSix (),
double max_cost = NumericTraits<double>::max( )); double max_cost = NumericTraits<double>::max( ));
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class Shape, class SrcAccessor, template <class SrcImageIterator, class Shape, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
void void
seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> src, seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> src,
pair<SeedImageIterator, SeedAccessor> seeds, pair<SeedImageIterator, SeedAccessor> seeds,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType = CompleteGrow, SRGType srgType = CompleteGrow,
Neighborhood neighborhood = NeighborCode3DSix (), Neighborhood neighborhood = NeighborCode3DSix (),
double max_cost = NumericTraits<double>::max( )); double max_cost = NumericTraits<double>::max( ));
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b>
<b>\#include</b> \<vigra/seededregiongrowing3d.hxx\><br>
Namespace: vigra
See \ref seededRegionGrowing() for an example
*/ */
doxygen_overloaded_function(template <...> void seededRegionGrowing3D) doxygen_overloaded_function(template <...> void seededRegionGrowing3D)
template <class SrcImageIterator, class Diff_type, class SrcAccessor, template <class SrcImageIterator, class Diff_type, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
void void
seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor as, seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor as,
SeedImageIterator seedsul, SeedAccessor aseeds, SeedImageIterator seedsul, SeedAccessor aseeds,
skipping to change at line 326 skipping to change at line 352
typedef typename RegionStatisticsArray::value_type RegionStatistics; typedef typename RegionStatisticsArray::value_type RegionStatistics;
typedef typename PromoteTraits<typename RegionStatistics::cost_type, do uble>::Promote CostType; typedef typename PromoteTraits<typename RegionStatistics::cost_type, do uble>::Promote CostType;
typedef detail::SeedRgVoxel<CostType, Diff_type> Voxel; typedef detail::SeedRgVoxel<CostType, Diff_type> Voxel;
typename Voxel::Allocator allocator; typename Voxel::Allocator allocator;
typedef std::priority_queue< Voxel *, typedef std::priority_queue< Voxel *,
std::vector<Voxel *>, std::vector<Voxel *>,
typename Voxel::Compare > SeedRgVoxelHeap ; typename Voxel::Compare > SeedRgVoxelHeap ;
typedef MultiArray<3, int> IVolume; typedef MultiArray<3, int> IVolume;
typedef IVolume::traverser Traverser;
// copy seed image in an image with border // copy seed image in an image with border
Diff_type regionshape = shape + Diff_type(2,2,2); Diff_type regionshape = shape + Diff_type(2,2,2);
IVolume regions(regionshape); IVolume regions(regionshape);
MultiIterator<3,int> ir = regions.traverser_begin(); Traverser ir = regions.traverser_begin();
ir = ir + Diff_type(1,1,1); ir = ir + Diff_type(1,1,1);
//IVolume::Iterator iry, irx, irz; //IVolume::Iterator iry, irx, irz;
MultiIterator<3,int> iry, irx, irz; Traverser iry, irx, irz;
//initImageBorder(destImageRange(regions), 1, SRGWatershedLabel); //initImageBorder(destImageRange(regions), 1, SRGWatershedLabel);
initMultiArrayBorder(destMultiArrayRange(regions), 1, SRGWatershedLabel ); initMultiArrayBorder(destMultiArrayRange(regions), 1, SRGWatershedLabel );
copyMultiArray(seedsul, Diff_type(w,h,d), aseeds, ir, AccessorTraits<in t>::default_accessor()); copyMultiArray(seedsul, Diff_type(w,h,d), aseeds, ir, AccessorTraits<in t>::default_accessor());
// allocate and init memory for the results // allocate and init memory for the results
SeedRgVoxelHeap pheap; SeedRgVoxelHeap pheap;
int cneighbor; int cneighbor;
#if 0
static const Diff_type dist[] = { Diff_type(-1, 0, 0), Diff_type( 0,-1,
0),
Diff_type( 1, 0, 0), Diff_type( 0, 1,
0),
Diff_type( 0, 0,-1), Diff_type( 0, 0,
1) };
#endif
typedef typename Neighborhood::Direction Direction; typedef typename Neighborhood::Direction Direction;
int directionCount = Neighborhood::DirectionCount; int directionCount = Neighborhood::DirectionCount;
Diff_type pos(0,0,0); Diff_type pos(0,0,0);
for(isz=srcul, irz=ir, pos[2]=0; pos[2]<d; for(isz=srcul, irz=ir, pos[2]=0; pos[2]<d;
pos[2]++, isz.dim2()++, irz.dim2()++) pos[2]++, isz.dim2()++, irz.dim2()++)
{ {
//std::cerr << "Z = " << pos[2] << std::endl; //std::cerr << "Z = " << pos[2] << std::endl;
skipping to change at line 570 skipping to change at line 591
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestImageIterator, DestAccessor> img4, pair<DestImageIterator, DestAccessor> img4,
RegionStatisticsArray & stats) RegionStatisticsArray & stats)
{ {
seededRegionGrowing3D(img1.first, img1.second, img1.third, seededRegionGrowing3D(img1.first, img1.second, img1.third,
img3.first, img3.second, img3.first, img3.second,
img4.first, img4.second, img4.first, img4.second,
stats); stats);
} }
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray, class Neighborhood>
inline void
seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
MultiArrayView<3, TS, AS> const & img3,
MultiArrayView<3, T2, S2> img4,
RegionStatisticsArray & stats,
SRGType srgType, Neighborhood n, double max_cost)
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing3D(): shape mismatch between input and output."
);
seededRegionGrowing3D(srcMultiArrayRange(img1),
srcMultiArray(img3),
destMultiArray(img4),
stats, srgType, n, max_cost);
}
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray, class Neighborhood>
inline void
seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
MultiArrayView<3, TS, AS> const & img3,
MultiArrayView<3, T2, S2> img4,
RegionStatisticsArray & stats,
SRGType srgType, Neighborhood n)
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing3D(): shape mismatch between input and output."
);
seededRegionGrowing3D(srcMultiArrayRange(img1),
srcMultiArray(img3),
destMultiArray(img4),
stats, srgType, n, NumericTraits<double>::max());
}
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray>
inline void
seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
MultiArrayView<3, TS, AS> const & img3,
MultiArrayView<3, T2, S2> img4,
RegionStatisticsArray & stats, SRGType srgType)
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing3D(): shape mismatch between input and output."
);
seededRegionGrowing3D(srcMultiArrayRange(img1),
srcMultiArray(img3),
destMultiArray(img4),
stats, srgType, NeighborCode3DSix());
}
template <class T1, class S1,
class TS, class AS,
class T2, class S2,
class RegionStatisticsArray>
inline void
seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
MultiArrayView<3, TS, AS> const & img3,
MultiArrayView<3, T2, S2> img4,
RegionStatisticsArray & stats)
{
vigra_precondition(img1.shape() == img3.shape(),
"seededRegionGrowing3D(): shape mismatch between input and output."
);
seededRegionGrowing3D(srcMultiArrayRange(img1),
srcMultiArray(img3),
destMultiArray(img4),
stats);
}
} // namespace vigra } // namespace vigra
#endif // VIGRA_SEEDEDREGIONGROWING_HXX #endif // VIGRA_SEEDEDREGIONGROWING_HXX
 End of changes. 10 change blocks. 
13 lines changed or deleted 112 lines changed or added


 separableconvolution.hxx   separableconvolution.hxx 
skipping to change at line 46 skipping to change at line 46
#ifndef VIGRA_SEPARABLECONVOLUTION_HXX #ifndef VIGRA_SEPARABLECONVOLUTION_HXX
#define VIGRA_SEPARABLECONVOLUTION_HXX #define VIGRA_SEPARABLECONVOLUTION_HXX
#include <cmath> #include <cmath>
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "imageiteratoradapter.hxx" #include "imageiteratoradapter.hxx"
#include "bordertreatment.hxx" #include "bordertreatment.hxx"
#include "gaussians.hxx" #include "gaussians.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
template <class ARITHTYPE>
class Kernel1D;
/********************************************************/ /********************************************************/
/* */ /* */
/* internalConvolveLineOptimistic */ /* internalConvolveLineOptimistic */
/* */ /* */
/********************************************************/ /********************************************************/
// This function assumes that the input array is actually larger than // This function assumes that the input array is actually larger than
// the range [is, iend), so that it can safely access values outside // the range [is, iend), so that it can safely access values outside
// this range. This is useful if (1) we work on a small ROI, or // this range. This is useful if (1) we work on a small ROI, or
// (2) we enlarge the input by copying with border treatment. // (2) we enlarge the input by copying with border treatment.
skipping to change at line 794 skipping to change at line 798
If <tt>start</tt> and <tt>stop</tt> are non-zero, the relation If <tt>start</tt> and <tt>stop</tt> are non-zero, the relation
<tt>0 <= start < stop <= width</tt> must hold (where <tt>width</tt> <tt>0 <= start < stop <= width</tt> must hold (where <tt>width</tt>
is the length of the input array). The convolution is then restricted t o that is the length of the input array). The convolution is then restricted t o that
subrange, and it is assumed that the output array only refers to that subrange, and it is assumed that the output array only refers to that
subrange (i.e. <tt>id</tt> points to the element corresponding to subrange (i.e. <tt>id</tt> points to the element corresponding to
<tt>start</tt>). If <tt>start</tt> and <tt>stop</tt> are both zero <tt>start</tt>). If <tt>start</tt> and <tt>stop</tt> are both zero
(the default), the entire array is convolved. (the default), the entire array is convolved.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void convolveLine(SrcIterator is, SrcIterator isend, SrcAccessor sa , void convolveLine(SrcIterator is, SrcIterator isend, SrcAccessor sa ,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator ik, KernelAccessor ka, KernelIterator ik, KernelAccessor ka,
int kleft, int kright, BorderTreatmentMode border , int kleft, int kright, BorderTreatmentMode border ,
int start = 0, int stop = 0 ) int start = 0, int stop = 0 )
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void convolveLine(triple<SrcIterator, SrcIterator, SrcAccessor> src , void convolveLine(triple<SrcIterator, SrcIterator, SrcAccessor> src ,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, tuple5<KernelIterator, KernelAccessor,
int, int, BorderTreatmentMode> kernel, int, int, BorderTreatmentMode> kernel,
int start = 0, int stop = 0) int start = 0, int stop = 0)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/separableconvolution.hxx\> <b>\#include</b> \<vigra/separableconvolution.hxx\><br/>
Namespace: vigra
\code \code
std::vector<float> src, dest; std::vector<float> src, dest;
... ...
// define binomial filter of size 5 // define binomial filter of size 5
static float kernel[] = static float kernel[] =
{ 1.0/16.0, 4.0/16.0, 6.0/16.0, 4.0/16.0, 1.0/16.0}; { 1.0/16.0, 4.0/16.0, 6.0/16.0, 4.0/16.0, 1.0/16.0};
typedef vigra::StandardAccessor<float> FAccessor; typedef vigra::StandardAccessor<float> FAccessor;
skipping to change at line 886 skipping to change at line 890
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
kleft <= 0 kleft <= 0
kright >= 0 kright >= 0
iend - is >= kright + kleft + 1 iend - is >= kright + kleft + 1
\endcode \endcode
If border == BORDER_TREATMENT_CLIP: Sum of kernel elements must be If border == BORDER_TREATMENT_CLIP: Sum of kernel elements must be
!= 0. != 0.
*/ */
doxygen_overloaded_function(template <...> void convolveLine) doxygen_overloaded_function(template <...> void convolveLine)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void convolveLine(SrcIterator is, SrcIterator iend, SrcAccessor sa, void convolveLine(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator ik, KernelAccessor ka, KernelIterator ik, KernelAccessor ka,
int kleft, int kright, BorderTreatmentMode border, int kleft, int kright, BorderTreatmentMode border,
int start = 0, int stop = 0) int start = 0, int stop = 0)
{ {
typedef typename KernelAccessor::value_type KernelValue;
vigra_precondition(kleft <= 0, vigra_precondition(kleft <= 0,
"convolveLine(): kleft must be <= 0.\n"); "convolveLine(): kleft must be <= 0.\n");
vigra_precondition(kright >= 0, vigra_precondition(kright >= 0,
"convolveLine(): kright must be >= 0.\n"); "convolveLine(): kright must be >= 0.\n");
// int w = iend - is; // int w = iend - is;
int w = std::distance( is, iend ); int w = std::distance( is, iend );
vigra_precondition(w >= std::max(kright, -kleft) + 1, vigra_precondition(w >= std::max(kright, -kleft) + 1,
"convolveLine(): kernel longer than line.\n"); "convolveLine(): kernel longer than line.\n");
skipping to change at line 1000 skipping to change at line 1001
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Performs a 1 dimensional convolution in x direction. /** \brief Performs a 1 dimensional convolution in x direction.
It calls \ref convolveLine() for every row of the image. See \ref convo lveLine() It calls \ref convolveLine() for every row of the image. See \ref convo lveLine()
for more information about required interfaces and vigra_preconditions. for more information about required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class T3>
void
separableConvolveX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T3> const & kernel);
}
\endcode
\deprecatedAPI{separableConvolveX}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void separableConvolveX(SrcImageIterator supperleft, void separableConvolveX(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor s a, SrcImageIterator slowerright, SrcAccessor s a,
DestImageIterator dupperleft, DestAccessor da, DestImageIterator dupperleft, DestAccessor da,
KernelIterator ik, KernelAccessor ka, KernelIterator ik, KernelAccessor ka,
int kleft, int kright, BorderTreatmentMode border) int kleft, int kright, BorderTreatmentMode border)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void separableConvolveX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, void separableConvolveX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, tuple5<KernelIterator, KernelAccessor,
int, int, BorderTreatmentMode> kernel) int, int, BorderTreatmentMode> kernel)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/separableconvolution.hxx\> <b>\#include</b> \<vigra/separableconvolution.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), dest(w,h);
...
// define Gaussian kernel with std. deviation 3.0
Kernel1D<double> kernel;
kernel.initGaussian(3.0);
// apply 1D filter along the x-axis
separableConvolveX(src, dest, kernel);
\endcode
\deprecatedUsage{separableConvolveX}
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// define Gaussian kernel with std. deviation 3.0 // define Gaussian kernel with std. deviation 3.0
vigra::Kernel1D<double> kernel; vigra::Kernel1D<double> kernel;
kernel.initGaussian(3.0); kernel.initGaussian(3.0);
// apply 1D filter along the x-axis
vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d (kernel)); vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d (kernel));
\endcode \endcode
\deprecatedEnd
<b>Preconditions:</b>
<ul>
<li> The x-axis must be longer than the kernel radius: <tt>w > std::max
(kernel.right(), -kernel.left())</tt>.
<li> If <tt>border == BORDER_TREATMENT_CLIP</tt>: The sum of kernel ele
ments must be != 0.
</ul>
*/ */
doxygen_overloaded_function(template <...> void separableConvolveX) doxygen_overloaded_function(template <...> void separableConvolveX)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void separableConvolveX(SrcIterator supperleft, void separableConvolveX(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
KernelIterator ik, KernelAccessor ka, KernelIterator ik, KernelAccessor ka,
int kleft, int kright, BorderTreatmentMode border) int kleft, int kright, BorderTreatmentMode border)
{ {
typedef typename KernelAccessor::value_type KernelValue;
vigra_precondition(kleft <= 0, vigra_precondition(kleft <= 0,
"separableConvolveX(): kleft must be <= 0.\n"); "separableConvolveX(): kleft must be <= 0.\n");
vigra_precondition(kright >= 0, vigra_precondition(kright >= 0,
"separableConvolveX(): kright must be >= 0.\n"); "separableConvolveX(): kright must be >= 0.\n");
int w = slowerright.x - supperleft.x; int w = slowerright.x - supperleft.x;
int h = slowerright.y - supperleft.y; int h = slowerright.y - supperleft.y;
vigra_precondition(w >= std::max(kright, -kleft) + 1, vigra_precondition(w >= std::max(kright, -kleft) + 1,
"separableConvolveX(): kernel longer than line\n"); "separableConvolveX(): kernel longer than line\n");
skipping to change at line 1085 skipping to change at line 1119
convolveLine(rs, rs+w, sa, rd, da, convolveLine(rs, rs+w, sa, rd, da,
ik, ka, kleft, kright, border); ik, ka, kleft, kright, border);
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
inline void inline void
separableConvolveX(triple<SrcIterator, SrcIterator, SrcAccessor> src, separableConvolveX(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, tuple5<KernelIterator, KernelAccessor,
int, int, BorderTreatmentMode> kernel) int, int, BorderTreatmentMode> kernel)
{ {
separableConvolveX(src.first, src.second, src.third, separableConvolveX(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
kernel.first, kernel.second, kernel.first, kernel.second,
kernel.third, kernel.fourth, kernel.fifth); kernel.third, kernel.fourth, kernel.fifth);
}
template <class T1, class S1,
class T2, class S2,
class T3>
inline void
separableConvolveX(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T3> const & kernel)
{
vigra_precondition(src.shape() == dest.shape(),
"separableConvolveX(): shape mismatch between input and output.");
separableConvolveX(srcImageRange(src),
destImage(dest), kernel1d(kernel));
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* separableConvolveY */ /* separableConvolveY */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Performs a 1 dimensional convolution in y direction. /** \brief Performs a 1 dimensional convolution in y direction.
It calls \ref convolveLine() for every column of the image. See \ref co nvolveLine() It calls \ref convolveLine() for every column of the image. See \ref co nvolveLine()
for more information about required interfaces and vigra_preconditions. for more information about required interfaces and vigra_preconditions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class T3>
void
separableConvolveY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T3> const & kernel);
}
\endcode
\deprecatedAPI{separableConvolveY}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void separableConvolveY(SrcImageIterator supperleft, void separableConvolveY(SrcImageIterator supperleft,
SrcImageIterator slowerright, SrcAccessor s a, SrcImageIterator slowerright, SrcAccessor s a,
DestImageIterator dupperleft, DestAccessor da, DestImageIterator dupperleft, DestAccessor da,
KernelIterator ik, KernelAccessor ka, KernelIterator ik, KernelAccessor ka,
int kleft, int kright, BorderTreatmentMode border) int kleft, int kright, BorderTreatmentMode border)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void separableConvolveY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, void separableConvolveY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, tuple5<KernelIterator, KernelAccessor,
int, int, BorderTreatmentMode> kernel) int, int, BorderTreatmentMode> kernel)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/separableconvolution.hxx\> <b>\#include</b> \<vigra/separableconvolution.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
...
// define Gaussian kernel with std. deviation 3.0
Kernel1D kernel;
kernel.initGaussian(3.0);
// apply 1D filter along the y-axis
separableConvolveY(src, dest, kernel);
\endcode
\deprecatedUsage{separableConvolveY}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// define Gaussian kernel with std. deviation 3.0 // define Gaussian kernel with std. deviation 3.0
vigra::Kernel1D kernel; vigra::Kernel1D kernel;
kernel.initGaussian(3.0); kernel.initGaussian(3.0);
vigra::separableConvolveY(srcImageRange(src), destImage(dest), kernel1d (kernel)); vigra::separableConvolveY(srcImageRange(src), destImage(dest), kernel1d (kernel));
\endcode \endcode
\deprecatedEnd
<b>Preconditions:</b>
<ul>
<li> The y-axis must be longer than the kernel radius: <tt>h > std::max
(kernel.right(), -kernel.left())</tt>.
<li> If <tt>border == BORDER_TREATMENT_CLIP</tt>: The sum of kernel ele
ments must be != 0.
</ul>
*/ */
doxygen_overloaded_function(template <...> void separableConvolveY) doxygen_overloaded_function(template <...> void separableConvolveY)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void separableConvolveY(SrcIterator supperleft, void separableConvolveY(SrcIterator supperleft,
SrcIterator slowerright, SrcAccessor sa, SrcIterator slowerright, SrcAccessor sa,
DestIterator dupperleft, DestAccessor da, DestIterator dupperleft, DestAccessor da,
KernelIterator ik, KernelAccessor ka, KernelIterator ik, KernelAccessor ka,
int kleft, int kright, BorderTreatmentMode border) int kleft, int kright, BorderTreatmentMode border)
{ {
typedef typename KernelAccessor::value_type KernelValue;
vigra_precondition(kleft <= 0, vigra_precondition(kleft <= 0,
"separableConvolveY(): kleft must be <= 0.\n"); "separableConvolveY(): kleft must be <= 0.\n");
vigra_precondition(kright >= 0, vigra_precondition(kright >= 0,
"separableConvolveY(): kright must be >= 0.\n"); "separableConvolveY(): kright must be >= 0.\n");
int w = slowerright.x - supperleft.x; int w = slowerright.x - supperleft.x;
int h = slowerright.y - supperleft.y; int h = slowerright.y - supperleft.y;
vigra_precondition(h >= std::max(kright, -kleft) + 1, vigra_precondition(h >= std::max(kright, -kleft) + 1,
"separableConvolveY(): kernel longer than line\n"); "separableConvolveY(): kernel longer than line\n");
skipping to change at line 1193 skipping to change at line 1273
convolveLine(cs, cs+h, sa, cd, da, convolveLine(cs, cs+h, sa, cd, da,
ik, ka, kleft, kright, border); ik, ka, kleft, kright, border);
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
inline void inline void
separableConvolveY(triple<SrcIterator, SrcIterator, SrcAccessor> src, separableConvolveY(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, tuple5<KernelIterator, KernelAccessor,
int, int, BorderTreatmentMode> kernel) int, int, BorderTreatmentMode> kernel)
{ {
separableConvolveY(src.first, src.second, src.third, separableConvolveY(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
kernel.first, kernel.second, kernel.first, kernel.second,
kernel.third, kernel.fourth, kernel.fifth); kernel.third, kernel.fourth, kernel.fifth);
}
template <class T1, class S1,
class T2, class S2,
class T3>
inline void
separableConvolveY(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel1D<T3> const & kernel)
{
vigra_precondition(src.shape() == dest.shape(),
"separableConvolveY(): shape mismatch between input and output.");
separableConvolveY(srcImageRange(src),
destImage(dest), kernel1d(kernel));
} }
//@} //@}
/********************************************************/ /********************************************************/
/* */ /* */
/* Kernel1D */ /* Kernel1D */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 1226 skipping to change at line 1320
Convolution functions access the kernel via a 1 dimensional random acce ss Convolution functions access the kernel via a 1 dimensional random acce ss
iterator which they get by calling \ref center(). This iterator iterator which they get by calling \ref center(). This iterator
points to the center of the kernel. The kernel's size is given by its l eft() (<=0) points to the center of the kernel. The kernel's size is given by its l eft() (<=0)
and right() (>= 0) methods. The desired border treatment mode is and right() (>= 0) methods. The desired border treatment mode is
returned by borderTreatment(). returned by borderTreatment().
The different init functions create a kernel with the specified The different init functions create a kernel with the specified
properties. The kernel's value_type must be a linear space, i.e. it properties. The kernel's value_type must be a linear space, i.e. it
must define multiplication with doubles and NumericTraits. must define multiplication with doubles and NumericTraits.
The kernel defines a factory function kernel1d() to create an argument
object
(see \ref KernelArgumentObjectFactories).
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/stdconvolution.hxx\> <b>\#include</b> \<vigra/separableconvolution.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), dest(w,h);
...
// define Gaussian kernel with std. deviation 3.0
Kernel1D kernel;
kernel.initGaussian(3.0);
// apply 1D kernel along the x-axis
separableConvolveX(src, dest, kernel);
\endcode
\deprecatedUsage{Kernel1D}
The kernel defines a factory function kernel1d() to create an argument
object
(see \ref KernelArgumentObjectFactories).
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// define Gaussian kernel with std. deviation 3.0 // define Gaussian kernel with std. deviation 3.0
vigra::Kernel1D kernel; vigra::Kernel1D kernel;
kernel.initGaussian(3.0); kernel.initGaussian(3.0);
vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d (kernel)); vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d (kernel));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
value_type v = vigra::NumericTraits<value_type>::one(); // if norm is n ot value_type v = vigra::NumericTraits<value_type>::one(); // if norm is n ot
// given explic itly // given explic itly
double d; double d;
v = d * v; v = d * v;
\endcode \endcode
\deprecatedEnd
*/ */
template <class ARITHTYPE> template <class ARITHTYPE = double>
class Kernel1D class Kernel1D
{ {
public: public:
typedef ArrayVector<ARITHTYPE> InternalVector; typedef ArrayVector<ARITHTYPE> InternalVector;
/** the kernel's value type /** the kernel's value type
*/ */
typedef typename InternalVector::value_type value_type; typedef typename InternalVector::value_type value_type;
/** the kernel's reference type /** the kernel's reference type
skipping to change at line 1772 skipping to change at line 1878
void initAveraging(int radius, value_type norm); void initAveraging(int radius, value_type norm);
/** Init as an Averaging filter with norm 1. /** Init as an Averaging filter with norm 1.
*/ */
void initAveraging(int radius) void initAveraging(int radius)
{ {
initAveraging(radius, one()); initAveraging(radius, one());
} }
/** /**
Init as a symmetric gradient filter of the form Init as a symmetric gradient filter of the form
<TT>[ 0.5 * norm, 0.0 * norm, -0.5 * norm]</TT> <TT>[ 0.5 * norm, 0.0 * norm, -0.5 * norm]</TT>
<b>Deprecated</b>. Use initSymmetricDifference() instead. <b>Deprecated</b>. Use initSymmetricDifference() instead.
Postconditions: Postconditions:
\code \code
1. left() == -1 1. left() == -1
2. right() == 1 2. right() == 1
3. borderTreatment() == BORDER_TREATMENT_REPEAT 3. borderTreatment() == BORDER_TREATMENT_REPEAT
4. norm() == norm 4. norm() == norm
\endcode \endcode
*/ */
void void initSymmetricGradient(value_type norm )
initSymmetricGradient(value_type norm )
{ {
initSymmetricDifference(norm); initSymmetricDifference(norm);
setBorderTreatment(BORDER_TREATMENT_REPEAT); setBorderTreatment(BORDER_TREATMENT_REPEAT);
} }
/** Init as a symmetric gradient filter with norm 1. /** Init as a symmetric gradient filter with norm 1.
<b>Deprecated</b>. Use initSymmetricDifference() instead. <b>Deprecated</b>. Use initSymmetricDifference() instead.
*/ */
void initSymmetricGradient() void initSymmetricGradient()
skipping to change at line 1849 skipping to change at line 1954
3. borderTreatment() == BORDER_TREATMENT_REFLECT 3. borderTreatment() == BORDER_TREATMENT_REFLECT
4. norm() == 1.0 4. norm() == 1.0
\endcode \endcode
*/ */
void initBackwardDifference() void initBackwardDifference()
{ {
this->initExplicitly(0, 1) = 1.0, -1.0; this->initExplicitly(0, 1) = 1.0, -1.0;
this->setBorderTreatment(BORDER_TREATMENT_REFLECT); this->setBorderTreatment(BORDER_TREATMENT_REFLECT);
} }
void void initSymmetricDifference(value_type norm );
initSymmetricDifference(value_type norm );
/** Init as the 3-tap symmetric difference filter /** Init as the 3-tap symmetric difference filter
The filter values are The filter values are
\code \code
[0.5, 0, -0.5] [0.5, 0, -0.5]
\endcode \endcode
Postconditions: Postconditions:
\code \code
skipping to change at line 1888 skipping to change at line 1992
\endcode \endcode
Postconditions: Postconditions:
\code \code
1. left() == -1 1. left() == -1
2. right() == 1 2. right() == 1
3. borderTreatment() == BORDER_TREATMENT_REFLECT 3. borderTreatment() == BORDER_TREATMENT_REFLECT
4. norm() == 1 4. norm() == 1
\endcode \endcode
*/ */
void void initSecondDifference3()
initSecondDifference3()
{ {
this->initExplicitly(-1, 1) = 1.0, -2.0, 1.0; this->initExplicitly(-1, 1) = 1.0, -2.0, 1.0;
this->setBorderTreatment(BORDER_TREATMENT_REFLECT); this->setBorderTreatment(BORDER_TREATMENT_REFLECT);
} }
/** /**
Init an optimal 5-tap first derivative filter. Init an optimal 5-tap first derivative filter.
This filter must be used in conjunction with the corresponding 5 This filter must be used in conjunction with the corresponding
-tap smoothing filter 5-tap smoothing filter
(see initOptimalFirstDerivativeSmoothing5()), such that the deri (see initOptimalFirstDerivativeSmoothing5()), such that the der
vative filter is applied along one dimension, ivative filter is applied along one dimension,
and the smoothing filter along the other. and the smoothing filter along the other.
The filter values are The filter values are
\code \code
[0.1, 0.3, 0.0, -0.3, -0.1] [0.1, 0.3, 0.0, -0.3, -0.1]
\endcode \endcode
These values are optimal in the sense that the 5x5 filter obtai ned by combining These values are optimal in the sense that the 5x5 filter obtai ned by combining
this filter with the corresponding 5-tap smoothing filter is th e best possible 5x5 approximation to a this filter with the corresponding 5-tap smoothing filter is th e best possible 5x5 approximation to a
Gaussian first derivative filter. The equivalent Gaussian has s igma = 0.906. Gaussian first derivative filter. The equivalent Gaussian has s igma = 0.906.
skipping to change at line 1929 skipping to change at line 2032
\endcode \endcode
*/ */
void initOptimalFirstDerivative5() void initOptimalFirstDerivative5()
{ {
this->initExplicitly(-2, 2) = 0.1, 0.3, 0.0, -0.3, -0.1; this->initExplicitly(-2, 2) = 0.1, 0.3, 0.0, -0.3, -0.1;
this->setBorderTreatment(BORDER_TREATMENT_REFLECT); this->setBorderTreatment(BORDER_TREATMENT_REFLECT);
} }
/** /**
Init an optimal 5-tap second derivative filter. Init an optimal 5-tap second derivative filter.
This filter must be used in conjunction with the corresponding 5 This filter must be used in conjunction with the corresponding
-tap smoothing filter 5-tap smoothing filter
(see initOptimalSecondDerivativeSmoothing5()), such that the der (see initOptimalSecondDerivativeSmoothing5()), such that the de
ivative filter is applied along one dimension, rivative filter is applied along one dimension,
and the smoothing filter along the other. and the smoothing filter along the other.
The filter values are The filter values are
\code \code
[0.22075, 0.117, -0.6755, 0.117, 0.22075] [0.22075, 0.117, -0.6755, 0.117, 0.22075]
\endcode \endcode
These values are optimal in the sense that the 5x5 filter obtai ned by combining These values are optimal in the sense that the 5x5 filter obtai ned by combining
this filter with the corresponding 5-tap smoothing filter is th e best possible 5x5 approximation to a this filter with the corresponding 5-tap smoothing filter is th e best possible 5x5 approximation to a
Gaussian second derivative filter. The equivalent Gaussian has sigma = 0.817. Gaussian second derivative filter. The equivalent Gaussian has sigma = 0.817.
skipping to change at line 2142 skipping to change at line 2245
{ {
*k = *k * sum; *k = *k * sum;
} }
norm_ = norm; norm_ = norm;
} }
/***********************************************************************/ /***********************************************************************/
template <class ARITHTYPE> template <class ARITHTYPE>
void Kernel1D<ARITHTYPE>::initGaussian(double std_dev, void
value_type norm, Kernel1D<ARITHTYPE>::initGaussian(double std_dev,
double windowRatio) value_type norm,
double windowRatio)
{ {
vigra_precondition(std_dev >= 0.0, vigra_precondition(std_dev >= 0.0,
"Kernel1D::initGaussian(): Standard deviation must be >= 0.") ; "Kernel1D::initGaussian(): Standard deviation must be >= 0.") ;
vigra_precondition(windowRatio >= 0.0, vigra_precondition(windowRatio >= 0.0,
"Kernel1D::initGaussian(): windowRatio must be >= 0."); "Kernel1D::initGaussian(): windowRatio must be >= 0.");
if(std_dev > 0.0) if(std_dev > 0.0)
{ {
Gaussian<ARITHTYPE> gauss((ARITHTYPE)std_dev); Gaussian<ARITHTYPE> gauss((ARITHTYPE)std_dev);
skipping to change at line 2195 skipping to change at line 2299
else else
norm_ = 1.0; norm_ = 1.0;
// best border treatment for Gaussians is BORDER_TREATMENT_REFLECT // best border treatment for Gaussians is BORDER_TREATMENT_REFLECT
border_treatment_ = BORDER_TREATMENT_REFLECT; border_treatment_ = BORDER_TREATMENT_REFLECT;
} }
/***********************************************************************/ /***********************************************************************/
template <class ARITHTYPE> template <class ARITHTYPE>
void Kernel1D<ARITHTYPE>::initDiscreteGaussian(double std_dev, void
value_type norm) Kernel1D<ARITHTYPE>::initDiscreteGaussian(double std_dev,
value_type norm)
{ {
vigra_precondition(std_dev >= 0.0, vigra_precondition(std_dev >= 0.0,
"Kernel1D::initDiscreteGaussian(): Standard deviation must be >= 0."); "Kernel1D::initDiscreteGaussian(): Standard deviation must be >= 0.");
if(std_dev > 0.0) if(std_dev > 0.0)
{ {
// first calculate required kernel sizes // first calculate required kernel sizes
int radius = (int)(3.0*std_dev + 0.5); int radius = (int)(3.0*std_dev + 0.5);
if(radius == 0) if(radius == 0)
radius = 1; radius = 1;
skipping to change at line 2371 skipping to change at line 2476
right_ = radius; right_ = radius;
norm_ = norm; norm_ = norm;
// best border treatment for Binomial is BORDER_TREATMENT_REFLECT // best border treatment for Binomial is BORDER_TREATMENT_REFLECT
border_treatment_ = BORDER_TREATMENT_REFLECT; border_treatment_ = BORDER_TREATMENT_REFLECT;
} }
/***********************************************************************/ /***********************************************************************/
template <class ARITHTYPE> template <class ARITHTYPE>
void Kernel1D<ARITHTYPE>::initAveraging(int radius, void
value_type norm) Kernel1D<ARITHTYPE>::initAveraging(int radius,
value_type norm)
{ {
vigra_precondition(radius > 0, vigra_precondition(radius > 0,
"Kernel1D::initAveraging(): Radius must be > 0."); "Kernel1D::initAveraging(): Radius must be > 0.");
// calculate scaling // calculate scaling
double scale = 1.0 / (radius * 2 + 1); double scale = 1.0 / (radius * 2 + 1);
// normalize // normalize
kernel_.erase(kernel_.begin(), kernel_.end()); kernel_.erase(kernel_.begin(), kernel_.end());
kernel_.reserve(radius*2+1); kernel_.reserve(radius*2+1);
 End of changes. 47 change blocks. 
61 lines changed or deleted 171 lines changed or added


 sifImport.hxx   sifImport.hxx 
skipping to change at line 60 skipping to change at line 60
* 4. 6. 3.0 * 4. 6. 3.0
*/ */
#ifndef VIGRA_SIFIMPORT_HXX #ifndef VIGRA_SIFIMPORT_HXX
#define VIGRA_SIFIMPORT_HXX #define VIGRA_SIFIMPORT_HXX
#include <fstream> #include <fstream>
#include <cstring> #include <cstring>
#include <cstddef> #include <cstddef>
#include <vector> #include <vector>
#include "vigra/multi_array.hxx" #include "multi_array.hxx"
#include "vigra/array_vector.hxx" #include "array_vector.hxx"
namespace vigra { namespace vigra {
/** \addtogroup VigraSIFImport Import of Images from Andor Cameras /** \addtogroup VigraSIFImport Import of Images from Andor Cameras
Read an Andor SIF file into a MultiArrayView. Read an Andor SIF file into a MultiArrayView.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
skipping to change at line 178 skipping to change at line 178
and write them into the given 'array'. and write them into the given 'array'.
The array must have the correct number of dimensions and shape for the dataset The array must have the correct number of dimensions and shape for the dataset
represented by 'info'. represented by 'info'.
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
void void
readSIF(const SIFImportInfo &info, MultiArrayView<3, float, Unstrid edArrayTag> array); readSIF(const SIFImportInfo &info, MultiArrayView<3, float> array);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/sifImport.hxx\><br> <b>\#include</b> \<vigra/sifImport.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
SIFImportInfo info(filename); SIFImportInfo info(filename);
// create a 3D array of appropriate size // create a 3D array of appropriate size
typedef MultiArray<3, float>::difference_type Shape; typedef MultiArray<3, float>::difference_type Shape;
MultiArray<3, float> in(Shape(info.width(), info.height(), info.stacksi ze())); MultiArray<3, float> in(Shape(info.width(), info.height(), info.stacksi ze()));
readSIF(info, in); readSIF(info, in);
\endcode \endcode
*/ */
VIGRA_EXPORT void readSIF(const SIFImportInfo &info, MultiArrayView<3, floa VIGRA_EXPORT void readSIF(const SIFImportInfo &info, MultiArrayView<3, floa
t, UnstridedArrayTag> array); t> array);
template <unsigned int N, class T, class S>
void readSIF(const SIFImportInfo &info, MultiArrayView<N, T, S> array)
{
vigra_precondition(false, "readSIF(): Destination array must be MultiAr
rayView<3, float>.");
}
inline void readSIF(const SIFImportInfo &info, MultiArrayView<3, float, Uns
tridedArrayTag> array)
{
readSIF(info, MultiArrayView<3, float>(array));
}
/** /**
\brief Read parts of the image data from an Andor SIF file specified wi th an SIFImportinfo object \brief Read parts of the image data from an Andor SIF file specified wi th an SIFImportInfo object
and write them into the MultiArray array. and write them into the MultiArray array.
\code \code
SIFImportInfo info(filename); SIFImportInfo info(filename);
// create a 3D array of appropriate size // create a 3D array of appropriate size
MultiArray<3, float> in(Shape3(info.width(), info.height(), 1)); MultiArray<3, float> in(Shape3(info.width(), info.height(), 1));
readBlock(info, Shape3(0,0,0), Shape3(w,h,1), im); // read the first fr ame only readBlock(info, Shape3(0,0,0), Shape3(w,h,1), im); // read the first fr ame only
\endcode \endcode
*/ */
VIGRA_EXPORT void readSIFBlock(const SIFImportInfo &info, Shape3 offset, Sh VIGRA_EXPORT void readSIFBlock(const SIFImportInfo &info, Shape3 offset, Sh
ape3 shape, MultiArrayView<3, float, UnstridedArrayTag> array); ape3 shape, MultiArrayView<3, float> array);
template <unsigned int N, class T, class S>
void readSIFBlock(const SIFImportInfo &info, Shape3 offset, Shape3 shape, M
ultiArrayView<N, T, S> array)
{
vigra_precondition(false, "readSIFBlock(): Destination array must be Mu
ltiArrayView<3, float>.");
}
inline void readSIFBlock(const SIFImportInfo &info, Shape3 offset, Shape3 s
hape, MultiArrayView<3, float, UnstridedArrayTag> array)
{
readSIFBlock(info, offset, shape, MultiArrayView<3, float>(array));
}
VIGRA_EXPORT std::ostream& operator<<(std::ostream& os, const SIFImportInfo & info); VIGRA_EXPORT std::ostream& operator<<(std::ostream& os, const SIFImportInfo & info);
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_SIFIMPORT_HXX #endif // VIGRA_SIFIMPORT_HXX
 End of changes. 5 change blocks. 
8 lines changed or deleted 35 lines changed or added


 singular_value_decomposition.hxx   singular_value_decomposition.hxx 
skipping to change at line 69 skipping to change at line 69
The singular value decomposition always exists, so this function will The singular value decomposition always exists, so this function will
never fail (except if the shapes of the argument matrices don't match). never fail (except if the shapes of the argument matrices don't match).
The effective numerical rank of A is returned. The effective numerical rank of A is returned.
(Adapted from JAMA, a Java Matrix Library, developed jointly (Adapted from JAMA, a Java Matrix Library, developed jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama) . by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama) .
<b>\#include</b> \<vigra/singular_value_decomposition.hxx\> or<br> <b>\#include</b> \<vigra/singular_value_decomposition.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
*/ */
template <class T, class C1, class C2, class C3, class C4> template <class T, class C1, class C2, class C3, class C4>
unsigned int unsigned int
singularValueDecomposition(MultiArrayView<2, T, C1> const & A, singularValueDecomposition(MultiArrayView<2, T, C1> const & A,
MultiArrayView<2, T, C2> &U, MultiArrayView<2, T, C3> &S, MultiArrayVie w<2, T, C4> &V) MultiArrayView<2, T, C2> &U, MultiArrayView<2, T, C3> &S, MultiArrayVie w<2, T, C4> &V)
{ {
typedef T Real; typedef T Real;
typedef MultiArrayShape<2>::type Shape;
const MultiArrayIndex rows = rowCount(A); const MultiArrayIndex rows = rowCount(A);
const MultiArrayIndex cols = columnCount(A); const MultiArrayIndex cols = columnCount(A);
vigra_precondition(rows >= cols, vigra_precondition(rows >= cols,
"singularValueDecomposition(): Input matrix A must be rectangular wi th rowCount >= columnCount."); "singularValueDecomposition(): Input matrix A must be rectangular wi th rowCount >= columnCount.");
vigra_precondition(rowCount(S) == cols && columnCount(S) == 1, vigra_precondition(rowCount(S) == cols && columnCount(S) == 1,
"singularValueDecomposition(): Output S must be column vector with r owCount == columnCount(A)."); "singularValueDecomposition(): Output S must be column vector with r owCount == columnCount(A).");
vigra_precondition(rowCount(U) == rows && columnCount(U) == cols, vigra_precondition(rowCount(U) == rows && columnCount(U) == cols,
"singularValueDecomposition(): Output matrix U must have the same di mensions as input matrix A."); "singularValueDecomposition(): Output matrix U must have the same di mensions as input matrix A.");
vigra_precondition(rowCount(V) == cols && columnCount(V) == cols, vigra_precondition(rowCount(V) == cols && columnCount(V) == cols,
"singularValueDecomposition(): Output matrix V must be square with n = columnCount(A)."); "singularValueDecomposition(): Output matrix V must be square with n = columnCount(A).");
MultiArrayIndex m = rows; MultiArrayIndex m = rows;
MultiArrayIndex n = cols; MultiArrayIndex n = cols;
MultiArrayIndex nu = n; MultiArrayIndex nu = n;
U.init(0.0); U.init(0.0);
S.init(0.0); S.init(0.0);
V.init(0.0); V.init(0.0);
ArrayVector<Real> e((unsigned int)n); ArrayVector<Real> e(static_cast<unsigned int>(n));
ArrayVector<Real> work((unsigned int)m); ArrayVector<Real> work(static_cast<unsigned int>(m));
Matrix<Real> a(A); Matrix<Real> a(A);
MultiArrayView<1, T, C3> s = S.bindOuter(0); MultiArrayView<1, T, C3> s = S.bindOuter(0);
MultiArrayIndex i=0, j=0, k=0; MultiArrayIndex i=0, j=0, k=0;
// Reduce a to bidiagonal form, storing the diagonal elements // Reduce a to bidiagonal form, storing the diagonal elements
// in s and the super-diagonal elements in e. // in s and the super-diagonal elements in e.
MultiArrayIndex nct = std::min(m-1,n); MultiArrayIndex nct = std::min(m-1,n);
MultiArrayIndex nrt = std::max((MultiArrayIndex)0,n-2); MultiArrayIndex nrt = std::max(static_cast<MultiArrayIndex>(0),n-2);
for (k = 0; k < std::max(nct,nrt); ++k) for (k = 0; k < std::max(nct,nrt); ++k)
{ {
if (k < nct) if (k < nct)
{ {
// Compute the transformation for the k-th column and // Compute the transformation for the k-th column and
// place the k-th diagonal in s(k). // place the k-th diagonal in s(k).
// Compute 2-norm of k-th column without under/overflow. // Compute 2-norm of k-th column without under/overflow.
s(k) = 0.0; s(k) = 0.0;
for (i = k; i < m; ++i) for (i = k; i < m; ++i)
{ {
skipping to change at line 318 skipping to change at line 317
V(k, k) = 1.0; V(k, k) = 1.0;
} }
// Main iteration loop for the singular values. // Main iteration loop for the singular values.
MultiArrayIndex pp = p-1; MultiArrayIndex pp = p-1;
int iter = 0; int iter = 0;
Real eps = NumericTraits<Real>::epsilon()*2.0; Real eps = NumericTraits<Real>::epsilon()*2.0;
while (p > 0) while (p > 0)
{ {
MultiArrayIndex k=0; k=0;
int kase=0; int kase=0;
// Here is where a test for too many iterations would go. // Here is where a test for too many iterations would go.
// This section of the program inspects for // This section of the program inspects for
// negligible elements in the s and e arrays. On // negligible elements in the s and e arrays. On
// completion the variables kase and k are set as follows. // completion the variables kase and k are set as follows.
// kase = 1 if s(p) and e[k-1] are negligible and k<p // kase = 1 if s(p) and e[k-1] are negligible and k<p
// kase = 2 if s(k) is negligible and k<p // kase = 2 if s(k) is negligible and k<p
skipping to change at line 548 skipping to change at line 547
iter = 0; iter = 0;
--p; --p;
break; break;
} }
default: default:
vigra_fail("vigra::svd(): Internal error."); vigra_fail("vigra::svd(): Internal error.");
} }
} }
Real tol = std::max(m,n)*s(0)*eps; Real tol = std::max(m,n)*s(0)*eps;
unsigned int rank = 0; unsigned int rank = 0;
for (MultiArrayIndex i = 0; i < n; ++i) for (i = 0; i < n; ++i)
{ {
if (s(i) > tol) if (s(i) > tol)
{ {
++rank; ++rank;
} }
} }
return rank; // effective rank return rank; // effective rank
} }
} // namespace linalg } // namespace linalg
 End of changes. 6 change blocks. 
7 lines changed or deleted 6 lines changed or added


 slanted_edge_mtf.hxx   slanted_edge_mtf.hxx 
skipping to change at line 53 skipping to change at line 53
#include "fftw3.hxx" #include "fftw3.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "linear_solve.hxx" #include "linear_solve.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "static_assert.hxx" #include "static_assert.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "transformimage.hxx" #include "transformimage.hxx"
#include "utilities.hxx" #include "utilities.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup SlantedEdgeMTF Camera MTF Estimation /** \addtogroup SlantedEdgeMTF Camera MTF Estimation
Determine the magnitude transfer function (MTF) of a camera using the s lanted edge method. Determine the magnitude transfer function (MTF) of a camera using the s lanted edge method.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
skipping to change at line 76 skipping to change at line 77
/** \brief Pass options to one of the \ref slantedEdgeMTF() functions. /** \brief Pass options to one of the \ref slantedEdgeMTF() functions.
<tt>SlantedEdgeMTFOptions</tt> is an argument objects that holds vario us optional <tt>SlantedEdgeMTFOptions</tt> is an argument objects that holds vario us optional
parameters used by the \ref slantedEdgeMTF() functions. If a parameter is not explicitly parameters used by the \ref slantedEdgeMTF() functions. If a parameter is not explicitly
set, a suitable default will be used. Changing the defaults is only nec essary if you can't set, a suitable default will be used. Changing the defaults is only nec essary if you can't
obtain good input data, but absolutely need an MTF estimate. obtain good input data, but absolutely need an MTF estimate.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br> <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(w,h); MultiArray<2, float> src(w,h);
std::vector<vigra::TinyVector<double, 2> > mtf; std::vector<vigra::TinyVector<double, 2> > mtf;
... ...
vigra::slantedEdgeMTF(srcImageRange(src), mtf, slantedEdgeMTF(src, mtf,
vigra::SlantedEdgeMTFOptions().mtfSmoothingScale( SlantedEdgeMTFOptions().mtfSmoothingScale(1.0));
1.0));
// print the frequency / attenuation pairs found // print the frequency / attenuation pairs found
for(int k=0; k<result.size(); ++k) for(int k=0; k<result.size(); ++k)
std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation : " << mtf[k][1] << std::endl; std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation : " << mtf[k][1] << std::endl;
\endcode \endcode
*/ */
class SlantedEdgeMTFOptions class SlantedEdgeMTFOptions
{ {
public: public:
skipping to change at line 530 skipping to change at line 531
differ by at least 1 pixel between the two ends of the edge). differ by at least 1 pixel between the two ends of the edge).
<li> Our implementation uses a more accurate subpixel derivative algori thm. In addition, we first perform a shading <li> Our implementation uses a more accurate subpixel derivative algori thm. In addition, we first perform a shading
correction in order to reduce possible derivative bias due to nonu niform illumination. correction in order to reduce possible derivative bias due to nonu niform illumination.
<li> If the input image is large enough (i.e. there are at least 20 pix els on either side of the edge over <li> If the input image is large enough (i.e. there are at least 20 pix els on either side of the edge over
the edge's entire length), our algorithm attempts to subtract the estimated noise power spectrum the edge's entire length), our algorithm attempts to subtract the estimated noise power spectrum
from the estimated MTF. from the estimated MTF.
</ul> </ul>
The source value type (<TT>SrcAccessor::value_type</TT>) must be a scal The source value type <TT>T1</TT> must be a scalar type which is conver
ar type which is convertible to <tt>double</tt>. tible to <tt>double</tt>.
The result is written into the \a result sequence, whose <tt>value_type The result is written into the \a result sequence, which must be back-i
</tt> must be constructible nsertable (supports <tt>push_back()</tt>)
and whose <tt>value_type</tt> must be constructible
from two <tt>double</tt> values. Algorithm options can be set via the \ a options object from two <tt>double</tt> values. Algorithm options can be set via the \ a options object
(see \ref vigra::NoiseNormalizationOptions for details). (see \ref vigra::NoiseNormalizationOptions for details).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1, class BackInsertable>
void
slantedEdgeMTF(MultiArrayView<2, T1, S1> const & src, BackInsertabl
e & mtf,
SlantedEdgeMTFOptions const & options = SlantedEdgeM
TFOptions());
}
\endcode
\deprecatedAPI{slantedEdgeMTF}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
slantedEdgeMTF(SrcIterator sul, SrcIterator slr, SrcAccessor src, B ackInsertable & mtf, slantedEdgeMTF(SrcIterator sul, SrcIterator slr, SrcAccessor src, B ackInsertable & mtf,
SlantedEdgeMTFOptions const & options = SlantedEdgeMTFO ptions()); SlantedEdgeMTFOptions const & options = SlantedEdgeM TFOptions());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, class BackInsertabl e> template <class SrcIterator, class SrcAccessor, class BackInsertabl e>
void void
slantedEdgeMTF(triple<SrcIterator, SrcIterator, SrcAccessor> src, B ackInsertable & mtf, slantedEdgeMTF(triple<SrcIterator, SrcIterator, SrcAccessor> src, B ackInsertable & mtf,
SlantedEdgeMTFOptions const & options = SlantedEdgeM TFOptions()) SlantedEdgeMTFOptions const & options = SlantedEdgeM TFOptions())
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br> <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h);
std::vector<vigra::TinyVector<double, 2> > mtf;
...
// keep all options at their default values
slantedEdgeMTF(src, mtf);
// print the frequency / attenuation pairs found
for(int k=0; k<result.size(); ++k)
std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation
: " << mtf[k][1] << std::endl;
\endcode
\deprecatedUsage{slantedEdgeMTF}
\code
vigra::BImage src(w,h); vigra::BImage src(w,h);
std::vector<vigra::TinyVector<double, 2> > mtf; std::vector<vigra::TinyVector<double, 2> > mtf;
... ...
vigra::slantedEdgeMTF(srcImageRange(src), mtf); vigra::slantedEdgeMTF(srcImageRange(src), mtf);
// print the frequency / attenuation pairs found // print the frequency / attenuation pairs found
for(int k=0; k<result.size(); ++k) for(int k=0; k<result.size(); ++k)
std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation : " << mtf[k][1] << std::endl; std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation : " << mtf[k][1] << std::endl;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator upperleft, lowerright; SrcIterator upperleft, lowerright;
SrcAccessor src; SrcAccessor src;
typedef SrcAccessor::value_type SrcType; typedef SrcAccessor::value_type SrcType;
typedef NumericTraits<SrcType>::isScalar isScalar; typedef NumericTraits<SrcType>::isScalar isScalar;
assert(isScalar::asBool == true); assert(isScalar::asBool == true);
double value = src(uperleft); double value = src(uperleft);
BackInsertable result; BackInsertable result;
typedef BackInsertable::value_type ResultType; typedef BackInsertable::value_type ResultType;
double intensity, variance; double intensity, variance;
result.push_back(ResultType(intensity, variance)); result.push_back(ResultType(intensity, variance));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void slantedEdgeMTF) doxygen_overloaded_function(template <...> void slantedEdgeMTF)
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
void void
slantedEdgeMTF(SrcIterator sul, SrcIterator slr, SrcAccessor src, BackInser table & mtf, slantedEdgeMTF(SrcIterator sul, SrcIterator slr, SrcAccessor src, BackInser table & mtf,
SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOption s()) SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOption s())
{ {
DImage preparedInput; DImage preparedInput;
unsigned int edgeWidth = detail::prepareSlantedEdgeInput(sul, slr, src, preparedInput, options); unsigned int edgeWidth = detail::prepareSlantedEdgeInput(sul, slr, src, preparedInput, options);
skipping to change at line 621 skipping to change at line 647
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> template <class SrcIterator, class SrcAccessor, class BackInsertable>
inline void inline void
slantedEdgeMTF(triple<SrcIterator, SrcIterator, SrcAccessor> src, BackInser table & mtf, slantedEdgeMTF(triple<SrcIterator, SrcIterator, SrcAccessor> src, BackInser table & mtf,
SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOption s()) SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOption s())
{ {
slantedEdgeMTF(src.first, src.second, src.third, mtf, options); slantedEdgeMTF(src.first, src.second, src.third, mtf, options);
} }
template <class T1, class S1, class BackInsertable>
inline void
slantedEdgeMTF(MultiArrayView<2, T1, S1> const & src, BackInsertable & mtf,
SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOption
s())
{
slantedEdgeMTF(srcImageRange(src), mtf, options);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* mtfFitGaussian */ /* mtfFitGaussian */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Fit a Gaussian function to a given MTF. /** \brief Fit a Gaussian function to a given MTF.
This function expects a sequence of frequency / attenuation pairs as pr oduced by \ref slantedEdgeMTF() This function expects a sequence of frequency / attenuation pairs as pr oduced by \ref slantedEdgeMTF()
and finds the best fitting Gaussian point spread function (Gaussian fun ctions are good approximations and finds the best fitting Gaussian point spread function (Gaussian fun ctions are good approximations
skipping to change at line 647 skipping to change at line 681
\code \code
namespace vigra { namespace vigra {
template <class Vector> template <class Vector>
double mtfFitGaussian(Vector const & mtf); double mtfFitGaussian(Vector const & mtf);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br> <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(w,h); MultiArray<2, float> src(w,h);
std::vector<vigra::TinyVector<double, 2> > mtf; std::vector<vigra::TinyVector<double, 2> > mtf;
... ...
vigra::slantedEdgeMTF(srcImageRange(src), mtf); slantedEdgeMTF(src, mtf);
double scale = vigra::mtfFitGaussian(mtf) double scale = vigra::mtfFitGaussian(mtf)
std::cout << "The camera PSF is approximately a Gaussian at scale " << scale << std::endl; std::cout << "The camera PSF is approximately a Gaussian at scale " << scale << std::endl;
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
Vector mtf; Vector mtf;
int numberOfMeasurements = mtf.size() int numberOfMeasurements = mtf.size()
 End of changes. 18 change blocks. 
18 lines changed or deleted 55 lines changed or added


 splineimageview.hxx   splineimageview.hxx 
skipping to change at line 138 skipping to change at line 138
private: private:
typedef typename InternalImage::traverser InternalTraverser; typedef typename InternalImage::traverser InternalTraverser;
typedef typename InternalTraverser::row_iterator InternalRowIterator; typedef typename InternalTraverser::row_iterator InternalRowIterator;
typedef typename InternalTraverser::column_iterator InternalColumnItera tor; typedef typename InternalTraverser::column_iterator InternalColumnItera tor;
typedef BSpline<ORDER, double> Spline; typedef BSpline<ORDER, double> Spline;
enum { ksize_ = ORDER + 1, kcenter_ = ORDER / 2 }; enum { ksize_ = ORDER + 1, kcenter_ = ORDER / 2 };
public: public:
/** Construct SplineImageView for the given image.
/** Construct SplineImageView for a 2D MultiArrayView.
If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>),
the recursive
prefilter of the cardinal spline function is not applied, resul
ting
in an approximating (smoothing) rather than interpolating splin
e. This is
especially useful if customized prefilters are to be applied.
*/
template <class U, class S>
SplineImageView(MultiArrayView<2, U, S> const & s, bool skipPrefilterin
g = false)
: w_(s.shape(0)), h_(s.shape(1)), w1_(w_-1), h1_(h_-1),
x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcente
r_ - 2),
image_(w_, h_),
x_(-1.0), y_(-1.0),
u_(-1.0), v_(-1.0)
{
copyImage(srcImageRange(s), destImage(image_));
if(!skipPrefiltering)
init();
}
/** Construct SplineImageView for an image given by \ref ImageItera
tors and \ref DataAccessors.
If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>), the recursive If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>), the recursive
prefilter of the cardinal spline function is not applied, resul ting prefilter of the cardinal spline function is not applied, resul ting
in an approximating (smoothing) rather than interpolating splin e. This is in an approximating (smoothing) rather than interpolating splin e. This is
especially useful if customized prefilters are to be applied. especially useful if customized prefilters are to be applied.
*/ */
template <class SrcIterator, class SrcAccessor> template <class SrcIterator, class SrcAccessor>
SplineImageView(SrcIterator is, SrcIterator iend, SrcAccessor sa, bool skipPrefiltering = false) SplineImageView(SrcIterator is, SrcIterator iend, SrcAccessor sa, bool skipPrefiltering = false)
: w_(iend.x - is.x), h_(iend.y - is.y), w1_(w_-1), h1_(h_-1), : w_(iend.x - is.x), h_(iend.y - is.y), w1_(w_-1), h1_(h_-1),
x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcente r_ - 2), x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcente r_ - 2),
image_(w_, h_), image_(w_, h_),
x_(-1.0), y_(-1.0), x_(-1.0), y_(-1.0),
u_(-1.0), v_(-1.0) u_(-1.0), v_(-1.0)
{ {
copyImage(srcIterRange(is, iend, sa), destImage(image_)); copyImage(srcIterRange(is, iend, sa), destImage(image_));
if(!skipPrefiltering) if(!skipPrefiltering)
init(); init();
} }
/** Construct SplineImageView for the given image. /** Construct SplineImageView for an image given by \ref ArgumentO bjectFactories.
If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>), the recursive If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>), the recursive
prefilter of the cardinal spline function is not applied, resul ting prefilter of the cardinal spline function is not applied, resul ting
in an approximating (smoothing) rather than interpolating splin e. This is in an approximating (smoothing) rather than interpolating splin e. This is
especially useful if customized prefilters are to be applied. especially useful if customized prefilters are to be applied.
*/ */
template <class SrcIterator, class SrcAccessor> template <class SrcIterator, class SrcAccessor>
SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool s kipPrefiltering = false) SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool s kipPrefiltering = false)
: w_(s.second.x - s.first.x), h_(s.second.y - s.first.y), w1_(w_-1), h1 _(h_-1), : w_(s.second.x - s.first.x), h_(s.second.y - s.first.y), w1_(w_-1), h1 _(h_-1),
x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcente r_ - 2), x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcente r_ - 2),
skipping to change at line 669 skipping to change at line 690
} }
return detail::RequiresExplicitCast<VALUETYPE>::cast(sum); return detail::RequiresExplicitCast<VALUETYPE>::cast(sum);
} }
template <int ORDER, class VALUETYPE> template <int ORDER, class VALUETYPE>
template <class Array> template <class Array>
void void
SplineImageView<ORDER, VALUETYPE>::coefficientArray(double x, double y, Arr ay & res) const SplineImageView<ORDER, VALUETYPE>::coefficientArray(double x, double y, Arr ay & res) const
{ {
typedef typename Array::value_type ResType; typedef typename Array::value_type ResType;
typename Spline::WeightMatrix & weights = Spline::weights(); typename Spline::WeightMatrix const & weights = Spline::weights();
ResType tmp[ksize_][ksize_]; ResType tmp[ksize_][ksize_];
calculateIndices(x, y); calculateIndices(x, y);
for(int j=0; j<ksize_; ++j) for(int j=0; j<ksize_; ++j)
{ {
for(int i=0; i<ksize_; ++i) for(int i=0; i<ksize_; ++i)
{ {
tmp[i][j] = ResType(); tmp[i][j] = ResType();
for(int k=0; k<ksize_; ++k) for(int k=0; k<ksize_; ++k)
{ {
skipping to change at line 1763 skipping to change at line 1784
*/ */
SplineImageView1(InternalIndexer const & i) SplineImageView1(InternalIndexer const & i)
: Base(i.shape(0), i.shape(1), i) : Base(i.shape(0), i.shape(1), i)
{} {}
template<class T, class SU> template<class T, class SU>
SplineImageView1(MultiArrayView<2, T, SU> const & i) SplineImageView1(MultiArrayView<2, T, SU> const & i)
: Base(i.shape(0), i.shape(1)), : Base(i.shape(0), i.shape(1)),
image_(i.shape(0), i.shape(1)) image_(i.shape(0), i.shape(1))
{ {
for(unsigned int y=0; y<this->height(); ++y) copyImage(srcImageRange(i), destImage(image_));
for(unsigned int x=0; x<this->width(); ++x) // for(unsigned int y=0; y<this->height(); ++y)
image_(x,y) = detail::RequiresExplicitCast<VALUETYPE>::cast // for(unsigned int x=0; x<this->width(); ++x)
(i(x,y)); // image_(x,y) = detail::RequiresExplicitCast<VALUETYPE>::c
ast(i(x,y));
this->internalIndexer_ = InternalIndexer(typename InternalIndexer:: difference_type(this->width(), this->height()), this->internalIndexer_ = InternalIndexer(typename InternalIndexer:: difference_type(this->width(), this->height()),
image_.data()); image_.data());
} }
template <class SrcIterator, class SrcAccessor> template <class SrcIterator, class SrcAccessor>
SplineImageView1(SrcIterator is, SrcIterator iend, SrcAccessor sa) SplineImageView1(SrcIterator is, SrcIterator iend, SrcAccessor sa)
: Base(iend.x - is.x, iend.y - is.y), : Base(iend.x - is.x, iend.y - is.y),
image_(iend-is) image_(iend-is)
{ {
copyImage(srcIterRange(is, iend, sa), destImage(image_)); copyImage(srcIterRange(is, iend, sa), destImage(image_));
skipping to change at line 1850 skipping to change at line 1872
{ {
copyImage(srcIterRange(is, iend, sa), destImage(this->image_)); copyImage(srcIterRange(is, iend, sa), destImage(this->image_));
} }
template <class SrcIterator, class SrcAccessor> template <class SrcIterator, class SrcAccessor>
SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool / * unused */ = false) SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool / * unused */ = false)
: Base(s) : Base(s)
{ {
copyImage(s, destImage(this->image_)); copyImage(s, destImage(this->image_));
} }
template<class T, class SU>
SplineImageView(MultiArrayView<2, T, SU> const & i, bool /* unused */ =
false)
: Base(i)
{}
}; };
} // namespace vigra } // namespace vigra
#endif /* VIGRA_SPLINEIMAGEVIEW_HXX */ #endif /* VIGRA_SPLINEIMAGEVIEW_HXX */
 End of changes. 5 change blocks. 
7 lines changed or deleted 41 lines changed or added


 splines.hxx   splines.hxx 
skipping to change at line 48 skipping to change at line 48
#include <cmath> #include <cmath>
#include "config.hxx" #include "config.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "polynomial.hxx" #include "polynomial.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "fixedpoint.hxx" #include "fixedpoint.hxx"
namespace vigra { namespace vigra {
namespace autodiff {
template <class T, int N>
class DualVector;
} // namespace autodiff
/** \addtogroup MathFunctions Mathematical Functions /** \addtogroup MathFunctions Mathematical Functions
*/ */
//@{ //@{
/* B-Splines of arbitrary order and interpolating Catmull/Rom splines. /* B-Splines of arbitrary order and interpolating Catmull/Rom splines.
<b>\#include</b> \<vigra/splines.hxx\><br> <b>\#include</b> \<vigra/splines.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
skipping to change at line 159 skipping to change at line 166
/** Get the prefilter coefficients required for interpolation. /** Get the prefilter coefficients required for interpolation.
To interpolate with a B-spline, \ref resamplingConvolveImage() To interpolate with a B-spline, \ref resamplingConvolveImage()
can be used. However, the image to be interpolated must be can be used. However, the image to be interpolated must be
pre-filtered using \ref recursiveFilterX() and \ref recursiveFi lterY() pre-filtered using \ref recursiveFilterX() and \ref recursiveFi lterY()
with the filter coefficients given by this function. The length of the array with the filter coefficients given by this function. The length of the array
corresponds to how many times the above recursive filtering corresponds to how many times the above recursive filtering
has to be applied (zero length means no prefiltering necessary) . has to be applied (zero length means no prefiltering necessary) .
*/ */
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> const & b = calculatePrefilterCoefficien return prefilterCoefficients_;
ts();
return b;
} }
static ArrayVector<double> const & calculatePrefilterCoefficients(); typedef ArrayVector<ArrayVector<T> > WeightMatrix;
typedef T WeightMatrix[ORDER+1][ORDER+1];
/** Get the coefficients to transform spline coefficients into /** Get the coefficients to transform spline coefficients into
the coefficients of the corresponding polynomial. the coefficients of the corresponding polynomial.
Currently internally used in SplineImageView; needs more Currently internally used in SplineImageView; needs more
documentation ??? documentation ???
*/ */
static WeightMatrix & weights() static WeightMatrix const & weights()
{ {
static WeightMatrix & b = calculateWeightMatrix(); return weightMatrix_;
return b;
} }
static WeightMatrix & calculateWeightMatrix();
protected: protected:
result_type exec(first_argument_type x, second_argument_type derivative _order) const; result_type exec(first_argument_type x, second_argument_type derivative _order) const;
// factory function for the prefilter coefficients array
static ArrayVector<double> calculatePrefilterCoefficients();
// factory function for the weight matrix
static WeightMatrix calculateWeightMatrix();
BSplineBase<ORDER-1, T> s1_; BSplineBase<ORDER-1, T> s1_;
static ArrayVector<double> prefilterCoefficients_;
static WeightMatrix weightMatrix_;
}; };
template <int ORDER, class T> template <int ORDER, class T>
ArrayVector<double> BSplineBase<ORDER, T>::prefilterCoefficients_(BSplineBa
se<ORDER, T>::calculatePrefilterCoefficients());
template <int ORDER, class T>
typename BSplineBase<ORDER, T>::WeightMatrix BSplineBase<ORDER, T>::weightM
atrix_(calculateWeightMatrix());
template <int ORDER, class T>
typename BSplineBase<ORDER, T>::result_type typename BSplineBase<ORDER, T>::result_type
BSplineBase<ORDER, T>::exec(first_argument_type x, second_argument_type der ivative_order) const BSplineBase<ORDER, T>::exec(first_argument_type x, second_argument_type der ivative_order) const
{ {
if(derivative_order == 0) if(derivative_order == 0)
{ {
T n12 = (ORDER + 1.0) / 2.0; T n12 = (ORDER + 1.0) / 2.0;
return ((n12 + x) * s1_(x + 0.5) + (n12 - x) * s1_(x - 0.5)) / ORDE R; return ((n12 + x) * s1_(x + 0.5) + (n12 - x) * s1_(x - 0.5)) / ORDE R;
} }
else else
{ {
--derivative_order; --derivative_order;
return s1_(x + 0.5, derivative_order) - s1_(x - 0.5, derivative_ord er); return s1_(x + 0.5, derivative_order) - s1_(x - 0.5, derivative_ord er);
} }
} }
template <int ORDER, class T> template <int ORDER, class T>
ArrayVector<double> const & BSplineBase<ORDER, T>::calculatePrefilterCoeffi ArrayVector<double>
cients() BSplineBase<ORDER, T>::calculatePrefilterCoefficients()
{ {
static ArrayVector<double> b; ArrayVector<double> res;
if(ORDER > 1) if(ORDER > 1)
{ {
static const int r = ORDER / 2; const int r = ORDER / 2;
StaticPolynomial<2*r, double> p(2*r); StaticPolynomial<2*r, double> p(2*r);
BSplineBase spline; BSplineBase spline;
for(int i = 0; i <= 2*r; ++i) for(int i = 0; i <= 2*r; ++i)
p[i] = spline(T(i-r)); p[i] = spline(T(i-r));
ArrayVector<double> roots; ArrayVector<double> roots;
polynomialRealRoots(p, roots); polynomialRealRoots(p, roots);
for(unsigned int i = 0; i < roots.size(); ++i) for(unsigned int i = 0; i < roots.size(); ++i)
if(VIGRA_CSTD::fabs(roots[i]) < 1.0) if(VIGRA_CSTD::fabs(roots[i]) < 1.0)
b.push_back(roots[i]); res.push_back(roots[i]);
} }
return b; return res;
} }
template <int ORDER, class T> template <int ORDER, class T>
typename BSplineBase<ORDER, T>::WeightMatrix & typename BSplineBase<ORDER, T>::WeightMatrix
BSplineBase<ORDER, T>::calculateWeightMatrix() BSplineBase<ORDER, T>::calculateWeightMatrix()
{ {
static WeightMatrix b; WeightMatrix res(ORDER+1, ArrayVector<T>(ORDER+1));
double faculty = 1.0; double faculty = 1.0;
for(int d = 0; d <= ORDER; ++d) for(int d = 0; d <= ORDER; ++d)
{ {
if(d > 1) if(d > 1)
faculty *= d; faculty *= d;
double x = ORDER / 2; // (note: integer division) double x = ORDER / 2; // (note: integer division)
BSplineBase spline; BSplineBase spline;
for(int i = 0; i <= ORDER; ++i, --x) for(int i = 0; i <= ORDER; ++i, --x)
b[d][i] = spline(x, d) / faculty; res[d][i] = spline(x, d) / faculty;
} }
return b; return res;
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* BSpline<N, T> */ /* BSpline<N, T> */
/* */ /* */
/********************************************************/ /********************************************************/
/** Spline functors for arbitrary orders. /** Spline functors for arbitrary orders.
skipping to change at line 299 skipping to change at line 315
template <unsigned int IntBits, unsigned int FracBits> template <unsigned int IntBits, unsigned int FracBits>
FixedPoint<IntBits, FracBits> operator()(FixedPoint<IntBits, FracBits> x) const FixedPoint<IntBits, FracBits> operator()(FixedPoint<IntBits, FracBits> x) const
{ {
typedef FixedPoint<IntBits, FracBits> Value; typedef FixedPoint<IntBits, FracBits> Value;
return x.value < Value::ONE_HALF && -Value::ONE_HALF <= x.value return x.value < Value::ONE_HALF && -Value::ONE_HALF <= x.value
? Value(Value::ONE, FPNoShift) ? Value(Value::ONE, FPNoShift)
: Value(0, FPNoShift); : Value(0, FPNoShift);
} }
template <class U, int N>
autodiff::DualVector<U, N> operator()(autodiff::DualVector<U, N> const
& x) const
{
return x < 0.5 && -0.5 <= x
? autodiff::DualVector<U, N>(1.0)
: autodiff::DualVector<U, N>(0.0);
}
result_type operator()(first_argument_type x, second_argument_type deri vative_order) const result_type operator()(first_argument_type x, second_argument_type deri vative_order) const
{ {
return exec(x, derivativeOrder_ + derivative_order); return exec(x, derivativeOrder_ + derivative_order);
} }
value_type operator[](value_type x) const value_type operator[](value_type x) const
{ return operator()(x); } { return operator()(x); }
double radius() const double radius() const
{ return 0.5; } { return 0.5; }
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return derivativeOrder_; } { return derivativeOrder_; }
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> b; return prefilterCoefficients_;
return b;
} }
typedef T WeightMatrix[1][1]; typedef T WeightMatrix[1][1];
static WeightMatrix & weights()
static WeightMatrix const & weights()
{ {
static T b[1][1] = {{ 1.0}}; return weightMatrix_;
return b;
} }
protected: protected:
result_type exec(first_argument_type x, second_argument_type derivative _order) const result_type exec(first_argument_type x, second_argument_type derivative _order) const
{ {
if(derivative_order == 0) if(derivative_order == 0)
return x < 0.5 && -0.5 <= x ? return x < 0.5 && -0.5 <= x ?
1.0 1.0
: 0.0; : 0.0;
else else
return 0.0; return 0.0;
} }
unsigned int derivativeOrder_; unsigned int derivativeOrder_;
static ArrayVector<double> prefilterCoefficients_;
static WeightMatrix weightMatrix_;
}; };
template <class T>
ArrayVector<double> BSplineBase<0, T>::prefilterCoefficients_;
template <class T>
typename BSplineBase<0, T>::WeightMatrix BSplineBase<0, T>::weightMatrix_ =
{{ 1.0 }};
/********************************************************/ /********************************************************/
/* */ /* */
/* BSpline<1, T> */ /* BSpline<1, T> */
/* */ /* */
/********************************************************/ /********************************************************/
template <class T> template <class T>
class BSpline<1, T> class BSpline<1, T>
{ {
public: public:
skipping to change at line 377 skipping to change at line 408
template <unsigned int IntBits, unsigned int FracBits> template <unsigned int IntBits, unsigned int FracBits>
FixedPoint<IntBits, FracBits> operator()(FixedPoint<IntBits, FracBits> x) const FixedPoint<IntBits, FracBits> operator()(FixedPoint<IntBits, FracBits> x) const
{ {
typedef FixedPoint<IntBits, FracBits> Value; typedef FixedPoint<IntBits, FracBits> Value;
int v = abs(x.value); int v = abs(x.value);
return v < Value::ONE ? return v < Value::ONE ?
Value(Value::ONE - v, FPNoShift) Value(Value::ONE - v, FPNoShift)
: Value(0, FPNoShift); : Value(0, FPNoShift);
} }
template <class U, int N>
autodiff::DualVector<U, N> operator()(autodiff::DualVector<U, N> x) con
st
{
x = abs(x);
return x < 1.0
? 1.0 - x
: autodiff::DualVector<U, N>(0.0);
}
result_type operator()(first_argument_type x, second_argument_type deri vative_order) const result_type operator()(first_argument_type x, second_argument_type deri vative_order) const
{ {
return exec(x, derivativeOrder_ + derivative_order); return exec(x, derivativeOrder_ + derivative_order);
} }
value_type operator[](value_type x) const value_type operator[](value_type x) const
{ return operator()(x); } { return operator()(x); }
double radius() const double radius() const
{ return 1.0; } { return 1.0; }
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return derivativeOrder_; } { return derivativeOrder_; }
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> b; return prefilterCoefficients_;
return b;
} }
typedef T WeightMatrix[2][2]; typedef T WeightMatrix[2][2];
static WeightMatrix & weights()
static WeightMatrix const & weights()
{ {
static T b[2][2] = {{ 1.0, 0.0}, {-1.0, 1.0}}; return weightMatrix_;
return b;
} }
protected: protected:
T exec(T x, unsigned int derivative_order) const; T exec(T x, unsigned int derivative_order) const;
unsigned int derivativeOrder_; unsigned int derivativeOrder_;
static ArrayVector<double> prefilterCoefficients_;
static WeightMatrix weightMatrix_;
}; };
template <class T> template <class T>
ArrayVector<double> BSpline<1, T>::prefilterCoefficients_;
template <class T>
typename BSpline<1, T>::WeightMatrix BSpline<1, T>::weightMatrix_ = {{ 1.0,
0.0}, {-1.0, 1.0}};
template <class T>
T BSpline<1, T>::exec(T x, unsigned int derivative_order) const T BSpline<1, T>::exec(T x, unsigned int derivative_order) const
{ {
switch(derivative_order) switch(derivative_order)
{ {
case 0: case 0:
{ {
x = VIGRA_CSTD::fabs(x); x = VIGRA_CSTD::fabs(x);
return x < 1.0 ? return x < 1.0 ?
1.0 - x 1.0 - x
: 0.0; : 0.0;
skipping to change at line 484 skipping to change at line 531
return v == ONE_HALF return v == ONE_HALF
? Value(ONE_HALF, FPNoShift) ? Value(ONE_HALF, FPNoShift)
: v <= ONE_HALF : v <= ONE_HALF
? Value(THREE_QUARTERS - ? Value(THREE_QUARTERS -
(int)(sq((unsigned)v >> PREMULTIPLY_SHIFT2) >> POSTMULTIPLY_SHIFT2), FPNoShift) (int)(sq((unsigned)v >> PREMULTIPLY_SHIFT2) >> POSTMULTIPLY_SHIFT2), FPNoShift)
: v < THREE_HALVES : v < THREE_HALVES
? Value((int)(sq((unsigned)(THREE_HALVES-v) >> PREMULTIPLY_SHIFT1) >> (POSTMULTIPLY_SHIFT1 + 1)), FPNoShift) ? Value((int)(sq((unsigned)(THREE_HALVES-v) >> PREMULTIPLY_SHIFT1) >> (POSTMULTIPLY_SHIFT1 + 1)), FPNoShift)
: Value(0, FPNoShift); : Value(0, FPNoShift);
} }
template <class U, int N>
autodiff::DualVector<U, N> operator()(autodiff::DualVector<U, N> x) con
st
{
x = abs(x);
return x < 0.5
? 0.75 - x*x
: x < 1.5
? 0.5 * sq(1.5 - x)
: autodiff::DualVector<U, N>(0.0);
}
result_type operator()(first_argument_type x, second_argument_type deri vative_order) const result_type operator()(first_argument_type x, second_argument_type deri vative_order) const
{ {
return exec(x, derivativeOrder_ + derivative_order); return exec(x, derivativeOrder_ + derivative_order);
} }
result_type dx(argument_type x) const result_type dx(argument_type x) const
{ return operator()(x, 1); } { return operator()(x, 1); }
value_type operator[](value_type x) const value_type operator[](value_type x) const
{ return operator()(x); } { return operator()(x); }
double radius() const double radius() const
{ return 1.5; } { return 1.5; }
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return derivativeOrder_; } { return derivativeOrder_; }
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> b(1, 2.0*M_SQRT2 - 3.0); return prefilterCoefficients_;
return b;
} }
typedef T WeightMatrix[3][3]; typedef T WeightMatrix[3][3];
static WeightMatrix & weights()
static WeightMatrix const & weights()
{ {
static T b[3][3] = {{ 0.125, 0.75, 0.125}, return weightMatrix_;
{-0.5, 0.0, 0.5},
{ 0.5, -1.0, 0.5}};
return b;
} }
protected: protected:
result_type exec(first_argument_type x, second_argument_type derivative _order) const; result_type exec(first_argument_type x, second_argument_type derivative _order) const;
unsigned int derivativeOrder_; unsigned int derivativeOrder_;
static ArrayVector<double> prefilterCoefficients_;
static WeightMatrix weightMatrix_;
}; };
template <class T> template <class T>
ArrayVector<double> BSpline<2, T>::prefilterCoefficients_(1, 2.0*M_SQRT2 -
3.0);
template <class T>
typename BSpline<2, T>::WeightMatrix BSpline<2, T>::weightMatrix_ =
{{ 0.125, 0.75, 0.125},
{-0.5, 0.0, 0.5},
{ 0.5, -1.0, 0.5}};
template <class T>
typename BSpline<2, T>::result_type typename BSpline<2, T>::result_type
BSpline<2, T>::exec(first_argument_type x, second_argument_type derivative_ order) const BSpline<2, T>::exec(first_argument_type x, second_argument_type derivative_ order) const
{ {
switch(derivative_order) switch(derivative_order)
{ {
case 0: case 0:
{ {
x = VIGRA_CSTD::fabs(x); x = VIGRA_CSTD::fabs(x);
return x < 0.5 ? return x < 0.5 ?
0.75 - x*x 0.75 - x*x
skipping to change at line 613 skipping to change at line 679
: v < ONE : v < ONE
? Value(TWO_THIRDS + ? Value(TWO_THIRDS +
(((int)(sq((unsigned)v >> PREMULTIPLY_SHIFT) >> (POSTMULTIPLY_SHIFT + PREMULTIPLY_SHIFT)) (((int)(sq((unsigned)v >> PREMULTIPLY_SHIFT) >> (POSTMULTIPLY_SHIFT + PREMULTIPLY_SHIFT))
* (((v >> 1) - ONE) >> PREMULTIPLY_S HIFT)) >> POSTMULTIPLY_SHIFT), FPNoShift) * (((v >> 1) - ONE) >> PREMULTIPLY_S HIFT)) >> POSTMULTIPLY_SHIFT), FPNoShift)
: v < TWO : v < TWO
? Value((int)((sq((unsigned)(TWO-v) >> PREMULTI PLY_SHIFT) >> (POSTMULTIPLY_SHIFT + PREMULTIPLY_SHIFT)) ? Value((int)((sq((unsigned)(TWO-v) >> PREMULTI PLY_SHIFT) >> (POSTMULTIPLY_SHIFT + PREMULTIPLY_SHIFT))
* ((unsigned)(TWO-v) >> PREMULTIPLY_S HIFT) / 6) >> POSTMULTIPLY_SHIFT, FPNoShift) * ((unsigned)(TWO-v) >> PREMULTIPLY_S HIFT) / 6) >> POSTMULTIPLY_SHIFT, FPNoShift)
: Value(0, FPNoShift); : Value(0, FPNoShift);
} }
template <class U, int N>
autodiff::DualVector<U, N> operator()(autodiff::DualVector<U, N> x) con
st
{
x = abs(x);
if(x < 1.0)
{
return 2.0/3.0 + x*x*(-1.0 + 0.5*x);
}
else if(x < 2.0)
{
x = 2.0 - x;
return x*x*x/6.0;
}
else
return autodiff::DualVector<U, N>(0.0);
}
result_type operator()(first_argument_type x, second_argument_type deri vative_order) const result_type operator()(first_argument_type x, second_argument_type deri vative_order) const
{ {
return exec(x, derivativeOrder_ + derivative_order); return exec(x, derivativeOrder_ + derivative_order);
} }
result_type dx(argument_type x) const result_type dx(argument_type x) const
{ return operator()(x, 1); } { return operator()(x, 1); }
result_type dxx(argument_type x) const result_type dxx(argument_type x) const
{ return operator()(x, 2); } { return operator()(x, 2); }
skipping to change at line 635 skipping to change at line 718
{ return operator()(x); } { return operator()(x); }
double radius() const double radius() const
{ return 2.0; } { return 2.0; }
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return derivativeOrder_; } { return derivativeOrder_; }
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> b(1, VIGRA_CSTD::sqrt(3.0) - 2.0); return prefilterCoefficients_;
return b;
} }
typedef T WeightMatrix[4][4]; typedef T WeightMatrix[4][4];
static WeightMatrix & weights()
static WeightMatrix const & weights()
{ {
static T b[4][4] = {{ 1.0 / 6.0, 2.0 / 3.0, 1.0 / 6.0, 0.0}, return weightMatrix_;
{-0.5, 0.0, 0.5, 0.0},
{ 0.5, -1.0, 0.5, 0.0},
{-1.0 / 6.0, 0.5, -0.5, 1.0 / 6.0}};
return b;
} }
protected: protected:
result_type exec(first_argument_type x, second_argument_type derivative _order) const; result_type exec(first_argument_type x, second_argument_type derivative _order) const;
unsigned int derivativeOrder_; unsigned int derivativeOrder_;
static ArrayVector<double> prefilterCoefficients_;
static WeightMatrix weightMatrix_;
}; };
template <class T> template <class T>
ArrayVector<double> BSpline<3, T>::prefilterCoefficients_(1, VIGRA_CSTD::sq
rt(3.0) - 2.0);
template <class T>
typename BSpline<3, T>::WeightMatrix BSpline<3, T>::weightMatrix_ =
{{ 1.0 / 6.0, 2.0 / 3.0, 1.0 / 6.0, 0.0},
{-0.5, 0.0, 0.5, 0.0},
{ 0.5, -1.0, 0.5, 0.0},
{-1.0 / 6.0, 0.5, -0.5, 1.0 / 6.0}};
template <class T>
typename BSpline<3, T>::result_type typename BSpline<3, T>::result_type
BSpline<3, T>::exec(first_argument_type x, second_argument_type derivative_ order) const BSpline<3, T>::exec(first_argument_type x, second_argument_type derivative_ order) const
{ {
switch(derivative_order) switch(derivative_order)
{ {
case 0: case 0:
{ {
x = VIGRA_CSTD::fabs(x); x = VIGRA_CSTD::fabs(x);
if(x < 1.0) if(x < 1.0)
{ {
skipping to change at line 750 skipping to change at line 841
result_type operator()(argument_type x) const result_type operator()(argument_type x) const
{ {
return exec(x, derivativeOrder_); return exec(x, derivativeOrder_);
} }
result_type operator()(first_argument_type x, second_argument_type deri vative_order) const result_type operator()(first_argument_type x, second_argument_type deri vative_order) const
{ {
return exec(x, derivativeOrder_ + derivative_order); return exec(x, derivativeOrder_ + derivative_order);
} }
template <class U, int N>
autodiff::DualVector<U, N> operator()(autodiff::DualVector<U, N> x) con
st
{
x = abs(x);
if(x <= 0.5)
{
return 115.0/192.0 + x*x*(-0.625 + x*x*0.25);
}
else if(x < 1.5)
{
return (55.0/16.0 + x*(1.25 + x*(-7.5 + x*(5.0 - x)))) / 6.0;
}
else if(x < 2.5)
{
x = 2.5 - x;
return sq(x*x) / 24.0;
}
else
return autodiff::DualVector<U, N>(0.0);
}
result_type dx(argument_type x) const result_type dx(argument_type x) const
{ return operator()(x, 1); } { return operator()(x, 1); }
result_type dxx(argument_type x) const result_type dxx(argument_type x) const
{ return operator()(x, 2); } { return operator()(x, 2); }
result_type dx3(argument_type x) const result_type dx3(argument_type x) const
{ return operator()(x, 3); } { return operator()(x, 3); }
value_type operator[](value_type x) const value_type operator[](value_type x) const
{ return operator()(x); } { return operator()(x); }
double radius() const double radius() const
{ return 2.5; } { return 2.5; }
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return derivativeOrder_; } { return derivativeOrder_; }
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> const & b = initPrefilterCoefficients(); return prefilterCoefficients_;
return b; }
typedef T WeightMatrix[5][5];
static WeightMatrix const & weights()
{
return weightMatrix_;
} }
static ArrayVector<double> const & initPrefilterCoefficients() protected:
result_type exec(first_argument_type x, second_argument_type derivative
_order) const;
static ArrayVector<double> calculatePrefilterCoefficients()
{ {
static ArrayVector<double> b(2); ArrayVector<double> b(2);
// -19 + 4*sqrt(19) + 2*sqrt(2*(83 - 19*sqrt(19))) // -19 + 4*sqrt(19) + 2*sqrt(2*(83 - 19*sqrt(19)))
b[0] = -0.361341225900220177092212841325; b[0] = -0.361341225900220177092212841325;
// -19 - 4*sqrt(19) + 2*sqrt(2*(83 + 19*sqrt(19))) // -19 - 4*sqrt(19) + 2*sqrt(2*(83 + 19*sqrt(19)))
b[1] = -0.013725429297339121360331226939; b[1] = -0.013725429297339121360331226939;
return b; return b;
} }
typedef T WeightMatrix[5][5]; unsigned int derivativeOrder_;
static WeightMatrix & weights() static ArrayVector<double> prefilterCoefficients_;
{ static WeightMatrix weightMatrix_;
static T b[5][5] = {{ 1.0/384.0, 19.0/96.0, 115.0/192.0, 19.0/96.0, };
1.0/384.0},
template <class T>
ArrayVector<double> BSpline<4, T>::prefilterCoefficients_(calculatePrefilte
rCoefficients());
template <class T>
typename BSpline<4, T>::WeightMatrix BSpline<4, T>::weightMatrix_ =
{{ 1.0/384.0, 19.0/96.0, 115.0/192.0, 19.0/96.0,
1.0/384.0},
{-1.0/48.0, -11.0/24.0, 0.0, 11.0/24.0, 1.0/48. 0}, {-1.0/48.0, -11.0/24.0, 0.0, 11.0/24.0, 1.0/48. 0},
{ 1.0/16.0, 1.0/4.0, -5.0/8.0, 1.0/4.0, 1.0/16. 0}, { 1.0/16.0, 1.0/4.0, -5.0/8.0, 1.0/4.0, 1.0/16. 0},
{-1.0/12.0, 1.0/6.0, 0.0, -1.0/6.0, 1.0/12.0}, {-1.0/12.0, 1.0/6.0, 0.0, -1.0/6.0, 1.0/12.0},
{ 1.0/24.0, -1.0/6.0, 0.25, -1.0/6.0, 1.0/24.0} }; { 1.0/24.0, -1.0/6.0, 0.25, -1.0/6.0, 1.0/24.0} };
return b;
}
protected:
result_type exec(first_argument_type x, second_argument_type derivative
_order) const;
unsigned int derivativeOrder_;
};
template <class T> template <class T>
typename BSpline<4, T>::result_type typename BSpline<4, T>::result_type
BSpline<4, T>::exec(first_argument_type x, second_argument_type derivative_ order) const BSpline<4, T>::exec(first_argument_type x, second_argument_type derivative_ order) const
{ {
switch(derivative_order) switch(derivative_order)
{ {
case 0: case 0:
{ {
x = VIGRA_CSTD::fabs(x); x = VIGRA_CSTD::fabs(x);
skipping to change at line 945 skipping to change at line 1065
result_type operator()(argument_type x) const result_type operator()(argument_type x) const
{ {
return exec(x, derivativeOrder_); return exec(x, derivativeOrder_);
} }
result_type operator()(first_argument_type x, second_argument_type deri vative_order) const result_type operator()(first_argument_type x, second_argument_type deri vative_order) const
{ {
return exec(x, derivativeOrder_ + derivative_order); return exec(x, derivativeOrder_ + derivative_order);
} }
template <class U, int N>
autodiff::DualVector<U, N> operator()(autodiff::DualVector<U, N> x) con
st
{
x = abs(x);
if(x <= 1.0)
{
return 0.55 + x*x*(-0.5 + x*x*(0.25 - x/12.0));
}
else if(x < 2.0)
{
return 17.0/40.0 + x*(0.625 + x*(-1.75 + x*(1.25 + x*(-0.375 +
x/24.0))));
}
else if(x < 3.0)
{
x = 3.0 - x;
return x*sq(x*x) / 120.0;
}
else
return autodiff::DualVector<U, N>(0.0);
}
result_type dx(argument_type x) const result_type dx(argument_type x) const
{ return operator()(x, 1); } { return operator()(x, 1); }
result_type dxx(argument_type x) const result_type dxx(argument_type x) const
{ return operator()(x, 2); } { return operator()(x, 2); }
result_type dx3(argument_type x) const result_type dx3(argument_type x) const
{ return operator()(x, 3); } { return operator()(x, 3); }
result_type dx4(argument_type x) const result_type dx4(argument_type x) const
skipping to change at line 968 skipping to change at line 1109
{ return operator()(x); } { return operator()(x); }
double radius() const double radius() const
{ return 3.0; } { return 3.0; }
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return derivativeOrder_; } { return derivativeOrder_; }
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> const & b = initPrefilterCoefficients(); return prefilterCoefficients_;
return b; }
typedef T WeightMatrix[6][6];
static WeightMatrix const & weights()
{
return weightMatrix_;
} }
static ArrayVector<double> const & initPrefilterCoefficients() protected:
result_type exec(first_argument_type x, second_argument_type derivative
_order) const;
static ArrayVector<double> calculatePrefilterCoefficients()
{ {
static ArrayVector<double> b(2); ArrayVector<double> b(2);
// -(13/2) + sqrt(105)/2 + sqrt(1/2*((135 - 13*sqrt(105)))) // -(13/2) + sqrt(105)/2 + sqrt(1/2*((135 - 13*sqrt(105))))
b[0] = -0.430575347099973791851434783493; b[0] = -0.430575347099973791851434783493;
// (1/2)*((-13) - sqrt(105) + sqrt(2*((135 + 13*sqrt(105))))) // (1/2)*((-13) - sqrt(105) + sqrt(2*((135 + 13*sqrt(105)))))
b[1] = -0.043096288203264653822712376822; b[1] = -0.043096288203264653822712376822;
return b; return b;
} }
typedef T WeightMatrix[6][6]; unsigned int derivativeOrder_;
static WeightMatrix & weights() static ArrayVector<double> prefilterCoefficients_;
{ static WeightMatrix weightMatrix_;
static T b[6][6] = {{ 1.0/120.0, 13.0/60.0, 11.0/20.0, 13.0/60.0, 1 };
.0/120.0, 0.0},
template <class T>
ArrayVector<double> BSpline<5, T>::prefilterCoefficients_(calculatePrefilte
rCoefficients());
template <class T>
typename BSpline<5, T>::WeightMatrix BSpline<5, T>::weightMatrix_ =
{{ 1.0/120.0, 13.0/60.0, 11.0/20.0, 13.0/60.0, 1
.0/120.0, 0.0},
{-1.0/24.0, -5.0/12.0, 0.0, 5.0/12.0, 1.0/24.0, 0.0}, {-1.0/24.0, -5.0/12.0, 0.0, 5.0/12.0, 1.0/24.0, 0.0},
{ 1.0/12.0, 1.0/6.0, -0.5, 1.0/6.0, 1.0/12.0, 0 .0}, { 1.0/12.0, 1.0/6.0, -0.5, 1.0/6.0, 1.0/12.0, 0 .0},
{-1.0/12.0, 1.0/6.0, 0.0, -1.0/6.0, 1.0/12.0, 0 .0}, {-1.0/12.0, 1.0/6.0, 0.0, -1.0/6.0, 1.0/12.0, 0 .0},
{ 1.0/24.0, -1.0/6.0, 0.25, -1.0/6.0, 1.0/24.0, 0.0}, { 1.0/24.0, -1.0/6.0, 0.25, -1.0/6.0, 1.0/24.0, 0.0},
{-1.0/120.0, 1.0/24.0, -1.0/12.0, 1.0/12.0, -1. 0/24.0, 1.0/120.0}}; {-1.0/120.0, 1.0/24.0, -1.0/12.0, 1.0/12.0, -1. 0/24.0, 1.0/120.0}};
return b;
}
protected:
result_type exec(first_argument_type x, second_argument_type derivative
_order) const;
unsigned int derivativeOrder_;
};
template <class T> template <class T>
typename BSpline<5, T>::result_type typename BSpline<5, T>::result_type
BSpline<5, T>::exec(first_argument_type x, second_argument_type derivative_ order) const BSpline<5, T>::exec(first_argument_type x, second_argument_type derivative_ order) const
{ {
switch(derivative_order) switch(derivative_order)
{ {
case 0: case 0:
{ {
x = VIGRA_CSTD::fabs(x); x = VIGRA_CSTD::fabs(x);
skipping to change at line 1201 skipping to change at line 1350
/** Derivative order of the function: always 0. /** Derivative order of the function: always 0.
*/ */
unsigned int derivativeOrder() const unsigned int derivativeOrder() const
{ return 0; } { return 0; }
/** Prefilter coefficients for compatibility with \ref vigra::BSpli ne. /** Prefilter coefficients for compatibility with \ref vigra::BSpli ne.
(array has zero length, since prefiltering is not necessary). (array has zero length, since prefiltering is not necessary).
*/ */
ArrayVector<double> const & prefilterCoefficients() const ArrayVector<double> const & prefilterCoefficients() const
{ {
static ArrayVector<double> b; return prefilterCoefficients_;
return b;
} }
protected:
static ArrayVector<double> prefilterCoefficients_;
}; };
template <class T> template <class T>
ArrayVector<double> CatmullRomSpline<T>::prefilterCoefficients_;
template <class T>
typename CatmullRomSpline<T>::result_type typename CatmullRomSpline<T>::result_type
CatmullRomSpline<T>::operator()(argument_type x) const CatmullRomSpline<T>::operator()(argument_type x) const
{ {
x = VIGRA_CSTD::fabs(x); x = VIGRA_CSTD::fabs(x);
if (x <= 1.0) if (x <= 1.0)
{ {
return 1.0 + x * x * (-2.5 + 1.5 * x); return 1.0 + x * x * (-2.5 + 1.5 * x);
} }
else if (x >= 2.0) else if (x >= 2.0)
{ {
 End of changes. 57 change blocks. 
84 lines changed or deleted 251 lines changed or added


 stdconvolution.hxx   stdconvolution.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_STDCONVOLUTION_HXX #ifndef VIGRA_STDCONVOLUTION_HXX
#define VIGRA_STDCONVOLUTION_HXX #define VIGRA_STDCONVOLUTION_HXX
#include <cmath> #include <cmath>
#include "stdimage.hxx" #include "stdimage.hxx"
#include "bordertreatment.hxx" #include "bordertreatment.hxx"
#include "separableconvolution.hxx" #include "separableconvolution.hxx"
#include "utilities.hxx" #include "utilities.hxx"
#include "sized_int.hxx" #include "sized_int.hxx"
#include "multi_iterator.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup StandardConvolution Two-dimensional convolution functions template <class ARITHTYPE>
class Kernel2D;
Perform 2D non-separable convolution, with and without ROI mask.
These generic convolution functions implement /** \addtogroup CommonConvolutionFilters
the standard 2D convolution operation for images that fit
into the required interface. Arbitrary ROI's are supported
by the mask version of the algorithm.
The functions need a suitable 2D kernel to operate.
*/ */
//@{ //@{
/** \brief Performs a 2 dimensional convolution of the source image using t // documentation is in convolution.hxx
he given
kernel.
The KernelIterator must point to the center of the kernel, and
the kernel's size is given by its upper left (x and y of distance <= 0)
and
lower right (distance >= 0) corners. The image must always be larger th
an the
kernel. At those positions where the kernel does not completely fit
into the image, the specified \ref BorderTreatmentMode is
applied. You can choice between following BorderTreatmentModes:
<ul>
<li>BORDER_TREATMENT_CLIP</li>
<li>BORDER_TREATMENT_AVOID</li>
<li>BORDER_TREATMENT_WRAP</li>
<li>BORDER_TREATMENT_REFLECT</li>
<li>BORDER_TREATMENT_REPEAT</li>
</ul><br>
The images's pixel type (SrcAccessor::value_type) must be a
linear space over the kernel's value_type (KernelAccessor::value_type),
i.e. addition of source values, multiplication with kernel values,
and NumericTraits must be defined.
The kernel's value_type must be an algebraic field,
i.e. the arithmetic operations (+, -, *, /) and NumericTraits must
be defined.
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor>
void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAcces
sor src_acc,
DestIterator dest_ul, DestAccessor dest_acc,
KernelIterator ki, KernelAccessor ak,
Diff2D kul, Diff2D klr, BorderTreatmentMode bord
er);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor>
void convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> sr
c,
pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, Diff2D, D
iff2D,
BorderTreatmentMode> kernel);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/stdconvolution.hxx\><br>
Namespace: vigra
\code
vigra::FImage src(w,h), dest(w,h);
...
// define horizontal Sobel filter
vigra::Kernel2D<float> sobel;
sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and l
ower right
0.125, 0.0, -0.125,
0.25, 0.0, -0.25,
0.125, 0.0, -0.125;
sobel.setBorderTreatment(vigra::BORDER_TREATMENT_REFLECT);
vigra::convolveImage(srcImageRange(src), destImage(dest), kernel2d(sobe
l));
\endcode
<b> Required Interface:</b>
\code
ImageIterator src_ul, src_lr;
ImageIterator dest_ul;
ImageIterator ik;
SrcAccessor src_accessor;
DestAccessor dest_accessor;
KernelAccessor kernel_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(sr
c_ul);
s = s + s;
s = kernel_accessor(ik) * s;
s -= s;
dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), dest_ul);
NumericTraits<KernelAccessor::value_type>::RealPromote k = kernel_acces
sor(ik);
k += k;
k -= k;
k = k / k;
\endcode
<b> Preconditions:</b>
\code
kul.x <= 0
kul.y <= 0
klr.x >= 0
klr.y >= 0
src_lr.x - src_ul.x >= klr.x + kul.x + 1
src_lr.y - src_ul.y >= klr.y + kul.y + 1
\endcode
If border == BORDER_TREATMENT_CLIP: Sum of kernel elements must be
!= 0.
*/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_ acc, void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_ acc,
DestIterator dest_ul, DestAccessor dest_acc, DestIterator dest_ul, DestAccessor dest_acc,
KernelIterator ki, KernelAccessor ak, KernelIterator ki, KernelAccessor ak,
Diff2D kul, Diff2D klr, BorderTreatmentMode border) Diff2D kul, Diff2D klr, BorderTreatmentMode border)
{ {
vigra_precondition((border == BORDER_TREATMENT_CLIP || vigra_precondition((border == BORDER_TREATMENT_CLIP ||
border == BORDER_TREATMENT_AVOID || border == BORDER_TREATMENT_AVOID ||
skipping to change at line 383 skipping to change at line 265
// store convolution result in destination pixel // store convolution result in destination pixel
dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(sum), xd); dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(sum), xd);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
inline inline void
void convolveImage( convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D, BorderTreatmentMode> kernel)
BorderTreatmentMode> kernel)
{ {
convolveImage(src.first, src.second, src.third, convolveImage(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
kernel.first, kernel.second, kernel.third, kernel.first, kernel.second, kernel.third,
kernel.fourth, kernel.fifth); kernel.fourth, kernel.fifth);
} }
template <class T1, class S1,
class T2, class S2,
class T3>
inline void
convolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Kernel2D<T3> const & kernel)
{
vigra_precondition(src.shape() == dest.shape(),
"convolveImage(): shape mismatch between input and output.");
convolveImage(srcImageRange(src),
destImage(dest),
kernel2d(kernel));
}
/** \brief Performs a 2-dimensional normalized convolution, i.e. convolutio n with a mask image. /** \brief Performs a 2-dimensional normalized convolution, i.e. convolutio n with a mask image.
This functions computes This functions computes
<a href ="http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/PIROD DI1/NormConv/NormConv.html">normalized <a href ="http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/PIROD DI1/NormConv/NormConv.html">normalized
convolution</a> as defined in convolution</a> as defined in
Knutsson, H. and Westin, C-F.: <i>Normalized and differential convoluti on: Knutsson, H. and Westin, C-F.: <i>Normalized and differential convoluti on:
Methods for Interpolation and Filtering of incomplete and uncertain dat a</i>. Methods for Interpolation and Filtering of incomplete and uncertain dat a</i>.
Proc. of the IEEE Conf. on Computer Vision and Pattern Recognition, 199 3, 515-523. Proc. of the IEEE Conf. on Computer Vision and Pattern Recognition, 199 3, 515-523.
The mask image must be binary and encodes which pixels of the original image The mask image must be binary and encodes which pixels of the original image
skipping to change at line 434 skipping to change at line 330
The images's pixel type (SrcAccessor::value_type) must be a The images's pixel type (SrcAccessor::value_type) must be a
linear space over the kernel's value_type (KernelAccessor::value_type), linear space over the kernel's value_type (KernelAccessor::value_type),
i.e. addition of source values, multiplication with kernel values, i.e. addition of source values, multiplication with kernel values,
and NumericTraits must be defined. and NumericTraits must be defined.
The kernel's value_type must be an algebraic field, The kernel's value_type must be an algebraic field,
i.e. the arithmetic operations (+, -, *, /) and NumericTraits must i.e. the arithmetic operations (+, -, *, /) and NumericTraits must
be defined. be defined.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class TM, class SM,
class T3>
void
normalizedConvolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
Kernel2D<T3> const & kernel);
}
\endcode
\deprecatedAPI{normalizedConvolveImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void void
normalizedConvolveImage(SrcIterator src_ul, SrcIterator src_lr, Src Accessor src_acc, normalizedConvolveImage(SrcIterator src_ul, SrcIterator src_lr, Src Accessor src_acc,
MaskIterator mul, MaskAccessor am, MaskIterator mul, MaskAccessor am,
DestIterator dest_ul, DestAccessor dest_acc , DestIterator dest_ul, DestAccessor dest_acc ,
KernelIterator ki, KernelAccessor ak, KernelIterator ki, KernelAccessor ak,
Diff2D kul, Diff2D klr, BorderTreatmentMode border); Diff2D kul, Diff2D klr, BorderTreatmentMode border);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void normalizedConvolveImage(triple<SrcIterator, SrcIterator, SrcAc cessor> src, void normalizedConvolveImage(triple<SrcIterator, SrcIterator, SrcAc cessor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D, tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
BorderTreatmentMode> kernel); BorderTreatmentMode> kernel);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/stdconvolution.hxx\><br> <b>\#include</b> \<vigra/stdconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, float> src(w,h), dest(w,h);
MultiArray<2, unsigned char> mask(w,h);
...
// define 3x3 binomial filter
vigra::Kernel2D<float> binom;
binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and
lower right
0.0625, 0.125, 0.0625,
0.125, 0.25, 0.125,
0.0625, 0.125, 0.0625;
normalizedConvolveImage(src, mask, dest, binom);
\endcode
\deprecatedUsage{normalizedConvolveImage}
\code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
vigra::CImage mask(w,h); vigra::CImage mask(w,h);
... ...
// define 3x3 binomial filter // define 3x3 binomial filter
vigra::Kernel2D<float> binom; vigra::Kernel2D<float> binom;
binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and lower right binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and lower right
0.0625, 0.125, 0.0625, 0.0625, 0.125, 0.0625,
0.125, 0.25, 0.125, 0.125, 0.25, 0.125,
0.0625, 0.125, 0.0625; 0.0625, 0.125, 0.0625;
vigra::normalizedConvolveImage(srcImageRange(src), maskImage(mask), des tImage(dest), kernel2d(binom)); vigra::normalizedConvolveImage(srcImageRange(src), maskImage(mask), des tImage(dest), kernel2d(binom));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator src_ul, src_lr; ImageIterator src_ul, src_lr;
ImageIterator mul; ImageIterator mul;
ImageIterator dest_ul; ImageIterator dest_ul;
ImageIterator ik; ImageIterator ik;
SrcAccessor src_accessor; SrcAccessor src_accessor;
MaskAccessor mask_accessor; MaskAccessor mask_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
KernelAccessor kernel_accessor; KernelAccessor kernel_accessor;
skipping to change at line 517 skipping to change at line 442
dest_accessor.set( dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), dest_ul); NumericTraits<DestAccessor::value_type>::fromRealPromote(s), dest_ul);
NumericTraits<KernelAccessor::value_type>::RealPromote k = kernel_acces sor(ik); NumericTraits<KernelAccessor::value_type>::RealPromote k = kernel_acces sor(ik);
k += k; k += k;
k -= k; k -= k;
k = k / k; k = k / k;
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
\code <ul>
kul.x <= 0 <li> The image must be longer than the kernel radius: <tt>w > std::max(
kul.y <= 0 kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and
klr.x >= 0 <tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt
klr.y >= 0 >.
src_lr.x - src_ul.x >= klr.x + kul.x + 1 <li> The sum of kernel elements must be != 0.
src_lr.y - src_ul.y >= klr.y + kul.y + 1 <li> <tt>border == BORDER_TREATMENT_CLIP || border == BORDER_TREATMENT_
border == BORDER_TREATMENT_CLIP || border == BORDER_TREATMENT_AVOID AVOID</tt>
\endcode </ul>
Sum of kernel elements must be != 0.
*/ */
doxygen_overloaded_function(template <...> void normalizedConvolveImage) doxygen_overloaded_function(template <...> void normalizedConvolveImage)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void void
normalizedConvolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc, normalizedConvolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
MaskIterator mul, MaskAccessor am, MaskIterator mul, MaskAccessor am,
skipping to change at line 662 skipping to change at line 582
detail::RequiresExplicitCast<SumType>::cast((n orm / ksum) * sum)), xd); detail::RequiresExplicitCast<SumType>::cast((n orm / ksum) * sum)), xd);
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
inline inline void
void normalizedConvolveImage( normalizedConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> sr pair<MaskIterator, MaskAccessor> mask,
c, pair<DestIterator, DestAccessor> dest,
pair<MaskIterator, MaskAccessor> mask, tuple5<KernelIterator, KernelAccessor, Diff2D, Diff
pair<DestIterator, DestAccessor> dest, 2D,
tuple5<KernelIterator, KernelAccessor, Diff2D, D BorderTreatmentMode> kernel)
iff2D,
BorderTreatmentMode> kernel)
{ {
normalizedConvolveImage(src.first, src.second, src.third, normalizedConvolveImage(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, dest.first, dest.second,
kernel.first, kernel.second, kernel.third, kernel.first, kernel.second, kernel.third,
kernel.fourth, kernel.fifth); kernel.fourth, kernel.fifth);
} }
template <class T1, class S1,
class T2, class S2,
class TM, class SM,
class T3>
inline void
normalizedConvolveImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
Kernel2D<T3> const & kernel)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"normalizedConvolveImage(): shape mismatch between input and output
.");
normalizedConvolveImage(srcImageRange(src),
maskImage(mask),
destImage(dest),
kernel2d(kernel));
}
/** \brief Deprecated name of 2-dimensional normalized convolution, i.e. co nvolution with a mask image. /** \brief Deprecated name of 2-dimensional normalized convolution, i.e. co nvolution with a mask image.
See \ref normalizedConvolveImage() for documentation. See \ref normalizedConvolveImage() for documentation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void void
convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAc cessor src_acc, convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAc cessor src_acc,
MaskIterator mul, MaskAccessor am, MaskIterator mul, MaskAccessor am,
DestIterator dest_ul, DestAccessor dest_acc, DestIterator dest_ul, DestAccessor dest_acc,
KernelIterator ki, KernelAccessor ak, KernelIterator ki, KernelAccessor ak,
Diff2D kul, Diff2D klr, BorderTreatmentMode b order); Diff2D kul, Diff2D klr, BorderTreatmentMode b order);
} }
\endcode \endcode
\deprecatedAPI{convolveImageWithMask}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor>
void
convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAc
cessor src_acc,
MaskIterator mul, MaskAccessor am,
DestIterator dest_ul, DestAccessor dest_acc,
KernelIterator ki, KernelAccessor ak,
Diff2D kul, Diff2D klr, BorderTreatmentMode b
order);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void convolveImageWithMask(triple<SrcIterator, SrcIterator, SrcAcce ssor> src, void convolveImageWithMask(triple<SrcIterator, SrcIterator, SrcAcce ssor> src,
pair<MaskIterator, MaskAccessor> mask, pair<MaskIterator, MaskAccessor> mask,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, D iff2D, Diff2D, tuple5<KernelIterator, KernelAccessor, D iff2D, Diff2D,
BorderTreatmentMode> kernel); BorderTreatmentMode> kernel);
} }
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void convolveImageWithMask) doxygen_overloaded_function(template <...> void convolveImageWithMask)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class MaskIterator, class MaskAccessor, class MaskIterator, class MaskAccessor,
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
inline void inline void
convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor s rc_acc, convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor s rc_acc,
MaskIterator mul, MaskAccessor am, MaskIterator mul, MaskAccessor am,
skipping to change at line 770 skipping to change at line 724
/** \brief Generic 2 dimensional convolution kernel. /** \brief Generic 2 dimensional convolution kernel.
This kernel may be used for convolution of 2 dimensional signals. This kernel may be used for convolution of 2 dimensional signals.
Convolution functions access the kernel via an ImageIterator Convolution functions access the kernel via an ImageIterator
which they get by calling \ref center(). This iterator which they get by calling \ref center(). This iterator
points to the center of the kernel. The kernel's size is given by its u pperLeft() points to the center of the kernel. The kernel's size is given by its u pperLeft()
(upperLeft().x <= 0, upperLeft().y <= 0) (upperLeft().x <= 0, upperLeft().y <= 0)
and lowerRight() (lowerRight().x >= 0, lowerRight().y >= 0) methods. and lowerRight() (lowerRight().x >= 0, lowerRight().y >= 0) methods.
The desired border treatment mode is returned by borderTreatment(). The desired border treatment mode is returned by borderTreatment().
(Note that the \ref StandardConvolution "2D convolution functions" don'
t currently
support all modes.)
The different init functions create a kernel with the specified The different init functions create a kernel with the specified
properties. The requirements for the kernel's value_type depend properties. The requirements for the kernel's value_type depend
on the init function used. At least NumericTraits must be defined. on the init function used. At least NumericTraits must be defined.
The kernel defines a factory function kernel2d() to create an argument
object
(see \ref KernelArgumentObjectFactories).
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/stdconvolution.hxx\><br> <b>\#include</b> \<vigra/stdconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::FImage src(w,h), dest(w,h); MultiArray<2, float> src(w,h), dest(w,h);
... ...
// define horizontal Sobel filter // define horizontal Sobel filter
vigra::Kernel2D<float> sobel; vigra::Kernel2D<float> sobel;
sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and l ower right sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and l ower right
0.125, 0.0, -0.125, 0.125, 0.0, -0.125,
0.25, 0.0, -0.25, 0.25, 0.0, -0.25,
0.125, 0.0, -0.125; 0.125, 0.0, -0.125;
vigra::convolveImage(srcImageRange(src), destImage(dest), kernel2d(sobe l)); convolveImage(src, dest, sobel);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
value_type v = NumericTraits<value_type>::one(); value_type v = NumericTraits<value_type>::one();
\endcode \endcode
See also the init functions. See also the init functions.
*/ */
template <class ARITHTYPE> template <class ARITHTYPE = double>
class Kernel2D class Kernel2D
{ {
public: public:
/** the kernel's value type /** the kernel's value type
*/ */
typedef ARITHTYPE value_type; typedef ARITHTYPE value_type;
/** 2D random access iterator over the kernel's values /** 2D random access iterator over the kernel's values
*/ */
typedef typename BasicImage<value_type>::traverser Iterator; typedef typename BasicImage<value_type>::traverser Iterator;
skipping to change at line 959 skipping to change at line 907
<b> Required Interface:</b> <b> Required Interface:</b>
The kernel's value_type must be a linear algebra. The kernel's value_type must be a linear algebra.
\code \code
vigra::Kernel2D<...>::value_type v; vigra::Kernel2D<...>::value_type v;
v = v * v; v = v * v;
\endcode \endcode
*/ */
void initSeparable(Kernel1D<value_type> const & kx, void initSeparable(Kernel1D<value_type> const & kx,
Kernel1D<value_type> const & ky) Kernel1D<value_type> const & ky)
{ {
left_ = Diff2D(kx.left(), ky.left()); left_ = Diff2D(kx.left(), ky.left());
right_ = Diff2D(kx.right(), ky.right()); right_ = Diff2D(kx.right(), ky.right());
int w = right_.x - left_.x + 1; int w = right_.x - left_.x + 1;
int h = right_.y - left_.y + 1; int h = right_.y - left_.y + 1;
kernel_.resize(w, h); kernel_.resize(w, h);
norm_ = kx.norm() * ky.norm(); norm_ = kx.norm() * ky.norm();
typedef typename Kernel1D<value_type>::const_iterator KIter; typedef typename Kernel1D<value_type>::const_iterator KIter;
skipping to change at line 1011 skipping to change at line 959
\code \code
xleft <= 0; xleft <= 0;
xright >= 0; xright >= 0;
yleft <= 0; yleft <= 0;
yright >= 0; yright >= 0;
\endcode \endcode
*/ */
template <class KernelIterator> template <class KernelIterator>
void initSeparable(KernelIterator kxcenter, int xleft, int xright, void initSeparable(KernelIterator kxcenter, int xleft, int xright,
KernelIterator kycenter, int yleft, int yright) KernelIterator kycenter, int yleft, int yright )
{ {
vigra_precondition(xleft <= 0 && yleft <= 0, vigra_precondition(xleft <= 0 && yleft <= 0,
"Kernel2D::initSeparable(): left borders must be <= 0."); "Kernel2D::initSeparable(): left borders must be <= 0.");
vigra_precondition(xright >= 0 && yright >= 0, vigra_precondition(xright >= 0 && yright >= 0,
"Kernel2D::initSeparable(): right borders must b e >= 0."); "Kernel2D::initSeparable(): right borders must b e >= 0.");
left_ = Point2D(xleft, yleft); left_ = Point2D(xleft, yleft);
right_ = Point2D(xright, yright); right_ = Point2D(xright, yright);
int w = right_.x - left_.x + 1; int w = right_.x - left_.x + 1;
skipping to change at line 1049 skipping to change at line 997
typename BasicImage<value_type>::iterator iend = kernel_.end(); typename BasicImage<value_type>::iterator iend = kernel_.end();
norm_ = *i; norm_ = *i;
++i; ++i;
for(; i!= iend; ++i) for(; i!= iend; ++i)
{ {
norm_ += *i; norm_ += *i;
} }
} }
/** Init as a 2D Gaussian function with given standard deviation an /** \brief Init as a 2D box filter with given radius.
d norm.
The function returns a reference to the kernel.
*/
void initAveraging(int radius)
{
Kernel1D<value_type> avg;
avg.initAveraging(radius);
return initSeparable(avg, avg);
}
/** \brief Init as a 2D Gaussian function with given standard devia
tion and norm.
The function returns a reference to the kernel.
*/ */
void initGaussian(double std_dev, value_type norm) void initGaussian(double std_dev, value_type norm)
{ {
Kernel1D<value_type> gauss; Kernel1D<value_type> gauss;
gauss.initGaussian(std_dev, norm); gauss.initGaussian(std_dev, norm);
initSeparable(gauss, gauss); return initSeparable(gauss, gauss);
} }
/** Init as a 2D Gaussian function with given standard deviation an /** \brief Init as a 2D Gaussian function with given standard devia
d unit norm. tion and unit norm.
The function returns a reference to the kernel.
*/ */
void initGaussian(double std_dev) void initGaussian(double std_dev)
{ {
initGaussian(std_dev, NumericTraits<value_type>::one()); return initGaussian(std_dev, NumericTraits<value_type>::one());
} }
/** Init the 2D kernel as a circular averaging filter. The norm wil l be /** Init the 2D kernel as a circular averaging filter. The norm wil l be
calculated as calculated as
<TT>NumericTraits<value_type>::one() / (number of non-zero kern el values)</TT>. <TT>NumericTraits<value_type>::one() / (number of non-zero kern el values)</TT>.
The kernel's value_type must be a linear space. The kernel's value_type must be a linear space.
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
skipping to change at line 1128 skipping to change at line 1091
for(int y=-radius; y<=radius; ++y) for(int y=-radius; y<=radius; ++y)
{ {
for(int x=-radius; x<=radius; ++x) for(int x=-radius; x<=radius; ++x)
{ {
k(x,y) = count * k(x,y); k(x,y) = count * k(x,y);
} }
} }
} }
/** Init the kernel by an explicit initializer list. /** Init the kernel by an explicit initializer list.
The upper left and lower right corners of the kernel must be pa The upper left and lower right corners (inclusive) of the kerne
ssed. l must be passed
A comma-separated initializer list is given after the assignmen either as <tt>Shape2</tt> or <tt>Diff2D</tt> objects. A comma-s
t operator. eparated initializer
This function is used like this: list for the kernel's weights is given after the assignment ope
rator like this:
\code \code
// define horizontal Sobel filter // define horizontal Sobel filter
vigra::Kernel2D<float> sobel; vigra::Kernel2D<float> sobel;
sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
0.125, 0.0, -0.125, 0.125, 0.0, -0.125,
0.25, 0.0, -0.25, 0.25, 0.0, -0.25,
0.125, 0.0, -0.125; 0.125, 0.0, -0.125;
\endcode \endcode
The norm is set to the sum of the initializer values. If the wr ong number of The norm is set to the sum of the initializer values. If the wr ong number of
values is given, a run-time error results. It is, however, poss ible to give values is given, a run-time error results. It is, however, poss ible to give
just one initializer. This creates an averaging filter with the given constant: just one initializer. This creates an averaging filter with the given constant:
\code \code
vigra::Kernel2D<float> average3x3; vigra::Kernel2D<float> average3x3;
average3x3.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = 1.0/9.0 ; average3x3.initExplicitly(Shape2(-1,-1), Shape2(1,1)) = 1.0/9.0 ;
\endcode \endcode
Here, the norm is set to value*width()*height(). Here, the norm is set to value*width()*height().
<b> Preconditions:</b> <b> Preconditions:</b>
\code \code
1. upperleft.x <= 0; 1. upperleft.x <= 0;
2. upperleft.y <= 0; 2. upperleft.y <= 0;
3. lowerright.x >= 0; 3. lowerright.x >= 0;
4. lowerright.y >= 0; 4. lowerright.y >= 0;
5. the number of values in the initializer list 5. the number of values in the initializer list
is 1 or equals the size of the kernel. is 1 or equals the size of the kernel.
\endcode \endcode
*/ */
Kernel2D & initExplicitly(Diff2D upperleft, Diff2D lowerright) Kernel2D & initExplicitly(Shape2 const & upperleft, Shape2 const & lowe rright)
{ {
vigra_precondition(upperleft.x <= 0 && upperleft.y <= 0, vigra_precondition(upperleft[0] <= 0 && upperleft[1] <= 0,
"Kernel2D::initExplicitly(): left borders must b e <= 0."); "Kernel2D::initExplicitly(): left borders must b e <= 0.");
vigra_precondition(lowerright.x >= 0 && lowerright.y >= 0, vigra_precondition(lowerright[0] >= 0 && lowerright[1] >= 0,
"Kernel2D::initExplicitly(): right borders must be >= 0."); "Kernel2D::initExplicitly(): right borders must be >= 0.");
left_ = Point2D(upperleft); left_ = Point2D(upperleft[0], upperleft[1]);
right_ = Point2D(lowerright); right_ = Point2D(lowerright[0], lowerright[1]);
int w = right_.x - left_.x + 1; int w = right_.x - left_.x + 1;
int h = right_.y - left_.y + 1; int h = right_.y - left_.y + 1;
kernel_.resize(w, h); kernel_.resize(w, h);
return *this; return *this;
} }
Kernel2D & initExplicitly(Diff2D const & upperleft, Diff2D const & lowe
rright)
{
return initExplicitly(Shape2(upperleft), Shape2(lowerright));
}
/** Coordinates of the upper left corner of the kernel. /** Coordinates of the upper left corner of the kernel.
*/ */
Point2D upperLeft() const { return left_; } Point2D upperLeft() const { return left_; }
/** Coordinates of the lower right corner of the kernel. /** Coordinates of the lower right corner of the kernel.
*/ */
Point2D lowerRight() const { return right_; } Point2D lowerRight() const { return right_; }
/** Width of the kernel. /** Width of the kernel.
*/ */
 End of changes. 38 change blocks. 
197 lines changed or deleted 161 lines changed or added


 symmetry.hxx   symmetry.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_SYMMETRY_HXX #ifndef VIGRA_SYMMETRY_HXX
#define VIGRA_SYMMETRY_HXX #define VIGRA_SYMMETRY_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "convolution.hxx" #include "convolution.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup SymmetryDetection Symmetry Detection /** \addtogroup SymmetryDetection Symmetry Detection
Measure the local symmetry at each pixel. Measure the local symmetry at each pixel.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
skipping to change at line 72 skipping to change at line 73
Conf. on Computer Vision, Part 1, pp. 358-368, Springer LNCS 2350, 2002 ]. Conf. on Computer Vision, Part 1, pp. 358-368, Springer LNCS 2350, 2002 ].
Minima of the algorithm response mark dark blobs, maxima correspond to light blobs. Minima of the algorithm response mark dark blobs, maxima correspond to light blobs.
The "radial strictness parameter" is fixed at <TT>alpha</tt> = 2.0, the The "radial strictness parameter" is fixed at <TT>alpha</tt> = 2.0, the
spatial spreading of the raw response is done by a Gaussian convolution spatial spreading of the raw response is done by a Gaussian convolution
at <tt>0.25*scale</TT> (these values are recommendations from the paper ). at <tt>0.25*scale</TT> (these values are recommendations from the paper ).
Loy and Zelinsky additionally propose to add the operator response from several Loy and Zelinsky additionally propose to add the operator response from several
scales (see usage example below). scales (see usage example below).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
radialSymmetryTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale);
}
\endcode
\deprecatedAPI{radialSymmetryTransform}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccess or as, radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccess or as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void radialSymmetryTransform( void radialSymmetryTransform(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
double scale) double scale)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/symmetry.hxx\><br> <b>\#include</b> \<vigra/symmetry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
MultiArray<2, unsigned char> src(w,h), centers(w,h);
MultiArray<2, float> symmetry(w,h);
// use edge detection filters at various scales
for(double scale = 2.0; scale <= 8.0; scale *= 2.0)
{
MultiArray<2, float> tmp(w,h);
// find centers of symmetry
radialSymmetryTransform(src, tmp, scale);
symmetry += tmp;
}
// mark centers of symmetry
centers.init(128);
localMinima(symmetry, centers, 0);
localMaxima(symmetry, centers, 255);
\endcode
\deprecatedUsage{radialSymmetryTransform}
\code
vigra::BImage src(w,h), centers(w,h); vigra::BImage src(w,h), centers(w,h);
vigra::FImage symmetry(w,h); vigra::FImage symmetry(w,h);
// empty result image // empty result image
centers.init(128); centers.init(128);
symmetry.init(0.0); symmetry.init(0.0);
// input width of edge detection filter // input width of edge detection filter
for(double scale = 2.0; scale <= 8.0; scale *= 2.0) for(double scale = 2.0; scale <= 8.0; scale *= 2.0)
{ {
skipping to change at line 125 skipping to change at line 161
// find centers of symmetry // find centers of symmetry
radialSymmetryTransform(srcImageRange(src), destImage(tmp), scale); radialSymmetryTransform(srcImageRange(src), destImage(tmp), scale);
combineTwoImages(srcImageRange(symmetry), srcImage(tmp), destImage( symmetry), combineTwoImages(srcImageRange(symmetry), srcImage(tmp), destImage( symmetry),
std::plus<float>()); std::plus<float>());
} }
localMinima(srcImageRange(symmetry), destImage(centers), 0); localMinima(srcImageRange(symmetry), destImage(centers), 0);
localMaxima(srcImageRange(symmetry), destImage(centers), 255); localMaxima(srcImageRange(symmetry), destImage(centers), 255);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
// SrcAccessor::value_type must be a built-in type // SrcAccessor::value_type must be a built-in type
SrcAccessor::value_type u = src_accessor(src_upperleft); SrcAccessor::value_type u = src_accessor(src_upperleft);
dest_accessor.set(u, dest_upperleft); dest_accessor.set(u, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void radialSymmetryTransform) doxygen_overloaded_function(template <...> void radialSymmetryTransform)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as, radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as,
DestIterator dul, DestAccessor ad, DestIterator dul, DestAccessor ad,
double scale) double scale)
{ {
skipping to change at line 248 skipping to change at line 283
double o = (double)orientationCounter(x, y) / maxOrientation; double o = (double)orientationCounter(x, y) / maxOrientation;
magnitudeAccumulator(x, y) = detail::RequiresExplicitCast<TmpTy pe>::cast(o * o * magnitudeAccumulator(x, y) / maxMagnitude); magnitudeAccumulator(x, y) = detail::RequiresExplicitCast<TmpTy pe>::cast(o * o * magnitudeAccumulator(x, y) / maxMagnitude);
} }
} }
gaussianSmoothing(srcImageRange(magnitudeAccumulator), destIter(dul, ad ), 0.25*scale); gaussianSmoothing(srcImageRange(magnitudeAccumulator), destIter(dul, ad ), 0.25*scale);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void radialSymmetryTransform( radialSymmetryTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
triple<SrcIterator, SrcIterator, SrcAccessor> src, pair<DestIterator, DestAccessor> dest,
pair<DestIterator, DestAccessor> dest, double scale)
double scale)
{ {
radialSymmetryTransform(src.first, src.second, src.third, radialSymmetryTransform(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale); scale);
}
template <class T1, class S1,
class T2, class S2>
inline void
radialSymmetryTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
double scale)
{
vigra_precondition(src.shape() == dest.shape(),
"radialSymmetryTransform(): shape mismatch between input and output
.");
radialSymmetryTransform(srcImageRange(src),
destImage(dest),
scale);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_SYMMETRY_HXX */ #endif /* VIGRA_SYMMETRY_HXX */
 End of changes. 11 change blocks. 
11 lines changed or deleted 60 lines changed or added


 tensorutilities.hxx   tensorutilities.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_TENSORUTILITIES_HXX #ifndef VIGRA_TENSORUTILITIES_HXX
#define VIGRA_TENSORUTILITIES_HXX #define VIGRA_TENSORUTILITIES_HXX
#include <cmath> #include <cmath>
#include "utilities.hxx" #include "utilities.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup TensorImaging Tensor Image Processing /** \addtogroup TensorImaging Tensor Image Processing
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* vectorToTensor */ /* vectorToTensor */
skipping to change at line 70 skipping to change at line 71
the output must contain vectors of length 3 which will represent the te nsor components the output must contain vectors of length 3 which will represent the te nsor components
in the order t11, t12 (== t21 due to symmetry), t22. in the order t11, t12 (== t21 due to symmetry), t22.
<b>Note:</b> In order to account for the left-handedness of the image c oordinate system, <b>Note:</b> In order to account for the left-handedness of the image c oordinate system,
the second tensor component (t12) can be negated by setting <tt>negateC omponent2 = false</tt>. the second tensor component (t12) can be negated by setting <tt>negateC omponent2 = false</tt>.
Angles will then be interpreted counter-clockwise rather than clockwise . By default, Angles will then be interpreted counter-clockwise rather than clockwise . By default,
this behavior is switched off. this behavior is switched off.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
vectorToTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool negateComponent2 = false);
}
\endcode
\deprecatedAPI{vectorToTensor}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor s rc, void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor s rc,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
bool negateComponent2 = false); bool negateComponent2 = false);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s , void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s ,
pair<DestIterator, DestAccessor> d, pair<DestIterator, DestAccessor> d,
bool negateComponent2 = false); bool negateComponent2 = false);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tensorutilities.hxx\> <b>\#include</b> \<vigra/tensorutilities.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> img(w,h);
MultiArray<2, TinyVector<float, 2> > gradient(w,h);
MultiArray<2, TinyVector<float, 3> > tensor(w,h);
...
gaussianGradient(img, gradient, 2.0);
vectorToTensor(gradient, tensor);
\endcode
\deprecatedUsage{vectorToTensor}
\code \code
FImage img(w,h); FImage img(w,h);
FVector2Image gradient(w,h); FVector2Image gradient(w,h);
FVector3Image tensor(w,h); FVector3Image tensor(w,h);
gaussianGradient(srcImageRange(img), destImage(gradient), 2.0); gaussianGradient(srcImageRange(img), destImage(gradient), 2.0);
vectorToTensor(srcImageRange(gradient), destImage(tensor)); vectorToTensor(srcImageRange(gradient), destImage(tensor));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void vectorToTensor) doxygen_overloaded_function(template <...> void vectorToTensor)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
bool negateComponent2) bool negateComponent2)
{ {
vigra_precondition(src.size(sul) == 2, vigra_precondition(src.size(sul) == 2,
skipping to change at line 160 skipping to change at line 186
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline
void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest) DestIterator dul, DestAccessor dest)
{ {
vectorToTensor(sul, slr, src, dul, dest, false); vectorToTensor(sul, slr, src, dul, dest, false);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
pair<DestIterator, DestAccessor> d, pair<DestIterator, DestAccessor> d,
bool negateComponent2) bool negateComponent2)
{ {
vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateCom ponent2); vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateCom ponent2);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> d)
{ {
vectorToTensor(s.first, s.second, s.third, d.first, d.second, false); vectorToTensor(s.first, s.second, s.third, d.first, d.second, false);
} }
template <class T1, class S1,
class T2, class S2>
inline void
vectorToTensor(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
bool negateComponent2 = false)
{
vigra_precondition(src.shape() == dest.shape(),
"vectorToTensor(): shape mismatch between input and output.");
vectorToTensor(srcImageRange(src), destImage(dest), negateComponent2);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* tensorEigenRepresentation */ /* tensorEigenRepresentation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate eigen representation of a symmetric 2x2 tensor. /** \brief Calculate eigen representation of a symmetric 2x2 tensor.
This function turns a 3-band image representing the tensor components This function turns a 3-band image representing the tensor components
t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen
representation e1, e2, and angle, where e1 \> e2. When the tensor is representation e1, e2, and angle, where e1 \> e2. When the tensor is
defined in a left-handed coordinate system (the default on images), the angle will defined in a left-handed coordinate system (the default on images), the angle will
then be given in clockwise orientation, starting at the x-axis. Otherwi se, it then be given in clockwise orientation, starting at the x-axis. Otherwi se, it
will be given in counter-clockwise orientation. will be given in counter-clockwise orientation.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
tensorEigenRepresentation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest);
}
\endcode
\deprecatedAPI{tensorEigenRepresentation}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, Sr cAccessor src, void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, Sr cAccessor src,
DestIterator dul, DestAccessor dest) ; DestIterator dul, DestAccessor dest) ;
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, Src Accessor> s, void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, Src Accessor> s,
pair<DestIterator, DestAccessor> d); pair<DestIterator, DestAccessor> d);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tensorutilities.hxx\> <b>\#include</b> \<vigra/tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<2, TinyVector<float, 3> > tensor(w,h),
eigen(w,h);
tensorEigenRepresentation(tensor, eigen);
\endcode
\deprecatedUsage{tensorEigenRepresentation}
\code
FVector3Image tensor(w,h); FVector3Image tensor(w,h);
FVector3Image eigen(w,h); FVector3Image eigen(w,h);
tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen)); tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void tensorEigenRepresentation) doxygen_overloaded_function(template <...> void tensorEigenRepresentation)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccesso r src, void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccesso r src,
DestIterator dul, DestAccessor dest) DestIterator dul, DestAccessor dest)
{ {
vigra_precondition(src.size(sul) == 3, vigra_precondition(src.size(sul) == 3,
"tensorEigenRepresentation(): input image must have 3 bands."); "tensorEigenRepresentation(): input image must have 3 bands.");
skipping to change at line 271 skipping to change at line 330
else else
{ {
dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); / / orientation dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); / / orientation
} }
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> src
> s, ,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> dest)
{
tensorEigenRepresentation(src.first, src.second, src.third, dest.first,
dest.second);
}
template <class T1, class S1,
class T2, class S2>
inline void
tensorEigenRepresentation(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{ {
tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second vigra_precondition(src.shape() == dest.shape(),
); "tensorEigenRepresentation(): shape mismatch between input and outp
ut.");
tensorEigenRepresentation(srcImageRange(src), destImage(dest));
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* tensorTrace */ /* tensorTrace */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the trace of a 2x2 tensor. /** \brief Calculate the trace of a 2x2 tensor.
This function turns a 3-band image representing the tensor components This function turns a 3-band image representing the tensor components
t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the
tensor trace t11 + t22. tensor trace t11 + t22.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2>
void
tensorTrace(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest);
}
\endcode
\deprecatedAPI{tensorTrace}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest); DestIterator dul, DestAccessor dest);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
pair<DestIterator, DestAccessor> d); pair<DestIterator, DestAccessor> d);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tensorutilities.hxx\> <b>\#include</b> \<vigra/tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<2, TinyVector<float, 3> > tensor(w,h);
MultiArray<2, float> trace(w,h);
tensorTrace(tensor, trace);
\endcode
\deprecatedUsage{tensorTrace}
\code
FVector3Image tensor(w,h); FVector3Image tensor(w,h);
FImage trace(w,h); FImage trace(w,h);
tensorTrace(srcImageRange(tensor), destImage(trace)); tensorTrace(srcImageRange(tensor), destImage(trace));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void tensorTrace) doxygen_overloaded_function(template <...> void tensorTrace)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest) DestIterator dul, DestAccessor dest)
{ {
vigra_precondition(src.size(sul) == 3, vigra_precondition(src.size(sul) == 3,
"tensorTrace(): input image must have 3 bands."); "tensorTrace(): input image must have 3 bands.");
skipping to change at line 351 skipping to change at line 442
typename DestIterator::row_iterator d = dul.rowIterator(); typename DestIterator::row_iterator d = dul.rowIterator();
for(; s < send; ++s, ++d) for(; s < send; ++s, ++d)
{ {
dest.set(src.getComponent(s,0) + src.getComponent(s,2), d); dest.set(src.getComponent(s,0) + src.getComponent(s,2), d);
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline inline void
void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> d) pair<DestIterator, DestAccessor> dest)
{
tensorTrace(src.first, src.second, src.third, dest.first, dest.second);
}
template <class T1, class S1,
class T2, class S2>
inline void
tensorTrace(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{ {
tensorTrace(s.first, s.second, s.third, d.first, d.second); vigra_precondition(src.shape() == dest.shape(),
"tensorTrace(): shape mismatch between input and output.");
tensorTrace(srcImageRange(src), destImage(dest));
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* tensorToEdgeCorner */ /* tensorToEdgeCorner */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts. /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts.
This function turns a 3-band image representing the tensor components This function turns a 3-band image representing the tensor components
t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding
the tensor's edgeness (difference of the tensor's the tensor's edgeness (difference of the tensor's
eigenvalues) and orientation, and a 1-band image representing its corne r part eigenvalues) and orientation, and a 1-band image representing its corne r part
(equal to the twice the small eigen value). The original tensor must be (equal to the twice the small eigen value). The original tensor must be
positive definite and defined in a right-handed coordinate system (e.g. positive definite and defined in a right-handed coordinate system (e.g.
the tensor resulting from \ref boundaryTensor()). the tensor resulting from \ref boundaryTensor()).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T21, class S21,
class T22, class S22>
void
tensorToEdgeCorner(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T21, S21> edge,
MultiArrayView<2, T22, S22> corner);
}
\endcode
\deprecatedAPI{tensorToEdgeCorner}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator1, class DestAccessor1, class DestIterator1, class DestAccessor1,
class DestIterator2, class DestAccessor2> class DestIterator2, class DestAccessor2>
void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccess or src, void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccess or src,
DestIterator1 edgeul, DestAccessor1 edge, DestIterator1 edgeul, DestAccessor1 edge,
DestIterator2 cornerul, DestAccessor2 corne r); DestIterator2 cornerul, DestAccessor2 corne r);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator1, class DestAccessor1, class DestIterator1, class DestAccessor1,
class DestIterator2, class DestAccessor2> class DestIterator2, class DestAccessor2>
void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccesso r> s, void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccesso r> s,
pair<DestIterator1, DestAccessor1> edge, pair<DestIterator1, DestAccessor1> edge,
pair<DestIterator2, DestAccessor2> corner); pair<DestIterator2, DestAccessor2> corner);
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tensorutilities.hxx\> <b>\#include</b> \<vigra/tensorutilities.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<2, TinyVector<float, 3> > tensor(w,h);
MultiArray<2, TinyVector<float, 2> > edgePart(w,h);
MultiArray<2, float> cornerPart(w,h);
...
tensorTrace(tensor, edgePart, cornerPart);
\endcode
\deprecatedUsage{tensorToEdgeCorner}
\code
FVector3Image tensor(w,h); FVector3Image tensor(w,h);
FVector2Image edgePart(w,h); FVector2Image edgePart(w,h);
FImage cornerPart(w,h); FImage cornerPart(w,h);
tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(corne rPart)); tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(corne rPart));
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void tensorToEdgeCorner) doxygen_overloaded_function(template <...> void tensorToEdgeCorner)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator1, class DestAccessor1, class DestIterator1, class DestAccessor1,
class DestIterator2, class DestAccessor2> class DestIterator2, class DestAccessor2>
void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator1 edgeul, DestAccessor1 edge, DestIterator1 edgeul, DestAccessor1 edge,
DestIterator2 cornerul, DestAccessor2 corner) DestIterator2 cornerul, DestAccessor2 corner)
{ {
skipping to change at line 462 skipping to change at line 589
edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); / / orientation edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); / / orientation
} }
corner.set(d1 - d4, c); // cornerness = 2 * small EV corner.set(d1 - d4, c); // cornerness = 2 * small EV
} }
} }
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator1, class DestAccessor1, class DestIterator1, class DestAccessor1,
class DestIterator2, class DestAccessor2> class DestIterator2, class DestAccessor2>
inline inline void
void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator1, DestAccessor1> edge, pair<DestIterator1, DestAccessor1> edge,
pair<DestIterator2, DestAccessor2> corner) pair<DestIterator2, DestAccessor2> corner)
{ {
tensorToEdgeCorner(s.first, s.second, s.third, tensorToEdgeCorner(src.first, src.second, src.third,
edge.first, edge.second, corner.first, corner.second ); edge.first, edge.second, corner.first, corner.second );
} }
template <class T1, class S1,
class T21, class S21,
class T22, class S22>
inline void
tensorToEdgeCorner(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T21, S21> edge,
MultiArrayView<2, T22, S22> corner)
{
vigra_precondition(src.shape() == edge.shape(),
"tensorToEdgeCorner(): shape mismatch between input and output.");
tensorToEdgeCorner(srcImageRange(src),
destImage(edge), destImage(corner));
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_TENSORUTILITIES_HXX */ #endif /* VIGRA_TENSORUTILITIES_HXX */
 End of changes. 35 change blocks. 
38 lines changed or deleted 180 lines changed or added


 tiff.hxx   tiff.hxx 
skipping to change at line 42 skipping to change at line 42
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_TIFF_HXX #ifndef VIGRA_TIFF_HXX
#define VIGRA_TIFF_HXX #define VIGRA_TIFF_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "rgbvalue.hxx" #include "rgbvalue.hxx"
#include "multi_shape.hxx"
extern "C" extern "C"
{ {
#include <tiff.h> #include <tiff.h>
#include <tiffio.h> #include <tiffio.h>
} }
namespace vigra { namespace vigra {
typedef TIFF TiffImage; typedef TIFF TiffImage;
skipping to change at line 74 skipping to change at line 76
<a href="http://www.libtiff.org/">http://www.libtiff.org/</a> for detai ls. <a href="http://www.libtiff.org/">http://www.libtiff.org/</a> for detai ls.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* importTiffImage */ /* importTiffImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Convert given TiffImage into image specified by iterator range. /** \brief Read a given TIFF image.
Accessors are used to write the data.
This function calls \ref tiffToScalarImage() or \ref tiffToRGBImage(), depending on This function calls \ref tiffToScalarImage() or \ref tiffToRGBImage(), depending on
the accessor's value_type. the destinations's value_type. Usually, it is better to use \ref import
Image().
importTiffImage() should only be used if explicit access to the TIFF ob
ject
<tt>TiffImage</tt> is required.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S>
void
importTiffImage(TiffImage * tiff, MultiArrayView<2, T, S> dest);
}
\endcode
\deprecatedAPI{importTiffImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
void void
importTiffImage(TiffImage * tiff, ImageIterator iter, Accessor a) importTiffImage(TiffImage * tiff, ImageIterator iter, Accessor a)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
void void
importTiffImage(TiffImage * tiff, pair<ImageIterator, Accessor> des t) importTiffImage(TiffImage * tiff, pair<ImageIterator, Accessor> des t)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tiff.hxx\> <b>\#include</b> \<vigra/tiff.hxx\><br/>
Namespace: vigra
\code \code
uint32 w, h; uint32 w, h;
TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r"); TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r");
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
vigra::BImage img(w,h); MultiArray<2, unsigned char> img(w,h);
vigra::importTiffImage(tiff, destImage(img)); importTiffImage(tiff, img);
TIFFClose(tiff); TIFFClose(tiff);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see \ref tiffToScalarImage() and \ref tiffToRGBImage() see \ref tiffToScalarImage() and \ref tiffToRGBImage()
<b> Preconditions:</b> <b> Preconditions:</b>
skipping to change at line 145 skipping to change at line 159
importTiffImage(tiff, iter, a, isScalar()); importTiffImage(tiff, iter, a, isScalar());
} }
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
importTiffImage(TiffImage * tiff, pair<ImageIterator, Accessor> dest) importTiffImage(TiffImage * tiff, pair<ImageIterator, Accessor> dest)
{ {
importTiffImage(tiff, dest.first, dest.second); importTiffImage(tiff, dest.first, dest.second);
} }
template <class T, class S>
inline void
importTiffImage(TiffImage * tiff, MultiArrayView<2, T, S> dest)
{
importTiffImage(tiff, destImage(dest));
}
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
importTiffImage(TiffImage * tiff, ImageIterator iter, Accessor a, VigraTrue Type) importTiffImage(TiffImage * tiff, ImageIterator iter, Accessor a, VigraTrue Type)
{ {
tiffToScalarImage(tiff, iter, a); tiffToScalarImage(tiff, iter, a);
} }
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
importTiffImage(TiffImage * tiff, ImageIterator iter, Accessor a, VigraFals eType) importTiffImage(TiffImage * tiff, ImageIterator iter, Accessor a, VigraFals eType)
skipping to change at line 167 skipping to change at line 188
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* tiffToScalarImage */ /* tiffToScalarImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Convert single-band TiffImage to scalar image. /** \brief Convert single-band TiffImage to scalar image.
This function uses accessors to write the data. Note that unexpected results can occur when the destination pixel type
is weaker than the pixel type
in the file (e.g. when a <tt>float</tt> file is imported into a <tt>uns
igned char</tt> image).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
void void
tiffToScalarImage(TiffImage * tiff, ImageIterator iter, Accessor a) tiffToScalarImage(TiffImage * tiff, ImageIterator iter, Accessor a)
} }
\endcode \endcode
\deprecatedAPI{tiffToScalarImage}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class ImageIterator, class Accessor>
void
tiffToScalarImage(TiffImage * tiff, ImageIterator iter, Accessor a)
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
void void
tiffToScalarImage(TiffImage * tiff, pair<ImageIterator, Accessor> d est) tiffToScalarImage(TiffImage * tiff, pair<ImageIterator, Accessor> d est)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tiff.hxx\> <b>\#include</b> \<vigra/tiff.hxx\><br/>
Namespace: vigra
\code \code
uint32 w, h; uint32 w, h;
uint16 photometric uint16 photometric;
TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r");
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric);
if(photometric != PHOTOMETRIC_MINISWHITE &&
photometric != PHOTOMETRIC_MINISBLACK)
{
// not a scalar image - handle error
}
MultiArray<2, unsigned char> img(w,h);
tiffToScalarImage(tiff, img);
TIFFClose(tiff);
\endcode
\deprecatedUsage{tiffToScalarImage}
\code
uint32 w, h;
uint16 photometric;
TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r"); TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r");
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric);
if(photometric != PHOTOMETRIC_MINISWHITE && if(photometric != PHOTOMETRIC_MINISWHITE &&
photometric != PHOTOMETRIC_MINISBLACK) photometric != PHOTOMETRIC_MINISBLACK)
{ {
// not a scalar image - handle error // not a scalar image - handle error
} }
vigra::BImage img(w,h); vigra::BImage img(w,h);
vigra::tiffToScalarImage(tiff, destImage(img)); vigra::tiffToScalarImage(tiff, destImage(img));
TIFFClose(tiff); TIFFClose(tiff);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft; ImageIterator upperleft;
<unsigned char, short, long, float, double> value; <unsigned char, short, long, float, double> value;
Accessor accessor; Accessor accessor;
accessor.set(value, upperleft); accessor.set(value, upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
ImageIterator must refer to a large enough image. The output array must have the correct shape.
\code \code
uint16 sampleFormat, samplesPerPixel, bitsPerSample, photometric; uint16 sampleFormat, samplesPerPixel, bitsPerSample, photometric;
TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleFormat); TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleFormat);
TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
sampleFormat != SAMPLEFORMAT_VOID sampleFormat != SAMPLEFORMAT_VOID
samplesPerPixel == 1 samplesPerPixel == 1
photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MIN
photometric == PHOTOMETRIC_MINISBLACK ISBLACK
bitsPerSample == 1 || bitsPerSample == 1 ||
bitsPerSample == 8 || bitsPerSample == 8 ||
bitsPerSample == 16 || bitsPerSample == 16 ||
bitsPerSample == 32 || bitsPerSample == 32 ||
bitsPerSample == 64 bitsPerSample == 64
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void tiffToScalarImage) doxygen_overloaded_function(template <...> void tiffToScalarImage)
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
void void
tiffToScalarImage(TiffImage * tiff, ImageIterator iter, Accessor a) tiffToScalarImage(TiffImage * tiff, ImageIterator iter, Accessor a)
{ {
vigra_precondition(tiff != 0, vigra_precondition(tiff != 0,
"tiffToScalarImage(TiffImage *, ScalarImageIterator): " "tiffToScalarImage(TiffImage *, ScalarImageIterator): "
"NULL pointer to input data."); "NULL pointer to input data.");
skipping to change at line 522 skipping to change at line 574
{ {
tiffToScalarImage(tiff, dest.first, dest.second); tiffToScalarImage(tiff, dest.first, dest.second);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* tiffToRGBImage */ /* tiffToRGBImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Convert RGB (3-band or color-mapped) TiffImage /** \brief Import a RGB (3-band or color-mapped) TiffImage
to RGB image. into a RGB image.
This function uses \ref RGBAccessor to write the data. Note that unexpected results can occur when the destination pixel type
A RGBImageIterator is an iterator which is associated with a is weaker than the pixel type
RGBAccessor. in the file (e.g. when a <tt>float</tt> file is imported into a <tt>uns
igned char</tt> image).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class RGBImageIterator, class RGBAccessor> template <class RGBImageIterator, class RGBAccessor>
void void
tiffToRGBImage(TiffImage * tiff, RGBImageIterator iter, RGBAccessor a) tiffToRGBImage(TiffImage * tiff, RGBImageIterator iter, RGBAccessor a)
} }
\endcode \endcode
\deprecatedAPI{tiffToRGBImage}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class RGBImageIterator, class RGBAccessor>
void
tiffToRGBImage(TiffImage * tiff, RGBImageIterator iter, RGBAccessor
a)
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class RGBImageIterator, class RGBAccessor> template <class RGBImageIterator, class RGBAccessor>
void void
tiffToRGBImage(TiffImage * tiff, pair<RGBImageIterator, RGBAccessor > dest) tiffToRGBImage(TiffImage * tiff, pair<RGBImageIterator, RGBAccessor > dest)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tiff.hxx\> <b>\#include</b> \<vigra/tiff.hxx\><br/>
Namespace: vigra
\code
uint32 w, h;
uint16 photometric
TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r");
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric);
if(photometric != PHOTOMETRIC_RGB &&
photometric != PHOTOMETRIC_PALETTE)
{
// not an RGB image - handle error
}
MultiArray<2, RGBValue<unsigned char> > img(w, h);
tiffToRGBImage(tiff, img);
TIFFClose(tiff);
\endcode
\deprecatedUsage{tiffToRGBImage}
\code \code
uint32 w, h; uint32 w, h;
uint16 photometric uint16 photometric
TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r"); TiffImage * tiff = TIFFOpen("tiffimage.tiff", "r");
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometric);
if(photometric != PHOTOMETRIC_RGB && if(photometric != PHOTOMETRIC_RGB &&
photometric != PHOTOMETRIC_PALETTE) photometric != PHOTOMETRIC_PALETTE)
{ {
// not an RGB image - handle error // not an RGB image - handle error
} }
vigra::BRGBImage img(w, h); vigra::BRGBImage img(w, h);
vigra::tiffToRGBImage(tiff, destImage(img)); vigra::tiffToRGBImage(tiff, destImage(img));
TIFFClose(tiff); TIFFClose(tiff);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft; ImageIterator upperleft;
<unsigned char, short, long, float, double> rvalue, gvalue, bvalue; <unsigned char, short, long, float, double> rvalue, gvalue, bvalue;
RGBAccessor accessor; RGBAccessor accessor;
accessor.setRed(rvalue, upperleft); accessor.setRed(rvalue, upperleft);
accessor.setGreen(gvalue, upperleft); accessor.setGreen(gvalue, upperleft);
accessor.setBlue(bvalue, upperleft); accessor.setBlue(bvalue, upperleft);
\endcode \endcode
\deprecatedEnd
<b> Preconditions:</b> <b> Preconditions:</b>
ImageIterator must refer to a large enough image. The destination image must have the appropriate size.
\code \code
uint16 sampleFormat, samplesPerPixel, bitsPerSample, photometric; uint16 sampleFormat, samplesPerPixel, bitsPerSample, photometric;
TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleFormat); TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleFormat);
TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
sampleFormat != SAMPLEFORMAT_VOID sampleFormat != SAMPLEFORMAT_VOID
samplesPerPixel == 3 // unless photometric == PHOTOMETRIC_PALETTE samplesPerPixel == 3 // unless photometric == PHOTOMETRIC_PALETTE
photometric == PHOTOMETRIC_RGB || photometric == PHOTOMETRIC_RGB ||
photometric == PHOTOMETRIC_PALETTE photometric == PHOTOMETRIC_PALETTE
bitsPerSample == 1 || bitsPerSample == 1 ||
bitsPerSample == 8 || bitsPerSample == 8 ||
bitsPerSample == 16 || bitsPerSample == 16 ||
bitsPerSample == 32 || bitsPerSample == 32 ||
bitsPerSample == 64 bitsPerSample == 64
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void tiffToRGBImage) doxygen_overloaded_function(template <...> void tiffToRGBImage)
template <class RGBImageIterator, class RGBAccessor> template <class RGBImageIterator, class RGBAccessor>
void void
tiffToRGBImage(TiffImage * tiff, RGBImageIterator iter, RGBAccessor a) tiffToRGBImage(TiffImage * tiff, RGBImageIterator iter, RGBAccessor a)
{ {
vigra_precondition(tiff != 0, vigra_precondition(tiff != 0,
"tiffToRGBImage(TiffImage *, RGBImageIterator): " "tiffToRGBImage(TiffImage *, RGBImageIterator): "
"NULL pointer to input data."); "NULL pointer to input data.");
skipping to change at line 1017 skipping to change at line 1099
/* */ /* */
/* createTiffImage */ /* createTiffImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Create a TiffImage from the given iterator range. /** \brief Create a TiffImage from the given iterator range.
Type and size of the TiffImage are determined by the input image. Type and size of the TiffImage are determined by the input image.
Currently, the function can create scalar images and RGB images of type Currently, the function can create scalar images and RGB images of type
unsigned char, short, int, float, and double. unsigned char, short, int, float, and double.
This function uses accessors to read the data.
Usually, it is better to use \ref exportImage(). createTiffImage() shou
ld only be used if explicit access to the TIFF object
<tt>TiffImage</tt> is required.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T, class S>
void
createTiffImage(MultiArrayView<2, T, S> const & src, TiffImage * ti
ff);
}
\endcode
\deprecatedAPI{createTiffImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
TiffImage * TiffImage *
createTiffImage(ImageIterator upperleft, ImageIterator lowerright, createTiffImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a) Accessor a)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
TiffImage * TiffImage *
createTiffImage(triple<ImageIterator, ImageIterator, Accessor> src) createTiffImage(triple<ImageIterator, ImageIterator, Accessor> src)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tiff.hxx\> <b>\#include</b> \<vigra/tiff.hxx\><br/>
Namespace: vigra
\code \code
MultiArray<2, float> img(width, height);
...
TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w");
createTiffImage(img, tiff);
TIFFClose(tiff); // implicitly writes the image to the disk
\endcode
\deprecatedUsage{createTiffImage}
\code
vigra::BImage img(width, height); vigra::BImage img(width, height);
... ...
TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w"); TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w");
vigra::createTiffImage(srcImageRange(img), tiff); vigra::createTiffImage(srcImageRange(img), tiff);
TIFFClose(tiff); // implicitly writes the image to the disk TIFFClose(tiff); // implicitly writes the image to the disk
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft; ImageIterator upperleft;
Accessor accessor; Accessor accessor;
accessor(upperleft); // result written into TiffImage accessor(upperleft); // result written into TiffImage
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void createTiffImage) doxygen_overloaded_function(template <...> void createTiffImage)
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
createTiffImage(ImageIterator upperleft, ImageIterator lowerright, createTiffImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, TiffImage * tiff) Accessor a, TiffImage * tiff)
{ {
CreateTiffImage<typename Accessor::value_type>:: CreateTiffImage<typename Accessor::value_type>::
exec(upperleft, lowerright, a, tiff); exec(upperleft, lowerright, a, tiff);
} }
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
createTiffImage(triple<ImageIterator, ImageIterator, Accessor> src, TiffIma ge * tiff) createTiffImage(triple<ImageIterator, ImageIterator, Accessor> src, TiffIma ge * tiff)
{ {
createTiffImage(src.first, src.second, src.third, tiff); createTiffImage(src.first, src.second, src.third, tiff);
} }
template <class T, class S>
inline void
createTiffImage(MultiArrayView<2, T, S> const & src, TiffImage * tiff)
{
createTiffImage(srcImageRange(src), tiff);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* createScalarTiffImage */ /* createScalarTiffImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Create a single-band TiffImage from the given scalar image. /** \brief Create a single-band TiffImage from the given scalar image.
Type and size of the TiffImage are determined by the input image Type and size of the TiffImage are determined by the input image
(may be one of unsigned char, short, int, float, or double). (may be one of unsigned char, short, int, float, or double).
This function uses accessors to read the data.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
TiffImage * TiffImage *
createScalarTiffImage(ImageIterator upperleft, ImageIterator lowerr ight, createScalarTiffImage(ImageIterator upperleft, ImageIterator lowerr ight,
Accessor a) Accessor a)
} }
\endcode \endcode
\deprecatedAPI{createScalarTiffImage}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class ImageIterator, class Accessor>
TiffImage *
createScalarTiffImage(ImageIterator upperleft, ImageIterator lowerr
ight,
Accessor a)
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
TiffImage * TiffImage *
createScalarTiffImage(triple<ImageIterator, ImageIterator, Accessor > src) createScalarTiffImage(triple<ImageIterator, ImageIterator, Accessor > src)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tiff.hxx\> <b>\#include</b> \<vigra/tiff.hxx\><br/>
Namespace: vigra
\code \code
vigra::BImage img(width, height); MultiArray<2, float> img(width, height);
...
TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w");
createScalarTiffImage(img, tiff);
TIFFClose(tiff); // implicitly writes the image to the disk
\endcode
\deprecatedUsage{createScalarTiffImage}
\code
vigra::BImage img(width, height);
... ...
TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w"); TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w");
vigra::createScalarTiffImage(srcImageRange(img), tiff); vigra::createScalarTiffImage(srcImageRange(img), tiff);
TIFFClose(tiff); // implicitly writes the image to the disk TIFFClose(tiff); // implicitly writes the image to the disk
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft; ImageIterator upperleft;
Accessor accessor; Accessor accessor;
accessor(upperleft); // result written into TiffImage accessor(upperleft); // result written into TiffImage
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void createScalarTiffImage) doxygen_overloaded_function(template <...> void createScalarTiffImage)
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
createScalarTiffImage(ImageIterator upperleft, ImageIterator lowerright, createScalarTiffImage(ImageIterator upperleft, ImageIterator lowerright,
Accessor a, TiffImage * tiff) Accessor a, TiffImage * tiff)
{ {
CreateTiffImage<typename Accessor::value_type>:: CreateTiffImage<typename Accessor::value_type>::
exec(upperleft, lowerright, a, tiff); exec(upperleft, lowerright, a, tiff);
skipping to change at line 1501 skipping to change at line 1634
/********************************************************/ /********************************************************/
/* */ /* */
/* createRGBTiffImage */ /* createRGBTiffImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Create a 3-band TiffImage from the given RGB image. /** \brief Create a 3-band TiffImage from the given RGB image.
Type and size of the TiffImage are determined by the input image Type and size of the TiffImage are determined by the input image
(may be one of unsigned char, int, float, or double). (may be one of unsigned char, int, float, or double).
This function uses \ref RGBAccessor to read the data. A
RGBImageIterator is an iterator that is associated with a
RGBAccessor.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code \code
namespace vigra { namespace vigra {
template <class RGBImageIterator, class RGBAccessor> template <class RGBImageIterator, class RGBAccessor>
TiffImage * TiffImage *
createRGBTiffImage(RGBImageIterator upperleft, RGBImageIterator low erright, createRGBTiffImage(RGBImageIterator upperleft, RGBImageIterator low erright,
RGBAccessor a) RGBAccessor a)
} }
\endcode \endcode
\deprecatedAPI{createRGBTiffImage}
pass \ref ImageIterators and \ref DataAccessors :
\code
namespace vigra {
template <class RGBImageIterator, class RGBAccessor>
TiffImage *
createRGBTiffImage(RGBImageIterator upperleft, RGBImageIterator low
erright,
RGBAccessor a)
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class RGBImageIterator, class RGBAccessor> template <class RGBImageIterator, class RGBAccessor>
TiffImage * TiffImage *
createRGBTiffImage(triple<RGBImageIterator, RGBImageIterator, RGBAc cessor> src) createRGBTiffImage(triple<RGBImageIterator, RGBImageIterator, RGBAc cessor> src)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/tiff.hxx\> <b>\#include</b> \<vigra/tiff.hxx\><br/>
Namespace: vigra
\code \code
vigra::BRGBImage img(width, height); MultiArray<2, RGBValue<unsigned char> > img(width, height);
...
TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w");
createRGBTiffImage(img, tiff);
TIFFClose(tiff); // implicitly writes the image to the disk
\endcode
\deprecatedUsage{createRGBTiffImage}
\code
vigra::BRGBImage img(width, height);
... ...
TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w"); TiffImage * tiff = TIFFOpen(("tiffimage.tiff", "w");
vigra::createRGBTiffImage(srcImageRange(img), tiff); vigra::createRGBTiffImage(srcImageRange(img), tiff);
TIFFClose(tiff); // implicitly writes the image to the disk TIFFClose(tiff); // implicitly writes the image to the disk
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ImageIterator upperleft; ImageIterator upperleft;
RGBAccessor accessor; RGBAccessor accessor;
accessor.red(upperleft); // result written into TiffImage accessor.red(upperleft); // result written into TiffImage
accessor.green(upperleft); // result written into TiffImage accessor.green(upperleft); // result written into TiffImage
accessor.blue(upperleft); // result written into TiffImage accessor.blue(upperleft); // result written into TiffImage
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> void createRGBTiffImage) doxygen_overloaded_function(template <...> void createRGBTiffImage)
template <class RGBImageIterator, class RGBAccessor> template <class RGBImageIterator, class RGBAccessor>
inline void inline void
createRGBTiffImage(RGBImageIterator upperleft, RGBImageIterator lowerright, createRGBTiffImage(RGBImageIterator upperleft, RGBImageIterator lowerright,
RGBAccessor a, TiffImage * tiff) RGBAccessor a, TiffImage * tiff)
{ {
CreateTiffImage<typename RGBAccessor::value_type>:: CreateTiffImage<typename RGBAccessor::value_type>::
exec(upperleft, lowerright, a, tiff); exec(upperleft, lowerright, a, tiff);
 End of changes. 66 change blocks. 
53 lines changed or deleted 216 lines changed or added


 timing.hxx   timing.hxx 
skipping to change at line 45 skipping to change at line 45
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_TIMING_HXX #ifndef VIGRA_TIMING_HXX
#define VIGRA_TIMING_HXX #define VIGRA_TIMING_HXX
#ifndef VIGRA_NO_TIMING #ifndef VIGRA_NO_TIMING
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
/*! \page TimingMacros Timing macros for runtime measurements /** \page TimingMacros Timing macros for runtime measurements
<b>\#include</b> \<vigra/timing.hxx\> <b>\#include</b> \<vigra/timing.hxx\>
These macros allow to perform execution speed measurements. Results are These macros allow to perform execution speed measurements. Results are rep
reported orted
in <i>milliseconds</i>. in <i>milliseconds</i>.
However, note that timings below 1 msec are generally subject to round- However, note that timings below 1 msec are generally subject to round-off
off errors. errors.
Under LINUX, you can \#define VIGRA_HIRES_TIMING to get better Under LINUX, you can \#define VIGRA_HIRES_TIMING to get better
accuracy, but this requires linking against librt. accuracy, but this requires linking against librt.
Basic usage: Basic usage:
\code \code
void time_it() void time_it()
{ {
USETICTOC USETICTOC
TIC TIC
... code to be timed ... code to be timed
TOC TOC
... untimed code ... untimed code
TIC TIC
... other code to be timed ... other code to be timed
TOC TOC
} }
\endcode \endcode
Instead of TOC, which outputs the time difference to std::cerr, Instead of TOC, which outputs the time difference to std::cerr,
you may use TOCN (the time difference in <i>msec</i> as a double) you may use TOCN (the time difference in <i>msec</i> as a double)
or TOCS (the time difference as a std::string). or TOCS (the time difference as a std::string).
Alternatively, you can perform nested timing like so: Alternatively, you can perform nested timing like so:
\code \code
void time_it() void time_it()
{ {
USE_NESTED_TICTOC USE_NESTED_TICTOC
TICPUSH TICPUSH
... code to be timed ... code to be timed
TICPUSH TICPUSH
... nested code to be timed ... nested code to be timed
TOC print time for nested code TOC print time for nested code
... more code to be timed ... more code to be timed
TOC print total time TOC print total time
} }
\endcode \endcode
*/ */
/*! \file timing.hxx Timing macros for runtime measurements /** \file timing.hxx Timing macros for runtime measurements
This header defines timing macros for runtime measurements. See \ref Timi ngMacros for examples. This header defines timing macros for runtime measurements. See \ref Timi ngMacros for examples.
\def USETICTOC \def USETICTOC
Enable timing using TIC/TOC* pairs. This macro defines temporary storage for the timing data, so it needs to precede the TIC/TOC macros in their con text. Enable timing using TIC/TOC* pairs. This macro defines temporary storage for the timing data, so it needs to precede the TIC/TOC macros in their con text.
\hideinitializer \hideinitializer
\def USE_NESTED_TICTOC \def USE_NESTED_TICTOC
Enable timing using TICPUSH/TOC* pairs. This macro defines temporary stor age for the timing data, so it needs to precede the TIC/TOC macros in their context. Enable timing using TICPUSH/TOC* pairs. This macro defines temporary stor age for the timing data, so it needs to precede the TIC/TOC macros in their context.
\hideinitializer \hideinitializer
skipping to change at line 155 skipping to change at line 155
namespace { namespace {
inline double queryTimerUnit() inline double queryTimerUnit()
{ {
LARGE_INTEGER frequency; LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency); QueryPerformanceFrequency(&frequency);
return 1000.0 / frequency.QuadPart; return 1000.0 / frequency.QuadPart;
} }
static const double timerUnit = queryTimerUnit();
inline double tic_toc_diff_num(LARGE_INTEGER const & tic) inline double tic_toc_diff_num(LARGE_INTEGER const & tic)
{ {
LARGE_INTEGER toc; LARGE_INTEGER toc;
QueryPerformanceCounter(&toc); QueryPerformanceCounter(&toc);
static double unit = queryTimerUnit(); return ((toc.QuadPart - tic.QuadPart) * timerUnit);
return ((toc.QuadPart - tic.QuadPart) * unit);
} }
inline std::string tic_toc_diff_string(LARGE_INTEGER const & tic) inline std::string tic_toc_diff_string(LARGE_INTEGER const & tic)
{ {
double diff = tic_toc_diff_num(tic); double diff = tic_toc_diff_num(tic);
std::stringstream s; std::stringstream s;
s << diff << " msec"; s << diff << " msec";
return s.str(); return s.str();
} }
 End of changes. 8 change blocks. 
16 lines changed or deleted 17 lines changed or added


 tinyvector.hxx   tinyvector.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_TINYVECTOR_HXX #ifndef VIGRA_TINYVECTOR_HXX
#define VIGRA_TINYVECTOR_HXX #define VIGRA_TINYVECTOR_HXX
namespace lemon {
struct Invalid;
} // namespace lemon
#include <cmath> // abs(double) #include <cmath> // abs(double)
#include <cstdlib> // abs(int) #include <cstdlib> // abs(int)
#include <iosfwd> // ostream #include <iosfwd> // ostream
#include <algorithm> #include <algorithm>
#include "config.hxx" #include "config.hxx"
#include "error.hxx" #include "error.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "memory.hxx" #include "memory.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "diff2d.hxx" #include "diff2d.hxx"
#include "static_assert.hxx"
#ifdef VIGRA_CHECK_BOUNDS #ifdef VIGRA_CHECK_BOUNDS
#define VIGRA_ASSERT_INSIDE(diff) \ #define VIGRA_ASSERT_INSIDE(diff) \
vigra_precondition(diff >= 0, "Index out of bounds");\ vigra_precondition(diff >= 0, "Index out of bounds");\
vigra_precondition(diff < SIZE, "Index out of bounds"); vigra_precondition(diff < SIZE, "Index out of bounds");
#else #else
#define VIGRA_ASSERT_INSIDE(diff) #define VIGRA_ASSERT_INSIDE(diff)
#endif #endif
namespace vigra { namespace vigra {
skipping to change at line 143 skipping to change at line 150
{ {
for(int i=0; i<LEVEL; ++i) for(int i=0; i<LEVEL; ++i)
left[i] = detail::RequiresExplicitCast<T1>::cast(pow(left, righ t)); left[i] = detail::RequiresExplicitCast<T1>::cast(pow(left, righ t));
} }
VIGRA_EXEC_LOOP(assign, =) VIGRA_EXEC_LOOP(assign, =)
VIGRA_EXEC_LOOP(add, +=) VIGRA_EXEC_LOOP(add, +=)
VIGRA_EXEC_LOOP(sub, -=) VIGRA_EXEC_LOOP(sub, -=)
VIGRA_EXEC_LOOP(mul, *=) VIGRA_EXEC_LOOP(mul, *=)
VIGRA_EXEC_LOOP(div, /=) VIGRA_EXEC_LOOP(div, /=)
VIGRA_EXEC_LOOP(mod, %=)
VIGRA_EXEC_LOOP(neg, = -) VIGRA_EXEC_LOOP(neg, = -)
VIGRA_EXEC_LOOP(abs, = vigra::abs) VIGRA_EXEC_LOOP(abs, = vigra::abs)
VIGRA_EXEC_LOOP(floor, = vigra::floor) VIGRA_EXEC_LOOP(floor, = vigra::floor)
VIGRA_EXEC_LOOP(ceil, = vigra::ceil) VIGRA_EXEC_LOOP(ceil, = vigra::ceil)
VIGRA_EXEC_LOOP(round, = vigra::round)
VIGRA_EXEC_LOOP(sqrt, = vigra::sqrt) VIGRA_EXEC_LOOP(sqrt, = vigra::sqrt)
VIGRA_EXEC_LOOP(fromPromote, = NumericTraits<T1>::fromPromote) VIGRA_EXEC_LOOP(fromPromote, = NumericTraits<T1>::fromPromote)
VIGRA_EXEC_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote) VIGRA_EXEC_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote)
VIGRA_EXEC_LOOP_SCALAR(addScalar, +)
VIGRA_EXEC_LOOP_SCALAR(subScalar, -)
VIGRA_EXEC_LOOP_SCALAR(mulScalar, *) VIGRA_EXEC_LOOP_SCALAR(mulScalar, *)
VIGRA_EXEC_LOOP_SCALAR(divScalar, /) VIGRA_EXEC_LOOP_SCALAR(divScalar, /)
VIGRA_EXEC_LOOP_MINMAX(min, >) VIGRA_EXEC_LOOP_MINMAX(min, >)
VIGRA_EXEC_LOOP_MINMAX(max, <) VIGRA_EXEC_LOOP_MINMAX(max, <)
template <class T> template <class T>
static T const & minimum(T const * p) static T const & minimum(T const * p)
{ {
return *std::min_element(p, p+LEVEL); return *std::min_element(p, p+LEVEL);
} }
template <class T> template <class T>
static T const & maximum(T const * p) static T const & maximum(T const * p)
{ {
return *std::max_element(p, p+LEVEL); return *std::max_element(p, p+LEVEL);
} }
template <class T>
static bool all(T const * p, T const & zero)
{
for(int i=0; i<LEVEL; ++i)
if(p[i] == zero)
return false;
return true;
}
template <class T>
static bool any(T const * p, T const & zero)
{
for(int i=0; i<LEVEL; ++i)
if(p[i] != zero)
return true;
return false;
}
template <class T1, class T2> template <class T1, class T2>
static bool notEqual(T1 const * left, T2 const * right) static bool notEqual(T1 const * left, T2 const * right)
{ {
for(int i=0; i<LEVEL; ++i) for(int i=0; i<LEVEL; ++i)
if(left[i] != right[i]) if(left[i] != right[i])
return true; return true;
return false; return false;
} }
template <class T1, class T2> template <class T1, class T2>
static bool less(T1 const * left, T2 const * right) static bool lexicographicLessThan(T1 const * left, T2 const * right)
{ {
for(int i=0; i<LEVEL; ++i) for(int i=0; i<LEVEL; ++i)
{ {
if(left[i] < right[i]) if(left[i] < right[i])
return true; return true;
if(right[i] < left[i]) if(right[i] < left[i])
return false; return false;
} }
return false; return false;
} }
template <class T>
static bool closeAtTolerance(T const * left, T const * right, T epsilon
)
{
bool res = true;
for(int i=0; i<LEVEL; ++i)
{
res = res && vigra::closeAtTolerance(left[i], right[i], epsilon
);
}
return res;
}
template <class T> template <class T>
static typename NumericTraits<T>::Promote static typename NumericTraits<T>::Promote
dot(T const * d) dot(T const * d)
{ {
typename NumericTraits<T>::Promote res(*d * *d); typename NumericTraits<T>::Promote res(*d * *d);
for(int i=1; i<LEVEL; ++i) for(int i=1; i<LEVEL; ++i)
res += d[i] * d[i]; res += d[i] * d[i];
return res; return res;
} }
skipping to change at line 267 skipping to change at line 308
} }
template <class T> template <class T>
static T const & maximum(T const * p) static T const & maximum(T const * p)
{ {
T const & m = UnrollScalarResult<LEVEL - 1>::maximum(p+1); T const & m = UnrollScalarResult<LEVEL - 1>::maximum(p+1);
return *p > m return *p > m
? *p ? *p
: m; : m;
} }
template <class T>
static bool all(T const * p, T const & zero)
{
return *p != zero && UnrollScalarResult<LEVEL - 1>::all(p+1, zero);
}
template <class T>
static bool any(T const * p, T const & zero)
{
return *p != zero || UnrollScalarResult<LEVEL - 1>::any(p+1, zero);
}
}; };
template <> template <>
struct UnrollScalarResult<1> struct UnrollScalarResult<1>
{ {
template <class T> template <class T>
static typename NumericTraits<T>::Promote static typename NumericTraits<T>::Promote
dot(T const * d) dot(T const * d)
{ {
return *d * *d ; return *d * *d ;
skipping to change at line 310 skipping to change at line 363
static T const & minimum(T const * p) static T const & minimum(T const * p)
{ {
return *p; return *p;
} }
template <class T> template <class T>
static T const & maximum(T const * p) static T const & maximum(T const * p)
{ {
return *p; return *p;
} }
template <class T>
static bool all(T const * p, T const & zero)
{
return *p != zero;
}
template <class T>
static bool any(T const * p, T const & zero)
{
return *p != zero;
}
}; };
#undef VIGRA_EXEC_LOOP #undef VIGRA_EXEC_LOOP
#undef VIGRA_EXEC_LOOP_MINMAX #undef VIGRA_EXEC_LOOP_MINMAX
#undef VIGRA_EXEC_LOOP_SCALAR #undef VIGRA_EXEC_LOOP_SCALAR
#define VIGRA_UNROLL_LOOP(NAME, OPER) \ #define VIGRA_UNROLL_LOOP(NAME, OPER) \
template <class T1, class T2> \ template <class T1, class T2> \
static void NAME(T1 * left, T2 const * right) \ static void NAME(T1 * left, T2 const * right) \
{ \ { \
skipping to change at line 377 skipping to change at line 442
{ {
*left = detail::RequiresExplicitCast<T1>::cast(pow(*left, right)); *left = detail::RequiresExplicitCast<T1>::cast(pow(*left, right));
UnrollLoop<LEVEL-1>::power(left+1, right); UnrollLoop<LEVEL-1>::power(left+1, right);
} }
VIGRA_UNROLL_LOOP(assign, =) VIGRA_UNROLL_LOOP(assign, =)
VIGRA_UNROLL_LOOP(add, +=) VIGRA_UNROLL_LOOP(add, +=)
VIGRA_UNROLL_LOOP(sub, -=) VIGRA_UNROLL_LOOP(sub, -=)
VIGRA_UNROLL_LOOP(mul, *=) VIGRA_UNROLL_LOOP(mul, *=)
VIGRA_UNROLL_LOOP(div, /=) VIGRA_UNROLL_LOOP(div, /=)
VIGRA_UNROLL_LOOP(mod, %=)
VIGRA_UNROLL_LOOP(neg, = -) VIGRA_UNROLL_LOOP(neg, = -)
VIGRA_UNROLL_LOOP(abs, = vigra::abs) VIGRA_UNROLL_LOOP(abs, = vigra::abs)
VIGRA_UNROLL_LOOP(floor, = vigra::floor) VIGRA_UNROLL_LOOP(floor, = vigra::floor)
VIGRA_UNROLL_LOOP(ceil, = vigra::ceil) VIGRA_UNROLL_LOOP(ceil, = vigra::ceil)
VIGRA_UNROLL_LOOP(round, = vigra::round)
VIGRA_UNROLL_LOOP(sqrt, = vigra::sqrt) VIGRA_UNROLL_LOOP(sqrt, = vigra::sqrt)
VIGRA_UNROLL_LOOP(fromPromote, = NumericTraits<T1>::fromPromote) VIGRA_UNROLL_LOOP(fromPromote, = NumericTraits<T1>::fromPromote)
VIGRA_UNROLL_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote ) VIGRA_UNROLL_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote )
VIGRA_UNROLL_LOOP_SCALAR(addScalar, +)
VIGRA_UNROLL_LOOP_SCALAR(subScalar, -)
VIGRA_UNROLL_LOOP_SCALAR(mulScalar, *) VIGRA_UNROLL_LOOP_SCALAR(mulScalar, *)
VIGRA_UNROLL_LOOP_SCALAR(divScalar, /) VIGRA_UNROLL_LOOP_SCALAR(divScalar, /)
VIGRA_UNROLL_LOOP_MINMAX(min, >) VIGRA_UNROLL_LOOP_MINMAX(min, >)
VIGRA_UNROLL_LOOP_MINMAX(max, <) VIGRA_UNROLL_LOOP_MINMAX(max, <)
template <class T> template <class T>
static T const & minimum(T const * p) static T const & minimum(T const * p)
{ {
return UnrollScalarResult<LEVEL>::minimum(p); return UnrollScalarResult<LEVEL>::minimum(p);
} }
template <class T> template <class T>
static T const & maximum(T const * p) static T const & maximum(T const * p)
{ {
return UnrollScalarResult<LEVEL>::maximum(p); return UnrollScalarResult<LEVEL>::maximum(p);
} }
template <class T>
static bool all(T const * p, T const & zero)
{
return UnrollScalarResult<LEVEL>::all(p, zero);
}
template <class T>
static bool any(T const * p, T const & zero)
{
return UnrollScalarResult<LEVEL>::any(p, zero);
}
template <class T1, class T2> template <class T1, class T2>
static bool notEqual(T1 const * left, T2 const * right) static bool notEqual(T1 const * left, T2 const * right)
{ {
return (*left != *right) || UnrollLoop<LEVEL - 1>::notEqual(left+1, right+1); return (*left != *right) || UnrollLoop<LEVEL - 1>::notEqual(left+1, right+1);
} }
template <class T1, class T2> template <class T1, class T2>
static bool less(T1 const * left, T2 const * right) static bool lexicographicLessThan(T1 const * left, T2 const * right)
{ {
if(*left < *right) if(*left < *right)
return true; return true;
if(*right < *left) if(*right < *left)
return false; return false;
return UnrollLoop<LEVEL - 1>::less(left+1, right+1); return UnrollLoop<LEVEL - 1>::lexicographicLessThan(left+1, right+1
);
}
template <class T>
static bool closeAtTolerance(T const * left, T const * right, T epsilon
)
{
return vigra::closeAtTolerance(*left, *right, epsilon) &&
UnrollLoop<LEVEL - 1>::closeAtTolerance(left+1, right+1,
epsilon);
} }
template <class T> template <class T>
static typename NumericTraits<T>::Promote static typename NumericTraits<T>::Promote
dot(T const * d) dot(T const * d)
{ {
return UnrollScalarResult<LEVEL>::dot(d); return UnrollScalarResult<LEVEL>::dot(d);
} }
template <class T1, class T2> template <class T1, class T2>
skipping to change at line 460 skipping to change at line 548
static void assignCast(T1, T2) {} static void assignCast(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void assign(T1, T2) {} static void assign(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void assignScalar(T1, T2) {} static void assignScalar(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void power(T1, T2) {} static void power(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void add(T1, T2) {} static void add(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void addScalar(T1, T2) {}
template <class T1, class T2>
static void sub(T1, T2) {} static void sub(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void subScalar(T1, T2) {}
template <class T1, class T2>
static void mul(T1, T2) {} static void mul(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void mulScalar(T1, T2) {} static void mulScalar(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void div(T1, T2) {} static void div(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void mod(T1, T2) {}
template <class T1, class T2>
static void divScalar(T1, T2) {} static void divScalar(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void fromPromote(T1, T2) {} static void fromPromote(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void fromRealPromote(T1, T2) {} static void fromRealPromote(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void neg(T1, T2) {} static void neg(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void abs(T1, T2) {} static void abs(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void floor(T1, T2) {} static void floor(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void ceil(T1, T2) {} static void ceil(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void round(T1, T2) {}
template <class T1, class T2>
static void sqrt(T1, T2) {} static void sqrt(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static bool notEqual(T1, T2) { return false; } static bool notEqual(T1, T2) { return false; }
template <class T1, class T2> template <class T1, class T2>
static bool less(T1, T2) { return false; } static bool lexicographicLessThan(T1, T2) { return false; }
template <class T1, class T2> template <class T1, class T2>
static void min(T1, T2) {} static void min(T1, T2) {}
template <class T1, class T2> template <class T1, class T2>
static void max(T1, T2) {} static void max(T1, T2) {}
template <class T> template <class T>
static T minimum(T const * p) static T minimum(T const *) { return NumericTraits<T>::max(); }
{
return NumericTraits<T>::max();
}
template <class T> template <class T>
static T maximum(T const * p) static T maximum(T const *) { return NumericTraits<T>::min(); }
{ template <class T>
return NumericTraits<T>::min(); static bool all(T const *, T const &) { return true; }
} template <class T>
static bool any(T const *, T const &) { return false; }
template <class T>
static bool closeAtTolerance(T const *, T const *, T) { return true; }
}; };
template <int SIZE> template <int SIZE>
struct LoopType struct LoopType
{ {
typedef typename IfBool<(SIZE <= 5), UnrollLoop<SIZE>, ExecLoop<SIZE> > static const int MaxUnrollSize = 5;
::type type; typedef typename IfBool<(SIZE <= MaxUnrollSize), UnrollLoop<SIZE>, Exec
Loop<SIZE> >::type type;
}; };
struct DontInit {}; struct DontInit {};
inline DontInit dontInit() {return DontInit(); } inline DontInit dontInit() {return DontInit(); }
} // namespace detail } // namespace detail
template <class T, int SIZE> template <class T, int SIZE>
skipping to change at line 657 skipping to change at line 754
/** Component-wise divide-assignment /** Component-wise divide-assignment
*/ */
template <class T1, class D1, class D2> template <class T1, class D1, class D2>
DERIVED & operator/=(TinyVectorBase<T1, SIZE, D1, D2> const & r) DERIVED & operator/=(TinyVectorBase<T1, SIZE, D1, D2> const & r)
{ {
Loop::div(data_, r.begin()); Loop::div(data_, r.begin());
return static_cast<DERIVED &>(*this); return static_cast<DERIVED &>(*this);
} }
/** Component-wise modulo-assignment
*/
template <class T1, class D1, class D2>
DERIVED & operator%=(TinyVectorBase<T1, SIZE, D1, D2> const & r)
{
Loop::mod(data_, r.begin());
return static_cast<DERIVED &>(*this);
}
/** Component-wise scalar multiply-assignment
*/
DERIVED & operator+=(double r)
{
Loop::addScalar(data_, r);
return static_cast<DERIVED &>(*this);
}
/** Component-wise scalar divide-assignment
*/
DERIVED & operator-=(double r)
{
Loop::subScalar(data_, r);
return static_cast<DERIVED &>(*this);
}
/** Component-wise scalar multiply-assignment /** Component-wise scalar multiply-assignment
*/ */
DERIVED & operator*=(double r) DERIVED & operator*=(double r)
{ {
Loop::mulScalar(data_, r); Loop::mulScalar(data_, r);
return static_cast<DERIVED &>(*this); return static_cast<DERIVED &>(*this);
} }
/** Component-wise scalar divide-assignment /** Component-wise scalar divide-assignment
*/ */
DERIVED & operator/=(double r) DERIVED & operator/=(double r)
{ {
Loop::divScalar(data_, r); Loop::divScalar(data_, r);
return static_cast<DERIVED &>(*this); return static_cast<DERIVED &>(*this);
} }
/** Calculate magnitude. /** Calculate magnitude (i.e. 2-norm / Euclidean norm / length).
*/ * \see squaredMagnitude()
*/
NormType magnitude() const NormType magnitude() const
{ {
return sqrt(static_cast<typename return sqrt(static_cast<typename
SquareRootTraits<SquaredNormType>::SquareRootArgument>(square dMagnitude())); SquareRootTraits<SquaredNormType>::SquareRootArgument>(square dMagnitude()));
} }
/** Calculate squared magnitude. /** Calculate squared magnitude (i.e. sum of squared elements).
*/ */
SquaredNormType squaredMagnitude() const SquaredNormType squaredMagnitude() const
{ {
return Loop::squaredNorm(data_); return Loop::squaredNorm(data_);
} }
/** Return the minimal element. /** Return the minimal element.
*/ */
VALUETYPE const & minimum() const VALUETYPE const & minimum() const
{ {
return Loop::minimum(data_); return Loop::minimum(data_);
} }
/** Return the maximal element. /** Return the maximal element.
*/ */
VALUETYPE const & maximum() const VALUETYPE const & maximum() const
{ {
return Loop::maximum(data_); return Loop::maximum(data_);
} }
/** Check that all elements of this vector are non-zero (or 'true'
if T is bool).
*/
bool all() const
{
return Loop::all(data_, VALUETYPE());
}
/** Check that at least one element of this vector is non-zero (or
'true' if T is bool).
*/
bool any() const
{
return Loop::any(data_, VALUETYPE());
}
/** Access component by index. /** Access component by index.
*/ */
reference operator[](difference_type i) reference operator[](difference_type i)
{ {
VIGRA_ASSERT_INSIDE(i); VIGRA_ASSERT_INSIDE(i);
return data_[i]; return data_[i];
} }
/** Get component by index. /** Get component by index.
*/ */
skipping to change at line 733 skipping to change at line 870
iterator end() { return data_ + SIZE; } iterator end() { return data_ + SIZE; }
/** Get const random access iterator to begin of vector. /** Get const random access iterator to begin of vector.
*/ */
const_iterator begin() const { return data_; } const_iterator begin() const { return data_; }
/** Get const random access iterator past-the-end of vector. /** Get const random access iterator past-the-end of vector.
*/ */
const_iterator end() const { return data_ + SIZE; } const_iterator end() const { return data_ + SIZE; }
/** Get const random access iterator to begin of vector.
*/
const_iterator cbegin() const { return data_; }
/** Get const random access iterator past-the-end of vector.
*/
const_iterator cend() const { return data_ + SIZE; }
/** Get a view to the subarray with length <tt>(TO-FROM)</tt> start
ing at <tt>FROM</tt>.
The bounds must fullfill <tt>0 <= FROM < TO <= SIZE</tt>, but t
his is only
checked when <tt>VIGRA_CHECK_BOUNDS</tt> is \#define'd.
*/
template <int FROM, int TO>
TinyVectorView<VALUETYPE, TO-FROM> subarray() const
{
#ifdef VIGRA_CHECK_BOUNDS
vigra_precondition(FROM >= 0, "Index out of bounds");
vigra_precondition(FROM < TO, "Index out of bounds");
vigra_precondition(TO <=SIZE, "Index out of bounds");
#endif
return TinyVectorView<VALUETYPE, TO-FROM>(data_+FROM);
}
TinyVector<VALUETYPE, SIZE-1>
dropIndex(int m) const
{
#ifdef VIGRA_CHECK_BOUNDS
vigra_precondition(0 <= m && m < SIZE, "Dimension out of bounds");
#endif
TinyVector<VALUETYPE, SIZE-1> res(SkipInitialization);
for(int k=0; k<m; ++k)
res[k] = data_[k];
for(int k=m; k<SIZE-1; ++k)
res[k] = data_[k+1];
return res;
}
/** Size of TinyVector vector always equals the template parameter SIZE. /** Size of TinyVector vector always equals the template parameter SIZE.
*/ */
size_type size() const { return SIZE; } size_type size() const { return SIZE; }
pointer data() { return data_; } pointer data() { return data_; }
const_pointer data() const { return data_; } const_pointer data() const { return data_; }
reference front()
{
return data_[0];
}
const_reference front() const
{
return data_[0];
}
reference back()
{
return data_[SIZE-1];
}
const_reference back() const
{
return data_[SIZE-1];
}
/** \brief Factory function for a unit vector for dimension \a k.
*/
static TinyVector<VALUETYPE, SIZE> unitVector(int k)
{
VIGRA_ASSERT_INSIDE(k);
TinyVector<VALUETYPE, SIZE> ret;
ret[k] = 1;
return ret;
}
/** \brief Factory function for a linear sequence.
The result will be initialized as <tt>res[k] = start + k*step</
tt>.
*/
static TinyVector<VALUETYPE, SIZE> linearSequence(VALUETYPE start=VALUE
TYPE(), VALUETYPE step=VALUETYPE(1))
{
TinyVector<VALUETYPE, SIZE> ret(SkipInitialization);
for(int k=0; k<SIZE; ++k, start+=step)
ret[k] = start;
return ret;
}
protected: protected:
DATA data_; DATA data_;
}; };
#ifndef DOXYGEN
template <int SIZE, int DESIRED_SIZE>
struct TinyVector_constructor_has_wrong_number_of_arguments
: staticAssert::AssertBool<SIZE == DESIRED_SIZE>
{};
#endif /* DOXYGEN */
/** \brief Class for fixed size vectors. /** \brief Class for fixed size vectors.
\ingroup RangesAndPoints \ingroup RangesAndPoints
This class contains an array of size SIZE of the specified VALUETYPE. This class contains an array of size SIZE of the specified VALUETYPE.
The interface conforms to STL vector, except that there are no function s The interface conforms to STL vector, except that there are no function s
that change the size of a TinyVector. that change the size of a TinyVector.
\ref TinyVectorOperators "Arithmetic operations" \ref TinyVectorOperators "Arithmetic operations"
on TinyVectors are defined as component-wise applications of these on TinyVectors are defined as component-wise applications of these
operations. Addition and subtraction of two TinyVectors operations. Addition and subtraction of two TinyVectors
skipping to change at line 808 skipping to change at line 1033
/** Construction with constant value. /** Construction with constant value.
Initializes all vector elements with the given value. Initializes all vector elements with the given value.
*/ */
explicit TinyVector(value_type const & initial) explicit TinyVector(value_type const & initial)
: BaseType() : BaseType()
{ {
Loop::assignScalar(BaseType::begin(), initial); Loop::assignScalar(BaseType::begin(), initial);
} }
/** Construction from lemon::Invalid.
Initializes all vector elements with -1.
*/
TinyVector(lemon::Invalid const &)
: BaseType()
{
Loop::assignScalar(BaseType::begin(), -1);
}
/** Construction with Diff2D. /** Construction with Diff2D.
Use only when <tt>SIZE == 2</tt>. Use only when <tt>SIZE == 2</tt>.
*/ */
explicit TinyVector(Diff2D const & initial) explicit TinyVector(Diff2D const & initial)
: BaseType() : BaseType()
{ {
BaseType::data_[0] = detail::RequiresExplicitCast<T>::cast(initial. x); BaseType::data_[0] = detail::RequiresExplicitCast<T>::cast(initial. x);
BaseType::data_[1] = detail::RequiresExplicitCast<T>::cast(initial. y); BaseType::data_[1] = detail::RequiresExplicitCast<T>::cast(initial. y);
} }
/** Construction with explicit values. /** Construction with explicit values.
Call only if SIZE == 2 Call only if SIZE == 2
*/ */
TinyVector(value_type const & i1, value_type const & i2) TinyVector(value_type const & i1, value_type const & i2)
: BaseType() : BaseType()
{ {
VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arg uments<SIZE, 2>));
BaseType::data_[0] = i1; BaseType::data_[0] = i1;
BaseType::data_[1] = i2; BaseType::data_[1] = i2;
} }
/** Construction with explicit values. /** Construction with explicit values.
Call only if SIZE == 3 Call only if SIZE == 3
*/ */
TinyVector(value_type const & i1, value_type const & i2, value_type con st & i3) TinyVector(value_type const & i1, value_type const & i2, value_type con st & i3)
: BaseType() : BaseType()
{ {
VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arg uments<SIZE, 3>));
BaseType::data_[0] = i1; BaseType::data_[0] = i1;
BaseType::data_[1] = i2; BaseType::data_[1] = i2;
BaseType::data_[2] = i3; BaseType::data_[2] = i3;
} }
/** Construction with explicit values. /** Construction with explicit values.
Call only if SIZE == 4 Call only if SIZE == 4
*/ */
TinyVector(value_type const & i1, value_type const & i2, TinyVector(value_type const & i1, value_type const & i2,
value_type const & i3, value_type const & i4) value_type const & i3, value_type const & i4)
: BaseType() : BaseType()
{ {
VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arg uments<SIZE, 4>));
BaseType::data_[0] = i1; BaseType::data_[0] = i1;
BaseType::data_[1] = i2; BaseType::data_[1] = i2;
BaseType::data_[2] = i3; BaseType::data_[2] = i3;
BaseType::data_[3] = i4; BaseType::data_[3] = i4;
} }
/** Construction with explicit values. /** Construction with explicit values.
Call only if SIZE == 5 Call only if SIZE == 5
*/ */
TinyVector(value_type const & i1, value_type const & i2, TinyVector(value_type const & i1, value_type const & i2,
value_type const & i3, value_type const & i4, value_type const & i3, value_type const & i4,
value_type const & i5) value_type const & i5)
: BaseType() : BaseType()
{ {
VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arg uments<SIZE, 5>));
BaseType::data_[0] = i1; BaseType::data_[0] = i1;
BaseType::data_[1] = i2; BaseType::data_[1] = i2;
BaseType::data_[2] = i3; BaseType::data_[2] = i3;
BaseType::data_[3] = i4; BaseType::data_[3] = i4;
BaseType::data_[4] = i5; BaseType::data_[4] = i5;
} }
/** Default constructor (initializes all elements with zero). /** Default constructor (initializes all elements with zero).
*/ */
TinyVector() TinyVector()
: BaseType() : BaseType()
{ {
Loop::assignScalar(BaseType::data_, NumericTraits<value_type>::zero ()); Loop::assignScalar(BaseType::data_, value_type());
} }
/** Construct without initializing the vector elements. /** Construct without initializing the vector elements.
*/ */
explicit TinyVector(SkipInitializationTag) explicit TinyVector(SkipInitializationTag)
: BaseType() : BaseType()
{} {}
explicit TinyVector(detail::DontInit) explicit TinyVector(detail::DontInit)
: BaseType() : BaseType()
skipping to change at line 896 skipping to change at line 1135
/** Copy constructor. /** Copy constructor.
*/ */
TinyVector(TinyVector const & r) TinyVector(TinyVector const & r)
: BaseType() : BaseType()
{ {
Loop::assign(BaseType::data_, r.data_); Loop::assign(BaseType::data_, r.data_);
} }
/** Constructor from C array. /** Constructor from C array.
*/ */
explicit TinyVector(const_pointer data) template <class U>
explicit TinyVector(U const * data)
: BaseType() : BaseType()
{ {
Loop::assign(BaseType::data_, data); Loop::assign(BaseType::data_, data);
} }
/** Constructor by reverse copy from C array. /** Constructor by reverse copy from C array.
Usage: Usage:
\code \code
TinyVector<int, 3> v(1,2,3); TinyVector<int, 3> v(1,2,3);
TinyVector<int, 3> reverse(v.begin(), TinyVector<int, 3>::Rever seCopy); TinyVector<int, 3> reversed(v.begin(), TinyVector<int, 3>::Reve rseCopy);
\endcode \endcode
*/ */
explicit TinyVector(const_pointer data, ReverseCopyTag) explicit TinyVector(const_pointer data, ReverseCopyTag)
: BaseType() : BaseType()
{ {
Loop::reverseAssign(BaseType::data_, data+SIZE-1); Loop::reverseAssign(BaseType::data_, data+SIZE-1);
} }
/** Copy with type conversion. /** Copy with type conversion.
*/ */
skipping to change at line 1117 skipping to change at line 1357
/// component-wise not equal /// component-wise not equal
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4> template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
inline bool inline bool
operator!=(TinyVectorBase<V1, SIZE, D1, D2> const & l, operator!=(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r) TinyVectorBase<V2, SIZE, D3, D4> const & r)
{ {
typedef typename detail::LoopType<SIZE>::type ltype; typedef typename detail::LoopType<SIZE>::type ltype;
return ltype::notEqual(l.begin(), r.begin()); return ltype::notEqual(l.begin(), r.begin());
} }
/// component-wise lexicographical comparison /// lexicographical comparison
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4> template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
inline bool inline bool
operator<(TinyVectorBase<V1, SIZE, D1, D2> const & l, operator<(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r) TinyVectorBase<V2, SIZE, D3, D4> const & r)
{ {
typedef typename detail::LoopType<SIZE>::type ltype; typedef typename detail::LoopType<SIZE>::type ltype;
return ltype::less(l.begin(), r.begin()); return ltype::lexicographicLessThan(l.begin(), r.begin());
}
/// pointwise less-than
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline bool
allLess(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
for(int k=0; k < SIZE; ++k)
if (l[k] >= r[k])
return false;
return true;
}
/// pointwise greater-than
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline bool
allGreater(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
for(int k=0; k < SIZE; ++k)
if(l[k] <= r[k])
return false;
return true;
}
/// pointwise less-equal
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline bool
allLessEqual(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
for(int k=0; k < SIZE; ++k)
if (l[k] > r[k])
return false;
return true;
}
/// pointwise greater-equal
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline bool
allGreaterEqual(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
for(int k=0; k < SIZE; ++k)
if (l[k] < r[k])
return false;
return true;
}
template <class V, int SIZE, class D1, class D2, class D3, class D4>
bool
closeAtTolerance(TinyVectorBase<V, SIZE, D1, D2> const & l,
TinyVectorBase<V, SIZE, D3, D4> const & r,
V epsilon = NumericTraits<V>::epsilon())
{
typedef typename detail::LoopType<SIZE>::type ltype;
return ltype::closeAtTolerance(l.begin(), r.begin(), epsilon);
}
template <class V, int SIZE>
bool
closeAtTolerance(TinyVector<V, SIZE> const & l,
TinyVector<V, SIZE> const & r,
V epsilon = NumericTraits<V>::epsilon())
{
typedef typename detail::LoopType<SIZE>::type ltype;
return ltype::closeAtTolerance(l.begin(), r.begin(), epsilon);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* TinyVector Output */ /* TinyVector Output */
/* */ /* */
/********************************************************/ /********************************************************/
/// stream output /// stream output
template <class V1, int SIZE, class DATA, class DERIVED> template <class V1, int SIZE, class DATA, class DERIVED>
skipping to change at line 1527 skipping to change at line 1835
/// component-wise division /// component-wise division
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4> template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
inline inline
typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2, SIZE> >::Promot e typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2, SIZE> >::Promot e
operator/(TinyVectorBase<V1, SIZE, D1, D2> const & l, operator/(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r) TinyVectorBase<V2, SIZE, D3, D4> const & r)
{ {
return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZ E> >::Promote(l) /= r; return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZ E> >::Promote(l) /= r;
} }
/// component-wise modulo
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline
typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2, SIZE> >::Promot
e
operator%(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZ
E> >::Promote(l) %= r;
}
/// component-wise left scalar addition
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator+(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
{
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(r) +=
v;
}
/// component-wise right scalar addition
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator+(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
{
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) +=
v;
}
/// component-wise left scalar subtraction
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator-(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
{
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(v) -=
r;
}
/// component-wise right scalar subtraction
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator-(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
{
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) -=
v;
}
/// component-wise left scalar multiplication /// component-wise left scalar multiplication
template <class V, int SIZE, class D1, class D2> template <class V, int SIZE, class D1, class D2>
inline inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator*(double v, TinyVectorBase<V, SIZE, D1, D2> const & r) operator*(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
{ {
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(r) *= v; return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(r) *= v;
} }
/// component-wise right scalar multiplication /// component-wise right scalar multiplication
template <class V, int SIZE, class D1, class D2> template <class V, int SIZE, class D1, class D2>
inline inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator*(TinyVectorBase<V, SIZE, D1, D2> const & l, double v) operator*(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
{ {
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) *= v; return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) *= v;
} }
/// component-wise scalar division /// component-wise left scalar division
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator/(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
{
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(v) /=
r;
}
/// component-wise right scalar division
template <class V, int SIZE, class D1, class D2> template <class V, int SIZE, class D1, class D2>
inline inline
typename NumericTraits<TinyVector<V, SIZE> >::RealPromote typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
operator/(TinyVectorBase<V, SIZE, D1, D2> const & l, double v) operator/(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
{ {
return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) /= v; return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) /= v;
} }
/// component-wise scalar division without type promotion /// component-wise scalar division without type promotion
template <class V, int SIZE, class D1, class D2> template <class V, int SIZE, class D1, class D2>
skipping to change at line 1617 skipping to change at line 1980
inline inline
TinyVector<V, SIZE> TinyVector<V, SIZE>
floor(TinyVectorBase<V, SIZE, D1, D2> const & v) floor(TinyVectorBase<V, SIZE, D1, D2> const & v)
{ {
TinyVector<V, SIZE> res(detail::dontInit()); TinyVector<V, SIZE> res(detail::dontInit());
typedef typename detail::LoopType<SIZE>::type ltype; typedef typename detail::LoopType<SIZE>::type ltype;
ltype::floor(res.begin(), v.begin()); ltype::floor(res.begin(), v.begin());
return res; return res;
} }
/** Apply round() function to each vector component.
*/
template <class V, int SIZE, class D1, class D2>
inline
TinyVector<V, SIZE>
round(TinyVectorBase<V, SIZE, D1, D2> const & v)
{
TinyVector<V, SIZE> res(detail::dontInit());
typedef typename detail::LoopType<SIZE>::type ltype;
ltype::round(res.begin(), v.begin());
return res;
}
/** Apply roundi() function to each vector component, i.e. return an in
teger vector.
*/
template <class V, int SIZE, class D1, class D2>
inline
TinyVector<std::ptrdiff_t, SIZE>
roundi(TinyVectorBase<V, SIZE, D1, D2> const & v)
{
TinyVector<V, SIZE> res(detail::dontInit());
for(int k=0; k<SIZE; ++k)
res[k] = roundi(v[k]);
return res;
}
/** Apply sqrt() function to each vector component. /** Apply sqrt() function to each vector component.
*/ */
template <class V, int SIZE, class D1, class D2> template <class V, int SIZE, class D1, class D2>
inline inline
TinyVector<V, SIZE> TinyVector<V, SIZE>
sqrt(TinyVectorBase<V, SIZE, D1, D2> const & v) sqrt(TinyVectorBase<V, SIZE, D1, D2> const & v)
{ {
TinyVector<V, SIZE> res(detail::dontInit()); TinyVector<V, SIZE> res(detail::dontInit());
typedef typename detail::LoopType<SIZE>::type ltype; typedef typename detail::LoopType<SIZE>::type ltype;
ltype::sqrt(res.begin(), v.begin()); ltype::sqrt(res.begin(), v.begin());
skipping to change at line 1833 skipping to change at line 2222
} }
/// squared norm /// squared norm
template <class V, int SIZE> template <class V, int SIZE>
inline inline
typename TinyVector<V, SIZE>::SquaredNormType typename TinyVector<V, SIZE>::SquaredNormType
squaredNorm(TinyVector<V, SIZE> const & t) squaredNorm(TinyVector<V, SIZE> const & t)
{ {
return t.squaredMagnitude(); return t.squaredMagnitude();
} }
using std::reverse;
/// reversed copy
template <class V, int SIZE>
inline
TinyVector<V, SIZE>
reverse(TinyVector<V, SIZE> const & t)
{
return TinyVector<V, SIZE>(t.begin(), TinyVector<V, SIZE>::ReverseCopy)
;
}
/** \brief transposed copy
Elements are arranged such that <tt>res[k] = t[permutation[k]]</tt>
.
*/
template <class V, int SIZE, class T>
inline
TinyVector<V, SIZE>
transpose(TinyVector<V, SIZE> const & t, TinyVector<T, SIZE> const & permut
ation)
{
TinyVector<V, SIZE> res(SkipInitialization);
for(int k=0; k<SIZE; ++k)
{
VIGRA_ASSERT_INSIDE(permutation[k]);
res[k] = t[permutation[k]];
}
return res;
}
/** \brief Clip negative values.
All elements smaller than 0 are set to zero.
*/
template<class V,int SIZE>
inline
TinyVector<V, SIZE> clipLower(TinyVector<V, SIZE> const & t){
return clipLower(t, V(0));
}
/** \brief Clip values below a threshold.
All elements smaller than \a val are set to \a val.
*/
template<class V,int SIZE>
inline
TinyVector<V, SIZE> clipLower(TinyVector<V, SIZE> const & t,const V val){
TinyVector<V, SIZE> res(SkipInitialization);
for(int k=0; k<SIZE; ++k){
res[k]=t[k]< val ? val : t[k];
}
return res;
}
/** \brief Clip values above a threshold.
All elements bigger than \a val are set to \a val.
*/
template<class V,int SIZE>
inline
TinyVector<V, SIZE> clipUpper(TinyVector<V, SIZE> const & t,const V val){
TinyVector<V, SIZE> res(SkipInitialization);
for(int k=0; k<SIZE; ++k){
res[k]=t[k]> val ? val : t[k];
}
return res;
}
/** \brief Clip values to an interval.
All elements less than \a valLower are set to \a valLower, all elem
ents
bigger than \a valUpper are set to \a valUpper.
*/
template<class V,int SIZE>
inline
TinyVector<V, SIZE> clip(TinyVector<V, SIZE> const & t,const V valLower, co
nst V valUpper){
TinyVector<V, SIZE> res(SkipInitialization);
for(int k=0; k<SIZE; ++k){
res[k] = (t[k] < valLower)
? valLower
: (t[k] > valUpper)
? valUpper
: t[k];
}
return res;
}
/** \brief Clip values to a vector of intervals.
All elements less than \a valLower are set to \a valLower, all elem
ents
bigger than \a valUpper are set to \a valUpper.
*/
template<class V,int SIZE>
inline
TinyVector<V, SIZE> clip(TinyVector<V, SIZE> const & t,
TinyVector<V, SIZE> const & valLower,
TinyVector<V, SIZE> const & valUpper)
{
TinyVector<V, SIZE> res(SkipInitialization);
for(int k=0; k<SIZE; ++k){
res[k] = (t[k] < valLower[k])
? valLower[k]
: (t[k] > valUpper[k])
? valUpper[k]
: t[k];
}
return res;
}
template<class V,int SIZE>
inline
bool isZero(TinyVector<V, SIZE> const & t){
for(int k=0; k<SIZE; ++k){
if(t[k]!=static_cast<V>(0))
return false;
}
return true;
}
template<class V,int SIZE>
inline typename NumericTraits<V>::RealPromote
mean(TinyVector<V, SIZE> const & t){
const V sumVal = sum(t);
return static_cast< typename NumericTraits<V>::RealPromote>(sumVal)/SIZ
E;
}
template<class V,int SIZE>
inline typename NumericTraits<V>::RealPromote
sizeDividedSquaredNorm(TinyVector<V, SIZE> const & t){
return squaredNorm(t)/SIZE;
}
template<class V,int SIZE>
inline typename NumericTraits<V>::RealPromote
sizeDividedNorm(TinyVector<V, SIZE> const & t){
return norm(t)/SIZE;
}
//@} //@}
// mask cl.exe shortcomings [end] // mask cl.exe shortcomings [end]
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning( pop ) #pragma warning( pop )
#endif #endif
} // namespace vigra } // namespace vigra
#undef VIGRA_ASSERT_INSIDE #undef VIGRA_ASSERT_INSIDE
#endif // VIGRA_TINYVECTOR_HXX #endif // VIGRA_TINYVECTOR_HXX
 End of changes. 46 change blocks. 
24 lines changed or deleted 582 lines changed or added


 transformimage.hxx   transformimage.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_TRANSFORMIMAGE_HXX #ifndef VIGRA_TRANSFORMIMAGE_HXX
#define VIGRA_TRANSFORMIMAGE_HXX #define VIGRA_TRANSFORMIMAGE_HXX
#include "utilities.hxx" #include "utilities.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "iteratortraits.hxx" #include "iteratortraits.hxx"
#include "rgbvalue.hxx" #include "rgbvalue.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include "inspectimage.hxx" #include "inspectimage.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
/** \addtogroup TransformAlgo Algorithms to Transform Images /** \addtogroup TransformAlgo Algorithms to Transform Images
Apply functor to calculate a pixelwise transformation of one image Apply functor to calculate a pixelwise transformation of one image
@{ @{
*/ */
/********************************************************/ /********************************************************/
skipping to change at line 96 skipping to change at line 97
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* transformImage */ /* transformImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply unary point transformation to each pixel. /** \brief Apply unary point transformation to each pixel.
After the introduction of arithmetic and algebraic \ref MultiMathModule
"array experessions",
this function is rarely needed. Moreover, \ref transformMultiArray() pr
ovides the
same functionality for arbitrary dimensional arrays.
The transformation given by the functor is applied to every source The transformation given by the functor is applied to every source
pixel and the result written into the corresponding destination pixel. pixel and the result written into the corresponding destination pixel.
The function uses accessors to access the pixel data.
Note that the unary functors of the STL can be used in addition to Note that the unary functors of the STL can be used in addition to
the functors specifically defined in \ref TransformFunctor. the functors specifically defined in \ref TransformFunctor.
Creation of new functors is easiest by using \ref FunctorExpressions. Creation of new functors is easiest by using \ref FunctorExpressions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2, class Functor>
void
transformImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{transformImage}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functo r> class DestImageIterator, class DestAccessor, class Functo r>
void void
transformImage(SrcImageIterator src_upperleft, transformImage(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
Functor const & f) Functor const & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functo r> class DestImageIterator, class DestAccessor, class Functo r>
void void
transformImage(triple<SrcImageIterator, SrcImageIterator, SrcAccess or> src, transformImage(triple<SrcImageIterator, SrcImageIterator, SrcAccess or> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <cmath> // for sqrt()
MultiArray<2, float> src(100, 200),
dest(100, 200);
...
transformImage(src, dest, &std::sqrt );
\endcode
\deprecatedUsage{transformImage}
\code
#include <cmath> // for sqrt() #include <cmath> // for sqrt()
FImage src(100, 200),
dest(100, 200);
vigra::transformImage(srcImageRange(src), vigra::transformImage(srcImageRange(src),
destImage(dest), destImage(dest),
(double(*)(double))&std::sqrt ); (double(*)(double))&std::sqrt );
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
SrcImageIterator::row_iterator sx = src_upperleft.rowIterator(); SrcImageIterator::row_iterator sx = src_upperleft.rowIterator();
DestImageIterator::row_iterator dx = dest_upperleft.rowIterator(); DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
Functor functor; Functor functor;
dest_accessor.set(functor(src_accessor(sx)), dx); dest_accessor.set(functor(src_accessor(sx)), dx);
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void transformImage) doxygen_overloaded_function(template <...> void transformImage)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functor> class DestImageIterator, class DestAccessor, class Functor>
void void
transformImage(SrcImageIterator src_upperleft, transformImage(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
Functor const & f) Functor const & f)
skipping to change at line 185 skipping to change at line 213
for(; src_upperleft.y < src_lowerright.y; ++src_upperleft.y, ++dest_upp erleft.y) for(; src_upperleft.y < src_lowerright.y; ++src_upperleft.y, ++dest_upp erleft.y)
{ {
transformLine(src_upperleft.rowIterator(), transformLine(src_upperleft.rowIterator(),
src_upperleft.rowIterator() + w, sa, src_upperleft.rowIterator() + w, sa,
dest_upperleft.rowIterator(), da, f); dest_upperleft.rowIterator(), da, f);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functor> class DestImageIterator, class DestAccessor, class Functor>
inline inline void
void
transformImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, transformImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
{ {
transformImage(src.first, src.second, src.third, transformImage(src.first, src.second, src.third,
dest.first, dest.second, f); dest.first, dest.second, f);
} }
template <class T1, class S1,
class T2, class S2, class Functor>
inline void
transformImage(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Functor const & f)
{
vigra_precondition(src.shape() == dest.shape(),
"transformImage(): shape mismatch between input and output.");
transformImage(srcImageRange(src),
destImage(dest), f);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* transformImageIf */ /* transformImageIf */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Apply unary point transformation to each pixel within the ROI /** \brief Apply unary point transformation to each pixel within the ROI
(i.e., where the mask is non-zero). (i.e., where the mask is non-zero).
After the introduction of arithmetic and algebraic \ref MultiMathModule
"array experessions",
this function is rarely needed. Moreover, \ref combineTwoMultiArrays()
provides the
same functionality for arbitrary dimensional arrays.
The transformation given by the functor is applied to every source The transformation given by the functor is applied to every source
pixel in the ROI (i.e. when the return value of the mask's accessor pixel in the ROI (i.e. when the return value of the mask's accessor
is not zero) is not zero)
and the result is written into the corresponding destination pixel. and the result is written into the corresponding destination pixel.
The function uses accessors to access the pixel data. The function uses accessors to access the pixel data.
Note that the unary functors of the STL can be used in addition to Note that the unary functors of the STL can be used in addition to
the functors specifically defined in \ref TransformFunctor. the functors specifically defined in \ref TransformFunctor.
Creation of new functors is easiest by using \ref FunctorExpressions. Creation of new functors is easiest by using \ref FunctorExpressions.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class TM, class SM,
class T2, class S2,
class Functor>
void
transformImageIf(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
Functor const & f);
}
\endcode
\deprecatedAPI{transformImageIf}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, clas DestAccessor, class DestImageIterator, clas DestAccessor,
class Functor> class Functor>
void void
transformImageIf(SrcImageIterator src_upperleft, transformImageIf(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
MaskImageIterator mask_upperleft, MaskAccessor ma, MaskImageIterator mask_upperleft, MaskAccessor ma,
DestImageIterator dest_upperleft, DestAccessor da, DestImageIterator dest_upperleft, DestAccessor da,
Functor const & f) Functor const & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, clas DestAccessor, class DestImageIterator, clas DestAccessor,
class Functor> class Functor>
void void
transformImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAcce ssor> src, transformImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAcce ssor> src,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <cmath> // for sqrt() #include <cmath> // for sqrt()
MultiArray<2, unsigned char> mask(100, 200),
MultiArray<2, float> src(100, 200),
dest(100, 200);
... // fill src and mask
transformImageIf(src, mask, dest, &std::sqrt );
\endcode
\deprecatedUsage{transformImageIf}
\code
#include <cmath> // for sqrt()
vigra::transformImageIf(srcImageRange(src), vigra::transformImageIf(srcImageRange(src),
maskImage(mask), maskImage(mask),
destImage(dest), destImage(dest),
(double(*)(double))&std::sqrt ); (double(*)(double))&std::sqrt );
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcImageIterator src_upperleft, src_lowerright;
DestImageIterator dest_upperleft; DestImageIterator dest_upperleft;
MaskImageIterator mask_upperleft; MaskImageIterator mask_upperleft;
SrcImageIterator::row_iterator sx = src_upperleft.rowIterator(); SrcImageIterator::row_iterator sx = src_upperleft.rowIterator();
MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator(); MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
DestImageIterator::row_iterator dx = dest_upperleft.rowIterator(); DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
MaskAccessor mask_accessor; MaskAccessor mask_accessor;
Functor functor; Functor functor;
if(mask_accessor(mx)) if(mask_accessor(mx))
dest_accessor.set(functor(src_accessor(sx)), dx); dest_accessor.set(functor(src_accessor(sx)), dx);
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void transformImageIf) doxygen_overloaded_function(template <...> void transformImageIf)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
void void
transformImageIf(SrcImageIterator src_upperleft, transformImageIf(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
skipping to change at line 311 skipping to change at line 383
src_upperleft.rowIterator() + w, sa, src_upperleft.rowIterator() + w, sa,
mask_upperleft.rowIterator(), ma, mask_upperleft.rowIterator(), ma,
dest_upperleft.rowIterator(), da, f); dest_upperleft.rowIterator(), da, f);
} }
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class MaskImageIterator, class MaskAccessor, class MaskImageIterator, class MaskAccessor,
class DestImageIterator, class DestAccessor, class DestImageIterator, class DestAccessor,
class Functor> class Functor>
inline inline void
void
transformImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr c, transformImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> sr c,
pair<MaskImageIterator, MaskAccessor> mask, pair<MaskImageIterator, MaskAccessor> mask,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
Functor const & f) Functor const & f)
{ {
transformImageIf(src.first, src.second, src.third, transformImageIf(src.first, src.second, src.third,
mask.first, mask.second, mask.first, mask.second,
dest.first, dest.second, f); dest.first, dest.second, f);
} }
template <class T1, class S1,
class TM, class SM,
class T2, class S2,
class Functor>
inline void
transformImageIf(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, TM, SM> const & mask,
MultiArrayView<2, T2, S2> dest,
Functor const & f)
{
vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.s
hape(),
"transformImageIf(): shape mismatch between input and output.");
transformImageIf(srcImageRange(src),
maskImage(mask),
destImage(dest), f);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* gradientBasedTransform */ /* gradientBasedTransform */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate a function of the image gradient. /** \brief Calculate a function of the image gradient.
The gradient and the function represented by <TT>Functor f</TT> The gradient and the function represented by <TT>Functor f</TT>
are calculated in one go: for each location, the symmetric are calculated in one go: for each location, the symmetric
difference in x- and y-directions (asymmetric difference at the difference in x- and y-directions (asymmetric difference at the
image borders) are passed to the given functor, and the result is image borders) are passed to the given functor, and the result is
written the destination image. Functors to be used with this written to the destination image. Functors to be used with this
function include \ref MagnitudeFunctor and \ref function include \ref MagnitudeFunctor and \ref
RGBGradientMagnitudeFunctor. RGBGradientMagnitudeFunctor.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Functor>
void
gradientBasedTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Functor const & grad);
}
\endcode
\deprecatedAPI{gradientBasedTransform}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functo r> class DestImageIterator, class DestAccessor, class Functo r>
void void
gradientBasedTransform(SrcImageIterator srcul, SrcImageIterator src lr, SrcAccessor sa, gradientBasedTransform(SrcImageIterator srcul, SrcImageIterator src lr, SrcAccessor sa,
DestImageIterator destul, DestAccessor da, F unctor const & f) DestImageIterator destul, DestAccessor da, F unctor const & f)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functo r> class DestImageIterator, class DestAccessor, class Functo r>
void void
gradientBasedTransform(triple<SrcImageIterator, SrcImageIterator, S rcAccessor> src, gradientBasedTransform(triple<SrcImageIterator, SrcImageIterator, S rcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, Functor const & const & f) pair<DestImageIterator, DestAccessor> dest, Functor const & const & f)
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\> <b>\#include</b> \<vigra/transformimage.hxx\><br/>
Namespace: vigra
\code
MultiArray<2, float> src(w,h), magnitude(w,h);
...
gradientBasedTransform(src, magnitude,
MagnitudeFunctor<float>());
\endcode
\deprecatedUsage{gradientBasedTransform}
\code \code
vigra::FImage src(w,h), magnitude(w,h); vigra::FImage src(w,h), magnitude(w,h);
... ...
gradientBasedTransform(srcImageRange(src), destImage(magnitude), gradientBasedTransform(srcImageRange(src), destImage(magnitude),
vigra::MagnitudeFunctor<float>()); vigra::MagnitudeFunctor<float>());
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator is, isend; SrcImageIterator is, isend;
DestImageIterator id; DestImageIterator id;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
typename NumericTraits<typename SrcAccessor::value_type>::RealPromote typename NumericTraits<typename SrcAccessor::value_type>::RealPromote
diffx, diffy; diffx, diffy;
diffx = src_accessor(is, Diff2D(-1,0)) - src_accessor(is, Diff2D(1,0)); diffx = src_accessor(is, Diff2D(-1,0)) - src_accessor(is, Diff2D(1,0));
diffy = src_accessor(is, Diff2D(0,-1)) - src_accessor(is, Diff2D(0,1)); diffy = src_accessor(is, Diff2D(0,-1)) - src_accessor(is, Diff2D(0,1));
Functor f; Functor f;
dest_accessor.set(f(diffx, diffy), id); dest_accessor.set(f(diffx, diffy), id);
\endcode \endcode
\deprecatedEnd
\see TransformFunctor, MultiMathModule, \ref FunctorExpressions
*/ */
doxygen_overloaded_function(template <...> void gradientBasedTransform) doxygen_overloaded_function(template <...> void gradientBasedTransform)
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functor> class DestImageIterator, class DestAccessor, class Functor>
void void
gradientBasedTransform(SrcImageIterator srcul, SrcImageIterator srclr, SrcA ccessor sa, gradientBasedTransform(SrcImageIterator srcul, SrcImageIterator srclr, SrcA ccessor sa,
DestImageIterator destul, DestAccessor da, Functor c onst & grad) DestImageIterator destul, DestAccessor da, Functor c onst & grad)
{ {
int w = srclr.x - srcul.x; int w = srclr.x - srcul.x;
int h = srclr.y - srcul.y; int h = srclr.y - srcul.y;
int x,y; int x,y;
SrcImageIterator sy = srcul; SrcImageIterator sy = srcul;
DestImageIterator dy = destul; DestImageIterator dy = destul;
static const Diff2D left(-1,0); const Diff2D left(-1,0);
static const Diff2D right(1,0); const Diff2D right(1,0);
static const Diff2D top(0,-1); const Diff2D top(0,-1);
static const Diff2D bottom(0,1); const Diff2D bottom(0,1);
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
TmpType diffx, diffy; TmpType diffx, diffy;
SrcImageIterator sx = sy; SrcImageIterator sx = sy;
DestImageIterator dx = dy; DestImageIterator dx = dy;
diffx = sa(sx) - sa(sx, right); diffx = sa(sx) - sa(sx, right);
diffy = sa(sx) - sa(sx, bottom); diffy = sa(sx) - sa(sx, bottom);
da.set(grad(diffx, diffy), dx); da.set(grad(diffx, diffy), dx);
skipping to change at line 483 skipping to change at line 595
da.set(grad(diffx, diffy), dx); da.set(grad(diffx, diffy), dx);
} }
diffx = sa(sx, left) - sa(sx); diffx = sa(sx, left) - sa(sx);
diffy = sa(sx, top) - sa(sx); diffy = sa(sx, top) - sa(sx);
da.set(grad(diffx, diffy), dx); da.set(grad(diffx, diffy), dx);
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor, class Functor> class DestImageIterator, class DestAccessor, class Functor>
inline inline void
void
gradientBasedTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccess or> src, gradientBasedTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccess or> src,
pair<DestImageIterator, DestAccessor> dest, Functor const & grad) pair<DestImageIterator, DestAccessor> dest, Functor const & grad)
{ {
gradientBasedTransform(src.first, src.second, src.third, gradientBasedTransform(src.first, src.second, src.third,
dest.first, dest.second, grad); dest.first, dest.second, grad);
} }
template <class T1, class S1,
class T2, class S2, class Functor>
inline void
gradientBasedTransform(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, Functor const & grad
)
{
vigra_precondition(src.shape() == dest.shape(),
"gradientBasedTransform(): shape mismatch between input and output.
");
gradientBasedTransform(srcImageRange(src),
destImage(dest), grad);
}
/** @} */ /** @} */
/** \addtogroup TransformFunctor Functors to Transform Images /** \addtogroup TransformFunctor Functors to Transform Images
Note that the unary functors of the STL can also be used in Note that the unary functors of the STL can also be used in
connection with \ref transformImage(). connection with \ref transformImage().
*/ */
//@{ //@{
template <class DestValueType, class Multiplier = double> template <class DestValueType, class Multiplier = double>
class LinearIntensityTransform class LinearIntensityTransform
skipping to change at line 641 skipping to change at line 764
linearIntensityTransform(Multiplier scale, DestValueType offset); linearIntensityTransform(Multiplier scale, DestValueType offset);
template <class DestValueType, class Multiplier> template <class DestValueType, class Multiplier>
ScalarIntensityTransform<DestValueType, Multiplier> ScalarIntensityTransform<DestValueType, Multiplier>
linearIntensityTransform(Multiplier scale); linearIntensityTransform(Multiplier scale);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::IImage src(width, height); vigra::IImage src(width, height);
vigra::BImage dest(width, height); vigra::BImage dest(width, height);
... ...
vigra::FindMinMax<IImage::PixelType> minmax; // functor to find range vigra::FindMinMax<IImage::PixelType> minmax; // functor to find range
vigra::inspectImage(srcImageRange(src), minmax); // find original range vigra::inspectImage(srcImageRange(src), minmax); // find original range
// transform to range 0...255 // transform to range 0...255
skipping to change at line 725 skipping to change at line 848
template <class SrcValueType, class DestValueTyp e> template <class SrcValueType, class DestValueTyp e>
LinearIntensityTransform<DestValueType, typename NumericTraits<Dest ValueType>::RealPromote> LinearIntensityTransform<DestValueType, typename NumericTraits<Dest ValueType>::RealPromote>
linearRangeMapping(SrcValueType src_min, SrcValueType src_max, linearRangeMapping(SrcValueType src_min, SrcValueType src_max,
DestValueType dest_min, DestValueType dest_max ) ; DestValueType dest_min, DestValueType dest_max ) ;
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::IImage src(width, height); vigra::IImage src(width, height);
vigra::BImage dest(width, height); vigra::BImage dest(width, height);
... ...
vigra::FindMinMax<IImage::PixelType> minmax; // functor to find range vigra::FindMinMax<IImage::PixelType> minmax; // functor to find range
vigra::inspectImage(srcImageRange(src), minmax); // find original range vigra::inspectImage(srcImageRange(src), minmax); // find original range
// transform to range 0...255 // transform to range 0...255
skipping to change at line 830 skipping to change at line 953
or equal the higher threshold (i.e. within the closed interval or equal the higher threshold (i.e. within the closed interval
[lower, higher]) the destination pixel is set to 'yesresult', [lower, higher]) the destination pixel is set to 'yesresult',
otherwise to 'noresult'. otherwise to 'noresult'.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>) <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(width, height), dest(width, height); vigra::BImage src(width, height), dest(width, height);
... ...
vigra::transformImage(src.upperLeft(), src.lowerRight(), src.accessor() , vigra::transformImage(src.upperLeft(), src.lowerRight(), src.accessor() ,
dest.upperLeft(), dest.accessor(), dest.upperLeft(), dest.accessor(),
vigra::Threshold< vigra::Threshold<
vigra::BImage::PixelType, vigra::BImage::PixelType>(10, 100, 0, 2 55)); vigra::BImage::PixelType, vigra::BImage::PixelType>(10, 100, 0, 2 55));
\endcode \endcode
skipping to change at line 945 skipping to change at line 1068
If the <TT>PixelType</TT> is <TT>unsigned char</TT>, a look-up-table is used If the <TT>PixelType</TT> is <TT>unsigned char</TT>, a look-up-table is used
for faster computation. for faster computation.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>) <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage bimage(width, height); vigra::BImage bimage(width, height);
double brightness, contrast; double brightness, contrast;
... ...
vigra::transformImage(srcImageRange(bimage), destImage(bimage), vigra::transformImage(srcImageRange(bimage), destImage(bimage),
vigra::BrightnessContrastFunctor<unsigned char>(brightness, contrast )); vigra::BrightnessContrastFunctor<unsigned char>(brightness, contrast ));
vigra::FImage fimage(width, height); vigra::FImage fimage(width, height);
... ...
skipping to change at line 1207 skipping to change at line 1330
If the <TT>PixelType</TT> is <TT>unsigned char</TT>, a If the <TT>PixelType</TT> is <TT>unsigned char</TT>, a
look-up-table is used for faster computation. look-up-table is used for faster computation.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>) <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage bimage(width, height); vigra::BImage bimage(width, height);
double gamma; double gamma;
... ...
vigra::transformImage(srcImageRange(bimage), destImage(bimage), vigra::transformImage(srcImageRange(bimage), destImage(bimage),
vigra::GammaFunctor<unsigned char>(gamma)); vigra::GammaFunctor<unsigned char>(gamma));
vigra::FImage fimage(width, height); vigra::FImage fimage(width, height);
... ...
skipping to change at line 1440 skipping to change at line 1563
At least, the vector type is required to have a function At least, the vector type is required to have a function
'<em>result</em><TT> = dot(v,v)</TT>'. '<em>result</em><TT> = dot(v,v)</TT>'.
<b> Traits defined:</b> <b> Traits defined:</b>
<tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>) <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/transformimage.hxx\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::TinyVector<float, 2> Vector; typedef vigra::TinyVector<float, 2> Vector;
vigra::BasicImage<Vector> grad(width, height); vigra::BasicImage<Vector> grad(width, height);
vigra::FImage magn(width,height); vigra::FImage magn(width,height);
... ...
vigra::transformImage(srcImageRange(grad), destImage(magn), vigra::transformImage(srcImageRange(grad), destImage(magn),
VectorNormFunctor<float>() VectorNormFunctor<float>()
); );
\endcode \endcode
 End of changes. 46 change blocks. 
39 lines changed or deleted 169 lines changed or added


 tuple.hxx   tuple.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_TUPLE_HXX #ifndef VIGRA_TUPLE_HXX
#define VIGRA_TUPLE_HXX #define VIGRA_TUPLE_HXX
#include <utility> // for pair #include <utility> // for pair
namespace vigra { namespace vigra {
/*! \page TupleTypes Tuple Types /** \page TupleTypes Tuple Types
pair, triple, tuple4, tuple5 pair, triple, tuple4, tuple5
<b>\#include</b> \<vigra/utilities.hxx\><br> <b>\#include</b> \<vigra/utilities.hxx\><br>
Namespace: vigra Namespace: vigra
VIGRA defines tuple types \p vigra::triple, \p vigra::tuple4, \p vigra: :tuple5. VIGRA defines tuple types \p vigra::triple, \p vigra::tuple4, \p vigra: :tuple5.
In addition, \p std::pair is imported into namespace vigra from the C++ standard In addition, \p std::pair is imported into namespace vigra from the C++ standard
library. All these types are defined similarly: library. All these types are defined similarly:
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 tv_filter.hxx   tv_filter.hxx 
skipping to change at line 56 skipping to change at line 56
#include "multi_math.hxx" #include "multi_math.hxx"
#include "eigensystem.hxx" #include "eigensystem.hxx"
#include "convolution.hxx" #include "convolution.hxx"
#include "fixedpoint.hxx" #include "fixedpoint.hxx"
#include "project2ellipse.hxx" #include "project2ellipse.hxx"
#ifndef VIGRA_MIXED_2ND_DERIVATIVES #ifndef VIGRA_MIXED_2ND_DERIVATIVES
#define VIGRA_MIXED_2ND_DERIVATIVES 1 #define VIGRA_MIXED_2ND_DERIVATIVES 1
#endif #endif
#define setZeroX(A) A.subarray(Shape2(width-1,0),Shape2(width,height))*=0;
#define setZeroY(A) A.subarray(Shape2(0,height-1),Shape2(width,height))*=0;
namespace vigra{ namespace vigra{
/** \addtogroup NonLinearDiffusion /** \addtogroup NonLinearDiffusion
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* totalVariationFilter */ /* totalVariationFilter */
skipping to change at line 140 skipping to change at line 143
totalVariationFilter(data,weight,out,alpha,steps,eps); totalVariationFilter(data,weight,out,alpha,steps,eps);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void totalVariationFilter) doxygen_overloaded_function(template <...> void totalVariationFilter)
template <class stride1,class stride2> template <class stride1,class stride2>
void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayV iew<2,double,stride2> out, double alpha, int steps, double eps=0){ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayV iew<2,double,stride2> out, double alpha, int steps, double eps=0){
using namespace multi_math; using namespace multi_math;
int width=data.shape(0),height=data.shape(1);
MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape()); MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape());
Kernel1D<double> Lx,LTx; Kernel1D<double> Lx,LTx;
Lx.initExplicitly(0,1)=1,-1; // = Right sided finit e differences for d/dx and d/dy Lx.initExplicitly(-1,0)=1,-1; // = Right sided fini te differences for d/dx and d/dy
Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions
LTx.initExplicitly(-1,0)=-1,1; // = Left sided finit e differences for -d/dx and -d/dy LTx.initExplicitly(0,1)=-1,1; // = Left sided finite differences for -d/dx and -d/dy
LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c. LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c.
out=data; out=data;
u_bar=data; u_bar=data;
double tau=1.0 / std::max(alpha,1.) / std::sqrt(8.0) * 0.06; double tau=1.0 / std::max(alpha,1.) / std::sqrt(8.0) * 0.06;
double sigma=1.0 / std::sqrt(8.0) / 0.06; double sigma=1.0 / std::sqrt(8.0) / 0.06;
for (int i=0;i<steps;i++){ for (int i=0;i<steps;i++){
separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroX(temp1);
vx+=(sigma*temp1); vx+=(sigma*temp1);
separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroY(temp1);
vy+=(sigma*temp1); vy+=(sigma*temp1);
//project to constraint set //project to constraint set
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
double l=hypot(vx(x,y),vy(x,y)); double l=hypot(vx(x,y),vy(x,y));
if (l>1){ if (l>1){
vx(x,y)/=l; vx(x,y)/=l;
vy(x,y)/=l; vy(x,y)/=l;
} }
skipping to change at line 180 skipping to change at line 184
} }
separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx)); separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx)); separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
u_bar=out; u_bar=out;
out-=tau*(out-data+alpha*(temp1+temp2)); out-=tau*(out-data+alpha*(temp1+temp2));
u_bar=2*out-u_bar; //cf. Chambolle/Pock and Popov's algorithm u_bar=2*out-u_bar; //cf. Chambolle/Pock and Popov's algorithm
//stopping criterion //stopping criterion
if (eps>0){ if (eps>0){
separableConvolveX(srcImageRange(out),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(out),destImage(temp1),kernel1d(Lx));
separableConvolveY(srcImageRange(out),destImage(temp2),kernel1d(Lx)); setZeroX(temp1);
separableConvolveY(srcImageRange(out),destImage(temp2),kernel1d(Lx));
setZeroY(temp2);
double f_primal=0,f_dual=0; double f_primal=0,f_dual=0;
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
f_primal+=.5*(out(x,y)-data(x,y))*(out(x,y)-data(x,y))+alpha*hypo t(temp1(x,y),temp2(x,y)); f_primal+=.5*(out(x,y)-data(x,y))*(out(x,y)-data(x,y))+alpha*hypo t(temp1(x,y),temp2(x,y));
} }
} }
separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx)); separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx)); separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
skipping to change at line 208 skipping to change at line 212
break; break;
} }
} }
} }
} }
template <class stride1,class stride2, class stride3> template <class stride1,class stride2, class stride3>
void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayV iew<2,double,stride2> weight, MultiArrayView<2,double,stride3> out,double a lpha, int steps, double eps=0){ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayV iew<2,double,stride2> weight, MultiArrayView<2,double,stride3> out,double a lpha, int steps, double eps=0){
using namespace multi_math; using namespace multi_math;
int width=data.shape(0),height=data.shape(1);
MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape()); MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape());
Kernel1D<double> Lx,LTx; Kernel1D<double> Lx,LTx;
Lx.initExplicitly(0,1)=1,-1; // = Right sided finit e differences for d/dx and d/dy Lx.initExplicitly(-1,0)=1,-1; // = Right sided fini te differences for d/dx and d/dy
Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions
LTx.initExplicitly(-1,0)=-1,1; // = Left sided finit e differences for -d/dx and -d/dy LTx.initExplicitly(0,1)=-1,1; // = Left sided finite differences for -d/dx and -d/dy
LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c. LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c.
out=data; out=data;
u_bar=data; u_bar=data;
double tau=1.0 / std::max(alpha,1.) / std::sqrt(8.0) * 0.06; double tau=1.0 / std::max(alpha,1.) / std::sqrt(8.0) * 0.06;
double sigma=1.0 / std::sqrt(8.0) / 0.06; double sigma=1.0 / std::sqrt(8.0) / 0.06;
for (int i=0;i<steps;i++){ for (int i=0;i<steps;i++){
separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroX(temp1);
vx+=(sigma*temp1); vx+=(sigma*temp1);
separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroY(temp1);
vy+=(sigma*temp1); vy+=(sigma*temp1);
//project to constraint set //project to constraint set
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
double l=hypot(vx(x,y),vy(x,y)); double l=hypot(vx(x,y),vy(x,y));
if (l>1){ if (l>1){
vx(x,y)/=l; vx(x,y)/=l;
vy(x,y)/=l; vy(x,y)/=l;
} }
skipping to change at line 247 skipping to change at line 252
} }
separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx)); separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx)); separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
u_bar=out; u_bar=out;
out-=tau*(weight*(out-data)+alpha*(temp1+temp2)); out-=tau*(weight*(out-data)+alpha*(temp1+temp2));
u_bar=2*out-u_bar; u_bar=2*out-u_bar;
//stopping criterion //stopping criterion
if (eps>0){ if (eps>0){
separableConvolveX(srcImageRange(out),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(out),destImage(temp1),kernel1d(Lx));
separableConvolveY(srcImageRange(out),destImage(temp2),kernel1d(Lx)); setZeroX(temp1);
separableConvolveY(srcImageRange(out),destImage(temp2),kernel1d(Lx));
setZeroY(temp2);
double f_primal=0,f_dual=0; double f_primal=0,f_dual=0;
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
f_primal+=.5*weight(x,y)*(out(x,y)-data(x,y))*(out(x,y)-data(x,y) )+alpha*hypot(temp1(x,y),temp2(x,y)); f_primal+=.5*weight(x,y)*(out(x,y)-data(x,y))*(out(x,y)-data(x,y) )+alpha*hypot(temp1(x,y),temp2(x,y));
} }
} }
separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx)); separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx)); separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
skipping to change at line 336 skipping to change at line 341
(see \ref anisotropicTotalVariationFilter() and \ref secondOrderTotalVariat ionFilter() for usage in an application). (see \ref anisotropicTotalVariationFilter() and \ref secondOrderTotalVariat ionFilter() for usage in an application).
*/ */
doxygen_overloaded_function(template <...> void getAnisotropy) doxygen_overloaded_function(template <...> void getAnisotropy)
template <class stride1,class stride2,class stride3,class stride4> template <class stride1,class stride2,class stride3,class stride4>
void getAnisotropy(MultiArrayView<2,double,stride1> data,MultiArrayView<2,d ouble,stride2> phi, void getAnisotropy(MultiArrayView<2,double,stride1> data,MultiArrayView<2,d ouble,stride2> phi,
MultiArrayView<2,double,stride3> alpha, MultiArrayView< 2,double,stride4> beta, MultiArrayView<2,double,stride3> alpha, MultiArrayView< 2,double,stride4> beta,
double alpha_par, double beta_par, double sigma_par, do uble rho_par, double K_par){ double alpha_par, double beta_par, double sigma_par, do uble rho_par, double K_par){
using namespace multi_math; using namespace multi_math;
int width=data.shape(0),height=data.shape(1);
MultiArray<2,double> smooth(data.shape()),tmp(data.shape()); MultiArray<2,double> smooth(data.shape()),tmp(data.shape());
vigra::Kernel1D<double> gauss; vigra::Kernel1D<double> gauss;
gauss.initGaussian(sigma_par); gauss.initGaussian(sigma_par);
separableConvolveX(srcImageRange(data), destImage(tmp), kernel1d(gauss)); separableConvolveX(srcImageRange(data), destImage(tmp), kernel1d(gauss));
separableConvolveY(srcImageRange(tmp), destImage(smooth), kernel1d(gauss) ); separableConvolveY(srcImageRange(tmp), destImage(smooth), kernel1d(gauss) );
MultiArray<2,double> stxx(data.shape()),stxy(data.shape()),styy(data.shap e()); MultiArray<2,double> stxx(data.shape()),stxy(data.shape()),styy(data.shap e());
skipping to change at line 464 skipping to change at line 470
*/ */
doxygen_overloaded_function(template <...> void anisotropicTotalVariationF ilter) doxygen_overloaded_function(template <...> void anisotropicTotalVariationF ilter)
template <class stride1,class stride2,class stride3,class stride4,class str ide5,class stride6> template <class stride1,class stride2,class stride3,class stride4,class str ide5,class stride6>
void anisotropicTotalVariationFilter(MultiArrayView<2,double,stride1> data, MultiArrayView<2,double,stride2> weight, void anisotropicTotalVariationFilter(MultiArrayView<2,double,stride1> data, MultiArrayView<2,double,stride2> weight,
MultiArrayView<2,double,stride3> phi,MultiArrayView<2,d ouble,stride4> alpha, MultiArrayView<2,double,stride3> phi,MultiArrayView<2,d ouble,stride4> alpha,
MultiArrayView<2,double,stride5> beta,MultiArrayView<2, double,stride6> out, MultiArrayView<2,double,stride5> beta,MultiArrayView<2, double,stride6> out,
int steps){ int steps){
using namespace multi_math; using namespace multi_math;
int width=data.shape(0),height=data.shape(1);
MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape()); MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape());
MultiArray<2,double> rx(data.shape()),ry(data.shape()); MultiArray<2,double> rx(data.shape()),ry(data.shape());
Kernel1D<double> Lx,LTx; Kernel1D<double> Lx,LTx;
Lx.initExplicitly(0,1)=1,-1; // = Right sided finit e differences for d/dx and d/dy Lx.initExplicitly(-1,0)=1,-1; // = Right sided fini te differences for d/dx and d/dy
Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions
LTx.initExplicitly(-1,0)=-1,1; // = Left sided finit e differences for -d/dx and -d/dy LTx.initExplicitly(0,1)=-1,1; // = Left sided finite differences for -d/dx and -d/dy
LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c. LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c.
u_bar=out; u_bar=out;
double m=0; double m=0;
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
m=std::max(m,alpha(x,y)); m=std::max(m,alpha(x,y));
m=std::max(m,beta (x,y)); m=std::max(m,beta (x,y));
} }
} }
m=std::max(m,1.); m=std::max(m,1.);
double tau=.9/m/std::sqrt(8.)*0.06; double tau=.9/m/std::sqrt(8.)*0.06;
double sigma=.9/m/std::sqrt(8.)/0.06; double sigma=.9/m/std::sqrt(8.)/0.06;
for (int i=0;i<steps;i++){ for (int i=0;i<steps;i++){
separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroX(temp1);
vx+=(sigma*temp1); vx+=(sigma*temp1);
separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroY(temp1);
vy+=(sigma*temp1); vy+=(sigma*temp1);
//project to constraint set //project to constraint set
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
double e1,e2,skp1,skp2; double e1,e2,skp1,skp2;
e1=std::cos(phi(x,y)); e1=std::cos(phi(x,y));
e2=std::sin(phi(x,y)); e2=std::sin(phi(x,y));
skp1=vx(x,y)*e1+vy(x,y)*e2; skp1=vx(x,y)*e1+vy(x,y)*e2;
skipping to change at line 613 skipping to change at line 620
[1] Frank Lenzen, Florian Becker, Jan Lellmann, Stefania Petra and Christop h Schn&ouml;rr, A Class of Quasi-Variational Inequalities for Adaptive Imag e Denoising and Decomposition, Computational Optimization and Applications, Springer, 2012. [1] Frank Lenzen, Florian Becker, Jan Lellmann, Stefania Petra and Christop h Schn&ouml;rr, A Class of Quasi-Variational Inequalities for Adaptive Imag e Denoising and Decomposition, Computational Optimization and Applications, Springer, 2012.
*/ */
doxygen_overloaded_function(template <...> void secondOrderTotalVariationFi lter) doxygen_overloaded_function(template <...> void secondOrderTotalVariationFi lter)
template <class stride1,class stride2,class stride3,class stride4,class str ide5,class stride6,class stride7,class stride8,class stride9> template <class stride1,class stride2,class stride3,class stride4,class str ide5,class stride6,class stride7,class stride8,class stride9>
void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data, void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data,
MultiArrayView<2,double,stride2> weight,MultiAr rayView<2,double,stride3> phi, MultiArrayView<2,double,stride2> weight,MultiAr rayView<2,double,stride3> phi,
MultiArrayView<2,double,stride4> alpha,MultiArr ayView<2,double,stride5> beta, MultiArrayView<2,double,stride4> alpha,MultiArr ayView<2,double,stride5> beta,
MultiArrayView<2,double,stride6> gamma, MultiArrayView<2,double,stride6> gamma,
MultiArrayView<2,double,stride7> xedges,MultiAr rayView<2,double,stride8> yedges, MultiArrayView<2,double,stride7> xedges,MultiAr rayView<2,double,stride8> yedges,
MultiArrayView<2,double,stride9> out, MultiArrayView<2,double,stride9> out,
int steps){ int steps){
using namespace multi_math; using namespace multi_math;
int width=data.shape(0),height=data.shape(1);
MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape()); MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shap e()),vy(data.shape()),u_bar(data.shape());
MultiArray<2,double> rx(data.shape()),ry(data.shape()); MultiArray<2,double> rx(data.shape()),ry(data.shape());
MultiArray<2,double> wx(data.shape()),wy(data.shape()),wz(data.shape()); MultiArray<2,double> wx(data.shape()),wy(data.shape()),wz(data.shape());
Kernel1D<double> Lx,LTx; Kernel1D<double> Lx,LTx;
Lx.initExplicitly(0,1)=1,-1; // = Right sided finit e differences for d/dx and d/dy Lx.initExplicitly(-1,0)=1,-1; // = Right sided fini te differences for d/dx and d/dy
Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT); // with hom. Neumann boundary conditions
LTx.initExplicitly(-1,0)=-1,1; // = Left sided finit e differences for -d/dx and -d/dy LTx.initExplicitly(0,1)=-1,1; // = Left sided finite differences for -d/dx and -d/dy
LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c. LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD); // with hom. Dirichl et b. c.
u_bar=out; u_bar=out;
double m=0; double m=0;
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
m=std::max(m,alpha(x,y)); m=std::max(m,alpha(x,y));
m=std::max(m,beta (x,y)); m=std::max(m,beta (x,y));
m=std::max(m,gamma(x,y));
} }
} }
m=std::max(m,1.); m=std::max(m,1.);
double tau=.1/m;//std::sqrt(8)*0.06; double tau=.1/m;//std::sqrt(8)*0.06;
double sigma=.1;//m;/std::sqrt(8)/0.06; double sigma=.1;//m;/std::sqrt(8)/0.06;
//std::cout<<"tau= "<<tau<<std::endl;
for (int i=0;i<steps;i++){ for (int i=0;i<steps;i++){
separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroX(temp1);
vx+=(sigma*temp1); vx+=(sigma*temp1);
separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroY(temp1);
vy+=(sigma*temp1); vy+=(sigma*temp1);
// update wx // update wx
separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroX(temp1);
temp1*=xedges; temp1*=xedges;
separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
wx-=sigma*temp2;//(-Lx'*(xedges.*(Lx*u))); wx-=sigma*temp2;//(-Lx'*(xedges.*(Lx*u)));
//update wy //update wy
separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroY(temp1);
temp1*=yedges; temp1*=yedges;
separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
wy-=sigma*temp2;//(-Ly'*(yedges.*(Ly*u))); wy-=sigma*temp2;//(-Ly'*(yedges.*(Ly*u)));
//update wz //update wz
#if (VIGRA_MIXED_2ND_DERIVATIVES) #if (VIGRA_MIXED_2ND_DERIVATIVES)
separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroY(temp1);
temp1*=yedges; temp1*=yedges;
separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
wz-=sigma*temp2;//-Lx'*(yedges.*(Ly*u)) wz-=sigma*temp2;//-Lx'*(yedges.*(Ly*u))
separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx)); setZeroX(temp1);
temp1*=xedges; temp1*=xedges;
separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
wz-=sigma*temp2;//-Ly'*(xedges.*(Lx*u))); wz-=sigma*temp2;//-Ly'*(xedges.*(Lx*u)));
#endif #endif
//project to constraint sets //project to constraint sets
for (int y=0;y<data.shape(1);y++){ for (int y=0;y<data.shape(1);y++){
for (int x=0;x<data.shape(0);x++){ for (int x=0;x<data.shape(0);x++){
double e1,e2,skp1,skp2; double e1,e2,skp1,skp2;
skipping to change at line 707 skipping to change at line 718
} }
} }
separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx)); separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx)); separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
u_bar=out; u_bar=out;
out-=tau*(weight*(out-data)+temp1+temp2); out-=tau*(weight*(out-data)+temp1+temp2);
// update wx // update wx
separableConvolveX(srcImageRange(wx),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(wx),destImage(temp1),kernel1d(Lx));set ZeroX(temp1);
temp1*=xedges; temp1*=xedges;
separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
out+=tau*temp2; // (-1)^2 out+=tau*temp2; // (-1)^2
//update wy //update wy
separableConvolveY(srcImageRange(wy),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(wy),destImage(temp1),kernel1d(Lx));set ZeroY(temp1);
temp1*=yedges; temp1*=yedges;
separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
out+=tau*temp2; out+=tau*temp2;
//update wz //update wz
#if (VIGRA_MIXED_2ND_DERIVATIVES) #if (VIGRA_MIXED_2ND_DERIVATIVES)
separableConvolveY(srcImageRange(wz),destImage(temp1),kernel1d(Lx)); separableConvolveY(srcImageRange(wz),destImage(temp1),kernel1d(Lx));set ZeroY(temp1);
temp1*=yedges; temp1*=yedges;
separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
out+=tau*temp2; out+=tau*temp2;
separableConvolveX(srcImageRange(wz),destImage(temp1),kernel1d(Lx)); separableConvolveX(srcImageRange(wz),destImage(temp1),kernel1d(Lx));set ZeroX(temp1);
temp1*=xedges; temp1*=xedges;
separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ; separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx)) ;
out+=tau*temp2; out+=tau*temp2;
#endif #endif
u_bar=2*out-u_bar; //cf. Chambolle/Pock and Popov's algorithm u_bar=2*out-u_bar; //cf. Chambolle/Pock and Popov's algorithm
} }
} }
 End of changes. 35 change blocks. 
29 lines changed or deleted 44 lines changed or added


 union_find.hxx   union_find.hxx 
skipping to change at line 39 skipping to change at line 39
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */ /* OTHER DEALINGS IN THE SOFTWARE. */
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_UNION_FIND_HXX #ifndef VIGRA_UNION_FIND_HXX
#define VIGRA_UNION_FIND_HXX #define VIGRA_UNION_FIND_HXX
/*std*/
#include <map>
/*vigra*/
#include "config.hxx" #include "config.hxx"
#include "error.hxx" #include "error.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "iteratoradapter.hxx"
namespace vigra { namespace vigra {
namespace detail { namespace detail {
template <class T, class IsSigned = VigraFalseType>
struct UnionFindAccessorImpl
{
static const T max_label = NumericTraits<T>::maxConst >> 1;
static const T anchor_bit = ~max_label;
static T max()
{
return max_label;
}
static T deletedAnchor()
{
return NumericTraits<T>::maxConst;
}
static bool isAnchor(T const & t)
{
return (t & anchor_bit) != 0;
}
static bool isValidAnchor(T const & t)
{
return isAnchor(t) && t != deletedAnchor();
}
static bool notAnchor(T const & t)
{
return (t & anchor_bit) == 0;
}
static T toAnchor(T const & t)
{
return t | anchor_bit;
}
static T fromAnchor(T const & t)
{
return t & max_label;
}
};
template <class T>
struct UnionFindAccessorImpl<T, VigraTrueType>
{
static T max()
{
return NumericTraits<T>::max();
}
static T deletedAnchor()
{
return NumericTraits<T>::min();
}
static bool isAnchor(T const & t)
{
return t < 0;
}
static bool isValidAnchor(T const & t)
{
return isAnchor(t) && t != deletedAnchor();
}
static bool notAnchor(T const & t)
{
return t >= 0;
}
static T toAnchor(T const & t)
{
return -t - 1;
}
static T fromAnchor(T const & t)
{
return -(t + 1);
}
};
template <class Array, class LabelAccessor>
class UnionFindIteratorPolicy
{
public:
typedef UnionFindIteratorPolicy BaseType;
typedef typename Array::difference_type value_type;
typedef typename Array::difference_type difference_type;
typedef value_type const & reference;
typedef value_type const & index_reference;
typedef value_type const * pointer;
typedef typename std::forward_iterator_tag iterator_category;
Array const & array_;
value_type index_;
UnionFindIteratorPolicy(Array const & array, value_type index=0)
: array_(array)
, index_(index)
{}
static void initialize(BaseType & d)
{
advanceToAnchor(d);
}
static reference dereference(BaseType const & d)
{
return d.index_;
}
static bool equal(BaseType const & d1, BaseType const & d2)
{
return d1.index_ == d2.index_;
}
static bool less(BaseType const & d1, BaseType const & d2)
{
return d1.index_ < d2.index_;
}
static void increment(BaseType & d)
{
++d.index_;
advanceToAnchor(d);
}
static void advanceToAnchor(BaseType & d)
{
while(d.index_ < (value_type)d.array_.size()-1 &&
!LabelAccessor::isValidAnchor(d.array_[d.index_]))
{
++d.index_;
}
}
};
} // namespace detail
template <class T> template <class T>
class UnionFindArray class UnionFindArray
{ {
typedef typename ArrayVector<T>::difference_type IndexType; typedef ArrayVector<T> Labe
lArray;
typedef typename LabelArray::difference_type Inde
xType;
typedef detail::UnionFindAccessorImpl<T,
typename NumericTraits<T>::isSigned> Labe
lAccessor;
typedef detail::UnionFindIteratorPolicy<LabelArray, LabelAccessor> Iter
atorPolicy;
typedef IteratorAdaptor<IteratorPolicy> iter
ator;
typedef iterator cons
t_iterator;
mutable ArrayVector<T> labels_; mutable ArrayVector<T> labels_;
public: public:
UnionFindArray(T next_free_label = 1) UnionFindArray(T next_free_label = 1)
{ {
for(T k=0; k <= next_free_label; ++k) vigra_precondition(next_free_label <= LabelAccessor::max(),
labels_.push_back(k); "UnionFindArray(): Need more labels than can be represented"
"in the destination type.");
for(T k=0; k < next_free_label; ++k)
labels_.push_back(LabelAccessor::toAnchor(k));
labels_.push_back(LabelAccessor::toAnchor(next_free_label));
}
const_iterator begin(unsigned int start_at=0) const
{
return const_iterator(IteratorPolicy(labels_, start_at));
}
const_iterator end() const
{
return const_iterator(IteratorPolicy(labels_, labels_.size()-1));
} }
T nextFreeLabel() const T nextFreeIndex() const
{ {
return labels_.back(); return T(labels_.size() - 1);
} }
T find(T label) const T findIndex(T index) const
{ {
T root = label; IndexType root = index;
while(root != labels_[(IndexType)root]) while(LabelAccessor::notAnchor(labels_[root]))
root = labels_[(IndexType)root]; root = (IndexType)labels_[root];
// path compression // path compression
while(label != root) while((IndexType)index != root)
{ {
T next = labels_[(IndexType)label]; T next = labels_[(IndexType)index];
labels_[(IndexType)label] = root; labels_[(IndexType)index] = root;
label = next; index = next;
} }
return root; return (T)root;
} }
T findLabel(T index) const
{
return LabelAccessor::fromAnchor(labels_[findIndex(index)]);
}
void deleteIndex(T index)
{
labels_[findIndex(index)] = LabelAccessor::deletedAnchor();
}
// this function does not yet check for deletedIndex()
T makeUnion(T l1, T l2) T makeUnion(T l1, T l2)
{ {
l1 = find(l1); IndexType i1 = findIndex(l1);
l2 = find(l2); IndexType i2 = findIndex(l2);
if(l1 <= l2) if(i1 == i2)
{
return i1;
}
else if(i1 < i2)
{ {
labels_[(IndexType)l2] = l1; labels_[i2] = i1;
return l1; return (T)i1;
} }
else else
{ {
labels_[(IndexType)l1] = l2; labels_[i1] = i2;
return l2; return (T)i2;
} }
} }
T finalizeLabel(T label) T finalizeIndex(T index)
{ {
if(label == (T)labels_.size()-1) if(index == (T)labels_.size()-1)
{ {
// indeed a new region // indeed a new region
vigra_invariant(label < NumericTraits<T>::max(), vigra_invariant(index < LabelAccessor::max(),
"connected components: Need more labels than can be rep resented in the destination type."); "connected components: Need more labels than can be rep resented in the destination type.");
// create new back entry // create new back entry
labels_.push_back((T)labels_.size()); labels_.push_back(LabelAccessor::toAnchor((T)labels_.size()));
} }
else else
{ {
// no new label => reset the back entry of the label array // no new index => reset the back entry of the index array
labels_.back() = (T)labels_.size()-1; labels_.back() = LabelAccessor::toAnchor((T)labels_.size()-1);
} }
return label; return index;
} }
T makeNewLabel() T makeNewIndex()
{ {
T label = labels_.back(); T index = LabelAccessor::fromAnchor(labels_.back());
vigra_invariant(label < NumericTraits<T>::max(), vigra_invariant(index < LabelAccessor::max(),
"connected components: Need more labels than can be represented i n the destination type."); "connected components: Need more labels than can be represented i n the destination type.");
labels_.push_back((T)labels_.size()); labels_.push_back(LabelAccessor::toAnchor((T)labels_.size()));
return label; return index;
} }
unsigned int makeContiguous() unsigned int makeContiguous()
{ {
// compress trees // compress trees
unsigned int count = 0; unsigned int count = 0;
for(IndexType i=0; i<(IndexType)(labels_.size()-1); ++i) for(IndexType i=0; i<(IndexType)(labels_.size()-1); ++i)
{ {
if(labels_[i] == i) if(LabelAccessor::isValidAnchor(labels_[i]))
{ {
labels_[i] = (T)count++; labels_[i] = LabelAccessor::toAnchor((T)count++);
} }
else else
{ {
labels_[i] = labels_[(IndexType)labels_[i]]; labels_[i] = findIndex(i); // path compression
} }
} }
return count-1; return count-1;
} }
T operator[](T label) const
{
return labels_[(IndexType)label];
}
}; };
} // namespace detail
} // namespace vigra } // namespace vigra
#endif // VIGRA_UNION_FIND_HXX #endif // VIGRA_UNION_FIND_HXX
 End of changes. 30 change blocks. 
43 lines changed or deleted 223 lines changed or added


 utilities.hxx   utilities.hxx 
skipping to change at line 49 skipping to change at line 49
#include "config.hxx" #include "config.hxx"
#include "error.hxx" #include "error.hxx"
#include "metaprogramming.hxx" #include "metaprogramming.hxx"
#include "tuple.hxx" #include "tuple.hxx"
#include "diff2d.hxx" #include "diff2d.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <cctype> #include <cctype>
/*! \file */
namespace vigra { namespace vigra {
/** Convert a value to a string. Available for integral and floating point types /** Convert a value to a string. Available for integral and floating point types
and void *. and void *.
*/ */
doxygen_overloaded_function(template <class T> std::string asString(T t)) doxygen_overloaded_function(template <class T> std::string asString(T t))
#define VIGRA_AS_STRING(T) \ #define VIGRA_AS_STRING(T) \
inline std::string asString(T t) \ inline std::string asString(T t) \
{ \ { \
skipping to change at line 83 skipping to change at line 85
VIGRA_AS_STRING(signed int) VIGRA_AS_STRING(signed int)
VIGRA_AS_STRING(unsigned int) VIGRA_AS_STRING(unsigned int)
VIGRA_AS_STRING(float) VIGRA_AS_STRING(float)
VIGRA_AS_STRING(double) VIGRA_AS_STRING(double)
VIGRA_AS_STRING(long double) VIGRA_AS_STRING(long double)
VIGRA_AS_STRING(void *) VIGRA_AS_STRING(void *)
#undef VIGRA_AS_STRING #undef VIGRA_AS_STRING
template <class T> template <class T>
std::string & operator<<(std::string & s, T const & t) std::string operator<<(std::string const & s, T const & t)
{ {
std::stringstream ss; std::stringstream ss;
ss << t; ss << t;
return s += ss.str(); return s + ss.str();
} }
/** Convert string to lower case. /** Convert string to lower case.
*/ */
inline std::string tolower(std::string s) inline std::string tolower(std::string s)
{ {
for(unsigned int k=0; k<s.size(); ++k) for(unsigned int k=0; k<s.size(); ++k)
s[k] = (std::string::value_type)std::tolower(s[k]); s[k] = (std::string::value_type)std::tolower(s[k]);
return s; return s;
} }
skipping to change at line 124 skipping to change at line 126
res += (std::string::value_type)std::tolower(s[k]); res += (std::string::value_type)std::tolower(s[k]);
} }
return res; return res;
} }
inline std::string normalizeString(const char * s) inline std::string normalizeString(const char * s)
{ {
return normalizeString(std::string(s)); return normalizeString(std::string(s));
} }
namespace detail {
template <class T>
struct FinallyImpl
{
T & destructor_;
FinallyImpl(T & destructor)
: destructor_(destructor)
{}
~FinallyImpl()
{
destructor_();
}
};
} // namespace detail
} // namespace vigra } // namespace vigra
#define VIGRA_TOKEN_PASTE_IMPL(x, y) x##y
#define VIGRA_TOKEN_PASTE(x, y) VIGRA_TOKEN_PASTE_IMPL(x, y)
#define VIGRA_FINALLY_IMPL(destructor, counter) \
auto VIGRA_TOKEN_PASTE(_vigra_finally_impl_, counter) = [&]() { destruc
tor; }; \
::vigra::detail::FinallyImpl<decltype(VIGRA_TOKEN_PASTE(_vigra_finally_
impl_, counter))> \
VIGRA_TOKEN_PASTE(_vigra_finally_, counter)(VIGRA_TOKEN_PASTE(_vigr
a_finally_impl_, counter))
/** Emulate the 'finally' keyword as known from Python and other langua
ges.
This macro improves upon the famous
<a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initi
alization">Resource Acquisition Is Initialization</a> idiom, where a resour
ce (e.g. heap memory or a mutex) is automatically free'ed when program exec
ution leaves the current scope. Normally, this is implemented by calling a
suitable function in the destructor of a dedicated helper class (e.g. <tt>s
td::unique_ptr</tt> or <tt>std::lock_guard<std::mutex></tt>).
Traditionally, a separate helper class has to be implemented for ea
ch kind of resource to be handled. In contrast, the macro <tt>VIGRA_FINALLY
</tt> creates such a class on the fly by means of an embedded lambda expres
sion.
<b>Usage:</b>
<b>\#include</b> \<vigra/utilities.hxx\><br/>
\code
std::mutex my_mutex;
...
{
// the following two lines are equivalent to
// std::unique_ptr<std::string> my_string = new std::string
("foo");
std::string * my_string = new std::string("foo");
VIGRA_FINALLY(delete my_string);
// the following two lines are equivalent to
// std::lock_guard<std::mutex> lock(my_mutex);
my_mutex.lock();
VIGRA_FINALLY(my_mutex.unlock());
...
}
// the string has been deallocated and the mutex is unlocked
\endcode
You can pass any code to this macro. Multiple statements must be en
closed in braces as usual. Arbitrary many calls to <tt>VIGRA_FINALLY</tt> c
an be placed in the same scope. Their actions will be executed in the rever
sed order of declaration:
\code
int i = 0;
...
{
VIGRA_FINALLY({ // execute multiple statements
i = i*i;
++i;
});
VIGRA_FINALLY( i += 2 ); // this executes first
assert(i == 0); // as yet, nothing happend
}
assert(i == 5); // 'finally' code was executed in rev
ersed order at end-of-scope
\endcode
This idea was popularized by Marko Tintor in "<a href="http://blog.
memsql.com/c-error-handling-with-auto/">The Auto Macro: A Clean Approach to
C++ Error Handling</a>".
*/
#define VIGRA_FINALLY(destructor) \
VIGRA_FINALLY_IMPL(destructor, __COUNTER__)
namespace std { namespace std {
template <class T1, class T2> template <class T1, class T2>
ostream & operator<<(ostream & s, std::pair<T1, T2> const & p) ostream & operator<<(ostream & s, std::pair<T1, T2> const & p)
{ {
s << "(" << p.first << ", " << p.second << ")"; s << "(" << p.first << ", " << p.second << ")";
return s; return s;
} }
} }
/*! \page Utilities Utilities /** \page Utilities Utilities
Basic helper functionality needed throughout. Basic helper functionality needed throughout.
<UL style="list-style-image:url(documents/bullet.gif)"> <UL style="list-style-image:url(documents/bullet.gif)">
<LI> \ref vigra::ArrayVector <LI> \ref vigra::ArrayVector
<BR>&nbsp;&nbsp;&nbsp;<em>replacement for std::vector (always uses consecutive memory)</em> <BR>&nbsp;&nbsp;&nbsp;<em>replacement for std::vector (always uses consecutive memory)</em>
<LI> \ref vigra::BucketQueue and \ref vigra::MappedBucketQueue <LI> \ref vigra::BucketQueue and \ref vigra::MappedBucketQueue
<BR>&nbsp;&nbsp;&nbsp;<em>efficient priority queues for integer pr iorities</em> <BR>&nbsp;&nbsp;&nbsp;<em>efficient priority queues for integer pr iorities</em>
<LI> \ref RangesAndPoints <LI> \ref RangesAndPoints
<BR>&nbsp;&nbsp;&nbsp;<em>2-D and N-D positions, extents, and boxe s</em> <BR>&nbsp;&nbsp;&nbsp;<em>2-D and N-D positions, extents, and boxe s</em>
<LI> \ref PixelNeighborhood <LI> \ref PixelNeighborhood
skipping to change at line 159 skipping to change at line 241
<LI> \ref VoxelNeighborhood <LI> \ref VoxelNeighborhood
<BR>&nbsp;&nbsp;&nbsp;<em>6- and 26-neighborhood definitions and c irculators</em> <BR>&nbsp;&nbsp;&nbsp;<em>6- and 26-neighborhood definitions and c irculators</em>
<LI> \ref vigra::IteratorAdaptor <LI> \ref vigra::IteratorAdaptor
<BR>&nbsp;&nbsp;&nbsp;<em>Quickly create STL-compatible 1D iterato r adaptors</em> <BR>&nbsp;&nbsp;&nbsp;<em>Quickly create STL-compatible 1D iterato r adaptors</em>
<LI> \ref TupleTypes <LI> \ref TupleTypes
<BR>&nbsp;&nbsp;&nbsp;<em>pair, triple, tuple4, tuple5</em> <BR>&nbsp;&nbsp;&nbsp;<em>pair, triple, tuple4, tuple5</em>
<LI> \ref MathConstants <LI> \ref MathConstants
<BR>&nbsp;&nbsp;&nbsp;<em>M_PI, M_SQRT2</em> <BR>&nbsp;&nbsp;&nbsp;<em>M_PI, M_SQRT2</em>
<LI> \ref TimingMacros <LI> \ref TimingMacros
<BR>&nbsp;&nbsp;&nbsp;<em>Macros for taking execution speed measur ements</em> <BR>&nbsp;&nbsp;&nbsp;<em>Macros for taking execution speed measur ements</em>
<LI> \ref VIGRA_FINALLY
<BR>&nbsp;&nbsp;&nbsp;<em>Emulation of the 'finally' keyword from
Python</em>
</UL> </UL>
*/ */
#endif // VIGRA_BASICS_HXX #endif // VIGRA_BASICS_HXX
 End of changes. 7 change blocks. 
3 lines changed or deleted 107 lines changed or added


 voxelneighborhood.hxx   voxelneighborhood.hxx 
skipping to change at line 190 skipping to change at line 190
CausalFirst = InFront, CausalFirst = InFront,
CausalLast = West, CausalLast = West,
AntiCausalFirst = Behind, AntiCausalFirst = Behind,
AntiCausalLast = East, AntiCausalLast = East,
InitialDirection = InFront, InitialDirection = InFront,
OppositeDirPrefix = 1, OppositeDirPrefix = 1,
OppositeOffset = 3 OppositeOffset = 3
}; };
template <int DUMMY>
struct StaticData
{
static unsigned int b[];
static unsigned int c[];
static Direction bd[43][6];
static Direction bc[43][3];
static Diff3D d[];
static Diff3D rd[][6];
};
static unsigned int directionBit(Direction d) static unsigned int directionBit(Direction d)
{ {
static unsigned int b[] = { 1 << InFront, return StaticData<0>::b[d];
1 << North,
1 << West,
1 << Behind,
1 << South,
1 << East
};
return b[d];
}; };
/** The number of valid neighbors if the current center is at the volum e border. /** The number of valid neighbors if the current center is at the volum e border.
*/ */
static unsigned int nearBorderDirectionCount(AtVolumeBorder b) static unsigned int nearBorderDirectionCount(AtVolumeBorder b)
{ {
static unsigned int c[] = { 6, 5, 5, 0, 5, 4, 4, 0, 5, 4, return StaticData<0>::c[b];
4, 0, 0, 0, 0, 0, 5, 4, 4, 0,
4, 3, 3, 0, 4, 3, 3, 0, 0, 0,
0, 0, 5, 4, 4, 0, 4, 3, 3, 0,
4, 3, 3};
return c[b];
} }
/** The valid direction codes when the center is at the volume border. /** The valid direction codes when the center is at the volume border.
\a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>. \a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>.
*/ */
static Direction nearBorderDirections(AtVolumeBorder b, int index) static Direction nearBorderDirections(AtVolumeBorder b, int index)
{ {
static Direction c[43][6] = { return StaticData<0>::bd[b][index];
{ InFront, North, West, Behind, South, East}, // 0 - NotA
tBorder
{ InFront, North, West, Behind, South, Error}, // 1 - AtRi
ghtBorder
{ InFront, North, Behind, South, East, Error}, // 2 - AtLe
ftBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, West, Behind, South, East, Error}, // 4 - AtTo
pBorder
{ InFront, West, Behind, South, Error, Error}, // 5 - AtTo
pRightBorder
{ InFront, Behind, South, East, Error, Error}, // 6 - AtTo
pLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, North, West, Behind, East, Error}, // 8 - AtBo
ttomBorder
{ InFront, North, West, Behind, Error, Error}, // 9 - AtBo
ttomRightBorder
{ InFront, North, Behind, East, Error, Error}, //10- AtBot
tomLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ North, West, Behind, South, East, Error}, //16 - AtFr
ontBorder
{ North, West, Behind, South, Error, Error}, //17 - AtFr
ontRightBorder
{ North, Behind, South, East, Error, Error}, //18 - AtFr
ontLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ West, Behind, South, East, Error, Error}, //20 - AtTo
pFrontBorder
{ West, Behind, South, Error, Error, Error}, //21 - AtTo
pRightFrontBorder
{ Behind, South, East, Error, Error, Error}, //22 - AtTo
pLeftFrontBorder
{ Error, Error, Error, Error, Error, Error},
{ North, West, Behind, East, Error, Error}, //24 - AtBo
ttomFrontBorder
{ North, West, Behind, Error, Error, Error}, //25 - AtBo
ttomRightFrontBorder
{ North, Behind, East, Error, Error, Error}, //26 - AtBo
ttomLeftFrontBorder
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ InFront, North, West, South, East,Error}, //32 - AtRe
arBorder
{ InFront, North, West, South, Error, Error}, //33 - AtRe
arRightBorder
{ InFront, North, South, East, Error, Error}, //34 - AtRe
arLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, West, South, East, Error, Error}, //36 - AtTo
pRearBorder
{ InFront, West, South, Error, Error, Error}, //37 - AtTo
pRightRearBorder
{ InFront, South, East, Error, Error, Error}, //38 - AtTo
pLeftRearBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, North, West, East, Error, Error}, //40 - AtBo
ttomRearBorder
{ InFront, North, West, Error, Error, Error}, //41 - AtBo
ttomRightRearBorder
{ InFront, North, East, Error, Error, Error} //42 - AtBo
ttomLeftRearBorder
};
return c[b][index];
} }
/** The valid direction three codes in anti causal direction (means: lo ok back in scanline /** The valid direction three codes in anti causal direction (means: lo ok back in scanline
direction)when the center is at the volume border. direction)when the center is at the volume border.
Should be used with isAtVolumeBorderCausal to determine the Directi ons, as this Should be used with isAtVolumeBorderCausal to determine the Directi ons, as this
avoids using of the nonesense border ids (e.g. 0,1,8,9...) of this table. avoids using of the nonesense border ids (e.g. 0,1,8,9...) of this table.
\a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>. \a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>.
*/ */
static Direction nearBorderDirectionsCausal(AtVolumeBorder b, int index ) static Direction nearBorderDirectionsCausal(AtVolumeBorder b, int index )
{ {
static Direction c[43][3] = { return StaticData<0>::bc[b][index];
{ InFront, North, West}, // 0 - NotAtBorder
{ InFront, North, West}, // 1 - AtRightBorde
r
{ InFront, North, Error}, // 2 - AtLeftBorder
{ Error, Error, Error},
{ InFront, West, Error}, // 4 - AtTopBorder
{ InFront, West, Error}, // 5 - AtTopRightBo
rder
{ InFront, Error,Error}, // 6 - AtTopLeftBor
der
{ Error, Error, Error},
{ InFront, North, West}, // 8 - AtBottomBord
er
{ InFront, North, West}, // 9 - AtBottomRigh
tBorder
{ InFront, North, Error}, //10- AtBottomLeftB
order
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ North, West, Error}, //16 - AtFrontBorde
r
{ North, West, Error}, //17 - AtFrontRight
Border
{ North, Error, Error}, //18 - AtFrontLeftB
order
{ Error, Error, Error},
{ West, Error, Error}, //20 - AtTopFrontBo
rder
{ West, Error, Error}, //21 - AtTopRightFr
ontBorder
{ Error, Error, Error}, //22 - AtTopLeftFro
ntBorder
{ Error, Error, Error},
{ North, West, Error}, //24 - AtBottomFron
tBorder
{ North, West, Error}, //25 - AtBottomRigh
tFrontBorder
{ North, Error, Error}, //26 - AtBottomLeft
FrontBorder
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ InFront, North, West}, //32 - AtRearBorder
{ InFront, North, West}, //33 - AtRearRightB
order
{ InFront, North, Error}, //34 - AtRearLeftBo
rder
{ Error, Error, Error},
{ InFront, West, Error}, //36 - AtTopRearBor
der
{ InFront, West, Error}, //37 - AtTopRightRe
arBorder
{ InFront, Error, Error}, //38 - AtTopLeftRea
rBorder
{ Error, Error, Error},
{ InFront, North, West}, //40 - AtBottomRear
Border
{ InFront, North, West}, //41 - AtBottomRigh
tRearBorder
{ InFront, North, Error} //42 - AtBottomLeft
RearBorder
};
return c[b][index];
} }
/** transform direction code into corresponding Diff3D offset. /** transform direction code into corresponding Diff3D offset.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff3D const & diff(Direction code) static Diff3D const & diff(Direction code)
{ {
static Diff3D d[] = { return StaticData<0>::d[code];
Diff3D( 0, 0, -1), //InFront
Diff3D( 0, -1, 0), //North
Diff3D( -1, 0, 0), //West
Diff3D( 0, 0, 1), //Behind
Diff3D( 0, 1, 0), //South
Diff3D( 1, 0, 0) //East
};
return d[code];
} }
/** Equivalent to <tt>diff(static_cast<Direction>(code))</tt>. /** Equivalent to <tt>diff(static_cast<Direction>(code))</tt>.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff3D const & diff(int code) { return diff(static_cast<Directio n>(code)); } static Diff3D const & diff(int code) { return diff(static_cast<Directio n>(code)); }
/** Equivalent to <tt>diff(code)[dim]</tt> */ /** Equivalent to <tt>diff(code)[dim]</tt> */
static int diff(Direction code, int dim) { return diff(code)[dim]; } static int diff(Direction code, int dim) { return diff(code)[dim]; }
/** Get the relative offset from one neighbor to the other. /** Get the relative offset from one neighbor to the other.
For example, <tt>relativeDiff(East, West) == multi_differencetype(- 2,0,0)</tt>. For example, <tt>relativeDiff(East, West) == multi_differencetype(- 2,0,0)</tt>.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff3D const & relativeDiff(Direction fromCode, Direction toCode ) static Diff3D const & relativeDiff(Direction fromCode, Direction toCode )
{ {
static Diff3D d[6][6] = return StaticData<0>::rd[fromCode][toCode];
{
// InFront - North - West
- Behind - South - East
{ Diff3D( 0, 0, 0), Diff3D(0, -1, 1), Diff3D(-1, 0, 1), Dif
f3D( 0, 0, 2), Diff3D( 0, 1, 1), Diff3D( 1, 0, 1)}, //InFront
{ Diff3D( 0, 1,-1), Diff3D( 0, 0, 0), Diff3D(-1, 1, 0), Dif
f3D( 0, 1, 1), Diff3D( 0, 2, 0), Diff3D( 1, 1, 0)}, //North
{ Diff3D( 1, 0,-1), Diff3D( 1,-1, 0), Diff3D( 0, 0, 0), Dif
f3D( 1, 0, 1), Diff3D( 1, 1, 0), Diff3D( 2, 0, 0)}, //West
{ Diff3D( 0, 0,-2), Diff3D( 0,-1,-1), Diff3D(-1, 0,-1), Dif
f3D( 0, 0, 0), Diff3D( 0, 1,-1), Diff3D( 1, 0,-1)}, //Behind
{ Diff3D( 0,-1,-1), Diff3D( 0,-2, 0), Diff3D(-1,-1, 0), Dif
f3D( 0,-1, 1), Diff3D( 0, 0, 0), Diff3D( 1,-1, 0)}, //South
{ Diff3D(-1, 0,-1), Diff3D(-1,-1, 0), Diff3D(-2, 0, 0), Dif
f3D(-1, 0, 1), Diff3D(-1, 1, 0), Diff3D( 0, 0, 0) } //East
};
return d[fromCode][toCode];
} }
/** Equivalent to relativeDiff(static_cast<Direction>(fromCode), static _cast<Direction>(toCode)). /** Equivalent to relativeDiff(static_cast<Direction>(fromCode), static _cast<Direction>(toCode)).
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff3D const & relativeDiff(int fromCode, int toCode) static Diff3D const & relativeDiff(int fromCode, int toCode)
{ {
return relativeDiff(static_cast<Direction>(fromCode), static_cast<D irection>(toCode)); return relativeDiff(static_cast<Direction>(fromCode), static_cast<D irection>(toCode));
} }
skipping to change at line 459 skipping to change at line 349
typedef NeighborCode3D::Direction Direction; typedef NeighborCode3D::Direction Direction;
static const Direction East = NeighborCode3D::East; /**< Export NeighborCode3D::East to namespace Neighborhood3DSix */ static const Direction East = NeighborCode3D::East; /**< Export NeighborCode3D::East to namespace Neighborhood3DSix */
static const Direction North = NeighborCode3D::North; /**< Export NeighborCode3D::North to namespace Neighborhood3DSix */ static const Direction North = NeighborCode3D::North; /**< Export NeighborCode3D::North to namespace Neighborhood3DSix */
static const Direction West = NeighborCode3D::West; /**< Export NeighborCode3D::West to namespace Neighborhood3DSix */ static const Direction West = NeighborCode3D::West; /**< Export NeighborCode3D::West to namespace Neighborhood3DSix */
static const Direction South = NeighborCode3D::South; /**< Export NeighborCode3D::South to namespace Neighborhood3DSix */ static const Direction South = NeighborCode3D::South; /**< Export NeighborCode3D::South to namespace Neighborhood3DSix */
static const Direction Behind = NeighborCode3D::Behind; /**< Export NeighborCode3D::Behind to namespace Neighborhood3DSix */ static const Direction Behind = NeighborCode3D::Behind; /**< Export NeighborCode3D::Behind to namespace Neighborhood3DSix */
static const Direction InFront = NeighborCode3D::InFront; /**< Export NeighborCode3D::InFront to namespace Neighborhood3DSix */ static const Direction InFront = NeighborCode3D::InFront; /**< Export NeighborCode3D::InFront to namespace Neighborhood3DSix */
static const Direction DirectionCount = NeighborCode3D::DirectionCount; /**< Export NeighborCode3D::DirectionCount to namespace Neighborhood3DSix */ static const Direction DirectionCount = NeighborCode3D::DirectionCount; /**< Export NeighborCode3D::DirectionCount to namespace Neighborhood3DSix */
template <int DUMMY>
unsigned int NeighborCode3D::StaticData<DUMMY>::b[] = {
1 << InFront,
1 << North,
1 << West,
1 << Behind,
1 << South,
1 << East
};
template <int DUMMY>
unsigned int NeighborCode3D::StaticData<DUMMY>::c[] = {
6, 5, 5, 0, 5, 4, 4, 0, 5, 4,
4, 0, 0, 0, 0, 0, 5, 4, 4, 0,
4, 3, 3, 0, 4, 3, 3, 0, 0, 0,
0, 0, 5, 4, 4, 0, 4, 3, 3, 0,
4, 3, 3};
template <int DUMMY>
Direction NeighborCode3D::StaticData<DUMMY>::bd[43][6] = {
{ InFront, North, West, Behind, South, East}, // 0 - NotA
tBorder
{ InFront, North, West, Behind, South, Error}, // 1 - AtRi
ghtBorder
{ InFront, North, Behind, South, East, Error}, // 2 - AtLe
ftBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, West, Behind, South, East, Error}, // 4 - AtTo
pBorder
{ InFront, West, Behind, South, Error, Error}, // 5 - AtTo
pRightBorder
{ InFront, Behind, South, East, Error, Error}, // 6 - AtTo
pLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, North, West, Behind, East, Error}, // 8 - AtBo
ttomBorder
{ InFront, North, West, Behind, Error, Error}, // 9 - AtBo
ttomRightBorder
{ InFront, North, Behind, East, Error, Error}, //10- AtBot
tomLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ North, West, Behind, South, East, Error}, //16 - AtFr
ontBorder
{ North, West, Behind, South, Error, Error}, //17 - AtFr
ontRightBorder
{ North, Behind, South, East, Error, Error}, //18 - AtFr
ontLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ West, Behind, South, East, Error, Error}, //20 - AtTo
pFrontBorder
{ West, Behind, South, Error, Error, Error}, //21 - AtTo
pRightFrontBorder
{ Behind, South, East, Error, Error, Error}, //22 - AtTo
pLeftFrontBorder
{ Error, Error, Error, Error, Error, Error},
{ North, West, Behind, East, Error, Error}, //24 - AtBo
ttomFrontBorder
{ North, West, Behind, Error, Error, Error}, //25 - AtBo
ttomRightFrontBorder
{ North, Behind, East, Error, Error, Error}, //26 - AtBo
ttomLeftFrontBorder
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ Error, Error, Error, Error, Error, Error},
{ InFront, North, West, South, East,Error}, //32 - AtRe
arBorder
{ InFront, North, West, South, Error, Error}, //33 - AtRe
arRightBorder
{ InFront, North, South, East, Error, Error}, //34 - AtRe
arLeftBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, West, South, East, Error, Error}, //36 - AtTo
pRearBorder
{ InFront, West, South, Error, Error, Error}, //37 - AtTo
pRightRearBorder
{ InFront, South, East, Error, Error, Error}, //38 - AtTo
pLeftRearBorder
{ Error, Error, Error, Error, Error, Error},
{ InFront, North, West, East, Error, Error}, //40 - AtBo
ttomRearBorder
{ InFront, North, West, Error, Error, Error}, //41 - AtBo
ttomRightRearBorder
{ InFront, North, East, Error, Error, Error} //42 - AtBo
ttomLeftRearBorder
};
template <int DUMMY>
Direction NeighborCode3D::StaticData<DUMMY>::bc[43][3] = {
{ InFront, North, West}, // 0 - NotAtBorder
{ InFront, North, West}, // 1 - AtRightBorde
r
{ InFront, North, Error}, // 2 - AtLeftBorder
{ Error, Error, Error},
{ InFront, West, Error}, // 4 - AtTopBorder
{ InFront, West, Error}, // 5 - AtTopRightBo
rder
{ InFront, Error,Error}, // 6 - AtTopLeftBor
der
{ Error, Error, Error},
{ InFront, North, West}, // 8 - AtBottomBord
er
{ InFront, North, West}, // 9 - AtBottomRigh
tBorder
{ InFront, North, Error}, //10- AtBottomLeftB
order
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ North, West, Error}, //16 - AtFrontBorde
r
{ North, West, Error}, //17 - AtFrontRight
Border
{ North, Error, Error}, //18 - AtFrontLeftB
order
{ Error, Error, Error},
{ West, Error, Error}, //20 - AtTopFrontBo
rder
{ West, Error, Error}, //21 - AtTopRightFr
ontBorder
{ Error, Error, Error}, //22 - AtTopLeftFro
ntBorder
{ Error, Error, Error},
{ North, West, Error}, //24 - AtBottomFron
tBorder
{ North, West, Error}, //25 - AtBottomRigh
tFrontBorder
{ North, Error, Error}, //26 - AtBottomLeft
FrontBorder
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ Error, Error, Error},
{ InFront, North, West}, //32 - AtRearBorder
{ InFront, North, West}, //33 - AtRearRightB
order
{ InFront, North, Error}, //34 - AtRearLeftBo
rder
{ Error, Error, Error},
{ InFront, West, Error}, //36 - AtTopRearBor
der
{ InFront, West, Error}, //37 - AtTopRightRe
arBorder
{ InFront, Error, Error}, //38 - AtTopLeftRea
rBorder
{ Error, Error, Error},
{ InFront, North, West}, //40 - AtBottomRear
Border
{ InFront, North, West}, //41 - AtBottomRigh
tRearBorder
{ InFront, North, Error} //42 - AtBottomLeft
RearBorder
};
template <int DUMMY>
Diff3D NeighborCode3D::StaticData<DUMMY>::d[] = {
Diff3D( 0, 0, -1), //InFront
Diff3D( 0, -1, 0), //North
Diff3D( -1, 0, 0), //West
Diff3D( 0, 0, 1), //Behind
Diff3D( 0, 1, 0), //South
Diff3D( 1, 0, 0) //East
};
template <int DUMMY>
Diff3D NeighborCode3D::StaticData<DUMMY>::rd[][6] = {
// InFront - North - West - Beh
ind - South - East
{ Diff3D( 0, 0, 0), Diff3D(0, -1, 1), Diff3D(-1, 0, 1), Diff3D( 0, 0, 2), D
iff3D( 0, 1, 1), Diff3D( 1, 0, 1)}, //InFront
{ Diff3D( 0, 1,-1), Diff3D( 0, 0, 0), Diff3D(-1, 1, 0), Diff3D( 0, 1, 1), D
iff3D( 0, 2, 0), Diff3D( 1, 1, 0)}, //North
{ Diff3D( 1, 0,-1), Diff3D( 1,-1, 0), Diff3D( 0, 0, 0), Diff3D( 1, 0, 1), D
iff3D( 1, 1, 0), Diff3D( 2, 0, 0)}, //West
{ Diff3D( 0, 0,-2), Diff3D( 0,-1,-1), Diff3D(-1, 0,-1), Diff3D( 0, 0, 0), D
iff3D( 0, 1,-1), Diff3D( 1, 0,-1)}, //Behind
{ Diff3D( 0,-1,-1), Diff3D( 0,-2, 0), Diff3D(-1,-1, 0), Diff3D( 0,-1, 1), D
iff3D( 0, 0, 0), Diff3D( 1,-1, 0)}, //South
{ Diff3D(-1, 0,-1), Diff3D(-1,-1, 0), Diff3D(-2, 0, 0), Diff3D(-1, 0, 1), D
iff3D(-1, 1, 0), Diff3D( 0, 0, 0) } //East
};
}//namespace Neighborhood3DSix }//namespace Neighborhood3DSix
/** Export \ref vigra::Neighborhood3DSix::NeighborCode3D into the scope of namespace vigra. /** Export \ref vigra::Neighborhood3DSix::NeighborCode3D into the scope of namespace vigra.
*/ */
typedef Neighborhood3DSix::NeighborCode3D NeighborCode3DSix; typedef Neighborhood3DSix::NeighborCode3D NeighborCode3DSix;
/********************************************************/ /********************************************************/
/* */ /* */
/* Neighborhood3DTwentySix */ /* Neighborhood3DTwentySix */
/* */ /* */
skipping to change at line 527 skipping to change at line 550
CausalFirst = InFrontNorthWest, CausalFirst = InFrontNorthWest,
CausalLast = West, CausalLast = West,
AntiCausalFirst = BehindSouthEast, AntiCausalFirst = BehindSouthEast,
AntiCausalLast = East, AntiCausalLast = East,
InitialDirection = InFrontNorthWest, InitialDirection = InFrontNorthWest,
OppositeDirPrefix = -1, OppositeDirPrefix = -1,
OppositeOffset = 25 OppositeOffset = 25
}; };
static unsigned int directionBit(Direction d) template <int DUMMY>
struct StaticData
{ {
static unsigned int b[] = { static unsigned int b[];
1 << InFrontNorthWest, static unsigned int c[];
1 << InFrontNorth, static Direction bd[43][26];
1 << InFrontNorthEast, static Direction bc[43][13];
1 << InFrontWest, static Diff3D d[];
1 << InFront, };
1 << InFrontEast,
1 << InFrontSouthWest,
1 << InFrontSouth,
1 << InFrontSouthEast,
1 << NorthWest,
1 << North,
1 << NorthEast,
1 << West,
1 << East,
1 << SouthWest,
1 << South,
1 << SouthEast,
1 << BehindNorthWest, static unsigned int directionBit(Direction d)
1 << BehindNorth, {
1 << BehindNorthEast, return StaticData<0>::b[d];
1 << BehindWest,
1 << Behind,
1 << BehindEast,
1 << BehindSouthWest,
1 << BehindSouth,
1 << BehindSouthEast
};
return b[d];
}; };
/** The number of valid neighbors if the current center is at the volum e border. /** The number of valid neighbors if the current center is at the volum e border.
*/ */
static unsigned int nearBorderDirectionCount(AtVolumeBorder b) static unsigned int nearBorderDirectionCount(AtVolumeBorder b)
{ {
static unsigned int c[] = { 26, 17, 17, 0, 17, 11, 11, 0, 17, 11, return StaticData<0>::c[b];
11, 0, 0, 0, 0, 0, 17, 11, 11, 0,
11, 7, 7, 0, 11, 7, 7, 0, 0, 0,
0, 0, 17, 11, 11, 0, 11, 7, 7, 0,
11, 7, 7};
return c[b];
} }
/** The valid direction codes when the center is at the volume border. /** The valid direction codes when the center is at the volume border.
\a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>. \a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>.
*/ */
static Direction nearBorderDirections(AtVolumeBorder b, int index) static Direction nearBorderDirections(AtVolumeBorder b, int index)
{ {
static Direction c[43][26] = { return StaticData<0>::bd[b][index];
//0 - NotAtBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEas
t,
NorthWest, North, NorthEast,
West, East,
SouthWest, South, SouthEast,
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast},
//1 - AtRightBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEast,
*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,
*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//2 - AtLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNorthE
ast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSouthE
ast,
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//3 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//4 - AtTopBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
*/
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind,
BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//5 - AtTopRightBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,*/
InFrontWest, InFront, /*InFrontEast,*
/
InFrontSouthWest, InFrontSouth, /*InFrontSouthE
ast,*/
/*NorthWest, North, NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*
/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//6 - AtTopLeftBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNort
hEast,*/
/*InFrontWest,*/ InFront, InFrontEast
,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSout
hEast,
/*NorthWest, North, NorthEast,*/
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEas
t,*/
/*BehindWest, */ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEas
t,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//7 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//8 - AtBottomBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast
,
InFrontWest, InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,
*/
NorthWest, North, NorthEast,
West, East,
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//9 - AtBottomRightBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEa
st,*/
InFrontWest, InFront, /*InFrontEast,*/
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast
,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*
/
BehindWest, Behind, /*BehindEast,*/
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//10 - AtBottomLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNort
hEast,
/*InFrontWest,*/ InFront, InFrontEast
,
/*InFrontSouthWest, InFrontSouth, InFrontSout
hEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast
,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast
*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//11 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//12 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//13 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//14 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//15 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//16 - AtFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEa
st,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West, East,
SouthWest, South, SouthEast,
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//17 - AtFrontRightBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEa
st,
InFrontWest, InFront,
InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//18 - AtFrontLeftBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEas
t,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//19 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//20 - AtTopFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEas
t,*/
/*NorthWest, North, NorthEast,*/
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast
,*/
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast
,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//21 - AtTopRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast
,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast
,*/
/*NorthWest, North, NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*
/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//22 - AtTopLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEas
t,*/
/*NorthWest, North, NorthEast,*/
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEas
t,*/
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEas
t,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//23 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//24 - AtBottomFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
*/
NorthWest, North, NorthEast,
West, East,
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//25 - AtBottomRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEa
st,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /* East,*/
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,
*/
BehindWest, Behind, /*BehindEast,*/
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//26 - AtBottomLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//27 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//28 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//29 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//30 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//31 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//32 - AtRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//33 - AtRearRightBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEast,
*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,
*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//34 - AtRearLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNorthEas
t,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSouthEas
t,
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*
/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//35 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//36 - AtTopRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,*/
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEas
t,
/*NorthWest, North, NorthEast,*/
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*
/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//37 - AtTopRightRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,*/
InFrontWest, InFront, /*InFrontEast,*
/
InFrontSouthWest, InFrontSouth, /*InFrontSouthE
ast,*/
/*NorthWest, North, NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//38 - AtTopLeftRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNor
thEast,*/
/*InFrontWest,*/ InFront, InFrontEas
t,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSout
hEast,
/*NorthWest, North, NorthEast,*/
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast
,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast
,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//39 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error, Error, Er
ror,
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error},
//40 - AtBottomRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEas
t,
InFrontWest, InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEas
t,*/
NorthWest, North, NorthEast,
West, East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error},
//41 - AtBottomRightRearBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEas
t,*/
InFrontWest, InFront, /*InFrontEast,*/
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,
*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//42 - AtBottomLeftRearBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNort
hEast,
/*InFrontWest,*/ InFront, InFrontEast
,
/*InFrontSouthWest, InFrontSouth, InFrontSout
hEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Er
ror, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error}
};
return c[b][index];
} }
/** The valid direction three codes in anti causal direction (means: lo ok back in scanline /** The valid direction three codes in anti causal direction (means: lo ok back in scanline
direction)when the center is at the volume border. direction)when the center is at the volume border.
Should be used with isAtVolumeBorderCausal to determine the Dir ections, as this Should be used with isAtVolumeBorderCausal to determine the Dir ections, as this
avoids using of the nonesense border ids (e.g. 0,1,8,9...) of t his table. avoids using of the nonesense border ids (e.g. 0,1,8,9...) of t his table.
\a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>. \a index must be in the range <tt>0...nearBorderDirectionCount(b)-1 </tt>.
*/ */
static Direction nearBorderDirectionsCausal(AtVolumeBorder b, int index ) static Direction nearBorderDirectionsCausal(AtVolumeBorder b, int index )
{ {
static Direction c[43][13] = { return StaticData<0>::bc[b][index];
//0 - NotAtBorder -----> should never be used
{ InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
NorthWest, North, NorthE
ast,
West},
//1 - AtRightBorder
{ InFrontNorthWest, InFrontNorth, /* InF
rontNorthEast, */
InFrontWest, InFront, /* InF
rontEast, */
InFrontSouthWest, InFrontSouth, /* InF
rontSouthEast, */
NorthWest, North, /* Nor
thEast, */
West,
Error, Error, Error, Error},
//2 - AtLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth,InFron
tNorthEast,
/*InFrontWest,*/ InFront, InFron
tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron
tSouthEast,
/*NorthWest,*/ North, NorthE
ast,
/*West*/
Error, Error, Error, Error, Error},
//3 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//4 - AtTopBorder
{ /*InFrontNorthWest,InFrontNorth, InFron
tNorthEast,*/
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
/*NorthWest, North, NorthE
ast,*/
West,
Error, Error, Error, Error, Error, Error}
,
//5 - AtTopRightBorder
{ /*InFrontNorthWest,InFrontNorth, InFron
tNorthEast,*/
InFrontWest, InFront, /*InFr
ontEast,*/
InFrontSouthWest, InFrontSouth, /*InFr
ontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error,
Error, Error},
//6 - AtTopLeftBorder
{ /*InFrontNorthWest,InFrontNorth, InFro
ntNorthEast,*/
/*InFrontWest,*/ InFront, InFro
ntEast,
/*InFrontSouthWest,*/InFrontSouth, InFro
ntSouthEast,
/*NorthWest, North, North
East,*/
/*West,*/
Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//7 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//8 - AtBottomBorder
{ InFrontNorthWest, InFrontNorth, InFro
ntNorthEast,
InFrontWest, InFront, InFro
ntEast,
/* InFrontSouthWest, InFrontSouth, In
FrontSouthEast, */
NorthWest, North, North
East,
West,
Error, Error, Error},
//9 - AtBottomRightBorder
{ InFrontNorthWest, InFrontNorth, /* InF
rontNorthEast, */
InFrontWest, InFront, /* InF
rontEast, */
/* InFrontSouthWest, InFrontSouth, InF
rontSouthEast, */
NorthWest, North, /* Nor
thEast, */
West,
Error, Error, Error,Error, Error, Error},
//10 - AtBottomLeftBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFron
tNorthEast,
/*InFrontWest,*/ InFront, InFron
tEast,
/*InFrontSouthWest, InFrontSouth, InFront
SouthEast, */
/*NorthWest,*/ North, NorthE
ast,
/*West*/
Error, Error, Error, Error, Error, Error,
Error},
//11 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//12 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//13 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//14 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//15 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//16 - AtFrontBorder
{ /*InFrontNorthWest,InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
NorthWest, North, NorthE
ast,
West,
Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//17 - AtFrontRightBorder
{ /*InFrontNorthWest,InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
NorthWest, North, /*Nort
hEast,*/
West,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//18 - AtFrontLeftBorder
{ /*InFrontNorthWest,InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
/*NorthWest,*/ North, NorthE
ast,
/*West,*/
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error},
//19 - Nothin'
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//20 - AtTopFrontBorder
{ /*InFrontNorthWest,InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//21 - AtTopRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
/*NorthWest, North, NorthE
ast,*/
West,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//22 - AtTopLeftFrontBorder
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//23 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//24 - AtBottomFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
NorthWest, North, NorthE
ast,
West,
Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//25 - AtBottomRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
NorthWest, North, /*Nort
hEast,*/
West,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//26 - AtBottomLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,*/
/*NorthWest,*/ North, NorthE
ast,
/* West, */
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error},
//27 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//28 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//29 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//30 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//31 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//32 - AtRearBorder
{ InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
NorthWest, North, NorthE
ast,
West},
//33 - AtRearRightBorder
{ InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
NorthWest, North, NorthE
ast,
West},
//34 - AtRearLeftBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFron
tNorthEast,
/*InFrontWest,*/ InFront, InFron
tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron
tSouthEast,
/*NorthWest,*/ North, NorthE
ast,
/*West*/
Error, Error, Error, Error, Error},
//35 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//36 - AtTopRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,*/
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
/*NorthWest, North, NorthE
ast,*/
West,
Error, Error, Error, Error, Error, Error}
,
//37 - AtTopRightRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,*/
InFrontWest, InFront, /*InFr
ontEast,*/
InFrontSouthWest, InFrontSouth, /*InFr
ontSouthEast,*/
/*NorthWest, North, NorthE
ast,*/
West,
Error, Error, Error, Error, Error, Error,
Error, Error},
//38 - AtTopLeftRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFron
tNorthEast,*/
/*InFrontWest,*/ InFront, InFron
tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron
tSouthEast,
/*NorthWest, North, NorthEast,*/
/*West,*/
Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//39 - Nothin
{ Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error},
//40 - AtBottomRearBorder
{ InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
NorthWest, North, NorthE
ast,
West},
//41 - AtBottomRightRearBorder
{ InFrontNorthWest, InFrontNorth, InFron
tNorthEast,
InFrontWest, InFront, InFron
tEast,
InFrontSouthWest, InFrontSouth, InFron
tSouthEast,
NorthWest, North, NorthE
ast,
West},
//42 - AtBottomLeftRearBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFron
tNorthEast,
/*InFrontWest,*/ InFront, InFron
tEast,
/*InFrontSouthWest,InFrontSouth, InFron
tSouthEast,*/
/*NorthWest,*/ North, NorthE
ast,
/*West*/
Error, Error, Error, Error, Error, Error,
Error}
};
return c[b][index];
} }
/** transform direction code into corresponding Diff3D offset. /** transform direction code into corresponding Diff3D offset.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff3D const & diff(Direction code) static Diff3D const & diff(Direction code)
{ {
static Diff3D d[] = { Diff3D( -1, -1, -1), //InFrontNorthWest return StaticData<0>::d[code];
Diff3D( 0, -1, -1), //InFrontNorth
Diff3D( 1, -1, -1), //InFrontNorthEast
Diff3D( -1, 0, -1), //InFrontWest
Diff3D( 0, 0, -1), //InFront
Diff3D( 1, 0, -1), //InFrontEast
Diff3D( -1, 1, -1), //InFrontSouthWest
Diff3D( 0, 1, -1), //InFrontSouth
Diff3D( 1, 1, -1), //InFrontSouthEast
Diff3D( -1, -1, 0), //NorthWest
Diff3D( 0, -1, 0), //North
Diff3D( 1, -1, 0), //NorthEast
Diff3D( -1, 0, 0), //West
Diff3D( 1, 0, 0), //East
Diff3D( -1, 1, 0), //SouthWest
Diff3D( 0, 1, 0), //South
Diff3D( 1, 1, 0), //SouthEast
Diff3D( -1, -1, 1), //BehindNorthWest
Diff3D( 0, -1, 1), //BehindNorth
Diff3D( 1, -1, 1), //BehindNorthEast
Diff3D( -1, 0, 1), //BehindWest
Diff3D( 0, 0, 1), //Behind
Diff3D( 1, 0, 1), //BehindEast
Diff3D( -1, 1, 1), //BehindSouthWest
Diff3D( 0, 1, 1), //BehindSouth
Diff3D( 1, 1, 1), //BehindSouthEast
};
return d[code];
} }
/** Equivalent to <tt>diff(static_cast<Direction>(code))</tt>. /** Equivalent to <tt>diff(static_cast<Direction>(code))</tt>.
(note: there is no bounds checking on the code you pass.) (note: there is no bounds checking on the code you pass.)
*/ */
static Diff3D const & diff(int code) { return diff(static_cast<Directio n>(code)); } static Diff3D const & diff(int code) { return diff(static_cast<Directio n>(code)); }
/** Equivalent to <tt>diff(code)[dim]</tt> */ /** Equivalent to <tt>diff(code)[dim]</tt> */
static int diff(Direction code, int dim) { return diff(code)[dim]; } static int diff(Direction code, int dim) { return diff(code)[dim]; }
skipping to change at line 1590 skipping to change at line 876
static const Direction BehindNorthEast = NeighborCode3D::BehindNorthEast ; /**< Export NeighborCode3D::BehindNorthEast to namespace Neighborho od3DTwentySix */ static const Direction BehindNorthEast = NeighborCode3D::BehindNorthEast ; /**< Export NeighborCode3D::BehindNorthEast to namespace Neighborho od3DTwentySix */
static const Direction BehindWest = NeighborCode3D::BehindWest; /**< Export NeighborCode3D::BehindWest to namespace Neighborhood3DT wentySix */ static const Direction BehindWest = NeighborCode3D::BehindWest; /**< Export NeighborCode3D::BehindWest to namespace Neighborhood3DT wentySix */
static const Direction Behind = NeighborCode3D::Behind; /**< Export NeighborCode3D::Behind to namespace Neighborhood3DTwent ySix */ static const Direction Behind = NeighborCode3D::Behind; /**< Export NeighborCode3D::Behind to namespace Neighborhood3DTwent ySix */
static const Direction BehindEast = NeighborCode3D::BehindEast; /**< Export NeighborCode3D::BehindEast to namespace Neighborhood3DT wentySix */ static const Direction BehindEast = NeighborCode3D::BehindEast; /**< Export NeighborCode3D::BehindEast to namespace Neighborhood3DT wentySix */
static const Direction BehindSouthWest = NeighborCode3D::BehindSouthWest ; /**< Export NeighborCode3D::BehindSouthWest to namespace Neighborho od3DTwentySix */ static const Direction BehindSouthWest = NeighborCode3D::BehindSouthWest ; /**< Export NeighborCode3D::BehindSouthWest to namespace Neighborho od3DTwentySix */
static const Direction BehindSouth = NeighborCode3D::BehindSouth; /**< Export NeighborCode3D::BehindSouth to namespace Neighborhood3D TwentySix */ static const Direction BehindSouth = NeighborCode3D::BehindSouth; /**< Export NeighborCode3D::BehindSouth to namespace Neighborhood3D TwentySix */
static const Direction BehindSouthEast = NeighborCode3D::BehindSouthEast ; /**< Export NeighborCode3D::BehindSouthEast to namespace Neighborho od3DTwentySix */ static const Direction BehindSouthEast = NeighborCode3D::BehindSouthEast ; /**< Export NeighborCode3D::BehindSouthEast to namespace Neighborho od3DTwentySix */
static const Direction DirectionCount = NeighborCode3D::DirectionCount; /**< Export NeighborCode3D::DirectionCount to namespace Neighborhoo d3DTwentySix */ static const Direction DirectionCount = NeighborCode3D::DirectionCount; /**< Export NeighborCode3D::DirectionCount to namespace Neighborhoo d3DTwentySix */
template <int DUMMY>
unsigned int NeighborCode3D::StaticData<DUMMY>::b[] = {
1 << InFrontNorthWest,
1 << InFrontNorth,
1 << InFrontNorthEast,
1 << InFrontWest,
1 << InFront,
1 << InFrontEast,
1 << InFrontSouthWest,
1 << InFrontSouth,
1 << InFrontSouthEast,
1 << NorthWest,
1 << North,
1 << NorthEast,
1 << West,
1 << East,
1 << SouthWest,
1 << South,
1 << SouthEast,
1 << BehindNorthWest,
1 << BehindNorth,
1 << BehindNorthEast,
1 << BehindWest,
1 << Behind,
1 << BehindEast,
1 << BehindSouthWest,
1 << BehindSouth,
1 << BehindSouthEast
};
template <int DUMMY>
unsigned int NeighborCode3D::StaticData<DUMMY>::c[] = {
26, 17, 17, 0, 17, 11, 11, 0, 17, 11,
11, 0, 0, 0, 0, 0, 17, 11, 11, 0,
11, 7, 7, 0, 11, 7, 7, 0, 0, 0,
0, 0, 17, 11, 11, 0, 11, 7, 7, 0,
11, 7, 7};
template <int DUMMY>
Direction NeighborCode3D::StaticData<DUMMY>::bd[43][26] = {
//0 - NotAtBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West, East,
SouthWest, South, SouthEast,
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast},
//1 - AtRightBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//2 - AtLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSouthEast,
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//3 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//4 - AtTopBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//5 - AtTopRightBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//6 - AtTopLeftBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
/*BehindWest, */ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//7 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//8 - AtBottomBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West, East,
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//9 - AtBottomRightBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//10 - AtBottomLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//11 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//12 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//13 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//14 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//15 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//16 - AtFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West, East,
SouthWest, South, SouthEast,
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//17 - AtFrontRightBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//18 - AtFrontLeftBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//19 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//20 - AtTopFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//21 - AtTopRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
BehindSouthWest, BehindSouth, /*BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//22 - AtTopLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,*/
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest,*/ BehindSouth, BehindSouthEast,
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//23 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//24 - AtBottomFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West, East,
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//25 - AtBottomRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /* East,*/
/*SouthWest, South, SouthEast,*/
BehindNorthWest, BehindNorth, /*BehindNorthEast,*/
BehindWest, Behind, /*BehindEast,*/
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//26 - AtBottomLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest,*/ BehindNorth, BehindNorthEast,
/*BehindWest,*/ Behind, BehindEast,
/*BehindSouthWest, BehindSouth, BehindSouthEast*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//27 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//28 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//29 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//30 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//31 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//32 - AtRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//33 - AtRearRightBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//34 - AtRearLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSouthEast,
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//35 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//36 - AtTopRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
West, East,
SouthWest, South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//37 - AtTopRightRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West, /*East,*/
SouthWest, South, /*SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//38 - AtTopLeftRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/ InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
/*West,*/ East,
/*SouthWest,*/ South, SouthEast,
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//39 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//40 - AtBottomRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West, East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error},
//41 - AtBottomRightRearBorder
{ InFrontNorthWest, InFrontNorth, /*InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West, /*East,*/
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error},
//42 - AtBottomLeftRearBorder
{ /*InFrontNorthWest,*/ InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/ East,
/*SouthWest, South, SouthEast,*/
/*BehindNorthWest, BehindNorth, BehindNorthEast,
BehindWest, Behind, BehindEast,
BehindSouthWest, BehindSouth, BehindSouthEast,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error}
};
template <int DUMMY>
Direction NeighborCode3D::StaticData<DUMMY>::bc[43][13] = {
//0 - NotAtBorder -----> should never be used
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West},
//1 - AtRightBorder
{ InFrontNorthWest, InFrontNorth, /* InFrontNorthEast, */
InFrontWest, InFront, /* InFrontEast, */
InFrontSouthWest, InFrontSouth, /* InFrontSouthEast, */
NorthWest, North, /* NorthEast, */
West,
Error, Error, Error, Error},
//2 - AtLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth,InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/InFrontSouth, InFrontSouthEast,
/*NorthWest,*/ North, NorthEast,
/*West*/
Error, Error, Error, Error, Error},
//3 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//4 - AtTopBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error},
//5 - AtTopRightBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error, Error, Error},
//6 - AtTopLeftBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,*/
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
/*West,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//7 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//8 - AtBottomBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
/* InFrontSouthWest, InFrontSouth, InFrontSouthEast, */
NorthWest, North, NorthEast,
West,
Error, Error, Error},
//9 - AtBottomRightBorder
{ InFrontNorthWest, InFrontNorth, /* InFrontNorthEast, */
InFrontWest, InFront, /* InFrontEast, */
/* InFrontSouthWest, InFrontSouth, InFrontSouthEast, */
NorthWest, North, /* NorthEast, */
West,
Error, Error, Error,Error, Error, Error},
//10 - AtBottomLeftBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest, InFrontSouth, InFrontSouthEast, */
/*NorthWest,*/ North, NorthEast,
/*West*/
Error, Error, Error, Error, Error, Error, Error},
//11 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//12 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//13 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//14 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//15 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//16 - AtFrontBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//17 - AtFrontRightBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West,
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error}
,
//18 - AtFrontLeftBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error},
//19 - Nothin'
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//20 - AtTopFrontBorder
{ /*InFrontNorthWest,InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error},
//21 - AtTopRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error},
//22 - AtTopLeftFrontBorder
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//23 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//24 - AtBottomFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, NorthEast,
West,
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//25 - AtBottomRightFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
NorthWest, North, /*NorthEast,*/
West,
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error}
,
//26 - AtBottomLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/* West, */
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error},
//27 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//28 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//29 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//30 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//31 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//32 - AtRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West},
//33 - AtRearRightBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West},
//34 - AtRearLeftBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/InFrontSouth, InFrontSouthEast,
/*NorthWest,*/ North, NorthEast,
/*West*/
Error, Error, Error, Error, Error},
//35 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//36 - AtTopRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error},
//37 - AtTopRightRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
InFrontWest, InFront, /*InFrontEast,*/
InFrontSouthWest, InFrontSouth, /*InFrontSouthEast,*/
/*NorthWest, North, NorthEast,*/
West,
Error, Error, Error, Error, Error, Error, Error, Error},
//38 - AtTopLeftRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFrontNorthEast,*/
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,*/InFrontSouth, InFrontSouthEast,
/*NorthWest, North, NorthEast,*/
/*West,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error},
//39 - Nothin
{ Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error},
//40 - AtBottomRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West},
//41 - AtBottomRightRearBorder
{ InFrontNorthWest, InFrontNorth, InFrontNorthEast,
InFrontWest, InFront, InFrontEast,
InFrontSouthWest, InFrontSouth, InFrontSouthEast,
NorthWest, North, NorthEast,
West},
//42 - AtBottomLeftRearBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFrontNorthEast,
/*InFrontWest,*/ InFront, InFrontEast,
/*InFrontSouthWest,InFrontSouth, InFrontSouthEast,*/
/*NorthWest,*/ North, NorthEast,
/*West*/
Error, Error, Error, Error, Error, Error, Error}
};
template <int DUMMY>
Diff3D NeighborCode3D::StaticData<DUMMY>::d[] = {
Diff3D( -1, -1, -1), //InFrontNorthWest
Diff3D( 0, -1, -1), //InFrontNorth
Diff3D( 1, -1, -1), //InFrontNorthEast
Diff3D( -1, 0, -1), //InFrontWest
Diff3D( 0, 0, -1), //InFront
Diff3D( 1, 0, -1), //InFrontEast
Diff3D( -1, 1, -1), //InFrontSouthWest
Diff3D( 0, 1, -1), //InFrontSouth
Diff3D( 1, 1, -1), //InFrontSouthEast
Diff3D( -1, -1, 0), //NorthWest
Diff3D( 0, -1, 0), //North
Diff3D( 1, -1, 0), //NorthEast
Diff3D( -1, 0, 0), //West
Diff3D( 1, 0, 0), //East
Diff3D( -1, 1, 0), //SouthWest
Diff3D( 0, 1, 0), //South
Diff3D( 1, 1, 0), //SouthEast
Diff3D( -1, -1, 1), //BehindNorthWest
Diff3D( 0, -1, 1), //BehindNorth
Diff3D( 1, -1, 1), //BehindNorthEast
Diff3D( -1, 0, 1), //BehindWest
Diff3D( 0, 0, 1), //Behind
Diff3D( 1, 0, 1), //BehindEast
Diff3D( -1, 1, 1), //BehindSouthWest
Diff3D( 0, 1, 1), //BehindSouth
Diff3D( 1, 1, 1), //BehindSouthEast
};
}//namespace Neighborhood3DTwentySix }//namespace Neighborhood3DTwentySix
/** Export \ref vigra::Neighborhood3DTwentySix::NeighborCode3D into the sco pe of namespace vigra. /** Export \ref vigra::Neighborhood3DTwentySix::NeighborCode3D into the sco pe of namespace vigra.
*/ */
typedef Neighborhood3DTwentySix::NeighborCode3D NeighborCode3DTwentySix; typedef Neighborhood3DTwentySix::NeighborCode3D NeighborCode3DTwentySix;
//@} //@}
} // namespace vigra } // namespace vigra
 End of changes. 16 change blocks. 
1213 lines changed or deleted 1004 lines changed or added


 watersheds.hxx   watersheds.hxx 
skipping to change at line 48 skipping to change at line 48
#include <functional> #include <functional>
#include "mathutil.hxx" #include "mathutil.hxx"
#include "stdimage.hxx" #include "stdimage.hxx"
#include "pixelneighborhood.hxx" #include "pixelneighborhood.hxx"
#include "localminmax.hxx" #include "localminmax.hxx"
#include "labelimage.hxx" #include "labelimage.hxx"
#include "seededregiongrowing.hxx" #include "seededregiongrowing.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "union_find.hxx" #include "union_find.hxx"
#include "multi_shape.hxx"
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
unsigned int watershedLabeling(SrcIterator upperlefts, unsigned int watershedLabeling(SrcIterator upperlefts,
SrcIterator lowerrights, SrcAccessor sa, SrcIterator lowerrights, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood) Neighborhood)
skipping to change at line 71 skipping to change at line 72
int w = lowerrights.x - upperlefts.x; int w = lowerrights.x - upperlefts.x;
int h = lowerrights.y - upperlefts.y; int h = lowerrights.y - upperlefts.y;
int x,y; int x,y;
SrcIterator ys(upperlefts); SrcIterator ys(upperlefts);
SrcIterator xs(ys); SrcIterator xs(ys);
DestIterator yd(upperleftd); DestIterator yd(upperleftd);
DestIterator xd(yd); DestIterator xd(yd);
// temporary image to store region labels // temporary image to store region labels
detail::UnionFindArray<LabelType> labels; UnionFindArray<LabelType> labels;
// initialize the neighborhood circulators // initialize the neighborhood circulators
NeighborOffsetCirculator<Neighborhood> ncstart(Neighborhood::CausalFirs t); NeighborOffsetCirculator<Neighborhood> ncstart(Neighborhood::CausalFirs t);
NeighborOffsetCirculator<Neighborhood> ncstartBorder(Neighborhood::Nort h); NeighborOffsetCirculator<Neighborhood> ncstartBorder(Neighborhood::Nort h);
NeighborOffsetCirculator<Neighborhood> ncend(Neighborhood::CausalLast); NeighborOffsetCirculator<Neighborhood> ncend(Neighborhood::CausalLast);
++ncend; ++ncend;
NeighborOffsetCirculator<Neighborhood> ncendBorder(Neighborhood::North) ; NeighborOffsetCirculator<Neighborhood> ncendBorder(Neighborhood::North) ;
++ncendBorder; ++ncendBorder;
// pass 1: scan image from upper left to lower right // pass 1: scan image from upper left to lower right
skipping to change at line 94 skipping to change at line 95
// Each component will be represented by a tree of pixels. Each // Each component will be represented by a tree of pixels. Each
// pixel contains the scan order address of its parent in the // pixel contains the scan order address of its parent in the
// tree. In order for pass 2 to work correctly, the parent must // tree. In order for pass 2 to work correctly, the parent must
// always have a smaller scan order address than the child. // always have a smaller scan order address than the child.
// Therefore, we can merge trees only at their roots, because the // Therefore, we can merge trees only at their roots, because the
// root of the combined tree must have the smallest scan order // root of the combined tree must have the smallest scan order
// address among all the tree's pixels/ nodes. The root of each // address among all the tree's pixels/ nodes. The root of each
// tree is distinguished by pointing to itself (it contains its // tree is distinguished by pointing to itself (it contains its
// own scan order address). This condition is enforced whenever a // own scan order address). This condition is enforced whenever a
// new region is found or two regions are merged // new region is found or two regions are merged
da.set(labels.finalizeLabel(labels.nextFreeLabel()), xd); da.set(labels.finalizeIndex(labels.nextFreeIndex()), xd);
++xs.x; ++xs.x;
++xd.x; ++xd.x;
for(x = 1; x != w; ++x, ++xs.x, ++xd.x) for(x = 1; x != w; ++x, ++xs.x, ++xd.x)
{ {
if((sa(xs) & Neighborhood::directionBit(Neighborhood::West)) || if((sa(xs) & Neighborhood::directionBit(Neighborhood::West)) ||
(sa(xs, Neighborhood::west()) & Neighborhood::directionBit(Neigh borhood::East))) (sa(xs, Neighborhood::west()) & Neighborhood::directionBit(Neigh borhood::East)))
{ {
da.set(da(xd, Neighborhood::west()), xd); da.set(da(xd, Neighborhood::west()), xd);
} }
else else
{ {
da.set(labels.finalizeLabel(labels.nextFreeLabel()), xd); da.set(labels.finalizeIndex(labels.nextFreeIndex()), xd);
} }
} }
++ys.y; ++ys.y;
++yd.y; ++yd.y;
for(y = 1; y != h; ++y, ++ys.y, ++yd.y) for(y = 1; y != h; ++y, ++ys.y, ++yd.y)
{ {
xs = ys; xs = ys;
xd = yd; xd = yd;
for(x = 0; x != w; ++x, ++xs.x, ++xd.x) for(x = 0; x != w; ++x, ++xs.x, ++xd.x)
{ {
NeighborOffsetCirculator<Neighborhood> nc(x == w-1 NeighborOffsetCirculator<Neighborhood> nc(x == w-1
? ncstartBorder ? ncstartBorder
: ncstart); : ncstart);
NeighborOffsetCirculator<Neighborhood> nce(x == 0 NeighborOffsetCirculator<Neighborhood> nce(x == 0
? ncendBorder ? ncendBorder
: ncend); : ncend);
LabelType currentLabel = labels.nextFreeLabel(); LabelType currentIndex = labels.nextFreeIndex();
for(; nc != nce; ++nc) for(; nc != nce; ++nc)
{ {
if((sa(xs) & nc.directionBit()) || (sa(xs, *nc) & nc.opposi teDirectionBit())) if((sa(xs) & nc.directionBit()) || (sa(xs, *nc) & nc.opposi teDirectionBit()))
{ {
currentLabel = labels.makeUnion(da(xd,*nc), currentLabe l); currentIndex = labels.makeUnion(da(xd,*nc), currentInde x);
} }
} }
da.set(labels.finalizeLabel(currentLabel), xd); da.set(labels.finalizeIndex(currentIndex), xd);
} }
} }
unsigned int count = labels.makeContiguous(); unsigned int count = labels.makeContiguous();
// pass 2: assign one label to each region (tree) // pass 2: assign one label to each region (tree)
// so that labels form a consecutive sequence 1, 2, ... // so that labels form a consecutive sequence 1, 2, ...
yd = upperleftd; yd = upperleftd;
for(y=0; y != h; ++y, ++yd.y) for(y=0; y != h; ++y, ++yd.y)
{ {
DestIterator xd(yd); DestIterator xd(yd);
for(x = 0; x != w; ++x, ++xd.x) for(x = 0; x != w; ++x, ++xd.x)
{ {
da.set(labels[da(xd)], xd); da.set(labels.findLabel(da(xd)), xd);
} }
} }
return count; return count;
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
unsigned int watershedLabeling(triple<SrcIterator, SrcIterator, SrcAccessor > src, unsigned int watershedLabeling(triple<SrcIterator, SrcIterator, SrcAccessor > src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
skipping to change at line 320 skipping to change at line 321
//@{ //@{
/**\brief Options object for generateWatershedSeeds(). /**\brief Options object for generateWatershedSeeds().
* *
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br> <b>\#include</b> \<vigra/watersheds.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
IImage seeds(boundary_indicator.size()); MultiArray<2, float> boundary_indicator(w, h);
MultiArray<2, int> seeds(boundary_indicator.shape());
// detect all minima in 'boundary_indicator' that are below gray le vel 22 // detect all minima in 'boundary_indicator' that are below gray le vel 22
generateWatershedSeeds(srcImageRange(boundary_indicator), generateWatershedSeeds(boundary_indicator, seeds,
destImage(seeds),
SeedOptions().minima().threshold(22.0)); SeedOptions().minima().threshold(22.0));
\endcode \endcode
*/ */
class SeedOptions class SeedOptions
{ {
public: public:
enum DetectMinima { LevelSets, Minima, ExtendedMinima, Unspecified }; enum DetectMinima { LevelSets, Minima, ExtendedMinima, Unspecified };
double thresh; double thresh;
DetectMinima mini; DetectMinima mini;
skipping to change at line 432 skipping to change at line 433
of by looking at level sets (i.e. regions where the boundaryness is bel ow a threshold). of by looking at level sets (i.e. regions where the boundaryness is bel ow a threshold).
Both methods can also be combined, so that only minima below a threshol d are returned. Both methods can also be combined, so that only minima below a threshol d are returned.
The particular seeding strategy is specified by the <tt>options</tt> ob ject The particular seeding strategy is specified by the <tt>options</tt> ob ject
(see \ref SeedOptions). (see \ref SeedOptions).
The pixel type of the input image must be <tt>LessThanComparable</tt>. The pixel type of the input image must be <tt>LessThanComparable</tt>.
The pixel type of the output image must be large enough to hold the lab els for all seeds. The pixel type of the output image must be large enough to hold the lab els for all seeds.
(typically, you will use <tt>UInt32</tt>). The function will label seed s by consecutive integers (typically, you will use <tt>UInt32</tt>). The function will label seed s by consecutive integers
(starting from 1) and returns the largest label it used. (starting from 1) and returns the largest label it used.
Pass \ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode to d Pass \ref vigra::NeighborhoodType "IndirectNeighborhood" or \ref vigra:
etermine the :NeighborhoodType "DirectNeighborhood"
(first form of the function)
or \ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode (secon
d and third forms) to determine the
neighborhood where pixel values are compared. neighborhood where pixel values are compared.
The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use arbitrary-dimensional arrays:
\code
namespace vigra {
template <unsigned int N, class T, class S1,
class Label, class S2>
Label
generateWatershedSeeds(MultiArrayView<N, T, S1> const & data,
MultiArrayView<N, Label, S2> seeds,
NeighborhoodType neighborhood = IndirectNeig
hborhood,
SeedOptions const & options = SeedOptions())
;
}
\endcode
\deprecatedAPI{generateWatershedSeeds}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode> class Neighborhood = EightNeighborCode>
unsigned int unsigned int
generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrig hts, SrcAccessor sa, generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrig hts, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood = EightNeighborCod e(), Neighborhood neighborhood = EightNeighborCod e(),
SeedOptions const & options = SeedOptions()) ; SeedOptions const & options = SeedOptions()) ;
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode> class Neighborhood = EightNeighborCode>
unsigned int unsigned int
generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor > src, generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor > src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood = EightNeighborCod e(), Neighborhood neighborhood = EightNeighborCod e(),
SeedOptions const & options = SeedOptions()) ; SeedOptions const & options = SeedOptions()) ;
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br> <b>\#include</b> \<vigra/multi_watersheds.hxx\> (MultiArray variant)<br
>
<b>\#include</b> \<vigra/watersheds.hxx\> (deprecated variants)<br>
Namespace: vigra Namespace: vigra
For detailed examples see watershedsRegionGrowing(). For detailed examples see \ref watershedsMultiArray() and \ref watershe dsRegionGrowing().
*/ */
doxygen_overloaded_function(template <...> unsigned int generateWatershedSe eds) doxygen_overloaded_function(template <...> unsigned int generateWatershedSe eds)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
unsigned int unsigned int
generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrights, Src Accessor sa, generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrights, Src Accessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood, Neighborhood neighborhood,
skipping to change at line 558 skipping to change at line 574
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
SeedOptions const & options = SeedOptions()) SeedOptions const & options = SeedOptions())
{ {
return generateWatershedSeeds(src.first, src.second, src.third, return generateWatershedSeeds(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
EightNeighborCode(), options); EightNeighborCode(), options);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* watersheds */ /* watershedsUnionFind */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Region segmentation by means of the union-find watershed algorit hm. /** \brief Region segmentation by means of the union-find watershed algorit hm.
Note: This function is largely obsolete, \ref watershedsMultiArray() sh
ould be
preferred unless top speed is required.
This function implements the union-find version of the watershed algori thms This function implements the union-find version of the watershed algori thms
as described in described as algorithm 4.7 in
J. Roerdink, R. Meijster: "<em>The watershed transform: definitions, al J. Roerdink, R. Meijster: <em>"The watershed transform: definitions, al
gorithms, gorithms,
and parallelization strategies</em>", Fundamenta Informaticae, 41:187-2 and parallelization strategies"</em>, Fundamenta Informaticae, 41:187-2
28, 2000 28, 2000
The source image is a boundary indicator such as the gaussianGradientMa gnitude() The source image is a boundary indicator such as the gaussianGradientMa gnitude()
or the trace of the \ref boundaryTensor(). Local minima of the boundary indicator or the trace of the \ref boundaryTensor(). Local minima of the boundary indicator
are used as region seeds, and all other pixels are recursively assigned to the same are used as region seeds, and all other pixels are recursively assigned to the same
region as their lowest neighbor. Pass \ref vigra::EightNeighborCode or region as their lowest neighbor. Pass \ref vigra::EightNeighborCode or
\ref vigra::FourNeighborCode to determine the neighborhood where pixel values \ref vigra::FourNeighborCode to determine the neighborhood where pixel values
are compared. The pixel type of the input image must be <tt>LessThanCom parable</tt>. are compared. The pixel type of the input image must be <tt>LessThanCom parable</tt>.
The function uses accessors. The function uses accessors.
Note that VIGRA provides an alternative implementation of the watershed transform via Note that VIGRA provides an alternative implementation of the watershed transform via
\ref watershedsRegionGrowing(). It is slower, but offers many more conf iguration options. \ref watershedsRegionGrowing(). It is slower, but offers many more conf iguration options.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Neighborhood>
unsigned int
watershedsUnionFind(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Neighborhood neighborhood = EightNeighborCode()
);
}
\endcode
\deprecatedAPI{watershedsUnionFind}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode> class Neighborhood = EightNeighborCode>
unsigned int unsigned int
watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights , SrcAccessor sa, watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights , SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood = EightNeighborCode() ) Neighborhood neighborhood = EightNeighborCode() )
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode> class Neighborhood = EightNeighborCode>
unsigned int unsigned int
watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> s rc, watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> s rc,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood = EightNeighborCode() ) Neighborhood neighborhood = EightNeighborCode() )
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br> <b>\#include</b> \<vigra/watersheds.hxx\><br>
Namespace: vigra Namespace: vigra
Example: watersheds of the gradient magnitude. Example: watersheds of the gradient magnitude.
\code \code
MultiArray<2, float> in(w,h);
... // read input data
// compute gradient magnitude as boundary indicator
MultiArray<2, float> gradMag(w, h);
gaussianGradientMagnitude(src, gradMag, 3.0);
// the pixel type of the destination image must be large enough to hold
// numbers up to 'max_region_label' to prevent overflow
MultiArray<2, unsigned int> labeling(w,h);
unsigned int max_region_label = watershedsUnionFind(gradMag, labeling);
\endcode
\deprecatedUsage{watershedsUnionFind}
Example: watersheds of the gradient magnitude.
\code
vigra::BImage in(w,h); vigra::BImage in(w,h);
... // read input data ... // read input data
// compute gradient magnitude as boundary indicator // compute gradient magnitude as boundary indicator
vigra::FImage gradMag(w, h); vigra::FImage gradMag(w, h);
gaussianGradientMagnitude(srcImageRange(src), destImage(gradMag), 3.0); gaussianGradientMagnitude(srcImageRange(src), destImage(gradMag), 3.0);
// the pixel type of the destination image must be large enough to hold // the pixel type of the destination image must be large enough to hold
// numbers up to 'max_region_label' to prevent overflow // numbers up to 'max_region_label' to prevent overflow
vigra::IImage labeling(w,h); vigra::IImage labeling(w,h);
int max_region_label = watershedsUnionFind(srcImageRange(gradMag), dest Image(labeling)); int max_region_label = watershedsUnionFind(srcImageRange(gradMag), dest Image(labeling));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestIterator dest_upperleft; DestIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
// compare src values // compare src values
src_accessor(src_upperleft) <= src_accessor(src_upperleft) src_accessor(src_upperleft) <= src_accessor(src_upperleft)
// set result // set result
int label; int label;
dest_accessor.set(label, dest_upperleft); dest_accessor.set(label, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int watershedsUnionFind ) doxygen_overloaded_function(template <...> unsigned int watershedsUnionFind )
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
unsigned int unsigned int
watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights, SrcAcc essor sa, watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights, SrcAcc essor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood) Neighborhood neighborhood)
skipping to change at line 680 skipping to change at line 729
DestIterator upperleftd, DestAccessor da) DestIterator upperleftd, DestAccessor da)
{ {
return watershedsUnionFind(upperlefts, lowerrights, sa, upperleftd, da, EightNeighborCode()); return watershedsUnionFind(upperlefts, lowerrights, sa, upperleftd, da, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
inline unsigned int inline unsigned int
watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> src, watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, Neighborhood neighborhood ) pair<DestIterator, DestAccessor> dest, Neighborhood nei ghborhood)
{ {
return watershedsUnionFind(src.first, src.second, src.third, return watershedsUnionFind(src.first, src.second, src.third,
dest.first, dest.second, neighborhood); dest.first, dest.second, neighborhood);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline unsigned int inline unsigned int
watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> src, watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest) pair<DestIterator, DestAccessor> dest)
{ {
return watershedsUnionFind(src.first, src.second, src.third, return watershedsUnionFind(src.first, src.second, src.third,
dest.first, dest.second); dest.first, dest.second);
}
template <class T1, class S1,
class T2, class S2,
class Neighborhood>
inline unsigned int
watershedsUnionFind(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest, Neighborhood neighborho
od)
{
return watershedsUnionFind(srcImageRange(src),
destImage(dest), neighborhood);
}
template <class T1, class S1,
class T2, class S2>
inline unsigned int
watershedsUnionFind(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest)
{
vigra_precondition(src.shape() == dest.shape(),
"watershedsUnionFind(): shape mismatch between input and output.");
return watershedsUnionFind(srcImageRange(src),
destImage(dest));
} }
/** \brief Options object for watershedsRegionGrowing(). /** \brief Options object for watershed algorithms.
<b> Usage:</b> <b> Usage:</b>
see watershedsRegionGrowing() for detailed examples. see \ref watershedsMultiArray() and watershedsRegionGrowing() for detai led examples.
*/ */
class WatershedOptions class WatershedOptions
{ {
public: public:
enum Method { RegionGrowing, UnionFind };
double max_cost, bias; double max_cost, bias;
SRGType terminate; SRGType terminate;
Method method;
unsigned int biased_label, bucket_count; unsigned int biased_label, bucket_count;
SeedOptions seed_options; SeedOptions seed_options;
/** \brief Create options object with default settings. /** \brief Create options object with default settings.
Defaults are: perform complete grow (all pixels are assigned to regions), Defaults are: perform complete grow (all pixels are assigned to regions),
use standard algorithm, assume that the destination image alrea dy contains use standard algorithm, assume that the destination image alrea dy contains
region seeds. region seeds.
*/ */
WatershedOptions() WatershedOptions()
: max_cost(0.0), : max_cost(0.0),
bias(1.0), bias(1.0),
terminate(CompleteGrow), terminate(CompleteGrow),
method(RegionGrowing),
biased_label(0), biased_label(0),
bucket_count(0), bucket_count(0),
seed_options(SeedOptions().unspecified()) seed_options(SeedOptions().unspecified())
{} {}
/** \brief Perform complete grow. /** \brief Perform complete grow.
That is, all pixels are assigned to regions, without explicit c ontours That is, all pixels are assigned to regions, without explicit c ontours
in between. in between.
skipping to change at line 787 skipping to change at line 863
when the input boundary indicator image contains integers when the input boundary indicator image contains integers
in the range <tt>[0, ..., bucket_count-1]</tt>. Since in the range <tt>[0, ..., bucket_count-1]</tt>. Since
these boundary indicators are typically represented as these boundary indicators are typically represented as
UInt8 images, the default <tt>bucket_count</tt> is 256. UInt8 images, the default <tt>bucket_count</tt> is 256.
Default: don't use the turbo algorithm Default: don't use the turbo algorithm
*/ */
WatershedOptions & turboAlgorithm(unsigned int bucket_count = 256) WatershedOptions & turboAlgorithm(unsigned int bucket_count = 256)
{ {
this->bucket_count = bucket_count; this->bucket_count = bucket_count;
method = RegionGrowing;
return *this; return *this;
} }
/** \brief Specify seed options. /** \brief Specify seed options.
In this case, watershedsRegionGrowing() assumes that the destin ation In this case, watershedsRegionGrowing() assumes that the destin ation
image does not yet contain seeds. It will therefore call image does not yet contain seeds. It will therefore call
generateWatershedSeeds() and pass on the seed options. generateWatershedSeeds() and pass on the seed options.
Default: don't compute seeds (i.e. assume that destination imag e already Default: don't compute seeds (i.e. assume that destination imag e already
skipping to change at line 820 skipping to change at line 897
with a factor slightly below 1. with a factor slightly below 1.
Default: don't bias any region. Default: don't bias any region.
*/ */
WatershedOptions & biasLabel(unsigned int label, double factor) WatershedOptions & biasLabel(unsigned int label, double factor)
{ {
biased_label = label; biased_label = label;
bias = factor; bias = factor;
return *this; return *this;
} }
/** \brief Specify the algorithm to be used.
Possible values are <tt>WatershedOptions::RegionGrowing</tt> an
d
<tt>WatershedOptions::UnionFind</tt>. The latter algorithm is f
astest
but doesn't support seeds and any of the other options.
Default: RegionGrowing.
*/
WatershedOptions & useMethod(Method method)
{
this->method = method;
return *this;
}
/** \brief Use region-growing watershed.
Use this method when you want to specify seeds explicitly (seed
ed watersheds)
or use any of the other options.
Default: true.
*/
WatershedOptions & regionGrowing()
{
method = RegionGrowing;
return *this;
}
/** \brief Use union-find watershed.
This is the fasted method, but it doesn't support seeds and any
of the other
options (they will be silently ignored).
Default: false.
*/
WatershedOptions & unionFind()
{
method = UnionFind;
return *this;
}
}; };
namespace detail { namespace detail {
template <class CostType, class LabelType> template <class CostType, class LabelType>
class WatershedStatistics class WatershedStatistics
{ {
public: public:
typedef SeedRgDirectValueFunctor<CostType> value_type; typedef SeedRgDirectValueFunctor<CostType> value_type;
skipping to change at line 976 skipping to change at line 1093
} }
LabelType biased_label; LabelType biased_label;
value_type stats, biased_stats; value_type stats, biased_stats;
}; };
} // namespace detail } // namespace detail
/** \brief Region segmentation by means of a flooding-based watershed algor ithm. /** \brief Region segmentation by means of a flooding-based watershed algor ithm.
Note: This function is largely obsolete, \ref watershedsMultiArray() sh
ould be
preferred unless top speed is required.
This function implements variants of the watershed algorithm This function implements variants of the watershed algorithm
described in described in
L. Vincent and P. Soille: "<em>Watersheds in digital spaces: An efficie L. Vincent and P. Soille: <em>"Watersheds in digital spaces: An efficie
nt algorithm nt algorithm
based on immersion simulations</em>", IEEE Trans. Patt. Analysis Mach. based on immersion simulations"</em>, IEEE Trans. Patt. Analysis Mach.
Intell. 13(6):583-598, 1991 Intell. 13(6):583-598, 1991
The source image is a boundary indicator such as the gaussianGradientMa gnitude() The source image is a boundary indicator such as the gaussianGradientMa gnitude()
or the trace of the \ref boundaryTensor(), and the destination is a lab el image or the trace of the \ref boundaryTensor(), and the destination is a lab el image
designating membership of each pixel in one of the regions. Plateaus in the boundary designating membership of each point in one of the regions. Plateaus in the boundary
indicator (i.e. regions of constant gray value) are handled via a Eucli dean distance indicator (i.e. regions of constant gray value) are handled via a Eucli dean distance
transform by default. transform by default.
By default, the destination image is assumed to hold seeds for a seeded watershed By default, the destination image is assumed to hold seeds for a seeded watershed
transform. Seeds may, for example, be created by means of generateWater shedSeeds(). transform. Seeds may, for example, be created by means of generateWater shedSeeds().
Note that the seeds will be overridden with the final watershed segment ation. Note that the seeds will be overridden with the final watershed segment ation.
Alternatively, you may provide \ref SeedOptions in order to instruct Alternatively, you may provide \ref SeedOptions in order to instruct
watershedsRegionGrowing() to generate its own seeds (it will call gener ateWatershedSeeds() watershedsRegionGrowing() to generate its own seeds (it will call gener ateWatershedSeeds()
internally). In that case, the destination image should be zero-initial ized. internally). In that case, the destination image should be zero-initial ized.
skipping to change at line 1022 skipping to change at line 1142
memory because it allocates less temporary storage. memory because it allocates less temporary storage.
<li> Whether one region (label) is to be preferred or discouraged by bi asing its cost <li> Whether one region (label) is to be preferred or discouraged by bi asing its cost
with a given factor (smaller than 1 for preference, larger than 1 for discouragement). with a given factor (smaller than 1 for preference, larger than 1 for discouragement).
</ul> </ul>
Note that VIGRA provides an alternative implementation of the watershed transform via Note that VIGRA provides an alternative implementation of the watershed transform via
\ref watershedsUnionFind(). \ref watershedsUnionFind().
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass 2D array views:
\code
namespace vigra {
template <class T1, class S1,
class T2, class S2,
class Neighborhood = EightNeighborCode>
unsigned int
watershedsRegionGrowing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Neighborhood neighborhood = EightNeighborCo
de(),
WatershedOptions const & options = Watershe
dOptions());
template <class T1, class S1,
class T2, class S2>
unsigned int
watershedsRegionGrowing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
WatershedOptions const & options = Watershe
dOptions());
}
\endcode
\deprecatedAPI{watershedsRegionGrowing}
pass \ref ImageIterators and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode> class Neighborhood = EightNeighborCode>
unsigned int unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerri ghts, SrcAccessor sa, watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerri ghts, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood = EightNeighborCo de(), Neighborhood neighborhood = EightNeighborCo de(),
WatershedOptions const & options = Watershe dOptions()); WatershedOptions const & options = Watershe dOptions());
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerri ghts, SrcAccessor sa, watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerri ghts, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
WatershedOptions const & options = Watershe dOptions()); WatershedOptions const & options = Watershe dOptions());
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode> class Neighborhood = EightNeighborCode>
unsigned int unsigned int
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccesso r> src, watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood = EightNeighborCo de(), Neighborhood neighborhood = EightNeighborCo de(),
WatershedOptions const & options = Watershe dOptions()); WatershedOptions const & options = Watershe dOptions());
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int unsigned int
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccesso r> src, watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccesso r> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
WatershedOptions const & options = Watershe dOptions()); WatershedOptions const & options = Watershe dOptions());
} }
\endcode \endcode
\deprecatedEnd
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br> <b>\#include</b> \<vigra/watersheds.hxx\><br>
Namespace: vigra Namespace: vigra
Example: watersheds of the gradient magnitude. Example: watersheds of the gradient magnitude.
\code \code
MultiArray<2, float> src(w, h);
... // read input data
// compute gradient magnitude at scale 1.0 as a boundary indicator
MultiArray<2, float> gradMag(w, h);
gaussianGradientMagnitude(src, gradMag, 1.0);
// example 1
{
// the pixel type of the destination image must be large enough to
hold
// numbers up to 'max_region_label' to prevent overflow
MultiArray<2, unsigned int> labeling(w, h);
// call watershed algorithm for 4-neighborhood, leave a 1-pixel bou
ndary between regions,
// and autogenerate seeds from all gradient minima where the magnit
ude is below 2.0
unsigned int max_region_label =
watershedsRegionGrowing(gradMag, labeling,
FourNeighborCode(),
WatershedOptions().keepContours()
.seedOptions(SeedOptions().minim
a().threshold(2.0)));
}
// example 2
{
MultiArray<2, unsigned int> labeling(w, h);
// compute seeds beforehand (use connected components of all pixels
// where the gradient is below 4.0)
unsigned int max_region_label =
generateWatershedSeeds(gradMag, labeling,
SeedOptions().levelSets(4.0));
// quantize the gradient image to 256 gray levels
MultiArray<2, unsigned char> gradMag256(w, h);
FindMinMax<float> minmax;
inspectImage(gradMag, minmax); // find original range
transformImage(gradMag, gradMag256,
linearRangeMapping(minmax, 0, 255));
// call the turbo algorithm with 256 bins, using 8-neighborhood
watershedsRegionGrowing(gradMag256, labeling,
WatershedOptions().turboAlgorithm(256));
}
// example 3
{
MultiArray<2, unsigned int> labeling(w, h);
.. // get seeds from somewhere, e.g. an interactive labeling progra
m,
// make sure that label 1 corresponds to the background
// bias the watershed algorithm so that the background is preferred
// by reducing the cost for label 1 to 90%
watershedsRegionGrowing(gradMag, labeling,
WatershedOptions().biasLabel(1, 0.9));
}
\endcode
\deprecatedUsage{watershedsRegionGrowing}
\code
vigra::BImage src(w, h); vigra::BImage src(w, h);
... // read input data ... // read input data
// compute gradient magnitude at scale 1.0 as a boundary indicator // compute gradient magnitude at scale 1.0 as a boundary indicator
vigra::FImage gradMag(w, h); vigra::FImage gradMag(w, h);
gaussianGradientMagnitude(srcImageRange(src), destImage(gradMag), 1.0); gaussianGradientMagnitude(srcImageRange(src), destImage(gradMag), 1.0);
// example 1 // example 1
{ {
// the pixel type of the destination image must be large enough to hold // the pixel type of the destination image must be large enough to hold
skipping to change at line 1129 skipping to change at line 1331
.. // get seeds from somewhere, e.g. an interactive labeling progra m, .. // get seeds from somewhere, e.g. an interactive labeling progra m,
// make sure that label 1 corresponds to the background // make sure that label 1 corresponds to the background
// bias the watershed algorithm so that the background is preferred // bias the watershed algorithm so that the background is preferred
// by reducing the cost for label 1 to 90% // by reducing the cost for label 1 to 90%
watershedsRegionGrowing(srcImageRange(gradMag), destImage(labeling) , watershedsRegionGrowing(srcImageRange(gradMag), destImage(labeling) ,
WatershedOptions().biasLabel(1, 0.9)); WatershedOptions().biasLabel(1, 0.9));
} }
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestIterator dest_upperleft; DestIterator dest_upperleft;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
// compare src values // compare src values
src_accessor(src_upperleft) <= src_accessor(src_upperleft) src_accessor(src_upperleft) <= src_accessor(src_upperleft)
// set result // set result
int label; int label;
dest_accessor.set(label, dest_upperleft); dest_accessor.set(label, dest_upperleft);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int watershedsRegionGro wing) doxygen_overloaded_function(template <...> unsigned int watershedsRegionGro wing)
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
unsigned int unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerrights, Sr cAccessor sa, watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerrights, Sr cAccessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood, Neighborhood neighborhood,
skipping to change at line 1256 skipping to change at line 1457
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline unsigned int inline unsigned int
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src, watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
WatershedOptions const & options = WatershedOptions ()) WatershedOptions const & options = WatershedOptions ())
{ {
return watershedsRegionGrowing(src.first, src.second, src.third, return watershedsRegionGrowing(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
EightNeighborCode(), options); EightNeighborCode(), options);
}
template <class T1, class S1,
class T2, class S2,
class Neighborhood>
inline unsigned int
watershedsRegionGrowing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
Neighborhood neighborhood,
WatershedOptions const & options = WatershedOptions
())
{
vigra_precondition(src.shape() == dest.shape(),
"watershedsRegionGrowing(): shape mismatch between input and output
.");
return watershedsRegionGrowing(srcImageRange(src),
destImage(dest),
neighborhood, options);
}
template <class T1, class S1,
class T2, class S2>
inline unsigned int
watershedsRegionGrowing(MultiArrayView<2, T1, S1> const & src,
MultiArrayView<2, T2, S2> dest,
WatershedOptions const & options = WatershedOptions
())
{
vigra_precondition(src.shape() == dest.shape(),
"watershedsRegionGrowing(): shape mismatch between input and output
.");
return watershedsRegionGrowing(srcImageRange(src),
destImage(dest),
EightNeighborCode(), options);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_WATERSHEDS_HXX #endif // VIGRA_WATERSHEDS_HXX
 End of changes. 50 change blocks. 
45 lines changed or deleted 300 lines changed or added


 watersheds3d.hxx   watersheds3d.hxx 
skipping to change at line 144 skipping to change at line 144
//basically needed for iteration and border-checks //basically needed for iteration and border-checks
int w = srcShape[0], h = srcShape[1], d = srcShape[2]; int w = srcShape[0], h = srcShape[1], d = srcShape[2];
int x,y,z; int x,y,z;
//declare and define Iterators for all three dims at src //declare and define Iterators for all three dims at src
SrcIterator zs = s_Iter; SrcIterator zs = s_Iter;
DestIterator zd = d_Iter; DestIterator zd = d_Iter;
// temporary image to store region labels // temporary image to store region labels
detail::UnionFindArray<LabelType> labels; UnionFindArray<LabelType> labels;
// initialize the neighborhood traversers // initialize the neighborhood traversers
NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst ); NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst );
NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast ); NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast );
++nce; ++nce;
// pass 1: scan image from upper left front to lower right back // pass 1: scan image from upper left front to lower right back
// to find connected components // to find connected components
// Each component will be represented by a tree of pixels. Each // Each component will be represented by a tree of pixels. Each
// pixel contains the scan order address of its parent in the // pixel contains the scan order address of its parent in the
skipping to change at line 175 skipping to change at line 175
SrcIterator ys = zs; SrcIterator ys = zs;
DestIterator yd = zd; DestIterator yd = zd;
for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1()) for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1())
{ {
SrcIterator xs = ys; SrcIterator xs = ys;
DestIterator xd = yd; DestIterator xd = yd;
for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0()) for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
{ {
LabelType currentLabel = labels.nextFreeLabel(); // default : new region LabelType currentIndex = labels.nextFreeIndex(); // default : new region
//check whether there is a special border treatment to be u sed or not //check whether there is a special border treatment to be u sed or not
AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, d); AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, d);
//We are not at the border! //We are not at the border!
if(atBorder == NotAtBorder) if(atBorder == NotAtBorder)
{ {
nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh ood3D::CausalFirst); nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh ood3D::CausalFirst);
do do
{ {
// Direction of NTraversr Neighbor's direct ion bit is pointing // Direction of NTraversr Neighbor's direct ion bit is pointing
// = Direction of voxel towards us? // = Direction of voxel towards us?
if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc .oppositeDirectionBit())) if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc .oppositeDirectionBit()))
{ {
currentLabel = labels.makeUnion(da(xd,*nc), cur rentLabel); currentIndex = labels.makeUnion(da(xd,*nc), cur rentIndex);
} }
++nc; ++nc;
}while(nc!=nce); }while(nc!=nce);
} }
//we are at a border - handle this!! //we are at a border - handle this!!
else else
{ {
nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh ood3D::nearBorderDirectionsCausal(atBorder,0)); nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh ood3D::nearBorderDirectionsCausal(atBorder,0));
int j=0; int j=0;
while(nc.direction() != Neighborhood3D::Error) while(nc.direction() != Neighborhood3D::Error)
{ {
int dummy = x+(*nc)[0]; // prevents an apparently
incorrect optimization in gcc 4.8
if (dummy<0)
{
std::cerr << "internal error " << dummy << std:
:endl;
}
// Direction of NTraversr Neighbor's direct ion bit is pointing // Direction of NTraversr Neighbor's direct ion bit is pointing
// = Direction of voxel towards us? // = Direction of voxel towards us?
if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc .oppositeDirectionBit())) if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc .oppositeDirectionBit()))
{ {
currentLabel = labels.makeUnion(da(xd,*nc), cur rentLabel); currentIndex = labels.makeUnion(da(xd,*nc), cur rentIndex);
} }
nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j)); nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j));
} }
} }
da.set(labels.finalizeLabel(currentLabel), xd); da.set(labels.finalizeIndex(currentIndex), xd);
} }
} }
} }
unsigned int count = labels.makeContiguous(); unsigned int count = labels.makeContiguous();
// pass 2: assign one label to each region (tree) // pass 2: assign one label to each region (tree)
// so that labels form a consecutive sequence 1, 2, ... // so that labels form a consecutive sequence 1, 2, ...
zd = d_Iter; zd = d_Iter;
for(z=0; z != d; ++z, ++zd.dim2()) for(z=0; z != d; ++z, ++zd.dim2())
{ {
DestIterator yd(zd); DestIterator yd(zd);
for(y=0; y != h; ++y, ++yd.dim1()) for(y=0; y != h; ++y, ++yd.dim1())
{ {
DestIterator xd(yd); DestIterator xd(yd);
for(x = 0; x != w; ++x, ++xd.dim0()) for(x = 0; x != w; ++x, ++xd.dim0())
{ {
da.set(labels[da(xd)], xd); da.set(labels.findLabel(da(xd)), xd);
} }
} }
} }
return count; return count;
} }
/** \addtogroup SeededRegionGrowing /** \addtogroup SeededRegionGrowing
*/ */
//@{ //@{
/** \brief Generate seeds for watershed computation and seeded region growi
ng.
The source image is a boundary indicator such as the gradient magnitude
or the trace of the \ref boundaryTensor(). Seeds are generally generate
d
at locations where the boundaryness (i.e. the likelihood of the point b
eing on the
boundary) is very small. In particular, seeds can be placed by either
looking for local minima (possibly including minimal plateaus) of the b
oundaryness,
of by looking at level sets (i.e. regions where the boundaryness is bel
ow a threshold).
Both methods can also be combined, so that only minima below a threshol
d are returned.
The particular seeding strategy is specified by the <tt>options</tt> ob
ject
(see \ref SeedOptions).
The pixel type of the input image must be <tt>LessThanComparable</tt>.
The pixel type of the output image must be large enough to hold the lab
els for all seeds.
(typically, you will use <tt>UInt32</tt>). The function will label seed
s by consecutive integers
(starting from 1) and returns the largest label it used.
Pass \ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode to d
etermine the
neighborhood where pixel values are compared.
The function uses accessors.
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode>
unsigned int
generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrig
hts, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood = EightNeighborCod
e(),
SeedOptions const & options = SeedOptions())
;
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode>
unsigned int
generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor
> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood = EightNeighborCod
e(),
SeedOptions const & options = SeedOptions())
;
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br>
Namespace: vigra
For detailed examples see watershedsRegionGrowing().
*/
doxygen_overloaded_function(template <...> unsigned int generateWatershedSe
eds3D)
#if 0
template <unsigned int N, class T1, class C1, class T2, class C2>
class Neighborhood>
unsigned int
generateWatershedSeeds3D(MultiArrayView<N, T1, C1> in, MultiArrayView<N, T2
, C2> out,
Neighborhood neighborhood,
SeedOptions const & options = SeedOptions())
{
using namespace functor;
vigra_precondition(in.shape() == out.shape(),
"generateWatershedSeeds3D(): Shape mismatch between input and outpu
t.");
vigra_precondition(options.mini != SeedOptions::LevelSets ||
options.thresholdIsValid<SrcType>(),
"generateWatershedSeeds3D(): SeedOptions.levelSets() must be specif
ied with threshold.");
MultiArray<N, UInt8> seeds(in.shape());
if(options.mini == SeedOptions::LevelSets)
{
transformMultiArray(srcMultiArrayRange(in), destMultiArray(seeds),
ifThenElse(Arg1() <= Param(options.thresh), Par
am(1), Param(0)));
}
else
{
localMinima(in, seeds,
LocalMinmaxOptions().neighborhood(Neighborhood::DirectionCount)
.markWith(1.0)
.threshold(options.thresh)
.allowAtBorder()
.allowPlateaus(options.mini == SeedOptions:
:ExtendedMinima));
}
return labelVolumeWithBackground(srcMultiArrayRange(seeds), destMultiAr
ray(out),
neighborhood, 0);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline unsigned int
generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrights, Src
Accessor sa,
DestIterator upperleftd, DestAccessor da,
SeedOptions const & options = SeedOptions())
{
return generateWatershedSeeds(upperlefts, lowerrights, sa, upperleftd,
da,
EightNeighborCode(), options);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood>
inline unsigned int
generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood,
SeedOptions const & options = SeedOptions())
{
return generateWatershedSeeds(src.first, src.second, src.third,
dest.first, dest.second,
neighborhood, options);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline unsigned int
generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
SeedOptions const & options = SeedOptions())
{
return generateWatershedSeeds(src.first, src.second, src.third,
dest.first, dest.second,
EightNeighborCode(), options);
}
#endif
/********************************************************/ /********************************************************/
/* */ /* */
/* watersheds3D */ /* watersheds3D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Region Segmentation by means of the watershed algorithm. /** \brief Region Segmentation by means of the watershed algorithm.
This function is deprecated, use \ref watershedsMultiArray() instead.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: \deprecatedAPI{watersheds3D}
pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D> class Neighborhood3D>
unsigned int watersheds3D(SrcIterator s_Iter, SrcShape srcShape, Sr cAccessor sa, unsigned int watersheds3D(SrcIterator s_Iter, SrcShape srcShape, Sr cAccessor sa,
DestIterator d_Iter, DestAccessor da, DestIterator d_Iter, DestAccessor da,
Neighborhood3D neighborhood3D); Neighborhood3D neighborhood3D);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories :
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D> class Neighborhood3D>
unsigned int watersheds3D(triple<SrcIterator, SrcShape, SrcAccessor > src, unsigned int watersheds3D(triple<SrcIterator, SrcShape, SrcAccessor > src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
Neighborhood3D neighborhood3D); Neighborhood3D neighborhood3D);
} }
skipping to change at line 439 skipping to change at line 308
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,class SrcShape, template <class SrcIterator, class SrcAccessor,class SrcShape,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
unsigned int watersheds3DTwentySix(triple<SrcIterator, SrcShape, Sr cAccessor> src, unsigned int watersheds3DTwentySix(triple<SrcIterator, SrcShape, Sr cAccessor> src,
pair<DestIterator, DestAccessor> dest); pair<DestIterator, DestAccessor> dest);
} }
\endcode \endcode
\deprecatedEnd
This function implements the union-find version of the watershed algori thms This function implements the union-find version of the watershed algori thms
as described in as described in
J. Roerdink, R. Meijster: "<em>The watershed transform: definitions, al J. Roerdink, R. Meijster: <em>"The watershed transform: definitions, al
gorithms, gorithms,
and parallelization strategies</em>", Fundamenta Informaticae, 41:187-2 and parallelization strategies"</em>, Fundamenta Informaticae, 41:187-2
28, 2000 28, 2000
The source volume is a boundary indicator such as the gradient magnitud e The source volume is a boundary indicator such as the gradient magnitud e
of the trace of the \ref boundaryTensor(). Local minima of the boundary indicator of the trace of the \ref boundaryTensor(). Local minima of the boundary indicator
are used as region seeds, and all other voxels are recursively assigned to the same are used as region seeds, and all other voxels are recursively assigned to the same
region as their lowest neighbor. Pass \ref vigra::NeighborCode3DSix or region as their lowest neighbor. Pass \ref vigra::NeighborCode3DSix or
\ref vigra::NeighborCode3DTwentySix to determine the neighborhood where voxel values \ref vigra::NeighborCode3DTwentySix to determine the neighborhood where voxel values
are compared. The voxel type of the input volume must be <tt>LessThanCo mparable</tt>. are compared. The voxel type of the input volume must be <tt>LessThanCo mparable</tt>.
The function uses accessors.
...probably soon in VIGRA:
Note that VIGRA provides an alternative implementation of the watershed
transform via
\ref seededRegionGrowing3D(). It is slower, but handles plateaus better
and allows to keep a one pixel wide boundary between regions.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<vigra/watersheds3D.hxx\><br> <b>\#include</b> \<vigra/watersheds3D.hxx\><br>
Namespace: vigra Namespace: vigra
Example: watersheds3D of the gradient magnitude. Example: watersheds3D of the gradient magnitude.
\code \code
Shape3 shape(w, h, d);
MultiArray<3, float> src(shape), grad(shape);
...
double scale = 1;
gaussianGradientMagnitude(src, grad, scale);
MultiArray<3, int> labels(shape);
// find 6-connected regions
int max_region_label = watersheds3DSix(grad, labels);
// find 26-connected regions
max_region_label = watersheds3DTwentySix(grad, labels);
\endcode
\deprecatedUsage{watersheds3D}
\code
typedef vigra::MultiArray<3,int> IntVolume; typedef vigra::MultiArray<3,int> IntVolume;
typedef vigra::MultiArray<3,double> DVolume; typedef vigra::MultiArray<3,double> DVolume;
DVolume src(DVolume::difference_type(w,h,d)); DVolume src(DVolume::difference_type(w,h,d));
IntVolume dest(IntVolume::difference_type(w,h,d)); IntVolume dest(IntVolume::difference_type(w,h,d));
float gauss=1; float gauss=1;
vigra::MultiArray<3, vigra::TinyVector<float,3> > temp(IntVolume::diffe rence_type(w,h,d)); vigra::MultiArray<3, vigra::TinyVector<float,3> > temp(IntVolume::diffe rence_type(w,h,d));
vigra::gaussianGradientMultiArray(srcMultiArrayRange(vol),destMultiArra y(temp),gauss); vigra::gaussianGradientMultiArray(srcMultiArrayRange(vol),destMultiArra y(temp),gauss);
skipping to change at line 488 skipping to change at line 371
for(DVolume::iterator iter=src.begin(); iter!=src.end(); ++iter, ++temp _iter) for(DVolume::iterator iter=src.begin(); iter!=src.end(); ++iter, ++temp _iter)
*iter = norm(*temp_iter); *iter = norm(*temp_iter);
// find 6-connected regions // find 6-connected regions
int max_region_label = vigra::watersheds3DSix(srcMultiArrayRange(src), destMultiArray(dest)); int max_region_label = vigra::watersheds3DSix(srcMultiArrayRange(src), destMultiArray(dest));
// find 26-connected regions // find 26-connected regions
max_region_label = vigra::watersheds3DTwentySix(srcMultiArrayRange(src) , destMultiArray(dest)); max_region_label = vigra::watersheds3DTwentySix(srcMultiArrayRange(src) , destMultiArray(dest));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcIterator src_begin; SrcIterator src_begin;
SrcShape src_shape; SrcShape src_shape;
DestIterator dest_begin; DestIterator dest_begin;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
// compare src values // compare src values
src_accessor(src_begin) <= src_accessor(src_begin) src_accessor(src_begin) <= src_accessor(src_begin)
// set result // set result
int label; int label;
dest_accessor.set(label, dest_begin); dest_accessor.set(label, dest_begin);
\endcode \endcode
\deprecatedEnd
*/ */
doxygen_overloaded_function(template <...> unsigned int watersheds3D) doxygen_overloaded_function(template <...> unsigned int watersheds3D)
template <class SrcIterator, class SrcAccessor, class SrcShape, template <class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class Neighborhood3D> class Neighborhood3D>
unsigned int watersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccess or sa, unsigned int watersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccess or sa,
DestIterator d_Iter, DestAccessor da, Neighborho od3D neighborhood3D) DestIterator d_Iter, DestAccessor da, Neighborho od3D neighborhood3D)
{ {
//create temporary volume to store the DAG of directions to minima //create temporary volume to store the DAG of directions to minima
skipping to change at line 544 skipping to change at line 426
neighborhood3D); neighborhood3D);
return watershedLabeling3D( srcMultiArray(orientationVolume).first, srcShape, srcMultiArray(orientationVolume).second, return watershedLabeling3D( srcMultiArray(orientationVolume).first, srcShape, srcMultiArray(orientationVolume).second,
d_Iter, da, d_Iter, da,
neighborhood3D); neighborhood3D);
} }
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline unsigned int watersheds3DSix( vigra::triple<SrcIterator, SrcShape, S inline unsigned int watersheds3DSix( triple<SrcIterator, SrcShape, SrcAcces
rcAccessor> src, sor> src,
vigra::pair<DestIterator, DestAccessor pair<DestIterator, DestAccessor> dest)
> dest)
{ {
return watersheds3D(src.first, src.second, src.third, dest.first, dest. second, NeighborCode3DSix()); return watersheds3D(src.first, src.second, src.third, dest.first, dest. second, NeighborCode3DSix());
} }
template <class SrcIterator, class SrcShape, class SrcAccessor, template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline unsigned int watersheds3DTwentySix( vigra::triple<SrcIterator, SrcSh inline unsigned int watersheds3DTwentySix( triple<SrcIterator, SrcShape, Sr
ape, SrcAccessor> src, cAccessor> src,
vigra::pair<DestIterator, DestAc pair<DestIterator, DestAccessor>
cessor> dest) dest)
{ {
return watersheds3D(src.first, src.second, src.third, dest.first, dest. second, NeighborCode3DTwentySix()); return watersheds3D(src.first, src.second, src.third, dest.first, dest. second, NeighborCode3DTwentySix());
} }
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline unsigned int
watersheds3DSix(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
vigra_precondition(source.shape() == dest.shape(),
"watersheds3DSix(): shape mismatch between input and output.");
return watersheds3DSix(srcMultiArrayRange(source), destMultiArray(dest)
);
}
template <unsigned int N, class T1, class S1,
class T2, class S2>
inline unsigned int
watersheds3DTwentySix(MultiArrayView<N, T1, S1> const & source,
MultiArrayView<N, T2, S2> dest)
{
vigra_precondition(source.shape() == dest.shape(),
"watersheds3DTwentySix(): shape mismatch between input and output."
);
return watersheds3DTwentySix(srcMultiArrayRange(source), destMultiArray
(dest));
}
}//namespace vigra }//namespace vigra
#endif //VIGRA_watersheds3D_HXX #endif //VIGRA_watersheds3D_HXX
 End of changes. 21 change blocks. 
192 lines changed or deleted 74 lines changed or added


 wigner-matrix.hxx   wigner-matrix.hxx 
skipping to change at line 52 skipping to change at line 52
#include "utilities.hxx" #include "utilities.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "matrix.hxx" #include "matrix.hxx"
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "quaternion.hxx" #include "quaternion.hxx"
#include "clebsch-gordan.hxx" #include "clebsch-gordan.hxx"
namespace vigra { namespace vigra {
/*! /**
* \class WignerMatrix * \class WignerMatrix
* \brief computation of Wigner D matrix + rotation functions * \brief computation of Wigner D matrix + rotation functions
* in SH,VH and R³ * in SH,VH and R³
* *
* All rotations in Euler zyz' convention * All rotations in Euler zyz' convention
* *
* WARNING: not thread safe! use a new instance of WignerMatrix * WARNING: not thread safe! use a new instance of WignerMatrix
* for each thread!!! * for each thread!!!
*/ */
template <class Real> template <class Real>
class WignerMatrix class WignerMatrix
{ {
public: public:
// FIXME: should we rather use FFTWComplex? // FIXME: should we rather use FFTWComplex?
typedef std::complex<Real> Complex; typedef std::complex<Real> Complex;
typedef ArrayVector<ArrayVector<ArrayVector<Complex> > > NestedArray; typedef ArrayVector<ArrayVector<ArrayVector<Complex> > > NestedArray;
/*! \brief constructor /** \brief constructor
* *
* \param l_max maximum expansion band (used to pre-compute * \param l_max maximum expansion band (used to pre-compute
* the D matrix) * the D matrix)
* *
*/ */
WignerMatrix(int l_max); WignerMatrix(int l_max);
/*! \brief Compute D with fixed theta = pi/2, phi=0, psi=0. /** \brief Compute D with fixed theta = pi/2, phi=0, psi=0.
* *
* \param band expansion band * \param band expansion band
* *
FIXME: compute_D(l, 0.0, M_PI / 2.0, 0.0) creates the transpos ed matrix! FIXME: compute_D(l, 0.0, M_PI / 2.0, 0.0) creates the transpos ed matrix!
*/ */
void compute_D(int band); void compute_D(int band);
/*! \brief Compute D for arbitrary rotations. /** \brief Compute D for arbitrary rotations.
* *
* \param l expansion band * \param l expansion band
* \param phi rotation angle * \param phi rotation angle
* \param theta rotation angle * \param theta rotation angle
* \param psi rotation angle * \param psi rotation angle
* *
*/ */
void compute_D(int l, Real phi, Real theta, Real psi); void compute_D(int l, Real phi, Real theta, Real psi);
/*! \brief Get the (n,m) entry of D. /** \brief Get the (n,m) entry of D.
* *
* \param l expansion band * \param l expansion band
* \param n * \param n
* \param m * \param m
*/ */
Complex get_D(int l, int n, int m) const Complex get_D(int l, int n, int m) const
{ {
if (l>0) if (l>0)
{ {
std::string message = std::string("WignerMatrix::get_D(): index out of bounds: l="); std::string message = std::string("WignerMatrix::get_D(): index out of bounds: l=");
skipping to change at line 121 skipping to change at line 121
n+l <= 2*l+1 && m+l >= 0 && n+l >= 0, n+l <= 2*l+1 && m+l >= 0 && n+l >= 0,
message.c_str()); message.c_str());
return D[l](n+l, m+l); return D[l](n+l, m+l);
} }
else else
{ {
return Complex(Real(1.0)); return Complex(Real(1.0));
} }
} }
/*! \brief Return the rotation matrix D for the lth band. /** \brief Return the rotation matrix D for the lth band.
* *
* \param l expansion band * \param l expansion band
*/ */
Matrix<Complex> const & get_D(int l) const Matrix<Complex> const & get_D(int l) const
{ {
std::string message = std::string("WignerMatrix::get_D(): index out of bounds: l="); std::string message = std::string("WignerMatrix::get_D(): index out of bounds: l=");
message << l << " l_max=" << l_max << "\n"; message << l << " l_max=" << l_max << "\n";
vigra_precondition(l > 0 && l <= l_max, message.c_str()); vigra_precondition(l > 0 && l <= l_max, message.c_str());
return D[l]; return D[l];
} }
/*! \brief Rotate in PH. /** \brief Rotate in PH.
* *
* \param PH input PH expansion * \param PH input PH expansion
* \param phi rotation angle * \param phi rotation angle
* \param theta rotation angle * \param theta rotation angle
* \param psi rotation angle * \param psi rotation angle
* *
* \retval PHresult PH expansion * \retval PHresult PH expansion
*/ */
void rotatePH(NestedArray const & PH, Real phi, Real theta, Real psi, void rotatePH(NestedArray const & PH, Real phi, Real theta, Real psi,
NestedArray & PHresult); NestedArray & PHresult);
 End of changes. 7 change blocks. 
7 lines changed or deleted 7 lines changed or added


 windows.h   windows.h 
skipping to change at line 57 skipping to change at line 57
# define _VIGRA_UNDEFINE_NOMINMAX # define _VIGRA_UNDEFINE_NOMINMAX
# endif # endif
# include <windows.h> # include <windows.h>
# ifdef _VIGRA_UNDEFINE_NOMINMAX # ifdef _VIGRA_UNDEFINE_NOMINMAX
# undef NOMINMAX # undef NOMINMAX
# undef _VIGRA_UNDEFINE_NOMINMAX # undef _VIGRA_UNDEFINE_NOMINMAX
# endif # endif
# ifdef DIFFERENCE # ifdef DIFFERENCE
# undef DIFFERENCE # undef DIFFERENCE
# endif # endif
# ifdef IN
# undef IN
# endif
# ifdef OUT
# undef OUT
# endif
#endif #endif
#endif /* VIGRA_WINDOWS_H */ #endif /* VIGRA_WINDOWS_H */
 End of changes. 1 change blocks. 
0 lines changed or deleted 6 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/