accessor.hxx   accessor.hxx 
skipping to change at line 126 skipping to change at line 126
StandardAccessor is a trivial accessor that simply encapsulates StandardAccessor 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 reference</em> . read and write functions. It passes its arguments <em>by reference</em> .
If you want to return items by value, you If you want to return items by value, you
must use StandardValueAccessor instead of StandardAccessor. must use StandardValueAccessor instead of StandardAccessor.
Both accessors have different optimization properties -- Both accessors have different optimization properties --
StandardAccessor is usually faster for compound pixel types, StandardAccessor is usually faster for compound pixel types,
while StandardValueAccessor is faster for the built-in types. while StandardValueAccessor is faster for the built-in types.
When a floating point number is assigned by means of an accessor When a floating point number is assigned by means of an accessor
with integral value_type, the value is rounded and clipped as approriat e. with integral value_type, the value is rounded and clipped as appropria te.
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VALUETYPE> template <class VALUETYPE>
class StandardAccessor class StandardAccessor
{ {
public: public:
/** the value_type /** the value_type
*/ */
typedef VALUETYPE value_type; typedef VALUETYPE value_type;
skipping to change at line 156 skipping to change at line 156
/** 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 DIFFERENCE>
VALUETYPE const & operator()(ITERATOR const & i, DIFFERENCE const & dif f) const VALUETYPE const & operator()(ITERATOR const & i, DIFFERENCE const & dif f) const
{ {
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 -> intergral this includ es 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 = detail::RequiresExplicitCast<VALUETYPE>::cast(value); } { *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); }
/* 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 -> intergral this includ es 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 DIFFERENCE>
void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const
{ {
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>.
If the iterator returns its items by reference (such as \ref vigra::Ima geIterator), If the iterator returns its items by reference (such as \ref vigra::Ima geIterator),
you can also use StandardAccessor. you can also use StandardAccessor.
These accessors have different optimization properties -- These accessors have different optimization properties --
StandardAccessor is usually faster for compound pixel types, StandardAccessor is usually faster for compound pixel types,
while StandardValueAccessor is faster for the built-in types. while StandardValueAccessor is faster for the built-in types.
When a floating point number is assigned by means of an accessor When a floating point number is assigned by means of an accessor
with integral value_type, the value is rounded and clipped as approriat e. with integral value_type, the value is rounded and clipped as appropria te.
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VALUETYPE> template <class VALUETYPE>
class StandardValueAccessor class StandardValueAccessor
{ {
public: public:
/** the value_type /** the value_type
*/ */
typedef VALUETYPE value_type; typedef VALUETYPE value_type;
/** Read the current data item. The type <TT>ITERATOR::reference</T T> /** Read the current data item. The type <TT>ITERATOR::reference</T T>
is automatically converted to <TT>VALUETYPE</TT>. is automatically converted to <TT>VALUETYPE</TT>.
In case of a conversion floating point -> intergral this includ es rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
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 -> intergral this includ es 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 DIFFERENCE>
VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const VALUETYPE operator()(ITERATOR const & i, DIFFERENCE 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 -> intergral this includ es 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); }
/* 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 -> intergral this includ es 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 DIFFERENCE>
void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const
{ {
i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value); i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value);
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
skipping to change at line 264 skipping to change at line 264
StandardConstAccessor is a trivial accessor that simply encapsulates StandardConstAccessor is a trivial accessor that simply encapsulates
the iterator's operator*() and operator[]() in its the iterator's operator*() and operator[]() in its
read functions. It passes its arguments <em>by reference</em>. read functions. It passes its arguments <em>by reference</em>.
If the iterator returns its items by value (such as \ref vigra::Coordin ateIterator), you If the iterator returns its items by value (such as \ref vigra::Coordin ateIterator), you
must use StandardConstValueAccessor instead of StandardConstAccessor. must use StandardConstValueAccessor instead of StandardConstAccessor.
Both accessors also have different optimization properties -- Both accessors also have different optimization properties --
StandardConstAccessor is usually faster for compound pixel types, StandardConstAccessor is usually faster for compound pixel types,
while StandardConstValueAccessor is faster for the built-in types. while StandardConstValueAccessor is faster for the built-in types.
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VALUETYPE> template <class VALUETYPE>
class StandardConstAccessor class StandardConstAccessor
{ {
public: public:
typedef VALUETYPE value_type; typedef VALUETYPE value_type;
/** read the current data item /** read the current data item
*/ */
skipping to change at line 300 skipping to change at line 300
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>.
If the iterator returns its items by reference (such as \ref vigra::Con stImageIterator), If the iterator returns its items by reference (such as \ref vigra::Con stImageIterator),
you can also use StandardConstAccessor. you can also use StandardConstAccessor.
These accessors have different optimization properties -- These accessors have different optimization properties --
StandardConstAccessor is usually faster for compound pixel types, StandardConstAccessor is usually faster for compound pixel types,
while StandardConstValueAccessor is faster for the built-in types. while StandardConstValueAccessor is faster for the built-in types.
When an iterator passes a floating point number to an accessor When an iterator passes a floating point number to an accessor
with integral value_type, the value is rounded and clipped as approriat e. with integral value_type, the value is rounded and clipped as appropria te.
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VALUETYPE> template <class VALUETYPE>
class StandardConstValueAccessor class StandardConstValueAccessor
{ {
public: public:
typedef VALUETYPE value_type; typedef VALUETYPE value_type;
/** Read the current data item. The type <TT>ITERATOR::reference</T T> /** Read the current data item. The type <TT>ITERATOR::reference</T T>
is automatically converted to <TT>VALUETYPE</TT>. is automatically converted to <TT>VALUETYPE</TT>.
In case of a conversion floating point -> intergral this includ es rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
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 -> intergral this includ es 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 DIFFERENCE>
VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const
{ {
return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]); return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]);
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
skipping to change at line 359 skipping to change at line 359
\code \code
vigra::BRGBImage image(w,h); vigra::BRGBImage image(w,h);
// init red channel with 255 // init red channel with 255
initImage(destImageRange(image, initImage(destImageRange(image,
VectorComponentAccessor<vigra::BRGBImage::valu e_type>(0)), VectorComponentAccessor<vigra::BRGBImage::valu e_type>(0)),
255); 255);
\endcode \endcode
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VECTORTYPE> template <class VECTORTYPE>
class VectorComponentAccessor class VectorComponentAccessor
{ {
int index_; int index_;
public: public:
/** the value_type /** the value_type
*/ */
skipping to change at line 394 skipping to change at line 394
/** 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 DIFFERENCE>
value_type const & operator()(ITERATOR const & i, DIFFERENCE const & di ff) const value_type const & operator()(ITERATOR const & i, DIFFERENCE const & di ff) 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 -> intergral this includ es 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 -> intergral this includ es 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 DIFFERENCE>
void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V const & value, ITERATOR const & i, DIFFERENCE 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)
skipping to change at line 443 skipping to change at line 443
\code \code
vigra::BRGBImage image(w,h); vigra::BRGBImage image(w,h);
// init red channel with 255 // init red channel with 255
initImage(destImageRange(image, initImage(destImageRange(image,
VectorComponentValueAccessor<vigra::BRGBImage: :value_type>(0)), VectorComponentValueAccessor<vigra::BRGBImage: :value_type>(0)),
255); 255);
\endcode \endcode
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VECTORTYPE> template <class VECTORTYPE>
class VectorComponentValueAccessor class VectorComponentValueAccessor
{ {
int index_; int index_;
public: public:
/** the value_type /** the value_type
*/ */
skipping to change at line 465 skipping to change at line 465
/** determine the component to be accessed /** determine the component to be accessed
*/ */
VectorComponentValueAccessor(int index) VectorComponentValueAccessor(int index)
: index_(index) : index_(index)
{} {}
/** Read the current data item. /** Read the current data item.
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 -> intergral this includ es rounding and clipping. In case of a conversion floating point -> integral this include s rounding and clipping.
*/ */
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 -> intergral this includ es 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 DIFFERENCE>
value_type operator()(ITERATOR const & i, DIFFERENCE const & diff) cons t value_type operator()(ITERATOR const & i, DIFFERENCE const & diff) cons 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 -> intergral this includ es 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 -> intergral this includ es 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 DIFFERENCE>
void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V value, ITERATOR const & i, DIFFERENCE 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)
skipping to change at line 519 skipping to change at line 519
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* VectorElementAccessor */ /* VectorElementAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Accessor for one component of a vector. /** \brief Accessor for one component of a vector.
This works like VectorComponentAccessor, only the template paramters di This works like VectorComponentAccessor, only the template parameters d
ffer: iffer:
Here, we need a vector accessor type , wheras VectorComponentAccessor r Here, we need a vector accessor type , whereas VectorComponentAccessor
equires a vector type. requires a vector type.
<b>Usage:</b> <b>Usage:</b>
\code \code
vigra::BRGBImage image(w,h); vigra::BRGBImage image(w,h);
// init red channel with 255 // init red channel with 255
initImage(destImageRange(image, initImage(destImageRange(image,
VectorElementAccessor<vigra::BRGBImage::Access or>(0)), VectorElementAccessor<vigra::BRGBImage::Access or>(0)),
255); 255);
\endcode \endcode
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class ACCESSOR> template <class ACCESSOR>
class VectorElementAccessor class VectorElementAccessor
{ {
int index_; int index_;
ACCESSOR a_; ACCESSOR a_;
public: public:
/** the value_type /** the value_type
skipping to change at line 570 skipping to change at line 570
/** 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 DIFFERENCE>
value_type const & operator()(ITERATOR const & i, DIFFERENCE const & di ff) const value_type const & operator()(ITERATOR const & i, DIFFERENCE const & di ff) 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 -> intergral this includ es 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 -> intergral this includ es 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 DIFFERENCE>
void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const
{ {
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)
skipping to change at line 610 skipping to change at line 610
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Accessor for items that are STL compatible sequences. /** \brief Accessor for items that are STL compatible sequences.
It encapsulates access to the sequences' begin() and end() It encapsulates access to the sequences' begin() and end()
functions. functions.
<b>Usage:</b> <b>Usage:</b>
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef std::list<std::list<int> > ListOfLists; typedef std::list<std::list<int> > ListOfLists;
ListOfLists ll; ListOfLists ll;
... ...
typedef vigra::SequenceAccessor<ListOfLists::value_type> ListOfListsAcc essor; typedef vigra::SequenceAccessor<ListOfLists::value_type> ListOfListsAcc essor;
ListOfListsAccessor a; ListOfListsAccessor a;
skipping to change at line 709 skipping to change at line 709
/* VectorAccessor */ /* VectorAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Accessor for items that are STL compatible vectors. /** \brief Accessor for items that are STL compatible vectors.
It encapsulates access to a vector's access functionality. It encapsulates access to a vector's access functionality.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
The accessor has two modes of operation: The accessor has two modes of operation:
<ol> <ol>
<li> Access the vector's iterator via the <TT>begin()</TT> and <TT>end( )</TT> <li> Access the vector's iterator via the <TT>begin()</TT> and <TT>end( )</TT>
functions: functions:
\code \code
typedef std::list<std::vector<int> > ListOfVectors; typedef std::list<std::vector<int> > ListOfVectors;
skipping to change at line 795 skipping to change at line 795
*/ */
template <class ITERATOR> template <class ITERATOR>
component_type const & getComponent(ITERATOR const & i, int idx) const component_type const & getComponent(ITERATOR const & i, int idx) const
{ {
return (*i)[idx]; return (*i)[idx];
} }
/** Set the component data at given vector index /** Set the component data at given vector index
at given iterator position. The type <TT>V</TT> of the passed at given iterator position. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>component_t ype</TT>. in <TT>value</TT> is automatically converted to <TT>component_t ype</TT>.
In case of a conversion floating point -> intergral this includ es 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 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 DIFFERENCE>
component_type const & getComponent(ITERATOR const & i, DIFFERENCE cons t & diff, int idx) const component_type const & getComponent(ITERATOR const & i, DIFFERENCE cons t & 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 -> intergral this includ es 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 DIFFERENCE>
void void
setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & di ff, int idx) const setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & di ff, 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 */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Access two images simultaneously. /** \brief Access two images simultaneously.
This accessor is used when two images need to be treated as one This accessor is used when two images need to be treated as one
because an algorithm accepts only one image. For example, because an algorithm accepts only one image. For example,
\ref seededRegionGrowing() uses only one image two calculate \ref seededRegionGrowing() uses only one image two calculate
the cost for aggregating each pixel into a region. Somtimes, we the cost for aggregating each pixel into a region. Sometimes, we
need more information to calcuate this cost, for example gray value need more information to calculate this cost, for example gray value
and local gradient magnitude. These values can be stored in two images, and local gradient magnitude. These values can be stored in two images,
which appear as only one when we pass a <TT>MultiImageAccessor2</TT> to which appear as only one when we pass a <TT>MultiImageAccessor2</TT> to
the lagorithms. Of course, the cost functor must accept a <TT>pair</TT> the algorithms. Of course, the cost functor must accept a <TT>pair</TT>
of values for this to work. Instead of an actual image iterator, we of values for this to work. Instead of an actual image iterator, we
pass a <a href="CoordinateIterator.html">CoordinateIterator</a> which pass a <a href="CoordinateIterator.html">CoordinateIterator</a> which
selects the right pixels form both images. selects the right pixels form both images.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\><br> <b>\#include</b> \<vigra/accessor.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
using namespace vigra; using namespace vigra;
FImage gray_values(w,h), gradient_magnitude(w,h); FImage gray_values(w,h), gradient_magnitude(w,h);
IImage seeds(w,h), labels(w,h); IImage seeds(w,h), labels(w,h);
seededRegionGrowing( seededRegionGrowing(
srcIterRange(CoordinateIterator(), CoordinateIterator(w,h), srcIterRange(CoordinateIterator(), CoordinateIterator(w,h),
 End of changes. 34 change blocks. 
38 lines changed or deleted 38 lines changed or added


 affine_registration.hxx   affine_registration.hxx 
skipping to change at line 400 skipping to change at line 400
/* estimateTranslation */ /* estimateTranslation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \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> \<<a href="affine__registration_8hxx-source.html">vigr a/affine_registration.hxx</a>\><br> <b>\#include</b> \<vigra/affine_registration.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 496 skipping to change at line 496
/* */ /* */
/********************************************************/ /********************************************************/
/** \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> \<<a href="affine__registration_8hxx-source.html">vigr a/affine_registration.hxx</a>\><br> <b>\#include</b> \<vigra/affine_registration.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 592 skipping to change at line 592
/* */ /* */
/********************************************************/ /********************************************************/
/** \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> \<<a href="affine__registration_8hxx-source.html">vigr a/affine_registration.hxx</a>\><br> <b>\#include</b> \<vigra/affine_registration.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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,
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 affinegeometry.hxx   affinegeometry.hxx 
skipping to change at line 213 skipping to change at line 213
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
rotateImage(SplineImageView<ORDER, T> const & src, rotateImage(SplineImageView<ORDER, T> const & src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
double angleInDegree); double angleInDegree);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="affinegeometry_8hxx-source.html">vigra/ affinegeometry.hxx</a>\><br> <b>\#include</b> \<vigra/affinegeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image src(width, height); Image src(width, height);
vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)) ; vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)) ;
Image dest(width, height); Image dest(width, height);
vigra::rotateImage(spline, destImage(dest), 38.5); vigra::rotateImage(spline, destImage(dest), 38.5);
skipping to change at line 351 skipping to change at line 351
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
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 writen 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 represent a 2-dimensional affine transform by means of homog eneous 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> \<<a href="affinegeometry_8hxx-source.html">vigra/ affinegeometry.hxx</a>\><br> <b>\#include</b> \<vigra/affinegeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image src(width, height); Image src(width, height);
vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)) ; vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)) ;
Image dest1(width, height); Image dest1(width, height);
// equivalent (up to round-off errors) with // equivalent (up to round-off errors) with
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 array_vector.hxx   array_vector.hxx 
skipping to change at line 72 skipping to change at line 72
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 <tt><a href="http ://www.sgi.com/tech/stl/Vector.html">std::vector</a></tt>
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> \<<a href="array__vector_8hxx-source.html">vigra/array _vector.hxx</a>\><br> <b>\#include</b> \<vigra/array_vector.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
class ArrayVectorView class ArrayVectorView
{ {
typedef ArrayVectorView<T> this_type; typedef ArrayVectorView<T> this_type;
public: public:
/** default constructor /** default constructor
*/ */
skipping to change at line 195 skipping to change at line 195
When the shapes of the two arrays match, the array contents When the shapes of the two arrays match, the array contents
(not the pointers) are swapped. Otherwise, a <tt>PreconditionVi olation</tt> (not the pointers) are swapped. Otherwise, a <tt>PreconditionVi olation</tt>
exception is thrown. exception is thrown.
*/ */
template <class U> template <class U>
void swapData(ArrayVectorView<U> rhs) void swapData(ArrayVectorView<U> rhs)
{ {
swapDataImpl(rhs); swapDataImpl(rhs);
} }
/** Construct <tt>ArrayVectorView</tt> refering to a subarray. /** Construct <tt>ArrayVectorView</tt> referring to a subarray.
\a begin and \a end must be a valid sub-range of the current ar ray. \a begin and \a end must be a valid sub-range of the current ar ray.
Otherwise, a <tt>PreconditionViolation</tt> Otherwise, a <tt>PreconditionViolation</tt>
exception is thrown. exception is thrown.
*/ */
this_type subarray (size_type begin, size_type end) const this_type subarray (size_type begin, size_type end) const
{ {
vigra_precondition(begin <= end && end <= size_, vigra_precondition(begin <= end && end <= size_,
"ArrayVectorView::subarray(): Limits out of range."); "ArrayVectorView::subarray(): Limits out of range.");
return this_type(end-begin, data_ + begin); return this_type(end-begin, data_ + begin);
} }
skipping to change at line 221 skipping to change at line 221
return data_; return data_;
} }
/** Get contained pointer to the data. /** Get contained pointer to the data.
*/ */
inline pointer data() inline pointer data()
{ {
return data_; return data_;
} }
/** Get const iterator refering to the first array element. /** Get const iterator referring to the first array element.
*/ */
inline const_iterator begin() const inline const_iterator begin() const
{ {
return data(); return data();
} }
/** Get iterator refering to the first array element. /** Get iterator referring to the first array element.
*/ */
inline iterator begin() inline iterator begin()
{ {
return data(); return data();
} }
/** Get const iterator pointing beyond the last array element. /** Get const iterator pointing beyond the last array element.
*/ */
inline const_iterator end() const inline const_iterator end() const
{ {
skipping to change at line 458 skipping to change at line 458
However, it gives two useful guarantees, that <tt>std::vector</tt> fail s However, it gives two useful guarantees, that <tt>std::vector</tt> fail s
to provide: to provide:
<ul> <ul>
<li>The memory is always allocated as one contiguous piece.</li> <li>The memory is always allocated as one contiguous piece.</li>
<li>The iterator is always a <TT>T *</TT> </li> <li>The iterator is always a <TT>T *</TT> </li>
</ul> </ul>
This means that memory managed by <tt>ArrayVector</tt> can be passed This means that memory managed by <tt>ArrayVector</tt> can be passed
to algorithms that expect raw memory. This is especially important to algorithms that expect raw memory. This is especially important
when lagacy or C code has to be called, but it is also useful for certa in when legacy or C code has to be called, but it is also useful for certa in
optimizations. optimizations.
Moreover, <tt>ArrayVector</tt> is derived from <tt>ArrayVectorView</tt> so that one Moreover, <tt>ArrayVector</tt> is derived from <tt>ArrayVectorView</tt> so that one
can create views of the array (in particular, subarrays). This implies another can create views of the array (in particular, subarrays). This implies another
important difference to <tt>std::vector</tt>: the indexing operator important difference to <tt>std::vector</tt>: the indexing operator
(<tt>ArrayVector::operator[]</tt>) takes <tt>signed</tt> indices. In th is way, (<tt>ArrayVector::operator[]</tt>) takes <tt>signed</tt> indices. In th is way,
an <tt>ArrayVectorView</tt> can be used with negative indices: an <tt>ArrayVectorView</tt> can be used with negative indices:
\code \code
ArrayVector<int> data(100); ArrayVector<int> data(100);
ArrayVectorView<int> view = data.subarray(50, 100); ArrayVectorView<int> view = data.subarray(50, 100);
view[-50] = 1; // valid access view[-50] = 1; // valid access
\endcode \endcode
Refer to the documentation of <tt>std::vector</tt> for a detailed Refer to the documentation of <tt>std::vector</tt> for a detailed
description of <tt>ArrayVector</tt> functionality. description of <tt>ArrayVector</tt> functionality.
<b>\#include</b> \<<a href="array__vector_8hxx-source.html">vigra/array _vector.hxx</a>\><br> <b>\#include</b> \<vigra/array_vector.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class Alloc /* = std::allocator<T> */ > template <class T, class Alloc /* = std::allocator<T> */ >
class ArrayVector class ArrayVector
: public ArrayVectorView<T> : public ArrayVectorView<T>
{ {
typedef ArrayVector<T, Alloc> this_type; typedef ArrayVector<T, Alloc> this_type;
enum { minimumCapacity = 2, resizeFactor = 2 }; enum { minimumCapacity = 2, resizeFactor = 2 };
public: public:
skipping to change at line 701 skipping to change at line 701
} }
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 )
{ {
difference_type pos = p - this->begin(); difference_type pos = p - this->begin();
size_type new_size = this->size() + n; size_type new_size = this->size() + n;
if(new_size >= capacity_) if(new_size > capacity_)
{ {
size_type new_capacity = std::max(new_size, resizeFactor*capacity_) ; size_type new_capacity = std::max(new_size, resizeFactor*capacity_) ;
pointer new_data = reserve_raw(new_capacity); pointer new_data = reserve_raw(new_capacity);
std::uninitialized_copy(this->begin(), p, new_data); try
std::uninitialized_fill(new_data + pos, new_data + pos + n, v); {
std::uninitialized_copy(p, this->end(), new_data + pos + n); std::uninitialized_copy(this->begin(), p, new_data);
std::uninitialized_fill(new_data + pos, new_data + pos + n, v);
std::uninitialized_copy(p, this->end(), new_data + pos + n);
}
catch(...)
{
alloc_.deallocate(new_data, new_capacity);
throw;
}
deallocate(this->data_, this->size_); deallocate(this->data_, this->size_);
capacity_ = new_capacity; capacity_ = new_capacity;
this->data_ = new_data; this->data_ = new_data;
} }
else if(pos + n >= this->size_) else if(pos + n > this->size_)
{ {
size_type diff = pos + n - this->size_; size_type diff = pos + n - this->size_;
std::uninitialized_copy(p, this->end(), this->end() + diff); std::uninitialized_copy(p, this->end(), this->end() + diff);
std::uninitialized_fill(this->end(), this->end() + diff, v); std::uninitialized_fill(this->end(), this->end() + diff, v);
std::fill(p, this->end(), v); std::fill(p, this->end(), v);
} }
else else
{ {
size_type diff = this->size_ - (pos + n); size_type diff = this->size_ - (pos + n);
std::uninitialized_copy(this->end() - n, this->end(), this->end()); std::uninitialized_copy(this->end() - n, this->end(), this->end());
skipping to change at line 735 skipping to change at line 743
} }
this->size_ = new_size; this->size_ = new_size;
return this->begin() + pos; return this->begin() + pos;
} }
template <class T, class Alloc> template <class T, class Alloc>
template <class InputIterator> template <class InputIterator>
typename ArrayVector<T, Alloc>::iterator typename ArrayVector<T, Alloc>::iterator
ArrayVector<T, Alloc>::insert(iterator p, InputIterator i, InputIterator ie nd) ArrayVector<T, Alloc>::insert(iterator p, InputIterator i, InputIterator ie nd)
{ {
size_type n = iend - i; size_type n = std::distance(i, iend);
size_type pos = p - this->begin(); size_type pos = p - this->begin();
size_type new_size = this->size() + n; size_type new_size = this->size() + n;
if(new_size >= capacity_) if(new_size > capacity_)
{ {
size_type new_capacity = std::max(new_size, resizeFactor*capacity_) ; size_type new_capacity = std::max(new_size, resizeFactor*capacity_) ;
pointer new_data = reserve_raw(new_capacity); pointer new_data = reserve_raw(new_capacity);
std::uninitialized_copy(this->begin(), p, new_data); try
std::uninitialized_copy(i, iend, new_data + pos); {
std::uninitialized_copy(p, this->end(), new_data + pos + n); std::uninitialized_copy(this->begin(), p, new_data);
std::uninitialized_copy(i, iend, new_data + pos);
std::uninitialized_copy(p, this->end(), new_data + pos + n);
}
catch(...)
{
alloc_.deallocate(new_data, new_capacity);
throw;
}
deallocate(this->data_, this->size_); deallocate(this->data_, this->size_);
capacity_ = new_capacity; capacity_ = new_capacity;
this->data_ = new_data; this->data_ = new_data;
} }
else if(pos + n >= this->size_) else if(pos + n > this->size_)
{ {
size_type diff = pos + n - this->size_; size_type diff = pos + n - this->size_;
std::uninitialized_copy(p, this->end(), this->end() + diff); std::uninitialized_copy(p, this->end(), this->end() + diff);
std::uninitialized_copy(iend - diff, iend, this->end()); InputIterator split = i;
std::copy(i, iend - diff, p); std::advance(split, n - diff);
std::uninitialized_copy(split, iend, this->end());
std::copy(i, split, p);
} }
else else
{ {
size_type diff = this->size_ - (pos + n); size_type diff = this->size_ - (pos + n);
std::uninitialized_copy(this->end() - n, this->end(), this->end()); std::uninitialized_copy(this->end() - n, this->end(), this->end());
std::copy_backward(p, p + diff, this->end()); std::copy_backward(p, p + diff, this->end());
std::copy(i, iend, p); std::copy(i, iend, p);
} }
this->size_ = new_size; this->size_ = new_size;
return this->begin() + pos; return this->begin() + pos;
 End of changes. 14 change blocks. 
19 lines changed or deleted 37 lines changed or added


 basicgeometry.hxx   basicgeometry.hxx 
skipping to change at line 87 skipping to change at line 87
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 rotatio n); pair<DestImageIterator, DestAccessor> dest, int rotatio n);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="basicgeometry_8hxx-source.html">vigra/b asicgeometry.hxx</a>\><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 e exchanged Image dest(src.height(), src.width()); // note that width and height ar e exchanged
vigra::rotateImage(srcImageRange(src), destImage(dest), 90); vigra::rotateImage(srcImageRange(src), destImage(dest), 90);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
skipping to change at line 203 skipping to change at line 203
{ {
rotateImage(src.first, src.second, src.third, dest.first, dest.second, rotation); rotateImage(src.first, src.second, src.third, dest.first, dest.second, rotation);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* reflectImage */ /* reflectImage */
/* */ /* */
/********************************************************/ /********************************************************/
enum Reflect{horizontal = 1, vertical = 2}; enum Reflect {horizontal = 1, vertical = 2};
inline
Reflect operator|(Reflect l, Reflect r)
{
return Reflect((unsigned int)l | (unsigned int)r);
}
/** \brief Reflect image horizontally or vertically. /** \brief Reflect image horizontally or vertically.
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.
skipping to change at line 240 skipping to change at line 246
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 ax is); pair<DestImageIterator, DestAccessor> dest, Reflect ax is);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="basicgeometry_8hxx-source.html">vigra/b asicgeometry.hxx</a>\><br> <b>\#include</b> \<vigra/basicgeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image dest(src.width(), src.height()); Image dest(src.width(), src.height());
vigra::reflectImage(srcImageRange(src), destImage(dest), vigra::horizon tal | vigra::vertical); vigra::reflectImage(srcImageRange(src), destImage(dest), vigra::horizon tal | vigra::vertical);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
skipping to change at line 345 skipping to change at line 351
{ {
reflectImage(src.first, src.second, src.third, dest.first, dest.second, reflect); reflectImage(src.first, src.second, src.third, dest.first, dest.second, reflect);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* transposeImage */ /* transposeImage */
/* */ /* */
/********************************************************/ /********************************************************/
// 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.
The transposition direction refers to the axis, i.e. The transposition direction refers to the axis, i.e.
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
aware that some <sys/types.h> define major/minor, too. Do not omit
the vigra namespace prefix.)
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 383 skipping to change at line 393
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, 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="basicgeometry_8hxx-source.html">vigra/b asicgeometry.hxx</a>\><br> <b>\#include</b> \<vigra/basicgeometry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
Image dest(src.width(), src.height()); Image dest(src.width(), src.height());
vigra::transposeImage(srcImageRange(src), destImage(dest), vigra::major | vigra::minor); vigra::transposeImage(srcImageRange(src), destImage(dest), vigra::major | vigra::minor);
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
skipping to change at line 630 skipping to change at line 640
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, 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="basicgeometry_8hxx-source.html">vigra/b asicgeometry.hxx</a>\><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())); Image dest((int)(factor*src.width()), (int)(factor*src.height()));
vigra::resampleImage(srcImageRange(src), destImage(dest), factor); vigra::resampleImage(srcImageRange(src), destImage(dest), factor);
\endcode \endcode
skipping to change at line 681 skipping to change at line 691
//Bei Verkleinerung muss das dest-Bild ceiling(src*factor), da z.B. //Bei Verkleinerung muss das dest-Bild ceiling(src*factor), da z.B.
//aus 6x6 grossem Bild wird eins 18x18 grosses gemacht bei Vergroesseru ngsfaktor 3.1 //aus 6x6 grossem Bild wird eins 18x18 grosses gemacht bei Vergroesseru ngsfaktor 3.1
//umgekehrt damit wir vom 18x18 zu 6x6 (und nicht 5x5) bei Vergroesseru ng von 1/3.1 //umgekehrt damit wir vom 18x18 zu 6x6 (und nicht 5x5) bei Vergroesseru ng von 1/3.1
//muss das kleinste Integer das groesser als 18/3.1 ist genommen werden . //muss das kleinste Integer das groesser als 18/3.1 ist genommen werden .
int height_new = sizeForResamplingFactor(height_old, yfactor); int height_new = sizeForResamplingFactor(height_old, yfactor);
int width_new = sizeForResamplingFactor(width_old, xfactor); int width_new = sizeForResamplingFactor(width_old, xfactor);
vigra_precondition((width_old > 1) && (height_old > 1), vigra_precondition((width_old > 1) && (height_old > 1),
"resampleImage(): " "resampleImage(): "
"Source image to small.\n"); "Source image too small.\n");
vigra_precondition((width_new > 1) && (height_new > 1), vigra_precondition((width_new > 1) && (height_new > 1),
"resampleImage(): " "resampleImage(): "
"Destination image to small.\n"); "Destination image too small.\n");
typedef typename SrcAccessor::value_type SRCVT; typedef typename SrcAccessor::value_type SRCVT;
typedef BasicImage<SRCVT> TmpImage; typedef BasicImage<SRCVT> TmpImage;
typedef typename TmpImage::traverser TmpImageIterator; typedef typename TmpImage::traverser TmpImageIterator;
BasicImage<SRCVT> tmp(width_old, height_new); BasicImage<SRCVT> tmp(width_old, height_new);
int x,y; int x,y;
typename BasicImage<SRCVT>::Iterator yt = tmp.upperLeft(); typename BasicImage<SRCVT>::Iterator yt = tmp.upperLeft();
 End of changes. 9 change blocks. 
7 lines changed or deleted 17 lines changed or added


 basicimage.hxx   basicimage.hxx 
skipping to change at line 119 skipping to change at line 119
/********************************************************/ /********************************************************/
/* */ /* */
/* 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> \<<a href="basicimage_8hxx-source.html">vigra/basicima ge.hxx</a>\> <b>\#include</b> \<vigra/basicimage.hxx\>
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 256 skipping to change at line 256
/********************************************************/ /********************************************************/
/* */ /* */
/* 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> \<<a href="basicimage_8hxx-source.html">vigra/basicima ge.hxx</a>\> <b>\#include</b> \<vigra/basicimage.hxx\>
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 287
/********************************************************/ /********************************************************/
/* */ /* */
/* 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> \<<a href="basicimage_8hxx-source.html">vigra/basicima ge.hxx</a>\> <b>\#include</b> \<vigra/basicimage.hxx\>
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 464
/* */ /* */
/* 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> \<<a href="basicimage_8hxx-source.html">vigra/basicima ge.hxx</a>\> <b>\#include</b> \<vigra/basicimage.hxx\>
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
*/ */
skipping to change at line 816 skipping to change at line 816
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(int width, int height, SkipInitializationTag)
{ {
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 arra \a data. from the C-style array \a data.
*/ */
void resizeCopy(int width, int height, const_pointer data); void resizeCopy(int width, int height, const_pointer data);
/** resize image to size of other image and copy it's 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 );
skipping to change at line 861 skipping to change at line 861
/** test whether a given coordinate is inside the image /** test whether a given coordinate is inside the image
*/ */
bool isInside(difference_type const & d) const bool isInside(difference_type const & d) const
{ {
return d.x >= 0 && d.y >= 0 && return d.x >= 0 && d.y >= 0 &&
d.x < width() && d.y < height(); d.x < width() && d.y < height();
} }
/** access pixel at given location. <br> /** access pixel at given location. <br>
usage: <TT> value_type value = image[Diff2D(1,2)] </TT> usage: <TT> value_type value = image[Diff2D(1,2)] </TT>
*/ */
reference operator[](difference_type const & d) reference operator[](difference_type const & d)
{ {
VIGRA_ASSERT_INSIDE(d); VIGRA_ASSERT_INSIDE(d);
return lines_[d.y][d.x]; return lines_[d.y][d.x];
} }
/** read pixel at given location. <br> /** read pixel at given location. <br>
usage: <TT> value_type value = image[Diff2D(1,2)] </TT> usage: <TT> value_type value = image[Diff2D(1,2)] </TT>
*/ */
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()(int dx, int 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()(int dx, int 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[](int 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[](int 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 poining 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,
"BasicImage::upperLeft(): image must have non-zero size."); "BasicImage::upperLeft(): image must have non-zero size.");
return traverser(lines_); return traverser(lines_);
} }
/** init 2D random access iterator poining to /** init 2D random access iterator pointing to
pixel(width, height), i.e. one pixel right and below lower right pixel(width, height), i.e. one pixel right and below lower right
corner of the image as is common in C/C++. corner of the image as is common in C/C++.
*/ */
traverser lowerRight() traverser lowerRight()
{ {
vigra_precondition(data_ != 0, vigra_precondition(data_ != 0,
"BasicImage::lowerRight(): image must have non-zero size."); "BasicImage::lowerRight(): image must have non-zero size.");
return upperLeft() + size(); return upperLeft() + size();
} }
/** init 2D random access const iterator poining to upper left pixe l /** init 2D random access const iterator pointing to upper left pix el
*/ */
const_traverser upperLeft() const const_traverser upperLeft() const
{ {
vigra_precondition(data_ != 0, vigra_precondition(data_ != 0,
"BasicImage::upperLeft(): image must have non-zero size."); "BasicImage::upperLeft(): image must have non-zero size.");
return const_traverser(const_cast<PIXELTYPE **>(lines_)); return const_traverser(const_cast<PIXELTYPE **>(lines_));
} }
/** init 2D random access const iterator poining to /** init 2D random access const iterator pointing to
pixel(width, height), i.e. one pixel right and below lower right pixel(width, height), i.e. one pixel right and below lower right
corner of the image as is common in C/C++. corner of the image as is common in C/C++.
*/ */
const_traverser lowerRight() const const_traverser lowerRight() const
{ {
vigra_precondition(data_ != 0, vigra_precondition(data_ != 0,
"BasicImage::lowerRight(): image must have non-zero size."); "BasicImage::lowerRight(): image must have non-zero size.");
return upperLeft() + size(); return upperLeft() + size();
} }
skipping to change at line 1087 skipping to change at line 1087
PIXELTYPE * data_; PIXELTYPE * data_;
PIXELTYPE ** lines_; PIXELTYPE ** lines_;
int width_, height_; int 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<PIXELTYPE, Alloc> & rhs) BasicImage<PIXELTYPE, Alloc>::operator=(const BasicImage & rhs)
{ {
if(this != &rhs) if(this != &rhs)
{ {
if((width() != rhs.width()) || if((width() != rhs.width()) ||
(height() != rhs.height())) (height() != rhs.height()))
{ {
resizeCopy(rhs); resizeCopy(rhs);
} }
else else
{ {
skipping to change at line 1226 skipping to change at line 1226
height_ = height; height_ = height;
} }
else if(newsize > 0) // keep size, copy data else if(newsize > 0) // keep size, copy data
{ {
std::copy(data, data + newsize, data_); std::copy(data, data + newsize, data_);
} }
} }
template <class PIXELTYPE, class Alloc> template <class PIXELTYPE, class Alloc>
void void
BasicImage<PIXELTYPE, Alloc>::swap( BasicImage<PIXELTYPE, Alloc>& rhs ) BasicImage<PIXELTYPE, Alloc>::swap( BasicImage & rhs )
{ {
if (&rhs!=this) if (&rhs!=this)
{ {
std::swap( data_, rhs.data_ ); std::swap( data_, rhs.data_ );
std::swap( lines_, rhs.lines_ ); std::swap( lines_, rhs.lines_ );
std::swap( width_, rhs.width_ ); std::swap( width_, rhs.width_ );
std::swap( height_, rhs.height_ ); std::swap( height_, rhs.height_ );
} }
} }
 End of changes. 18 change blocks. 
20 lines changed or deleted 20 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> \<<a href="basicimageview_8hxx-source.html">vigra/basi cimageview.hxx</a>\> <b>\#include</b> \<vigra/basicimageview.hxx\>
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
*/ */
skipping to change at line 247 skipping to change at line 247
/** test whether a given coordinate is inside the image /** test whether a given coordinate is inside the image
*/ */
bool isInside(difference_type const & d) const bool isInside(difference_type const & d) const
{ {
return d.x >= 0 && d.y >= 0 && return d.x >= 0 && d.y >= 0 &&
d.x < width() && d.y < height(); d.x < width() && d.y < height();
} }
/** access pixel at given location. <br> /** access pixel at given location. <br>
usage: <TT> value_type value = image[Diff2D(1,2)] </TT> usage: <TT> value_type value = image[Diff2D(1,2)] </TT>
*/ */
reference operator[](difference_type const & d) reference operator[](difference_type const & d)
{ {
VIGRA_ASSERT_INSIDE(d); VIGRA_ASSERT_INSIDE(d);
return data_[d.y*stride_ + d.x]; return data_[d.y*stride_ + d.x];
} }
/** read pixel at given location. <br> /** read pixel at given location. <br>
usage: <TT> value_type value = image[Diff2D(1,2)] </TT> usage: <TT> value_type value = image[Diff2D(1,2)] </TT>
*/ */
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()(int dx, int 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()(int dx, int 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[](int 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[](int 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 poining 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_);
} }
/** init 2D random access iterator poining to /** init 2D random access iterator pointing to
pixel(width, height), i.e. one pixel right and below lower right pixel(width, height), i.e. one pixel right and below lower right
corner of the image as is common in C/C++. corner of the image as is common in C/C++.
*/ */
traverser lowerRight() traverser lowerRight()
{ {
return upperLeft() + size(); return upperLeft() + size();
} }
/** init 2D random access const iterator poining to upper left pixe l /** init 2D random access const iterator pointing to upper left pix el
*/ */
const_traverser upperLeft() const const_traverser upperLeft() const
{ {
return const_traverser(data_, stride_); return const_traverser(data_, stride_);
} }
/** init 2D random access const iterator poining to /** init 2D random access const iterator pointing to
pixel(width, height), i.e. one pixel right and below lower right pixel(width, height), i.e. one pixel right and below lower right
corner of the image as is common in C/C++. corner of the image as is common in C/C++.
*/ */
const_traverser lowerRight() const const_traverser lowerRight() const
{ {
return upperLeft() + size(); return upperLeft() + size();
} }
/** init 1D random access iterator pointing to first pixel. /** init 1D random access iterator pointing to first pixel.
Note: Only works if stride equals width. Note: Only works if stride equals width.
 End of changes. 11 change blocks. 
13 lines changed or deleted 13 lines changed or added


 bordertreatment.hxx   bordertreatment.hxx 
skipping to change at line 48 skipping to change at line 48
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> \<<a href="bordertreatment_8hxx-source.html">vigra/bor dertreatment.hxx</a>\><br> <b>\#include</b> \<vigra/bordertreatment.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
enum BorderTreatmentMode enum BorderTreatmentMode
{ {
// do not operate on a pixel where the kernel does // do not operate on a pixel where the kernel does
// not fit in the image // not fit in the image
BORDER_TREATMENT_AVOID, BORDER_TREATMENT_AVOID,
// clip kernel at image border (this is only useful if the // clip kernel at image border (this is only useful if the
 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 407 skipping to change at line 407
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="boundarytensor_8hxx-source.html">vigra/boun darytensor.hxx</a>\> <b>\#include</b> \<vigra/boundarytensor.hxx\>
\code \code
FImage impulse(17,17), res(17, 17); FImage 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(srcImageRange(impulse), destImage(res), 2.0, 1, 0);
\endcode \endcode
*/ */
skipping to change at line 584 skipping to change at line 584
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="boundarytensor_8hxx-source.html">vigra/boun darytensor.hxx</a>\> <b>\#include</b> \<vigra/boundarytensor.hxx\>
\code \code
FImage img(w,h); FImage img(w,h);
FVector3Image bt(w,h); FVector3Image bt(w,h);
... ...
boundaryTensor(srcImageRange(img), destImage(bt), 2.0); boundaryTensor(srcImageRange(img), destImage(bt), 2.0);
\endcode \endcode
*/ */
doxygen_overloaded_function(template <...> void boundaryTensor) doxygen_overloaded_function(template <...> void boundaryTensor)
skipping to change at line 633 skipping to change at line 633
/** \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> \<<a href="boundarytensor_8hxx-source.html">vigra/boun darytensor.hxx</a>\> <b>\#include</b> \<vigra/boundarytensor.hxx\>
pass arguments explicitly: pass arguments explicitly:
\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);
} }
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 cellconfigurations.hxx   cellconfigurations.hxx 
************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 2009-2010 by Ullrich Koethe */ /* Copyright 2009-2010 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 */
/* */ /* */
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 codec.hxx   codec.hxx 
skipping to change at line 38 skipping to change at line 38
/* 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. */
/* */ /* */
/************************************************************************/ /************************************************************************/
/* Modifications by Pablo d'Angelo /* Modifications by Pablo d'Angelo
* updated to vigra 1.4 by Douglas Wilkins * updated to vigra 1.4 by Douglas Wilkins
* as of 18 Febuary 2006: * as of 18 February 2006:
* - Added UINT16 and UINT32 pixel types. * - Added UINT16 and UINT32 pixel types.
* - Added support for obtaining extra bands beyond RGB. * - Added support for obtaining extra bands beyond RGB.
* - Added support for a position field that indicates the start of this * - Added support for a position field that indicates the start of this
* image relative to some global origin. * image relative to some global origin.
* - Added support for x and y resolution fields. * - Added support for x and y resolution fields.
* - Added support for ICC Profiles * - Added support for ICC Profiles
*/ */
#ifndef VIGRA_CODEC_HXX #ifndef VIGRA_CODEC_HXX
#define VIGRA_CODEC_HXX #define VIGRA_CODEC_HXX
skipping to change at line 66 skipping to change at line 66
#include "diff2d.hxx" #include "diff2d.hxx"
#include "sized_int.hxx" #include "sized_int.hxx"
// possible pixel types: // possible pixel types:
// "undefined", "UINT8", "UINT16", "INT16", "UINT32", "INT32", "FLOAT", "DO UBLE" // "undefined", "UINT8", "UINT16", "INT16", "UINT32", "INT32", "FLOAT", "DO UBLE"
// possible compression types: // possible compression types:
// "undefined", "RLE", "LZW", "LOSSLESS", "JPEG", "DEFLATE" // "undefined", "RLE", "LZW", "LOSSLESS", "JPEG", "DEFLATE"
// possible file types: // possible file types:
// "undefined", "TIFF", "VIFF", "JPEG", "PNG", "PNM", "BMP", "SUN", "XPM" // "undefined", "TIFF", "VIFF", "JPEG", "PNG", "PNM", "BMP", "SUN", "XPM", "EXR"
// possible name extensions: // possible name extensions:
// "undefined", "tif", "tiff", "jpg", "jpeg", "png", "pnm", "bmp", "sun", // "undefined", "tif", "tiff", "jpg", "jpeg", "png", "pnm", "bmp", "sun",
// "xpm" (also capital forms) // "xpm", "exr" (also capital forms)
namespace vigra namespace vigra
{ {
template <class T> template <class T>
struct TypeAsString struct TypeAsString
{ {
static std::string result() { return "undefined"; } static std::string result() { return "undefined"; }
}; };
template <> template <>
skipping to change at line 146 skipping to change at line 146
std::vector<int> bandNumbers; std::vector<int> bandNumbers;
}; };
// Decoder and Encoder are virtual types that define a common // Decoder and Encoder are virtual types that define a common
// interface for all image file formats impex supports. // interface for all image file formats impex supports.
struct Decoder struct Decoder
{ {
virtual ~Decoder() {}; virtual ~Decoder() {};
virtual void init( const std::string & ) = 0; virtual void init( const std::string & ) = 0;
// initialize with an image index. For codecs that do not support t
his feature, the standard init is called.
virtual void init( const std::string & fileName, unsigned int image
Index)
{
init(fileName);
}
virtual void close() = 0; virtual void close() = 0;
virtual void abort() = 0; virtual void abort() = 0;
virtual std::string getFileType() const = 0; virtual std::string getFileType() const = 0;
virtual std::string getPixelType() const = 0; virtual std::string getPixelType() const = 0;
virtual unsigned int getNumImages() const
{
return 1;
}
virtual void setImageIndex(unsigned int)
{
}
virtual unsigned int getImageIndex() const
{
return 0;
}
virtual unsigned int getWidth() const = 0; virtual unsigned int getWidth() const = 0;
virtual unsigned int getHeight() const = 0; virtual unsigned int getHeight() const = 0;
virtual unsigned int getNumBands() const = 0; virtual unsigned int getNumBands() const = 0;
virtual unsigned int getNumExtraBands() const virtual unsigned int getNumExtraBands() const
{ {
return 0; return 0;
} }
virtual vigra::Diff2D getPosition() const virtual vigra::Diff2D getPosition() const
{ {
skipping to change at line 174 skipping to change at line 195
virtual float getXResolution() const virtual float getXResolution() const
{ {
return 0.0f; return 0.0f;
} }
virtual float getYResolution() const virtual float getYResolution() const
{ {
return 0.0f; return 0.0f;
} }
virtual vigra::Size2D getCanvasSize() const
{
return vigra::Size2D(this->getWidth(), this->getHeight());
}
virtual unsigned int getOffset() const = 0; virtual unsigned int getOffset() const = 0;
virtual const void * currentScanlineOfBand( unsigned int ) const = 0; virtual const void * currentScanlineOfBand( unsigned int ) const = 0;
virtual void nextScanline() = 0; virtual void nextScanline() = 0;
typedef ArrayVector<unsigned char> ICCProfile; typedef ArrayVector<unsigned char> ICCProfile;
const ICCProfile & getICCProfile() const const ICCProfile & getICCProfile() const
{ {
return iccProfile_; return iccProfile_;
} }
ICCProfile iccProfile_; ICCProfile iccProfile_;
}; };
struct Encoder struct Encoder
{ {
virtual ~Encoder() {}; virtual ~Encoder() {};
virtual void init( const std::string & ) = 0; virtual void init( const std::string & ) = 0;
// initialize with file access mode. For codecs that do not support
this feature, the standard init is called.
virtual void init( const std::string & fileName, const std::string
& mode )
{
init(fileName);
}
virtual void close() = 0; virtual void close() = 0;
virtual void abort() = 0; virtual void abort() = 0;
virtual std::string getFileType() const = 0; virtual std::string getFileType() const = 0;
virtual unsigned int getOffset() const = 0; virtual unsigned int getOffset() const = 0;
virtual void setWidth( unsigned int ) = 0; virtual void setWidth( unsigned int ) = 0;
virtual void setHeight( unsigned int ) = 0; virtual void setHeight( unsigned int ) = 0;
virtual void setNumBands( unsigned int ) = 0; virtual void setNumBands( unsigned int ) = 0;
virtual void setCompressionType( const std::string &, int = -1 ) = 0; virtual void setCompressionType( const std::string &, int = -1 ) = 0;
virtual void setPixelType( const std::string & ) = 0; virtual void setPixelType( const std::string & ) = 0;
virtual void finalizeSettings() = 0; virtual void finalizeSettings() = 0;
virtual void setPosition( const vigra::Diff2D & /*pos*/ ) virtual void setPosition( const vigra::Diff2D & /*pos*/ )
{ {
} }
virtual void setCanvasSize( const vigra::Size2D & /*size*/)
{
}
virtual void setXResolution( float /*xres*/ ) virtual void setXResolution( float /*xres*/ )
{ {
} }
virtual void setYResolution( float /*yres*/ ) virtual void setYResolution( float /*yres*/ )
{ {
} }
typedef ArrayVector<unsigned char> ICCProfile; typedef ArrayVector<unsigned char> ICCProfile;
virtual void setICCProfile(const ICCProfile & /* data */) virtual void setICCProfile(const ICCProfile & /* data */)
skipping to change at line 246 skipping to change at line 282
}; };
// factory functions to encapsulate the codec managers // factory functions to encapsulate the codec managers
// //
// codecs are selected according to the following order: // codecs are selected according to the following order:
// - (if provided) the FileType // - (if provided) the FileType
// - (in case of decoders) the file's magic string // - (in case of decoders) the file's magic string
// - the filename extension // - the filename extension
VIGRA_EXPORT std::auto_ptr<Decoder> VIGRA_EXPORT std::auto_ptr<Decoder>
getDecoder( const std::string &, const std::string & = "undefined" ); getDecoder( const std::string &, const std::string & = "undefined", uns igned int = 0 );
VIGRA_EXPORT std::auto_ptr<Encoder> VIGRA_EXPORT std::auto_ptr<Encoder>
getEncoder( const std::string &, const std::string & = "undefined" ); getEncoder( const std::string &, const std::string & = "undefined", con st std::string & = "w" );
VIGRA_EXPORT std::string VIGRA_EXPORT std::string
getEncoderType( const std::string &, const std::string & = "undefined" ); getEncoderType( const std::string &, const std::string & = "undefined" );
// functions to query the capabilities of certain codecs // functions to query the capabilities of certain codecs
VIGRA_EXPORT std::vector<std::string> queryCodecPixelTypes( const std:: string & ); VIGRA_EXPORT std::vector<std::string> queryCodecPixelTypes( const std:: string & );
VIGRA_EXPORT bool negotiatePixelType( std::string const & codecname, VIGRA_EXPORT bool negotiatePixelType( std::string const & codecname,
std::string const & srcPixeltype, std::string & destPixelt ype); std::string const & srcPixeltype, std::string & destPixelt ype);
 End of changes. 10 change blocks. 
5 lines changed or deleted 45 lines changed or added


 colorconversions.hxx   colorconversions.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_COLORCONVERSIONS_HXX #ifndef VIGRA_COLORCONVERSIONS_HXX
#define VIGRA_COLORCONVERSIONS_HXX #define VIGRA_COLORCONVERSIONS_HXX
#include <cmath> #include <cmath>
#include <string>
#include "mathutil.hxx" #include "mathutil.hxx"
#include "rgbvalue.hxx" #include "rgbvalue.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
namespace vigra { namespace vigra {
namespace detail namespace detail
{ {
template<class ValueType> template<class ValueType>
skipping to change at line 101 skipping to change at line 102
? 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.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<UL> <UL>
<LI> <b>RGB/sRGB/R'G'B'</b><br> <LI> <b>RGB/sRGB/R'G'B'</b><br>
<em>linear and non-linear (gamma corrected) additive color</em> <em>linear and non-linear (gamma corrected) additive color</em>
<p> <p>
<UL style="list-style-image:url(documents/bullet.gif)"> <UL style="list-style-image:url(documents/bullet.gif)">
<LI> \ref vigra::RGB2sRGBFunctor <LI> \ref vigra::RGB2sRGBFunctor
<LI> \ref vigra::sRGB2RGBFunctor <LI> \ref vigra::sRGB2RGBFunctor
<LI> \ref vigra::RGB2RGBPrimeFunctor <LI> \ref vigra::RGB2RGBPrimeFunctor
skipping to change at line 192 skipping to change at line 193
</UL> </UL>
\anchor _details \anchor _details
This module provides conversion from RGB/R'G'B' into more perceptually uniform This module provides conversion from RGB/R'G'B' into more perceptually uniform
color spaces. In image analysis, colors are usually converted into anot her color space color spaces. In image analysis, colors are usually converted into anot her color space
in order to get good estimates of perceived color differences by just c alculating in order to get good estimates of perceived color differences by just c alculating
Euclidean distances between the transformed colors. The L*a*b* and L*u* v* were Euclidean distances between the transformed colors. The L*a*b* and L*u* v* were
designed with exactly this application in mind and thus give the best r esults. But these designed with exactly this application in mind and thus give the best r esults. But these
conversions are also the most computationally demanding. The Y'PbPr col or difference conversions are also the most computationally demanding. The Y'PbPr col or difference
space (designed for coding digital video) is computationally much cheap er, and space (designed for coding digital video) is computationally much cheap er, and
almost as good. Y'CbCr represents esentially the same transformation, b ut the color values almost as good. Y'CbCr represents essentially the same transformation, but the color values
are scaled so that they can be stored with 8 bits per channel with mini mal loss of are scaled so that they can be stored with 8 bits per channel with mini mal loss of
information. The other transformations are of lesser interest here: XYZ is a device independent information. The other transformations are of lesser interest here: XYZ is a device independent
(but not perceptually uniform) color representation, and Y'IQ and Y'UV are the color (but not perceptually uniform) color representation, and Y'IQ and Y'UV are the color
spaces used by the PAL and NTSC analog video standards. Detailed inform ation about spaces used by the PAL and NTSC analog video standards. Detailed inform ation about
these color spaces and their transformations can be found in these color spaces and their transformations can be found in
<a href="http://www.poynton.com/ColorFAQ.html">Charles Poynton's Color FAQ</a> <a href="http://www.poynton.com/ColorFAQ.html">Charles Poynton's Color FAQ</a>
When you want to perform a color conversion, you must first know in whi ch When you want to perform a color conversion, you must first know in whi ch
color space the data are given. Although this sounds trivial, it is color space the data are given. Although this sounds trivial, it is
quite often done wrong, because the distinction between RGB and sRGB (s till images) or R'G'B' quite often done wrong, because the distinction between RGB and sRGB (s till images) or R'G'B'
skipping to change at line 253 skipping to change at line 254
between color spaces). A saturation of 1 is the highest saturation that any RGB color between color spaces). A saturation of 1 is the highest saturation that any RGB color
in the unit cube can have after transformation into the respective colo r space, in the unit cube can have after transformation into the respective colo r space,
and saturation 0 corresponds to gray. Polar coordinates provide a more intuitive and saturation 0 corresponds to gray. Polar coordinates provide a more intuitive
interface to color specification by users and make different color spac es somewhat interface to color specification by users and make different color spac es somewhat
comparable. comparable.
*/ */
//@{ //@{
/** \brief Convert linear (raw) RGB into non-linear (gamma corrected) R'G'B '. /** \brief Convert linear (raw) RGB into non-linear (gamma corrected) R'G'B '.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
R' = R_{max} \left(\frac{R}{R_{max}} \right)^{0.45} \qquad R' = R_{max} \left(\frac{R}{R_{max}} \right)^{0.45} \qquad
G' = G_{max} \left(\frac{G}{G_{max}} \right)^{0.45} \qquad G' = G_{max} \left(\frac{G}{G_{max}} \right)^{0.45} \qquad
B' = B_{max} \left(\frac{B}{B_{max}} \right)^{0.45} B' = B_{max} \left(\frac{B}{B_{max}} \right)^{0.45}
\f] \f]
skipping to change at line 318 skipping to change at line 319
*/ */
template <class V> template <class V>
result_type operator()(V const & rgb) const result_type operator()(V const & rgb) const
{ {
return TinyVector<To, 3>( return TinyVector<To, 3>(
detail::gammaCorrection<To>(rgb[0], 0.45, max_), detail::gammaCorrection<To>(rgb[0], 0.45, max_),
detail::gammaCorrection<To>(rgb[1], 0.45, max_), detail::gammaCorrection<To>(rgb[1], 0.45, max_),
detail::gammaCorrection<To>(rgb[2], 0.45, max_)); detail::gammaCorrection<To>(rgb[2], 0.45, max_));
} }
static std::string targetColorSpace()
{
return "RGB'";
}
private: private:
component_type max_; component_type max_;
}; };
template <> template <>
class RGB2RGBPrimeFunctor<unsigned char, unsigned char> class RGB2RGBPrimeFunctor<unsigned char, unsigned char>
{ {
unsigned char lut_[256]; unsigned char lut_[256];
public: public:
typedef TinyVector<unsigned char, 3> argument_type;
typedef TinyVector<unsigned char, 3> result_type;
typedef TinyVector<unsigned char, 3> value_type; typedef TinyVector<unsigned char, 3> value_type;
RGB2RGBPrimeFunctor() RGB2RGBPrimeFunctor()
{ {
for(int i=0; i<256; ++i) for(int i=0; i<256; ++i)
{ {
lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, 255.0 ); lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, 255.0 );
} }
} }
skipping to change at line 352 skipping to change at line 362
{ {
lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, max); lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, max);
} }
} }
template <class V> template <class V>
TinyVector<unsigned char, 3> operator()(V const & rgb) const TinyVector<unsigned char, 3> operator()(V const & rgb) const
{ {
return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]); return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]);
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class From, class To> template <class From, class To>
class FunctorTraits<RGB2RGBPrimeFunctor<From, To> > class FunctorTraits<RGB2RGBPrimeFunctor<From, To> >
: public FunctorTraitsBase<RGB2RGBPrimeFunctor<From, To> > : public FunctorTraitsBase<RGB2RGBPrimeFunctor<From, To> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert linear (raw) RGB into standardized sRGB. /** \brief Convert linear (raw) RGB into standardized sRGB.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The sRGB color space is a slight improvement over the R'G'B' space. It is now a widely accepted The sRGB color space is a slight improvement over the R'G'B' space. It is now a widely accepted
international standard (IEC 61966-2.1) which is used by most consumer p roducts international standard (IEC 61966-2.1) which is used by most consumer p roducts
(digital cameras, printers, and screens). The functor realizes the tran sformation (digital cameras, printers, and screens). The functor realizes the tran sformation
\f[ \f[
C_{sRGB} = \left\{ \begin{array}{ll} C_{sRGB} = \left\{ \begin{array}{ll}
12.92\,C_{RGB} & \textrm{ if }\frac{C_{RGB}}{C_{max}} \le 0.0031308 \\ 12.92\,C_{RGB} & \textrm{ if }\frac{C_{RGB}}{C_{max}} \le 0.0031308 \\
C_{max}\left( 1.055 \left(\frac{C_{RGB}}{C_{max}}\right)^{1/2.4}-0. 055\right) & \textrm{ otherwise} C_{max}\left( 1.055 \left(\frac{C_{RGB}}{C_{max}}\right)^{1/2.4}-0. 055\right) & \textrm{ otherwise}
skipping to change at line 432 skipping to change at line 447
*/ */
template <class V> template <class V>
result_type operator()(V const & rgb) const result_type operator()(V const & rgb) const
{ {
return TinyVector<To, 3>( return TinyVector<To, 3>(
detail::sRGBCorrection<To>(rgb[0], max_), detail::sRGBCorrection<To>(rgb[0], max_),
detail::sRGBCorrection<To>(rgb[1], max_), detail::sRGBCorrection<To>(rgb[1], max_),
detail::sRGBCorrection<To>(rgb[2], max_)); detail::sRGBCorrection<To>(rgb[2], max_));
} }
static std::string targetColorSpace()
{
return "sRGB";
}
private: private:
component_type max_; component_type max_;
}; };
template <> template <>
class RGB2sRGBFunctor<unsigned char, unsigned char> class RGB2sRGBFunctor<unsigned char, unsigned char>
{ {
unsigned char lut_[256]; unsigned char lut_[256];
public: public:
typedef TinyVector<unsigned char, 3> argument_type;
typedef TinyVector<unsigned char, 3> result_type;
typedef TinyVector<unsigned char, 3> value_type; typedef TinyVector<unsigned char, 3> value_type;
RGB2sRGBFunctor() RGB2sRGBFunctor()
{ {
for(int i=0; i<256; ++i) for(int i=0; i<256; ++i)
{ {
lut_[i] = detail::sRGBCorrection<unsigned char>(i, 255.0); lut_[i] = detail::sRGBCorrection<unsigned char>(i, 255.0);
} }
} }
skipping to change at line 466 skipping to change at line 490
{ {
lut_[i] = detail::sRGBCorrection<unsigned char>(i, max); lut_[i] = detail::sRGBCorrection<unsigned char>(i, max);
} }
} }
template <class V> template <class V>
TinyVector<unsigned char, 3> operator()(V const & rgb) const TinyVector<unsigned char, 3> operator()(V const & rgb) const
{ {
return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]); return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]);
} }
static std::string targetColorSpace()
{
return "sRGB";
}
}; };
template <class From, class To> template <class From, class To>
class FunctorTraits<RGB2sRGBFunctor<From, To> > class FunctorTraits<RGB2sRGBFunctor<From, To> >
: public FunctorTraitsBase<RGB2sRGBFunctor<From, To> > : public FunctorTraitsBase<RGB2sRGBFunctor<From, To> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into non-linear (raw ) RGB. /** \brief Convert non-linear (gamma corrected) R'G'B' into non-linear (raw ) RGB.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
R = R_{max} \left(\frac{R'}{R_{max}} \right)^{1/0.45} \qquad R = R_{max} \left(\frac{R'}{R_{max}} \right)^{1/0.45} \qquad
G = G_{max} \left(\frac{G'}{G_{max}} \right)^{1/0.45} \qquad G = G_{max} \left(\frac{G'}{G_{max}} \right)^{1/0.45} \qquad
B = B_{max} \left(\frac{B'}{B_{max}} \right)^{1/0.45} B = B_{max} \left(\frac{B'}{B_{max}} \right)^{1/0.45}
\f] \f]
skipping to change at line 542 skipping to change at line 571
/** apply the transformation /** apply the transformation
*/ */
result_type operator()(argument_type const & rgb) const result_type operator()(argument_type const & rgb) const
{ {
return TinyVector<To, 3>( return TinyVector<To, 3>(
detail::gammaCorrection<To>(rgb[0], gamma_, max_), detail::gammaCorrection<To>(rgb[0], gamma_, max_),
detail::gammaCorrection<To>(rgb[1], gamma_, max_), detail::gammaCorrection<To>(rgb[1], gamma_, max_),
detail::gammaCorrection<To>(rgb[2], gamma_, max_)); detail::gammaCorrection<To>(rgb[2], gamma_, max_));
} }
static std::string targetColorSpace()
{
return "RGB";
}
private: private:
component_type max_; component_type max_;
double gamma_; double gamma_;
}; };
template <> template <>
class RGBPrime2RGBFunctor<unsigned char, unsigned char> class RGBPrime2RGBFunctor<unsigned char, unsigned char>
{ {
unsigned char lut_[256]; unsigned char lut_[256];
public: public:
typedef TinyVector<unsigned char, 3> argument_type;
typedef TinyVector<unsigned char, 3> result_type;
typedef TinyVector<unsigned char, 3> value_type; typedef TinyVector<unsigned char, 3> value_type;
RGBPrime2RGBFunctor() RGBPrime2RGBFunctor()
{ {
for(int i=0; i<256; ++i) for(int i=0; i<256; ++i)
{ {
lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, 2 55.0); lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, 2 55.0);
} }
} }
skipping to change at line 577 skipping to change at line 615
{ {
lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, m ax); lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, m ax);
} }
} }
template <class V> template <class V>
TinyVector<unsigned char, 3> operator()(V const & rgb) const TinyVector<unsigned char, 3> operator()(V const & rgb) const
{ {
return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]); return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]);
} }
static std::string targetColorSpace()
{
return "RGB";
}
}; };
template <class From, class To> template <class From, class To>
class FunctorTraits<RGBPrime2RGBFunctor<From, To> > class FunctorTraits<RGBPrime2RGBFunctor<From, To> >
: public FunctorTraitsBase<RGBPrime2RGBFunctor<From, To> > : public FunctorTraitsBase<RGBPrime2RGBFunctor<From, To> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert standardized sRGB into non-linear (raw) RGB. /** \brief Convert standardized sRGB into non-linear (raw) RGB.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The sRGB color space is a slight improvement over the R'G'B' space. Is is now a widely accepted The sRGB color space is a slight improvement over the R'G'B' space. Is is now a widely accepted
international standard (IEC 61966-2.1) which is used by most consumer p roducts international standard (IEC 61966-2.1) which is used by most consumer p roducts
(digital cameras, printers, and screens). The functor realizes the tran sformation (digital cameras, printers, and screens). The functor realizes the tran sformation
\f[ \f[
C_{RGB} = \left\{\begin{array}{ll} C_{RGB} = \left\{\begin{array}{ll}
C_{sRGB} / 12.92 & \textrm{if }\frac{C_{sRGB}}{C_{max}} \le 0.04045 \\ C_{sRGB} / 12.92 & \textrm{if }\frac{C_{sRGB}}{C_{max}} \le 0.04045 \\
C_{max}\left( \frac{C_{sRGB}/C_{max}+0.055}{1.055}\right)^{2.4} & \ textrm{otherwise} C_{max}\left( \frac{C_{sRGB}/C_{max}+0.055}{1.055}\right)^{2.4} & \ textrm{otherwise}
skipping to change at line 656 skipping to change at line 699
/** apply the transformation /** apply the transformation
*/ */
result_type operator()(argument_type const & rgb) const result_type operator()(argument_type const & rgb) const
{ {
return TinyVector<To, 3>( return TinyVector<To, 3>(
detail::inverse_sRGBCorrection<To>(rgb[0], max_), detail::inverse_sRGBCorrection<To>(rgb[0], max_),
detail::inverse_sRGBCorrection<To>(rgb[1], max_), detail::inverse_sRGBCorrection<To>(rgb[1], max_),
detail::inverse_sRGBCorrection<To>(rgb[2], max_)); detail::inverse_sRGBCorrection<To>(rgb[2], max_));
} }
static std::string targetColorSpace()
{
return "RGB";
}
private: private:
component_type max_; component_type max_;
}; };
template <> template <>
class sRGB2RGBFunctor<unsigned char, unsigned char> class sRGB2RGBFunctor<unsigned char, unsigned char>
{ {
unsigned char lut_[256]; unsigned char lut_[256];
public: public:
typedef TinyVector<unsigned char, 3> argument_type;
typedef TinyVector<unsigned char, 3> result_type;
typedef TinyVector<unsigned char, 3> value_type; typedef TinyVector<unsigned char, 3> value_type;
sRGB2RGBFunctor() sRGB2RGBFunctor()
{ {
for(int i=0; i<256; ++i) for(int i=0; i<256; ++i)
{ {
lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, 255. 0); lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, 255. 0);
} }
} }
skipping to change at line 690 skipping to change at line 742
{ {
lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, max) ; lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, max) ;
} }
} }
template <class V> template <class V>
TinyVector<unsigned char, 3> operator()(V const & rgb) const TinyVector<unsigned char, 3> operator()(V const & rgb) const
{ {
return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]); return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut _[rgb[2]]);
} }
static std::string targetColorSpace()
{
return "RGB";
}
}; };
template <class From, class To> template <class From, class To>
class FunctorTraits<sRGB2RGBFunctor<From, To> > class FunctorTraits<sRGB2RGBFunctor<From, To> >
: public FunctorTraitsBase<sRGB2RGBFunctor<From, To> > : public FunctorTraitsBase<sRGB2RGBFunctor<From, To> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert linear (raw) RGB into standardized tri-stimulus XYZ. /** \brief Convert linear (raw) RGB into standardized tri-stimulus XYZ.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
According to ITU-R Recommendation BT.709, the functor realizes the tran sformation According to ITU-R Recommendation BT.709, the functor realizes the tran sformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
X & = & 0.412453\enspace R / R_{max} + 0.357580\enspace G / G_{max} + 0.180423\enspace B / B_{max}\\ X & = & 0.412453\enspace R / R_{max} + 0.357580\enspace G / G_{max} + 0.180423\enspace B / B_{max}\\
Y & = & 0.212671\enspace R / R_{max} + 0.715160\enspace G / G_{max} + 0.072169\enspace B / B_{max} \\ Y & = & 0.212671\enspace R / R_{max} + 0.715160\enspace G / G_{max} + 0.072169\enspace B / B_{max} \\
Z & = & 0.019334\enspace R / R_{max} + 0.119193\enspace G / G_{max} + 0.950227\enspace B / B_{max} Z & = & 0.019334\enspace R / R_{max} + 0.119193\enspace G / G_{max} + 0.950227\enspace B / B_{max}
\end{array} \end{array}
skipping to change at line 777 skipping to change at line 834
component_type red = rgb[0] / max_; component_type red = rgb[0] / max_;
component_type green = rgb[1] / max_; component_type green = rgb[1] / max_;
component_type blue = rgb[2] / max_; component_type blue = rgb[2] / max_;
result_type result; result_type result;
result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423* blue); result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423* blue);
result[1] = Convert::cast(0.212671*red + 0.715160*green + 0.072169* blue); result[1] = Convert::cast(0.212671*red + 0.715160*green + 0.072169* blue);
result[2] = Convert::cast(0.019334*red + 0.119193*green + 0.950227* blue); result[2] = Convert::cast(0.019334*red + 0.119193*green + 0.950227* blue);
return result; return result;
} }
static std::string targetColorSpace()
{
return "XYZ";
}
private: private:
component_type max_; component_type max_;
}; };
template <class T> template <class T>
class FunctorTraits<RGB2XYZFunctor<T> > class FunctorTraits<RGB2XYZFunctor<T> >
: public FunctorTraitsBase<RGB2XYZFunctor<T> > : public FunctorTraitsBase<RGB2XYZFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into standardized tr i-stimulus XYZ. /** \brief Convert non-linear (gamma corrected) R'G'B' into standardized tr i-stimulus XYZ.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
R'G'B' \Rightarrow RGB \Rightarrow XYZ R'G'B' \Rightarrow RGB \Rightarrow XYZ
\f] \f]
See vigra::RGBPrime2RGBFunctor and vigra::RGB2XYZFunctor for a descript ion of the two See vigra::RGBPrime2RGBFunctor and vigra::RGB2XYZFunctor for a descript ion of the two
steps. steps.
skipping to change at line 832 skipping to change at line 894
typedef TinyVector<component_type, 3> result_type; typedef TinyVector<component_type, 3> result_type;
/** \deprecated use argument_type and result_type /** \deprecated use argument_type and result_type
*/ */
typedef TinyVector<component_type, 3> value_type; typedef TinyVector<component_type, 3> value_type;
/** default constructor /** default constructor
The maximum value for each RGB component defaults to 255. The maximum value for each RGB component defaults to 255.
*/ */
RGBPrime2XYZFunctor() RGBPrime2XYZFunctor()
: max_(component_type(255.0)), gamma_(1.0/ 0.45) : gamma_(1.0/ 0.45), max_(component_type(255.0))
{} {}
/** constructor /** constructor
\arg max - the maximum value for each RGB component \arg max - the maximum value for each RGB component
*/ */
RGBPrime2XYZFunctor(component_type max) RGBPrime2XYZFunctor(component_type max)
: max_(max), gamma_(1.0/ 0.45) : gamma_(1.0/ 0.45), max_(max)
{} {}
/** apply the transformation /** apply the transformation
*/ */
result_type operator()(argument_type const & rgb) const result_type operator()(argument_type const & rgb) const
{ {
typedef detail::RequiresExplicitCast<component_type> Convert; typedef detail::RequiresExplicitCast<component_type> Convert;
component_type red = detail::gammaCorrection<component_type>(rgb[0] /max_, gamma_); component_type red = detail::gammaCorrection<component_type>(rgb[0] /max_, gamma_);
component_type green = detail::gammaCorrection<component_type>(rgb[ 1]/max_, gamma_); component_type green = detail::gammaCorrection<component_type>(rgb[ 1]/max_, gamma_);
component_type blue = detail::gammaCorrection<component_type>(rgb[2 ]/max_, gamma_); component_type blue = detail::gammaCorrection<component_type>(rgb[2 ]/max_, gamma_);
result_type result; result_type result;
result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423* blue); result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423* blue);
result[1] = Convert::cast(0.212671*red + 0.715160*green + 0.072169* blue); result[1] = Convert::cast(0.212671*red + 0.715160*green + 0.072169* blue);
result[2] = Convert::cast(0.019334*red + 0.119193*green + 0.950227* blue); result[2] = Convert::cast(0.019334*red + 0.119193*green + 0.950227* blue);
return result; return result;
} }
static std::string targetColorSpace()
{
return "XYZ";
}
private: private:
double gamma_; double gamma_;
component_type max_; component_type max_;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2XYZFunctor<T> > class FunctorTraits<RGBPrime2XYZFunctor<T> >
: public FunctorTraitsBase<RGBPrime2XYZFunctor<T> > : public FunctorTraitsBase<RGBPrime2XYZFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert standardized tri-stimulus XYZ into linear (raw) RGB. /** \brief Convert standardized tri-stimulus XYZ into linear (raw) RGB.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
According to ITU-R Recommendation BT.709, the functor realizes the tran sformation According to ITU-R Recommendation BT.709, the functor realizes the tran sformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
R & = & R_{max} (3.2404813432\enspace X - 1.5371515163\enspace Y - 0.4985363262\enspace Z) \\ R & = & R_{max} (3.2404813432\enspace X - 1.5371515163\enspace Y - 0.4985363262\enspace Z) \\
G & = & G_{max} (-0.9692549500\enspace X + 1.8759900015\enspace Y + 0.0415559266\enspace Z) \\ G & = & G_{max} (-0.9692549500\enspace X + 1.8759900015\enspace Y + 0.0415559266\enspace Z) \\
B & = & B_{max} (0.0556466391\enspace X - 0.2040413384\enspace Y + 1.0573110696\enspace Z) B & = & B_{max} (0.0556466391\enspace X - 0.2040413384\enspace Y + 1.0573110696\enspace Z)
\end{array} \end{array}
skipping to change at line 941 skipping to change at line 1008
result_type operator()(V const & xyz) const result_type operator()(V const & xyz) const
{ {
typedef detail::RequiresExplicitCast<component_type> Convert; typedef detail::RequiresExplicitCast<component_type> Convert;
component_type red = Convert::cast( 3.2404813432*xyz[0] - 1.53715 15163*xyz[1] - 0.4985363262*xyz[2]); component_type red = Convert::cast( 3.2404813432*xyz[0] - 1.53715 15163*xyz[1] - 0.4985363262*xyz[2]);
component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.87599 00015*xyz[1] + 0.0415559266*xyz[2]); component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.87599 00015*xyz[1] + 0.0415559266*xyz[2]);
component_type blue = Convert::cast( 0.0556466391*xyz[0] - 0.20404 13384*xyz[1] + 1.0573110696*xyz[2]); component_type blue = Convert::cast( 0.0556466391*xyz[0] - 0.20404 13384*xyz[1] + 1.0573110696*xyz[2]);
return value_type(NumericTraits<T>::fromRealPromote(red * max_), return value_type(NumericTraits<T>::fromRealPromote(red * max_),
NumericTraits<T>::fromRealPromote(green * max_), NumericTraits<T>::fromRealPromote(green * max_),
NumericTraits<T>::fromRealPromote(blue * max_)); NumericTraits<T>::fromRealPromote(blue * max_));
} }
static std::string targetColorSpace()
{
return "RGB";
}
}; };
template <class T> template <class T>
class FunctorTraits<XYZ2RGBFunctor<T> > class FunctorTraits<XYZ2RGBFunctor<T> >
: public FunctorTraitsBase<XYZ2RGBFunctor<T> > : public FunctorTraitsBase<XYZ2RGBFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert standardized tri-stimulus XYZ into non-linear (gamma cor rected) R'G'B'. /** \brief Convert standardized tri-stimulus XYZ into non-linear (gamma cor rected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
XYZ \Rightarrow RGB \Rightarrow R'G'B' XYZ \Rightarrow RGB \Rightarrow R'G'B'
\f] \f]
See vigra::XYZ2RGBFunctor and vigra::RGB2RGBPrimeFunctor for a descript ion of the two See vigra::XYZ2RGBFunctor and vigra::RGB2RGBPrimeFunctor for a descript ion of the two
steps. steps.
skipping to change at line 998 skipping to change at line 1070
typedef TinyVector<T, 3> result_type; typedef TinyVector<T, 3> result_type;
/** \deprecated use argument_type and result_type /** \deprecated use argument_type and result_type
*/ */
typedef TinyVector<T, 3> value_type; typedef TinyVector<T, 3> value_type;
/** default constructor. /** default constructor.
The maximum value for each RGB component defaults to 255. The maximum value for each RGB component defaults to 255.
*/ */
XYZ2RGBPrimeFunctor() XYZ2RGBPrimeFunctor()
: max_(component_type(255.0)), gamma_(0.45) : gamma_(0.45), max_(component_type(255.0))
{} {}
/** constructor /** constructor
\arg max - the maximum value for each RGB component \arg max - the maximum value for each RGB component
*/ */
XYZ2RGBPrimeFunctor(component_type max) XYZ2RGBPrimeFunctor(component_type max)
: max_(max), gamma_(0.45) : gamma_(0.45), max_(max)
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & xyz) const result_type operator()(V const & xyz) const
{ {
typedef detail::RequiresExplicitCast<component_type> Convert; typedef detail::RequiresExplicitCast<component_type> Convert;
component_type red = Convert::cast( 3.2404813432*xyz[0] - 1.53715 15163*xyz[1] - 0.4985363262*xyz[2]); component_type red = Convert::cast( 3.2404813432*xyz[0] - 1.53715 15163*xyz[1] - 0.4985363262*xyz[2]);
component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.87599 00015*xyz[1] + 0.0415559266*xyz[2]); component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.87599 00015*xyz[1] + 0.0415559266*xyz[2]);
component_type blue = Convert::cast( 0.0556466391*xyz[0] - 0.20404 13384*xyz[1] + 1.0573110696*xyz[2]); component_type blue = Convert::cast( 0.0556466391*xyz[0] - 0.20404 13384*xyz[1] + 1.0573110696*xyz[2]);
return value_type(NumericTraits<T>::fromRealPromote(detail::gammaCo rrection<component_type>(red, gamma_) * max_), return value_type(NumericTraits<T>::fromRealPromote(detail::gammaCo rrection<component_type>(red, gamma_) * max_),
NumericTraits<T>::fromRealPromote(detail::gammaCo rrection<component_type>(green, gamma_) * max_), NumericTraits<T>::fromRealPromote(detail::gammaCo rrection<component_type>(green, gamma_) * max_),
NumericTraits<T>::fromRealPromote(detail::gammaCo rrection<component_type>(blue, gamma_) * max_)); NumericTraits<T>::fromRealPromote(detail::gammaCo rrection<component_type>(blue, gamma_) * max_));
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<XYZ2RGBPrimeFunctor<T> > class FunctorTraits<XYZ2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<XYZ2RGBPrimeFunctor<T> > : public FunctorTraitsBase<XYZ2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CI E L*u*v*. /** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CI E L*u*v*.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \ mbox{if} \quad 0.008856 < \frac{Y}{Y_n}\\ L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \ mbox{if} \quad 0.008856 < \frac{Y}{Y_n}\\
& & \\ & & \\
L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\ L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\
& & \\ & & \\
skipping to change at line 1118 skipping to change at line 1195
component_type denom = Convert::cast(xyz[0] + 15.0*xyz[1] + 3.0 *xyz[2]); component_type denom = Convert::cast(xyz[0] + 15.0*xyz[1] + 3.0 *xyz[2]);
component_type uprime = Convert::cast(4.0 * xyz[0] / denom); component_type uprime = Convert::cast(4.0 * xyz[0] / denom);
component_type vprime = Convert::cast(9.0 * xyz[1] / denom); component_type vprime = Convert::cast(9.0 * xyz[1] / denom);
result[0] = L; result[0] = L;
result[1] = Convert::cast(13.0*L*(uprime - 0.197839)); result[1] = Convert::cast(13.0*L*(uprime - 0.197839));
result[2] = Convert::cast(13.0*L*(vprime - 0.468342)); result[2] = Convert::cast(13.0*L*(vprime - 0.468342));
} }
return result; return result;
} }
static std::string targetColorSpace()
{
return "Luv";
}
private: private:
double gamma_, kappa_, epsilon_; double gamma_, kappa_, epsilon_;
}; };
template <class T> template <class T>
class FunctorTraits<XYZ2LuvFunctor<T> > class FunctorTraits<XYZ2LuvFunctor<T> >
: public FunctorTraitsBase<XYZ2LuvFunctor<T> > : public FunctorTraitsBase<XYZ2LuvFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert perceptual uniform CIE L*u*v* into standardized tri-stim ulus XYZ. /** \brief Convert perceptual uniform CIE L*u*v* into standardized tri-stim ulus XYZ.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::XYZ2LuvFunctor The functor realizes the inverse of the transformation described in vig ra::XYZ2LuvFunctor
<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>)
*/ */
template <class T> template <class T>
class Luv2XYZFunctor class Luv2XYZFunctor
skipping to change at line 1195 skipping to change at line 1277
result[1] = Convert::cast( result[1] = Convert::cast(
luv[0] < 8.0 luv[0] < 8.0
? luv[0] * ikappa_ ? luv[0] * ikappa_
: VIGRA_CSTD::pow((luv[0] + 16.0) / 116.0, gamma_)); : VIGRA_CSTD::pow((luv[0] + 16.0) / 116.0, gamma_));
result[0] = Convert::cast(9.0*uprime*result[1] / 4.0 / vprime); result[0] = Convert::cast(9.0*uprime*result[1] / 4.0 / vprime);
result[2] = Convert::cast(((9.0 / vprime - 15.0)*result[1] - re sult[0])/ 3.0); result[2] = Convert::cast(((9.0 / vprime - 15.0)*result[1] - re sult[0])/ 3.0);
} }
return result; return result;
} }
static std::string targetColorSpace()
{
return "XYZ";
}
private: private:
double gamma_, ikappa_; double gamma_, ikappa_;
}; };
template <class T> template <class T>
class FunctorTraits<Luv2XYZFunctor<T> > class FunctorTraits<Luv2XYZFunctor<T> >
: public FunctorTraitsBase<Luv2XYZFunctor<T> > : public FunctorTraitsBase<Luv2XYZFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CI E L*a*b*. /** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CI E L*a*b*.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \ mbox{if} \quad \frac{216}{24389} < \frac{Y}{Y_n}\\ L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \ mbox{if} \quad \frac{216}{24389} < \frac{Y}{Y_n}\\
& & \\ & & \\
L^{*} & = & \frac{24389}{27} \enspace \frac{Y}{Y_n} \quad \mbox{oth erwise} \\ L^{*} & = & \frac{24389}{27} \enspace \frac{Y}{Y_n} \quad \mbox{oth erwise} \\
& & \\ & & \\
skipping to change at line 1284 skipping to change at line 1371
xyz[1] < epsilon_ xyz[1] < epsilon_
? kappa_ * xyz[1] ? kappa_ * xyz[1]
: 116.0 * ygamma - 16.0); : 116.0 * ygamma - 16.0);
result_type result; result_type result;
result[0] = L; result[0] = L;
result[1] = Convert::cast(500.0*(xgamma - ygamma)); result[1] = Convert::cast(500.0*(xgamma - ygamma));
result[2] = Convert::cast(200.0*(ygamma - zgamma)); result[2] = Convert::cast(200.0*(ygamma - zgamma));
return result; return result;
} }
static std::string targetColorSpace()
{
return "Lab";
}
private: private:
double gamma_, kappa_, epsilon_; double gamma_, kappa_, epsilon_;
}; };
template <class T> template <class T>
class FunctorTraits<XYZ2LabFunctor<T> > class FunctorTraits<XYZ2LabFunctor<T> >
: public FunctorTraitsBase<XYZ2LabFunctor<T> > : public FunctorTraitsBase<XYZ2LabFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert perceptual uniform CIE L*a*b* into standardized tri-stim ulus XYZ. /** \brief Convert perceptual uniform CIE L*a*b* into standardized tri-stim ulus XYZ.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::XYZ2LabFunctor The functor realizes the inverse of the transformation described in vig ra::XYZ2LabFunctor
<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>)
*/ */
template <class T> template <class T>
class Lab2XYZFunctor class Lab2XYZFunctor
skipping to change at line 1355 skipping to change at line 1447
component_type ygamma = Convert::cast(std::pow((double)Y, 1.0 / gam ma_)); component_type ygamma = Convert::cast(std::pow((double)Y, 1.0 / gam ma_));
component_type X = Convert::cast(std::pow(lab[1] / 500.0 + ygamma, gamma_) * 0.950456); component_type X = Convert::cast(std::pow(lab[1] / 500.0 + ygamma, gamma_) * 0.950456);
component_type Z = Convert::cast(std::pow(-lab[2] / 200.0 + ygamma, gamma_) * 1.088754); component_type Z = Convert::cast(std::pow(-lab[2] / 200.0 + ygamma, gamma_) * 1.088754);
result_type result; result_type result;
result[0] = X; result[0] = X;
result[1] = Y; result[1] = Y;
result[2] = Z; result[2] = Z;
return result; return result;
} }
static std::string targetColorSpace()
{
return "XYZ";
}
private: private:
double gamma_, ikappa_; double gamma_, ikappa_;
}; };
template <class T> template <class T>
class FunctorTraits<Lab2XYZFunctor<T> > class FunctorTraits<Lab2XYZFunctor<T> >
: public FunctorTraitsBase<Lab2XYZFunctor<T> > : public FunctorTraitsBase<Lab2XYZFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert linear (raw) RGB into perceptual uniform CIE L*u*v*. /** \brief Convert linear (raw) RGB into perceptual uniform CIE L*u*v*.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
RGB \Rightarrow XYZ \Rightarrow L^*u^*v^* RGB \Rightarrow XYZ \Rightarrow L^*u^*v^*
\f] \f]
See vigra::RGB2XYZFunctor and vigra::XYZ2LuvFunctor for a description o f the two See vigra::RGB2XYZFunctor and vigra::XYZ2LuvFunctor for a description o f the two
steps. The resulting color components will have the following bounds: steps. The resulting color components will have the following bounds:
skipping to change at line 1443 skipping to change at line 1540
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & rgb) const result_type operator()(V const & rgb) const
{ {
return xyz2luv(rgb2xyz(rgb)); return xyz2luv(rgb2xyz(rgb));
} }
static std::string targetColorSpace()
{
return "Luv";
}
private: private:
RGB2XYZFunctor<T> rgb2xyz; RGB2XYZFunctor<T> rgb2xyz;
XYZ2LuvFunctor<component_type> xyz2luv; XYZ2LuvFunctor<component_type> xyz2luv;
}; };
template <class T> template <class T>
class FunctorTraits<RGB2LuvFunctor<T> > class FunctorTraits<RGB2LuvFunctor<T> >
: public FunctorTraitsBase<RGB2LuvFunctor<T> > : public FunctorTraitsBase<RGB2LuvFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert linear (raw) RGB into perceptual uniform CIE L*a*b*. /** \brief Convert linear (raw) RGB into perceptual uniform CIE L*a*b*.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
RGB \Rightarrow XYZ \Rightarrow L^*a^*b^* RGB \Rightarrow XYZ \Rightarrow L^*a^*b^*
\f] \f]
See vigra::RGB2XYZFunctor and vigra::XYZ2LabFunctor for a description o f the two See vigra::RGB2XYZFunctor and vigra::XYZ2LabFunctor for a description o f the two
steps. The resulting color components will have the following bounds: steps. The resulting color components will have the following bounds:
skipping to change at line 1532 skipping to change at line 1634
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & rgb) const result_type operator()(V const & rgb) const
{ {
return xyz2lab(rgb2xyz(rgb)); return xyz2lab(rgb2xyz(rgb));
} }
static std::string targetColorSpace()
{
return "Lab";
}
private: private:
RGB2XYZFunctor<T> rgb2xyz; RGB2XYZFunctor<T> rgb2xyz;
XYZ2LabFunctor<component_type> xyz2lab; XYZ2LabFunctor<component_type> xyz2lab;
}; };
template <class T> template <class T>
class FunctorTraits<RGB2LabFunctor<T> > class FunctorTraits<RGB2LabFunctor<T> >
: public FunctorTraitsBase<RGB2LabFunctor<T> > : public FunctorTraitsBase<RGB2LabFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert perceptual uniform CIE L*u*v* into linear (raw) RGB. /** \brief Convert perceptual uniform CIE L*u*v* into linear (raw) RGB.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGB2LuvFunctor The functor realizes the inverse of the transformation described in vig ra::RGB2LuvFunctor
<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>)
*/ */
template <class T> template <class T>
class Luv2RGBFunctor class Luv2RGBFunctor
skipping to change at line 1594 skipping to change at line 1701
: xyz2rgb(max) : xyz2rgb(max)
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & luv) const result_type operator()(V const & luv) const
{ {
return xyz2rgb(luv2xyz(luv)); return xyz2rgb(luv2xyz(luv));
} }
static std::string targetColorSpace()
{
return "RGB";
}
}; };
template <class T> template <class T>
class FunctorTraits<Luv2RGBFunctor<T> > class FunctorTraits<Luv2RGBFunctor<T> >
: public FunctorTraitsBase<Luv2RGBFunctor<T> > : public FunctorTraitsBase<Luv2RGBFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert perceptual uniform CIE L*a*b* into linear (raw) RGB. /** \brief Convert perceptual uniform CIE L*a*b* into linear (raw) RGB.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGB2LabFunctor The functor realizes the inverse of the transformation described in vig ra::RGB2LabFunctor
<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>)
*/ */
template <class T> template <class T>
class Lab2RGBFunctor class Lab2RGBFunctor
skipping to change at line 1660 skipping to change at line 1772
: xyz2rgb(max) : xyz2rgb(max)
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & lab) const result_type operator()(V const & lab) const
{ {
return xyz2rgb(lab2xyz(lab)); return xyz2rgb(lab2xyz(lab));
} }
static std::string targetColorSpace()
{
return "RGB";
}
}; };
template <class T> template <class T>
class FunctorTraits<Lab2RGBFunctor<T> > class FunctorTraits<Lab2RGBFunctor<T> >
: public FunctorTraitsBase<Lab2RGBFunctor<T> > : public FunctorTraitsBase<Lab2RGBFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual unif orm CIE L*u*v*. /** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual unif orm CIE L*u*v*.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*u^*v^* R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*u^*v^*
\f] \f]
See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2Lu vFunctor for a description of the three See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2Lu vFunctor for a description of the three
steps. The resulting color components will have the following bounds: steps. The resulting color components will have the following bounds:
skipping to change at line 1739 skipping to change at line 1856
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & rgb) const result_type operator()(V const & rgb) const
{ {
return xyz2luv(rgb2xyz(rgb)); return xyz2luv(rgb2xyz(rgb));
} }
static std::string targetColorSpace()
{
return "Luv";
}
private: private:
RGBPrime2XYZFunctor<T> rgb2xyz; RGBPrime2XYZFunctor<T> rgb2xyz;
XYZ2LuvFunctor<component_type> xyz2luv; XYZ2LuvFunctor<component_type> xyz2luv;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2LuvFunctor<T> > class FunctorTraits<RGBPrime2LuvFunctor<T> >
: public FunctorTraitsBase<RGBPrime2LuvFunctor<T> > : public FunctorTraitsBase<RGBPrime2LuvFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual unif orm CIE L*a*b*. /** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual unif orm CIE L*a*b*.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the transformation The functor realizes the transformation
\f[ \f[
R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*a^*b^* R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*a^*b^*
\f] \f]
See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2La bFunctor for a description of the three See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2La bFunctor for a description of the three
steps. The resulting color components will have the following bounds: steps. The resulting color components will have the following bounds:
skipping to change at line 1821 skipping to change at line 1943
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & rgb) const result_type operator()(V const & rgb) const
{ {
return xyz2lab(rgb2xyz(rgb)); return xyz2lab(rgb2xyz(rgb));
} }
static std::string targetColorSpace()
{
return "Lab";
}
private: private:
RGBPrime2XYZFunctor<T> rgb2xyz; RGBPrime2XYZFunctor<T> rgb2xyz;
XYZ2LabFunctor<component_type> xyz2lab; XYZ2LabFunctor<component_type> xyz2lab;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2LabFunctor<T> > class FunctorTraits<RGBPrime2LabFunctor<T> >
: public FunctorTraitsBase<RGBPrime2LabFunctor<T> > : public FunctorTraitsBase<RGBPrime2LabFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert perceptual uniform CIE L*u*v* into non-linear (gamma cor rected) R'G'B'. /** \brief Convert perceptual uniform CIE L*u*v* into non-linear (gamma cor rected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGBPrime2LuvFunctor The functor realizes the inverse of the transformation described in vig ra::RGBPrime2LuvFunctor
<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>)
*/ */
template <class T> template <class T>
class Luv2RGBPrimeFunctor class Luv2RGBPrimeFunctor
skipping to change at line 1890 skipping to change at line 2017
: xyz2rgb(max) : xyz2rgb(max)
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & luv) const result_type operator()(V const & luv) const
{ {
return xyz2rgb(luv2xyz(luv)); return xyz2rgb(luv2xyz(luv));
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<Luv2RGBPrimeFunctor<T> > class FunctorTraits<Luv2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<Luv2RGBPrimeFunctor<T> > : public FunctorTraitsBase<Luv2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert perceptual uniform CIE L*a*b* into non-linear (gamma cor rected) R'G'B'. /** \brief Convert perceptual uniform CIE L*a*b* into non-linear (gamma cor rected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGBPrime2LabFunctor The functor realizes the inverse of the transformation described in vig ra::RGBPrime2LabFunctor
<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>)
*/ */
template <class T> template <class T>
class Lab2RGBPrimeFunctor class Lab2RGBPrimeFunctor
skipping to change at line 1956 skipping to change at line 2088
: xyz2rgb(max) : xyz2rgb(max)
{} {}
/** apply the transformation /** apply the transformation
*/ */
template <class V> template <class V>
result_type operator()(V const & lab) const result_type operator()(V const & lab) const
{ {
return xyz2rgb(lab2xyz(lab)); return xyz2rgb(lab2xyz(lab));
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<Lab2RGBPrimeFunctor<T> > class FunctorTraits<Lab2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<Lab2RGBPrimeFunctor<T> > : public FunctorTraitsBase<Lab2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into Y'PbPr color di fference components. /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'PbPr color di fference components.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
According to ITU-R Recommendation BT.601, the functor realizes the tran sformation According to ITU-R Recommendation BT.601, the functor realizes the tran sformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0. 114\enspace B / B_{max}\\ Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0. 114\enspace B / B_{max}\\
Pb & = & -0.1687358916\enspace R / R_{max} + 0.3312641084\enspace G / G_{max} + 0.5\enspace B / B_{max} \\ Pb & = & -0.1687358916\enspace R / R_{max} + 0.3312641084\enspace G / G_{max} + 0.5\enspace B / B_{max} \\
Pr & = & 0.5\enspace R / R_{max} + 0.4186875892\enspace G / G_{max} + 0.0813124108\enspace B / B_{max} Pr & = & 0.5\enspace R / R_{max} + 0.4186875892\enspace G / G_{max} + 0.0813124108\enspace B / B_{max}
\end{array} \end{array}
skipping to change at line 2057 skipping to change at line 2194
component_type green = rgb[1] / max_; component_type green = rgb[1] / max_;
component_type blue = rgb[2] / max_; component_type blue = rgb[2] / max_;
result_type result; result_type result;
result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue); result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue);
result[1] = Convert::cast(-0.1687358916*red - 0.3312641084*green + 0.5*blue); result[1] = Convert::cast(-0.1687358916*red - 0.3312641084*green + 0.5*blue);
result[2] = Convert::cast(0.5*red - 0.4186875892*green - 0.08131241 08*blue); result[2] = Convert::cast(0.5*red - 0.4186875892*green - 0.08131241 08*blue);
return result; return result;
} }
static std::string targetColorSpace()
{
return "Y'PbPr";
}
private: private:
component_type max_; component_type max_;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2YPrimePbPrFunctor<T> > class FunctorTraits<RGBPrime2YPrimePbPrFunctor<T> >
: public FunctorTraitsBase<RGBPrime2YPrimePbPrFunctor<T> > : public FunctorTraitsBase<RGBPrime2YPrimePbPrFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert Y'PbPr color difference components into non-linear (gamm a corrected) R'G'B'. /** \brief Convert Y'PbPr color difference components into non-linear (gamm a corrected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimePbPrFunctor The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimePbPrFunctor
<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>)
*/ */
template <class T> template <class T>
class YPrimePbPr2RGBPrimeFunctor class YPrimePbPr2RGBPrimeFunctor
skipping to change at line 2130 skipping to change at line 2272
result_type operator()(V const & ypbpr) const result_type operator()(V const & ypbpr) const
{ {
typedef detail::RequiresExplicitCast<component_type> Convert; typedef detail::RequiresExplicitCast<component_type> Convert;
component_type nred = Convert::cast(ypbpr[0] + 1.402*ypbpr[2]); component_type nred = Convert::cast(ypbpr[0] + 1.402*ypbpr[2]);
component_type ngreen = Convert::cast(ypbpr[0] - 0.3441362862*ypbpr [1] - 0.7141362862*ypbpr[2]); component_type ngreen = Convert::cast(ypbpr[0] - 0.3441362862*ypbpr [1] - 0.7141362862*ypbpr[2]);
component_type nblue = Convert::cast(ypbpr[0] + 1.772*ypbpr[1]); component_type nblue = Convert::cast(ypbpr[0] + 1.772*ypbpr[1]);
return result_type(NumericTraits<T>::fromRealPromote(nred * max_), return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
NumericTraits<T>::fromRealPromote(ngreen * max_) , NumericTraits<T>::fromRealPromote(ngreen * max_) ,
NumericTraits<T>::fromRealPromote(nblue * max_)) ; NumericTraits<T>::fromRealPromote(nblue * max_)) ;
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<YPrimePbPr2RGBPrimeFunctor<T> > class FunctorTraits<YPrimePbPr2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<YPrimePbPr2RGBPrimeFunctor<T> > : public FunctorTraitsBase<YPrimePbPr2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into Y'IQ components . /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'IQ components .
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
According to the PAL analog videa standard, the functor realizes the tr ansformation According to the PAL analog video standard, the functor realizes the tr ansformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0. 114\enspace B / B_{max}\\ Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0. 114\enspace B / B_{max}\\
I & = & 0.596\enspace R / R_{max} - 0.274\enspace G / G_{max} - 0.3 22\enspace B / B_{max} \\ I & = & 0.596\enspace R / R_{max} - 0.274\enspace G / G_{max} - 0.3 22\enspace B / B_{max} \\
Q & = & 0.212\enspace R / R_{max} - 0.523\enspace G / G_{max} + 0.3 11\enspace B / B_{max} Q & = & 0.212\enspace R / R_{max} - 0.523\enspace G / G_{max} + 0.3 11\enspace B / B_{max}
\end{array} \end{array}
\f] \f]
By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
skipping to change at line 2230 skipping to change at line 2377
component_type green = rgb[1] / max_; component_type green = rgb[1] / max_;
component_type blue = rgb[2] / max_; component_type blue = rgb[2] / max_;
result_type result; result_type result;
result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue); result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue);
result[1] = Convert::cast(0.596*red - 0.274*green - 0.322*blue); result[1] = Convert::cast(0.596*red - 0.274*green - 0.322*blue);
result[2] = Convert::cast(0.212*red - 0.523*green + 0.311*blue); result[2] = Convert::cast(0.212*red - 0.523*green + 0.311*blue);
return result; return result;
} }
static std::string targetColorSpace()
{
return "Y'IQ";
}
private: private:
component_type max_; component_type max_;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2YPrimeIQFunctor<T> > class FunctorTraits<RGBPrime2YPrimeIQFunctor<T> >
: public FunctorTraitsBase<RGBPrime2YPrimeIQFunctor<T> > : public FunctorTraitsBase<RGBPrime2YPrimeIQFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert Y'IQ color components into non-linear (gamma corrected) R'G'B'. /** \brief Convert Y'IQ color components into non-linear (gamma corrected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimeIQFunctor The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimeIQFunctor
<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>)
*/ */
template <class T> template <class T>
class YPrimeIQ2RGBPrimeFunctor class YPrimeIQ2RGBPrimeFunctor
skipping to change at line 2303 skipping to change at line 2455
result_type operator()(V const & yiq) const result_type operator()(V const & yiq) const
{ {
typedef detail::RequiresExplicitCast<component_type> Convert; typedef detail::RequiresExplicitCast<component_type> Convert;
component_type nred = Convert::cast(yiq[0] + 0.9548892043*yiq[1] + 0.6221039350*yiq[2]); component_type nred = Convert::cast(yiq[0] + 0.9548892043*yiq[1] + 0.6221039350*yiq[2]);
component_type ngreen = Convert::cast(yiq[0] - 0.2713547827*yiq[1] - 0.6475120259*yiq[2]); component_type ngreen = Convert::cast(yiq[0] - 0.2713547827*yiq[1] - 0.6475120259*yiq[2]);
component_type nblue = Convert::cast(yiq[0] - 1.1072510054*yiq[1] + 1.7024603738*yiq[2]); component_type nblue = Convert::cast(yiq[0] - 1.1072510054*yiq[1] + 1.7024603738*yiq[2]);
return result_type(NumericTraits<T>::fromRealPromote(nred * max_), return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
NumericTraits<T>::fromRealPromote(ngreen * max_) , NumericTraits<T>::fromRealPromote(ngreen * max_) ,
NumericTraits<T>::fromRealPromote(nblue * max_)) ; NumericTraits<T>::fromRealPromote(nblue * max_)) ;
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<YPrimeIQ2RGBPrimeFunctor<T> > class FunctorTraits<YPrimeIQ2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<YPrimeIQ2RGBPrimeFunctor<T> > : public FunctorTraitsBase<YPrimeIQ2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into Y'UV components . /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'UV components .
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
According to the NTSC analog videa standard, the functor realizes the t ransformation According to the NTSC analog video standard, the functor realizes the t ransformation
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0. 114\enspace B / B_{max}\\ Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0. 114\enspace B / B_{max}\\
U & = & -0.147\enspace R / R_{max} - 0.289\enspace G / G_{max} + 0. 436\enspace B / B_{max} \\ U & = & -0.147\enspace R / R_{max} - 0.289\enspace G / G_{max} + 0. 436\enspace B / B_{max} \\
V & = & 0.615\enspace R / R_{max} - 0.515\enspace G / G_{max} - 0.1 00\enspace B / B_{max} V & = & 0.615\enspace R / R_{max} - 0.515\enspace G / G_{max} - 0.1 00\enspace B / B_{max}
\end{array} \end{array}
\f] \f]
By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
skipping to change at line 2403 skipping to change at line 2560
component_type green = rgb[1] / max_; component_type green = rgb[1] / max_;
component_type blue = rgb[2] / max_; component_type blue = rgb[2] / max_;
result_type result; result_type result;
result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue); result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue);
result[1] = Convert::cast(-0.1471376975*red - 0.2888623025*green + 0.436*blue); result[1] = Convert::cast(-0.1471376975*red - 0.2888623025*green + 0.436*blue);
result[2] = Convert::cast(0.6149122807*red - 0.5149122807*green - 0 .100*blue); result[2] = Convert::cast(0.6149122807*red - 0.5149122807*green - 0 .100*blue);
return result; return result;
} }
static std::string targetColorSpace()
{
return "Y'UV";
}
private: private:
component_type max_; component_type max_;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2YPrimeUVFunctor<T> > class FunctorTraits<RGBPrime2YPrimeUVFunctor<T> >
: public FunctorTraitsBase<RGBPrime2YPrimeUVFunctor<T> > : public FunctorTraitsBase<RGBPrime2YPrimeUVFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert Y'UV color components into non-linear (gamma corrected) R'G'B'. /** \brief Convert Y'UV color components into non-linear (gamma corrected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimeUVFunctor The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimeUVFunctor
<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>)
*/ */
template <class T> template <class T>
class YPrimeUV2RGBPrimeFunctor class YPrimeUV2RGBPrimeFunctor
skipping to change at line 2476 skipping to change at line 2638
result_type operator()(V const & yuv) const result_type operator()(V const & yuv) const
{ {
typedef detail::RequiresExplicitCast<component_type> Convert; typedef detail::RequiresExplicitCast<component_type> Convert;
component_type nred = Convert::cast(yuv[0] + 1.140*yuv[2]); component_type nred = Convert::cast(yuv[0] + 1.140*yuv[2]);
component_type ngreen = Convert::cast(yuv[0] - 0.3946517044*yuv[1] - 0.580681431*yuv[2]); component_type ngreen = Convert::cast(yuv[0] - 0.3946517044*yuv[1] - 0.580681431*yuv[2]);
component_type nblue = Convert::cast(yuv[0] + 2.0321100920*yuv[1]) ; component_type nblue = Convert::cast(yuv[0] + 2.0321100920*yuv[1]) ;
return result_type(NumericTraits<T>::fromRealPromote(nred * max_), return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
NumericTraits<T>::fromRealPromote(ngreen * max_) , NumericTraits<T>::fromRealPromote(ngreen * max_) ,
NumericTraits<T>::fromRealPromote(nblue * max_)) ; NumericTraits<T>::fromRealPromote(nblue * max_)) ;
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<YPrimeUV2RGBPrimeFunctor<T> > class FunctorTraits<YPrimeUV2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<YPrimeUV2RGBPrimeFunctor<T> > : public FunctorTraitsBase<YPrimeUV2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert non-linear (gamma corrected) R'G'B' into Y'CbCr color di fference components. /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'CbCr color di fference components.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This functor basically applies the same transformation as vigra::RGBPri me2YPrimePbPrFunctor This functor basically applies the same transformation as vigra::RGBPri me2YPrimePbPrFunctor
but the color components are scaled so that they can be coded as 8 bit intergers with but the color components are scaled so that they can be coded as 8 bit integers with
minimal loss of information: minimal loss of information:
\f[ \f[
\begin{array}{rcl} \begin{array}{rcl}
16\leq & Y' & \leq 235 \\ 16\leq & Y' & \leq 235 \\
16 \leq & Cb & \leq 240 \\ 16 \leq & Cb & \leq 240 \\
16 \leq & Cr & \leq 240 16 \leq & Cr & \leq 240
\end{array} \end{array}
\f] \f]
skipping to change at line 2566 skipping to change at line 2733
component_type green = rgb[1] / max_; component_type green = rgb[1] / max_;
component_type blue = rgb[2] / max_; component_type blue = rgb[2] / max_;
result_type result; result_type result;
result[0] = Convert::cast(16.0 + 65.481*red + 128.553*green + 24.96 6*blue); result[0] = Convert::cast(16.0 + 65.481*red + 128.553*green + 24.96 6*blue);
result[1] = Convert::cast(128.0 - 37.79683972*red - 74.20316028*gre en + 112.0*blue); result[1] = Convert::cast(128.0 - 37.79683972*red - 74.20316028*gre en + 112.0*blue);
result[2] = Convert::cast(128.0 + 112.0*red - 93.78601998*green - 1 8.21398002*blue); result[2] = Convert::cast(128.0 + 112.0*red - 93.78601998*green - 1 8.21398002*blue);
return result; return result;
} }
static std::string targetColorSpace()
{
return "Y'CbCr";
}
private: private:
component_type max_; component_type max_;
}; };
template <class T> template <class T>
class FunctorTraits<RGBPrime2YPrimeCbCrFunctor<T> > class FunctorTraits<RGBPrime2YPrimeCbCrFunctor<T> >
: public FunctorTraitsBase<RGBPrime2YPrimeCbCrFunctor<T> > : public FunctorTraitsBase<RGBPrime2YPrimeCbCrFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
/** \brief Convert Y'CbCr color difference components into non-linear (gamm a corrected) R'G'B'. /** \brief Convert Y'CbCr color difference components into non-linear (gamm a corrected) R'G'B'.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimeCbCrFunctor The functor realizes the inverse of the transformation described in vig ra::RGBPrime2YPrimeCbCrFunctor
<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>)
*/ */
template <class T> template <class T>
class YPrimeCbCr2RGBPrimeFunctor class YPrimeCbCr2RGBPrimeFunctor
skipping to change at line 2643 skipping to change at line 2815
component_type cb = Convert::cast(ycbcr[1] - 128.0); component_type cb = Convert::cast(ycbcr[1] - 128.0);
component_type cr = Convert::cast(ycbcr[2] - 128.0); component_type cr = Convert::cast(ycbcr[2] - 128.0);
component_type nred = Convert::cast(0.00456621*y + 0.006258928571 *cr); component_type nred = Convert::cast(0.00456621*y + 0.006258928571 *cr);
component_type ngreen = Convert::cast(0.00456621*y - 0.001536322706 *cb - 0.003188108420*cr); component_type ngreen = Convert::cast(0.00456621*y - 0.001536322706 *cb - 0.003188108420*cr);
component_type nblue = Convert::cast(0.00456621*y + 0.007910714286 *cb); component_type nblue = Convert::cast(0.00456621*y + 0.007910714286 *cb);
return result_type(NumericTraits<T>::fromRealPromote(nred * max_), return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
NumericTraits<T>::fromRealPromote(ngreen * max_) , NumericTraits<T>::fromRealPromote(ngreen * max_) ,
NumericTraits<T>::fromRealPromote(nblue * max_)) ; NumericTraits<T>::fromRealPromote(nblue * max_)) ;
} }
static std::string targetColorSpace()
{
return "RGB'";
}
}; };
template <class T> template <class T>
class FunctorTraits<YPrimeCbCr2RGBPrimeFunctor<T> > class FunctorTraits<YPrimeCbCr2RGBPrimeFunctor<T> >
: public FunctorTraitsBase<YPrimeCbCr2RGBPrimeFunctor<T> > : public FunctorTraitsBase<YPrimeCbCr2RGBPrimeFunctor<T> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
}; };
skipping to change at line 2713 skipping to change at line 2890
YPbPr: white = [341.352, 1, 0] YPbPr: white = [341.352, 1, 0]
YCbCr: white = [341.352, 1, 0] YCbCr: white = [341.352, 1, 0]
YIQ: white = [154.581, 1, 1.24102e-16] YIQ: white = [154.581, 1, 1.24102e-16]
YUV: white = [229.992, 1, 9.81512e-17] YUV: white = [229.992, 1, 9.81512e-17]
*/ */
/** \ingroup ColorConversions /** \ingroup ColorConversions
\defgroup PolarColors Polar Color Coordinates \defgroup PolarColors Polar Color Coordinates
Transform colors from/to a polar representation (hue, brighness, satura Transform colors from/to a polar representation (hue, brightness, satur
tion). ation).
In many situations, this is more inituitive than direct initialization In many situations, this is more intuitive than direct initialization i
in a n a
particular color space. The polar coordinates are particular color space. The polar coordinates are
normalized so that a color angle of 0 degrees is always associated with red normalized so that a color angle of 0 degrees is always associated with red
(green is at about 120 degrees, blue at about 240 degrees - exact value s differ (green is at about 120 degrees, blue at about 240 degrees - exact value s differ
between color spaces). A saturation of 1 is the highest saturation that any RGB color between color spaces). A saturation of 1 is the highest saturation that any RGB color
gets after transformation into the respective color space, and saturati on 0 corresponds to gets after transformation into the respective color space, and saturati on 0 corresponds to
gray. Thus, different color spaces become somewhat comparable. gray. Thus, different color spaces become somewhat comparable.
*/ */
//@{ //@{
/** \brief Init L*a*b* color triple from polar representation. /** \brief Init L*a*b* color triple from polar representation.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declarations:</b> <b> Declarations:</b>
\code \code
TinyVector<float, 3> TinyVector<float, 3>
polar2Lab(double color, double brightness, double saturation); polar2Lab(double color, double brightness, double saturation);
TinyVector<float, 3> TinyVector<float, 3>
polar2Lab(TinyVector<float, 3> const & polar); polar2Lab(TinyVector<float, 3> const & polar);
skipping to change at line 2786 skipping to change at line 2963
/** \brief Create polar representation form L*a*b* /** \brief Create polar representation form L*a*b*
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
TinyVector<float, 3> lab2Polar(TinyVector<float, 3> const & lab); TinyVector<float, 3> lab2Polar(TinyVector<float, 3> const & lab);
} }
\endcode \endcode
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This realizes the inverse of the transformation described in This realizes the inverse of the transformation described in
\ref polar2Lab(). \ref polar2Lab().
*/ */
template <class V> template <class V>
TinyVector<float, 3> TinyVector<float, 3>
lab2Polar(V const & lab) lab2Polar(V const & lab)
{ {
TinyVector<float, 3> result; TinyVector<float, 3> result;
skipping to change at line 2810 skipping to change at line 2987
: VIGRA_CSTD::atan2(lab[2], lab[1])/M_PI*180.0-39.9977; : VIGRA_CSTD::atan2(lab[2], lab[1])/M_PI*180.0-39.9977;
result[0] = angle < 0.0 ? result[0] = angle < 0.0 ?
float(angle + 360.0) : float(angle + 360.0) :
float(angle); float(angle);
result[2] = float(VIGRA_CSTD::sqrt(lab[1]*lab[1] + lab[2]*lab[2])/133.8 09); result[2] = float(VIGRA_CSTD::sqrt(lab[1]*lab[1] + lab[2]*lab[2])/133.8 09);
return result; return result;
} }
/** \brief Init L*u*v* color triple from polar representation. /** \brief Init L*u*v* color triple from polar representation.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declarations:</b> <b> Declarations:</b>
\code \code
TinyVector<float, 3> TinyVector<float, 3>
polar2Luv(double color, double brightness, double saturation); polar2Luv(double color, double brightness, double saturation);
TinyVector<float, 3> TinyVector<float, 3>
polar2Luv(TinyVector<float, 3> const & polar); polar2Luv(TinyVector<float, 3> const & polar);
skipping to change at line 2871 skipping to change at line 3048
/** \brief Create polar representation form L*u*v* /** \brief Create polar representation form L*u*v*
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
TinyVector<float, 3> luv2Polar(TinyVector<float, 3> const & luv); TinyVector<float, 3> luv2Polar(TinyVector<float, 3> const & luv);
} }
\endcode \endcode
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This realizes the inverse of the transformation described in This realizes the inverse of the transformation described in
\ref polar2Luv(). \ref polar2Luv().
*/ */
template <class V> template <class V>
TinyVector<float, 3> TinyVector<float, 3>
luv2Polar(V const & luv) luv2Polar(V const & luv)
{ {
TinyVector<float, 3> result; TinyVector<float, 3> result;
skipping to change at line 2895 skipping to change at line 3072
: VIGRA_CSTD::atan2(luv[2], luv[1])/M_PI*180.0-12.1727; : VIGRA_CSTD::atan2(luv[2], luv[1])/M_PI*180.0-12.1727;
result[0] = angle < 0.0 ? result[0] = angle < 0.0 ?
float(angle + 360.0) : float(angle + 360.0) :
float(angle); float(angle);
result[2] = float(VIGRA_CSTD::sqrt(luv[1]*luv[1] + luv[2]*luv[2])/179.0 4); result[2] = float(VIGRA_CSTD::sqrt(luv[1]*luv[1] + luv[2]*luv[2])/179.0 4);
return result; return result;
} }
/** \brief Init Y'PbPr color triple from polar representation. /** \brief Init Y'PbPr color triple from polar representation.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declarations:</b> <b> Declarations:</b>
\code \code
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimePbPr(double color, double brightness, double saturation); polar2YPrimePbPr(double color, double brightness, double saturation);
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimePbPr(TinyVector<float, 3> const & polar); polar2YPrimePbPr(TinyVector<float, 3> const & polar);
skipping to change at line 2956 skipping to change at line 3133
/** \brief Create polar representation form Y'PbPr /** \brief Create polar representation form Y'PbPr
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
TinyVector<float, 3> yPrimePbPr2Polar(TinyVector<float, 3> const & ypbpr); TinyVector<float, 3> yPrimePbPr2Polar(TinyVector<float, 3> const & ypbpr);
} }
\endcode \endcode
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This realizes the inverse of the transformation described in This realizes the inverse of the transformation described in
\ref polar2YPrimePbPr(). \ref polar2YPrimePbPr().
*/ */
template <class V> template <class V>
TinyVector<float, 3> TinyVector<float, 3>
yPrimePbPr2Polar(V const & ypbpr) yPrimePbPr2Polar(V const & ypbpr)
{ {
TinyVector<float, 3> result; TinyVector<float, 3> result;
skipping to change at line 2980 skipping to change at line 3157
: VIGRA_CSTD::atan2(-ypbpr[1], ypbpr[2])/M_PI*180.0-18.6481; : VIGRA_CSTD::atan2(-ypbpr[1], ypbpr[2])/M_PI*180.0-18.6481;
result[0] = angle < 0.0 ? result[0] = angle < 0.0 ?
float(angle + 360.0) : float(angle + 360.0) :
float(angle); float(angle);
result[2] = float(VIGRA_CSTD::sqrt(ypbpr[1]*ypbpr[1] + ypbpr[2]*ypbpr[2 ])/0.533887); result[2] = float(VIGRA_CSTD::sqrt(ypbpr[1]*ypbpr[1] + ypbpr[2]*ypbpr[2 ])/0.533887);
return result; return result;
} }
/** \brief Init Y'CbCr color triple from polar representation. /** \brief Init Y'CbCr color triple from polar representation.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declarations:</b> <b> Declarations:</b>
\code \code
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimeCbCr(double color, double brightness, double saturation); polar2YPrimeCbCr(double color, double brightness, double saturation);
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimeCbCr(TinyVector<float, 3> const & polar); polar2YPrimeCbCr(TinyVector<float, 3> const & polar);
skipping to change at line 3041 skipping to change at line 3218
/** \brief Create polar representation form Y'CbCr /** \brief Create polar representation form Y'CbCr
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
TinyVector<float, 3> yPrimeCbCr2Polar(TinyVector<float, 3> const & ycbcr); TinyVector<float, 3> yPrimeCbCr2Polar(TinyVector<float, 3> const & ycbcr);
} }
\endcode \endcode
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This realizes the inverse of the transformation described in This realizes the inverse of the transformation described in
\ref polar2YPrimeCbCr(). \ref polar2YPrimeCbCr().
*/ */
template <class V> template <class V>
TinyVector<float, 3> TinyVector<float, 3>
yPrimeCbCr2Polar(V const & ycbcr) yPrimeCbCr2Polar(V const & ycbcr)
{ {
TinyVector<float, 3> result; TinyVector<float, 3> result;
skipping to change at line 3067 skipping to change at line 3244
: VIGRA_CSTD::atan2(-cb, cr)/M_PI*180.0-18.6482; : VIGRA_CSTD::atan2(-cb, cr)/M_PI*180.0-18.6482;
result[0] = angle < 0.0 ? result[0] = angle < 0.0 ?
float(angle + 360.0) : float(angle + 360.0) :
float(angle); float(angle);
result[2] = float(VIGRA_CSTD::sqrt(cb*cb + cr*cr)/119.591); result[2] = float(VIGRA_CSTD::sqrt(cb*cb + cr*cr)/119.591);
return result; return result;
} }
/** \brief Init Y'IQ color triple from polar representation. /** \brief Init Y'IQ color triple from polar representation.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declarations:</b> <b> Declarations:</b>
\code \code
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimeIQ(double color, double brightness, double saturation); polar2YPrimeIQ(double color, double brightness, double saturation);
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimeIQ(TinyVector<float, 3> const & polar); polar2YPrimeIQ(TinyVector<float, 3> const & polar);
skipping to change at line 3128 skipping to change at line 3305
/** \brief Create polar representation form Y'IQ /** \brief Create polar representation form Y'IQ
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
TinyVector<float, 3> yPrimeIQ2Polar(TinyVector<float, 3> const & yi q); TinyVector<float, 3> yPrimeIQ2Polar(TinyVector<float, 3> const & yi q);
} }
\endcode \endcode
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This realizes the inverse of the transformation described in This realizes the inverse of the transformation described in
\ref polar2YPrimeIQ(). \ref polar2YPrimeIQ().
*/ */
template <class V> template <class V>
TinyVector<float, 3> TinyVector<float, 3>
yPrimeIQ2Polar(V const & yiq) yPrimeIQ2Polar(V const & yiq)
{ {
TinyVector<float, 3> result; TinyVector<float, 3> result;
skipping to change at line 3152 skipping to change at line 3329
: VIGRA_CSTD::atan2(-yiq[2], yiq[1])/M_PI*180.0+19.5807; : VIGRA_CSTD::atan2(-yiq[2], yiq[1])/M_PI*180.0+19.5807;
result[0] = angle < 0.0 ? result[0] = angle < 0.0 ?
float(angle + 360.0) : float(angle + 360.0) :
float(angle); float(angle);
result[2] = float(VIGRA_CSTD::sqrt(yiq[1]*yiq[1] + yiq[2]*yiq[2])/0.632 582); result[2] = float(VIGRA_CSTD::sqrt(yiq[1]*yiq[1] + yiq[2]*yiq[2])/0.632 582);
return result; return result;
} }
/** \brief Init Y'UV color triple from polar representation. /** \brief Init Y'UV color triple from polar representation.
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declarations:</b> <b> Declarations:</b>
\code \code
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimeUV(double color, double brightness, double saturation); polar2YPrimeUV(double color, double brightness, double saturation);
TinyVector<float, 3> TinyVector<float, 3>
polar2YPrimeUV(TinyVector<float, 3> const & polar); polar2YPrimeUV(TinyVector<float, 3> const & polar);
skipping to change at line 3213 skipping to change at line 3390
/** \brief Create polar representation form Y'UV /** \brief Create polar representation form Y'UV
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
TinyVector<float, 3> yPrimeUV2Polar(TinyVector<float, 3> const & yu v); TinyVector<float, 3> yPrimeUV2Polar(TinyVector<float, 3> const & yu v);
} }
\endcode \endcode
<b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co lorconversions.hxx</a>\><br> <b>\#include</b> \<vigra/colorconversions.hxx\><br>
Namespace: vigra Namespace: vigra
This realizes the inverse of the transformation described in This realizes the inverse of the transformation described in
\ref polar2YPrimeUV(). \ref polar2YPrimeUV().
*/ */
template <class V> template <class V>
TinyVector<float, 3> TinyVector<float, 3>
yPrimeUV2Polar(V const & yuv) yPrimeUV2Polar(V const & yuv)
{ {
TinyVector<float, 3> result; TinyVector<float, 3> result;
 End of changes. 87 change blocks. 
53 lines changed or deleted 230 lines changed or added


 combineimages.hxx   combineimages.hxx 
skipping to change at line 157 skipping to change at line 157
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="combineimages_8hxx-source.html">vigra/c ombineimages.hxx</a>\><br> <b>\#include</b> \<vigra/combineimages.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <functional> // for plus #include <functional> // for plus
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<SrcValueType>());
skipping to change at line 296 skipping to change at line 296
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="combineimages_8hxx-source.html">vigra/c ombineimages.hxx</a>\><br> <b>\#include</b> \<vigra/combineimages.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <functional> // for plus #include <functional> // for plus
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()),
skipping to change at line 442 skipping to change at line 442
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="combineimages_8hxx-source.html">vigra/c ombineimages.hxx</a>\><br> <b>\#include</b> \<vigra/combineimages.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
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());
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 config.hxx   config.hxx 
skipping to change at line 53 skipping to change at line 53
// // // //
// VisualC++ 5.0 // // VisualC++ 5.0 //
// // // //
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#ifdef _MSC_VER #ifdef _MSC_VER
#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
#define NO_COVARIANT_RETURN_TYPES #define NO_COVARIANT_RETURN_TYPES
#ifdef VIGRA_NO_STD_MINMAX // activate if necessary #ifdef VIGRA_NO_STD_MINMAX // activate if necessary
namespace std { namespace std {
template<class T> template<class T>
const T& min(const T& x, const T& y) const T& min(const T& x, const T& y)
{ {
return (y < x) return (y < x)
? y ? y
: x; : x;
} }
template<class T> template<class T>
const T& max(const T& x, const T& y) const T& max(const T& x, const T& y)
{ {
return (x < y) return (x < y)
? y ? y
: x; : x;
} }
} }
#endif // VIGRA_NO_STD_MINMAX #endif // VIGRA_NO_STD_MINMAX
#endif // (_MSC_VER < 1300) #endif // (_MSC_VER < 1300)
#if _MSC_VER < 1310 #if _MSC_VER < 1310
#pragma warning( disable : 4786 4250 4244 4305) #pragma warning( disable : 4786 4250 4244 4305)
#define NO_PARTIAL_TEMPLATE_SPECIALIZATION #define NO_PARTIAL_TEMPLATE_SPECIALIZATION
#define NO_OUT_OF_LINE_MEMBER_TEMPLATES #define NO_OUT_OF_LINE_MEMBER_TEMPLATES
#include <cmath> #include <cmath>
#ifdef _MSC_EXTENSIONS #ifdef _MSC_EXTENSIONS
#ifndef CMATH_NOT_IN_STD #ifndef CMATH_NOT_IN_STD
namespace std { namespace std {
#endif // CMATH_NOT_IN_STD #endif // CMATH_NOT_IN_STD
inline double abs(double v) { return fabs(v); } inline double abs(double v) { return fabs(v); }
inline float abs(float v) { return fabs(v); } inline float abs(float v) { return fabs(v); }
#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
#define VIGRA_NEED_BIN_STREAMS #define VIGRA_NEED_BIN_STREAMS
#ifdef VIGRA_DLL #ifdef VIGRA_DLL
skipping to change at line 131 skipping to change at line 131
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#if defined(__GNUC__) #if defined(__GNUC__)
#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
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wshadow"
#endif // __GNUC__ #endif // __GNUC__
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// // // //
// MingW // // MingW //
// // // //
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
#if defined(__MINGW32__) #if defined(__MINGW32__)
#define VIGRA_NEED_BIN_STREAMS #define VIGRA_NEED_BIN_STREAMS
 End of changes. 10 change blocks. 
31 lines changed or deleted 36 lines changed or added


 configVersion.hxx   configVersion.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_VERSION_HXX #ifndef VIGRA_CONFIG_VERSION_HXX
#define VIGRA_CONFIG_VERSION_HXX #define VIGRA_CONFIG_VERSION_HXX
#define VIGRA_VERSION_MAJOR 1 #define VIGRA_VERSION_MAJOR 1
#define VIGRA_VERSION_MINOR 7 #define VIGRA_VERSION_MINOR 8
#define VIGRA_VERSION_PATCH 0 #define VIGRA_VERSION_PATCH 0
#define VIGRA_VERSION "1.7.0" #define VIGRA_VERSION "1.8.0"
#endif /* VIGRA_CONFIG_VERSION_HXX */ #endif /* VIGRA_CONFIG_VERSION_HXX */
 End of changes. 1 change blocks. 
4 lines changed or deleted 4 lines changed or added


 contourcirculator.hxx   contourcirculator.hxx 
skipping to change at line 88 skipping to change at line 88
{ {
area += crack.diff().x * crack.pos().y - area += crack.diff().x * crack.pos().y -
crack.diff().y * crack.pos().x; crack.diff().y * crack.pos().x;
} }
while(++crack != crackend); while(++crack != crackend);
area /= 2; area /= 2;
std::cout << "Area of region " << *region_anchor << ": " << area << std ::endl; std::cout << "Area of region " << *region_anchor << ": " << area << std ::endl;
\endcode \endcode
<b>\#include</b> \<<a href="contourcirculator_8hxx-source.html">vigra/c ontourcirculator.hxx</a>\><br> <b>\#include</b> \<vigra/contourcirculator.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class IMAGEITERATOR> template <class IMAGEITERATOR>
class CrackContourCirculator class CrackContourCirculator
{ {
typedef NeighborhoodCirculator<IMAGEITERATOR, EightNeighborCode> typedef NeighborhoodCirculator<IMAGEITERATOR, EightNeighborCode>
NEIGHBORHOODCIRCULATOR; NEIGHBORHOODCIRCULATOR;
typedef typename IMAGEITERATOR::value_type label_type; typedef typename IMAGEITERATOR::value_type label_type;
protected: protected:
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 convolution.hxx   convolution.hxx 
skipping to change at line 50 skipping to change at line 50
#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"
/** \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> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\><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 the most common 2D convo lution filters</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 <LI> \ref StandardConvolution
skipping to change at line 233 skipping to change at line 233
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);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
// implement sobel filter in x-direction // implement sobel filter in x-direction
Kernel1D<double> kx, ky; Kernel1D<double> kx, ky;
kx.initSymmetricGradient(); kx.initSymmetricGradient();
ky.initBinomial(1); ky.initBinomial(1);
skipping to change at line 337 skipping to change at line 337
{ {
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);
} }
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\code \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
skipping to change at line 429 skipping to change at line 429
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage 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) ; vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0, 0.5) ;
\endcode \endcode
skipping to change at line 500 skipping to change at line 500
/********************************************************/ /********************************************************/
/* */ /* */
/* 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. The function uses Gaussian kernel of the given scale. If two scales are provided,
<TT>BORDER_TREATMENT_REFLECT</TT>. smoothing in x and y direction will have different strength.
The function uses <TT>BORDER_TREATMENT_REFLECT</TT>.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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); 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 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_x, double scale_y = scale_x);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\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
*/ */
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 gaussianSmoothing(SrcIterator supperleft, void
SrcIterator slowerright, SrcAccessor sa, gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAcces
DestIterator dupperleft, DestAccessor da, sor sa,
double scale) DestIterator dupperleft, DestAccessor da,
double scale_x, double scale_y)
{ {
typedef typename typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote NumericTraits<typename SrcAccessor::value_type>::RealPromote
TmpType; TmpType;
BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization); BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
Kernel1D<double> smooth; Kernel1D<double> smooth_x, smooth_y;
smooth.initGaussian(scale); smooth_x.initGaussian(scale_x);
smooth.setBorderTreatment(BORDER_TREATMENT_REFLECT); smooth_x.setBorderTreatment(BORDER_TREATMENT_REFLECT);
smooth_y.initGaussian(scale_y);
smooth_y.setBorderTreatment(BORDER_TREATMENT_REFLECT);
separableConvolveX(srcIterRange(supperleft, slowerright, sa), separableConvolveX(srcIterRange(supperleft, slowerright, sa),
destImage(tmp), kernel1d(smooth)); destImage(tmp), kernel1d(smooth_x));
separableConvolveY(srcImageRange(tmp), separableConvolveY(srcImageRange(tmp),
destIter(dupperleft, da), kernel1d(smooth)); destIter(dupperleft, da), kernel1d(smooth_y));
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAcces
sor sa,
DestIterator dupperleft, DestAccessor da,
double scale)
{
gaussianSmoothing(supperleft, slowerright, sa,
dupperleft, da,
scale, scale);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
double scale_x, double scale_y)
{
gaussianSmoothing(src.first, src.second, src.third,
dest.first, dest.second, scale_x, scale_y);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
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); dest.first, dest.second, 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.
skipping to change at line 643 skipping to change at line 669
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\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
skipping to change at line 728 skipping to change at line 754
gaussianGradient(src.first, src.second, src.third, gaussianGradient(src.first, src.second, src.third,
dest.first, dest.second, scale); dest.first, dest.second, 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 sqaured magnitudes. return value is the square root of the sum of these squared magnitudes.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 758 skipping to change at line 784
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\code \code
vigra::FImage src(w,h), grad(w,h); vigra::FImage src(w,h), grad(w,h);
... ...
// calculate gradient magnitude at scale = 3.0 // calculate gradient magnitude at scale = 3.0
vigra::gaussianGradientMagnitude(srcImageRange(src), destImage(grad), 3 .0); vigra::gaussianGradientMagnitude(srcImageRange(src), destImage(grad), 3 .0);
\endcode \endcode
skipping to change at line 840 skipping to change at line 866
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\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
skipping to change at line 960 skipping to change at line 986
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\code \code
vigra::FImage src(w,h), hxx(w,h), hxy(w,h), hyy(w,h); vigra::FImage src(w,h), hxx(w,h), hxy(w,h), hyy(w,h);
... ...
// calculate Hessian of Gaussian at scale = 3.0 // calculate Hessian of Gaussian at scale = 3.0
vigra::hessianMatrixOfGaussian(srcImageRange(src), vigra::hessianMatrixOfGaussian(srcImageRange(src),
destImage(hxx), destImage(hxy), destImage(hyy), 3.0); destImage(hxx), destImage(hxy), destImage(hyy), 3.0);
\endcode \endcode
skipping to change at line 1119 skipping to change at line 1145
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu tion.hxx</a>\> <b>\#include</b> \<vigra/convolution.hxx\>
\code \code
vigra::FImage src(w,h), stxx(w,h), stxy(w,h), styy(w,h); vigra::FImage src(w,h), stxx(w,h), stxy(w,h), styy(w,h);
vigra::BasicImage<TinyVector<float, 3> > st(w,h); vigra::BasicImage<TinyVector<float, 3> > st(w,h);
... ...
// 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
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);
 End of changes. 19 change blocks. 
25 lines changed or deleted 53 lines changed or added


 copyimage.hxx   copyimage.hxx 
skipping to change at line 132 skipping to change at line 132
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> \<<a href="copyimage_8hxx-source.html">vigra/copyi mage.hxx</a>\><br> <b>\#include</b> \<vigra/copyimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::copyImage(srcImageRange(src), destImage(dest)); vigra::copyImage(srcImageRange(src), destImage(dest));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
skipping to change at line 258 skipping to change at line 258
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> \<<a href="copyimage_8hxx-source.html">vigra/copyi mage.hxx</a>\><br> <b>\#include</b> \<vigra/copyimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::copyImageIf(srcImageRange(src), maskImage(mask), destImage(dest) ); vigra::copyImageIf(srcImageRange(src), maskImage(mask), destImage(dest) );
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 cornerdetection.hxx   cornerdetection.hxx 
skipping to change at line 165 skipping to change at line 165
\ref structureTensor(). Then the entries of the structure tensor are co mbined as \ref structureTensor(). Then the entries of the structure tensor are co mbined as
\f[ \f[
\mbox{\rm CornerResponse} = \mbox{\rm det(StructureTensor)} - 0.04 \mbox{\rm tr(StructureTensor)}^2 \mbox{\rm CornerResponse} = \mbox{\rm det(StructureTensor)} - 0.04 \mbox{\rm tr(StructureTensor)}^2
= A B - C^2 - 0.04 (A + B)^2 = A B - C^2 - 0.04 (A + B)^2
\f] \f]
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 linaer 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 arguments explicitly:
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
skipping to change at line 199 skipping to change at line 199
inline 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="cornerdetection_8hxx-source.html">vigra /cornerdetection.hxx</a>\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
... ...
skipping to change at line 357 skipping to change at line 357
inline 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="cornerdetection_8hxx-source.html">vigra /cornerdetection.hxx</a>\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
... ...
skipping to change at line 505 skipping to change at line 505
inline 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="cornerdetection_8hxx-source.html">vigra /cornerdetection.hxx</a>\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
... ...
skipping to change at line 643 skipping to change at line 643
inline 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="cornerdetection_8hxx-source.html">vigra /cornerdetection.hxx</a>\><br> <b>\#include</b> \<vigra/cornerdetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
... ...
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 diff2d.hxx   diff2d.hxx 
skipping to change at line 133 skipping to change at line 133
static void increment(BaseType & d) static void increment(BaseType & d)
{ ++d.y; } { ++d.y; }
static void decrement(BaseType & d) static void decrement(BaseType & d)
{ --d.y; } { --d.y; }
static void advance(BaseType & d, difference_type n) static void advance(BaseType & d, difference_type n)
{ d.y += n; } { d.y += n; }
}; };
/** \addtogroup RangesAndPoints Two-dimensional Ranges and Points /** \addtogroup RangesAndPoints Ranges and Points
Specify a 2D position, extent, or rectangle. Specify 2-D and N-D positions, extents, and boxes.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* Diff2D */ /* Diff2D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Two dimensional difference vector. /** \brief Two dimensional difference vector.
skipping to change at line 179 skipping to change at line 179
Diff2D is also returned by <TT>image.size()</TT>, so that we can create Diff2D is also returned by <TT>image.size()</TT>, so that we can create
new images by calculating their size using Diff2D's arithmetic new images by calculating their size using Diff2D's arithmetic
functions: functions:
\code \code
// create an image that is 10 pixels smaller in each direction // create an image that is 10 pixels smaller in each direction
Image new_image(old_image.size() - Diff2D(10,10)); Image new_image(old_image.size() - Diff2D(10,10));
\endcode \endcode
<b>\#include</b> \<<a href="diff2d_8hxx-source.html">vigra/utilities.hx x</a>\><br> <b>\#include</b> \<vigra/diff2d.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class Diff2D class Diff2D
{ {
public: public:
/** The iterator's value type: a coordinate. /** The iterator's value type: a coordinate.
*/ */
typedef Diff2D PixelType; typedef Diff2D PixelType;
/** The iterator's value type: a coordinate. /** The iterator's value type: a coordinate.
skipping to change at line 474 skipping to change at line 474
Specializes \ref Diff2D for the specification of a 2-dimensional Specializes \ref Diff2D for the specification of a 2-dimensional
extent, in contrast to a point or position (for the latter extent, in contrast to a point or position (for the latter
use \ref Point2D). use \ref Point2D).
\code \code
// create an image that is 10 pixels squared // create an image that is 10 pixels squared
Image new_image(Size2D(10,10)); Image new_image(Size2D(10,10));
\endcode \endcode
<b>\#include</b> \<<a href="diff2d_8hxx-source.html">vigra/utilities.hx x</a>\><br> <b>\#include</b> \<vigra/diff2d.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class Size2D : public Diff2D class Size2D : public Diff2D
{ {
public: public:
/** Default Constructor. Init point at position (0,0) /** Default Constructor. Init point at position (0,0)
*/ */
Size2D() Size2D()
{} {}
skipping to change at line 584 skipping to change at line 584
Specializes \ref Diff2D for the specification of a 2-dimensional Specializes \ref Diff2D for the specification of a 2-dimensional
point or position, in contrast to an extent (for the latter point or position, in contrast to an extent (for the latter
use \ref Size2D). use \ref Size2D).
\code \code
// access an image at a point // access an image at a point
value = image[Point2D(10, 20)]; value = image[Point2D(10, 20)];
\endcode \endcode
<b>\#include</b> \<<a href="diff2d_8hxx-source.html">vigra/utilities.hx x</a>\><br> <b>\#include</b> \<vigra/diff2d.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class Point2D : public Diff2D class Point2D : public Diff2D
{ {
public: public:
/** The iterator's value type: a coordinate. /** The iterator's value type: a coordinate.
*/ */
typedef Point2D PixelType; typedef Point2D PixelType;
/** The iterator's value type: a coordinate. /** The iterator's value type: a coordinate.
skipping to change at line 863 skipping to change at line 863
Point2D p(0,100); Point2D p(0,100);
Rect2D r3 = r1 | r2; // upper left is (0,0), lower right is (30, 35) Rect2D r3 = r1 | r2; // upper left is (0,0), lower right is (30, 35)
assert(r3.contains(r2)); assert(r3.contains(r2));
assert(!r3.contains(p)); assert(!r3.contains(p));
r3 |= p; // lower right now (30,101) so that p is inside r3 r3 |= p; // lower right now (30,101) so that p is inside r3
assert(r3.contains(p)); assert(r3.contains(p));
\endcode \endcode
<b>\#include</b> \<<a href="diff2d_8hxx-source.html">vigra/utilities.hx x</a>\><br> <b>\#include</b> \<vigra/diff2d.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class Rect2D class Rect2D
{ {
Point2D upperLeft_, lowerRight_; Point2D upperLeft_, lowerRight_;
public: public:
/** Construct a null rectangle (isEmpty() will return true) /** Construct a null rectangle (isEmpty() will return true)
*/ */
Rect2D() Rect2D()
skipping to change at line 1271 skipping to change at line 1271
upperLeft_.y = r.upperLeft_.y; upperLeft_.y = r.upperLeft_.y;
if(r.lowerRight_.x < lowerRight_.x) if(r.lowerRight_.x < lowerRight_.x)
lowerRight_.x = r.lowerRight_.x; lowerRight_.x = r.lowerRight_.x;
if(r.lowerRight_.y < lowerRight_.y) if(r.lowerRight_.y < lowerRight_.y)
lowerRight_.y = r.lowerRight_.y; lowerRight_.y = r.lowerRight_.y;
return *this; return *this;
} }
/** Scale this rectangle by the given factor. /** Scale this rectangle by the given factor.
* To be specific, both upperLeft() and lowerRight() are * To be specific, both upperLeft() and lowerRight() are
* multiplicated by `factor`. * multiplied by `factor`.
*/ */
Rect2D & operator*=(int factor) Rect2D & operator*=(int factor)
{ {
upperLeft_ *= factor; upperLeft_ *= factor;
lowerRight_ *= factor; lowerRight_ *= factor;
return *this; return *this;
} }
/** Scale this rectangle by the given factor. /** Scale this rectangle by the given factor.
* To be specific, both upperLeft() and lowerRight() are * To be specific, both upperLeft() and lowerRight() are
* multiplicated by `factor`. * multiplied by `factor`.
*/ */
Rect2D & operator*=(double factor) Rect2D & operator*=(double factor)
{ {
upperLeft_ *= factor; upperLeft_ *= factor;
lowerRight_ *= factor; lowerRight_ *= factor;
return *this; return *this;
} }
/** Return rectangle scaled by the given factor. /** Return rectangle scaled by the given factor.
* To be specific, both upperLeft() and lowerRight() are * To be specific, both upperLeft() and lowerRight() are
* multiplicated by `factor`. * multiplied by `factor`.
*/ */
Rect2D operator*(int factor) const Rect2D operator*(int factor) const
{ {
return Rect2D(*this)*=factor; return Rect2D(*this)*=factor;
} }
/** Return rectangle scaled by the given factor. /** Return rectangle scaled by the given factor.
* To be specific, both upperLeft() and lowerRight() are * To be specific, both upperLeft() and lowerRight() are
* multiplicated by `factor`. * multiplied by `factor`.
*/ */
Rect2D operator*(double factor) const Rect2D operator*(double factor) const
{ {
return Rect2D(*this)*=factor; return Rect2D(*this)*=factor;
} }
/** Intersects this rectangle with the given one. The result /** Intersects this rectangle with the given one. The result
* is the maximal rectangle contained in both original ones. * is the maximal rectangle contained in both original ones.
* Intersecting with an empty rectangle will yield again an * Intersecting with an empty rectangle will yield again an
* empty rectangle. * empty rectangle.
 End of changes. 10 change blocks. 
10 lines changed or deleted 10 lines changed or added


 distancetransform.hxx   distancetransform.hxx 
skipping to change at line 331 skipping to change at line 331
class ValueType> class ValueType>
void distanceTransform( void distanceTransform(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest, pair<DestImageIterator, DestAccessor> dest,
ValueType background, int norm) ValueType background, int norm)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="distancetransform_8hxx-source.html">vigra/d istancetransform.hxx</a>\><br> <b>\#include</b> \<vigra/distancetransform.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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;
... ...
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 edgedetection.hxx   edgedetection.hxx 
skipping to change at line 133 skipping to change at line 133
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/e dgedetection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 367 skipping to change at line 367
+ + + . . . . . . . . * * + + + . . . . . . . . * *
+ . + . + . . . . . + . + . + . . . . .
\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 conformes to the requirements of a \ref CrackEdgeImage. It c an 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>
skipping to change at line 411 skipping to change at line 411
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/e dgedetection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 711 skipping to change at line 711
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/e dgedetection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 844 skipping to change at line 844
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/e dgedetection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 889 skipping to change at line 889
src_accessor.set(edge_marker, src_upperleft); src_accessor.set(edge_marker, src_upperleft);
\endcode \endcode
*/ */
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) / 2; int w = slr.x - sul.x;
int h = (slr.y - sul.y) / 2; int h = slr.y - sul.y;
int x, y;
vigra_precondition(w % 2 == 1 && h % 2 == 1,
"closeGapsInCrackEdgeImage(): Input is not a crack edge image (must
have odd-numbered shape).");
int w2 = w / 2, h2 = h / 2, x, y;
int count1, count2, count3; int count1, count2, count3;
static const Diff2D right(1,0); static const Diff2D right(1,0);
static const Diff2D bottom(0,1); static const Diff2D bottom(0,1);
static const Diff2D left(-1,0); static const Diff2D left(-1,0);
static const Diff2D top(0,-1); static const Diff2D top(0,-1);
static const Diff2D leftdist[] = { static const Diff2D leftdist[] = {
Diff2D(0, 0), Diff2D(-1, 1), Diff2D(-2, 0), Diff2D(-1, -1)}; Diff2D(0, 0), Diff2D(-1, 1), Diff2D(-2, 0), Diff2D(-1, -1)};
skipping to change at line 915 skipping to change at line 919
Diff2D(1, -1), Diff2D(0, 0), Diff2D(-1, -1), Diff2D(0, -2)}; Diff2D(1, -1), Diff2D(0, 0), Diff2D(-1, -1), Diff2D(0, -2)};
static const Diff2D bottomdist[] = { static const Diff2D bottomdist[] = {
Diff2D(1, 1), Diff2D(0, 2), Diff2D(-1, 1), Diff2D(0, 0)}; Diff2D(1, 1), Diff2D(0, 2), Diff2D(-1, 1), 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<h; ++y, sy.y+=2) for(y=0; y<h2; ++y, sy.y+=2)
{ {
sx = sy + Diff2D(2,0); sx = sy + Diff2D(2,0);
for(x=2; x<w; ++x, sx.x+=2) for(x=2; x<w2; ++x, sx.x+=2)
{ {
if(sa(sx) == edge_marker) continue; if(sa(sx) == edge_marker) continue;
if(sa(sx, left) != edge_marker) continue; if(sa(sx, left) != edge_marker) continue;
if(sa(sx, right) != edge_marker) continue; if(sa(sx, right) != edge_marker) continue;
count1 = 0; count1 = 0;
count2 = 0; count2 = 0;
count3 = 0; count3 = 0;
skipping to change at line 954 skipping to change at line 958
if(count1 <= 1 || count2 <= 1 || count3 == 15) if(count1 <= 1 || count2 <= 1 || count3 == 15)
{ {
sa.set(edge_marker, sx); sa.set(edge_marker, sx);
} }
} }
} }
sy = sul + Diff2D(1,2); sy = sul + Diff2D(1,2);
// close 1-pixel wide gaps (y-direction) // close 1-pixel wide gaps (y-direction)
for(y=2; y<h; ++y, sy.y+=2) for(y=2; y<h2; ++y, sy.y+=2)
{ {
sx = sy; sx = sy;
for(x=0; x<w; ++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, top) != edge_marker) continue; if(sa(sx, top) != edge_marker) continue;
if(sa(sx, bottom) != edge_marker) continue; if(sa(sx, bottom) != edge_marker) continue;
count1 = 0; count1 = 0;
count2 = 0; count2 = 0;
count3 = 0; count3 = 0;
skipping to change at line 1025 skipping to change at line 1029
\code \code
original edge points (*) resulting edge points original edge points (*) resulting edge points
. * . . . . * . . . . * . . . . * . . .
. * * * . . . * . . . * * * . . . * . .
. . . * . => . . . * . . . . * . => . . . * .
. . . * * . . . . * . . . * * . . . . *
. . . . . . . . . . . . . . . . . . . .
\endcode \endcode
Therfore, this algorithm should only be applied as a vizualization 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 arguments explicitly:
skipping to change at line 1057 skipping to change at line 1061
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/e dgedetection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1102 skipping to change at line 1106
src_accessor.set(background_marker, src_upperleft); src_accessor.set(background_marker, src_upperleft);
\endcode \endcode
*/ */
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) / 2; int w = slr.x - sul.x;
int h = (slr.y - sul.y) / 2; int h = slr.y - sul.y;
int x, y;
vigra_precondition(w % 2 == 1 && h % 2 == 1,
"beautifyCrackEdgeImage(): Input is not a crack edge image (must ha
ve odd-numbered shape).");
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); static const Diff2D right(1,0);
static const Diff2D bottom(0,1); static const Diff2D bottom(0,1);
static const Diff2D left(-1,0); static const Diff2D left(-1,0);
static const Diff2D top(0,-1); static const Diff2D top(0,-1);
// delete 0-cells at corners // delete 0-cells at corners
for(y=0; y<h; ++y, sy.y+=2) for(y=0; y<h2; ++y, sy.y+=2)
{ {
sx = sy; sx = sy;
for(x=0; x<w; ++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);
} }
} }
} }
skipping to change at line 1206 skipping to change at line 1214
Edgel() Edgel()
: x(0.0), y(0.0), strength(0.0), orientation(0.0) : x(0.0), y(0.0), strength(0.0), orientation(0.0)
{} {}
Edgel(value_type ix, value_type iy, value_type is, value_type io) Edgel(value_type ix, value_type iy, value_type is, value_type io)
: x(ix), y(iy), strength(is), orientation(io) : x(ix), y(iy), strength(is), orientation(io)
{} {}
}; };
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MagnitudeImage, class BackInsertable> class MagnitudeImage, class BackInsertable, class GradValue>
void internalCannyFindEdgels(SrcIterator ul, SrcAccessor grad, void internalCannyFindEdgels(SrcIterator ul, SrcAccessor grad,
MagnitudeImage const & magnitude, MagnitudeImage const & magnitude,
BackInsertable & edgels) BackInsertable & edgels, GradValue grad_thresh )
{ {
typedef typename SrcAccessor::value_type PixelType; typedef typename SrcAccessor::value_type PixelType;
typedef typename PixelType::value_type ValueType; typedef typename PixelType::value_type ValueType;
vigra_precondition(grad_thresh >= NumericTraits<GradValue>::zero(),
"cannyFindEdgels(): gradient threshold must not be negative.");
double t = 0.5 / VIGRA_CSTD::sin(M_PI/8.0); double t = 0.5 / VIGRA_CSTD::sin(M_PI/8.0);
ul += Diff2D(1,1); ul += Diff2D(1,1);
for(int y=1; y<magnitude.height()-1; ++y, ++ul.y) for(int y=1; y<magnitude.height()-1; ++y, ++ul.y)
{ {
SrcIterator ix = ul; SrcIterator ix = ul;
for(int x=1; x<magnitude.width()-1; ++x, ++ix.x) for(int x=1; x<magnitude.width()-1; ++x, ++ix.x)
{ {
double mag = magnitude(x, y); double mag = magnitude(x, y);
if(mag == 0.0) if(mag <= grad_thresh)
continue; continue;
ValueType gradx = grad.getComponent(ix, 0); ValueType gradx = grad.getComponent(ix, 0);
ValueType grady = grad.getComponent(ix, 1); ValueType grady = grad.getComponent(ix, 1);
int dx = (int)VIGRA_CSTD::floor(gradx*t/mag + 0.5); int dx = (int)VIGRA_CSTD::floor(gradx*t/mag + 0.5);
int dy = (int)VIGRA_CSTD::floor(grady*t/mag + 0.5); int dy = (int)VIGRA_CSTD::floor(grady*t/mag + 0.5);
int x1 = x - dx, int x1 = x - dx,
x2 = x + dx, x2 = x + dx,
y1 = y - dy, y1 = y - dy,
skipping to change at line 1272 skipping to change at line 1283
/********************************************************/ /********************************************************/
/** \brief Simple implementation of Canny's edge detector. /** \brief Simple implementation of Canny's edge detector.
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).
On the basis of the gradient image, a simple non-maxima supression is p erformed: On the basis of the gradient image, a simple non-maxima suppression is performed:
for each 3x3 neighborhood, it is determined whether the center pixel ha s for each 3x3 neighborhood, it is determined whether the center pixel ha s
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 octands). 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 arguments explicitly:
\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 scaler 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 scaler 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/edged etection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1389 skipping to change at line 1400
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); 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) BackInsertable & edgels)
{ {
cannyEdgelList(src.first, src.second, src.third, edgels); cannyEdgelList(src.first, src.second, src.third, edgels);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* cannyEdgelListThreshold */
/* */
/********************************************************/
/** \brief Canny's edge detector with thresholding.
This function works exactly like \ref cannyEdgelList(), but
you also pass a threshold for the minimal gradient magnitude,
so that edgels whose strength is below the threshold are not
inserted into the edgel list.
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
// compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor
src,
BackInsertable & edgels, GradValue grad_thr
eshold);
// compute edgels from a scalar image (determine gradient internall
y at 'scale')
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor
src,
BackInsertable & edgels, double scale, Grad
Value grad_threshold);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
// compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccesso
r> src,
BackInsertable & edgels, GradValue grad_thr
eshold);
// compute edgels from a scalar image (determine gradient internall
y at 'scale')
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccesso
r> src,
BackInsertable & edgels, double scale, Grad
Value grad_threshold);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra
\code
vigra::BImage src(w,h);
// empty edgel list
std::vector<vigra::Edgel> edgels;
...
// find edgels at scale 0.8, only considering gradient above 2.0
vigra::cannyEdgelListThreshold(srcImageRange(src), edgels, 0.8, 2.0);
\endcode
<b> Required Interface:</b>
\code
SrcImageIterator src_upperleft;
SrcAccessor src_accessor;
src_accessor(src_upperleft);
BackInsertable edgels;
edgels.push_back(Edgel());
\endcode
SrcAccessor::value_type must be a type convertible to float
<b> Preconditions:</b>
\code
scale > 0
\endcode
*/
doxygen_overloaded_function(template <...> void cannyEdgelListThreshold)
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, double scale, GradValue gr
ad_threshold)
{
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale);
cannyEdgelListThreshold(srcImageRange(grad), edgels, grad_threshold);
}
template <class SrcIterator, class SrcAccessor,
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
cannyEdgelListThreshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, GradValue grad_threshold)
{
using namespace functor;
typedef typename SrcAccessor::value_type SrcType;
typedef typename NumericTraits<typename SrcType::value_type>::RealPromo
te TmpType;
BasicImage<TmpType> magnitude(lr-ul);
transformImage(srcIterRange(ul, lr, src), destImage(magnitude), norm(Ar
g1()));
// find edgels
internalCannyFindEdgels(ul, src, magnitude, edgels, grad_threshold);
}
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
inline void
cannyEdgelListThreshold(triple<SrcIterator, SrcIterator, SrcAccessor> src,
BackInsertable & edgels, GradValue grad_threshold)
{
cannyEdgelListThreshold(src.first, src.second, src.third, 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() 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
skipping to change at line 1444 skipping to change at line 1594
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/edged etection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1490 skipping to change at line 1640
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 edge_marke r) double scale, GradValue gradient_threshold, DestValue edge_marke r)
{ {
std::vector<Edgel> edgels; std::vector<Edgel> edgels;
cannyEdgelList(sul, slr, sa, edgels, scale); cannyEdgelListThreshold(sul, slr, sa, edgels, scale, gradient_threshold );
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
for(unsigned int i=0; i<edgels.size(); ++i) for(unsigned int i=0; i<edgels.size(); ++i)
{ {
if(gradient_threshold < edgels[i].strength) Diff2D pix((int)(edgels[i].x + 0.5), (int)(edgels[i].y + 0.5));
{
Diff2D pix((int)(edgels[i].x + 0.5), (int)(edgels[i].y + 0.5));
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 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 edge_marke r) double scale, GradValue gradient_threshold, DestValue edge_marke r)
skipping to change at line 1682 skipping to change at line 1829
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/edged etection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1769 skipping to change at line 1916
1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 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, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1,
1, 0, 1, 0 }; 1, 0, 1, 0 };
eul += Diff2D(1,1); eul += Diff2D(1,1);
sul += Diff2D(1,1); sul += Diff2D(1,1);
int w2 = w-2; int w2 = w-2;
int h2 = h-2; int h2 = h-2;
typedef detail::SimplePoint<GradValue> SP; typedef detail::SimplePoint<GradValue> SP;
// use std::greater becaus we need the smallest gradients at the top of the queue // use std::greater because we need the smallest gradients at the top o f the queue
std::priority_queue<SP, std::vector<SP>, std::greater<SP> > pqueue; std::priority_queue<SP, std::vector<SP>, std::greater<SP> > pqueue;
Diff2D p(0,0); Diff2D p(0,0);
for(; p.y < h2; ++p.y) for(; p.y < h2; ++p.y)
{ {
for(p.x = 0; p.x < w2; ++p.x) for(p.x = 0; p.x < w2; ++p.x)
{ {
BImage::traverser e = eul + p; BImage::traverser e = eul + p;
if(*e == 0) if(*e == 0)
continue; continue;
skipping to change at line 1911 skipping to change at line 2058
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/edged etection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 2007 skipping to change at line 2154
double scale, GradValue gradient_threshold, DestValue edge_marke r) double scale, GradValue gradient_threshold, DestValue edge_marke r)
{ {
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, true ); scale, gradient_threshold, edge_marker, true );
} }
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class MaskImage, class BackInsertable> 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)
{ {
typedef typename SrcAccessor::value_type PixelType; typedef typename SrcAccessor::value_type PixelType;
typedef typename PixelType::value_type ValueType; typedef typename PixelType::value_type ValueType;
vigra_precondition(grad_thresh >= NumericTraits<GradValue>::zero(),
"cannyFindEdgels3x3(): gradient threshold must not be negative.");
ul += Diff2D(1,1); ul += Diff2D(1,1);
for(int y=1; y<mask.height()-1; ++y, ++ul.y) for(int y=1; y<mask.height()-1; ++y, ++ul.y)
{ {
SrcIterator ix = ul; SrcIterator ix = ul;
for(int x=1; x<mask.width()-1; ++x, ++ix.x) for(int x=1; x<mask.width()-1; ++x, ++ix.x)
{ {
if(!mask(x,y)) if(!mask(x,y))
continue; continue;
ValueType gradx = grad.getComponent(ix, 0); ValueType gradx = grad.getComponent(ix, 0);
ValueType grady = grad.getComponent(ix, 1); ValueType grady = grad.getComponent(ix, 1);
double mag = hypot(gradx, grady); double mag = hypot(gradx, grady);
if(mag == 0.0) if(mag <= grad_thresh)
continue; continue;
double c = gradx / mag, double c = gradx / mag,
s = grady / mag; s = grady / mag;
Matrix<double> ml(3,3), mr(3,1), l(3,1), r(3,1); Matrix<double> ml(3,3), mr(3,1), l(3,1), r(3,1);
l(0,0) = 1.0; l(0,0) = 1.0;
for(int yy = -1; yy <= 1; ++yy) for(int yy = -1; yy <= 1; ++yy)
{ {
for(int xx = -1; xx <= 1; ++xx) for(int xx = -1; xx <= 1; ++xx)
skipping to change at line 2100 skipping to change at line 2251
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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 scaler 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 scaler 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="edgedetection_8hxx-source.html">vigra/edged etection.hxx</a>\><br> <b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 2187 skipping to change at line 2338
BackInsertable & edgels, double scale) BackInsertable & edgels, double scale)
{ {
cannyEdgelList3x3(src.first, src.second, src.third, edgels, scale); cannyEdgelList3x3(src.first, src.second, src.third, edgels, scale);
} }
template <class SrcIterator, class SrcAccessor, class BackInsertable> 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;
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); 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) BackInsertable & edgels)
{ {
cannyEdgelList3x3(src.first, src.second, src.third, edgels); cannyEdgelList3x3(src.first, src.second, src.third, edgels);
} }
/********************************************************/
/* */
/* cannyEdgelList3x3Threshold */
/* */
/********************************************************/
/** \brief Improved implementation of Canny's edge detector with thresholdi
ng.
This function works exactly like \ref cannyEdgelList3x3(), but
you also pass a threshold for the minimal gradient magnitude,
so that edgels whose strength is below the threshold are not
inserted into the edgel list.
<b> Declarations:</b>
pass arguments explicitly:
\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 :
\code
namespace vigra {
// compute edgels from a gradient image
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelList3x3Threshold(triple<SrcIterator, SrcIterator, SrcAcce
ssor> 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(triple<SrcIterator, SrcIterator, SrcAcce
ssor> src,
BackInsertable & edgels, double scale, G
radValue grad_thresh);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/edgedetection.hxx\><br>
Namespace: vigra
\code
vigra::BImage src(w,h);
// empty edgel list
std::vector<vigra::Edgel> edgels;
...
// find edgels at scale 0.8
vigra::cannyEdgelList3x3(srcImageRange(src), edgels, 0.8);
\endcode
<b> Required Interface:</b>
\code
SrcImageIterator src_upperleft;
SrcAccessor src_accessor;
src_accessor(src_upperleft);
BackInsertable edgels;
edgels.push_back(Edgel());
\endcode
SrcAccessor::value_type must be a type convertible to float
<b> Preconditions:</b>
\code
scale > 0
\endcode
*/
doxygen_overloaded_function(template <...> void cannyEdgelList3x3Threshold)
template <class SrcIterator, class SrcAccessor,
class BackInsertable, class GradValue>
void
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, double scale, GradValue
grad_thresh)
{
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType;
BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale);
cannyEdgelList3x3Threshold(srcImageRange(grad), edgels, grad_thresh);
}
template <class SrcIterator, class SrcAccessor,
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
cannyEdgelList3x3Threshold(SrcIterator ul, SrcIterator lr, SrcAccessor src,
BackInsertable & edgels, GradValue grad_thresh)
{
UInt8Image edges(lr-ul);
cannyEdgeImageFromGradWithThinning(srcIterRange(ul, lr, src), destImage
(edges),
0.0, 1, false);
// find edgels
internalCannyFindEdgels3x3(ul, src, edges, edgels, 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)
{
cannyEdgelList3x3Threshold(src.first, src.second, src.third, edgels, gr
ad_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 accomodate 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 Laplacean filter. Consider the following sketch, where response of a Laplacian filter. Consider the following sketch, where
<TT>+</TT> encodes the foreground, <TT>-</TT> the background, and <TT>+</TT> encodes the foreground, <TT>-</TT> the background, and
<TT>*</TT> the resulting crack edges. <TT>*</TT> the resulting crack edges.
\code \code
sign of difference image insert cracks resulting CrackEdgeI mage sign of difference image insert cracks resulting CrackEdgeI mage
+ . - . - . * . . . + . - . - . * . . .
+ - - . . . . . . * * * . + - - . . . . . . * * * .
+ + - => + . + . - => . . . * . + + - => + . + . - => . . . * .
+ + + . . . . . . . . * * + + + . . . . . . . . * *
 End of changes. 46 change blocks. 
49 lines changed or deleted 377 lines changed or added


 eigensystem.hxx   eigensystem.hxx 
skipping to change at line 160 skipping to change at line 160
} }
d(j) = a(i-1, j); d(j) = a(i-1, j);
a(i, j) = 0.0; a(i, j) = 0.0;
} }
} }
d(i) = h; d(i) = h;
} }
// Accumulate transformations. // Accumulate transformations.
for(unsigned int i = 0; i < n-1; ++i) for(MultiArrayIndex i = 0; i < n-1; ++i)
{ {
a(n-1, i) = a(i, i); a(n-1, i) = a(i, i);
a(i, i) = 1.0; a(i, i) = 1.0;
T h = d(i+1); T h = d(i+1);
if(h != 0.0) if(h != 0.0)
{ {
for(unsigned int k = 0; k <= i; ++k) for(MultiArrayIndex k = 0; k <= i; ++k)
{ {
d(k) = a(k, i+1) / h; d(k) = a(k, i+1) / h;
} }
for(unsigned int j = 0; j <= i; ++j) for(MultiArrayIndex j = 0; j <= i; ++j)
{ {
T g = 0.0; T g = 0.0;
for(unsigned int k = 0; k <= i; ++k) for(MultiArrayIndex k = 0; k <= i; ++k)
{ {
g += a(k, i+1) * a(k, j); g += a(k, i+1) * a(k, j);
} }
for(unsigned int k = 0; k <= i; ++k) for(MultiArrayIndex k = 0; k <= i; ++k)
{ {
a(k, j) -= g * d(k); a(k, j) -= g * d(k);
} }
} }
} }
for(unsigned int k = 0; k <= i; ++k) for(MultiArrayIndex k = 0; k <= i; ++k)
{ {
a(k, i+1) = 0.0; a(k, i+1) = 0.0;
} }
} }
for(unsigned int j = 0; j < n; ++j) for(MultiArrayIndex j = 0; j < n; ++j)
{ {
d(j) = a(n-1, j); d(j) = a(n-1, j);
a(n-1, j) = 0.0; a(n-1, j) = 0.0;
} }
a(n-1, n-1) = 1.0; a(n-1, n-1) = 1.0;
e(0) = 0.0; e(0) = 0.0;
} }
// code adapted from JAMA // code adapted from JAMA
// de and z will be overwritten // de and z will be overwritten
skipping to change at line 226 skipping to change at line 226
e(n-1) = 0.0; e(n-1) = 0.0;
T f = 0.0; T f = 0.0;
T tst1 = 0.0; T tst1 = 0.0;
T eps = VIGRA_CSTD::pow(2.0,-52.0); T eps = VIGRA_CSTD::pow(2.0,-52.0);
for(MultiArrayIndex l = 0; l < n; ++l) for(MultiArrayIndex l = 0; l < n; ++l)
{ {
// Find small subdiagonalMatrix element // Find small subdiagonalMatrix element
tst1 = std::max(tst1, abs(d(l)) + abs(e(l))); tst1 = std::max(tst1, abs(d(l)) + abs(e(l)));
unsigned int m = l; MultiArrayIndex m = l;
// Original while-loop from Java code // Original while-loop from Java code
while(m < n) while(m < n)
{ {
if(abs(e(m)) <= eps*tst1) if(abs(e(m)) <= eps*tst1)
break; break;
++m; ++m;
} }
// If m == l, d(l) is an eigenvalue, // If m == l, d(l) is an eigenvalue,
skipping to change at line 260 skipping to change at line 260
T p = (d(l+1) - g) / (2.0 * e(l)); T p = (d(l+1) - g) / (2.0 * e(l));
T r = hypot(p,1.0); T r = hypot(p,1.0);
if(p < 0) if(p < 0)
{ {
r = -r; r = -r;
} }
d(l) = e(l) / (p + r); d(l) = e(l) / (p + r);
d(l+1) = e(l) * (p + r); d(l+1) = e(l) * (p + r);
T dl1 = d(l+1); T dl1 = d(l+1);
T h = g - d(l); T h = g - d(l);
for(unsigned int i = l+2; i < n; ++i) for(MultiArrayIndex i = l+2; i < n; ++i)
{ {
d(i) -= h; d(i) -= h;
} }
f = f + h; f = f + h;
// Implicit QL transformation. // Implicit QL transformation.
p = d(m); p = d(m);
T c = 1.0; T c = 1.0;
T c2 = c; T c2 = c;
skipping to change at line 291 skipping to change at line 291
h = c * p; h = c * p;
r = hypot(p,e(i)); r = hypot(p,e(i));
e(i+1) = s * r; e(i+1) = s * r;
s = e(i) / r; s = e(i) / r;
c = p / r; c = p / r;
p = c * d(i) - s * g; p = c * d(i) - s * g;
d(i+1) = h + s * (c * g + s * d(i)); d(i+1) = h + s * (c * g + s * d(i));
// Accumulate transformation. // Accumulate transformation.
for(unsigned int k = 0; k < n; ++k) for(MultiArrayIndex k = 0; k < n; ++k)
{ {
h = z(k, i+1); h = z(k, i+1);
z(k, i+1) = s * z(k, i) + c * h; z(k, i+1) = s * z(k, i) + c * h;
z(k, i) = c * z(k, i) - s * h; z(k, i) = c * z(k, i) - s * h;
} }
} }
p = -s * s2 * c3 * el1 * e(l) / dl1; p = -s * s2 * c3 * el1 * e(l) / dl1;
e(l) = s * p; e(l) = s * p;
d(l) = c * p; d(l) = c * p;
// Check for convergence. // Check for convergence.
} while(abs(e(l)) > eps*tst1); } while(abs(e(l)) > eps*tst1);
} }
d(l) = d(l) + f; d(l) = d(l) + f;
e(l) = 0.0; e(l) = 0.0;
} }
// Sort eigenvalues and corresponding vectors. // Sort eigenvalues and corresponding vectors.
for(unsigned int i = 0; i < n-1; ++i) for(MultiArrayIndex i = 0; i < n-1; ++i)
{ {
unsigned int k = i; MultiArrayIndex k = i;
T p = d(i); T p = d(i);
for(unsigned int j = i+1; j < n; ++j) for(MultiArrayIndex j = i+1; j < n; ++j)
{ {
T p1 = d(j); T p1 = d(j);
if(p < p1) if(p < p1)
{ {
k = j; k = j;
p = p1; p = p1;
} }
} }
if(k != i) if(k != i)
{ {
std::swap(d(k), d(i)); std::swap(d(k), d(i));
for(unsigned int j = 0; j < n; ++j) for(MultiArrayIndex j = 0; j < n; ++j)
{ {
std::swap(z(j, i), z(j, k)); std::swap(z(j, i), z(j, k));
} }
} }
} }
return true; return true;
} }
// Nonsymmetric reduction to Hessenberg form. // Nonsymmetric reduction to Hessenberg form.
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> \<<a href="eigensystem_8hxx-source.html">vigra/eigensy <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
stem.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1035 skipping to change at line 1035
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> \<<a href="eigensystem_8hxx-source.html">vigra/eigensy <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
stem.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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.");
skipping to change at line 1073 skipping to change at line 1073
/** Compute the roots of a polynomial using the eigenvalue method. /** Compute the roots of a polynomial using the eigenvalue method.
\a poly is a real polynomial (compatible to \ref vigra::PolynomialV iew), \a poly is a real polynomial (compatible to \ref vigra::PolynomialV iew),
and \a roots a complex valued vector (compatible to <tt>std::vector </tt> and \a roots a complex valued vector (compatible to <tt>std::vector </tt>
with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::C omplex</tt>) to which with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::C omplex</tt>) to which
the roots are appended. The function calls \ref nonsymmetricEigensy stem() with the standard the roots are appended. The function calls \ref nonsymmetricEigensy stem() with the standard
companion matrix yielding the roots as eigenvalues. It returns <tt> false</tt> if companion matrix yielding the roots as eigenvalues. It returns <tt> false</tt> if
it fails to converge. it fails to converge.
<b>\#include</b> \<<a href="eigensystem_8hxx-source.html">vigra/eig <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
ensystem.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra
/linear_algebra.hxx</a>\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
\see polynomialRoots(), vigra::Polynomial \see polynomialRoots(), vigra::Polynomial
*/ */
template <class POLYNOMIAL, class VECTOR> template <class POLYNOMIAL, class VECTOR>
bool polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly, VECTOR & root s, bool polishRoots) bool polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly, VECTOR & root s, bool polishRoots)
{ {
typedef typename POLYNOMIAL::value_type T; 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;
skipping to change at line 1127 skipping to change at line 1127
/** Compute the real roots of a real polynomial using the eigenvalue me thod. /** Compute the real roots of a real polynomial using the eigenvalue me thod.
\a poly is a real polynomial (compatible to \ref vigra::PolynomialV iew), \a poly is a real polynomial (compatible to \ref vigra::PolynomialV iew),
and \a roots a real valued vector (compatible to <tt>std::vector</t t> and \a roots a real valued vector (compatible to <tt>std::vector</t t>
with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::R eal</tt>) to which with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::R eal</tt>) to which
the roots are appended. The function calls \ref polynomialRootsEige nvalueMethod() and the roots are appended. The function calls \ref polynomialRootsEige nvalueMethod() and
throws away all complex roots. It returns <tt>false</tt> if it fail s to converge. throws away all complex roots. It returns <tt>false</tt> if it fail s to converge.
The parameter <tt>polishRoots</tt> is ignored (it is only here for syntax compatibility The parameter <tt>polishRoots</tt> is ignored (it is only here for syntax compatibility
with polynomialRealRoots()). with polynomialRealRoots()).
<b>\#include</b> \<<a href="eigensystem_8hxx-source.html">vigra/eig <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
ensystem.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra
/linear_algebra.hxx</a>\><br>
Namespaces: vigra and vigra::linalg Namespaces: vigra and vigra::linalg
\see polynomialRealRoots(), vigra::Polynomial \see polynomialRealRoots(), vigra::Polynomial
*/ */
template <class POLYNOMIAL, class VECTOR> template <class POLYNOMIAL, class VECTOR>
bool polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p, VECTOR & roo ts, bool /* polishRoots */) bool polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p, VECTOR & roo ts, bool /* polishRoots */)
{ {
typedef typename NumericTraits<typename VECTOR::value_type>::ComplexPro mote Complex; typedef typename NumericTraits<typename VECTOR::value_type>::ComplexPro mote Complex;
ArrayVector<Complex> croots; ArrayVector<Complex> croots;
if(!polynomialRootsEigenvalueMethod(p, croots)) if(!polynomialRootsEigenvalueMethod(p, croots))
 End of changes. 18 change blocks. 
30 lines changed or deleted 22 lines changed or added


 error.hxx   error.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_ERROR_HXX #ifndef VIGRA_ERROR_HXX
#define VIGRA_ERROR_HXX #define VIGRA_ERROR_HXX
#include <stdexcept> #include <stdexcept>
#include <stdio.h> #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> \<<a href="error_8hxx-source.html">vigra/error.hxx</a> \> <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;
class PostconditionViolation : public ContractViolation; class PostconditionViolation : public ContractViolation;
class InvariantViolation : public ContractViolation; class InvariantViolation : public ContractViolation;
} }
skipping to change at line 92 skipping to change at line 92
\code \code
vigra_fail(MESSAGE); vigra_fail(MESSAGE);
\endcode \endcode
unconditionally throws a '<TT>std::runtime_error</TT>' constructed from the message unconditionally throws a '<TT>std::runtime_error</TT>' constructed from the message
(along with file name and line number, if NDEBUG is not set). (along with file name and line number, if NDEBUG is not set).
<b> Usage:</b> <b> Usage:</b>
Include-File: Include-File:
\<<a href="error_8hxx-source.html">vigra/error.hxx</a>\> \<vigra/error.hxx\>
<p> <p>
Namespace: vigra (except for the macros, of course) Namespace: vigra (except for the macros, of course)
\code \code
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
try try
{ {
const char* input_file_name = argv[1]; const char* input_file_name = argv[1];
skipping to change at line 127 skipping to change at line 127
return 0; return 0;
} }
\endcode \endcode
**/ **/
namespace vigra { namespace vigra {
class ContractViolation : public StdException class ContractViolation : public StdException
{ {
public: public:
ContractViolation()
{}
ContractViolation(char const * prefix, char const * message, ContractViolation(char const * prefix, char const * message,
char const * file, int line) char const * file, int line)
{ {
sprintf(what_, "\n%.30s\n%.900s\n(%.100s:%d)\n", prefix, message, f (*this) << "\n" << prefix << "\n" << message << "\n("
ile, line); << file << ":" << line << ")\n";
} }
ContractViolation(char const * prefix, char const * message) ContractViolation(char const * prefix, char const * message)
{ {
sprintf(what_, "\n%.30s\n%.900s\n", prefix, message); (*this) << "\n" << prefix << "\n" << message << "\n";
}
~ContractViolation() throw()
{}
template<class T>
ContractViolation & operator<<(T const & data)
{
std::ostringstream what;
what << data;
what_ += what.str();
return *this;
} }
virtual const char * what() const throw() virtual const char * what() const throw()
{ {
return what_; try
{
return what_.c_str();
}
catch(...)
{
return "vigra::ContractViolation: error message was lost, sorry
.";
}
} }
private: private:
enum { bufsize_ = 1100 }; std::string what_;
char what_[bufsize_];
}; };
class PreconditionViolation : public ContractViolation class PreconditionViolation : public ContractViolation
{ {
public: public:
PreconditionViolation(char const * message, const char * file, int line ) PreconditionViolation(char const * message, const char * file, int line )
: ContractViolation("Precondition violation!", message, file, line) : ContractViolation("Precondition violation!", message, file, line)
{} {}
PreconditionViolation(char const * message) PreconditionViolation(char const * message)
skipping to change at line 190 skipping to change at line 212
: ContractViolation("Invariant violation!", message) : ContractViolation("Invariant violation!", message)
{} {}
}; };
#ifndef NDEBUG #ifndef NDEBUG
inline inline
void throw_invariant_error(bool predicate, char const * message, char const * file, int line) void throw_invariant_error(bool predicate, char const * message, char const * file, int line)
{ {
if(!predicate) if(!predicate)
throw vigra::InvariantViolation(message, file, line); throw vigra::InvariantViolation(message, file, line);
} }
inline inline
void throw_invariant_error(bool predicate, std::string message, char const * file, int line) void throw_invariant_error(bool predicate, std::string message, char const * file, int line)
{ {
if(!predicate) if(!predicate)
throw vigra::InvariantViolation(message.c_str(), file, line); throw vigra::InvariantViolation(message.c_str(), file, line);
} }
inline inline
void throw_precondition_error(bool predicate, char const * message, char co nst * file, int line) void throw_precondition_error(bool predicate, char const * message, char co nst * file, int line)
{ {
if(!predicate) if(!predicate)
throw vigra::PreconditionViolation(message, file, line); throw vigra::PreconditionViolation(message, file, line);
} }
inline inline
void throw_precondition_error(bool predicate, std::string message, char con st * file, int line) void throw_precondition_error(bool predicate, std::string message, char con st * file, int line)
{ {
if(!predicate) if(!predicate)
throw vigra::PreconditionViolation(message.c_str(), file, line); throw vigra::PreconditionViolation(message.c_str(), file, line);
} }
inline inline
void throw_postcondition_error(bool predicate, char const * message, char c onst * file, int line) void throw_postcondition_error(bool predicate, char const * message, char c onst * file, int line)
{ {
if(!predicate) if(!predicate)
throw vigra::PostconditionViolation(message, file, line); throw vigra::PostconditionViolation(message, file, line);
} }
inline inline
void throw_postcondition_error(bool predicate, std::string message, char co nst * file, int line) void throw_postcondition_error(bool predicate, std::string message, char co nst * file, int line)
{ {
if(!predicate) if(!predicate)
throw vigra::PostconditionViolation(message.c_str(), file, line); throw vigra::PostconditionViolation(message.c_str(), file, line);
} }
inline inline
void throw_runtime_error(char const * message, char const * file, int line) void throw_runtime_error(char const * message, char const * file, int line)
{ {
char what_[1100]; std::ostringstream what;
sprintf(what_, "\n%.900s\n(%.100s:%d)\n", message, file, line); what << "\n" << message << "\n(" << file << ":" << line << ")\n";
throw std::runtime_error(what_); throw std::runtime_error(what.str());
} }
inline inline
void throw_runtime_error(std::string message, char const * file, int line) void throw_runtime_error(std::string message, char const * file, int line)
{ {
char what_[1100]; std::ostringstream what;
sprintf(what_, "\n%.900s\n(%.100s:%d)\n", message.c_str(), file, line); what << "\n" << message << "\n(" << file << ":" << line << ")\n";
throw std::runtime_error(what_); throw std::runtime_error(what.str());
} }
#define vigra_precondition(PREDICATE, MESSAGE) vigra::throw_precondition_er ror((PREDICATE), MESSAGE, __FILE__, __LINE__) #define vigra_precondition(PREDICATE, MESSAGE) vigra::throw_precondition_er ror((PREDICATE), MESSAGE, __FILE__, __LINE__)
#define vigra_assert(PREDICATE, MESSAGE) vigra_precondition(PREDICATE, MESS AGE) #define vigra_assert(PREDICATE, MESSAGE) vigra_precondition(PREDICATE, MESS AGE)
#define vigra_postcondition(PREDICATE, MESSAGE) vigra::throw_postcondition_ error((PREDICATE), MESSAGE, __FILE__, __LINE__) #define vigra_postcondition(PREDICATE, MESSAGE) vigra::throw_postcondition_ error((PREDICATE), MESSAGE, __FILE__, __LINE__)
#define vigra_invariant(PREDICATE, MESSAGE) vigra::throw_invariant_error((P REDICATE), MESSAGE, __FILE__, __LINE__) #define vigra_invariant(PREDICATE, MESSAGE) vigra::throw_invariant_error((P REDICATE), MESSAGE, __FILE__, __LINE__)
#define vigra_fail(MESSAGE) vigra::throw_runtime_error(MESSAGE, __FILE__, _ _LINE__) #define vigra_fail(MESSAGE) vigra::throw_runtime_error(MESSAGE, __FILE__, _ _LINE__)
#else // NDEBUG #else // NDEBUG
inline inline
void throw_invariant_error(bool predicate, char const * message) void throw_invariant_error(bool predicate, char const * message)
{ {
if(!predicate) if(!predicate)
throw vigra::InvariantViolation(message); throw vigra::InvariantViolation(message);
} }
inline inline
void throw_precondition_error(bool predicate, char const * message) void throw_precondition_error(bool predicate, char const * message)
{ {
if(!predicate) if(!predicate)
throw vigra::PreconditionViolation(message); throw vigra::PreconditionViolation(message);
} }
inline inline
void throw_postcondition_error(bool predicate, char const * message) void throw_postcondition_error(bool predicate, char const * message)
{ {
if(!predicate) if(!predicate)
throw vigra::PostconditionViolation(message); throw vigra::PostconditionViolation(message);
} }
inline inline
void throw_invariant_error(bool predicate, std::string message) void throw_invariant_error(bool predicate, std::string message)
{ {
if(!predicate) if(!predicate)
throw vigra::InvariantViolation(message.c_str()); throw vigra::InvariantViolation(message.c_str());
} }
inline inline
void throw_precondition_error(bool predicate, std::string message) void throw_precondition_error(bool predicate, std::string message)
{ {
if(!predicate) if(!predicate)
throw vigra::PreconditionViolation(message.c_str()); throw vigra::PreconditionViolation(message.c_str());
} }
inline inline
void throw_postcondition_error(bool predicate, std::string message) void throw_postcondition_error(bool predicate, std::string message)
{ {
if(!predicate) if(!predicate)
throw vigra::PostconditionViolation(message.c_str()); throw vigra::PostconditionViolation(message.c_str());
} }
#define vigra_precondition(PREDICATE, MESSAGE) vigra::throw_precondition_er ror((PREDICATE), MESSAGE) #define vigra_precondition(PREDICATE, MESSAGE) vigra::throw_precondition_er ror((PREDICATE), MESSAGE)
#define vigra_assert(PREDICATE, MESSAGE) #define vigra_assert(PREDICATE, MESSAGE)
#define vigra_postcondition(PREDICATE, MESSAGE) vigra::throw_postcondition_ error((PREDICATE), MESSAGE) #define vigra_postcondition(PREDICATE, MESSAGE) vigra::throw_postcondition_ error((PREDICATE), MESSAGE)
#define vigra_invariant(PREDICATE, MESSAGE) vigra::throw_invariant_error((P REDICATE), MESSAGE) #define vigra_invariant(PREDICATE, MESSAGE) vigra::throw_invariant_error((P REDICATE), MESSAGE)
 End of changes. 22 change blocks. 
27 lines changed or deleted 49 lines changed or added


 fftw.hxx   fftw.hxx 
skipping to change at line 83 skipping to change at line 83
typedef fftw_real const & const_reference; typedef fftw_real const & const_reference;
/** iterator type (result of begin() ) /** iterator type (result of begin() )
*/ */
typedef fftw_real * iterator; typedef fftw_real * iterator;
/** const iterator type (result of begin() const) /** const iterator type (result of begin() const)
*/ */
typedef fftw_real const * const_iterator; typedef fftw_real const * const_iterator;
/** The norm type (result of magnitde()) /** The norm type (result of magnitude())
*/ */
typedef fftw_real NormType; typedef fftw_real NormType;
/** The squared norm type (result of squaredMagnitde()) /** The squared norm type (result of squaredMagnitde())
*/ */
typedef fftw_real SquaredNormType; typedef fftw_real SquaredNormType;
/** Construct from real and imaginary part. /** Construct from real and imaginary part.
Default: 0. Default: 0.
*/ */
skipping to change at line 669 skipping to change at line 669
More information on using FFTW can be found <a href="http://www.fftw.or g/doc/">here</a>. More information on using FFTW can be found <a href="http://www.fftw.or g/doc/">here</a>.
FFTW produces fourier images that have the DC component (the FFTW produces fourier images that have the DC component (the
origin of the Fourier space) in the upper left corner. Often, one origin of the Fourier space) in the upper left corner. Often, one
wants the origin in the center of the image, so that frequencies wants the origin in the center of the image, so that frequencies
always increase towards the border of the image. This can be always increase towards the border of the image. This can be
achieved by calling \ref moveDCToCenter(). The inverse achieved by calling \ref moveDCToCenter(). The inverse
transformation is done by \ref moveDCToUpperLeft(). transformation is done by \ref moveDCToUpperLeft().
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\> <br> <b>\#include</b> \<vigra/fftw.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
/********************************************************/ /********************************************************/
/* */ /* */
/* moveDCToCenter */ /* moveDCToCenter */
/* */ /* */
/********************************************************/ /********************************************************/
/* documentation: see fftw3.hxx /* documentation: see fftw3.hxx
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 fftw3.hxx   fftw3.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_FFTW3_HXX #ifndef VIGRA_FFTW3_HXX
#define VIGRA_FFTW3_HXX #define VIGRA_FFTW3_HXX
#include <cmath> #include <cmath>
#include <functional> #include <functional>
#include <complex>
#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 "numerictraits.hxx" #include "numerictraits.hxx"
#include "imagecontainer.hxx" #include "imagecontainer.hxx"
#include <fftw3.h> #include <fftw3.h>
namespace vigra { namespace vigra {
typedef double fftw_real; typedef double fftw_real;
template <class T>
struct FFTWReal;
template <>
struct FFTWReal<fftw_complex>
{
typedef double type;
};
template <>
struct FFTWReal<fftwf_complex>
{
typedef float type;
};
template <>
struct FFTWReal<fftwl_complex>
{
typedef long double type;
};
template <class T>
struct FFTWReal2Complex;
template <>
struct FFTWReal2Complex<double>
{
typedef fftw_complex type;
typedef fftw_plan plan_type;
};
template <>
struct FFTWReal2Complex<float>
{
typedef fftwf_complex type;
typedef fftwf_plan plan_type;
};
template <>
struct FFTWReal2Complex<long double>
{
typedef fftwl_complex type;
typedef fftwl_plan plan_type;
};
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWComplex */ /* FFTWComplex */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Wrapper class for the FFTW type '<TT>fftw_complex</TT>'. /** \brief Wrapper class for the FFTW complex types '<TT>fftw_complex</TT>' .
This class provides constructors and other member functions This class encapsulates the low-level complex number types provided by
for the C struct '<TT>fftw_complex</TT>'. This struct is the basic the
pixel type of the <a href="http://www.fftw.org/">FFTW Fast Fourier Tran <a href="http://www.fftw.org/">FFTW Fast Fourier Transform</a> library
sform</a> (i.e.
library. It inherits the data members '<TT>re</TT>' and '<TT>im</TT>' '<TT>fftw_complex</TT>', '<TT>fftwf_complex</TT>', '<TT>fftwl_complex</
that denote the real and imaginary part of the number. In addition it TT>').
defines transformations to polar coordinates, In particular, it provides constructors, member functions and
as well as \ref FFTWComplexOperators "arithmetic operators" and \ref FFTWComplexOperators "arithmetic operators" that make FFTW complex
\ref FFTWComplexAccessors "accessors". numbers
compatible with <tt>std::complex</tt>. In addition, the class defines
transformations to polar coordinates and \ref FFTWComplexAccessors "acc
essors".
FFTWComplex implements the concepts \ref AlgebraicField and FFTWComplex implements the concepts \ref AlgebraicField and
\ref DivisionAlgebra. The standard image types <tt>FFTWRealImage</tt> \ref DivisionAlgebra. The standard image types <tt>FFTWRealImage</tt>
and <tt>FFTWComplexImage</tt> are defined. and <tt>FFTWComplexImage</tt> are defined.
<b>See also:</b> <b>See also:</b>
<ul> <ul>
<li> \ref FFTWComplexTraits <li> \ref FFTWComplexTraits
<li> \ref FFTWComplexOperators <li> \ref FFTWComplexOperators
<li> \ref FFTWComplexAccessors <li> \ref FFTWComplexAccessors
</ul> </ul>
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template <class Real = double>
class FFTWComplex class FFTWComplex
{ {
fftw_complex data_;
public: public:
/** The wrapped complex type
*/
typedef typename FFTWReal2Complex<Real>::type complex_type;
/** The complex' component type, as defined in '<TT>fftw3.h</TT>' /** The complex' component type, as defined in '<TT>fftw3.h</TT>'
*/ */
typedef fftw_real value_type; typedef Real value_type;
/** reference type (result of operator[]) /** reference type (result of operator[])
*/ */
typedef fftw_real & reference; typedef value_type & reference;
/** const reference type (result of operator[] const) /** const reference type (result of operator[] const)
*/ */
typedef fftw_real const & const_reference; typedef value_type const & const_reference;
/** iterator type (result of begin() ) /** iterator type (result of begin() )
*/ */
typedef fftw_real * iterator; typedef value_type * iterator;
/** const iterator type (result of begin() const) /** const iterator type (result of begin() const)
*/ */
typedef fftw_real const * const_iterator; typedef value_type const * const_iterator;
/** The norm type (result of magnitde()) /** The norm type (result of magnitude())
*/ */
typedef fftw_real NormType; typedef value_type NormType;
/** The squared norm type (result of squaredMagnitde()) /** The squared norm type (result of squaredMagnitde())
*/ */
typedef fftw_real SquaredNormType; typedef value_type SquaredNormType;
/** Construct from real and imaginary part. /** Construct from real and imaginary part.
Default: 0. Default: 0.
*/ */
FFTWComplex(value_type const & re = 0.0, value_type const & im = 0.0) FFTWComplex(value_type const & re = 0.0, value_type const & im = 0.0)
{ {
data_[0] = re; data_[0] = re;
data_[1] = im; data_[1] = im;
} }
/** Copy constructor. /** Copy constructor.
*/ */
FFTWComplex(FFTWComplex const & o) FFTWComplex(FFTWComplex const & o)
{ {
data_[0] = o.data_[0]; data_[0] = o.data_[0];
data_[1] = o.data_[1]; data_[1] = o.data_[1];
} }
/** Copy constructor.
*/
template <class U>
FFTWComplex(FFTWComplex<U> const & o)
{
data_[0] = (Real)o.real();
data_[1] = (Real)o.imag();
}
/** Construct from plain <TT>fftw_complex</TT>. /** Construct from plain <TT>fftw_complex</TT>.
*/ */
FFTWComplex(fftw_complex const & o) FFTWComplex(fftw_complex const & o)
{ {
data_[0] = o[0]; data_[0] = (Real)o[0];
data_[1] = o[1]; data_[1] = (Real)o[1];
}
/** Construct from plain <TT>fftwf_complex</TT>.
*/
FFTWComplex(fftwf_complex const & o)
{
data_[0] = (Real)o[0];
data_[1] = (Real)o[1];
}
/** Construct from plain <TT>fftwl_complex</TT>.
*/
FFTWComplex(fftwl_complex const & o)
{
data_[0] = (Real)o[0];
data_[1] = (Real)o[1];
}
/** Construct from std::complex.
*/
template <class T>
FFTWComplex(std::complex<T> const & o)
{
data_[0] = (Real)o.real();
data_[1] = (Real)o.imag();
} }
/** Construct from TinyVector. /** Construct from TinyVector.
*/ */
template <class T> template <class T>
FFTWComplex(TinyVector<T, 2> const & o) FFTWComplex(TinyVector<T, 2> const & o)
{ {
data_[0] = o[0]; data_[0] = (Real)o[0];
data_[1] = o[1]; data_[1] = (Real)o[1];
} }
/** Assignment. /** Assignment.
*/ */
FFTWComplex& operator=(FFTWComplex const & o) FFTWComplex& operator=(FFTWComplex const & o)
{ {
data_[0] = o.data_[0]; data_[0] = o.data_[0];
data_[1] = o.data_[1]; data_[1] = o.data_[1];
return *this; return *this;
} }
/** Assignment. /** Assignment.
*/ */
template <class U>
FFTWComplex& operator=(FFTWComplex<U> const & o)
{
data_[0] = (Real)o.real();
data_[1] = (Real)o.imag();
return *this;
}
/** Assignment.
*/
FFTWComplex& operator=(fftw_complex const & o) FFTWComplex& operator=(fftw_complex const & o)
{ {
data_[0] = o[0]; data_[0] = (Real)o[0];
data_[1] = o[1]; data_[1] = (Real)o[1];
return *this; return *this;
} }
/** Assignment. /** Assignment.
*/ */
FFTWComplex& operator=(fftw_real const & o) FFTWComplex& operator=(fftwf_complex const & o)
{ {
data_[0] = o; data_[0] = (Real)o[0];
data_[1] = (Real)o[1];
return *this;
}
/** Assignment.
*/
FFTWComplex& operator=(fftwl_complex const & o)
{
data_[0] = (Real)o[0];
data_[1] = (Real)o[1];
return *this;
}
/** Assignment.
*/
FFTWComplex& operator=(double o)
{
data_[0] = (Real)o;
data_[1] = 0.0;
return *this;
}
/** Assignment.
*/
FFTWComplex& operator=(float o)
{
data_[0] = (Real)o;
data_[1] = 0.0;
return *this;
}
/** Assignment.
*/
FFTWComplex& operator=(long double o)
{
data_[0] = (Real)o;
data_[1] = 0.0; data_[1] = 0.0;
return *this; return *this;
} }
/** Assignment. /** Assignment.
*/ */
template <class T> template <class T>
FFTWComplex& operator=(TinyVector<T, 2> const & o) FFTWComplex& operator=(TinyVector<T, 2> const & o)
{ {
data_[0] = o[0]; data_[0] = (Real)o[0];
data_[1] = o[1]; data_[1] = (Real)o[1];
return *this;
}
/** Assignment.
*/
template <class T>
FFTWComplex& operator=(std::complex<T> const & o)
{
data_[0] = (Real)o.real();
data_[1] = (Real)o.imag();
return *this; return *this;
} }
reference re() reference re()
{ return data_[0]; } { return data_[0]; }
const_reference re() const const_reference re() const
{ return data_[0]; } { return data_[0]; }
reference real()
{ return data_[0]; }
const_reference real() const
{ return data_[0]; }
reference im() reference im()
{ return data_[1]; } { return data_[1]; }
const_reference im() const const_reference im() const
{ return data_[1]; } { return data_[1]; }
reference imag()
{ return data_[1]; }
const_reference imag() const
{ return data_[1]; }
/** Unary negation. /** Unary negation.
*/ */
FFTWComplex operator-() const FFTWComplex operator-() const
{ return FFTWComplex(-data_[0], -data_[1]); } { return FFTWComplex(-data_[0], -data_[1]); }
/** Squared magnitude x*conj(x) /** Squared magnitude x*conj(x)
*/ */
SquaredNormType squaredMagnitude() const SquaredNormType squaredMagnitude() const
{ return data_[0]*data_[0]+data_[1]*data_[1]; } { return data_[0]*data_[0]+data_[1]*data_[1]; }
skipping to change at line 247 skipping to change at line 397
{ return data_; } { return data_; }
iterator end() iterator end()
{ return data_ + 2; } { return data_ + 2; }
const_iterator begin() const const_iterator begin() const
{ return data_; } { return data_; }
const_iterator end() const const_iterator end() const
{ return data_ + 2; } { return data_ + 2; }
private:
complex_type data_;
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWComplexTraits */ /* FFTWComplexTraits */
/* */ /* */
/********************************************************/ /********************************************************/
/** \page FFTWComplexTraits Numeric and Promote Traits of FFTWComplex /** \page FFTWComplexTraits Numeric and Promote Traits of FFTWComplex
skipping to change at line 280 skipping to change at line 433
typedef fftw_real ValueType; typedef fftw_real ValueType;
typedef VigraFalseType isIntegral; typedef VigraFalseType isIntegral;
typedef VigraFalseType isScalar; typedef VigraFalseType isScalar;
typedef VigraFalseType isOrdered; typedef VigraFalseType isOrdered;
typedef VigraTrueType isComplex; typedef VigraTrueType isComplex;
// etc. // etc.
}; };
template<> template<class Real>
struct NumericTraits<FFTWComplex> struct NumericTraits<FFTWComplex<Real> >
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
typedef FFTWComplex RealPromote; typedef FFTWComplex<Real> RealPromote;
typedef FFTWComplex ComplexPromote; typedef FFTWComplex<Real> ComplexPromote;
typedef fftw_real ValueType; typedef Real ValueType;
typedef VigraFalseType isIntegral; typedef VigraFalseType isIntegral;
typedef VigraFalseType isScalar; typedef VigraFalseType isScalar;
typedef VigraFalseType isOrdered; typedef VigraFalseType isOrdered;
typedef VigraTrueType isComplex; typedef VigraTrueType isComplex;
// etc. // etc.
}; };
template<> template<>
struct NormTraits<fftw_complex> struct NormTraits<fftw_complex>
{ {
typedef fftw_complex Type; typedef fftw_complex Type;
typedef fftw_real SquaredNormType; typedef fftw_real SquaredNormType;
typedef fftw_real NormType; typedef fftw_real NormType;
}; };
template<> template<class Real>
struct NormTraits<FFTWComplex> struct NormTraits<FFTWComplex>
{ {
typedef FFTWComplex Type; typedef FFTWComplex Type;
typedef fftw_real SquaredNormType; typedef fftw_real SquaredNormType;
typedef fftw_real NormType; typedef fftw_real NormType;
}; };
template <> template <>
struct PromoteTraits<fftw_complex, fftw_complex> struct PromoteTraits<fftw_complex, fftw_complex>
{ {
skipping to change at line 330 skipping to change at line 483
{ {
typedef fftw_complex Promote; typedef fftw_complex Promote;
}; };
template <> template <>
struct PromoteTraits<double, fftw_complex> struct PromoteTraits<double, fftw_complex>
{ {
typedef fftw_complex Promote; typedef fftw_complex Promote;
}; };
template <> template <class Real>
struct PromoteTraits<FFTWComplex, FFTWComplex> struct PromoteTraits<FFTWComplex<Real>, FFTWComplex<Real> >
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
}; };
template <> template <class Real>
struct PromoteTraits<FFTWComplex, double> struct PromoteTraits<FFTWComplex<Real>, double>
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
}; };
template <> template <class Real>
struct PromoteTraits<double, FFTWComplex> struct PromoteTraits<double, FFTWComplex<Real> >
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
}; };
\endcode \endcode
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template<> template<>
struct NumericTraits<fftw_complex> struct NumericTraits<fftw_complex>
{ {
typedef fftw_complex Type; typedef fftw_complex Type;
typedef fftw_complex Promote; typedef fftw_complex Promote;
typedef fftw_complex RealPromote; typedef fftw_complex RealPromote;
typedef fftw_complex ComplexPromote; typedef fftw_complex ComplexPromote;
typedef fftw_real ValueType; typedef fftw_real ValueType;
typedef VigraFalseType isIntegral; typedef VigraFalseType isIntegral;
typedef VigraFalseType isScalar; typedef VigraFalseType isScalar;
typedef NumericTraits<fftw_real>::isSigned isSigned; typedef NumericTraits<fftw_real>::isSigned isSigned;
typedef VigraFalseType isOrdered; typedef VigraFalseType isOrdered;
typedef VigraTrueType isComplex; typedef VigraTrueType isComplex;
static FFTWComplex zero() { return FFTWComplex(0.0, 0.0); } static FFTWComplex<> zero() { return FFTWComplex<>(0.0, 0.0); }
static FFTWComplex one() { return FFTWComplex(1.0, 0.0); } static FFTWComplex<> one() { return FFTWComplex<>(1.0, 0.0); }
static FFTWComplex nonZero() { return one(); } static FFTWComplex<> nonZero() { return one(); }
static const Promote & toPromote(const Type & v) { return v; } static const Promote & toPromote(const Type & v) { return v; }
static const RealPromote & toRealPromote(const Type & v) { return v; } static const RealPromote & toRealPromote(const Type & v) { return v; }
static const Type & fromPromote(const Promote & v) { return v; } static const Type & fromPromote(const Promote & v) { return v; }
static const Type & fromRealPromote(const RealPromote & v) { return v; } static const Type & fromRealPromote(const RealPromote & v) { return v; }
}; };
template<> template<class Real>
struct NumericTraits<FFTWComplex> struct NumericTraits<FFTWComplex<Real> >
{ {
typedef FFTWComplex Type; typedef FFTWComplex<Real> Type;
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
typedef FFTWComplex RealPromote; typedef FFTWComplex<Real> RealPromote;
typedef FFTWComplex ComplexPromote; typedef FFTWComplex<Real> ComplexPromote;
typedef fftw_real ValueType; typedef typename Type::value_type ValueType;
typedef VigraFalseType isIntegral; typedef VigraFalseType isIntegral;
typedef VigraFalseType isScalar; typedef VigraFalseType isScalar;
typedef NumericTraits<fftw_real>::isSigned isSigned; typedef typename NumericTraits<ValueType>::isSigned isSigned;
typedef VigraFalseType isOrdered; typedef VigraFalseType isOrdered;
typedef VigraTrueType isComplex; typedef VigraTrueType isComplex;
static FFTWComplex zero() { return FFTWComplex(0.0, 0.0); } static Type zero() { return Type(0.0, 0.0); }
static FFTWComplex one() { return FFTWComplex(1.0, 0.0); } static Type one() { return Type(1.0, 0.0); }
static FFTWComplex nonZero() { return one(); } static Type nonZero() { return one(); }
static const Promote & toPromote(const Type & v) { return v; } static const Promote & toPromote(const Type & v) { return v; }
static const RealPromote & toRealPromote(const Type & v) { return v; } static const RealPromote & toRealPromote(const Type & v) { return v; }
static const Type & fromPromote(const Promote & v) { return v; } static const Type & fromPromote(const Promote & v) { return v; }
static const Type & fromRealPromote(const RealPromote & v) { return v; } static const Type & fromRealPromote(const RealPromote & v) { return v; }
}; };
template<> template<>
struct NormTraits<fftw_complex> struct NormTraits<fftw_complex>
{ {
typedef fftw_complex Type; typedef fftw_complex Type;
typedef fftw_real SquaredNormType; typedef fftw_real SquaredNormType;
typedef fftw_real NormType; typedef fftw_real NormType;
}; };
template<> template<class Real>
struct NormTraits<FFTWComplex> struct NormTraits<FFTWComplex<Real> >
{ {
typedef FFTWComplex Type; typedef FFTWComplex<Real> Type;
typedef fftw_real SquaredNormType; typedef typename Type::SquaredNormType SquaredNormType;
typedef fftw_real NormType; typedef typename Type::NormType NormType;
}; };
template <> template <>
struct PromoteTraits<fftw_complex, fftw_complex> struct PromoteTraits<fftw_complex, fftw_complex>
{ {
typedef fftw_complex Promote; typedef fftw_complex Promote;
}; };
template <> template <>
struct PromoteTraits<fftw_complex, double> struct PromoteTraits<fftw_complex, double>
{ {
typedef fftw_complex Promote; typedef fftw_complex Promote;
}; };
template <> template <>
struct PromoteTraits<double, fftw_complex> struct PromoteTraits<double, fftw_complex>
{ {
typedef fftw_complex Promote; typedef fftw_complex Promote;
}; };
template <> template <class Real>
struct PromoteTraits<FFTWComplex, FFTWComplex> struct PromoteTraits<FFTWComplex<Real>, FFTWComplex<Real> >
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
}; };
template <> template <class Real>
struct PromoteTraits<FFTWComplex, double> struct PromoteTraits<FFTWComplex<Real>, double>
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
}; };
template <> template <class Real>
struct PromoteTraits<double, FFTWComplex> struct PromoteTraits<double, FFTWComplex<Real> >
{ {
typedef FFTWComplex Promote; typedef FFTWComplex<Real> Promote;
}; };
template<class T> template<class T>
struct CanSkipInitialization<std::complex<T> > struct CanSkipInitialization<std::complex<T> >
{ {
typedef typename CanSkipInitialization<T>::type type; typedef typename CanSkipInitialization<T>::type type;
static const bool value = type::asBool; static const bool value = type::asBool;
}; };
template<> template<class Real>
struct CanSkipInitialization<FFTWComplex> struct CanSkipInitialization<FFTWComplex<Real> >
{ {
typedef CanSkipInitialization<fftw_real>::type type; typedef typename CanSkipInitialization<Real>::type type;
static const bool value = type::asBool; static const bool value = type::asBool;
}; };
namespace multi_math {
template <class ARG>
struct MultiMathOperand;
template <class Real>
struct MultiMathOperand<FFTWComplex<Real> >
{
typedef MultiMathOperand<FFTWComplex<Real> > AllowOverload;
typedef FFTWComplex<Real> result_type;
static const int ndim = 0;
MultiMathOperand(FFTWComplex<Real> const & v)
: v_(v)
{}
template <class SHAPE>
bool checkShape(SHAPE const &) const
{
return true;
}
template <class SHAPE>
FFTWComplex<Real> const & operator[](SHAPE const &) const
{
return v_;
}
void inc(unsigned int /*LEVEL*/) const
{}
void reset(unsigned int /*LEVEL*/) const
{}
FFTWComplex<Real> const & operator*() const
{
return v_;
}
FFTWComplex<Real> v_;
};
} // namespace multi_math
template<class Ty>
class FFTWAllocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef Ty *pointer;
typedef const Ty *const_pointer;
typedef Ty& reference;
typedef const Ty& const_reference;
typedef Ty value_type;
pointer address(reference val) const
{ return &val; }
const_pointer address(const_reference val) const
{ return &val; }
template<class Other>
struct rebind
{
typedef FFTWAllocator<Other> other;
};
FFTWAllocator() throw()
{}
template<class Other>
FFTWAllocator(const FFTWAllocator<Other>& right) throw()
{}
template<class Other>
FFTWAllocator& operator=(const FFTWAllocator<Other>& right)
{
return *this;
}
pointer allocate(size_type count, void * = 0)
{
return (pointer)fftw_malloc(count * sizeof(Ty));
}
void deallocate(pointer ptr, size_type count)
{
fftw_free(ptr);
}
void construct(pointer ptr, const Ty& val)
{
new(ptr) Ty(val);
}
void destroy(pointer ptr)
{
ptr->~Ty();
}
size_type max_size() const throw()
{
return NumericTraits<std::ptrdiff_t>::max() / sizeof(Ty);
}
};
} // namespace vigra
namespace std {
template<class Real>
class allocator<vigra::FFTWComplex<Real> >
{
public:
typedef vigra::FFTWComplex<Real> value_type;
typedef size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
pointer address(reference val) const
{ return &val; }
const_pointer address(const_reference val) const
{ return &val; }
template<class Other>
struct rebind
{
typedef allocator<Other> other;
};
allocator() throw()
{}
template<class Other>
allocator(const allocator<Other>& right) throw()
{}
template<class Other>
allocator& operator=(const allocator<Other>& right)
{
return *this;
}
pointer allocate(size_type count, void * = 0)
{
return (pointer)fftw_malloc(count * sizeof(value_type));
}
void deallocate(pointer ptr, size_type /*count*/)
{
fftw_free(ptr);
}
void construct(pointer ptr, const value_type& val)
{
new(ptr) value_type(val);
}
void destroy(pointer ptr)
{
ptr->~value_type();
}
size_type max_size() const throw()
{
return vigra::NumericTraits<std::ptrdiff_t>::max() / sizeof(value_t
ype);
}
};
} // namespace std
namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWComplex Operations */ /* FFTWComplex Operations */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup FFTWComplexOperators Functions for FFTWComplex /** \addtogroup FFTWComplexOperators Functions for FFTWComplex
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
These functions fulfill the requirements of an Algebraic Field. These functions fulfill the requirements of an Algebraic Field.
Return types are determined according to \ref FFTWComplexTraits. Return types are determined according to \ref FFTWComplexTraits.
Namespace: vigra Namespace: vigra
<p> <p>
*/ */
//@{ //@{
/// equal /// equal
inline bool operator ==(FFTWComplex const &a, const FFTWComplex &b) { template <class R>
inline bool operator ==(FFTWComplex<R> const &a, const FFTWComplex<R> &b) {
return a.re() == b.re() && a.im() == b.im(); return a.re() == b.re() && a.im() == b.im();
} }
template <class R>
inline bool operator ==(FFTWComplex<R> const &a, double b) {
return a.re() == b && a.im() == 0.0;
}
template <class R>
inline bool operator ==(double a, const FFTWComplex<R> &b) {
return a == b.re() && 0.0 == b.im();
}
/// not equal /// not equal
inline bool operator !=(FFTWComplex const &a, const FFTWComplex &b) { template <class R>
inline bool operator !=(FFTWComplex<R> const &a, const FFTWComplex<R> &b) {
return a.re() != b.re() || a.im() != b.im(); return a.re() != b.re() || a.im() != b.im();
} }
/// not equal
template <class R>
inline bool operator !=(FFTWComplex<R> const &a, double b) {
return a.re() != b || a.im() != 0.0;
}
/// not equal
template <class R>
inline bool operator !=(double a, const FFTWComplex<R> &b) {
return a != b.re() || 0.0 != b.im();
}
/// add-assignment /// add-assignment
inline FFTWComplex &operator +=(FFTWComplex &a, const FFTWComplex &b) { template <class R>
inline FFTWComplex<R> & operator +=(FFTWComplex<R> &a, const FFTWComplex<R>
&b) {
a.re() += b.re(); a.re() += b.re();
a.im() += b.im(); a.im() += b.im();
return a; return a;
} }
/// subtract-assignment /// subtract-assignment
inline FFTWComplex &operator -=(FFTWComplex &a, const FFTWComplex &b) { template <class R>
inline FFTWComplex<R> & operator -=(FFTWComplex<R> &a, const FFTWComplex<R>
&b) {
a.re() -= b.re(); a.re() -= b.re();
a.im() -= b.im(); a.im() -= b.im();
return a; return a;
} }
/// multiply-assignment /// multiply-assignment
inline FFTWComplex &operator *=(FFTWComplex &a, const FFTWComplex &b) { template <class R>
FFTWComplex::value_type t = a.re()*b.re()-a.im()*b.im(); inline FFTWComplex<R> & operator *=(FFTWComplex<R> &a, const FFTWComplex<R>
&b) {
typename FFTWComplex<R>::value_type t = a.re()*b.re()-a.im()*b.im();
a.im() = a.re()*b.im()+a.im()*b.re(); a.im() = a.re()*b.im()+a.im()*b.re();
a.re() = t; a.re() = t;
return a; return a;
} }
/// divide-assignment /// divide-assignment
inline FFTWComplex &operator /=(FFTWComplex &a, const FFTWComplex &b) { template <class R>
FFTWComplex::value_type sm = b.squaredMagnitude(); inline FFTWComplex<R> & operator /=(FFTWComplex<R> &a, const FFTWComplex<R>
FFTWComplex::value_type t = (a.re()*b.re()+a.im()*b.im())/sm; &b) {
typename FFTWComplex<R>::value_type sm = b.squaredMagnitude();
typename FFTWComplex<R>::value_type t = (a.re()*b.re()+a.im()*b.im())/s
m;
a.im() = (b.re()*a.im()-a.re()*b.im())/sm; a.im() = (b.re()*a.im()-a.re()*b.im())/sm;
a.re() = t; a.re() = t;
return a; return a;
} }
/// add-assignment with scalar double
template <class R>
inline FFTWComplex<R> & operator +=(FFTWComplex<R> &a, double b) {
a.re() += (R)b;
return a;
}
/// subtract-assignment with scalar double
template <class R>
inline FFTWComplex<R> & operator -=(FFTWComplex<R> &a, double b) {
a.re() -= (R)b;
return a;
}
/// multiply-assignment with scalar double /// multiply-assignment with scalar double
inline FFTWComplex &operator *=(FFTWComplex &a, const double &b) { template <class R>
a.re() *= b; inline FFTWComplex<R> & operator *=(FFTWComplex<R> &a, double b) {
a.im() *= b; a.re() *= (R)b;
a.im() *= (R)b;
return a; return a;
} }
/// divide-assignment with scalar double /// divide-assignment with scalar double
inline FFTWComplex &operator /=(FFTWComplex &a, const double &b) { template <class R>
a.re() /= b; inline FFTWComplex<R> & operator /=(FFTWComplex<R> &a, double b) {
a.im() /= b; a.re() /= (R)b;
a.im() /= (R)b;
return a; return a;
} }
/// addition /// addition
inline FFTWComplex operator +(FFTWComplex a, const FFTWComplex &b) { template <class R>
inline FFTWComplex<R> operator +(FFTWComplex<R> a, const FFTWComplex<R> &b)
{
a += b;
return a;
}
/// right addition with scalar double
template <class R>
inline FFTWComplex<R> operator +(FFTWComplex<R> a, double b) {
a += b; a += b;
return a; return a;
} }
/// left addition with scalar double
template <class R>
inline FFTWComplex<R> operator +(double a, FFTWComplex<R> b) {
b += a;
return b;
}
/// subtraction /// subtraction
inline FFTWComplex operator -(FFTWComplex a, const FFTWComplex &b) { template <class R>
inline FFTWComplex<R> operator -(FFTWComplex<R> a, const FFTWComplex<R> &b)
{
a -= b;
return a;
}
/// right subtraction with scalar double
template <class R>
inline FFTWComplex<R> operator -(FFTWComplex<R> a, double b) {
a -= b; a -= b;
return a; return a;
} }
/// left subtraction with scalar double
template <class R>
inline FFTWComplex<R> operator -(double a, FFTWComplex<R> const & b) {
return (-b) += a;
}
/// multiplication /// multiplication
inline FFTWComplex operator *(FFTWComplex a, const FFTWComplex &b) { template <class R>
inline FFTWComplex<R> operator *(FFTWComplex<R> a, const FFTWComplex<R> &b)
{
a *= b; a *= b;
return a; return a;
} }
/// right multiplication with scalar double /// right multiplication with scalar double
inline FFTWComplex operator *(FFTWComplex a, const double &b) { template <class R>
inline FFTWComplex<R> operator *(FFTWComplex<R> a, double b) {
a *= b; a *= b;
return a; return a;
} }
/// left multiplication with scalar double /// left multiplication with scalar double
inline FFTWComplex operator *(const double &a, FFTWComplex b) { template <class R>
inline FFTWComplex<R> operator *(double a, FFTWComplex<R> b) {
b *= a; b *= a;
return b; return b;
} }
/// division /// division
inline FFTWComplex operator /(FFTWComplex a, const FFTWComplex &b) { template <class R>
inline FFTWComplex<R> operator /(FFTWComplex<R> a, const FFTWComplex<R> &b)
{
a /= b; a /= b;
return a; return a;
} }
/// right division with scalar double /// right division with scalar double
inline FFTWComplex operator /(FFTWComplex a, const double &b) { template <class R>
inline FFTWComplex<R> operator /(FFTWComplex<R> a, double b) {
a /= b; a /= b;
return a; return a;
} }
using VIGRA_CSTD::abs; using VIGRA_CSTD::abs;
/// absolute value (= magnitude) /// absolute value (= magnitude)
inline FFTWComplex::value_type abs(const FFTWComplex &a) template <class R>
inline typename FFTWComplex<R>::NormType abs(const FFTWComplex<R> &a)
{ {
return a.magnitude(); return a.magnitude();
} }
/// pahse
template <class R>
inline R arg(const FFTWComplex<R> &a)
{
return a.phase();
}
/// real part
template <class R>
inline R real(const FFTWComplex<R> &a)
{
return a.real();
}
/// imaginary part
template <class R>
inline R imag(const FFTWComplex<R> &a)
{
return a.imag();
}
/// complex conjugate /// complex conjugate
inline FFTWComplex conj(const FFTWComplex &a) template <class R>
inline FFTWComplex<R> conj(const FFTWComplex<R> &a)
{ {
return FFTWComplex(a.re(), -a.im()); return FFTWComplex<R>(a.re(), -a.im());
} }
/// norm (= magnitude) /// norm (= magnitude)
inline FFTWComplex::NormType norm(const FFTWComplex &a) template <class R>
inline typename FFTWComplex<R>::NormType norm(const FFTWComplex<R> &a)
{ {
return a.magnitude(); return a.magnitude();
} }
/// squared norm (= squared magnitude) /// squared norm (= squared magnitude)
inline FFTWComplex::SquaredNormType squaredNorm(const FFTWComplex &a) template <class R>
inline typename FFTWComplex<R>::SquaredNormType squaredNorm(const FFTWCompl
ex<R> &a)
{ {
return a.squaredMagnitude(); return a.squaredMagnitude();
} }
#define VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(fct) \
template <class R> \
inline FFTWComplex<R> fct(const FFTWComplex<R> &a) \
{ \
return std::fct(reinterpret_cast<std::complex<R> const &>(a)); \
}
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(cos)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(cosh)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(exp)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(log)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(log10)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(sin)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(sinh)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(sqrt)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(tan)
VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION(tanh)
#undef VIGRA_DEFINE_FFTW_COMPLEX_FUNCTION
template <class R>
inline FFTWComplex<R> pow(const FFTWComplex<R> &a, int e)
{
return std::pow(reinterpret_cast<std::complex<R> const &>(a), e);
}
template <class R>
inline FFTWComplex<R> pow(const FFTWComplex<R> &a, R const & e)
{
return std::pow(reinterpret_cast<std::complex<R> const &>(a), e);
}
template <class R>
inline FFTWComplex<R> pow(const FFTWComplex<R> &a, const FFTWComplex<R> & e
)
{
return std::pow(reinterpret_cast<std::complex<R> const &>(a),
reinterpret_cast<std::complex<R> const &>(e));
}
template <class R>
inline FFTWComplex<R> pow(R const & a, const FFTWComplex<R> &e)
{
return std::pow(a, reinterpret_cast<std::complex<R> const &>(e));
}
//@} //@}
} // namespace vigra
namespace std {
template <class Real>
ostream & operator<<(ostream & s, vigra::FFTWComplex<Real> const & v)
{
s << std::complex<Real>(v.re(), v.im());
return s;
}
} // namespace std
namespace vigra {
/** \addtogroup StandardImageTypes /** \addtogroup StandardImageTypes
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWRealImage */ /* FFTWRealImage */
/* */ /* */
/********************************************************/ /********************************************************/
/** Float (<tt>fftw_real</tt>) image. /** Float (<tt>fftw_real</tt>) image.
The type <tt>fftw_real</tt> is defined as <tt>double</tt> (in FFTW 2 it used to be The type <tt>fftw_real</tt> is defined as <tt>double</tt> (in FFTW 2 it used to be
either <tt>float</tt> or <tt>double</tt>, as specified during compi lation of FFTW). either <tt>float</tt> or <tt>double</tt>, as specified during compi lation of FFTW).
FFTWRealImage uses \ref vigra::BasicImageIterator and \ref vigra::S tandardAccessor and FFTWRealImage uses \ref vigra::BasicImageIterator and \ref vigra::S tandardAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
</a>\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</
a>\> (for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<fftw_real> FFTWRealImage; typedef BasicImage<fftw_real> FFTWRealImage;
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWComplexImage */ /* FFTWComplexImage */
/* */ /* */
/********************************************************/ /********************************************************/
template<> template<class R>
struct IteratorTraits< struct IteratorTraits<
BasicImageIterator<FFTWComplex, FFTWComplex **> > BasicImageIterator<FFTWComplex<R>, FFTWComplex<R> **> >
{ {
typedef BasicImageIterator<FFTWComplex, FFTWComplex **> Iterator; typedef FFTWComplex<R> Type;
typedef Iterator iterator; typedef BasicImageIterator<Type, Type **> Iterator;
typedef BasicImageIterator<FFTWComplex, FFTWComplex **> mutable typedef Iterator iterator;
_iterator; typedef BasicImageIterator<Type, Type **> mutable_iterator;
typedef ConstBasicImageIterator<FFTWComplex, FFTWComplex **> const_i typedef ConstBasicImageIterator<Type, Type **> const_iterator;
terator; typedef typename iterator::iterator_category iterator_category;
typedef iterator::iterator_category iterator_category; typedef typename iterator::value_type value_type;
typedef iterator::value_type value_type; typedef typename iterator::reference reference;
typedef iterator::reference reference; typedef typename iterator::index_reference index_reference;
typedef iterator::index_reference index_reference; typedef typename iterator::pointer pointer;
typedef iterator::pointer pointer; typedef typename iterator::difference_type difference_type;
typedef iterator::difference_type difference_type; typedef typename iterator::row_iterator row_iterator;
typedef iterator::row_iterator row_iterator; typedef typename iterator::column_iterator column_iterator;
typedef iterator::column_iterator column_iterator; typedef VectorAccessor<Type> default_accessor;
typedef VectorAccessor<FFTWComplex> default_accessor; typedef VectorAccessor<Type> DefaultAccessor;
typedef VectorAccessor<FFTWComplex> DefaultAccessor; typedef VigraTrueType hasConstantStrides;
typedef VigraTrueType hasConstantStrides;
}; };
template<> template<class R>
struct IteratorTraits< struct IteratorTraits<
ConstBasicImageIterator<FFTWComplex, FFTWComplex **> > ConstBasicImageIterator<FFTWComplex<R>, FFTWComplex<R> **> >
{ {
typedef ConstBasicImageIterator<FFTWComplex, FFTWComplex **> Iterato typedef FFTWComplex<R> Type;
r; typedef ConstBasicImageIterator<Type, Type **> Iterator;
typedef Iterator iterator; typedef Iterator iterator;
typedef BasicImageIterator<FFTWComplex, FFTWComplex **> mutable typedef BasicImageIterator<Type, Type **> mutable_iterator;
_iterator; typedef ConstBasicImageIterator<Type, Type **> const_iterator;
typedef ConstBasicImageIterator<FFTWComplex, FFTWComplex **> const_i typedef typename iterator::iterator_category iterator_category;
terator; typedef typename iterator::value_type value_type;
typedef iterator::iterator_category iterator_category; typedef typename iterator::reference reference;
typedef iterator::value_type value_type; typedef typename iterator::index_reference index_reference;
typedef iterator::reference reference; typedef typename iterator::pointer pointer;
typedef iterator::index_reference index_reference; typedef typename iterator::difference_type difference_type;
typedef iterator::pointer pointer; typedef typename iterator::row_iterator row_iterator;
typedef iterator::difference_type difference_type; typedef typename iterator::column_iterator column_iterator;
typedef iterator::row_iterator row_iterator; typedef VectorAccessor<Type> default_accessor;
typedef iterator::column_iterator column_iterator; typedef VectorAccessor<Type> DefaultAccessor;
typedef VectorAccessor<FFTWComplex> default_accessor; typedef VigraTrueType hasConstantStrides;
typedef VectorAccessor<FFTWComplex> DefaultAccessor;
typedef VigraTrueType hasConstantStrides;
}; };
/** Complex (FFTWComplex) image. /** Complex (FFTWComplex) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
</a>\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</
a>\> (for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<FFTWComplex> FFTWComplexImage; typedef BasicImage<FFTWComplex<> &gt; FFTWComplexImage;
//@} //@}
/********************************************************/ /********************************************************/
/* */ /* */
/* FFTWComplex-Accessors */ /* FFTWComplex-Accessors */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup DataAccessors /** \addtogroup DataAccessors
*/ */
//@{ //@{
/** \defgroup FFTWComplexAccessors Accessors for FFTWComplex /** \defgroup FFTWComplexAccessors Accessors for FFTWComplex
Encapsulate access to pixels of type FFTWComplex Encapsulate access to pixels of type FFTWComplex
*/ */
//@{ //@{
/** Encapsulate access to the the real part of a complex number. /** Encapsulate access to the the real part of a complex number.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template <class Real = double>
class FFTWRealAccessor class FFTWRealAccessor
{ {
public: public:
/// The accessor's value type. /// The accessor's value type.
typedef fftw_real value_type; typedef Real value_type;
/// Read real part at iterator position. /// Read real part 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).re(); return (*i).re();
} }
/// Read real part at offset from iterator position. /// Read real part 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 {
skipping to change at line 749 skipping to change at line 1249
(*i).re()= v; (*i).re()= v;
} }
/// Write real part at offset from iterator position from a scalar. /// Write real part at offset from iterator position from a scalar.
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class DIFFERENCE>
void set(value_type const & v, ITERATOR const & i, DIFFERENCE d) const { void set(value_type const & v, ITERATOR const & i, DIFFERENCE d) const {
i[d].re()= v; i[d].re()= v;
} }
/// Write real part at iterator position into a scalar. /// Write real part at iterator position into a scalar.
template <class ITERATOR> template <class R, class ITERATOR>
void set(FFTWComplex const & v, ITERATOR const & i) const { void set(FFTWComplex<R> const & v, ITERATOR const & i) const {
*i = v.re(); *i = v.re();
} }
/// Write real part at offset from iterator position into a scalar. /// Write real part at offset from iterator position into a scalar.
template <class ITERATOR, class DIFFERENCE> template <class R, class ITERATOR, class DIFFERENCE>
void set(FFTWComplex const & v, ITERATOR const & i, DIFFERENCE d) const void set(FFTWComplex<R> const & v, ITERATOR const & i, DIFFERENCE d) co
{ nst {
i[d] = v.re(); i[d] = v.re();
} }
}; };
/** Encapsulate access to the the imaginary part of a complex number. /** Encapsulate access to the the imaginary part of a complex number.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template <class Real = double>
class FFTWImaginaryAccessor class FFTWImaginaryAccessor
{ {
public: public:
/// The accessor's value type. /// The accessor's value type.
typedef fftw_real value_type; typedef Real value_type;
/// Read imaginary part at iterator position. /// Read imaginary part 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).im(); return (*i).im();
} }
/// Read imaginary part at offset from iterator position. /// Read imaginary part 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 {
skipping to change at line 798 skipping to change at line 1299
(*i).im()= v; (*i).im()= v;
} }
/// Write imaginary part at offset from iterator position from a sc alar. /// Write imaginary part at offset from iterator position from a sc alar.
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class DIFFERENCE>
void set(value_type const & v, ITERATOR const & i, DIFFERENCE d) const { void set(value_type const & v, ITERATOR const & i, DIFFERENCE d) const {
i[d].im()= v; i[d].im()= v;
} }
/// Write imaginary part at iterator position into a scalar. /// Write imaginary part at iterator position into a scalar.
template <class ITERATOR> template <class R, class ITERATOR>
void set(FFTWComplex const & v, ITERATOR const & i) const { void set(FFTWComplex<R> const & v, ITERATOR const & i) const {
*i = v.im(); *i = v.im();
} }
/// Write imaginary part at offset from iterator position into a sc alar. /// Write imaginary part at offset from iterator position into a sc alar.
template <class ITERATOR, class DIFFERENCE> template <class R, class ITERATOR, class DIFFERENCE>
void set(FFTWComplex const & v, ITERATOR const & i, DIFFERENCE d) const void set(FFTWComplex<R> const & v, ITERATOR const & i, DIFFERENCE d) co
{ nst {
i[d] = v.im(); i[d] = v.im();
} }
}; };
/** Write a real number into a complex one. The imaginary part is set /** Write a real number into a complex one. The imaginary part is set
to 0. to 0.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
class FFTWWriteRealAccessor: public FFTWRealAccessor template <class Real = double>
class FFTWWriteRealAccessor
: public FFTWRealAccessor<Real>
{ {
public: public:
/// The accessor's value type. /// The accessor's value type.
typedef fftw_real value_type; typedef Real value_type;
/** Write real number at iterator position. Set imaginary part /** Write real number at iterator position. Set imaginary part
to 0. to 0.
*/ */
template <class ITERATOR> template <class ITERATOR>
void set(value_type const & v, ITERATOR const & i) const { void set(value_type const & v, ITERATOR const & i) const {
(*i).re()= v; (*i).re()= v;
(*i).im()= 0; (*i).im()= 0;
} }
/** Write real number at offset from iterator position. Set imagina ry part /** Write real number at offset from iterator position. Set imagina ry part
to 0. to 0.
*/ */
template <class ITERATOR, class DIFFERENCE> template <class ITERATOR, class DIFFERENCE>
void set(value_type const & v, ITERATOR const & i, DIFFERENCE d) const { void set(value_type const & v, ITERATOR const & i, DIFFERENCE d) const {
i[d].re()= v; i[d].re()= v;
i[d].im()= 0; i[d].im()= 0;
} }
}; };
/** Calculate squared magnitude of complex number on the fly.
<b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
Namespace: vigra
*/
template <class Real = double>
class FFTWSquaredMagnitudeAccessor
{
public:
/// The accessor's value type.
typedef Real value_type;
/// Read squared magnitude at iterator position.
template <class ITERATOR>
value_type operator()(ITERATOR const & i) const {
return (*i).squaredMagnitude();
}
/// Read squared magnitude at offset from iterator position.
template <class ITERATOR, class DIFFERENCE>
value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
return (i[d]).squaredMagnitude();
}
};
/** Calculate magnitude of complex number on the fly. /** Calculate magnitude of complex number on the fly.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template <class Real = double>
class FFTWMagnitudeAccessor class FFTWMagnitudeAccessor
{ {
public: public:
/// The accessor's value type. /// The accessor's value type.
typedef fftw_real value_type; typedef Real value_type;
/// Read magnitude at iterator position. /// Read magnitude 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).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 phase of complex number on the fly. /** Calculate phase of complex number on the fly.
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
\> (for FFTW 3) or<br> <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
<b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br>
Namespace: vigra Namespace: vigra
*/ */
template <class Real = double>
class FFTWPhaseAccessor class FFTWPhaseAccessor
{ {
public: public:
/// The accessor's value type. /// The accessor's value type.
typedef fftw_real value_type; typedef 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();
} }
/// Read phase at offset from iterator position. /// Read phase 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 {
skipping to change at line 901 skipping to change at line 1431
//@} //@}
//@} //@}
/********************************************************/ /********************************************************/
/* */ /* */
/* Fourier Transform */ /* Fourier Transform */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup FourierTransform Fast Fourier Transform /* \addtogroup FourierTransform Fast Fourier Transform
This documentation describes the VIGRA interface to FFTW version 3. The interface This documentation describes the VIGRA interface to FFTW version 3. The interface
to the old FFTW version 2 (file "vigra/fftw.hxx") is deprecated. to the old FFTW version 2 (file "vigra/fftw.hxx") is deprecated.
VIGRA uses the <a href="http://www.fftw.org/">FFTW Fast Fourier VIGRA uses the <a href="http://www.fftw.org/">FFTW Fast Fourier
Transform</a> package to perform Fourier transformations. VIGRA Transform</a> package to perform Fourier transformations. VIGRA
provides a wrapper for FFTW's complex number type (FFTWComplex), provides a wrapper for FFTW's complex number type (FFTWComplex),
but FFTW's functions are used verbatim. If the image is stored as but FFTW's functions are used verbatim. If the image is stored as
a FFTWComplexImage, the simplest call to an FFT function is like this: a FFTWComplexImage, the simplest call to an FFT function is like this:
skipping to change at line 955 skipping to change at line 1485
More information on using FFTW can be found <a href="http://www.fftw.or g/doc/">here</a>. More information on using FFTW can be found <a href="http://www.fftw.or g/doc/">here</a>.
FFTW produces fourier images that have the DC component (the FFTW produces fourier images that have the DC component (the
origin of the Fourier space) in the upper left corner. Often, one origin of the Fourier space) in the upper left corner. Often, one
wants the origin in the center of the image, so that frequencies wants the origin in the center of the image, so that frequencies
always increase towards the border of the image. This can be always increase towards the border of the image. This can be
achieved by calling \ref moveDCToCenter(). The inverse achieved by calling \ref moveDCToCenter(). The inverse
transformation is done by \ref moveDCToUpperLeft(). transformation is done by \ref moveDCToUpperLeft().
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> \><br> <b>\#include</b> \<vigra/fftw3.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
/** \addtogroup FourierTransform /** \addtogroup FourierTransform Fast Fourier Transform
VIGRA provides a powerful C++ API for the popular <a href="http://www.f
ftw.org/">FFTW library</a>
for fast Fourier transforms. There are two versions of the API: an olde
r one based on image
iterators (and therefore restricted to 2D) and a new one based on \ref
MultiArrayView that
works for arbitrary dimensions. In addition, the functions \ref convolv
eFFT() and
\ref applyFourierFilter() provide an easy-to-use interface for FFT-base
d convolution,
a major application of Fourier transforms.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* moveDCToCenter */ /* moveDCToCenter */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Rearrange the quadrants of a Fourier image so that the origin is /** \brief Rearrange the quadrants of a Fourier image so that the origin is
skipping to change at line 994 skipping to change at line 1531
After applying the function, the quadrants are at their usual places: After applying the function, the quadrants are at their usual places:
\code \code
2 2 1 1 2 2 1 1
2 2 1 1 2 2 1 1
3 3 DC 4 3 3 DC 4
3 3 4 4 3 3 4 4
\endcode \endcode
This transformation can be reversed by \ref moveDCToUpperLeft(). This transformation can be reversed by \ref moveDCToUpperLeft().
Note that the transformation must not be executed in place - input Note that the 2D versions of this transformation must not be executed i
and output images must be different. n place - input
and output images must be different. In contrast, the nD version (with
MultiArrayView
argument) always works in-place.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use MultiArrayView (this works in-place, with arbitrary dimension N):
\code
namespace vigra {
template <unsigned int N, class T, class Stride>
void moveDCToCenter(MultiArrayView<N, T, Stride> a);
}
\endcode
pass iterators explicitly (2D only, not in-place):
\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 moveDCToCenter(SrcImageIterator src_upperleft, void moveDCToCenter(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAccessor sa, SrcImageIterator src_lowerright, SrcAccessor sa,
DestImageIterator dest_upperleft, DestAccess or da); DestImageIterator dest_upperleft, DestAccess or da);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories ( 2D only, not in-place):
\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 moveDCToCenter( void moveDCToCenter(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest); pair<DestImageIterator, DestAccessor> dest);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx <b>\#include</b> \<vigra/fftw3.hxx\> (for 2D variants) <br>
</a>\><br> <b>\#include</b> \<vigra/multi_fft.hxx\> (for nD variants) <br>
Namespace: vigra Namespace: vigra
\code \code
vigra::FFTWComplexImage spatial(width,height), fourier(width,height); vigra::FFTWComplexImage spatial(width,height), fourier(width,height);
... // fill image with data ... // fill image with data
// create a plan with estimated performance optimization // create a plan with estimated performance optimization
fftw_plan forwardPlan = fftw_plan_dft_2d(height, width, fftw_plan forwardPlan = fftw_plan_dft_2d(height, width,
(fftw_complex *)spatial.begin(), (fftw_comp lex *)fourier.begin(), (fftw_complex *)spatial.begin(), (fftw_comp lex *)fourier.begin(),
FFTW_FORWARD, FFTW_ESTIMATE ); FFTW_FORWARD, FFTW_ESTIMATE );
// calculate FFT // calculate FFT
skipping to change at line 1100 skipping to change at line 1647
/********************************************************/ /********************************************************/
/* */ /* */
/* moveDCToUpperLeft */ /* moveDCToUpperLeft */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Rearrange the quadrants of a Fourier image so that the origin is /** \brief Rearrange the quadrants of a Fourier image so that the origin is
in the image's upper left. in the image's upper left.
This function is the inversion of \ref moveDCToCenter(). See there This function is the inversion of \ref moveDCToCenter(). See there
for declarations and a usage example. for a detailed description and usage examples.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use MultiArrayView (this works in-place, with arbitrary dimension N):
\code
namespace vigra {
template <unsigned int N, class T, class Stride>
void moveDCToUpperLeft(MultiArrayView<N, T, Stride> a);
}
\endcode
pass iterators explicitly (2D only, not in-place):
\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 moveDCToUpperLeft(SrcImageIterator src_upperleft, void moveDCToUpperLeft(SrcImageIterator src_upperleft,
SrcImageIterator src_lowerright, SrcAcce ssor sa, SrcImageIterator src_lowerright, SrcAcce ssor sa,
DestImageIterator dest_upperleft, DestAc cessor da); DestImageIterator dest_upperleft, DestAc cessor da);
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories (2D only, not in-place):
\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 moveDCToUpperLeft( void moveDCToUpperLeft(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src , triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src ,
pair<DestImageIterator, DestAccessor> dest); pair<DestImageIterator, DestAccessor> dest);
} }
\endcode \endcode
*/ */
skipping to change at line 1172 skipping to change at line 1727
template <class SrcImageIterator, class SrcAccessor, template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
inline void moveDCToUpperLeft( inline void moveDCToUpperLeft(
triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest) pair<DestImageIterator, DestAccessor> dest)
{ {
moveDCToUpperLeft(src.first, src.second, src.third, moveDCToUpperLeft(src.first, src.second, src.third,
dest.first, dest.second); dest.first, dest.second);
} }
template <class DestImageIterator, class DestAccessor>
void fftShift(DestImageIterator upperleft,
DestImageIterator lowerright, DestAccessor da)
{
int w = int(lowerright.x - upperleft.x);
int h = int(lowerright.y - upperleft.y);
int w2 = w/2;
int h2 = h/2;
int w1 = (w+1)/2;
int h1 = (h+1)/2;
// 2. Quadrant zum 4.
swapImageData(destIterRange(upperleft,
upperleft + Diff2D(w2, h2), da),
destIter (upperleft + Diff2D(w1, h1), da));
// 1. Quadrant zum 3.
swapImageData(destIterRange(upperleft + Diff2D(w2, 0),
upperleft + Diff2D(w, h2), da),
destIter (upperleft + Diff2D(0, h1), da));
}
template <class DestImageIterator, class DestAccessor>
inline void fftShift(
triple<DestImageIterator, DestImageIterator, DestAccessor> dest)
{
fftShift(dest.first, dest.second, dest.third);
}
namespace detail { namespace detail {
template <class T> template <class T>
void void
fourierTransformImpl(FFTWComplexImage::const_traverser sul, fourierTransformImpl(FFTWComplexImage::const_traverser sul,
FFTWComplexImage::const_traverser slr, FFTWComplexImag e::ConstAccessor src, FFTWComplexImage::const_traverser slr, FFTWComplexImag e::ConstAccessor src,
FFTWComplexImage::traverser dul, FFTWComplexImage::Acc essor dest, T sign) FFTWComplexImage::traverser dul, FFTWComplexImage::Acc essor dest, T sign)
{ {
int w = int(slr.x - sul.x); int w = int(slr.x - sul.x);
int h = int(slr.y - sul.y); int h = int(slr.y - sul.y);
skipping to change at line 1250 skipping to change at line 1776
} // namespace detail } // namespace detail
/********************************************************/ /********************************************************/
/* */ /* */
/* fourierTransform */ /* fourierTransform */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Compute forward and inverse Fourier transforms. /** \brief Compute forward and inverse Fourier transforms.
In the forward direction, the input image may be scalar or complex, and The array referring to the spatial domain (i.e. the input in a forward
the output image transform,
is always complex. In the inverse direction, both input and output must and the output in an inverse transform) may be scalar or complex. The a
be complex. rray representing
the frequency domain (i.e. output for forward transform, input for inve
rse transform)
must always be complex.
The new implementations (those using MultiArrayView arguments) perform
a normalized transform,
whereas the old ones (using 2D iterators or argument objects) perform a
n un-normalized
transform (i.e. the result of the inverse transform is scaled by the nu
mber of pixels).
In general, input and output arrays must have the same shape, with the
exception of the
special <a href="http://www.fftw.org/doc/Multi_002dDimensional-DFTs-of-
Real-Data.html">R2C
and C2R modes</a> defined by FFTW.
The R2C transform reduces the redundancy in the Fourier representation
of a real-valued signal:
Since the Fourier representation of a real signal is symmetric, about h
alf of the Fourier coefficients
can simply be dropped. By convention, this reduction is applied to the
first (innermost) dimension,
such that <tt>fourier.shape(0) == spatial.shape(0)/2 + 1</tt> holds. Th
e correct frequency domain
shape can be conveniently computed by means of the function \ref fftwCo
rrespondingShapeR2C().
Note that your program must always link against <tt>libfftw3</tt>. If y
ou want to compute Fourier
transforms for <tt>float</tt> or <tt>long double</tt> arrays, you must
<i>additionally</i> link against <tt>libfftw3f</tt> and <tt>libfftw3l</tt>
respectively. (Old-style functions only support <tt>double</tt>).
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.
optimal settings are guessed or read from saved "wisdom" files. If you
need more control over planning,
you can use the class \ref FFTWPlan.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use complex-valued MultiArrayView arguments (this works for arbitrary d
imension N):
\code
namespace vigra {
template <unsigned int N, class Real, class C1, class C2>
void
fourierTransform(MultiArrayView<N, FFTWComplex<Real>, C1> in,
MultiArrayView<N, FFTWComplex<Real>, C2> out);
template <unsigned int N, class Real, class C1, class C2>
void
fourierTransformInverse(MultiArrayView<N, FFTWComplex<Real>, C1> in
,
MultiArrayView<N, FFTWComplex<Real>, C2> ou
t);
}
\endcode
use real-valued MultiArrayView in the spatial domain, complex-valued Mu
ltiArrayView
in the frequency domain (this works for arbitrary dimension N, and also
supports
the R2C and C2R transform, depending on the array shape in the frequenc
y domain):
\code
namespace vigra {
template <unsigned int N, class Real, class C1, class C2>
void
fourierTransform(MultiArrayView<N, Real, C1> in,
MultiArrayView<N, FFTWComplex<Real>, C2> out);
template <unsigned int N, class Real, class C1, class C2>
void
fourierTransformInverse(MultiArrayView<N, FFTWComplex<Real>, C1> in
,
MultiArrayView<N, Real, C2> out);
}
\endcode
pass iterators explicitly (2D only, double only):
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor> template <class SrcImageIterator, class SrcAccessor>
void fourierTransform(SrcImageIterator srcUpperLeft, void fourierTransform(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAccessor s rc, SrcImageIterator srcLowerRight, SrcAccessor s rc,
FFTWComplexImage::traverser destUpperLeft, FF TWComplexImage::Accessor dest); FFTWComplexImage::traverser destUpperLeft, FF TWComplexImage::Accessor dest);
void void
fourierTransformInverse(FFTWComplexImage::const_traverser sul, fourierTransformInverse(FFTWComplexImage::const_traverser sul,
FFTWComplexImage::const_traverser slr, FFTW ComplexImage::ConstAccessor src, FFTWComplexImage::const_traverser slr, FFTW ComplexImage::ConstAccessor src,
FFTWComplexImage::traverser dul, FFTWComple xImage::Accessor dest) FFTWComplexImage::traverser dul, FFTWComple xImage::Accessor dest)
} }
\endcode \endcode
use argument objects in conjunction with \ref ArgumentObjectFactories : use argument objects in conjunction with \ref ArgumentObjectFactories ( 2D only, double only):
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor> template <class SrcImageIterator, class SrcAccessor>
void fourierTransform(triple<SrcImageIterator, SrcImageIterator, Sr cAccessor> src, void fourierTransform(triple<SrcImageIterator, SrcImageIterator, Sr cAccessor> src,
pair<FFTWComplexImage::traverser, FFTWComplex Image::Accessor> dest); pair<FFTWComplexImage::traverser, FFTWComplex Image::Accessor> dest);
void void
fourierTransformInverse(triple<FFTWComplexImage::const_traverser, fourierTransformInverse(triple<FFTWComplexImage::const_traverser,
FFTWComplexImage::const_traverser, F FTWComplexImage::ConstAccessor> src, FFTWComplexImage::const_traverser, F FTWComplexImage::ConstAccessor> src,
pair<FFTWComplexImage::traverser, FFTWCompl exImage::Accessor> dest); pair<FFTWComplexImage::traverser, FFTWCompl exImage::Accessor> dest);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> <b>\#include</b> \<vigra/fftw3.hxx\> (old-style 2D variants)<br>
\><br> <b>\#include</b> \<vigra/multi_fft.hxx\> (new-style nD variants)<br>
Namespace: vigra Namespace: vigra
old-style example (using FFTWComplexImage):
\code \code
// compute complex Fourier transform of a real image // compute complex Fourier transform of a real image, old-style impleme ntation
vigra::DImage src(w, h); vigra::DImage src(w, h);
vigra::FFTWComplexImage fourier(w, h); vigra::FFTWComplexImage fourier(w, h);
fourierTransform(srcImageRange(src), destImage(fourier)); fourierTransform(srcImageRange(src), destImage(fourier));
// compute inverse Fourier transform // compute inverse Fourier transform
// note that both source and destination image must be of type vigra::F FTWComplexImage // note that both source and destination image must be of type vigra::F FTWComplexImage
vigra::FFTWComplexImage inverseFourier(w, h); vigra::FFTWComplexImage inverseFourier(w, h);
fourierTransform(srcImageRange(fourier), destImage(inverseFourier)); fourierTransformInverse(srcImageRange(fourier), destImage(inverseFourie
r));
\endcode
new-style examples (using MultiArray):
\code
// compute Fourier transform of a real array, using the R2C algorithm
MultiArray<2, double> src(Shape2(w, h));
MultiArray<2, FFTWComplex<double> > fourier(fftwCorrespondingShapeR2C(s
rc.shape()));
fourierTransform(src, fourier);
// compute inverse Fourier transform, using the C2R algorithm
MultiArray<2, double> dest(src.shape());
fourierTransformInverse(fourier, dest);
\endcode \endcode
\code
// compute Fourier transform of a real array with standard algorithm
MultiArray<2, double> src(Shape2(w, h));
MultiArray<2, FFTWComplex<double> > fourier(src.shape());
fourierTransform(src, fourier);
// compute inverse Fourier transform, using the C2R algorithm
MultiArray<2, double> dest(src.shape());
fourierTransformInverse(fourier, dest);
\endcode
Complex input arrays are handled in the same way.
*/ */
doxygen_overloaded_function(template <...> void fourierTransform) doxygen_overloaded_function(template <...> void fourierTransform)
inline void inline void
fourierTransform(FFTWComplexImage::const_traverser sul, fourierTransform(FFTWComplexImage::const_traverser sul,
FFTWComplexImage::const_traverser slr, FFTWComplexImage::C onstAccessor src, FFTWComplexImage::const_traverser slr, FFTWComplexImage::C onstAccessor src,
FFTWComplexImage::traverser dul, FFTWComplexImage::Accesso r dest) FFTWComplexImage::traverser dul, FFTWComplexImage::Accesso r dest)
{ {
detail::fourierTransformImpl(sul, slr, src, dul, dest, FFTW_FORWARD); detail::fourierTransformImpl(sul, slr, src, dul, dest, FFTW_FORWARD);
} }
skipping to change at line 1324 skipping to change at line 1935
void fourierTransform(SrcImageIterator srcUpperLeft, void fourierTransform(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAccessor sa, SrcImageIterator srcLowerRight, SrcAccessor sa,
FFTWComplexImage::traverser destUpperLeft, FFTWComple xImage::Accessor da) FFTWComplexImage::traverser destUpperLeft, FFTWComple xImage::Accessor da)
{ {
// copy real input images into a complex one... // copy real input images into a complex one...
int w= srcLowerRight.x - srcUpperLeft.x; int w= srcLowerRight.x - srcUpperLeft.x;
int h= srcLowerRight.y - srcUpperLeft.y; int h= srcLowerRight.y - srcUpperLeft.y;
FFTWComplexImage workImage(w, h); FFTWComplexImage workImage(w, h);
copyImage(srcIterRange(srcUpperLeft, srcLowerRight, sa), copyImage(srcIterRange(srcUpperLeft, srcLowerRight, sa),
destImage(workImage, FFTWWriteRealAccessor())); destImage(workImage, FFTWWriteRealAccessor<>()));
// ...and call the complex -> complex version of the algorithm // ...and call the complex -> complex version of the algorithm
FFTWComplexImage const & cworkImage = workImage; FFTWComplexImage const & cworkImage = workImage;
fourierTransform(cworkImage.upperLeft(), cworkImage.lowerRight(), cwork Image.accessor(), fourierTransform(cworkImage.upperLeft(), cworkImage.lowerRight(), cwork Image.accessor(),
destUpperLeft, da); destUpperLeft, da);
} }
template <class SrcImageIterator, class SrcAccessor> template <class SrcImageIterator, class SrcAccessor>
inline inline
void fourierTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccesso r> src, void fourierTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccesso r> src,
pair<FFTWComplexImage::traverser, FFTWComplexImage::A ccessor> dest) pair<FFTWComplexImage::traverser, FFTWComplexImage::A ccessor> dest)
{ {
fourierTransform(src.first, src.second, src.third, dest.first, dest.sec ond); fourierTransform(src.first, src.second, src.third, dest.first, dest.sec ond);
} }
/** \brief Compute inverse Fourier transforms. /** \brief Compute inverse Fourier transforms.
See \ref fourierTransform() for details. See \ref fourierTransform() for details.
*/ */
doxygen_overloaded_function(template <...> void fourierTransformInverse)
inline void inline void
fourierTransformInverse(FFTWComplexImage::const_traverser sul, fourierTransformInverse(FFTWComplexImage::const_traverser sul,
FFTWComplexImage::const_traverser slr, FFTWComplexI mage::ConstAccessor src, FFTWComplexImage::const_traverser slr, FFTWComplexI mage::ConstAccessor src,
FFTWComplexImage::traverser dul, FFTWComplexImage:: Accessor dest) FFTWComplexImage::traverser dul, FFTWComplexImage:: Accessor dest)
{ {
detail::fourierTransformImpl(sul, slr, src, dul, dest, FFTW_BACKWARD); detail::fourierTransformImpl(sul, slr, src, dul, dest, FFTW_BACKWARD);
} }
template <class DestImageIterator, class DestAccessor> template <class DestImageIterator, class DestAccessor>
void fourierTransformInverse(FFTWComplexImage::const_traverser sul, void fourierTransformInverse(FFTWComplexImage::const_traverser sul,
skipping to change at line 1390 skipping to change at line 2003
/** \brief Apply a filter (defined in the frequency domain) to an image. /** \brief Apply a filter (defined in the frequency domain) to an image.
After transferring the image into the frequency domain, it is After transferring the image into the frequency domain, it is
multiplied pixel-wise with the filter and transformed back. The multiplied pixel-wise with the filter and transformed back. The
result is put into the given destination image which must have the righ t size. result is put into the given destination image which must have the righ t size.
The result will be normalized to compensate for the two FFTs. The result will be normalized to compensate for the two FFTs.
If the destination image is scalar, only the real part of the result im age is If the destination image is scalar, only the real part of the result im age is
retained. In this case, you are responsible for choosing a filter image retained. In this case, you are responsible for choosing a filter image
which ensures a zero imaginary part of the result (e.g. use a real, eve n symmetric which ensures a zero imaginary part of the result (e.g. use a real, eve n symmetric
filter image, or a purely imaginary, odd symmetric on). 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
\ref MultiArrayView interface.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 1424 skipping to change at line 2040
class FilterImageIterator, class FilterAccessor, class FilterImageIterator, class FilterAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
void applyFourierFilter(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, void applyFourierFilter(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
pair<FilterImageIterator, FilterAccessor> f ilter, pair<FilterImageIterator, FilterAccessor> f ilter,
pair<DestImageIterator, DestAccessor> dest) ; pair<DestImageIterator, DestAccessor> dest) ;
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> \><br> <b>\#include</b> \<vigra/fftw3.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// create a Gaussian filter in Fourier space // create a Gaussian filter in Fourier space
vigra::FImage gaussFilter(w, h), filter(w, h); vigra::FImage gaussFilter(w, h), filter(w, h);
for(int y=0; y<h; ++y) for(int y=0; y<h; ++y)
for(int x=0; x<w; ++x) for(int x=0; x<w; ++x)
{ {
xx = float(x - w / 2) / w; xx = float(x - w / 2) / w;
yy = float(y - h / 2) / h; yy = float(y - h / 2) / h;
skipping to change at line 1468 skipping to change at line 2084
SrcImageIterator srcLowerRight, SrcAccessor sa, SrcImageIterator srcLowerRight, SrcAccessor sa,
FilterImageIterator filterUpperLeft, FilterAccessor fa, FilterImageIterator filterUpperLeft, FilterAccessor fa,
DestImageIterator destUpperLeft, DestAccessor da) DestImageIterator destUpperLeft, DestAccessor da)
{ {
// copy real input images into a complex one... // copy real input images into a complex one...
int w = int(srcLowerRight.x - srcUpperLeft.x); int w = int(srcLowerRight.x - srcUpperLeft.x);
int h = int(srcLowerRight.y - srcUpperLeft.y); int h = int(srcLowerRight.y - srcUpperLeft.y);
FFTWComplexImage workImage(w, h); FFTWComplexImage workImage(w, h);
copyImage(srcIterRange(srcUpperLeft, srcLowerRight, sa), copyImage(srcIterRange(srcUpperLeft, srcLowerRight, sa),
destImage(workImage, FFTWWriteRealAccessor())); destImage(workImage, FFTWWriteRealAccessor<>()));
// ...and call the impl // ...and call the impl
FFTWComplexImage const & cworkImage = workImage; FFTWComplexImage const & cworkImage = workImage;
applyFourierFilterImpl(cworkImage.upperLeft(), cworkImage.lowerRight(), cworkImage.accessor(), applyFourierFilterImpl(cworkImage.upperLeft(), cworkImage.lowerRight(), cworkImage.accessor(),
filterUpperLeft, fa, filterUpperLeft, fa,
destUpperLeft, da); destUpperLeft, da);
} }
template <class FilterImageIterator, class FilterAccessor, template <class FilterImageIterator, class FilterAccessor,
class DestImageIterator, class DestAccessor> class DestImageIterator, class DestAccessor>
skipping to change at line 1545 skipping to change at line 2161
// FFT from srcImage to complexResultImg // FFT from srcImage to complexResultImg
fftw_plan forwardPlan= fftw_plan forwardPlan=
fftw_plan_dft_2d(h, w, (fftw_complex *)&(*srcUpperLeft), fftw_plan_dft_2d(h, w, (fftw_complex *)&(*srcUpperLeft),
(fftw_complex *)complexResultImg.begin(), (fftw_complex *)complexResultImg.begin(),
FFTW_FORWARD, FFTW_ESTIMATE ); FFTW_FORWARD, FFTW_ESTIMATE );
fftw_execute(forwardPlan); fftw_execute(forwardPlan);
fftw_destroy_plan(forwardPlan); fftw_destroy_plan(forwardPlan);
// convolve in freq. domain (in complexResultImg) // convolve in freq. domain (in complexResultImg)
combineTwoImages(srcImageRange(complexResultImg), srcIter(filterUpperLe ft, fa), combineTwoImages(srcImageRange(complexResultImg), srcIter(filterUpperLe ft, fa),
destImage(complexResultImg), std::multiplies<FFTWCompl ex>()); destImage(complexResultImg), std::multiplies<FFTWCompl ex<> &gt;());
// FFT back into spatial domain (inplace in complexResultImg) // FFT back into spatial domain (inplace in complexResultImg)
fftw_plan backwardPlan= fftw_plan backwardPlan=
fftw_plan_dft_2d(h, w, (fftw_complex *)complexResultImg.begin(), fftw_plan_dft_2d(h, w, (fftw_complex *)complexResultImg.begin(),
(fftw_complex *)complexResultImg.begin(), (fftw_complex *)complexResultImg.begin(),
FFTW_BACKWARD, FFTW_ESTIMATE); FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(backwardPlan); fftw_execute(backwardPlan);
fftw_destroy_plan(backwardPlan); fftw_destroy_plan(backwardPlan);
typedef typename typedef typename
skipping to change at line 1590 skipping to change at line 2206
} }
} }
inline inline
void applyFourierFilterImplNormalization(FFTWComplexImage const & srcImage, void applyFourierFilterImplNormalization(FFTWComplexImage const & srcImage,
FFTWComplexImage::traverser destUpperLeft, FFTWComplexImage::traverser destUpperLeft,
FFTWComplexImage::Accessor da, FFTWComplexImage::Accessor da,
VigraFalseType) VigraFalseType)
{ {
transformImage(srcImageRange(srcImage), destIter(destUpperLeft, da), transformImage(srcImageRange(srcImage), destIter(destUpperLeft, da),
linearIntensityTransform<FFTWComplex>(1.0/(srcImage.widt h() * srcImage.height()))); linearIntensityTransform<FFTWComplex<> >(1.0/(srcImage.w idth() * srcImage.height())));
} }
template <class DestImageIterator, class DestAccessor> template <class DestImageIterator, class DestAccessor>
void applyFourierFilterImplNormalization(FFTWComplexImage const & srcImage, void applyFourierFilterImplNormalization(FFTWComplexImage const & srcImage,
DestImageIterator destUpperLeft, DestImageIterator destUpperLeft,
DestAccessor da, DestAccessor da,
VigraTrueType) VigraTrueType)
{ {
double normFactor= 1.0/(srcImage.width() * srcImage.height()); double normFactor= 1.0/(srcImage.width() * srcImage.height());
skipping to change at line 1650 skipping to change at line 2266
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, class FilterTy pe> template <class SrcImageIterator, class SrcAccessor, class FilterTy pe>
void applyFourierFilterFamily(triple<SrcImageIterator, SrcImageIter ator, SrcAccessor> src, void applyFourierFilterFamily(triple<SrcImageIterator, SrcImageIter ator, SrcAccessor> src,
const ImageArray<FilterType> &filters , const ImageArray<FilterType> &filters ,
ImageArray<FFTWComplexImage> &results ) ImageArray<FFTWComplexImage> &results )
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a> \><br> <b>\#include</b> \<vigra/fftw3.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
// assuming the presence of a real-valued image named "image" to // assuming the presence of a real-valued image named "image" to
// be filtered in this example // be filtered in this example
vigra::ImageArray<vigra::FImage> filters(16, image.size()); vigra::ImageArray<vigra::FImage> filters(16, image.size());
for (int i=0; i<filters.size(); i++) for (int i=0; i<filters.size(); i++)
// create some meaningful filters here // create some meaningful filters here
skipping to change at line 1693 skipping to change at line 2309
void applyFourierFilterFamily(SrcImageIterator srcUpperLeft, void applyFourierFilterFamily(SrcImageIterator srcUpperLeft,
SrcImageIterator srcLowerRight, SrcAccessor s a, SrcImageIterator srcLowerRight, SrcAccessor s a,
const ImageArray<FilterType> &filters, const ImageArray<FilterType> &filters,
ImageArray<DestImage> &results) ImageArray<DestImage> &results)
{ {
int w = int(srcLowerRight.x - srcUpperLeft.x); int w = int(srcLowerRight.x - srcUpperLeft.x);
int h = int(srcLowerRight.y - srcUpperLeft.y); int h = int(srcLowerRight.y - srcUpperLeft.y);
FFTWComplexImage workImage(w, h); FFTWComplexImage workImage(w, h);
copyImage(srcIterRange(srcUpperLeft, srcLowerRight, sa), copyImage(srcIterRange(srcUpperLeft, srcLowerRight, sa),
destImage(workImage, FFTWWriteRealAccessor())); destImage(workImage, FFTWWriteRealAccessor<>()));
FFTWComplexImage const & cworkImage = workImage; FFTWComplexImage const & cworkImage = workImage;
applyFourierFilterFamilyImpl(cworkImage.upperLeft(), cworkImage.lowerRi ght(), cworkImage.accessor(), applyFourierFilterFamilyImpl(cworkImage.upperLeft(), cworkImage.lowerRi ght(), cworkImage.accessor(),
filters, results); filters, results);
} }
template <class FilterType, class DestImage> template <class FilterType, class DestImage>
inline inline
void applyFourierFilterFamily( void applyFourierFilterFamily(
FFTWComplexImage::const_traverser srcUpperLeft, FFTWComplexImage::const_traverser srcUpperLeft,
skipping to change at line 1773 skipping to change at line 2389
(fftw_complex *)result.begin(), (fftw_complex *)result.begin(),
FFTW_BACKWARD, FFTW_ESTIMATE ); FFTW_BACKWARD, FFTW_ESTIMATE );
typedef typename typedef typename
NumericTraits<typename DestImage::Accessor::value_type>::isScalar NumericTraits<typename DestImage::Accessor::value_type>::isScalar
isScalarResult; isScalarResult;
// convolve with filters in freq. domain // convolve with filters in freq. domain
for (unsigned int i= 0; i < filters.size(); i++) for (unsigned int i= 0; i < filters.size(); i++)
{ {
combineTwoImages(srcImageRange(freqImage), srcImage(filters[i]), combineTwoImages(srcImageRange(freqImage), srcImage(filters[i]),
destImage(result), std::multiplies<FFTWComplex>()) ; destImage(result), std::multiplies<FFTWComplex<> > ());
// FFT back into spatial domain (inplace in destImage) // FFT back into spatial domain (inplace in destImage)
fftw_execute(backwardPlan); fftw_execute(backwardPlan);
// normalization (after FFTs), maybe stripping imaginary part // normalization (after FFTs), maybe stripping imaginary part
applyFourierFilterImplNormalization(result, applyFourierFilterImplNormalization(result,
results[i].upperLeft(), results [i].accessor(), results[i].upperLeft(), results [i].accessor(),
isScalarResult()); isScalarResult());
} }
fftw_destroy_plan(backwardPlan); fftw_destroy_plan(backwardPlan);
skipping to change at line 1873 skipping to change at line 2489
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> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx </a>\><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
 End of changes. 143 change blocks. 
263 lines changed or deleted 902 lines changed or added


 fixedpoint.hxx   fixedpoint.hxx 
skipping to change at line 177 skipping to change at line 177
/* FixedPoint */ /* FixedPoint */
/* */ /* */
/********************************************************/ /********************************************************/
/** Template for fixed point arithmetic. /** Template for fixed point arithmetic.
Fixed point arithmetic is used when computations with fractional accura cy Fixed point arithmetic is used when computations with fractional accura cy
must be made at the highest speed possible (e.g. in the inner loop must be made at the highest speed possible (e.g. in the inner loop
of a volume rendering routine). The speed-up relative to floating of a volume rendering routine). The speed-up relative to floating
point arithmetic can be dramatic, especially when one can avoid point arithmetic can be dramatic, especially when one can avoid
conversions between integer anfloating point numbers (these are conversions between integer and floating point numbers (these are
very expensive because integer and floating point arithmetic very expensive because integer and floating point arithmetic
resides in different pipelines). resides in different pipelines).
The template wraps an <tt>int</tt> and uses <tt>IntBits</tt> to The template wraps an <tt>int</tt> and uses <tt>IntBits</tt> to
represent the integral part of a number, and <tt>FractionalBits</tt> represent the integral part of a number, and <tt>FractionalBits</tt>
for the fractional part, where <tt>IntBits + FractionalBits < 32</tt>. for the fractional part, where <tt>IntBits + FractionalBits < 32</tt>.
(The 32rd bit is reserved because FixedPoint is a signed type). (The 32rd bit is reserved because FixedPoint is a signed type).
These numbers will be automatically allocated in an intelligent way These numbers will be automatically allocated in an intelligent way
in the result of an arithmetic operation. For example, when two in the result of an arithmetic operation. For example, when two
fixed point numbers are multiplied, the required number of integer fixed point numbers are multiplied, the required number of integer
bits in the result is the sum of the number of integer bits of the bits in the result is the sum of the number of integer bits of the
arguments, but only when so many bits are avaiable. This is figured out arguments, but only when so many bits are available. This is figured ou t
by means of FixedPointTraits, and a compile-time error is raised by means of FixedPointTraits, and a compile-time error is raised
when no suitable representation can be found. The idea is that the righ t when no suitable representation can be found. The idea is that the righ t
thing happens automatically as often as possible. thing happens automatically as often as possible.
<tt>FixedPoint</tt> implements the required interface of an <tt>FixedPoint</tt> implements the required interface of an
\ref AlgebraicRing and the required numeric and \ref AlgebraicRing and the required numeric and
promotion traits. In addition, it supports functions <tt>add</tt>, promotion traits. In addition, it supports functions <tt>add</tt>,
<tt>sub</tt>, and <tt>mul</tt>, where a particular layout of the result can <tt>sub</tt>, and <tt>mul</tt>, where a particular layout of the result can
be enforced. be enforced.
<tt>unsigned char, signed char, unsigned short, signed short, int</tt> can be <tt>unsigned char, signed char, unsigned short, signed short, int</tt> can be
transformed into a FixedPoint with appropriate layout by means of the f actory transformed into a FixedPoint with appropriate layout by means of the f actory
function <tt>fixedPoint()</tt>. function <tt>fixedPoint()</tt>.
<b>See also:</b> <b>See also:</b>
<ul> <ul>
<li> \ref FixedPointOperations <li> \ref FixedPointOperations
<li> \ref FixedPointTraits <li> \ref FixedPointTraits
</ul> </ul>
<b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vigra/fixedpoi nt.hxx</a>\><br> <b>\#include</b> \<vigra/fixedpoint.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned IntBits, unsigned FractionalBits> template <unsigned IntBits, unsigned FractionalBits>
class FixedPoint class FixedPoint
{ {
public: public:
enum { enum {
INT_BITS = IntBits, INT_BITS = IntBits,
FRACTIONAL_BITS = FractionalBits, FRACTIONAL_BITS = FractionalBits,
TOTAL_BITS = IntBits + FractionalBits, TOTAL_BITS = IntBits + FractionalBits,
skipping to change at line 463 skipping to change at line 463
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* FixedPointOperations */ /* FixedPointOperations */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup FixedPointOperations Functions for FixedPoint /** \addtogroup FixedPointOperations Functions for FixedPoint
\brief <b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vig ra/fixedpoint.hxx</a>\><br> \brief <b>\#include</b> \<vigra/fixedpoint.hxx\><br>
These functions fulfill the requirements of an \ref AlgebraicRing. These functions fulfill the requirements of an \ref AlgebraicRing.
Namespace: vigra Namespace: vigra
<p> <p>
*/ */
//@{ //@{
/** Convert a FixedPoint to a built-in type. /** Convert a FixedPoint to a built-in type.
skipping to change at line 756 skipping to change at line 756
template <unsigned IntBits1, unsigned FracBits1, unsigned IntBits2, uns igned FracBits2> template <unsigned IntBits1, unsigned FracBits1, unsigned IntBits2, uns igned FracBits2>
struct PromoteTraits<FixedPoint<IntBits1, FracBits1>, struct PromoteTraits<FixedPoint<IntBits1, FracBits1>,
FixedPoint<IntBits2, FracBits2> > FixedPoint<IntBits2, FracBits2> >
{ {
typedef typename typedef typename
FixedPointTraits<FixedPoint<IntBits1, FracBits1>, FixedPoint<In tBits2, FracBits2> >::PlusType FixedPointTraits<FixedPoint<IntBits1, FracBits1>, FixedPoint<In tBits2, FracBits2> >::PlusType
Promote; Promote;
}; };
\endcode \endcode
<b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vigra/fixedpoi nt.hxx</a>\><br> <b>\#include</b> \<vigra/fixedpoint.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned IntBits, unsigned FracBits> template <unsigned IntBits, unsigned FracBits>
struct NumericTraits<FixedPoint<IntBits, FracBits> > struct NumericTraits<FixedPoint<IntBits, FracBits> >
{ {
typedef FixedPoint<IntBits, FracBits> Type; typedef FixedPoint<IntBits, FracBits> Type;
//typedef FixedPoint<IntBits, FracBits> Promote; //typedef FixedPoint<IntBits, FracBits> Promote;
//typedef FixedPoint<IntBits, FracBits> RealPromote; //typedef FixedPoint<IntBits, FracBits> RealPromote;
//typedef std::complex<RealPromote> ComplexPromote; //typedef std::complex<RealPromote> ComplexPromote;
skipping to change at line 867 skipping to change at line 867
template <int IntBits, FPOverflowHandling OverflowHandling> template <int IntBits, FPOverflowHandling OverflowHandling>
struct SquareRootTraits<FixedPoint16<IntBits, OverflowHandling> > struct SquareRootTraits<FixedPoint16<IntBits, OverflowHandling> >
{ {
typedef FixedPoint16<IntBits, OverflowHandling> Type; typedef FixedPoint16<IntBits, OverflowHandling> Type;
typedef FixedPoint16<(IntBits + 1) / 2, OverflowHandling> SquareRo otResult; typedef FixedPoint16<(IntBits + 1) / 2, OverflowHandling> SquareRo otResult;
typedef Type SquareRo otArgument; typedef Type SquareRo otArgument;
}; };
\endcode \endcode
<b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vigra/fixedpoi nt.hxx</a>\><br> <b>\#include</b> \<vigra/fixedpoint.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <int IntBits, FPOverflowHandling OverflowHandling> template <int IntBits, FPOverflowHandling OverflowHandling>
struct NumericTraits<FixedPoint16<IntBits, OverflowHandling> > struct NumericTraits<FixedPoint16<IntBits, OverflowHandling> >
{ {
typedef FixedPoint16<IntBits, OverflowHandling> Type; typedef FixedPoint16<IntBits, OverflowHandling> Type;
typedef Type Promote; typedef Type Promote;
// RealPromote undefined -- multiplication with double is not suppo rted. // RealPromote undefined -- multiplication with double is not suppo rted.
// ComplexPromote undefined -- multiplication with double is not su pported. // ComplexPromote undefined -- multiplication with double is not su pported.
skipping to change at line 1166 skipping to change at line 1166
Built-in numeric types can be converted into <tt>FixedPoint16</tt> by t he Built-in numeric types can be converted into <tt>FixedPoint16</tt> by t he
appropriate constructors, and from <tt>FixedPoint16</tt> by means of appropriate constructors, and from <tt>FixedPoint16</tt> by means of
<tt>fixed_point_cast&lt;TargetType&gt;(fixedPoint)</tt>. <tt>fixed_point_cast&lt;TargetType&gt;(fixedPoint)</tt>.
<b>See also:</b> <b>See also:</b>
<ul> <ul>
<li> \ref FixedPoint16Operations <li> \ref FixedPoint16Operations
<li> \ref FixedPoint16Traits <li> \ref FixedPoint16Traits
</ul> </ul>
<b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vigra/fixedpoi nt.hxx</a>\><br> <b>\#include</b> \<vigra/fixedpoint.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <int IntBits, FPOverflowHandling OverflowHandling> template <int IntBits, FPOverflowHandling OverflowHandling>
class FixedPoint16 class FixedPoint16
{ {
public: public:
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);
skipping to change at line 1192 skipping to change at line 1192
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 taget type's <tt> OverflowHandling</tt>. Possible overflow is handled according to the target type's <tt >OverflowHandling</tt>.
*/ */
explicit FixedPoint16(Int32 v) explicit FixedPoint16(Int32 v)
: value(detail::FP16OverflowHandling<OverflowHandling>::exec(v << FRACT IONAL_BITS)) : value(detail::FP16OverflowHandling<OverflowHandling>::exec(v << FRACT IONAL_BITS))
{ {
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 by a bitwise copy. This is normally only used internally. /** Construct from an int by a bitwise copy. This is normally only used internally.
*/ */
FixedPoint16(Int32 v, FixedPointNoShift) FixedPoint16(Int32 v, FixedPointNoShift)
: value(detail::FP16OverflowHandling<OverflowHandling>::exec(v)) : value(detail::FP16OverflowHandling<OverflowHandling>::exec(v))
{ {
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 a double and round the fractional part to /** Construct from a double and round the fractional part to
<tt>FRACTIONAL_BITS</tt> accuracy. Possible overflow is handled according <tt>FRACTIONAL_BITS</tt> accuracy. Possible overflow is handled according
to the taget type's <tt>OverflowHandling</tt>. to the target type's <tt>OverflowHandling</tt>.
*/ */
explicit FixedPoint16(double rhs) explicit FixedPoint16(double rhs)
: value(detail::FP16OverflowHandling<OverflowHandling>::exec(roundi(rhs * ONE))) : value(detail::FP16OverflowHandling<OverflowHandling>::exec(roundi(rhs * ONE)))
{ {
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)>));
} }
/** Copy constructor. /** Copy constructor.
*/ */
FixedPoint16(const FixedPoint16 &other) FixedPoint16(const FixedPoint16 &other)
: value(other.value) : value(other.value)
{ {
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 a FixedPoint16 with different layout. It rounds as appropriate and /** Construct from a FixedPoint16 with different layout. It rounds as appropriate and
handles possible overflow according to the taget type's <tt>Ove rflowHandling</tt>. handles possible overflow according to the target type's <tt>Ov erflowHandling</tt>.
*/ */
template <int IntBits2, FPOverflowHandling OverflowHandling2> template <int IntBits2, FPOverflowHandling OverflowHandling2>
FixedPoint16(const FixedPoint16<IntBits2, OverflowHandling2> &other) FixedPoint16(const FixedPoint16<IntBits2, OverflowHandling2> &other)
: value(detail::FP16OverflowHandling<OverflowHandling>::exec( : value(detail::FP16OverflowHandling<OverflowHandling>::exec(
detail::FP16Align<IntBits2, IntBits, /*Round*/true>::exec(other .value))) detail::FP16Align<IntBits2, IntBits, /*Round*/true>::exec(other .value)))
{ {
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)>));
} }
/** Assignment from int. The fractional part will become zero. /** Assignment from int. The fractional part will become zero.
Possible overflow is handled according to the taget type's <tt> OverflowHandling</tt>. Possible overflow is handled according to the target type's <tt >OverflowHandling</tt>.
*/ */
FixedPoint16 &operator=(Int32 rhs) FixedPoint16 &operator=(Int32 rhs)
{ {
value = detail::FP16OverflowHandling<OverflowHandling>::exec(rhs << FRACTIONAL_BITS); value = detail::FP16OverflowHandling<OverflowHandling>::exec(rhs << FRACTIONAL_BITS);
return *this; return *this;
} }
/** Assignment form double. The fractional part is rounded, and pos sible overflow is /** Assignment form double. The fractional part is rounded, and pos sible overflow is
handled according to the taget type's <tt>OverflowHandling</tt> . handled according to the target type's <tt>OverflowHandling</tt >.
*/ */
FixedPoint16 &operator=(double rhs) FixedPoint16 &operator=(double rhs)
{ {
value = detail::FP16OverflowHandling<OverflowHandling>::exec(roundi (rhs * ONE)); value = detail::FP16OverflowHandling<OverflowHandling>::exec(roundi (rhs * ONE));
return *this; return *this;
} }
/** Copy assignment. /** Copy assignment.
*/ */
FixedPoint16 & operator=(const FixedPoint16 &other) FixedPoint16 & operator=(const FixedPoint16 &other)
{ {
value = other.value; value = other.value;
return *this; return *this;
} }
/** Assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is /** Assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is
handled according to the taget 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::FP16OverflowHandling<OverflowHandling>::exec( value = detail::FP16OverflowHandling<OverflowHandling>::exec(
detail::FP16Align<IntBits2, IntBits, /*Round*/true>::exec(o ther.value)); detail::FP16Align<IntBits2, IntBits, /*Round*/true>::exec(o ther.value));
return *this; return *this;
} }
/** Conversion to float /** Conversion to float
skipping to change at line 1337 skipping to change at line 1337
/** Post-decrement. /** Post-decrement.
*/ */
FixedPoint16 operator--(int) FixedPoint16 operator--(int)
{ {
FixedPoint16 old(*this); FixedPoint16 old(*this);
--(*this); --(*this);
return old; return old;
} }
/** Add-assignment from a FixedPoint16 with different layout. It ro unds as appropriate, and possible overflow is /** Add-assignment from a FixedPoint16 with different layout. It ro unds as appropriate, and possible overflow is
handled according to the taget 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::FP16AddImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value); value = detail::FP16AddImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value);
return *this; return *this;
} }
/** Subtract-assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is /** Subtract-assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is
handled according to the taget 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::FP16SubImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value); value = detail::FP16SubImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value);
return *this; return *this;
} }
/** Multiply-assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is /** Multiply-assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is
handled according to the taget 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::FP16MulImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value); value = detail::FP16MulImpl<IntBits, IntBits2, IntBits, OverflowHan dling>::exec(value, other.value);
return *this; return *this;
} }
/** Divide-assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is /** Divide-assignment from a FixedPoint16 with different layout. It rounds as appropriate, and possible overflow is
handled according to the taget 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;
} }
}; };
namespace detail { namespace detail {
skipping to change at line 1434 skipping to change at line 1434
} // namespace detail } // namespace detail
/********************************************************/ /********************************************************/
/* */ /* */
/* FixedPoint16Operations */ /* FixedPoint16Operations */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup FixedPoint16Operations Functions for FixedPoint16 /** \addtogroup FixedPoint16Operations Functions for FixedPoint16
\brief <b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vig ra/fixedpoint.hxx</a>\><br> \brief <b>\#include</b> \<vigra/fixedpoint.hxx\><br>
These functions fulfill the requirements of an \ref AlgebraicRing. These functions fulfill the requirements of an \ref AlgebraicRing.
Namespace: vigra Namespace: vigra
<p> <p>
*/ */
//@{ //@{
/** Convert a FixedPoint16 to a built-in type. /** Convert a FixedPoint16 to a built-in type.
skipping to change at line 1618 skipping to change at line 1618
{ {
typedef typename SquareRootTraits<FixedPoint16<IntBits, OverflowHandlin g> >::SquareRootResult Result; typedef typename SquareRootTraits<FixedPoint16<IntBits, OverflowHandlin g> >::SquareRootResult Result;
enum { Shift = 15 + IntBits - 2*Result::INT_BITS }; enum { Shift = 15 + IntBits - 2*Result::INT_BITS };
return Result(sqrti(v.value << Shift), FPNoShift); return Result(sqrti(v.value << Shift), FPNoShift);
} }
#ifndef VIGRA_NO_HYPOT #ifndef VIGRA_NO_HYPOT
using ::hypot; using ::hypot;
#endif #endif
/// Length of hypothenuse. /// Length of hypotenuse.
template <int IntBits, FPOverflowHandling OverflowHandling> template <int IntBits, FPOverflowHandling OverflowHandling>
inline FixedPoint16<IntBits, OverflowHandling> inline FixedPoint16<IntBits, OverflowHandling>
hypot(FixedPoint16<IntBits, OverflowHandling> v1, FixedPoint16<IntBits, Ove rflowHandling> v2) hypot(FixedPoint16<IntBits, OverflowHandling> v1, FixedPoint16<IntBits, Ove rflowHandling> v2)
{ {
UInt32 l = abs(v1.value), r = abs(v2.value); UInt32 l = abs(v1.value), r = abs(v2.value);
// sq(l) + sq(r) <= 2**31, so overflow handling after sqrti is sufficie nt // sq(l) + sq(r) <= 2**31, so overflow handling after sqrti is sufficie nt
return FixedPoint16<IntBits, OverflowHandling>( return FixedPoint16<IntBits, OverflowHandling>(
detail::FP16OverflowHandling<OverflowHandling>::exec(sqr ti(sq(l) + sq(r))), detail::FP16OverflowHandling<OverflowHandling>::exec(sqr ti(sq(l) + sq(r))),
FPNoShift); FPNoShift);
} }
 End of changes. 19 change blocks. 
19 lines changed or deleted 19 lines changed or added


 flatmorphology.hxx   flatmorphology.hxx 
skipping to change at line 68 skipping to change at line 68
/** \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 explicitely: pass arguments explicitly:
\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)
} }
skipping to change at line 95 skipping to change at line 95
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="flatmorphology_8hxx-source.html">vigra/ flatmorphology.hxx</a>\><br> <b>\#include</b> \<vigra/flatmorphology.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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>
skipping to change at line 209 skipping to change at line 209
for(yy=1; yy<=ymax; ++yy) for(yy=1; yy<=ymax; ++yy)
{ {
xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy]; xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
for(xx=0; xx<=xmax; ++xx) for(xx=0; xx<=xmax; ++xx)
{ {
hist[sa(xs, Diff2D(xx, -yy))]++; hist[sa(xs, Diff2D(xx, -yy))]++;
winsize++; winsize++;
} }
} }
// find the desired histogramm bin // find the desired histogram bin
leftsum = 0; leftsum = 0;
if(rank == 0.0) if(rank == 0.0)
{ {
for(i=0; i<256; i++) for(i=0; i<256; i++)
{ {
if(hist[i]) break; if(hist[i]) break;
} }
rankpos = i; rankpos = i;
} }
else else
skipping to change at line 242 skipping to change at line 242
++xd.x; ++xd.x;
// inner columns // inner columns
for(x=1; x<w; ++x, ++xs.x, ++xd.x) for(x=1; x<w; ++x, ++xs.x, ++xd.x)
{ {
x0 = x; x0 = x;
y0 = y; y0 = y;
x1 = w - x - 1; x1 = w - x - 1;
y1 = h - y - 1; y1 = h - y - 1;
// update histogramm // update histogram
// remove pixels at left border // remove pixels at left border
yy = (y1 < radius) ? y1 : radius; yy = (y1 < radius) ? y1 : radius;
for(; yy>=0; yy--) for(; yy>=0; yy--)
{ {
unsigned char cur; unsigned char cur;
xx = struct_function[yy]+1; xx = struct_function[yy]+1;
if(xx > x0) break; if(xx > x0) break;
cur = sa(xs, Diff2D(-xx, yy)); cur = sa(xs, Diff2D(-xx, yy));
skipping to change at line 299 skipping to change at line 299
xx = struct_function[yy]; xx = struct_function[yy];
if(xx > x1) break; if(xx > x1) break;
cur = sa(xs, Diff2D(xx, -yy)); cur = sa(xs, Diff2D(xx, -yy));
hist[cur]++; hist[cur]++;
if(cur < rankpos) leftsum++; if(cur < rankpos) leftsum++;
winsize++; winsize++;
} }
// find the desired histogramm bin // find the desired histogram bin
if(rank == 0.0) if(rank == 0.0)
{ {
if(leftsum == 0) if(leftsum == 0)
{ {
// search to the right // search to the right
for(i=rankpos; i<256; i++) for(i=rankpos; i<256; i++)
{ {
if(hist[i]) break; if(hist[i]) break;
} }
rankpos = i; rankpos = i;
skipping to change at line 376 skipping to change at line 376
/* */ /* */
/********************************************************/ /********************************************************/
/** \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 vor 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 explicitely: pass arguments explicitly:
\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)
} }
skipping to change at line 445 skipping to change at line 445
/* */ /* */
/********************************************************/ /********************************************************/
/** \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 vor 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 explicitely: pass arguments explicitly:
\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)
} }
skipping to change at line 514 skipping to change at line 514
/* */ /* */
/********************************************************/ /********************************************************/
/** \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 vor 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 explicitely: pass arguments explicitly:
\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)
} }
skipping to change at line 592 skipping to change at line 592
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 explicitely: pass arguments explicitly:
\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,
skipping to change at line 623 skipping to change at line 623
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="flatmorphology_8hxx-source.html">vigra/flat morphology.hxx</a>\><br> <b>\#include</b> \<vigra/flatmorphology.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 755 skipping to change at line 755
{ {
Diff2D pos(xx, -yy); Diff2D pos(xx, -yy);
if(mask(xm, pos)) if(mask(xm, pos))
{ {
hist[sa(xs, pos)]++; hist[sa(xs, pos)]++;
winsize++; winsize++;
} }
} }
} }
// find the desired histogramm bin // find the desired histogram bin
if(winsize) if(winsize)
{ {
if(rank == 0.0) if(rank == 0.0)
{ {
for(i=0; i<256; i++) for(i=0; i<256; i++)
{ {
if(hist[i]) break; if(hist[i]) break;
} }
rankpos = i; rankpos = i;
} }
skipping to change at line 791 skipping to change at line 791
++xm.x; ++xm.x;
// inner columns // inner columns
for(x=1; x<w; ++x, ++xs.x, ++xd.x, ++xm.x) for(x=1; x<w; ++x, ++xs.x, ++xd.x, ++xm.x)
{ {
x0 = x; x0 = x;
y0 = y; y0 = y;
x1 = w - x - 1; x1 = w - x - 1;
y1 = h - y - 1; y1 = h - y - 1;
// update histogramm // update histogram
// remove pixels at left border // remove pixels at left border
yy = (y1 < radius) ? y1 : radius; yy = (y1 < radius) ? y1 : radius;
for(; yy>=0; yy--) for(; yy>=0; yy--)
{ {
unsigned char cur; unsigned char cur;
xx = struct_function[yy]+1; xx = struct_function[yy]+1;
if(xx > x0) break; if(xx > x0) break;
Diff2D pos(-xx, yy); Diff2D pos(-xx, yy);
if(mask(xm, pos)) if(mask(xm, pos))
skipping to change at line 864 skipping to change at line 864
if(mask(xm, pos)) if(mask(xm, pos))
{ {
cur = sa(xs, pos); cur = sa(xs, pos);
hist[cur]++; hist[cur]++;
if(cur < rankpos) leftsum++; if(cur < rankpos) leftsum++;
winsize++; winsize++;
} }
} }
// find the desired histogramm bin // find the desired histogram bin
if(winsize) if(winsize)
{ {
if(rank == 0.0) if(rank == 0.0)
{ {
if(leftsum == 0) if(leftsum == 0)
{ {
// search to the right // search to the right
for(i=rankpos; i<256; i++) for(i=rankpos; i<256; i++)
{ {
if(hist[i]) break; if(hist[i]) break;
skipping to change at line 953 skipping to change at line 953
/********************************************************/ /********************************************************/
/** \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 vor 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 explicitely: pass arguments explicitly:
\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,
skipping to change at line 1034 skipping to change at line 1034
/********************************************************/ /********************************************************/
/** \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 vor 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 explicitely: pass arguments explicitly:
\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,
skipping to change at line 1115 skipping to change at line 1115
/********************************************************/ /********************************************************/
/** \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 vor 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 explicitely: pass arguments explicitly:
\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,
 End of changes. 16 change blocks. 
16 lines changed or deleted 16 lines changed or added


 functorexpression.hxx   functorexpression.hxx 
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_FUNCTOREXPRESSION_HXX #ifndef VIGRA_FUNCTOREXPRESSION_HXX
#define VIGRA_FUNCTOREXPRESSION_HXX #define VIGRA_FUNCTOREXPRESSION_HXX
/** \page FunctorExpressions Functor Expressions /** \page FunctorExpressions Functor Expressions
Simple automatic functor creation by means of expression templates Simple automatic functor creation by means of expression templates
(also known as a "lambda library"). (also known as a "lambda library").
<b>\#include</b> \<<a href="functorexpression_8hxx-source.html">vigra/f unctorexpression.hxx</a>\><br> <b>\#include</b> \<vigra/functorexpression.hxx\><br>
Namespace: vigra::functor Namespace: vigra::functor
<b> Motivation</b> <b> Motivation</b>
Many generic algorithms are made more flexible by means of functors Many generic algorithms are made more flexible by means of functors
which define part of the algorithms' behavior according to the which define part of the algorithms' behavior according to the
needs of a specific situation. For example, we can apply an exponential needs of a specific situation. For example, we can apply an exponential
to each pixel by passing a pointer to the <TT>exp</TT> function to each pixel by passing a pointer to the <TT>exp</TT> function
to <TT>transformImage()</TT>: to <TT>transformImage()</TT>:
skipping to change at line 95 skipping to change at line 95
\code \code
double beta = ...; double beta = ...;
vigra::transformImage(srcImageRange(src), destImage(dest), vigra::transformImage(srcImageRange(src), destImage(dest),
Exponential(beta)); Exponential(beta));
\endcode \endcode
However, this approach has some disadvantages: However, this approach has some disadvantages:
<UL> <UL>
<li> Writing a functor is more work then simply programm the loop <li> Writing a functor is more work then simply program the loop
directly, i.e. non-generically. Programmers will tend to directly, i.e. non-generically. Programmers will tend to
avoid generic constructs, if they require so much writing. avoid generic constructs, if they require so much writing.
<li> Often, functors are only needed for a single expression. <li> Often, functors are only needed for a single expression.
It is not desirable to get into the trouble of introducing It is not desirable to get into the trouble of introducing
and documenting a new class if that class is used only once. and documenting a new class if that class is used only once.
<li> Functors cannot be implemented directly at the point of use. <li> Functors cannot be implemented directly at the point of use.
Thus, to find out exactly what a functor is doing, one needs Thus, to find out exactly what a functor is doing, one needs
to look somewhere else. This complicates use and maintainance to look somewhere else. This complicates use and maintenance
ot generic code. ot generic code.
</UL> </UL>
Therefore, it is necessary to provide a means to generate functors on Therefore, it is necessary to provide a means to generate functors on
the fly where they are needed. The C++ standard library contains so cal led the fly where they are needed. The C++ standard library contains so cal led
"functor combinators" that allow to construct complicated functors from "functor combinators" that allow to construct complicated functors from
simpler ones. The above problem "apply <TT>exp(-beta*v)</TT> to every p ixel" simpler ones. The above problem "apply <TT>exp(-beta*v)</TT> to every p ixel"
would be solved like this: would be solved like this:
skipping to change at line 233 skipping to change at line 233
float threshold = ...; float threshold = ...;
transformImage(srcImageRange(src), destImage(thresholded), transformImage(srcImageRange(src), destImage(thresholded),
ifThenElse(Arg1() < Param(threshold), ifThenElse(Arg1() < Param(threshold),
Param(0.0), // yes branch Param(0.0), // yes branch
Param(1.0)) // no branch Param(1.0)) // no branch
); );
\endcode \endcode
You can use the <TT>Var()</TT> functor to assign values to a variable You can use the <TT>Var()</TT> functor to assign values to a variable
(<TT>=, +=, -=, *=, /=</TT>&nbsp; are suported). For example, the avera ge gray (<TT>=, +=, -=, *=, /=</TT>&nbsp; are supported). For example, the aver age gray
value of the image is calculated like this: value of the image is calculated like this:
\code \code
using namespace vigra::functor; using namespace vigra::functor;
vigra::FImage src(w,h); vigra::FImage src(w,h);
...// fill src ...// fill src
double sum = 0.0; double sum = 0.0;
skipping to change at line 272 skipping to change at line 272
inspectImage(srcImageRange(label_image), inspectImage(srcImageRange(label_image),
ifThen(Arg1() == Param(region_label), ifThen(Arg1() == Param(region_label),
Var(size) += Param(1))); Var(size) += Param(1)));
std::cout << "Size of region " << region_label << ": " << size << std:: endl; std::cout << "Size of region " << region_label << ": " << size << std:: endl;
\endcode \endcode
Often, we want to execute several commands in one functor. This can be done Often, we want to execute several commands in one functor. This can be done
by means of the overloaded <TT>operator,()</TT> ("operator comma"). Exp ressions by means of the overloaded <TT>operator,()</TT> ("operator comma"). Exp ressions
seperated by a comma will be executed in succession. We can thus separated by a comma will be executed in succession. We can thus
simultaneously find the size and the average gray value of a region: simultaneously find the size and the average gray value of a region:
\code \code
using namespace vigra::functor; using namespace vigra::functor;
vigra::FImage src(w,h); vigra::FImage src(w,h);
vigra::IImage label_image(w,h); vigra::IImage label_image(w,h);
...// segment src and mark regions in label_image ...// segment src and mark regions in label_image
int region_label = ...; // the region we want to inspect int region_label = ...; // the region we want to inspect
skipping to change at line 470 skipping to change at line 470
template <class T1, class T2, class T3> template <class T1, class T2, class T3>
T1 const & operator()(T1 const & v1, T2 const &, T3 const &) const T1 const & operator()(T1 const & v1, T2 const &, T3 const &) const
{ {
return v1; return v1;
} }
private: private:
UnaryFunctor & operator=(UnaryFunctor const &); // not implemented UnaryFunctor & operator=(UnaryFunctor const &); // not implemented
}; };
typedef UnaryFunctor<ArgumentFunctor1> Identity;
template <> template <>
struct ResultTraits0<UnaryFunctor<ArgumentFunctor1> > struct ResultTraits0<UnaryFunctor<ArgumentFunctor1> >
{ {
typedef ErrorType Res; typedef ErrorType Res;
}; };
template <class T1> template <class T1>
struct ResultTraits1<UnaryFunctor<ArgumentFunctor1>, T1> struct ResultTraits1<UnaryFunctor<ArgumentFunctor1>, T1>
{ {
typedef T1 Res; typedef T1 Res;
 End of changes. 6 change blocks. 
5 lines changed or deleted 7 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> \<<a href="functortraits_8hxx-source.html">vigra/funct ortraits.hxx</a>\> <b>\#include</b> \<vigra/functortraits.hxx\>
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 71 skipping to change at line 71
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Create a gabor filter in frequency space. /** \brief Create a gabor filter in frequency space.
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 explicitely 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 arguments explicitly:
\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,
skipping to change at line 101 skipping to change at line 101
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="gaborfilter_8hxx-source.html">vigra/gaborfi lter.hxx</a>\><br> <b>\#include</b> \<vigra/gaborfilter.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 226 skipping to change at line 226
/********************************************************/ /********************************************************/
/* */ /* */
/* angularGaborSigma */ /* angularGaborSigma */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate sensible angular sigma for given parameters. /** \brief Calculate sensible angular sigma for given parameters.
"Sensible" means: If you use a range of gabor filters for feature "Sensible" means: If you use a range of gabor filters for feature
detection, you are interested in minimal redundance. This is hard detection, you are interested in minimal redundancy. This is hard
to define but one possible try is to arrange the filters in to define but one possible try is to arrange the filters in
frequency space, so that the half-peak-magnitude ellipses touch frequency space, so that the half-peak-magnitude ellipses touch
each other. each other.
To do so, you must know the number of directions (first parameter To do so, you must know the number of directions (first parameter
for the angular sigma function) and the center frequency of the for the angular sigma function) and the center frequency of the
filter you want to calculate the sigmas for. filter you want to calculate the sigmas for.
The exact formulas are: The exact formulas are:
\code \code
skipping to change at line 282 skipping to change at line 282
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> \<<a href="gaborfilter_8hxx-source.html">vigra/gaborfi lter.hxx</a>\> <b>\#include</b> \<vigra/gaborfilter.hxx\>
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 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_;
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 gaussians.hxx   gaussians.hxx 
skipping to change at line 57 skipping to change at line 57
#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> \<<a href="gaussians_8hxx-source.html">vigra/gaussians .hxx</a>\><br> <b>\#include</b> \<vigra/gaussians.hxx\><br>
Namespace: vigra Namespace: vigra
\ingroup MathFunctions \ingroup MathFunctions
*/ */
template <class T = double> template <class T = double>
class Gaussian class Gaussian
{ {
public: public:
/** the value type if used as a kernel in \ref resamplingConvolveIm age(). /** the value type if used as a kernel in \ref resamplingConvolveIm age().
 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 107 skipping to change at line 107
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="gradient__energy__tensor_8hxx-source.html"> vigra/gradient_energy_tensor.hxx</a>\> <b>\#include</b> \<vigra/gradient_energy_tensor.hxx\>
\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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 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 <H5version.h>
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR >= 8 && defined(H5_USE_16_API_DEFA #define H5Gcreate_vers 2
ULT)) #define H5Gopen_vers 2
# define H5Gcreate_vers 2 #define H5Dopen_vers 2
# define H5Gopen_vers 2 #define H5Dcreate_vers 2
# define H5Dopen_vers 2 #define H5Acreate_vers 2
# define H5Dcreate_vers 2
# define H5Acreate_vers 2
#endif
#include <hdf5.h> #include <hdf5.h>
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6) #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
# ifndef H5Gopen # ifndef H5Gopen
# define H5Gopen(a, b, c) H5Gopen(a, b) # define H5Gopen(a, b, c) H5Gopen(a, b)
# endif # endif
# ifndef H5Gcreate # ifndef H5Gcreate
# define H5Gcreate(a, b, c, d, e) H5Gcreate(a, b, 1) # define H5Gcreate(a, b, c, d, e) H5Gcreate(a, b, 1)
# endif # endif
# ifndef H5Dopen # ifndef H5Dopen
# define H5Dopen(a, b, c) H5Dopen(a, b) # define H5Dopen(a, b, c) H5Dopen(a, b)
# endif # endif
# ifndef H5Dcreate # ifndef H5Dcreate
# define H5Dcreate(a, b, c, d, e, f, g) H5Dcreate(a, b, c, d, f) # define H5Dcreate(a, b, c, d, e, f, g) H5Dcreate(a, b, c, d, f)
# endif # endif
# ifndef H5Acreate # ifndef H5Acreate
# define H5Acreate(a, b, c, d, e, f) H5Acreate(a, b, c, d, e) # define H5Acreate(a, b, c, d, e, f) H5Acreate(a, b, c, d, e)
# endif # endif
# ifndef H5Pset_obj_track_times
# define H5Pset_obj_track_times(a, b) do {} while (0)
# 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_impex.hxx" #include "multi_impex.hxx"
#include "utilities.hxx"
#include "error.hxx"
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 Wrapper for hid_t objects.
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 usually stored as objects of t ype 'hid_t'. 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
std::auto_ptr calls 'delete' on the contained pointer). A pointer to th e close function must be std::auto_ptr calls 'delete' on the contained pointer). A pointer to th e close function must be
passed to the constructor, along with an error message that is raised w hen creation/opening fails. passed to the constructor, along with an error message that is raised w hen creation/opening fails.
skipping to change at line 109 skipping to change at line 111
<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 as a plain hid_t object ... // use file_id in the same way as a plain hid_t object
\endcode \endcode
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex .hxx</a>\><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);
private: private:
hid_t handle_; hid_t handle_;
Destructor destructor_; Destructor destructor_;
public: public:
/** \brief Default constuctor. /** \brief Default constructor.
Creates a NULL handle. Creates a NULL handle.
**/ **/
HDF5Handle() HDF5Handle()
: 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.
skipping to change at line 149 skipping to change at line 151
<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
\endcode \endcode
**/ */
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 std::auto_ ptr). Hands over ownership of the RHS handle (analogous to std::auto_ ptr).
**/ */
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 std::auto_ptr). RHS handle (analogous to std::auto_ptr).
**/ */
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;
} }
return *this; return *this;
} }
/** \brief Destreuctor. /** \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 red within /** \brief Explicitly call the stored function (if one has been sto red within
this object) for the contained handle and set the handle to NU LL. this object) for the contained handle and set the handle to NU LL.
**/ */
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;
return res; return res;
} }
/** \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.
This function ensures that hid_t objects can be transparently repla ced with This function ensures that hid_t objects can be transparently repla ced with
HDF5Handle objects in user code. Do not call a close function on th e return HDF5Handle objects in user code. Do not call a close function on th e return
value - a crash will be likely otherwise. value - a crash will be likely otherwise.
**/ */
operator hid_t() const operator hid_t() const
{ {
return handle_; return handle_;
} }
/** \brief Equality comparison of the contained handle. /** \brief Equality comparison of the contained handle.
**/ */
bool operator==(HDF5Handle const & h) const bool operator==(HDF5Handle const & h) const
{ {
return handle_ == h.handle_; return handle_ == h.handle_;
} }
/** \brief Equality comparison of the contained handle. /** \brief Equality comparison of the contained handle.
**/ */
bool operator==(hid_t h) const bool operator==(hid_t h) const
{ {
return handle_ == h; return handle_ == h;
} }
/** \brief Unequality comparison of the contained handle. /** \brief Inequality comparison of the contained handle.
**/ */
bool operator!=(HDF5Handle const & h) const bool operator!=(HDF5Handle const & h) const
{ {
return handle_ != h.handle_; return handle_ != h.handle_;
} }
/** \brief Unequality 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;
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* 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 a HDF5 file used to read an image or array from an HDF5 file
and enquire about its properties. and enquire about its properties.
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx </a>\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
**/ */
class HDF5ImportInfo class HDF5ImportInfo
{ {
public: public:
enum PixelType { UINT8, UINT16, UINT32, UINT64, enum PixelType { UINT8, UINT16, UINT32, UINT64,
INT8, INT16, INT32, INT64, INT8, INT16, INT32, INT64,
FLOAT, DOUBLE }; FLOAT, DOUBLE };
/** Construct HDF5ImportInfo object. /** Construct HDF5ImportInfo object.
The dataset \a pathInFile in the HDF5 file \a filename is acces sed to The dataset \a pathInFile in the HDF5 file \a filename is acces sed to
read its properties. \a pathInFile may contain '/'-separated gr oup read its properties. \a pathInFile may contain '/'-separated gr oup
names, but must end with the name of the desired dataset: names, but must end with the name of the desired dataset:
\code \code
HDF5ImportInfo info(filename, "/group1/group2/my_dataset"); HDF5ImportInfo info(filename, "/group1/group2/my_dataset");
\endcode \endcode
**/ */
VIGRA_EXPORT HDF5ImportInfo( const char* filePath, const char* pathInFi le ); VIGRA_EXPORT HDF5ImportInfo( const char* filePath, const char* pathInFi le );
VIGRA_EXPORT ~HDF5ImportInfo(); VIGRA_EXPORT ~HDF5ImportInfo();
/** Get the filename of this HDF5 object. /** Get the filename of this HDF5 object.
**/ */
VIGRA_EXPORT const std::string& getFilePath() const; VIGRA_EXPORT const std::string& getFilePath() const;
/** Get the dataset's full name in the HDF5 file. /** Get the dataset's full name in the HDF5 file.
**/ */
VIGRA_EXPORT const std::string& getPathInFile() const; VIGRA_EXPORT const std::string& getPathInFile() const;
/** Get a handle to the file represented by this info object. /** Get a handle to the file represented by this info object.
**/ */
VIGRA_EXPORT hid_t getH5FileHandle() const; VIGRA_EXPORT hid_t getH5FileHandle() const;
/** Get a handle to the dataset represented by this info object. /** Get a handle to the dataset represented by this info object.
**/ */
VIGRA_EXPORT hid_t getDatasetHandle() const; VIGRA_EXPORT hid_t getDatasetHandle() const;
/** Get the number of dimensions of the dataset represented by this info object. /** Get the number of dimensions of the dataset represented by this info object.
**/ */
VIGRA_EXPORT MultiArrayIndex numDimensions() const; VIGRA_EXPORT MultiArrayIndex numDimensions() const;
/** Get the shape of the dataset represented by this info object. /** Get the shape of the dataset represented by this info object.
**/ */
VIGRA_EXPORT ArrayVector<hsize_t> const & shape() const VIGRA_EXPORT ArrayVector<hsize_t> const & shape() const
{ {
return m_dims; return m_dims;
} }
/** Get the shape (length) of the dataset along dimension \a dim. /** Get the shape (length) of the dataset along dimension \a dim.
**/ */
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>"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>"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
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)
<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; HDF5Handle 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 type>
inline hid_t getH5DataType() inline hid_t getH5DataType()
{ {
std::runtime_error("getH5DataType(): invalid type"); std::runtime_error("getH5DataType(): invalid type");
return 0; return 0;
} }
#define VIGRA_H5_DATATYPE(type, h5type) \ #define VIGRA_H5_DATATYPE(type, h5type) \
template<> \ template<> \
inline hid_t getH5DataType<type>() \ inline hid_t getH5DataType<type>() \
{ return h5type;} { return h5type;}
VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR) VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
VIGRA_H5_DATATYPE(Int8, H5T_NATIVE_INT8)
VIGRA_H5_DATATYPE(Int16, H5T_NATIVE_INT16)
VIGRA_H5_DATATYPE(Int32, H5T_NATIVE_INT32)
VIGRA_H5_DATATYPE(Int64, H5T_NATIVE_INT64)
VIGRA_H5_DATATYPE(UInt8, H5T_NATIVE_UINT8)
VIGRA_H5_DATATYPE(UInt16, H5T_NATIVE_UINT16)
VIGRA_H5_DATATYPE(UInt32, H5T_NATIVE_UINT32)
VIGRA_H5_DATATYPE(UInt64, H5T_NATIVE_UINT64)
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
template<>
inline hid_t getH5DataType<char*>()
{
hid_t stringtype = H5Tcopy (H5T_C_S1);
H5Tset_size(stringtype, H5T_VARIABLE);
return stringtype;
}
template<>
inline hid_t getH5DataType<const char*>()
{
hid_t stringtype = H5Tcopy (H5T_C_S1);
H5Tset_size(stringtype, H5T_VARIABLE);
return stringtype;
}
#undef VIGRA_H5_DATATYPE #undef VIGRA_H5_DATATYPE
#define VIGRA_H5_SIGNED_DATATYPE(type) \
template<> \
inline hid_t getH5DataType<type>() \
{ 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
#if 0
template<>
inline hid_t getH5DataType<FFTWComplex<float> >()
{
hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<float>)
);
H5Tinsert (complex_id, "real", 0, H5T_NATIVE_FLOAT);
H5Tinsert (complex_id, "imaginary", sizeof(float), H5T_NATIVE_FLOAT);
return complex_id;
}
template<>
inline hid_t getH5DataType<FFTWComplex<double> >()
{
hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<double>
));
H5Tinsert (complex_id, "real", 0, H5T_NATIVE_DOUBLE);
H5Tinsert (complex_id, "imaginary", sizeof(double), H5T_NATIVE_DOUBLE);
return complex_id;
}
#endif
} // namespace detail } // namespace detail
// helper friend function for callback HDF5_ls_inserter_callback()
void HDF5_ls_insert(void*, const std::string &);
// callback function for ls(), called via HDF5File::H5Literate()
// see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-3
3.2
// for as to why.
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*);
/********************************************************/
/* */
/* HDF5File */
/* */
/********************************************************/
/** \brief Access to HDF5 files
HDF5File provides a convenient way of accessing data in HDF5 files. vigra::
MultiArray
structures of any dimension can be stored to / loaded from HDF5 files. Typi
cal
HDF5 features like subvolume access, chunks and data compression are availa
ble,
string attributes can be attached to any dataset or group. Group- or datase
t-handles
are encapsulated in the class and managed automatically. The internal file-
system like
structure can be accessed by functions like "cd()" or "mkdir()".
<b>Example:</b>
Write the MultiArray out_multi_array to file. Change the current directory
to
"/group" and read in the same MultiArray as in_multi_array.
\code
HDF5File file("/path/to/file",HDF5File::New);
file.mkdir("group");
file.write("/group/dataset", out_multi_array);
file.cd("/group");
file.read("dataset", in_multi_array);
\endcode
<b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra
*/
class HDF5File
{
private:
HDF5Handle fileHandle_;
// current group handle
HDF5Handle cGroupHandle_;
// time tagging of datasets, turned off (= 0) by default.
int track_time;
// helper class for ls()
struct ls_closure
{
virtual void insert(const std::string &) = 0;
virtual ~ls_closure() {}
};
// datastructure to hold a list of dataset and group names
struct lsOpData : public ls_closure
{
std::vector<std::string> & objects;
lsOpData(std::vector<std::string> & o) : objects(o) {}
void insert(const std::string & x)
{
objects.push_back(x);
}
};
// (associative-)container closure
template<class Container>
struct ls_container_data : public ls_closure
{
Container & objects;
ls_container_data(Container & o) : objects(o) {}
void insert(const std::string & x)
{
objects.insert(std::string(x));
}
};
public:
// helper for callback HDF5_ls_inserter_callback(), used by ls()
friend void HDF5_ls_insert(void*, const std::string &);
/** \brief Set how a file is opened.
OpenMode::New creates a new file. If the file already exists, overwri
te it.
OpenMode::Open opens a file for reading/writing. The file will be cre
ated,
if necessary.
*/
enum OpenMode {
New, // Create new empty file (existing file will be dele
ted).
Open // Open file. Create if not existing.
};
/** \brief Create an HDF5File object.
Creates or opens HDF5 file at position filename. The current group is s
et
to "/".
*/
HDF5File(std::string filename, OpenMode mode, int track_creation_times
= 0)
: track_time(track_creation_times)
{
std::string errorMessage = "HDF5File: Could not create file '" + fi
lename + "'.";
fileHandle_ = HDF5Handle(createFile_(filename, mode), &H5Fclose, er
rorMessage.c_str());
cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5F
ile(): Failed to open root group.");
}
/** \brief Destructor to make sure that all data is flushed before clos
ing the file.
*/
~HDF5File()
{
//Write everything to disk before closing
H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
}
/** \brief Change current group to "/".
*/
inline void root()
{
std::string message = "HDF5File::root(): Could not open group '/'."
;
cGroupHandle_ = HDF5Handle(H5Gopen(fileHandle_, "/", H5P_DEFAULT),&
H5Gclose,message.c_str());
}
/** \brief Change the current group.
Both absolute and relative group names are allowed.
*/
inline void cd(std::string groupName)
{
std::string message = "HDF5File::cd(): Could not open group '" + gr
oupName + "'.\n";
// make groupName clean
groupName = get_absolute_path(groupName);
if(groupName == "/"){
cGroupHandle_ = HDF5Handle(openCreateGroup_("/"),&H5Gclose,mess
age.c_str());
return;
}
else{
if (H5Lexists(fileHandle_, groupName.c_str(), H5P_DEFAULT) == 0
)
{
std::cerr << message;
return;
}
cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName),&H5Gclos
e,message.c_str());
}
}
/** \brief Change the current group to its parent group.
returns true if successful, false otherwise.
*/
inline bool cd_up()
{
std::string groupName = currentGroupName_();
//do not try to move up if we already in "/"
if(groupName == "/"){
return false;
}
size_t lastSlash = groupName.find_last_of('/');
std::string parentGroup (groupName.begin(), groupName.begin()+lastS
lash+1);
cd(parentGroup);
return true;
}
inline void cd_up(int levels)
{
for(int i = 0; i<levels; i++)
cd_up();
}
/** \brief Create a new group.
If the first character is a "/", the path will be interpreted as abso
lute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
inline void mkdir(std::string groupName)
{
// make groupName clean
groupName = get_absolute_path(groupName);
hid_t handle = openCreateGroup_(groupName.c_str());
if (handle != cGroupHandle_){
H5Gclose(handle);
}
}
/** \brief Change the current group; create it if necessary.
If the first character is a "/", the path will be interpreted as abso
lute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
inline void cd_mk(std::string groupName)
{
// make groupName clean
groupName = get_absolute_path(groupName);
std::string message = "HDF5File::cd_mk(): Could not create group '
" + groupName + "'.";
cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName.c_str()),&H5G
close,message.c_str());
}
// helper function for the various ls() variants.
void ls_H5Literate(ls_closure & data)
{
H5Literate(cGroupHandle_, H5_INDEX_NAME, H5_ITER_NATIVE, NULL,
HDF5_ls_inserter_callback, static_cast<void*>(&data));
}
/** \brief List the contents of the current group.
The function returns a vector of strings holding the entries of the
current group. Only datasets and groups are listed, other objects
(e.g. datatypes) are ignored. Group names always have an ending "/".
*/
/**
*
*/
inline std::vector<std::string> ls()
{
std::vector<std::string> list;
lsOpData data(list);
ls_H5Literate(data);
return list;
}
/** \brief List the contents of the current group into a container-like
object via insert(). Only datasets and groups are inserted,
other
objects (e.g., datatypes) are ignored. Group names always ha
ve an
ending "/".
The argument cont is presumably an associative container, however,
only its member function <tt>cont.insert(std::string)</tt> will be
called.
\param cont reference to a container supplying a member functi
on
<tt>insert(const i_type &)</tt>, where <tt>i_type<
/tt>
is convertible to <tt>std::string</tt>.
*/
template<class Container>
void ls(Container & cont)
{
ls_container_data<Container> data(cont);
ls_H5Literate(data);
}
/** \brief Get the path of the current group.
*/
inline std::string pwd()
{
return currentGroupName_();
}
/** \brief Get the name of the associated file.
*/
inline std::string filename()
{
return fileName_();
}
/** \brief Get the number of dimensions of a certain dataset
If the first character is a "/", the path will be interpreted as abso
lute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
inline hssize_t getDatasetDimensions(std::string datasetName)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
//Open dataset and dataspace
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
dataspace.";
HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose,
errorMessage.c_str());
//return dimension information
return H5Sget_simple_extent_ndims(dataspaceHandle);
}
/** \brief Get the shape of each dimension of a certain dataset.
Normally, this function is called after determining the dimension of
the
dataset using \ref getDatasetDimensions().
If the first character is a "/", the path will be interpreted as abso
lute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
inline ArrayVector<hsize_t> getDatasetShape(std::string datasetName)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
//Open dataset and dataspace
std::string errorMessage = "HDF5File::getDatasetShape(): Unable to
open dataset '" + datasetName + "'.";
HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName
), &H5Dclose, errorMessage.c_str());
errorMessage = "HDF5File::getDatasetShape(): Unable to access datas
pace.";
HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose,
errorMessage.c_str());
//get dimension information
ArrayVector<hsize_t>::size_type dimensions = H5Sget_simple_extent_n
dims(dataspaceHandle);
ArrayVector<hsize_t> shape(dimensions);
ArrayVector<hsize_t> maxdims(dimensions);
H5Sget_simple_extent_dims(dataspaceHandle, shape.data(), maxdims.da
ta());
// invert the dimensions to guarantee c-order
ArrayVector<hsize_t> shape_inv(dimensions);
for(ArrayVector<hsize_t>::size_type i=0; i<shape.size(); i++) {
shape_inv[i] = shape[dimensions-1-i];
}
return shape_inv;
}
/** \brief Obtain the HDF5 handle of a dataset.
*/
inline hid_t getDatasetHandle(std::string dataset_name)
{
return getDatasetHandle_(dataset_name);
}
/** \brief Obtain the HDF5 handle of a group.
*/
inline hid_t getGroupHandle(std::string group_name)
{
// make group_name clean
group_name = get_absolute_path(group_name);
// group must exist
vigra_precondition((H5Lexists(fileHandle_, group_name.c_str(), H5P_
DEFAULT) == 1), "Error: Group '" + group_name + "' does not exist.");
//open group and return group handle
return openCreateGroup_( group_name);
}
/** \brief Obtain the HDF5 handle of a attribute.
*/
inline hid_t getAttributeHandle(std::string dataset_name, std::string a
ttribute_name)
{
HDF5Handle dset (getDatasetHandle_(dataset_name),&H5Dclose,std::str
ing("Error: Dataset '"+dataset_name+"' not found.").c_str());
return H5Aopen(dset, attribute_name.c_str(),H5P_DEFAULT);
}
/* Writing Attributes */
/** \brief Write MultiArray Attributes.
* In contrast to datasets, subarray access, chunks and compression ar
e not available.
*/
template<unsigned int N, class T>
inline void writeAttribute(std::string object_name, std::string attribu
te_name, const MultiArrayView<N, T, UnstridedArrayTag> & array)
{
// make object_name clean
object_name = get_absolute_path(object_name);
write_attribute_(object_name, attribute_name, array, detail::getH5D
ataType<T>(), 1);
}
template<unsigned int N, class T, int SIZE>
inline void writeAttribute(std::string datasetName, std::string attribu
teName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & a
rray)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
write_attribute_(datasetName, attributeName, array, detail::getH5Da
taType<T>(), SIZE);
}
template<unsigned int N, class T>
inline void writeAttribute(std::string datasetName, std::string attribu
teName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
write_attribute_(datasetName, attributeName, array, detail::getH5Da
taType<T>(), 3);
}
/** \brief Write a single value.
Specialization of the write function for simple datatypes
*/
inline void writeAttribute(std::string object_name, std::string attribu
te_name, char data)
{ writeAtomicAttribute(object_name,attribute_name,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, signed char data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, signed short data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, signed int data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, signed long data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, signed long long data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, unsigned char data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, unsigned short data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, unsigned int data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, unsigned long data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, unsigned long long data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, float data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, double data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, long double data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, const char* data)
{ writeAtomicAttribute(datasetName,attributeName,data); }
inline void writeAttribute(std::string datasetName, std::string attribu
teName, std::string const & data)
{ writeAtomicAttribute(datasetName,attributeName,data.c_str()); }
/** \brief Test if attribute exists.
*/
bool existsAttribute(std::string object_name, std::string attribute_nam
e)
{
std::string obj_path = get_absolute_path(object_name);
htri_t exists = H5Aexists_by_name(fileHandle_, obj_path.c_str(),
attribute_name.c_str(), H5P_DEFAU
LT);
vigra_precondition(exists >= 0, "HDF5File::existsAttribute(): "
"object \"" + object_name + "\" "
"not found.");
return exists != 0;
}
// Reading Attributes
/** \brief Read MultiArray Attributes.
* In contrast to datasets, subarray access is not available.
*/
template<unsigned int N, class T>
inline void readAttribute(std::string object_name, std::string attribut
e_name, const MultiArrayView<N, T, UnstridedArrayTag> & array)
{
// make object_name clean
object_name = get_absolute_path(object_name);
read_attribute_(object_name, attribute_name, array, detail::getH5Da
taType<T>(), 1);
}
template<unsigned int N, class T, int SIZE>
inline void readAttribute(std::string datasetName, std::string attribut
eName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & ar
ray)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
read_attribute_(datasetName, attributeName, array, detail::getH5Dat
aType<T>(), SIZE);
}
template<unsigned int N, class T>
inline void readAttribute(std::string datasetName, std::string attribut
eName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
read_attribute_(datasetName, attributeName, array, detail::getH5Dat
aType<T>(), 3);
}
/** \brief Read a single value.
Specialization of the read function for simple datatypes
*/
inline void readAttribute(std::string object_name, std::string attribut
e_name, char &data)
{ readAtomicAttribute(object_name,attribute_name,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, signed char &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, signed short &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, signed int &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, signed long &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, signed long long &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, unsigned char &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, unsigned short &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, unsigned int &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, unsigned long &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, unsigned long long &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, float &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, double &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, long double &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
inline void readAttribute(std::string datasetName, std::string attribut
eName, std::string &data)
{ readAtomicAttribute(datasetName,attributeName,data); }
// Writing data
/** \brief Write multi arrays.
Chunks can be activated by setting
\code iChunkSize = size; //size \> 0
\endcode .
The chunks will be hypercubes with edge length size.
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 be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<unsigned int N, class T>
inline void write(std::string datasetName, const MultiArrayView<N, T, U
nstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize;
}
write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize
, compression);
}
/** \brief Write multi arrays.
Chunks can be activated by providing a MultiArrayShape as chunkSize.
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 be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<unsigned int N, class T>
inline void write(std::string datasetName, const MultiArrayView<N, T, U
nstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int
compression = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize
, compression);
}
/** \brief Write a multi array into a larger volume.
blockOffset determines the position, where array is written.
Chunks can be activated by providing a MultiArrayShape as chunkSize.
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 be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<unsigned int N, class T>
inline void writeBlock(std::string datasetName, typename MultiArrayShap
e<N>::type blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & arr
ay)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<
T>(), 1);
}
// non-scalar (TinyVector) and unstrided multi arrays
template<unsigned int N, class T, int SIZE>
inline void write(std::string datasetName, const MultiArrayView<N, Tiny
Vector<T, SIZE>, UnstridedArrayTag> & array, int iChunkSize = 0, int compre
ssion = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize;
}
write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkS
ize, compression);
}
template<unsigned int N, class T, int SIZE>
inline void write(std::string datasetName, const MultiArrayView<N, Tiny
Vector<T, SIZE>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::t
ype chunkSize, int compression = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkS
ize, compression);
}
/** \brief Write array vectors.
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 be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<class T>
void write(const std::string & datasetName,
const ArrayVectorView<T> & array,
int compression = 0)
{
// convert to a (trivial) MultiArrayView and forward.
MultiArrayShape<1>::type shape(array.size());
const MultiArrayView<1, T> m_array(shape, const_cast<T*>(array.data
()));
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
template<unsigned int N, class T>
inline void write(std::string datasetName, const MultiArrayView<N, RGBV
alue<T>, UnstridedArrayTag> & array, int iChunkSize = 0, int compression =
0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize;
}
write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize
, compression);
}
template<unsigned int N, class T>
inline void write(std::string datasetName, const MultiArrayView<N, RGBV
alue<T>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chun
kSize, int compression = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
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.
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, 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 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 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 short data) { write
Atomic(datasetName,data); }
inline void write(std::string datasetName, unsigned int data) { writeAt
omic(datasetName,data); }
inline void write(std::string datasetName, unsigned long data) { writeA
tomic(datasetName,data); }
inline void write(std::string datasetName, unsigned long long data) { w
riteAtomic(datasetName,data); }
inline void write(std::string datasetName, float data) { writeAtomic(da
tasetName,data); }
inline void write(std::string datasetName, double data) { writeAtomic(d
atasetName,data); }
inline void write(std::string datasetName, long double data) { writeAto
mic(datasetName,data); }
inline void write(std::string datasetName, const char* data) { writeAto
mic(datasetName,data); }
inline void write(std::string datasetName, std::string const & data) {
writeAtomic(datasetName,data.c_str()); }
// Reading data
/** \brief Read data into a multi array.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<unsigned int N, class T>
inline void read(std::string datasetName, MultiArrayView<N, T, Unstride
dArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
read_(datasetName, array, detail::getH5DataType<T>(), 1);
}
/** \brief Read data into a MultiArray. Resize MultiArray to the correc
t size.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<unsigned int N, class T>
inline void readAndResize(std::string datasetName, MultiArray<N, T> & a
rray)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
// get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
hssize_t dimensions = getDatasetDimensions(datasetName);
// check if dimensions are correct
vigra_precondition((N == MultiArrayIndex(dimensions)), // 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.");
typename MultiArrayShape<N>::type shape;
for(int k=0; k< MultiArrayIndex(dimensions); ++k) {
shape[k] = MultiArrayIndex(dimshape[k]);
}
// reshape target MultiArray
array.reshape(shape);
read_(datasetName, array, detail::getH5DataType<T>(), 1);
}
/** \brief Read data into an array vector.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<class T>
inline void read(const std::string & datasetName, ArrayVectorView<T> &
array)
{
// convert to a (trivial) MultiArrayView and forward.
MultiArrayShape<1>::type shape(array.size());
MultiArrayView<1, T> m_array(shape, (array.data()));
read(datasetName, m_array);
}
/** \brief Read data into an array vector. Resize the array vector to t
he correct size.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<class T>
inline void readAndResize(std::string datasetName,
ArrayVector<T> & array)
{
// make dataset name clean
datasetName = get_absolute_path(datasetName);
// get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
hssize_t dimensions = getDatasetDimensions(datasetName);
// check if dimensions are correct
vigra_precondition((1 == MultiArrayIndex(dimensions)),
"HDF5File::readAndResize(): Array dimension disagrees with Data
set dimension must equal one for vigra::ArrayVector.");
// resize target array vector
array.resize((typename ArrayVector<T>::size_type)dimshape[0]);
// convert to a (trivial) MultiArrayView and forward.
MultiArrayShape<1>::type shape(array.size());
MultiArrayView<1, T> m_array(shape, (array.data()));
read_(datasetName, m_array, detail::getH5DataType<T>(), 1);
}
/** \brief Read a block of data into a multi array.
This function allows to read a small block out of a larger volume sto
red
in an HDF5 dataset.
blockOffset determines the position of the block.
blockSize determines the size in each dimension of the block.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
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, T, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
readBlock_(datasetName, blockOffset, blockShape, array, detail::get
H5DataType<T>(), 1);
}
// non-scalar (TinyVector) and unstrided target MultiArrayView
template<unsigned int N, class T, int SIZE>
inline void read(std::string datasetName, MultiArrayView<N, TinyVector<
T, SIZE>, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
}
// non-scalar (TinyVector) MultiArray
template<unsigned int N, class T, int SIZE>
inline void readAndResize(std::string datasetName, MultiArray<N, TinyVe
ctor<T, SIZE> > & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
// get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
hssize_t dimensions = getDatasetDimensions(datasetName);
// check if dimensions are correct
vigra_precondition(((N+1) == MultiArrayIndex(dimensions)), // the
object in the HDF5 file may have one additional dimension which we then int
erpret as the pixel type bands
"HDF5File::readAndResize(): Array dimension disagrees with data
set dimension.");
typename MultiArrayShape<N>::type shape;
for(int k=1; k< MultiArrayIndex(dimensions); ++k) {
shape[k-1] = MultiArrayIndex(dimshape[k]);
}
// reshape target MultiArray
array.reshape(shape);
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
template<unsigned int N, class T>
inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T>
, UnstridedArrayTag> & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
read_(datasetName, array, detail::getH5DataType<T>(), 3);
}
// non-scalar (RGBValue) MultiArray
template<unsigned int N, class T>
inline void readAndResize(std::string datasetName, MultiArray<N, RGBVal
ue<T> > & array)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
// get dataset dimension
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
hssize_t dimensions = getDatasetDimensions(datasetName);
// check if dimensions are correct
vigra_precondition(((N+1) == MultiArrayIndex(dimensions)), // the
object in the HDF5 file may have one additional dimension which we then int
erpret as the pixel type bands
"HDF5File::readAndResize(): Array dimension disagrees with data
set dimension.");
typename MultiArrayShape<N>::type shape;
for(int k=1; k< MultiArrayIndex(dimensions); ++k) {
shape[k-1] = MultiArrayIndex(dimshape[k]);
}
// reshape target MultiArray
array.reshape(shape);
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.
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, 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 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 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 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 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, float &data) { readAtomic(dat
asetName,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, std::string &data) { readAtom
ic(datasetName,data); }
/** \brief Create a new dataset.
This function can be used to create a dataset filled with a default v
alue,
for example before writing data into it using \ref writeBlock().
Attention: only atomic datatypes are provided. For spectral data, add
an
dimension (case RGB: add one dimension of size 3).
shape determines the dimension and the size of the dataset.
Chunks can be activated by providing a MultiArrayShape as chunkSize.
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 be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<unsigned int N, class T>
inline void createDataset(std::string datasetName, typename MultiArrayS
hape<N>::type shape, T init = T(), int iChunkSize = 0, int compressionParam
eter = 0)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<N>::type chunkSize;
for(int i = 0; i < N; i++){
chunkSize[i] = iChunkSize;
}
createDataset<N,T>(datasetName, shape, init, chunkSize, compression
Parameter);
}
template<unsigned int N, class T>
inline void createDataset(std::string datasetName, typename MultiArrayS
hape<N>::type shape, T init, typename MultiArrayShape<N>::type chunkSize, i
nt 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
*/
inline void flushToDisk()
{
H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
}
private:
/* Simple extension of std::string for splitting into two parts
*
* Strings (in particular: file/dataset paths) will be split into two
* parts. The split is made at the last occurrence of the delimiter.
*
* For example, "/path/to/some/file" will be split (delimiter = "/") i
nto
* first() = "/path/to/some" and last() = "file".
*/
class SplitString: public std::string {
public:
SplitString(std::string &sstring): std::string(sstring) {};
// return the part of the string before the delimiter
std::string first(char delimiter = '/')
{
size_t last = find_last_of(delimiter);
if(last == std::string::npos) // delimiter not found --> no fir
st
return "";
return std::string(begin(), begin()+last+1);
}
// return the part of the string after the delimiter
std::string last(char delimiter = '/')
{
size_t last = find_last_of(delimiter);
if(last == std::string::npos) // delimiter not found --> only l
ast
return std::string(*this);
return std::string(begin()+last+1, end());
}
};
public:
/** \brief takes any path and converts it into an absolute path
in the current file.
Elements like "." and ".." are treated as expected.
Links are not supported or resolved.
*/
inline std::string get_absolute_path(std::string path) {
// check for empty input or "." and return the current folder
if(path.length() == 0 || path == "."){
return currentGroupName_();
}
std::string str;
// convert to absolute path
if(relativePath_(path)){
std::string cname = currentGroupName_();
if (cname == "/")
str = currentGroupName_()+path;
else
str = currentGroupName_()+"/"+path;
}else{
str = path;
}
// cut out "./"
std::string::size_type startpos = 0;
while(str.find(std::string("./"), startpos) != std::string::npos){
std::string::size_type pos = str.find(std::string("./"), startp
os);
startpos = pos+1;
// only cut if "./" is not part of "../" (see below)
if(str.substr(pos-1,3) != "../"){
// cut out part of the string
str = str.substr(0,pos) + str.substr(pos+2,str.length()-pos
-2);
startpos = pos;
}
}
// cut out pairs of "bla/../"
while(str.find(std::string("..")) != std::string::npos){
std::string::size_type pos = str.find(std::string(".."));
// find first slash after ".."
std::string::size_type end = str.find("/",pos);
if(end != std::string::npos){
// also include slash
end++;
}else{
// no "/" after ".." --> this is a group, add a "/"
str = str + "/";
end = str.length();
}
// find first slash before ".."
std::string::size_type prev_slash = str.rfind("/",pos);
// if the root slash is the first before ".." --> Error
vigra_invariant(prev_slash != 0 && prev_slash != std::string::n
pos,
"Error parsing path: "+str);
// find second slash before ".."
std::string::size_type begin = str.rfind("/",prev_slash-1);
// cut out part of the string
str = str.substr(0,begin+1) + str.substr(end,str.length()-end);
}
return str;
}
private:
/* checks if the given path is a relative path.
*/
inline bool relativePath_(std::string & path)
{
std::string::size_type pos = path.find('/') ;
if(pos == 0)
return false;
return true;
}
/* return the name of the current group
*/
inline std::string currentGroupName_()
{
int len = H5Iget_name(cGroupHandle_,NULL,1000);
ArrayVector<char> name (len+1,0);
H5Iget_name(cGroupHandle_,name.begin(),len+1);
return std::string(name.begin());
}
/* return the name of the current file
*/
inline std::string fileName_()
{
int len = H5Fget_name(fileHandle_,NULL,1000);
ArrayVector<char> name (len+1,0);
H5Fget_name(fileHandle_,name.begin(),len+1);
return std::string(name.begin());
}
/* create an empty file and open is
*/
inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
{
// try to open file
FILE * pFile;
pFile = fopen ( filePath.c_str(), "r" );
hid_t fileId;
// check if opening was successful (= file exists)
if ( pFile == NULL )
{
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
{
fclose(pFile);
std::remove(filePath.c_str());
fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT
, H5P_DEFAULT);
}
return fileId;
}
/* open a group and subgroups. Create if necessary.
*/
inline hid_t openCreateGroup_(std::string groupName)
{
// make groupName clean
groupName = get_absolute_path(groupName);
// open root group
hid_t parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT);
if(groupName == "/")
{
return parent;
}
// remove leading /
groupName = std::string(groupName.begin()+1, groupName.end());
// check if the groupName has finishing slash
if( groupName.size() != 0 && *groupName.rbegin() != '/')
{
groupName = groupName + '/';
}
//open or create subgroups one by one
std::string::size_type begin = 0, end = groupName.find('/');
int ii = 0;
while (end != std::string::npos)
{
std::string group(groupName.begin()+begin, groupName.begin()+en
d);
hid_t prevParent = parent;
if(H5LTfind_dataset(parent, group.c_str()) == 0)
{
parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT,
H5P_DEFAULT, H5P_DEFAULT);
} else {
parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
}
if(ii != 0)
{
H5Gclose(prevParent);
}
if(parent < 0)
{
return parent;
}
++ii;
begin = end + 1;
end = groupName.find('/', begin);
}
return parent;
}
/* delete a dataset by unlinking it from the file structure. This does
not
delete the data!
*/
inline void deleteDataset_(hid_t parent, std::string datasetName)
{
// delete existing data and create new dataset
if(H5LTfind_dataset(parent, datasetName.c_str()))
{
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
if(H5Gunlink(parent, datasetName.c_str()) < 0)
{
vigra_postcondition(false, "HDF5File::deleteDataset_(): Una
ble to delete existing data.");
}
#else
if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0)
{
vigra_postcondition(false, "HDF5File::deleteDataset_(): Una
ble to delete existing data.");
}
#endif
}
}
/* get the handle of a dataset specified by a string
*/
inline hid_t getDatasetHandle_(std::string datasetName)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
std::string groupname = SplitString(datasetName).first();
std::string setname = SplitString(datasetName).last();
if (H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) <= 0)
{
std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << data
setName << "' does not exist.\n";
return -1;
}
//Open parent group
hid_t groupHandle = openCreateGroup_(groupname);
hid_t datasetHandle = H5Dopen(groupHandle, setname.c_str(), H5P_DEF
AULT);
if(groupHandle != cGroupHandle_)
{
H5Gclose(groupHandle);
}
//return dataset handle
return datasetHandle;
}
/* get the type of an object specified by a string
*/
H5O_type_t get_object_type_(std::string name)
{
name = get_absolute_path(name);
std::string group_name = SplitString(name).first();
std::string object_name = SplitString(name).last();
if (!object_name.size())
return H5O_TYPE_GROUP;
htri_t exists = H5Lexists(fileHandle_, name.c_str(), H5P_DEFAULT);
vigra_precondition(exists > 0, "HDF5File::get_object_type_(): "
"object \"" + name + "\" "
"not found.");
// open parent group
hid_t group_handle = openCreateGroup_(group_name);
H5O_type_t h5_type = HDF5_get_type(group_handle, name.c_str());
if (group_handle != cGroupHandle_)
{
H5Gclose(group_handle);
}
return h5_type;
}
/* low-level write function to write vigra MultiArray data as an attrib
ute
*/
template<unsigned int N, class T>
void write_attribute_(std::string name, const std::string & attribute_n
ame,
const MultiArrayView<N, T, UnstridedArrayTag> & a
rray,
const hid_t datatype, const int numBandsOfType)
{
// shape of the array. Add one dimension, if array contains non-sca
lars.
ArrayVector<hsize_t> shape(N + (numBandsOfType > 1),0);
for(unsigned int i = 0; i < N; i++){
shape[N-1-i] = array.shape(i); // reverse order
}
if(numBandsOfType > 1)
shape[N] = numBandsOfType;
HDF5Handle dataspace(H5Screate_simple(N + (numBandsOfType > 1),
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
This function allows to write data of atomic datatypes (int, long, do
uble)
as an attribute in the HDF5 file. So it is not necessary to create a
MultiArray
of size 1 to write a single number.
*/
template<class T>
inline void writeAtomicAttribute(std::string datasetName, std::string a
ttributeName, const T data)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<1>::type chunkSize;
chunkSize[0] = 0;
MultiArray<1,T> array(MultiArrayShape<1>::type(1));
array[0] = data;
write_attribute_(datasetName, attributeName, array, detail::getH5Da
taType<T>(), 1);
}
/* low-level read function to write vigra MultiArray data from attribut
es
*/
template<unsigned int N, class T>
inline void read_attribute_(std::string datasetName, std::string attrib
uteName, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatyp
e, 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> shape_inv(dims);
H5Sget_simple_extent_dims(attr_dataspace_handle, shape_inv.data(),
NULL);
// invert the dimensions to guarantee c-order
ArrayVector<hsize_t> dimshape(dims);
for(ArrayVector<hsize_t>::size_type i=0; i<shape_inv.size(); i++) {
dimshape[i] = shape_inv[dims-1-i];
}
int offset = (numBandsOfType > 1);
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)), mes
sage);
typename MultiArrayShape<N>::type shape;
for(int k=offset; k< MultiArrayIndex(dims); ++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.
This functions allows to read a single value attribute of atomic data
type (int, long, double)
from the HDF5 file. So it is not necessary to create a MultiArray
of size 1 to read a single number.
*/
template<class T>
inline void readAtomicAttribute(std::string datasetName, std::string at
tributeName, T & data)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
MultiArray<1,T> array(MultiArrayShape<1>::type(1));
read_attribute_(datasetName, attributeName, array, detail::getH5Dat
aType<T>(), 1);
data = array[0];
}
inline void readAtomicAttribute(std::string datasetName, std::string at
tributeName, std::string & data)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
MultiArray<1,const char *> array(MultiArrayShape<1>::type(1));
read_attribute_(datasetName, attributeName, array, detail::getH5Dat
aType<const char *>(), 1);
data = std::string(array[0]);
}
/* low-level write function to write vigra unstrided MultiArray data
*/
template<unsigned int N, class T>
inline void write_(std::string &datasetName, const MultiArrayView<N, T,
UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType
, typename MultiArrayShape<N>::type &chunkSize, 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(N + (numBandsOfType > 1),0);
for(unsigned int i = 0; i < N; i++){
shape[N-1-i] = array.shape(i); // reverse order
}
if(numBandsOfType > 1)
shape[N] = numBandsOfType;
HDF5Handle dataspace ( H5Screate_simple(N + (numBandsOfType > 1), s
hape.begin(), NULL), &H5Sclose, "HDF5File::write(): Can not create dataspac
e.");
// create and open group:
std::string errorMessage ("HDF5File::write(): can not create group
'" + groupname + "'.");
hid_t groupHandle = openCreateGroup_(groupname);
if(groupHandle <= 0)
{
std::cerr << errorMessage << "\n";
}
// delete dataset, if it already exists
deleteDataset_(groupHandle, setname.c_str());
// set up properties list
HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5F
ile::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(N + (numBandsOfType > 1),0);
for(unsigned int i = 0; i<N; i++)
{
cSize[i] = chunkSize[N-1-i];
}
if(numBandsOfType > 1)
cSize[N] = numBandsOfType;
H5Pset_chunk (plist, N + (numBandsOfType > 1), cSize.begin());
}
// enable compression
if(compressionParameter > 0)
{
H5Pset_deflate(plist, compressionParameter);
}
// create dataset
HDF5Handle datasetHandle (H5Dcreate(groupHandle, setname.c_str(), d
atatype, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT), &H5Dclose, "HDF5File::
write(): Can not create 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.");
if(groupHandle != cGroupHandle_)
{
H5Gclose(groupHandle);
}
}
/* Write single value as dataset.
This functions allows to write data of atomic datatypes (int, long, d
ouble)
as a dataset in the HDF5 file. So it is not necessary to create a Mul
tiArray
of size 1 to write a single number.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<class T>
inline void writeAtomic(std::string datasetName, const T data)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
typename MultiArrayShape<1>::type chunkSize;
chunkSize[0] = 0;
MultiArray<1,T> array(MultiArrayShape<1>::type(1));
array[0] = data;
write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize
,0);
}
/* low-level read function to read vigra unstrided MultiArray data
*/
template<unsigned int N, class T>
inline void read_(std::string datasetName, MultiArrayView<N, T, Unstrid
edArrayTag> array, const hid_t datatype, const int numBandsOfType)
{
//Prepare to read without using HDF5ImportInfo
ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
hssize_t dimensions = getDatasetDimensions(datasetName);
std::string errorMessage ("HDF5File::read(): Unable to open dataset
'" + datasetName + "'.");
HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose
, errorMessage.c_str());
int offset = (numBandsOfType > 1);
vigra_precondition(( (N + offset ) == MultiArrayIndex(dimensions))
, // the object in the HDF5 file may have one additional dimension which we
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< MultiArrayIndex(dimensions); ++k) {
shape[k-offset] = MultiArrayIndex(dimshape[k]);
}
vigra_precondition(shape == array.shape(),
"HDF5File::read(): Array shape disagrees with da
taset shape.");
// 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.
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 MultiArray
of size 1 to read a single number.
If the first character of datasetName is a "/", the path will be inte
rpreted as absolute path,
otherwise it will be interpreted as path relative to the current grou
p.
*/
template<class T>
inline void readAtomic(std::string datasetName, T & data)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
MultiArray<1,T> array(MultiArrayShape<1>::type(1));
read_(datasetName, array, detail::getH5DataType<T>(), 1);
data = array[0];
}
inline void readAtomic(std::string datasetName, std::string & data)
{
// make datasetName clean
datasetName = get_absolute_path(datasetName);
MultiArray<1,const char *> array(MultiArrayShape<1>::type(1));
read_(datasetName, array, detail::getH5DataType<const char *>(), 1)
;
data = std::string(array[0]);
}
/* low-level write function to write vigra unstrided MultiArray data in
to a sub-block of a dataset
*/
template<unsigned int N, class T>
inline void writeBlock_(std::string datasetName, typename MultiArraySha
pe<N>::type &blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & a
rray, const hid_t datatype, const int numBandsOfType)
{
// open dataset if it exists
std::string errorMessage = "HDF5File::writeBlock(): Error opening d
ataset '" + datasetName + "'.";
HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose
, errorMessage.c_str());
// hyperslab parameters for position, size, ...
hsize_t boffset [N];
hsize_t bshape [N];
hsize_t bones [N];
for(int i = 0; i < N; i++){
boffset[i] = blockOffset[N-1-i];
bshape[i] = array.size(N-1-i);
bones[i] = 1;
}
// create a target dataspace in memory with the shape of the desire
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
HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"
Unable to create target dataspace");
H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones
, bones, bshape);
// Write the data to the HDF5 dataset as is
H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle
, H5P_DEFAULT, array.data()); // .data() possible since void pointer!
}
/* low-level read function to read vigra unstrided MultiArray data from
a sub-block of a dataset
*/
template<unsigned int N, class T>
inline void readBlock_(std::string datasetName, typename MultiArrayShap
e<N>::type &blockOffset, typename MultiArrayShape<N>::type &blockShape, Mul
tiArrayView<N, T, UnstridedArrayTag> &array, const hid_t datatype, const in
t numBandsOfType)
{
//Prepare to read without using HDF5ImportInfo
//ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName) ;
hssize_t dimensions = getDatasetDimensions(datasetName);
std::string errorMessage ("HDF5File::readBlock(): Unable to open da
taset '" + datasetName + "'.");
HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose
, errorMessage.c_str());
int offset = (numBandsOfType > 1);
vigra_precondition(( (N + offset ) == MultiArrayIndex(dimensions))
, // the object in the HDF5 file may have one additional dimension which we
then interpret as the pixel type bands
"readHDF5_block(): Array dimension disagrees with data dimensio
n.");
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++){
// 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];
bones[i] = 1;
}
// create a target dataspace in memory with the shape of the desire
d block
HDF5Handle memspace_handle (H5Screate_simple(N,bshape,NULL),&H5Sclo
se,"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, bones
, bones, bshape);
// now read the data
H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle,
H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
}
}; /* class HDF5File */
namespace detail { namespace detail {
template <class Shape> template <class Shape>
inline void inline void
selectHyperslabs(HDF5Handle & mid1, HDF5Handle & mid2, Shape const & shape, int & counter, const int elements, const int numBandsOfType) selectHyperslabs(HDF5Handle & mid1, HDF5Handle & mid2, Shape const & shape, int & counter, const int elements, const int numBandsOfType)
{ {
// select hyperslab in HDF5 file // select hyperslab in HDF5 file
hsize_t shapeHDF5[2]; hsize_t shapeHDF5[2];
shapeHDF5[0] = 1; shapeHDF5[0] = 1;
shapeHDF5[1] = elements; shapeHDF5[1] = elements;
skipping to change at line 447 skipping to change at line 2152
template <class DestIterator, class Shape, class T> template <class DestIterator, class Shape, class T>
inline void inline void
readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, c onst hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elem ents, const int numBandsOfType, MetaInt<0>) readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, c onst hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elem ents, const int numBandsOfType, MetaInt<0>)
{ {
HDF5Handle mid1, mid2; HDF5Handle mid1, mid2;
// select hyperslabs // select hyperslabs
selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType); selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
// read from hdf5 // read from hdf5
H5Dread(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data()); herr_t read_status = H5Dread(dataset_id, datatype, mid2, mid1, H5P_DEFA
ULT, buffer.data());
vigra_precondition(read_status >= 0, "readHDF5Impl(): read from dataset
failed.");
// increase counter // increase counter
counter++; counter++;
//std::cout << "numBandsOfType: " << numBandsOfType << std::endl; //std::cout << "numBandsOfType: " << numBandsOfType << std::endl;
DestIterator dend = d + shape[0]; DestIterator dend = d + shape[0];
int k = 0; int k = 0;
for(; d < dend; ++d, k++) for(; d < dend; ++d, k++)
{ {
*d = buffer[k]; *d = buffer[k];
//std::cout << buffer[k] << "| "; //std::cout << buffer[k] << "| ";
} }
} }
skipping to change at line 476 skipping to change at line 2182
{ {
DestIterator dend = d + shape[N]; DestIterator dend = d + shape[N];
for(; d < dend; ++d) for(; d < dend; ++d)
{ {
readHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counte r, elements, numBandsOfType, MetaInt<N-1>()); readHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counte r, elements, numBandsOfType, MetaInt<N-1>());
} }
} }
} // namespace detail } // namespace detail
/** \brief Read the data specified by the given \ref vigra::HDF5ImportI nfo 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
and \ref vigra::TinyVector) are recognized and handled correctly. and \ref vigra::TinyVector) are recognized and handled correctly.
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template<unsigned int N, class T, class StrideTag> template<unsigned int N, class T, class StrideTag>
void void
readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag > array); readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag > array);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex .hxx</a>\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
HDF5ImportInfo info(filename, dataset_name); HDF5ImportInfo info(filename, dataset_name);
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 // scalar and unstrided target multi array
template<unsigned int N, class T> template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Unstr idedArrayTag> array) // scalar inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Unstr idedArrayTag> array) // scalar
{ {
readHDF5(info, array, detail::getH5DataType<T>(), 1); readHDF5(info, array, detail::getH5DataType<T>(), 1);
} }
// non-scalar (TinyVector) and unstrided target multi array // non-scalar (TinyVector) and unstrided target multi array
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVect or<T, SIZE>, UnstridedArrayTag> array) inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVect or<T, SIZE>, UnstridedArrayTag> array)
{ {
readHDF5(info, array, detail::getH5DataType<T>(), SIZE); readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
} }
// non-scalar (RGBValue) and unstrided target multi array // non-scalar (RGBValue) and unstrided target multi array
template<unsigned int N, class T> template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue <T>, UnstridedArrayTag> array) inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue <T>, UnstridedArrayTag> array)
{ {
readHDF5(info, array, detail::getH5DataType<T>(), 3); readHDF5(info, array, detail::getH5DataType<T>(), 3);
} }
// unstrided target multi array // unstrided target multi array
template<unsigned int N, class T> template<unsigned int N, class T>
void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArr ayTag> array, const hid_t datatype, const int numBandsOfType) void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArr ayTag> array, const hid_t datatype, const int numBandsOfType)
{ {
int offset = (numBandsOfType > 1); int offset = (numBandsOfType > 1);
//std::cout << "offset: " << offset << ", N: " << N << ", dims: " << //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << in
info.numDimensions() << std::endl; fo.numDimensions() << std::endl;
vigra_precondition(( (N + offset ) == info.numDimensions()), // the vigra_precondition(( (N + offset ) == info.numDimensions()), // the obj
object in the HDF5 file may have one additional dimension which we then int ect in the HDF5 file may have one additional dimension which we then interp
erpret as the pixel type bands ret as the pixel type bands
"readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimen sions()."); "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimen sions().");
typename MultiArrayShape<N>::type shape; typename MultiArrayShape<N>::type shape;
for(int k=offset; k<info.numDimensions(); ++k) { for(int k=offset; k<info.numDimensions(); ++k) {
shape[k-offset] = info.shapeOfDimension(k); shape[k-offset] = info.shapeOfDimension(k);
} }
vigra_precondition(shape == array.shape(), vigra_precondition(shape == array.shape(),
"readHDF5(): Array shape disagrees with HDF5ImportInfo."); "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
// simply read in the data as is // simply read in the data as is
H5Dread( info.getDatasetHandle(), datatype, H5S_ALL, H5S_ALL, H5P_DE H5Dread( info.getDatasetHandle(), datatype, H5S_ALL, H5S_ALL, H5P_DEFAU
FAULT, array.data() ); // .data() possible since void pointer! LT, array.data() ); // .data() possible since void pointer!
} }
// scalar and strided target multi array // scalar and strided target multi array
template<unsigned int N, class T> template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Strid edArrayTag> array) // scalar inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, Strid edArrayTag> array) // scalar
{ {
readHDF5(info, array, detail::getH5DataType<T>(), 1); readHDF5(info, array, detail::getH5DataType<T>(), 1);
} }
// non-scalar (TinyVector) and strided target multi array // non-scalar (TinyVector) and strided target multi array
template<unsigned int N, class T, int SIZE> template<unsigned int N, class T, int SIZE>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVect or<T, SIZE>, StridedArrayTag> array) inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVect or<T, SIZE>, StridedArrayTag> array)
{ {
readHDF5(info, array, detail::getH5DataType<T>(), SIZE); readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
} }
// non-scalar (RGBValue) and strided target multi array // non-scalar (RGBValue) and strided target multi array
template<unsigned int N, class T> template<unsigned int N, class T>
inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue <T>, StridedArrayTag> array) inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue <T>, StridedArrayTag> array)
{ {
readHDF5(info, array, detail::getH5DataType<T>(), 3); readHDF5(info, array, detail::getH5DataType<T>(), 3);
} }
// strided target multi array // strided target multi array
template<unsigned int N, class T> template<unsigned int N, class T>
void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArray Tag> array, const hid_t datatype, const int numBandsOfType) void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArray Tag> array, const hid_t datatype, const int numBandsOfType)
{ {
int offset = (numBandsOfType > 1); int offset = (numBandsOfType > 1);
//std::cout << "offset: " << offset << ", N: " << N << ", dims: " << //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << in
info.numDimensions() << std::endl; fo.numDimensions() << std::endl;
vigra_precondition(( (N + offset ) == info.numDimensions()), // the vigra_precondition(( (N + offset ) == info.numDimensions()), // the obj
object in the HDF5 file may have one additional dimension which we then int ect in the HDF5 file may have one additional dimension which we then interp
erpret as the pixel type bands ret as the pixel type bands
"readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimen sions()."); "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimen sions().");
typename MultiArrayShape<N>::type shape; typename MultiArrayShape<N>::type shape;
for(int k=offset; k<info.numDimensions(); ++k) { for(int k=offset; k<info.numDimensions(); ++k) {
shape[k-offset] = info.shapeOfDimension(k); shape[k-offset] = info.shapeOfDimension(k);
} }
vigra_precondition(shape == array.shape(), vigra_precondition(shape == array.shape(),
"readHDF5(): Array shape disagrees with HDF5ImportInfo."); "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
//Get the data //Get the data
int counter = 0; int counter = 0;
int elements = numBandsOfType; int elements = numBandsOfType;
for(unsigned int i=0;i<N;++i) for(unsigned int i=0;i<N;++i)
elements *= shape[i]; elements *= shape[i];
ArrayVector<T> buffer(shape[0]); ArrayVector<T> buffer(shape[0]);
detail::readHDF5Impl(array.traverser_begin(), shape, info.getDatasetHan dle(), datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt< N-1>()); detail::readHDF5Impl(array.traverser_begin(), shape, info.getDatasetHan dle(), datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt< N-1>());
} }
skipping to change at line 664 skipping to change at line 2370
return parent; return parent;
} }
inline void deleteDataset(hid_t parent, std::string dataset_name) inline void deleteDataset(hid_t parent, std::string dataset_name)
{ {
// delete existing data and create new dataset // delete existing data and create new dataset
if(H5LTfind_dataset(parent, dataset_name.c_str())) if(H5LTfind_dataset(parent, dataset_name.c_str()))
{ {
//std::cout << "dataset already exists" << std::endl; //std::cout << "dataset already exists" << std::endl;
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6) #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
if(H5Gunlink(parent, dataset_name.c_str()) < 0) if(H5Gunlink(parent, dataset_name.c_str()) < 0)
{ {
vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data."); vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data.");
} }
#else #else
if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0 ) if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0)
{ {
vigra_postcondition(false, "createDataset(): Unable to delete e xisting data."); vigra_postcondition(false, "createDataset(): Unable to delete e xisting data.");
} }
#endif #endif
} }
} }
inline hid_t createFile(std::string filePath, bool append_ = true) inline hid_t createFile(std::string filePath, bool append_ = true)
{ {
FILE * pFile; FILE * pFile;
skipping to change at line 730 skipping to change at line 2436
} }
// create all groups // create all groups
HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose, HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose,
"createDataset(): Unable to create and open group. gen eric v"); "createDataset(): Unable to create and open group. gen eric v");
// delete the dataset if it already exists // delete the dataset if it already exists
deleteDataset(group, data_set_name); deleteDataset(group, data_set_name);
// create dataspace // create dataspace
// add an extra dimension in case that the data is non-scalar // add an extra dimension in case that the data is non-scalar
HDF5Handle dataspace_handle; HDF5Handle dataspace_handle;
if(numBandsOfType > 1) { if(numBandsOfType > 1) {
// invert dimensions to guarantee c-order // invert dimensions to guarantee c-order
hsize_t shape_inv[N+1]; // one additional dimension for pixe hsize_t shape_inv[N+1]; // one additional dimension for pixel type
l type channel(s) channel(s)
for(unsigned int k=0; k<N; ++k) { for(unsigned int k=0; k<N; ++k) {
shape_inv[N-1-k] = array.shape(k); // the channels shape_inv[N-1-k] = array.shape(k); // the channels (eg of an R
(eg of an RGB image) are represented by the first dimension (before inversi GB image) are represented by the first dimension (before inversion)
on) //std::cout << shape_inv[N-k] << " (" << N << ")";
//std::cout << shape_inv[N-k] << " (" << N << ")"; }
} shape_inv[N] = numBandsOfType;
shape_inv[N] = numBandsOfType;
// create dataspace // create dataspace
dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_in dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_inv, NULL
v, NULL), ),
&H5S &H5Sclose, "createDataset(): unable to
close, "createDataset(): unable to create dataspace for non-scalar data."); create dataspace for non-scalar data.");
} else { } else {
// invert dimensions to guarantee c-order // invert dimensions to guarantee c-order
hsize_t shape_inv[N]; hsize_t shape_inv[N];
for(unsigned int k=0; k<N; ++k) for(unsigned int k=0; k<N; ++k)
shape_inv[N-1-k] = array.shape(k); shape_inv[N-1-k] = array.shape(k);
// create dataspace // create dataspace
dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
NULL), &H5Sclose, "createDataset(): unable to
&H5S create dataspace for scalar data.");
close, "createDataset(): unable to create dataspace for scalar data."); }
}
//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 { namespace detail {
template <class DestIterator, class Shape, class T> template <class DestIterator, class Shape, class T>
inline void 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>) 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 ]; DestIterator dend = d + (typename DestIterator::difference_type)shape[0 ];
int k = 0; int k = 0;
//std::cout << "new:" << std::endl; //std::cout << "new:" << std::endl;
for(; d < dend; ++d, k++) for(; d < dend; ++d, k++)
{ {
buffer[k] = *d; buffer[k] = *d;
//std::cout << buffer[k] << " "; //std::cout << buffer[k] << " ";
} }
//std::cout << std::endl; //std::cout << std::endl;
HDF5Handle mid1, mid2; HDF5Handle mid1, mid2;
// select hyperslabs // select hyperslabs
selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType); selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
// write to hdf5 // write to hdf5
H5Dwrite(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data()); H5Dwrite(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
// increase counter // increase counter
counter++; counter++;
} }
template <class DestIterator, class Shape, class T, int N> template <class DestIterator, class Shape, class T, int N>
void 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>) 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_t DestIterator dend = d + (typename DestIterator::difference_type)sha
ype)shape[N]; pe[N];
for(; d < dend; ++d) for(; d < dend; ++d)
{ {
writeHDF5Impl(d.begin(), shape, dataset_id, datatype writeHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, c
, buffer, counter, elements, numBandsOfType, MetaInt<N-1>()); ounter, elements, numBandsOfType, MetaInt<N-1>());
} }
} }
} // namespace detail } // 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 and \ref vigra::TinyVector) are recognized a nd handled correctly (i.e. \ref vigra::RGBValue and \ref vigra::TinyVector) are recognized a nd 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.
<b> Declaration:</b> <b> Declaration:</b>
skipping to change at line 826 skipping to change at line 2532
namespace vigra { namespace vigra {
template<unsigned int N, class T, class StrideTag> template<unsigned int N, class T, class StrideTag>
void void
writeHDF5(const char* filePath, const char* pathInFile, writeHDF5(const char* filePath, const char* pathInFile,
MultiArrayView<N, T, StrideTag>const & array); MultiArrayView<N, T, StrideTag>const & array);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex .hxx</a>\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
\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 // scalar and unstrided multi arrays
template<unsigned int N, class T> template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, T, UnstridedArrayTag> & array) // scalar inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, T, UnstridedArrayTag> & array) // scalar
{ {
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1 ); writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
} }
// 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>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array) inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
{ {
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), S IZE); writeHDF5(filePath, pathInFile, 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>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array) 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 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 // unstrided multi arrays
template<unsigned int N, class T> 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) 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 file_handle;
HDF5Handle dataset_handle; HDF5Handle dataset_handle;
createDataset(filePath, pathInFile, array, datatype, numBandsOfType, createDataset(filePath, pathInFile, array, datatype, numBandsOfType, fi
file_handle, dataset_handle); le_handle, dataset_handle);
// Write the data to the HDF5 dataset as is // Write the data to the HDF5 dataset as is
H5Dwrite( dataset_handle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, a rray.data()); // .data() possible since void pointer! H5Dwrite( dataset_handle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, arra y.data()); // .data() possible since void pointer!
H5Fflush(file_handle, H5F_SCOPE_GLOBAL); H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
} }
// scalar and strided multi arrays // scalar and strided multi arrays
template<unsigned int N, class T> template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, T, StridedArrayTag> & array) // scalar 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 ); writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
} }
// non-scalar (TinyVector) and strided multi arrays // non-scalar (TinyVector) and strided multi arrays
template<unsigned int N, class T, int SIZE> 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) 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>(), S IZE); writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE );
} }
// non-scalar (RGBValue) and strided multi arrays // non-scalar (RGBValue) and strided multi arrays
template<unsigned int N, class T> template<unsigned int N, class T>
inline void writeHDF5(const char* filePath, const char* pathInFile, const M ultiArrayView<N, RGBValue<T>, StridedArrayTag> & array) 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 writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
); }
// 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, FFTWComplex<T>, StridedArrayTag> & array)
{
writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 2);
} }
// strided multi arrays // strided multi arrays
template<unsigned int N, class T> 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) 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 file_handle;
HDF5Handle dataset_handle; HDF5Handle dataset_handle;
createDataset(filePath, pathInFile, array, datatype, numBandsOfType, createDataset(filePath, pathInFile, array, datatype, numBandsOfType, fi
file_handle, dataset_handle); le_handle, dataset_handle);
vigra::TinyVector<int,N> shape; vigra::TinyVector<int,N> shape;
vigra::TinyVector<int,N> stride; vigra::TinyVector<int,N> stride;
int elements = numBandsOfType; int elements = numBandsOfType;
for(unsigned int k=0; k<N; ++k) for(unsigned int k=0; k<N; ++k)
{ {
shape[k] = array.shape(k); shape[k] = array.shape(k);
stride[k] = array.stride(k); stride[k] = array.stride(k);
elements *= (int)shape[k]; elements *= (int)shape[k];
} }
int counter = 0; int counter = 0;
ArrayVector<T> buffer((int)array.shape(0)); ArrayVector<T> buffer((int)array.shape(0));
detail::writeHDF5Impl(array.traverser_begin(), shape, dataset_handle , datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>( )); detail::writeHDF5Impl(array.traverser_begin(), shape, dataset_handle, d atatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
H5Fflush(file_handle, H5F_SCOPE_GLOBAL); H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
} }
namespace detail namespace detail
{ {
struct MaxSizeFnc struct MaxSizeFnc
{ {
size_t size; size_t size;
MaxSizeFnc() MaxSizeFnc()
skipping to change at line 944 skipping to change at line 2664
in.size() : in.size() :
size; size;
} }
}; };
} }
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN
/** Write a numeric MultiArray as an attribute with name \a name /** Write a numeric MultiArray as an attribute with name \a name
of the dataset specified by the handle \a loc. of the dataset specified by the handle \a loc.
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex .hxx</a>\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template<size_t N, class T, class C> template<size_t N, class T, class C>
void writeHDF5Attr(hid_t loc, void writeHDF5Attr(hid_t loc,
const char* name, const char* name,
MultiArrayView<N, T, C> const & array) MultiArrayView<N, T, C> const & array)
{ {
if(H5Aexists(loc, name) > 0) if(H5Aexists(loc, name) > 0)
H5Adelete(loc, name); H5Adelete(loc, name);
skipping to change at line 980 skipping to change at line 2700
//copy data - since attributes are small - who cares! //copy data - since attributes are small - who cares!
ArrayVector<T> buffer; ArrayVector<T> buffer;
for(int ii = 0; ii < array.size(); ++ii) for(int ii = 0; ii < array.size(); ++ii)
buffer.push_back(array[ii]); buffer.push_back(array[ii]);
H5Awrite(attr, detail::getH5DataType<T>(), buffer.data()); H5Awrite(attr, detail::getH5DataType<T>(), buffer.data());
} }
/** Write a string MultiArray as an attribute with name \a name /** Write a string MultiArray as an attribute with name \a name
of the dataset specified by the handle \a loc. of the dataset specified by the handle \a loc.
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex .hxx</a>\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template<size_t N, class C> template<size_t N, class C>
void writeHDF5Attr(hid_t loc, void writeHDF5Attr(hid_t loc,
const char* name, const char* name,
MultiArrayView<N, std::string, C> const & array) MultiArrayView<N, std::string, C> const & array)
{ {
if(H5Aexists(loc, name) > 0) if(H5Aexists(loc, name) > 0)
H5Adelete(loc, name); H5Adelete(loc, name);
skipping to change at line 1026 skipping to change at line 2746
{ {
buf = buf + array[ii] buf = buf + array[ii]
+ std::string(max_size.size - array[ii].size(), ' '); + std::string(max_size.size - array[ii].size(), ' ');
} }
H5Awrite(attr, atype, buf.c_str()); H5Awrite(attr, atype, buf.c_str());
} }
/** Write a numeric ArrayVectorView as an attribute with name \a name /** Write a numeric ArrayVectorView as an attribute with name \a name
of the dataset specified by the handle \a loc. of the dataset specified by the handle \a loc.
<b>\#include</b> \<<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex .hxx</a>\><br> <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template<class T> template<class T>
inline void writeHDF5Attr( hid_t loc, inline void writeHDF5Attr( hid_t loc,
const char* name, const char* name,
ArrayVectorView<T> & array) ArrayVectorView<T> & array)
{ {
writeHDF5Attr(loc, name, writeHDF5Attr(loc, name,
MultiArrayView<1, T>(MultiArrayShape<1>::type(array.size( )), MultiArrayView<1, T>(MultiArrayShape<1>::type(array.size( )),
array.data())); array.data()));
} }
/** write an Attribute given a file and a path in the file. /** write an Attribute given a file and a path in the file.
* the path in the file should have the format the path in the file should have the format
* [attribute] or /[subgroups/]dataset.attribute or [attribute] or /[subgroups/]dataset.attribute or
* /[subgroups/]group.attribute. /[subgroups/]group.attribute.
* The attribute is written to the root group, a dataset or a subgroup The attribute is written to the root group, a dataset or a subgroup
* respectively respectively
*/ */
template<class Arr> template<class Arr>
inline void writeHDF5Attr( std::string filePath, inline void writeHDF5Attr( std::string filePath,
std::string pathInFile, std::string pathInFile,
Arr & ar) Arr & ar)
{ {
std::string path_name(pathInFile), group_name, data_set_name, message, attr_name; std::string path_name(pathInFile), group_name, data_set_name, message, attr_name;
std::string::size_type delimiter = path_name.rfind('/'); std::string::size_type delimiter = path_name.rfind('/');
//create or open file //create or open file
HDF5Handle file_id(createFile(filePath), &H5Fclose, HDF5Handle file_id(createFile(filePath), &H5Fclose,
 End of changes. 88 change blocks. 
156 lines changed or deleted 2193 lines changed or added


 imagecontainer.hxx   imagecontainer.hxx 
skipping to change at line 64 skipping to change at line 64
/********************************************************/ /********************************************************/
/** \brief Fundamental class template for arrays of equal-sized images. /** \brief Fundamental class template for arrays of equal-sized images.
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 custimized 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> \<<a href="imagecontainer_8hxx-source.html">vigra/imag econtainer.hxx</a>\> <b>\#include</b> \<vigra/imagecontainer.hxx\>
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:
skipping to change at line 256 skipping to change at line 256
bool empty() bool empty()
{ {
return images_.empty(); return images_.empty();
} }
/** Returns true if and only if both ImageArrays have exactly /** Returns true if and only if both ImageArrays have exactly
the same contents and all images did compare equal with the the same contents and all images did compare equal with the
corresponding image in the other ImageArray. (STL-Forward corresponding image in the other ImageArray. (STL-Forward
Container interface) Container interface)
*/ */
bool operator ==(const ImageArray<ImageType> &other) bool operator ==(const ImageArray<ImageType, Alloc> &other)
{ {
return (imageSize() == other.imageSize()) return (imageSize() == other.imageSize())
&& (images_ == other.images_); && (images_ == other.images_);
} }
/** Insert image at/before pos. (STL-Sequence interface) /** Insert image at/before pos. (STL-Sequence interface)
*/ */
iterator insert(iterator pos, const_reference image) iterator insert(iterator pos, const_reference image)
{ {
return images_.insert(pos, image); return images_.insert(pos, image);
skipping to change at line 457 skipping to change at line 457
/** \brief Class template for logarithmically tapering image pyramids. /** \brief Class template for logarithmically tapering image pyramids.
An ImagePyramid manages an array of images of the type given as An ImagePyramid manages an array of images of the type given as
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 custimized 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> \<<a href="imagecontainer_8hxx-source.html">vigra/imag econtainer.hxx</a>\> <b>\#include</b> \<vigra/imagecontainer.hxx\>
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:
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 imageinfo.hxx   imageinfo.hxx 
skipping to change at line 39 skipping to change at line 39
/* 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. */
/* */ /* */
/************************************************************************/ /************************************************************************/
/* Modifications by Pablo d'Angelo /* Modifications by Pablo d'Angelo
* updated to vigra 1.4 by Douglas Wilkins * updated to vigra 1.4 by Douglas Wilkins
* as of 18 Febuary 2006: * as of 18 February 2006:
* - Added UINT16 and UINT32 pixel types. * - Added UINT16 and UINT32 pixel types.
* - Added support for obtaining extra bands beyond RGB. * - Added support for obtaining extra bands beyond RGB.
* - Added support for a position field that indicates the start of this * - Added support for a position field that indicates the start of this
* image relative to some global origin. * image relative to some global origin.
* - Added support for x and y resolution fields. * - Added support for x and y resolution fields.
* - Added support for ICC profiles * - Added support for ICC profiles
*/ */
#ifndef VIGRA_IMAGEINFO_HXX #ifndef VIGRA_IMAGEINFO_HXX
#define VIGRA_IMAGEINFO_HXX #define VIGRA_IMAGEINFO_HXX
skipping to change at line 64 skipping to change at line 64
#include "error.hxx" #include "error.hxx"
#include "diff2d.hxx" #include "diff2d.hxx"
#include "codec.hxx" #include "codec.hxx"
#include "array_vector.hxx" #include "array_vector.hxx"
#include "multi_iterator.hxx" #include "multi_iterator.hxx"
namespace vigra namespace vigra
{ {
/** \addtogroup VigraImpex Image Import/Export Facilities /** \addtogroup VigraImpex Image Import/Export Facilities
supports GIF, TIFF, JPEG, BMP, PNM (PBM, PGM, PPM), PNG, SunRaster, KHO ROS-VIFF formats supports GIF, TIFF, JPEG, BMP, EXR, HDR, PNM (PBM, PGM, PPM), PNG, SunR aster, KHOROS-VIFF formats
**/ **/
//@{ //@{
/** \brief List the image formats VIGRA can read and write. /** \brief List the image formats VIGRA can read and write.
This is useful for creating error messages if VIGRA encounters an This is useful for creating error messages if VIGRA encounters an
image format it doesn't recognize. image format it doesn't recognize.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="imageinfo_8hxx-source.html">vigra/image info.hxx</a>\><br> <b>\#include</b> \<vigra/imageinfo.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
std::cout << "supported formats: " << vigra::impexListFormats() << std::endl; std::cout << "supported formats: " << vigra::impexListFormats() << std::endl;
\endcode \endcode
**/ **/
VIGRA_EXPORT std::string impexListFormats(); VIGRA_EXPORT std::string impexListFormats();
/** \brief List the file extension VIGRA understands. /** \brief List the file extension VIGRA understands.
This is useful for creating file dialogs that only list image files This is useful for creating file dialogs that only list image files
VIGRA can actually import. VIGRA can actually import.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="imageinfo_8hxx-source.html">vigra/image info.hxx</a>\><br> <b>\#include</b> \<vigra/imageinfo.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
std::cout << "supported extensions: " << vigra::impexListExtensions () << std::endl; std::cout << "supported extensions: " << vigra::impexListExtensions () << std::endl;
\endcode \endcode
**/ **/
VIGRA_EXPORT std::string impexListExtensions(); VIGRA_EXPORT std::string impexListExtensions();
/** \brief Test whether a file is an image format known to VIGRA. /** \brief Test whether a file is an image format known to VIGRA.
This checks the first few bytes of the file and compares them with the This checks the first few bytes of the file and compares them with the
"magic strings" of each recognized image format. "magic strings" of each recognized image format.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="imageinfo_8hxx-source.html">vigra/imageinfo .hxx</a>\><br> <b>\#include</b> \<vigra/imageinfo.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
std::cout << "is image: " << vigra::isImage("foo.bmp") << std::endl; std::cout << "is image: " << vigra::isImage("foo.bmp") << std::endl;
\endcode \endcode
**/ **/
VIGRA_EXPORT bool isImage(char const * filename); VIGRA_EXPORT bool isImage(char const * filename);
/********************************************************/ /********************************************************/
/* */ /* */
/* ImageExportInfo */ /* ImageExportInfo */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Argument object for the function exportImage(). /** \brief Argument object for the function exportImage().
See \ref exportImage() for usage example. This object must be used See \ref exportImage() for usage example. This object must be used
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> \<<a href="imageinfo_8hxx-source.html">vigra/imageinfo .hxx</a>\><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 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', '.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'.
JPEG support requires libjpeg, PNG support requires libpng, and EXR support requires libopenexr, JPEG support requires libjpeg,
TIFF support requires libtiff. PNG support requires libpng and TIFF support requires libtiff.
**/ **/
VIGRA_EXPORT ImageExportInfo( const char * ); VIGRA_EXPORT ImageExportInfo( const char *, const char * = "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', '.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'.
JPEG support requires libjpeg, PNG support requires libpng, and EXR support requires libopenexr, JPEG support requires libjpeg,
TIFF support requires libtiff. PNG support requires libpng and TIFF support requires libtiff.
**/ **/
VIGRA_EXPORT ImageExportInfo & setFileName(const char * filename); VIGRA_EXPORT ImageExportInfo & setFileName(const char * filename);
VIGRA_EXPORT const char * getFileName() const; VIGRA_EXPORT const char * getFileName() const;
/** Return the image file opening mode.
**/
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>"BMP"<DD> Microsoft Windows bitmap image file.
<DT>"EXR"<DD> OpenEXR high dynamic range image format.
(only available if libopenexr is installed)
<DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col or. <DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col or.
<DT>"HDR"<DD> Radiance RGBE high dynamic range image format.
<DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format; <DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format;
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.
skipping to change at line 193 skipping to change at line 200
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 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 aditionally 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
64 bit double) without conversion. So you will need to use 64 bit double) without conversion. So you will need to use
TIFF or VIFF if you need to store images with high TIFF or VIFF if you need to store images with high
accuracy (the appropriate type to write is automatically accuracy (the appropriate type to write is automatically
derived from the image type to be exported). However, many derived from the image type to be exported). However, many
other programs using TIFF (e.g. ImageMagick) have not other programs using TIFF (e.g. ImageMagick) have not
implemented support for those pixel types. So don't be implemented support for those pixel types. So don't be
surprised if the generated TIFF is not readable in some surprised if the generated TIFF is not readable in some
cases. If this happens, export the image as 'unsigned cases. If this happens, export the image as 'unsigned
char' or 'RGBValue\<unsigned char\>' by calling char' or 'RGBValue\<unsigned char\>' by calling
\ref ImageExportInfo::setPixelType(). \ref ImageExportInfo::setPixelType().
Support to reading and writing ICC color profiles is Support to reading and writing ICC color profiles is
provided for TIFF, JPEG, and PNG images. provided for TIFF, JPEG, and PNG images.
**/ **/
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. /** Set compression type and quality.
Recognized strings: "" (no compression), "LZW", This option is ignored when the target file format doesn't reco
"RunLength", "1" ... "100". A number is interpreted as the gnize
compression quality for JPEG compression. JPEG compression is the compression type. Valid arguments:
supported by the JPEG and TIFF formats. "LZW" is only available
if libtiff was installed with LZW enabled. By default, libtiff
came
with LZW disabled due to Unisys patent enforcement. In this cas
e,
VIGRA stores the image uncompressed.
Valid Compression for TIFF files: <DL>
JPEG jpeg compression, call setQuality as well! <DT>"NONE"<DD> (recognized by EXR and TIFF): do not compress (m
RLE runlength compression any other formats don't
LZW lzw compression compress either, but it is not an option for the
DEFLATE deflate compression m).
<DT>"JPEG"<DD> (recognized by JPEG and TIFF): use JPEG compress
ion.
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
(e.g. "JPEG QUALITY=70").
<DT>"JPEG-ARITH"<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).
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
(e.g. "JPEG-ARITH QUALITY=70").
<DT>"RLE", "RunLength"<DD> (recognized by EXR and TIFF): use ru
n-length encoding. (BMP also
uses run-length encoding, but there it is not an
option).
<DT>"PACKBITS"<DD> (recognized by TIFF): use packbits encoding
(a variant of RLE).
<DT>"DEFLATE"<DD> (recognized by TIFF): use deflate encoding, a
s defined in zlib (PNG also
uses deflate, but there it is not an option).
<DT>"LZW"<DD> (recognized by TIFF): use Lempel-Ziv-Welch encodi
ng.
<DT>"ZIP"<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
zip-style encoding.
<DT>"B44", "B44A"<DD> (recognized by EXR): see OpenEXR document
ation.
<DT>"ASCII"<DD> (recognized by PNM): store pixels as ASCII (hum
an readable numbers).
<DT>"RAW"<DD> (recognized by PNM): store pixels as uncompressed
binary data.
<DT>"BILEVEL"<DD> (recognized by PNM): store as one bit per pix
el.
<DT>"1" ... "100"<DD> deprecated (equivalent to <tt>setCompress
ion("JPEG QUALITY=number")</tt>
where the number denotes the desired quality).
</DL>
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
.
**/ **/
VIGRA_EXPORT ImageExportInfo & setCompression( const char * ); 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>"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>"FLOAT"<DD> 32-bit floating point (float) <DT>"FLOAT"<DD> 32-bit floating point (float)
skipping to change at line 289 skipping to change at line 318
VIGRA_EXPORT float getXResolution() const; VIGRA_EXPORT float getXResolution() const;
/** 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 and PNG 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.
@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)
**/ **/
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
getPosition()
**/
VIGRA_EXPORT Size2D getCanvasSize() const;
/** Get the size of the canvas, on which the image is positioned at
getPosition()
**/
VIGRA_EXPORT ImageExportInfo & setCanvasSize(const Size2D & size);
/** /**
ICC profiles (handled as raw data so far). ICC profiles (handled as raw data so far).
see getICCProfile()/setICCProfile() see getICCProfile()/setICCProfile()
**/ **/
typedef ArrayVector<unsigned char> ICCProfile; typedef ArrayVector<unsigned char> ICCProfile;
/** Returns a reference to the ICC profile. /** Returns a reference to the ICC profile.
*/ */
VIGRA_EXPORT const ICCProfile & getICCProfile() const; VIGRA_EXPORT const ICCProfile & getICCProfile() const;
/** Sets the ICC profile. /** Sets the ICC profile.
ICC profiles are currently supported by TIFF, PNG and JPEG imag es. ICC profiles are currently supported by TIFF, PNG and JPEG imag es.
(Otherwise, the profile data is silently ignored.) (Otherwise, the profile data is silently ignored.)
**/ **/
VIGRA_EXPORT ImageExportInfo & setICCProfile(const ICCProfile & profile ); VIGRA_EXPORT ImageExportInfo & setICCProfile(const ICCProfile & profile );
private: private:
std::string m_filename, m_filetype, m_pixeltype, m_comp; std::string m_filename, m_filetype, m_pixeltype, m_comp, m_mode;
float m_x_res, m_y_res; float m_x_res, m_y_res;
Diff2D m_pos; Diff2D m_pos;
ICCProfile m_icc_profile; ICCProfile m_icc_profile;
Size2D m_canvas_size;
double fromMin_, fromMax_, toMin_, toMax_; double fromMin_, fromMax_, toMin_, toMax_;
}; };
// return an encoder for a given ImageExportInfo object // return an encoder for a given ImageExportInfo object
VIGRA_EXPORT std::auto_ptr<Encoder> encoder( const ImageExportInfo & info ) ; VIGRA_EXPORT std::auto_ptr<Encoder> encoder( const ImageExportInfo & info ) ;
/********************************************************/ /********************************************************/
/* */ /* */
/* ImageImportInfo */ /* ImageImportInfo */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Argument object for the function importImage(). /** \brief Argument object for the function importImage().
See \ref importImage() for a usage example. This object must be See \ref importImage() for a usage example. This object must be
used to read an image from disk and enquire about its properties. used to read an image from disk and enquire about its properties.
<b>\#include</b> \<<a href="imageinfo_8hxx-source.html">vigra/imageinfo.hxx </a>\><br> <b>\#include</b> \<vigra/imageinfo.hxx\><br>
Namespace: vigra Namespace: vigra
**/ **/
class ImageImportInfo class ImageImportInfo
{ {
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>"BMP"<DD> Microsoft Windows bitmap image file.
<DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format <DT>"EXR"<DD> OpenEXR high dynamic range image format.
(only available if libjpeg is installed). (only available if libopenexr is installed)
<DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col or. <DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col or.
<DT>"PNG"<DD> Portable Network Graphics <DT>"HDR"<DD> Radiance RGBE high dynamic range image format.
<DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format;
compressed 24-bit color (only available if libjpeg is installed
).
<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>"VIFF"<DD> Khoros Visualization image file. <DT>"VIFF"<DD> Khoros Visualization image file.
</DL> </DL>
**/ **/
VIGRA_EXPORT ImageImportInfo( const char * ); VIGRA_EXPORT ImageImportInfo( const char *, unsigned int = 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 402 skipping to change at line 445
/** Get the total number of bands in the image. /** Get the total number of bands in the image.
**/ **/
VIGRA_EXPORT int numBands() const; VIGRA_EXPORT int numBands() const;
/** Get the number of extra (non color) bands in the image. /** Get the number of extra (non color) bands in the image.
** Usually these are the alpha channels. ** Usually these are the alpha channels.
**/ **/
VIGRA_EXPORT int numExtraBands() const; VIGRA_EXPORT int numExtraBands() const;
/** Get the number of images contained in the image file.
**/
VIGRA_EXPORT int numImages() const;
/** Sets the index of the image to import from the image file.
**/
VIGRA_EXPORT void setImageIndex(const int);
/** Gets the index of the image to import from the image file.
**/
VIGRA_EXPORT int getImageIndex() const;
/** Get size of the image. /** Get size of the image.
**/ **/
VIGRA_EXPORT Size2D size() const; VIGRA_EXPORT Size2D size() const;
/** Get size of the image in a form compatible to MultiArray. /** Get size of the image in a form compatible to MultiArray.
**/ **/
VIGRA_EXPORT MultiArrayShape<2>::type shape() const; VIGRA_EXPORT MultiArrayShape<2>::type shape() const;
/** Returns true if the image is gray scale. /** Returns true if the image is gray scale.
**/ **/
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.
skipping to change at line 461 skipping to change at line 516
/** 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
**/ **/
VIGRA_EXPORT Diff2D getPosition() const; VIGRA_EXPORT Diff2D getPosition() const;
/** Get the size of the canvas, on which the image is positioned at
getPosition()
**/
VIGRA_EXPORT Size2D getCanvasSize() const;
/** Returns the image resolution in horizontal direction /** Returns the image resolution in horizontal direction
**/ **/
VIGRA_EXPORT float getXResolution() const; VIGRA_EXPORT float getXResolution() const;
/** Returns the image resolution in vertical direction /** Returns the image resolution in vertical direction
**/ **/
VIGRA_EXPORT float getYResolution() const; VIGRA_EXPORT float getYResolution() const;
/** /**
ICC profiles (handled as raw data so far). ICC profiles (handled as raw data so far).
skipping to change at line 484 skipping to change at line 544
/** Returns a reference to the ICC profile. /** Returns a reference to the ICC profile.
Note: The reference will become invalid when the Note: The reference will become invalid when the
ImageImportInfo object has been destroyed. ImageImportInfo object has been destroyed.
**/ **/
VIGRA_EXPORT const ICCProfile & getICCProfile() const; VIGRA_EXPORT const ICCProfile & getICCProfile() const;
private: private:
std::string m_filename, m_filetype, m_pixeltype; std::string m_filename, m_filetype, m_pixeltype;
int m_width, m_height, m_num_bands, m_num_extra_bands; int m_width, m_height, m_num_bands, m_num_extra_bands, m_num_images, m_ image_index;
float m_x_res, m_y_res; float m_x_res, m_y_res;
Diff2D m_pos; Diff2D m_pos;
Size2D m_canvas_size;
ICCProfile m_icc_profile; ICCProfile m_icc_profile;
void readHeader_();
}; };
// return a decoder for a given ImageImportInfo object // return a decoder for a given ImageImportInfo object
VIGRA_EXPORT std::auto_ptr<Decoder> decoder( const ImageImportInfo & info ) ; VIGRA_EXPORT std::auto_ptr<Decoder> decoder( const ImageImportInfo & info ) ;
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_IMAGEINFO_HXX #endif // VIGRA_IMAGEINFO_HXX
 End of changes. 33 change blocks. 
39 lines changed or deleted 124 lines changed or added


 imageiterator.hxx   imageiterator.hxx 
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> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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 841 skipping to change at line 841
/** \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="documents/GenericProg2D.ps">Reusable Algorithms in Image Proce ssing</a> <a href="documents/GenericProg2D.ps">Reusable Algorithms in Image Proce ssing</a>
for a discussion of the concepts behind ImageIterators. for a discussion of the concepts behind ImageIterators.
<b>\#include</b> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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:
skipping to change at line 887 skipping to change at line 887
/* */ /* */
/* 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> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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:
skipping to change at line 961 skipping to change at line 961
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> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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:
skipping to change at line 1022 skipping to change at line 1022
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> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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>
{ {
skipping to change at line 1285 skipping to change at line 1285
/* 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> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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.
*/ */
skipping to change at line 1557 skipping to change at line 1557
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> \<<a href="imageiterator_8hxx-source.html">vigra/image iterator.hxx</a>\> <b>\#include</b> \<vigra/imageiterator.hxx\>
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. 7 change blocks. 
7 lines changed or deleted 7 lines changed or added


 imageiteratoradapter.hxx   imageiteratoradapter.hxx 
skipping to change at line 55 skipping to change at line 55
Iterate over rows, columns, neighborhoods, contours, and other image s ubsets Iterate over rows, columns, neighborhoods, contours, and other image s ubsets
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* ColumnIterator */ /* ColumnIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Iterator adapter to linearly access colums. /** \brief Iterator adapter to linearly access columns.
This iterator may be initialized from any standard ImageIterator, This iterator may be initialized from any standard ImageIterator,
a MultibandImageIterator and so on. a MultibandImageIterator and so on.
It gives you STL-compatible (random access iterator) access to It gives you STL-compatible (random access iterator) access to
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> \<<a href="imageiteratoradapter_8hxx-source.html">vigr a/imageiteratoradapter.hxx</a>\> <b>\#include</b> \<vigra/imageiteratoradapter.hxx\>
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
*/ */
skipping to change at line 276 skipping to change at line 276
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> \<<a href="imageiteratoradapter_8hxx-source.html">vigr a/imageiteratoradapter.hxx</a>\> <b>\#include</b> \<vigra/imageiteratoradapter.hxx\>
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
*/ */
skipping to change at line 472 skipping to change at line 472
/* */ /* */
/* LineIterator */ /* LineIterator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \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 arbitraty 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> \<<a href="imageiteratoradapter_8hxx-source.html">vigr a/imageiteratoradapter.hxx</a>\> <b>\#include</b> \<vigra/imageiteratoradapter.hxx\>
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
*/ */
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 impex.hxx   impex.hxx 
skipping to change at line 37 skipping to change at line 37
/* 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. */
/* */ /* */
/************************************************************************/ /************************************************************************/
/* Modifications by Pablo d'Angelo /* Modifications by Pablo d'Angelo
* updated to vigra 1.4 by Douglas Wilkins * updated to vigra 1.4 by Douglas Wilkins
* as of 18 Febuary 2006: * as of 18 February 2006:
* - Added import/export of UINT16 and UINT32 image types. * - Added import/export of UINT16 and UINT32 image types.
* Modifications by Andrew Mihal * Modifications by Andrew Mihal
* updated to vigra 1.4 by Douglas Wilkins * updated to vigra 1.4 by Douglas Wilkins
* as of 18 Febuary 2006: * as of 18 February 2006:
* - Moved some RowIterator declarations around to avoid using default cto rs * - Moved some RowIterator declarations around to avoid using default cto rs
* (cachedfileimages do not have default ctors for row iterators). * (cachedfileimages do not have default ctors for row iterators).
* - Added some case-specific optimizations * - Added some case-specific optimizations
*/ */
/*! /*!
\file impex.hxx \file impex.hxx
\brief image import and export functions \brief image import and export functions
this file provides the declarations and implementations of importImage() this file provides the declarations and implementations of importImage()
skipping to change at line 70 skipping to change at line 70
#include "stdimage.hxx" #include "stdimage.hxx"
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "imageinfo.hxx" #include "imageinfo.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "codec.hxx" #include "codec.hxx"
#include "accessor.hxx" #include "accessor.hxx"
#include "inspectimage.hxx" #include "inspectimage.hxx"
#include "transformimage.hxx" #include "transformimage.hxx"
#include "copyimage.hxx" #include "copyimage.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include <typeinfo>
#include <iostream>
// TODO // TODO
// next refactoring: pluggable conversion algorithms // next refactoring: pluggable conversion algorithms
namespace vigra namespace vigra
{ {
/** \addtogroup VigraImpex /** \addtogroup VigraImpex
**/ **/
//@{ //@{
/*! /*!
\brief used for reading bands after the source data type has been fig ured out. \brief used for reading bands after the source data type has been fig ured out.
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template< class ImageIterator, class Accessor, class SrcValueTy pe > template< class ImageIterator, class Accessor, class SrcValueTy pe >
void read_bands( Decoder * dec, ImageIterator ys, Accessor a, S rcValueType ) void read_bands( Decoder * dec, ImageIterator ys, Accessor a, S rcValueType )
} }
\endcode \endcode
skipping to change at line 112 skipping to change at line 115
typedef unsigned int size_type; typedef unsigned int size_type;
typedef typename ImageIterator::row_iterator DstRowIterator; typedef typename ImageIterator::row_iterator DstRowIterator;
typedef typename Accessor::value_type AccessorValueType; typedef typename Accessor::value_type AccessorValueType;
typedef typename AccessorValueType::value_type DstValueType; typedef typename AccessorValueType::value_type DstValueType;
const size_type width = dec->getWidth(); const size_type width = dec->getWidth();
const size_type height = dec->getHeight(); const size_type height = dec->getHeight();
const size_type num_bands = dec->getNumBands(); const size_type num_bands = dec->getNumBands();
vigra_precondition(num_bands == (size_type)a.size(ys), vigra_precondition(num_bands == (size_type)a.size(ys),
"importImage(): number of bands (color channels) in file and des tination image differ."); "importImage(): number of bands (color channels) in file and de stination image differ.");
SrcValueType const * scanline; SrcValueType const * scanline;
// MIHAL no default constructor available for cachedfileimages. // MIHAL no default constructor available for cachedfileimages.
DstRowIterator xs = ys.rowIterator(); DstRowIterator xs = ys.rowIterator();
// iterate // iterate
if (num_bands == 4) { if (num_bands == 4)
{
// Speedup for this particular case // Speedup for this particular case
unsigned int offset = dec->getOffset(); unsigned int offset = dec->getOffset();
SrcValueType const * scanline0; SrcValueType const * scanline0;
SrcValueType const * scanline1; SrcValueType const * scanline1;
SrcValueType const * scanline2; SrcValueType const * scanline2;
SrcValueType const * scanline3; SrcValueType const * scanline3;
for( size_type y = 0; y < height; ++y, ++ys.y ) { for( size_type y = 0; y < height; ++y, ++ys.y )
{
dec->nextScanline(); dec->nextScanline();
xs = ys.rowIterator(); xs = ys.rowIterator();
scanline0 = static_cast< SrcValueType const * > scanline0 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(0)); (dec->currentScanlineOfBand(0));
scanline1 = static_cast< SrcValueType const * > scanline1 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(1)); (dec->currentScanlineOfBand(1));
scanline2 = static_cast< SrcValueType const * > scanline2 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(2)); (dec->currentScanlineOfBand(2));
scanline3 = static_cast< SrcValueType const * > scanline3 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(3)); (dec->currentScanlineOfBand(3));
for( size_type x = 0; x < width; ++x, ++xs ) { for( size_type x = 0; x < width; ++x, ++xs )
/* {
a.template setComponent<SrcValueType, DstRowIterator, 0 a.setComponent( *scanline0, xs, 0);
>( *scanline0, xs );
a.template setComponent<SrcValueType, DstRowIterator, 1
>( *scanline1, xs );
a.template setComponent<SrcValueType, DstRowIterator, 2
>( *scanline2, xs );
a.template setComponent<SrcValueType, DstRowIterator, 3
>( *scanline3, xs );
*/
a.setComponent( *scanline0, xs, 0);
a.setComponent( *scanline1, xs, 1); a.setComponent( *scanline1, xs, 1);
a.setComponent( *scanline2, xs, 2); a.setComponent( *scanline2, xs, 2);
a.setComponent( *scanline3, xs, 3); a.setComponent( *scanline3, xs, 3);
scanline0 += offset; scanline0 += offset;
scanline1 += offset; scanline1 += offset;
scanline2 += offset; scanline2 += offset;
scanline3 += offset; scanline3 += offset;
} }
} }
} }
else { else
// General case {
for( size_type y = 0; y < height; ++y, ++ys.y ) { // General case
dec->nextScanline(); for( size_type y = 0; y < height; ++y, ++ys.y )
for( size_type b = 0; b < num_bands; ++b ) { {
xs = ys.rowIterator(); dec->nextScanline();
scanline = static_cast< SrcValueType const * > for( size_type b = 0; b < num_bands; ++b )
(dec->currentScanlineOfBand(b)); {
for( size_type x = 0; x < width; ++x, ++xs ) { xs = ys.rowIterator();
a.setComponent( *scanline, xs, b ); scanline = static_cast< SrcValueType const * >
scanline += dec->getOffset(); (dec->currentScanlineOfBand(b));
for( size_type x = 0; x < width; ++x, ++xs )
{
a.setComponent( *scanline, xs, b );
scanline += dec->getOffset();
}
} }
} }
} }
} } // read_bands()
// specialization for speed-up (the standard version would also work,
// but causes a stupid gcc waring)
template< class ImageIterator, class RGBType,
class SrcValueType >
void read_bands( Decoder * dec, ImageIterator ys,
RGBAccessor<RGBType> a, SrcValueType )
{
typedef unsigned int size_type;
typedef typename ImageIterator::row_iterator DstRowIterator;
typedef RGBType AccessorValueType;
typedef typename AccessorValueType::value_type DstValueType;
const size_type width = dec->getWidth();
const size_type height = dec->getHeight();
const size_type num_bands = dec->getNumBands();
vigra_precondition(num_bands == (size_type)a.size(ys),
"importImage(): number of bands (color channels) in file and des
tination image differ.");
// MIHAL no default constructor available for cachedfileimages.
DstRowIterator xs = ys.rowIterator();
// Speedup for this particular case
unsigned int offset = dec->getOffset();
SrcValueType const * scanline0;
SrcValueType const * scanline1;
SrcValueType const * scanline2;
for( size_type y = 0; y < height; ++y, ++ys.y )
{
dec->nextScanline();
xs = ys.rowIterator();
scanline0 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(0));
scanline1 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(1));
scanline2 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(2));
for( size_type x = 0; x < width; ++x, ++xs )
{
a.setComponent( *scanline0, xs, 0);
a.setComponent( *scanline1, xs, 1);
a.setComponent( *scanline2, xs, 2);
scanline0 += offset;
scanline1 += offset;
scanline2 += offset;
}
}
} // read_bands()
// specialization for speed-up (the standard version would also work,
// but causes a stupid gcc waring)
template< class ImageIterator, class ComponentType, class SrcValueType
>
void read_bands( Decoder * dec, ImageIterator ys,
VectorAccessor<TinyVector<ComponentType, 3> > a, SrcVa
lueType )
{
typedef unsigned int size_type;
typedef typename ImageIterator::row_iterator DstRowIterator;
typedef TinyVector<ComponentType, 3> AccessorValueType;
typedef typename AccessorValueType::value_type DstValueType;
const size_type width = dec->getWidth();
const size_type height = dec->getHeight();
const size_type num_bands = dec->getNumBands();
vigra_precondition(num_bands == (size_type)a.size(ys),
"importImage(): number of bands (color channels) in file and des
tination image differ.");
// MIHAL no default constructor available for cachedfileimages.
DstRowIterator xs = ys.rowIterator();
// Speedup for this particular case
unsigned int offset = dec->getOffset();
SrcValueType const * scanline0;
SrcValueType const * scanline1;
SrcValueType const * scanline2;
for( size_type y = 0; y < height; ++y, ++ys.y )
{
dec->nextScanline();
xs = ys.rowIterator();
scanline0 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(0));
scanline1 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(1));
scanline2 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(2));
for( size_type x = 0; x < width; ++x, ++xs )
{
a.setComponent( *scanline0, xs, 0);
a.setComponent( *scanline1, xs, 1);
a.setComponent( *scanline2, xs, 2);
scanline0 += offset;
scanline1 += offset;
scanline2 += offset;
}
}
} // read_bands()
// specialization for speed-up (the standard version would also work,
// but causes a stupid gcc waring)
template< class ImageIterator, class ComponentType, class SrcValueType
>
void read_bands( Decoder * dec, ImageIterator ys,
VectorAccessor<TinyVector<ComponentType, 4> > a, SrcVa
lueType )
{
typedef unsigned int size_type;
typedef typename ImageIterator::row_iterator DstRowIterator;
typedef TinyVector<ComponentType, 4> AccessorValueType;
typedef typename AccessorValueType::value_type DstValueType;
const size_type width = dec->getWidth();
const size_type height = dec->getHeight();
const size_type num_bands = dec->getNumBands();
vigra_precondition(num_bands == (size_type)a.size(ys),
"importImage(): number of bands (color channels) in file and des
tination image differ.");
// MIHAL no default constructor available for cachedfileimages.
DstRowIterator xs = ys.rowIterator();
// Speedup for this particular case
unsigned int offset = dec->getOffset();
SrcValueType const * scanline0;
SrcValueType const * scanline1;
SrcValueType const * scanline2;
SrcValueType const * scanline3;
for( size_type y = 0; y < height; ++y, ++ys.y )
{
dec->nextScanline();
xs = ys.rowIterator();
scanline0 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(0));
scanline1 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(1));
scanline2 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(2));
scanline3 = static_cast< SrcValueType const * >
(dec->currentScanlineOfBand(3));
for( size_type x = 0; x < width; ++x, ++xs )
{
a.setComponent( *scanline0, xs, 0);
a.setComponent( *scanline1, xs, 1);
a.setComponent( *scanline2, xs, 2);
a.setComponent( *scanline3, xs, 3);
scanline0 += offset;
scanline1 += offset;
scanline2 += offset;
scanline3 += offset;
}
}
} // read_bands() } // read_bands()
/*! /*!
\brief used for reading bands after the source data type has been fig ured out. \brief used for reading bands after the source data type has been fig ured out.
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template< class ImageIterator, class Accessor, class SrcValueTy pe > template< class ImageIterator, class Accessor, class SrcValueTy pe >
void read_band( Decoder * dec, ImageIterator ys, Accessor a, Sr cValueType ) void read_band( Decoder * dec, ImageIterator ys, Accessor a, Sr cValueType )
} }
\endcode \endcode
skipping to change at line 216 skipping to change at line 370
xs = ys.rowIterator(); xs = ys.rowIterator();
scanline = static_cast< SrcValueType const * >(dec->currentScan lineOfBand(0)); scanline = static_cast< SrcValueType const * >(dec->currentScan lineOfBand(0));
for( size_type x = 0; x < width; ++x, ++xs ) for( size_type x = 0; x < width; ++x, ++xs )
a.set( scanline[x], xs ); a.set( scanline[x], xs );
} }
} // read_band() } // read_band()
/*! /*!
\brief used for reading images of vector type, such as integer of flo at rgb. \brief used for reading images of vector type, such as integer of flo at rgb.
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template< class ImageIterator, class Accessor > template< class ImageIterator, class Accessor >
void importVectorImage( const ImageImportInfo & info, ImageIter ator iter, Accessor a ) void importVectorImage( const ImageImportInfo & info, ImageIter ator iter, Accessor a )
} }
\endcode \endcode
<b> Paramters:</b> <b> Parameters:</b>
<DL> <DL>
<DT>ImageIterator<DD> the image iterator type for the destination i mage <DT>ImageIterator<DD> the image iterator type for the destination i mage
<DT>Accessor<DD> the image accessor type for the destination image <DT>Accessor<DD> the image accessor type for the destination image
<DT>info<DD> user supplied image import information <DT>info<DD> user supplied image import information
<DT>iter<DD> image iterator referencing the upper left pixel of the destination image <DT>iter<DD> image iterator referencing the upper left pixel of the destination image
<DT>a<DD> image accessor for the destination image <DT>a<DD> image accessor for the destination image
</DL> </DL>
*/ */
doxygen_overloaded_function(template <...> void importVectorImage) doxygen_overloaded_function(template <...> void importVectorImage)
skipping to change at line 270 skipping to change at line 424
else else
vigra_precondition( false, "invalid pixeltype" ); vigra_precondition( false, "invalid pixeltype" );
// close the decoder // close the decoder
dec->close(); dec->close();
} }
/*! /*!
\brief used for reading images of scalar type, such as integer and f loat grayscale. \brief used for reading images of scalar type, such as integer and f loat grayscale.
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template < class ImageIterator, class Accessor > template < class ImageIterator, class Accessor >
void importScalarImage( const ImageImportInfo & info, ImageIter ator iter, Accessor a ) void importScalarImage( const ImageImportInfo & info, ImageIter ator iter, Accessor a )
} }
\endcode \endcode
<b> Paramters:</b> <b> Parameters:</b>
<DL> <DL>
<DT>ImageIterator<DD> the image iterator type for the destination i mage <DT>ImageIterator<DD> the image iterator type for the destination i mage
<DT>Accessor<DD> the image accessor type for the destination image <DT>Accessor<DD> the image accessor type for the destination image
<DT>info<DD> user supplied image import information <DT>info<DD> user supplied image import information
<DT>iter<DD> image iterator referencing the upper left pixel of the destination image <DT>iter<DD> image iterator referencing the upper left pixel of the destination image
<DT>a<DD> image accessor for the destination image <DT>a<DD> image accessor for the destination image
</DL> </DL>
*/ */
doxygen_overloaded_function(template <...> void importScalarImage) doxygen_overloaded_function(template <...> void importScalarImage)
template < class ImageIterator, class Accessor > template < class ImageIterator, class Accessor >
void importScalarImage( const ImageImportInfo & info, ImageIterator ite r, Accessor a ) void importScalarImage( const ImageImportInfo & info, ImageIterator ite r, Accessor a )
{ {
#if HAVE_UNIQUE_PTR
std::unique_ptr<Decoder> dec = decoder(info);
#else
std::auto_ptr<Decoder> dec = decoder(info); std::auto_ptr<Decoder> dec = decoder(info);
#endif
std::string pixeltype = dec->getPixelType(); std::string pixeltype = dec->getPixelType();
if ( pixeltype == "UINT8" ) if ( pixeltype == "UINT8" )
read_band( dec.get(), iter, a, (UInt8)0 ); read_band( dec.get(), iter, a, (UInt8)0 );
else if ( pixeltype == "INT16" ) else if ( pixeltype == "INT16" )
read_band( dec.get(), iter, a, Int16() ); read_band( dec.get(), iter, a, Int16() );
else if ( pixeltype == "UINT16" ) else if ( pixeltype == "UINT16" )
read_band( dec.get(), iter, a, (UInt16)0 ); read_band( dec.get(), iter, a, (UInt16)0 );
else if ( pixeltype == "INT32" ) else if ( pixeltype == "INT32" )
read_band( dec.get(), iter, a, Int32() ); read_band( dec.get(), iter, a, Int32() );
skipping to change at line 355 skipping to change at line 505
\code \code
namespace vigra { namespace vigra {
template <class ImageIterator, class Accessor> template <class ImageIterator, class Accessor>
inline void inline void
importImage(ImageImportInfo const & image, pair<ImageIterator, Accessor> dest) importImage(ImageImportInfo const & image, pair<ImageIterator, Accessor> dest)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::ImageImportInfo info("myimage.gif"); vigra::ImageImportInfo info("myimage.gif");
if(info.isGrayscale()) if(info.isGrayscale())
{ {
// create byte image of appropriate size // create byte image of appropriate size
vigra::BImage in(info.width(), info.height()); vigra::BImage in(info.width(), info.height());
skipping to change at line 388 skipping to change at line 538
\endcode \endcode
<b> Preconditions:</b> <b> Preconditions:</b>
<UL> <UL>
<LI> the image file must be readable <LI> the image file must be readable
<LI> the file type must be one of <LI> the file type must be one of
<DL> <DL>
<DT>"BMP"<DD> Microsoft Windows bitmap image file. <DT>"BMP"<DD> Microsoft Windows bitmap image file.
<DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit <DT>"EXR"<DD> OpenEXR high dynamic range image format.
color. (only available if libopenexr is installed)
<DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format <DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col
; compressed 24-bit color. (only available if libjpeg is installed) or.
<DT>"PNG"<DD> Portable Network Graphic. (only available if <DT>"HDR"<DD> Radiance RGBE high dynamic range image format.
libpng is installed) <DT>"JPEG"<DD> Joint Photographic Experts Group JFIF format;
<DT>"PBM"<DD> Portable bitmap format (black and white). compressed 24-bit color (only available if libjpeg is installed
<DT>"PGM"<DD> Portable graymap format (gray scale). ).
<DT>"PNM"<DD> Portable anymap. <DT>"PNG"<DD> Portable Network Graphic
<DT>"PPM"<DD> Portable pixmap format (color). (only available if libpng is installed).
<DT>"SUN"<DD> SUN Rasterfile. <DT>"PBM"<DD> Portable bitmap format (black and white).
<DT>"TIFF"<DD> Tagged Image File Format. (only available if <DT>"PGM"<DD> Portable graymap format (gray scale).
libtiff is installed.) <DT>"PNM"<DD> Portable anymap.
<DT>"VIFF"<DD> Khoros Visualization image file. <DT>"PPM"<DD> Portable pixmap format (color).
</DL> <DT>"SUN"<DD> SUN Rasterfile.
<DT>"TIFF"<DD> Tagged Image File Format.
(only available if libtiff is installed.)
<DT>"VIFF"<DD> Khoros Visualization image file.
</DL>
</UL> </UL>
**/ **/
doxygen_overloaded_function(template <...> void importImage) doxygen_overloaded_function(template <...> void importImage)
template < class ImageIterator, class Accessor > template < class ImageIterator, class Accessor >
void importImage( const ImageImportInfo & info, ImageIterator iter, Acc essor a ) void importImage( const ImageImportInfo & info, ImageIterator iter, Acc essor a )
{ {
typedef typename NumericTraits<typename Accessor::value_type>::isSc alar is_scalar; typedef typename NumericTraits<typename Accessor::value_type>::isSc alar is_scalar;
importImage( info, iter, a, is_scalar() ); importImage( info, iter, a, is_scalar() );
} }
skipping to change at line 433 skipping to change at line 589
template < class ImageIterator, class Accessor > template < class ImageIterator, class Accessor >
void importImage( const ImageImportInfo & info, ImageIterator iter, Acc essor a, VigraTrueType ) void importImage( const ImageImportInfo & info, ImageIterator iter, Acc essor a, VigraTrueType )
{ {
importScalarImage( info, iter, a ); importScalarImage( info, iter, a );
} }
/*! /*!
\brief used for writing bands after the source data type has been fig ured out. \brief used for writing bands after the source data type has been fig ured out.
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template< class ImageIterator, class Accessor, class DstValueTy pe > template< class ImageIterator, class Accessor, class DstValueTy pe >
void write_bands( Encoder * enc, ImageIterator ul, ImageIterato r lr, Accessor a, DstValueType ) void write_bands( Encoder * enc, ImageIterator ul, ImageIterato r lr, Accessor a, DstValueType )
} }
\endcode \endcode
skipping to change at line 475 skipping to change at line 631
enc->finalizeSettings(); enc->finalizeSettings();
DstValueType * scanline; DstValueType * scanline;
// iterate // iterate
ImageIterator ys(ul); ImageIterator ys(ul);
// MIHAL no default constructor available for cachedfileimages // MIHAL no default constructor available for cachedfileimages
SrcRowIterator xs = ys.rowIterator(); SrcRowIterator xs = ys.rowIterator();
// Speedup for the common cases // Speedup for the common cases
switch (num_bands) switch (num_bands)
{ {
case 2: case 2:
{ {
unsigned int offset = enc->getOffset(); unsigned int offset = enc->getOffset();
DstValueType * scanline0; DstValueType * scanline0;
DstValueType * scanline1; DstValueType * scanline1;
for( size_type y = 0; y < height; ++y, ++ys.y ) { for( size_type y = 0; y < height; ++y, ++ys.y ) {
xs = ys.rowIterator(); xs = ys.rowIterator();
scanline0 = static_cast< DstValueType * > scanline0 = static_cast< DstValueType * >
(enc->currentScanlineOfBand(0)); (enc->currentScanlineOfBand(0));
scanline1 = static_cast< DstValueType * > scanline1 = static_cast< DstValueType * >
(enc->currentScanlineOfBand(1)); (enc->currentScanlineOfBand(1));
for( size_type x = 0; x < width; ++x, ++xs) { for( size_type x = 0; x < width; ++x, ++xs) {
skipping to change at line 558 skipping to change at line 714
scanline1 += offset; scanline1 += offset;
scanline2 += offset; scanline2 += offset;
scanline3 += offset; scanline3 += offset;
} }
enc->nextScanline(); enc->nextScanline();
} }
break; break;
} }
default: default:
{ {
// General case // General case
for( size_type y = 0; y < height; ++y, ++ys.y ) { for( size_type y = 0; y < height; ++y, ++ys.y ) {
for( size_type b = 0; b < num_bands; ++b ) { for( size_type b = 0; b < num_bands; ++b ) {
xs = ys.rowIterator(); xs = ys.rowIterator();
scanline = static_cast< DstValueType * > scanline = static_cast< DstValueType * >
(enc->currentScanlineOfBand(b)); (enc->currentScanlineOfBand(b));
for( size_type x = 0; x < width; ++x, ++xs ) { for( size_type x = 0; x < width; ++x, ++xs ) {
*scanline = detail::RequiresExplicitCast<DstValueTy pe>::cast(a.getComponent( xs, b )); *scanline = detail::RequiresExplicitCast<DstValueTy pe>::cast(a.getComponent( xs, b ));
scanline += enc->getOffset(); scanline += enc->getOffset();
} }
} }
enc->nextScanline(); enc->nextScanline();
} }
} }
} }
} // write_bands() } // write_bands()
template< class MArray, class DstValueType > template< class MArray, class DstValueType >
void write_bands( Encoder * enc, MArray const & array, DstValueType) void write_bands( Encoder * enc, MArray const & array, DstValueType)
{ {
typedef unsigned int size_type; typedef unsigned int size_type;
// complete decoder settings // complete decoder settings
const size_type width = array.shape(0); const size_type width = array.shape(0);
const size_type height = array.shape(1); const size_type height = array.shape(1);
skipping to change at line 608 skipping to change at line 764
scanline += enc->getOffset(); scanline += enc->getOffset();
} }
} }
enc->nextScanline(); enc->nextScanline();
} }
} // write_bands() } // write_bands()
/*! /*!
\brief used for writing bands after the source data type has been fig ured out. \brief used for writing bands after the source data type has been fig ured out.
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx </a>\><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template< class ImageIterator, class Accessor, class DstValueTy pe > template< class ImageIterator, class Accessor, class DstValueTy pe >
void write_band( Encoder * enc, ImageIterator ul, ImageIterator lr, Accessor a, DstValueType ) void write_band( Encoder * enc, ImageIterator ul, ImageIterator lr, Accessor a, DstValueType )
} }
\endcode \endcode
skipping to change at line 940 skipping to change at line 1096
\code \code
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor> template <class SrcIterator, class SrcAccessor>
void exportImage(SrcIterator sul, SrcIterator slr, SrcAccessor sget , void exportImage(SrcIterator sul, SrcIterator slr, SrcAccessor sget ,
ImageExportInfo const & info) ImageExportInfo const & info)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="impex_8hxx-source.html">vigra/impex.hxx</a> \><br> <b>\#include</b> \<vigra/impex.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BRGBImage out(w, h); vigra::BRGBImage out(w, h);
... ...
// write as JPEG image, using compression quality 80 // write as JPEG image, using compression quality 80
vigra::exportImage(srcImageRange(out), vigra::exportImage(srcImageRange(out),
vigra::ImageExportInfo("myimage.jpg").setCompression( "80")); vigra::ImageExportInfo("myimage.jpg").setCompression( "80"));
skipping to change at line 1048 skipping to change at line 1204
} }
enc->close(); enc->close();
} }
template < class SrcIterator, class SrcAccessor > template < class SrcIterator, class SrcAccessor >
void exportImage( SrcIterator sul, SrcIterator slr, SrcAccessor sget, void exportImage( SrcIterator sul, SrcIterator slr, SrcAccessor sget,
const ImageExportInfo & info, VigraTrueType /*scalar* / ) const ImageExportInfo & info, VigraTrueType /*scalar* / )
{ {
typedef typename SrcAccessor::value_type SrcValueType; typedef typename SrcAccessor::value_type SrcValueType;
std::string pixeltype = info.getPixelType(); std::string pixeltype = info.getPixelType();
#ifdef HAVE_UNIQUE_PTR
std::unique_ptr<Encoder> enc = encoder(info);
#else
std::auto_ptr<Encoder> enc = encoder(info); std::auto_ptr<Encoder> enc = encoder(info);
#endif
bool downcast = negotiatePixelType(enc->getFileType(), bool downcast = negotiatePixelType(enc->getFileType(),
TypeAsString<SrcValueType>::result(), pixeltype) ; TypeAsString<SrcValueType>::result(), pixeltype) ;
enc->setPixelType(pixeltype); enc->setPixelType(pixeltype);
if(downcast || info.hasForcedRangeMapping()) if(downcast || info.hasForcedRangeMapping())
{ {
if(pixeltype == "UINT8") if(pixeltype == "UINT8")
detail::exportScalarImage( sul, slr, sget, enc.get(), info, (UInt8)0); detail::exportScalarImage( sul, slr, sget, enc.get(), info, (UInt8)0);
else if(pixeltype == "INT16") else if(pixeltype == "INT16")
detail::exportScalarImage( sul, slr, sget, enc.get(), info, Int16()); detail::exportScalarImage( sul, slr, sget, enc.get(), info, Int16());
else if(pixeltype == "UINT16") else if(pixeltype == "UINT16")
 End of changes. 27 change blocks. 
70 lines changed or deleted 222 lines changed or added


 initimage.hxx   initimage.hxx 
skipping to change at line 187 skipping to change at line 187
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="initimage_8hxx-source.html">vigra/initi mage.hxx</a>\><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); vigra::BImage img(100, 100);
// init the image with the value 128 // init the image with the value 128
vigra::initImage(destImageRange(img), 128); vigra::initImage(destImageRange(img), 128);
\endcode \endcode
skipping to change at line 288 skipping to change at line 288
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="initimage_8hxx-source.html">vigra/initi mage.hxx</a>\><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++; }
mutable int count; mutable int count;
}; };
skipping to change at line 402 skipping to change at line 402
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="initimage_8hxx-source.html">vigra/initi mage.hxx</a>\><br> <b>\#include</b> \<vigra/initimage.hxx\><br>
Namespace: vigra Namespace: vigra
\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());
skipping to change at line 511 skipping to change at line 511
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="initimage_8hxx-source.html">vigra/initi mage.hxx</a>\><br> <b>\#include</b> \<vigra/initimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 inspectimage.hxx   inspectimage.hxx 
skipping to change at line 151 skipping to change at line 151
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
skipping to change at line 272 skipping to change at line 272
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\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),
skipping to change at line 405 skipping to change at line 405
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
skipping to change at line 542 skipping to change at line 542
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><br> <b>\#include</b> \<vigra/inspectimage.hxx\><br>
Namespace: vigra Namespace: vigra
\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),
skipping to change at line 676 skipping to change at line 676
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> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><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 819 skipping to change at line 819
\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> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><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 920 skipping to change at line 920
\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> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><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 1068 skipping to change at line 1068
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> \<<a href="inspectimage_8hxx-source.html">vigra/in spectimage.hxx</a>\><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";
skipping to change at line 1245 skipping to change at line 1245
\ref ArrayOfRegionStatistics to find the sizes of all regions in \ref ArrayOfRegionStatistics to find the sizes 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> \<<a href="inspectimage_8hxx-source.html">vigra/inspec timage.hxx</a>\><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 1354 skipping to change at line 1354
\ref ArrayOfRegionStatistics to find the bounding rectangles \ref ArrayOfRegionStatistics to find the bounding rectangles
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> \<<a href="inspectimage_8hxx-source.html">vigra/inspec timage.hxx</a>\><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 that pixel's // simulates an image where each pixel value equals that pixel's
// coordinates. Tha image 'mask' determines the ROI. // coordinates. Tha image 'mask' determines the ROI.
vigra::inspectImageIf(srcIterRange(Diff2D(0,0), img.size()), vigra::inspectImageIf(srcIterRange(Diff2D(0,0), (Diff2D)img.size()),
srcImage(mask), roiRect); srcImage(mask), roiRect);
cout << "Upper left of ROI: " << cout << "Upper left of ROI: " <<
roiRect.upperLeft.x << ", " << roiRect.upperLeft.y << endl; roiRect.upperLeft.x << ", " << roiRect.upperLeft.y << endl;
cout << "Lower right of ROI: " << cout << "Lower right of ROI: " <<
roiRect.lowerRight.x << ", " << roiRect.lowerRight.y << endl; roiRect.lowerRight.x << ", " << roiRect.lowerRight.y << endl;
\endcode \endcode
*/ */
skipping to change at line 1500 skipping to change at line 1500
This Functor is best used in conjunction with This Functor is best used in conjunction with
\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> \<<a href="inspectimage_8hxx-source.html">vigra/inspec timage.hxx</a>\><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 1596 skipping to change at line 1596
of the reduction is available by calling <tt>reduceFunctor()</tt>. of the reduction is available by calling <tt>reduceFunctor()</tt>.
<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> \<<a href="inspectimage_8hxx-source.html">vigra/inspec timage.hxx</a>\><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 1632 skipping to change at line 1632
template <class FUNCTOR, class VALUETYPE> template <class FUNCTOR, class VALUETYPE>
class ReduceFunctor class ReduceFunctor
{ {
FUNCTOR f_; FUNCTOR f_;
VALUETYPE start_, accumulator_; VALUETYPE start_, accumulator_;
public: public:
/** the functor's argument type /** the functor's argument type
when used as a unary inspector. when used as a unary inspector.
(This is not strictly correct since the argument type (This is not strictly correct since the argument type
is actuall a template parameter.) is actually a template parameter.)
*/ */
typedef VALUETYPE argument_type; typedef VALUETYPE argument_type;
/** the functor's first argument type /** the functor's first argument type
when used as a binary inspector. when used as a binary inspector.
(This is not strictly correct since the argument type (This is not strictly correct since the argument type
is actuall a template parameter.) is actually a template parameter.)
*/ */
typedef VALUETYPE first_argument_type; typedef VALUETYPE first_argument_type;
/** the functor's second argument type /** the functor's second argument type
when used as a binary inspector. when used as a binary inspector.
(This is not strictly correct since the argument type (This is not strictly correct since the argument type
is actuall a template parameter.) is actually a template parameter.)
*/ */
typedef VALUETYPE second_argument_type; typedef VALUETYPE second_argument_type;
/** the functor's result type /** the functor's result type
*/ */
typedef VALUETYPE result_type; typedef VALUETYPE result_type;
/** create with the given functor and initial value \a initial /** create with the given functor and initial value \a initial
for the accumulator. for the accumulator.
*/ */
skipping to change at line 1730 skipping to change at line 1730
for each label, and selects the one to be updated according to the for each label, and selects the one to be updated according to the
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> \<<a href="inspectimage_8hxx-source.html">vigra/inspec timage.hxx</a>\><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);
vigra::inspectTwoImages(srcImageRange(img), srcImage(labels), minmax); vigra::inspectTwoImages(srcImageRange(img), srcImage(labels), minmax);
for(int i=0; i<= max_label; ++i) for(int i=0; i<= max_label; ++i)
{ {
cout << "Max gray lavel of region " << i << ": " cout << "Max gray level of region " << i << ": "
<< minmax.region[i].max << endl; << minmax.region[i].max << endl;
} }
// init functor as an array of 'max_label' FindAverage-Functors // init functor as an array of 'max_label' FindAverage-Functors
vigra::ArrayOfRegionStatistics<vigra::FindAverage<vigra::BImage::PixelT ype> > vigra::ArrayOfRegionStatistics<vigra::FindAverage<vigra::BImage::PixelT ype> >
average(max_label) ; average(max_label) ;
vigra::inspectTwoImages(srcImageRange(img), srcImage(labels), average); vigra::inspectTwoImages(srcImageRange(img), srcImage(labels), average);
// write back the average of each region into the original image // write back the average of each region into the original image
skipping to change at line 1909 skipping to change at line 1909
/** iterator to the end of the region array /** iterator to the end of the region array
*/ */
iterator end() iterator end()
{ return regions.end(); } { return regions.end(); }
/** const iterator to the end of the region array /** const iterator to the end of the region array
*/ */
const_iterator end() const const_iterator end() const
{ return regions.end(); } { return regions.end(); }
private:
std::vector<RegionStatistics> regions; std::vector<RegionStatistics> regions;
}; };
template <class RegionStatistics, class LabelType> template <class RegionStatistics, class LabelType>
class FunctorTraits<ArrayOfRegionStatistics<RegionStatistics, LabelType> > class FunctorTraits<ArrayOfRegionStatistics<RegionStatistics, LabelType> >
: public FunctorTraitsBase<ArrayOfRegionStatistics<RegionStatistics, LabelT ype> > : public FunctorTraitsBase<ArrayOfRegionStatistics<RegionStatistics, LabelT ype> >
{ {
public: public:
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
typedef VigraTrueType isBinaryAnalyser; typedef VigraTrueType isBinaryAnalyser;
 End of changes. 19 change blocks. 
19 lines changed or deleted 18 lines changed or added


 interpolating_accessor.hxx   interpolating_accessor.hxx 
skipping to change at line 63 skipping to change at line 63
/** \brief Bilinear interpolation at non-integer positions. /** \brief Bilinear interpolation at non-integer positions.
This accessor allows an image be accessed at arbitrary non-integer This accessor allows an image be accessed at arbitrary non-integer
coordinates and performs an bi-linear interpolation to coordinates and performs an bi-linear interpolation to
obtain a pixel value. obtain a pixel value.
It uses the given ACCESSOR (which is usually the It uses the given ACCESSOR (which is usually the
accessor originally associated with the iterator) accessor originally associated with the iterator)
to access data. to access data.
<b>\#include</b> \<<a href="accessor_8hxx-source.html">vigra/accessor.h xx</a>\> <b>\#include</b> \<vigra/accessor.hxx\>
Namespace: vigra Namespace: vigra
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
ITERATOR iter; ITERATOR iter;
ACCESSOR a; ACCESSOR a;
VALUETYPE destvalue; VALUETYPE destvalue;
float s; float s;
int x, y; int x, y;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 iteratoradapter.hxx   iteratoradapter.hxx 
skipping to change at line 49 skipping to change at line 49
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 adpaters 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.
Here is an example policy class that just exports the behaviour Here is an example policy class that just exports the behaviour
of the underlying iterator: of the underlying iterator:
skipping to change at line 142 skipping to change at line 142
By changing the definition of the policy members, a wide range of By changing the definition of the policy members, a wide range of
adaptor behaviors can be achieved. If the base iterator isn't a adaptor behaviors can be achieved. If the base iterator isn't a
random access iterator, just drop the functions that cannot be implemen ted. random access iterator, just drop the functions that cannot be implemen ted.
This simply means that some adaptor functions may not be called, This simply means that some adaptor functions may not be called,
as one would expect from an iterator that doesn't support random access . as one would expect from an iterator that doesn't support random access .
Note also that the <TT>BaseType</TT> needs not be an iterator - Note also that the <TT>BaseType</TT> needs not be an iterator -
it can be any type that contains the information necessary for the it can be any type that contains the information necessary for the
adaptor to do it's work. adaptor to do it's work.
<b>\#include</b> \<<a href="iteratoradapter_8hxx-source.html">vigra/ite ratoradapter.hxx</a>\><br> <b>\#include</b> \<vigra/iteratoradapter.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class Policy> template <class Policy>
class IteratorAdaptor class IteratorAdaptor
{ {
public: public:
typedef typename Policy::BaseType BaseType; typedef typename Policy::BaseType BaseType;
typedef typename Policy::value_type value_type; typedef typename Policy::value_type value_type;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 iteratortraits.hxx   iteratortraits.hxx 
skipping to change at line 104 skipping to change at line 104
The member <tt>hasConstantStrides</tt> is useful for certain The member <tt>hasConstantStrides</tt> is useful for certain
optimizations: it helps to decide whether we can replace iterator optimizations: it helps to decide whether we can replace iterator
operations such as <tt>iter++</tt> or <tt>iter += n</tt> with operations such as <tt>iter++</tt> or <tt>iter += n</tt> with
corresponding pointer operations (which may be faster), where corresponding pointer operations (which may be faster), where
the pointer is obtained as the address of iterator's pointee the pointer is obtained as the address of iterator's pointee
(the object the iterator currently refers to). (the object the iterator currently refers to).
This flag would be <tt>VigraFalseType</tt> for a This flag would be <tt>VigraFalseType</tt> for a
<tt>std::list<int>::iterator</tt>, but is <tt>VigraTrueType</tt> <tt>std::list<int>::iterator</tt>, but is <tt>VigraTrueType</tt>
for most VIGRA iterators. for most VIGRA iterators.
<b>\#include</b> \<<a href="iteratortraits_8hxx-source.html">vigra/iter atortraits.hxx</a>\> <b>\#include</b> \<vigra/iteratortraits.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T> template <class T>
struct IteratorTraits struct IteratorTraits
{ {
typedef T Iterator; typedef T Iterator;
typedef Iterator iterator; typedef Iterator iterator;
typedef typename iterator::iterator_category iterator_category; typedef typename iterator::iterator_category iterator_category;
typedef typename iterator::value_type value_type; typedef typename iterator::value_type value_type;
typedef typename iterator::reference reference; typedef typename iterator::reference reference;
skipping to change at line 231 skipping to change at line 231
\endcode \endcode
or or
\code \code
vigra::copyImageIf(srcIterRange(img1.upperLeft(), img1.lowerRight()), vigra::copyImageIf(srcIterRange(img1.upperLeft(), img1.lowerRight()),
maskIter(img2.upperLeft(), MaskPredicateAccessor()), maskIter(img2.upperLeft(), MaskPredicateAccessor()),
destIter(img3.upperLeft())); destIter(img3.upperLeft()));
\endcode \endcode
All versions can be mixed freely within one explession. All versions can be mixed freely within one expression.
Technically, the argument objects are simply defined as Technically, the argument objects are simply defined as
pairs and triples of iterators and accessor so that all algorithms pairs and triples of iterators and accessor so that all algorithms
should declare a call interface version based on pairs and triples should declare a call interface version based on pairs and triples
(see for example \ref copyImageIf()). (see for example \ref copyImageIf()).
\section ImageBasedArgumentObjectFactories Image Based Argument Object Fa ctories \section ImageBasedArgumentObjectFactories Image Based Argument Object Fa ctories
<b>Include:</b> automatically included with the image classes<br> <b>Include:</b> automatically included with the image classes<br>
Namespace: vigra Namespace: vigra
skipping to change at line 421 skipping to change at line 421
</td><td> </td><td>
create argument object with upper left at point given by <tt>\ref v igra::Point2D</tt> of destination image, create argument object with upper left at point given by <tt>\ref v igra::Point2D</tt> of destination image,
and given accessor and given accessor
</td></tr> </td></tr>
</table> </table>
\section MultiArrayBasedArgumentObjectFactories MultiArrayView Based Argu ment Object Factories \section MultiArrayBasedArgumentObjectFactories MultiArrayView Based Argu ment Object Factories
<b>Include:</b> automatically included with <b>Include:</b> automatically included with
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\ ><br> \<vigra/multi_array.hxx\><br>
Namespace: vigra Namespace: vigra
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::MultiArrayView. are given instances or subclasses of \ref vigra::MultiArrayView.
These factory functions access <TT>array.traverser_begin()</TT>, These factory functions access <TT>array.traverser_begin()</TT>,
<TT>array.traverser_end()</TT> to obtain the iterators. If no accessor is <TT>array.traverser_end()</TT> to obtain the iterators. If no accessor is
given, they use the <tt>AccessorTraits<T></tt> to determine the default given, they use the <tt>AccessorTraits<T></tt> to determine the default
accessor associated with the array's value type <tt>T</tt>. accessor associated with the array's value type <tt>T</tt>.
The following factory functions are provided: The following factory functions are provided:
<table> <table>
<tr><th bgcolor="#f0e0c0" colspan=2 align=left> <tr><th bgcolor="#f0e0c0" colspan=2 align=left>
<TT>\ref vigra::MultiArrayView "vigra::MultiArrayView<N, SomeType>" array;</TT> <TT>\ref vigra::MultiArrayView "vigra::MultiArrayView<N, SomeType>" img;</TT>
</th> </th>
</tr> </tr>
<tr><td> <tr><td>
<TT>srcMultiArrayRange(img)</TT> <TT>srcMultiArrayRange(img)</TT>
</td><td> </td><td>
create argument object containing a \ref vigra::MultiIterator create argument object containing a \ref vigra::MultiIterator
marking the begin of the array, a shape object giving the desired marking the begin of the array, a shape object giving the desired
shape of the array (possibly a subarray) and the default const acce ssor for shape of the array (possibly a subarray) and the default const acce ssor for
<tt>SomeType</tt> <tt>SomeType</tt>
skipping to change at line 513 skipping to change at line 513
<TT>destMultiArray(img, SomeAccessor())</TT> <TT>destMultiArray(img, SomeAccessor())</TT>
</td><td> </td><td>
create argument object containing a \ref vigra::MultiIterator's create argument object containing a \ref vigra::MultiIterator's
marking the begin of the array and the given accessor marking the begin of the array and the given accessor
</td></tr> </td></tr>
</table> </table>
\section IteratorBasedArgumentObjectFactories Iterator Based Argument Obj ect Factories \section IteratorBasedArgumentObjectFactories Iterator Based Argument Obj ect Factories
<b>\#include</b> \<<a href="iteratortraits_8hxx-source.html">vigra/iter atortraits.hxx</a>\> <b>\#include</b> \<vigra/iteratortraits.hxx\>
Namespace: vigra Namespace: vigra
These factories can be used to create argument objects when we These factories can be used to create argument objects when we
are given \ref ImageIterators. are given \ref ImageIterators.
These factory functions use \ref vigra::IteratorTraits to These factory functions use \ref vigra::IteratorTraits to
get the default accessor for the given iterator unless the get the default accessor for the given iterator unless the
accessor is given explicitly. The following factory functions accessor is given explicitly. The following factory functions
are provided: are provided:
<table> <table>
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 labelimage.hxx   labelimage.hxx 
skipping to change at line 50 skipping to change at line 50
#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"
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 criterium 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.
skipping to change at line 117 skipping to change at line 117
without overflow. Region numbers will be a consecutive sequence without overflow. Region numbers will be a consecutive sequence
starting with one and ending with the region number returned by starting with one and ending with the region number returned by
the function (inclusive). The parameter '<TT>eight_neighbors</TT>' the function (inclusive). The parameter '<TT>eight_neighbors</TT>'
determines whether the regions should be 4-connected or determines whether the regions should be 4-connected or
8-connected. The function uses accessors. 8-connected. The function uses accessors.
Return: the number of regions found (= largest region label) Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="labelimage_8hxx-source.html">vigra/labe limage.hxx</a>\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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));
skipping to change at line 364 skipping to change at line 364
labels without overflow. Region numbers will be a consecutive labels without overflow. Region numbers will be a consecutive
sequence starting with one and ending with the region number sequence starting with one and ending with the region number
returned by the function (inclusive). The parameter returned by the function (inclusive). The parameter
'<TT>eight_neighbors</TT>' determines whether the regions should '<TT>eight_neighbors</TT>' determines whether the regions should
be 4-connected or 8-connected. The function uses accessors. be 4-connected or 8-connected. The function uses accessors.
Return: the number of regions found (= largest region label) Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="labelimage_8hxx-source.html">vigra/labe limage.hxx</a>\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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));
skipping to change at line 652 skipping to change at line 652
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> \<<a href="labelimage_8hxx-source.html">vigra/labe limage.hxx</a>\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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> (
skipping to change at line 864 skipping to change at line 864
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>SrcAccessor::value-type</TT>) must be
equality-comparable. equality-comparable.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="labelimage_8hxx-source.html">vigra/labe limage.hxx</a>\><br> <b>\#include</b> \<vigra/labelimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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),
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 labelvolume.hxx   labelvolume.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_LABELVOLUME_HXX #define VIGRA_LABELVOLUME_HXX
#include "voxelneighborhood.hxx" #include "voxelneighborhood.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "union_find.hxx" #include "union_find.hxx"
namespace vigra{ namespace vigra{
/** \addtogroup Labeling Connected Components Labeling /** \addtogroup Labeling Connected Components Labeling
The 3-dimensional connected components algorithms may use either 6 or 26 connectivity. The 3-dimensional connected components algorithms may use either 6 or 26 connectivity.
By means of a functor the merge criterium can be defined arbitrarily. By means of a functor the merge criterion can be defined arbitrarily.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* labelVolume */ /* labelVolume */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find the connected components of a segmented volume. /** \brief Find the connected components of a segmented volume.
skipping to change at line 128 skipping to change at line 128
provided that realizes the desired predicate (second form). The provided that realizes the desired predicate (second form). The
destination's value type should be large enough to hold the labels destination's value type should be large enough to hold the labels
without overflow. Region numbers will be a consecutive sequence without overflow. Region numbers will be a consecutive sequence
starting with one and ending with the region number returned by starting with one and ending with the region number returned by
the function (inclusive). the function (inclusive).
Return: the number of regions found (= largest region label) Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="labelvolume_8hxx-source.html">vigra/labelvo lume.hxx</a>\><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(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));
skipping to change at line 247 skipping to change at line 247
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 currentLabel = label.nextFreeLabel();
//queck whether there is a special border treatment to be u //check whether there is a special border treatment to be u
sed or not sed or not
AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); 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)))
skipping to change at line 272 skipping to change at line 272
++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)
{ {
/*
SrcShape s(x,y,z), sn = s + *nc;
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
fset " << *nc << ", index " << (nc).direction() << " at border " <<
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); currentLabel = label.makeUnion(label[da(xd,*nc) ], currentLabel);
} }
nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j)); nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa l(atBorder,++j));
} }
} }
da.set(label.finalizeLabel(currentLabel), xd); da.set(label.finalizeLabel(currentLabel), xd);
} }
skipping to change at line 399 skipping to change at line 409
The destination's value type should be large enough to hold the The destination's value type should be large enough to hold the
labels without overflow. Region numbers will be a consecutive labels without overflow. Region numbers will be a consecutive
sequence starting with one and ending with the region number sequence starting with one and ending with the region number
returned by the function (inclusive). returned by the function (inclusive).
Return: the number of regions found (= largest region label) Return: the number of regions found (= largest region label)
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="labelvolume_8hxx-source.html">vigra/labelvo lume.hxx</a>\><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(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);
skipping to change at line 527 skipping to change at line 537
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[0], xd);
continue; continue;
} }
LabelType currentLabel = label.nextFreeLabel(); LabelType currentLabel = label.nextFreeLabel();
//queck whether there is a special border treatment to be u //check whether there is a special border treatment to be u
sed or not sed or not
AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); 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)))
 End of changes. 6 change blocks. 
11 lines changed or deleted 24 lines changed or added


 linear_algebra.hxx   linear_algebra.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 VIGRA_LINEAR_ALGREBRA_HXX #ifndef VIGRA_LINEAR_ALGEBRA_HXX
#define VIGRA_LINEAR_ALGREBRA_HXX #define VIGRA_LINEAR_ALGEBRA_HXX
#include "matrix.hxx" #include "matrix.hxx"
#include "linear_solve.hxx" #include "linear_solve.hxx"
#include "eigensystem.hxx" #include "eigensystem.hxx"
#endif // VIGRA_LINEAR_ALGREBRA_HXX #endif // VIGRA_LINEAR_ALGEBRA_HXX
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 linear_solve.hxx   linear_solve.hxx 
skipping to change at line 506 skipping to change at line 506
maxApproxSingularValue = std::max(nv, maxApproxSingularValue); maxApproxSingularValue = std::max(nv, maxApproxSingularValue);
minApproxSingularValue = std::min(nv, minApproxSingularValue); minApproxSingularValue = std::min(nv, minApproxSingularValue);
} }
else else
{ {
incrementalMaxSingularValueApproximation(columnVector(r, Shape( 0,k),k+1), zmax, maxApproxSingularValue); incrementalMaxSingularValueApproximation(columnVector(r, Shape( 0,k),k+1), zmax, maxApproxSingularValue);
incrementalMinSingularValueApproximation(columnVector(r, Shape( 0,k),k+1), zmin, minApproxSingularValue, tolerance); incrementalMinSingularValueApproximation(columnVector(r, Shape( 0,k),k+1), zmin, minApproxSingularValue, tolerance);
} }
#if 0 #if 0
Matrix<T> u(k+1,k+1), s(k+1, 1), v(k+1,k+1); Matrix<T> u(k+1,k+1), s(k+1, 1), v(k+1,k+1);
singularValueDecomposition(r.subarray(Shape(0,0), Shape(k+1,k+1)), u, s, v); singularValueDecomposition(r.subarray(Shape(0,0), Shape(k+1,k+1)), u, s, v);
std::cerr << "estimate, svd " << k << ": " << minApproxSingularValu e << " " << s(k,0) << "\n"; std::cerr << "estimate, svd " << k << ": " << minApproxSingularValu e << " " << s(k,0) << "\n";
#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
skipping to change at line 704 skipping to change at line 704
/** \defgroup MatrixAlgebra Advanced Matrix Algebra /** \defgroup MatrixAlgebra Advanced Matrix Algebra
\brief Solution of linear systems, eigen systems, linear least squares etc. \brief Solution of linear systems, eigen systems, linear least squares etc.
\ingroup LinearAlgebraModule \ingroup LinearAlgebraModule
*/ */
//@{ //@{
/** 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, it must have more rows tha inverse of \a v. If \a v is rectangular, \a res must have the trans
n columns, and \a res posed shape
must have the transposed shape of \a v. The inverse is then compute of \a v. The inverse is then computed in the least-squares
d 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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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;
const MultiArrayIndex n = columnCount(v); const MultiArrayIndex n = columnCount(v);
vigra_precondition(n <= rowCount(v), const MultiArrayIndex m = rowCount(v);
"inverse(): input matrix must have at least as many rows as columns. vigra_precondition(n == rowCount(res) && m == columnCount(res),
");
vigra_precondition(n == rowCount(res) && rowCount(v) == columnCount(res
),
"inverse(): shape of output matrix must be the transpose of the inpu t matrix' shape."); "inverse(): shape of output matrix must be the transpose of the inpu t matrix' shape.");
Matrix<T> r(v.shape()), q(n, n); if(m < n)
if(!qrDecomposition(v, q, r)) {
return false; // a didn't have full rank MultiArrayView<2, T, StridedArrayTag> vt = transpose(v);
linearSolveUpperTriangular(r, transpose(q), res); Matrix<T> r(vt.shape()), q(n, n);
if(!qrDecomposition(vt, q, r))
return false; // a didn't have full rank
linearSolveUpperTriangular(r.subarray(Shape(0,0), Shape(m,m)),
transpose(q).subarray(Shape(0,0), Shape(
m,n)),
transpose(res));
}
else
{
Matrix<T> r(v.shape()), q(m, m);
if(!qrDecomposition(v, q, r))
return false; // a didn't have full rank
linearSolveUpperTriangular(r.subarray(Shape(0,0), Shape(n,n)),
transpose(q).subarray(Shape(0,0), Shape(
n,m)),
res);
}
return true; return true;
} }
/** Create the inverse or pseudo-inverse of matrix \a v. /** Create the inverse or pseudo-inverse of matrix \a v.
The result is returned as a temporary matrix. If the matrix \a v is square, The result is returned as a temporary matrix. If the matrix \a v is square,
the result will have the same shape and contains the inverse of \a v. the result will have the same shape and contains the inverse of \a v.
If \a v is rectangular, it must have more rows than columns, and th If \a v is rectangular, the result will have the transposed shape o
e result will f \a v.
have the transposed shape of \a v. The inverse is then computed in The inverse is then computed in the least-squares
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 inverse is computed by means of QR decomposition. If \a v The inverse is computed by means of QR decomposition. If \a v
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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 792 skipping to change at line 808
\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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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.");
for(unsigned int k=0; k<method.size(); ++k) for(unsigned int k=0; k<method.size(); ++k)
skipping to change at line 836 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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 884 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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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),
"choleskyDecomposition(): Output matrix must have sa me shape as input matrix."); "choleskyDecomposition(): Output matrix must have sa me shape as input matrix.");
vigra_precondition(isSymmetric(A), vigra_precondition(isSymmetric(A),
"choleskyDecomposition(): Input matrix must be symme tric."); "choleskyDecomposition(): Input matrix must be symme tric.");
for (MultiArrayIndex j = 0; j < n; ++j) for (MultiArrayIndex j = 0; j < n; ++j)
{ {
T d(0.0); T d(0.0);
for (MultiArrayIndex k = 0; k < j; ++k) for (MultiArrayIndex k = 0; k < j; ++k)
{ {
T s(0.0); T s(0.0);
for (MultiArrayIndex i = 0; i < k; ++i) for (MultiArrayIndex i = 0; i < k; ++i)
{ {
s += L(k, i)*L(j, i); s += L(k, i)*L(j, i);
} }
L(j, k) = s = (A(j, k) - s)/L(k, k); L(j, k) = s = (A(j, k) - s)/L(k, k);
d = d + s*s; d = d + s*s;
} }
d = A(j, j) - d; d = A(j, j) - d;
if(d <= 0.0) if(d <= 0.0)
return false; // A is not positive definite return false; // A is not positive definite
L(j, j) = std::sqrt(d); L(j, j) = std::sqrt(d);
for (MultiArrayIndex k = j+1; k < n; ++k) for (MultiArrayIndex k = j+1; k < n; ++k)
{ {
L(j, k) = 0.0; L(j, k) = 0.0;
} }
} }
return true; return true;
} }
/** QR decomposition. /** QR decomposition.
\a a contains the original matrix, results are returned in \a q and \a r, where \a a contains the original matrix, results are returned in \a q and \a r, where
\a q is a orthogonal matrix, and \a r is an upper triangular matrix , such that \a q is a orthogonal matrix, and \a r is an upper triangular matrix , such that
(up to round-off errors): (up to round-off errors):
\code \code
a == q * r; a == q * r;
\endcode \endcode
If \a a dosn'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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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) &&
skipping to change at line 991 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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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; 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),
skipping to change at line 1031 skipping to change at line 1047
/** Solve a linear system with lower-triangular coefficient matrix. /** Solve a linear system with lower-triangular coefficient matrix.
The square matrix \a l must be a lower-triangular coefficient matri x. If \a l The square matrix \a l must be a lower-triangular coefficient matri x. If \a l
doesn't have full rank the function fails and returns <tt>false</tt >, doesn't have full rank the function fails and returns <tt>false</tt >,
otherwise it returns <tt>true</tt>. The upper triangular part of ma trix \a l will not be touched, otherwise it returns <tt>true</tt>. The upper triangular part of ma trix \a l will not be touched,
so it doesn't need to contain zeros. so it doesn't need to contain zeros.
The column vectors of matrix \a b are the right-hand sides of the e quation (several equations The column vectors of matrix \a b are the right-hand sides of the e quation (several equations
with the same coefficients can thus be solved in one go). The resul t is returned with the same coefficients can thus be solved in one go). The resul t is returned
in \a x, whose columns contain the solutions for the correspoinding in \a x, whose columns contain the solutions for the corresponding
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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1079 skipping to change at line 1095
return true; return true;
} }
/** Solve a linear system when the Cholesky decomposition of the left h and side is given. /** Solve a linear system when the Cholesky decomposition of the left h and side is given.
The square matrix \a L must be a lower-triangular matrix resulting from Cholesky The square matrix \a L must be a lower-triangular matrix resulting from Cholesky
decomposition of some positive definite coefficient matrix. decomposition of some positive definite coefficient matrix.
The column vectors of matrix \a b are the right-hand sides of the e quation (several equations The column vectors of matrix \a b are the right-hand sides of the e quation (several equations
with the same matrix \a L can thus be solved in one go). The result is returned with the same matrix \a L can thus be solved in one go). The result is returned
in \a x, whose columns contain the solutions for the correspoinding in \a x, whose columns contain the solutions for the corresponding
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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> & L, MultiArrayView<2, T, C2> c onst & 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);
skipping to change at line 1149 skipping to change at line 1165
(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> \<<a href="linear__solve_8hxx-source.html">vigra/linea <b>\#include</b> \<vigra/linear_solve.hxx\> or<br>
r_solve.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 linearSolve(const MultiArrayView<2, T, C1> &A, const MultiArrayView<2, T, C2> &b, bool linearSolve(const MultiArrayView<2, T, C1> &A, const MultiArrayView<2, T, C2> &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>::difference_type Shape;
typedef typename Matrix<T>::view_type SubMatrix; typedef typename Matrix<T>::view_type SubMatrix;
const MultiArrayIndex n = columnCount(A); const MultiArrayIndex n = columnCount(A);
skipping to change at line 1192 skipping to change at line 1208
{ {
return (MultiArrayIndex)linearSolveQR(A, b, res) == n; return (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 = (MultiArrayIndex)singularValueDecomposition( 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();
 End of changes. 24 change blocks. 
66 lines changed or deleted 60 lines changed or added


 localminmax.hxx   localminmax.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 1998-2002 by Ullrich Koethe */ /* Copyright 1998-2010 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 45 skipping to change at line 45
#ifndef VIGRA_LOCALMINMAX_HXX #ifndef VIGRA_LOCALMINMAX_HXX
#define VIGRA_LOCALMINMAX_HXX #define VIGRA_LOCALMINMAX_HXX
#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 "pixelneighborhood.hxx" #include "pixelneighborhood.hxx"
#include "voxelneighborhood.hxx"
namespace vigra { namespace vigra
{
/** \addtogroup LocalMinMax Local Minima and Maxima /** \addtogroup LocalMinMax Local Minima and Maxima
Detect local minima and maxima of the gray level, Detect local minima and maxima in a gray level image,
including extremal plateaus larger than 1 pixel including extremal plateaus larger than 1 pixel
*/ */
//@{ //@{
namespace detail { namespace detail {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class Neighborhood,
class Compare>
inline bool
isLocalExtremum(SrcIterator is, SrcAccessor sa, Neighborhood,
typename SrcAccessor::value_type threshold,
Compare compare, AtImageBorder atBorder)
{
typename SrcAccessor::value_type v = sa(is);
if(!compare(v, threshold))
return false;
int directionCount = Neighborhood::nearBorderDirectionCount(atBorder);
RestrictedNeighborhoodCirculator<SrcIterator, Neighborhood> sc(is, atBo
rder);
for(int i = 0; i < directionCount; ++i, ++sc)
{
if(!compare(v, sa(sc)))
return false;
}
return true;
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue, class Neighborhood, class DestValue, class Neighborhood,
class Compare> class Compare>
void void
localMinMax(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMinMax(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker, Neighborhood, DestValue marker, Neighborhood neighborhood,
Compare compare) typename SrcAccessor::value_type threshold,
Compare compare,
bool allowExtremaAtBorder = false)
{ {
int w = slr.x - sul.x - 2; int w = slr.x - sul.x;
int h = slr.y - sul.y - 2; int h = slr.y - sul.y;
int i,x,y; int x, y;
if(allowExtremaAtBorder)
{
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;
h -= 2;
sul += Diff2D(1,1); sul += Diff2D(1,1);
dul += Diff2D(1,1); dul += Diff2D(1,1);
for(y=0; y<h; ++y, ++sul.y, ++dul.y) for(y=0; y<h; ++y, ++sul.y, ++dul.y)
{ {
SrcIterator sx = sul; SrcIterator sx = sul;
DestIterator dx = dul; DestIterator dx = dul;
for(x=0; x<w; ++x, ++sx.x, ++dx.x) for(x=0; x<w; ++x, ++sx.x, ++dx.x)
{ {
typename SrcAccessor::value_type v = sa(sx); typename SrcAccessor::value_type v = sa(sx);
if(!compare(v, threshold))
continue;
int i;
NeighborhoodCirculator<SrcIterator, Neighborhood> sc(sx); NeighborhoodCirculator<SrcIterator, Neighborhood> sc(sx);
for(i = 0; i < Neighborhood::DirectionCount; ++i, ++sc) for(i = 0; i < Neighborhood::DirectionCount; ++i, ++sc)
{ {
if(!compare(v, sa(sc))) if(!compare(v, sa(sc)))
break; break;
} }
if(i == Neighborhood::DirectionCount) if(i == Neighborhood::DirectionCount)
da.set(marker, dx); da.set(marker, dx);
} }
} }
} }
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue,
class Neighborhood, class Compare>
void
localMinMax3D(SrcIterator sul, SrcShape shp, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker,
Neighborhood neighborhood,
typename SrcAccessor::value_type threshold,
Compare compare,
bool allowExtremaAtBorder = false)
{
int w = shp[0];
int h = shp[1];
int d = shp[2];
int x, y, z;
if (allowExtremaAtBorder)
{
throw std::runtime_error("not implemented!");
/*
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;
h -= 2;
d -= 2;
sul.dim0() += 1;
sul.dim1() += 1;
sul.dim2() += 1;
dul += Diff3D(1, 1, 1);
SrcIterator zs = sul;
DestIterator zd = dul;
for (z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2())
{
SrcIterator ys(zs);
DestIterator yd(zd);
for (y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1())
{
SrcIterator xs(ys);
DestIterator xd(yd);
for (x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
{
typename SrcAccessor::value_type v = sa(xs);
if (!compare(v, threshold))
continue;
int i;
NeighborhoodCirculator<SrcIterator, Neighborhood> sc(xs);
for (i = 0; i < Neighborhood::DirectionCount; ++i, ++sc)
{
if(!compare(v, sa(sc)))
break;
}
if(i == Neighborhood::DirectionCount)
da.set(marker, xd);
}
}
}
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue,
class Neighborhood, class Compare, class Equal>
void
extendedLocalMinMax(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(isExtremum[lab] == 0)
continue;
if(!compare(v, threshold))
{
// mark all regions that don't exceed the threshold as non-
extremum
isExtremum[lab] = 0;
continue;
}
AtImageBorder atBorder = isAtImageBorder(x, y, w, h);
if(atBorder == NotAtBorder)
{
NeighborhoodCirculator<SrcIterator, Neighborhood> sc(sx);
NeighborhoodCirculator<BasicImage<int>::traverser, Neighbor
hood> lc(lx);
for(i=0; i<Neighborhood::DirectionCount; ++i, ++sc, ++lc)
{
if(lab != *lc && compare(sa(sc),v))
{
isExtremum[lab] = 0;
break;
}
}
}
else
{
if(allowExtremaAtBorder)
{
RestrictedNeighborhoodCirculator<SrcIterator, Neighborh
ood>
sc(sx, atBor
der), scend(sc);
do
{
if(lab != *(lx+sc.diff()) && compare(sa(sc),v))
{
isExtremum[lab] = 0;
break;
}
}
while(++sc != scend);
}
else
{
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);
}
}
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue,
class Neighborhood, class Compare, class Equal>
void
extendedLocalMinMax3D(SrcIterator sul, SrcShape shp, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker,
Neighborhood neighbourhood,
Compare compare,
Equal equal,
typename SrcAccessor::value_type threshold,
bool allowExtremaAtBorder = false)
{
typedef typename SrcAccessor::value_type SrcType;
int w = shp[0];
int h = shp[1];
int d = shp[2];
int i, x, y, z;
MultiArray<3, int> labels(shp);
int number_of_regions =
labelVolume(sul, shp, sa, labels.traverser_begin(),
typename AccessorTraits<int>::default_accessor(),
neighbourhood);
MultiArray<3, int>::traverser zl(labels.traverser_begin());
SrcIterator zs = sul;
DestIterator zd = dul;
// assume that a region is a extremum until the opposite is proved
std::vector<unsigned char> isExtremum(number_of_regions + 1, (unsigned
char)1);
for (z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2(), ++zl.dim2())
{
SrcIterator ys(zs);
DestIterator yd(zd);
MultiArray<3, int>::traverser yl(zl);
for (y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1(), ++yl.dim1())
{
SrcIterator xs(ys);
DestIterator xd(yd);
MultiArray<3, int>::traverser xl(yl);
for (x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0(), ++xl.dim0())
{
int lab = *xl;
SrcType v = sa(xs);
if (isExtremum[lab] == 0)
continue;
if (!compare(v, threshold))
{
// mark all regions that don't exceed the threshold as
non-extremum
isExtremum[lab] = 0;
continue;
}
AtVolumeBorder atBorder = isAtVolumeBorder(x, y, z, w, h, d
);
if (atBorder == NotAtBorder)
{
NeighborhoodCirculator<SrcIterator, Neighborhood> sc(xs
);
NeighborhoodCirculator<MultiArray<3, int>::traverser, N
eighborhood> lc(xl);
for (i = 0; i < Neighborhood::DirectionCount; ++i, ++sc
, ++lc)
{
if (lab != *lc && compare(sa(sc), v))
{
isExtremum[lab] = 0;
break;
}
}
}
else
{
if (allowExtremaAtBorder)
{
RestrictedNeighborhoodCirculator<SrcIterator, Neigh
borhood>
sc(xs, atBorder), scend(sc);
do
{
if (lab != *(xl + sc.diff()) && compare(sa(sc),
v))
{
isExtremum[lab] = 0;
break;
}
}
while (++sc != scend);
}
else
{
isExtremum[lab] = 0;
}
}
}
}
}
zl = labels.traverser_begin();
zs = sul;
zd = dul;
for (z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2(), ++zl.dim2())
{
SrcIterator ys(zs);
DestIterator yd(zd);
MultiArray<3, int>::traverser yl(zl);
for (y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1(), ++yl.dim1())
{
SrcIterator xs(ys);
DestIterator xd(yd);
MultiArray<3, int>::traverser xl(yl);
for (x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0(), ++xl.dim0())
{
if(isExtremum[*xl])
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().
<b> Usage:</b>
<b>\#include</b> \<vigra/localminmax.hxx\><br>
Namespace: vigra
\code
vigra::BImage src(w,h), minima(w,h);
... // fill src
// use 4-neighborhood, allow minima at the image border,
// and discard those where the gray value is not below 5
vigra::localMinima(srcImageRange(src), destImage(minima),
vigra::LocalMinmaxOptions().neighborhood(4).allowAtB
order().threshold(5));
\endcode
*/
class LocalMinmaxOptions
{
public:
double marker, thresh;
int neigh;
bool use_threshold, allow_at_border, allow_plateaus;
/**\brief Construct default options object.
*
Defaults are: marker value '1', no threshold, indirect neighbor
hood,
don't allow extrema at border and extremal platea
us.
*/
LocalMinmaxOptions()
: marker(1.0),
thresh(0.0),
neigh(1),
use_threshold(false),
allow_at_border(false),
allow_plateaus(false)
{}
/**\brief Use the given neighborhood.
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'
indicates indirect neighborhood (i.e. 8-neighborhood in 2D,
26-neighborhood in 3D, 3<sup>N</sup>-1 neighborhood in N-D). Th
e specific number
of neighbors for the desired dimension can also be used.
Default: 1 (indirect neighborhood)
*/
LocalMinmaxOptions & neighborhood(unsigned int n)
{
neigh = n;
return *this;
}
/**\brief Mark extrema in the destination image with the given valu
e.
Default: 1
*/
LocalMinmaxOptions & markWith(double m)
{
marker = m;
return *this;
}
/**\brief Threshold the extrema.
Discard minima whose gray value is not below the threshold.
and maxima whose gray level is not above the threshold.
Default: don't threshold (i.e. return all extrema)
*/
LocalMinmaxOptions & threshold(double t)
{
use_threshold = true;
thresh = t;
return *this;
}
/**\brief Detect extrema at the image border.
Default: false
*/
LocalMinmaxOptions & allowAtBorder(bool f = true)
{
allow_at_border = f;
return *this;
}
/**\brief Allow extremal plateaus.
That is regions of constant gray value whose neighbors are all
higher (minima) or lower than the value of the region.
Default: false
*/
LocalMinmaxOptions & allowPlateaus(bool f = true)
{
allow_plateaus = f;
return *this;
}
};
/********************************************************/ /********************************************************/
/* */ /* */
/* localMinima */ /* localMinima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local minima in an image. /** \brief Find local minima in an image or multi-dimensional array.
The minima are found only when the have a size of one pixel. Note: the function is not yet implemented for arbitrary dimensional
Use \ref extendedLocalMinima() to find minimal plateaus. Minima are arrays, but see \ref localMinima3D() for 3D.
marked in the destination image with the given marker value
(default is 1), all other destination pixels remain unchanged. By default, minima are defined as points which are not
<TT>SrcAccessor::value_type</TT> must be less-comparable. at the array border and whose value is lower than the value
A pixel at the image border will never be marked as minimum. of all indirect neighbors (i.e. 8-neighbors in 2D,
Pass \ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode 26-neighbors in 3D, 3<sup>N</sup>-1 neighbors in N-D).
to determine the neighborhood where pixel values are compared. The detected points will be marked
The function uses accessors. with the default value 1 in the destination array.
The defaults can be overridden in various ways by providing
\ref LocalMinmaxOptions : you can switch to the direct neighborhood
(i.e. 4-neighborhood in 2D, 6-neighborhood in 3D, 2*N neighborhood
in N-D), allow minima at the border, discard minima where the function
value is not below a given threshold, allow extended minima
(i.e. minima that form minimal plateaus rather than isolated pixels --
note that this option is only supported for 2D images),
and change the marker in the destination image. See usage examples belo
w
for details.
There are also variants of the localMinima() function where parameters
are passed explicitly rather than via an option object. These versions
of the function are deprecated, but will be kept for compatibility.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use arbitrary-dimensional arrays:
\code
namespace vigra {
template <unsigned int N, class T1, class C1, class T2, class C2>
void
localMinima(MultiArrayView<N, T1, C1> src,
MultiArrayView<N, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions
());
}
\endcode
pass image iterators explicitly:
\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 Neighborhood = EightNeighborCode>
void void
localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker = NumericTraits<DestValue>::one(), LocalMinmaxOptions const & options = LocalMinmaxOptions
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 DestValue = DestAccessor::value_type,
class Neighborhood = EightNeighborCode>
void void
localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker = NumericTraits<DestValue>::one(), LocalMinmaxOptions const & options = LocalMinmaxOptions
Neighborhood neighborhood = EightNeighborCode()) ());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="localminmax_8hxx-source.html">vigra/loc <b>\#include</b> \<vigra/localminmax.hxx\><br>
alminmax.hxx</a>\><br> <b>\#include</b> \<vigra/multi_localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(w,h), minima(w,h); // 3D examples using MultiArray
vigra::MultiArrayShape<3>::type shape(w,h,d);
vigra::MultiArray<3, unsigned char> src(shape), minima(shape);
... // fill src
// init destiniation image // use default parameterisation
vigra::localMinima(src, minima);
// reset destination image
minima = 0; minima = 0;
// use 6-neighborhood and allow minima at the image border
vigra::localMinima(src, minima,
vigra::LocalMinmaxOptions().neighborhood(6).allowAtB
order());
\endcode
\code
// 2D examples using BasicImage
vigra::BImage src(w,h), minima(w,h);
... // fill src
// use default parameterisation
vigra::localMinima(srcImageRange(src), destImage(minima)); vigra::localMinima(srcImageRange(src), destImage(minima));
// reset destination image
minima = 0;
// use 4-neighborhood and allow minima at the image border
vigra::localMinima(srcImageRange(src), destImage(minima),
vigra::LocalMinmaxOptions().neighborhood(4).allowAtB
order());
// reset destination image
minima = 0;
// allow extended minima (minimal plateaus) and use value '255' as a ma
rker
vigra::localMinima(srcImageRange(src), destImage(minima),
vigra::LocalMinmaxOptions().allowPlateaus().markWith
(255));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestImageIterator 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
DestValue marker;
dest_accessor.set(marker, dest_upperleft);
\endcode \endcode
*/ */
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>
inline void
localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
LocalMinmaxOptions const & options = LocalMinmaxOptions())
{
typedef typename SrcAccessor::value_type SrcType;
typedef typename DestAccessor::value_type DestType;
SrcType threshold = options.use_threshold
? std::min(NumericTraits<SrcType>::max(), (SrcTy
pe)options.thresh)
: NumericTraits<SrcType>::max();
DestType marker = (DestType)options.marker;
if(options.allow_plateaus)
{
if(options.neigh == 0 || options.neigh == 4)
{
detail::extendedLocalMinMax(sul, slr, sa, dul, da, marker, Four
NeighborCode(),
std::less<SrcType>(), std::equal_to
<SrcType>(),
threshold, options.allow_at_border)
;
}
else if(options.neigh == 1 || options.neigh == 8)
{
detail::extendedLocalMinMax(sul, slr, sa, dul, da, marker, Eigh
tNeighborCode(),
std::less<SrcType>(), std::equal_to
<SrcType>(),
threshold, options.allow_at_border)
;
}
else
vigra_precondition(false, "localMinima(): neighborhood must be
4 or 8.");
}
else
{
if(options.neigh == 0 || options.neigh == 4)
{
detail::localMinMax(sul, slr, sa, dul, da, marker, FourNeighbor
Code(),
threshold, std::less<SrcType>(), options.al
low_at_border);
}
else if(options.neigh == 1 || options.neigh == 8)
{
detail::localMinMax(sul, slr, sa, dul, da, marker, EightNeighbo
rCode(),
threshold, std::less<SrcType>(), options.al
low_at_border);
}
else
vigra_precondition(false, "localMinima(): neighborhood must be
4 or 8.");
}
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue, class Neighborhood> class DestValue>
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,
DestValue marker, Neighborhood neighborhood) DestValue marker, FourNeighborCode neighborhood)
{ {
detail::localMinMax(sul, slr, sa, dul, da, marker, neighborhood, detail::localMinMax(sul, slr, sa, dul, da, marker, neighborhood,
std::less<typename SrcAccessor::value_type>()); NumericTraits<typename SrcAccessor::value_type>::ma
x(),
std::less<typename SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class DestValue>
inline void
localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker, EightNeighborCode neighborhood)
{
detail::localMinMax(sul, slr, sa, dul, da, marker, neighborhood,
NumericTraits<typename SrcAccessor::value_type>::ma
x(),
std::less<typename SrcAccessor::value_type>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
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,
DestValue marker) DestValue marker)
{ {
localMinima(sul, slr, sa, dul, da, marker, EightNeighborCode()); localMinima(sul, slr, sa, dul, da, marker, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor,
class DestValue>
inline void inline void
localMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
DestIterator dul, DestAccessor da) pair<DestIterator, DestAccessor> dest,
DestValue marker, FourNeighborCode neighborhood)
{ {
localMinima(sul, slr, sa, dul, da, localMinima(src.first, src.second, src.third,
NumericTraits<typename DestAccessor::value_type>::one(), dest.first, dest.second, marker, neighborhood);
EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue, class Neighborhood> class DestValue>
inline void inline void
localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, Neighborhood neighborhood) DestValue marker, EightNeighborCode neighborhood)
{ {
localMinima(src.first, src.second, src.third, localMinima(src.first, src.second, src.third,
dest.first, dest.second, marker, neighborhood); dest.first, dest.second, marker, neighborhood);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker) DestValue marker)
{ {
localMinima(src.first, src.second, src.third, localMinima(src.first, src.second, src.third,
dest.first, dest.second, marker, EightNeighborCode()); dest.first, dest.second, marker, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline 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())
{ {
localMinima(src.first, src.second, src.third, localMinima(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second, options);
NumericTraits<typename DestAccessor::value_type>::one(),
EightNeighborCode());
} }
/**************************************************************************
/
/********************************************************/
/* */
/* localMinima3D */
/* */
/********************************************************/
/** \brief Find local minima in a 3D multi array.
By default, minima are defined as points which are not
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)
template<class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor, class DestValue>
inline void
localMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker,
NeighborCode3DTwentySix neighborhood)
{
detail::localMinMax3D(sul, slr, sa, dul, da, marker, neighborhood,
NumericTraits<typename SrcAccessor::value_type>::max(),
std::less<typename SrcAccessor::value_type>());
}
template<class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor, class DestValue>
inline void
localMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker,
NeighborCode3DSix neighborhood)
{
detail::localMinMax3D(sul, slr, sa, dul, da, marker, neighborhood,
NumericTraits<typename SrcAccessor::value_type>::max(),
std::less<typename SrcAccessor::value_type>());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue>
inline void
localMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker)
{
localMinima3D(sul, slr, sa, dul, da, marker, NeighborCode3DSix());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue>
inline void
localMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
DestValue marker,
NeighborCode3DSix neighborhood)
{
localMinima3D(src.first, src.second, src.third, dest.first, dest.second
,
marker, neighborhood);
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue>
inline void
localMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
DestValue marker,
NeighborCode3DTwentySix neighborhood)
{
localMinima3D(src.first, src.second, src.third, dest.first, dest.second
,
marker, neighborhood);
}
/**************************************************************************
/
/********************************************************/ /********************************************************/
/* */ /* */
/* localMaxima */ /* localMaxima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local maxima in an image. /** \brief Find local maxima in an image or multi-dimensional array.
The maxima are found only when the have a size of one pixel. Note: the function is not yet implemented for arbitrary dimensional
Use \ref extendedLocalMaxima() to find maximal plateaus. Maxima are arrays, but see \ref localMaxima3D() for 3D.
marked in the destination image with the given marker value
(default is 1), all other destination pixels remain unchanged. By default, maxima are defined as points which are not
<TT>SrcAccessor::value_type</TT> must be less-comparable. at the array border and whose value is higher than the value
A pixel at the image border will never be marked as maximum. of all indirect neighbors (i.e. 8-neighbors in 2D,
The function uses accessors. 26-neighbors in 3D, 3<sup>N</sup>-1 neighbors in N-D).
The detected points will be marked
with the default value 1 in the destination array.
The defaults can be overridden in various ways by providing
\ref LocalMinmaxOptions : you can switch to the direct neighborhood
(i.e. 4-neighborhood in 2D, 6-neighborhood in 3D, 2*N neighborhood
in N-D), allow maxima at the border, discard maxima where the function
value is not above a given threshold, allow extended maxima
(i.e. maxima that form maximal plateaus rather than isolated pixels --
note that this option is only supported for 2D images),
and change the marker in the destination image. See usage examples belo
w
for details.
There are also variants of the localMaxima() function where parameters
are passed explicitly rather than via an option object. These versions
of the function are deprecated, but will be kept for compatibility.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use arbitrary-dimensional arrays:
\code
namespace vigra {
template <unsigned int N, class T1, class C1, class T2, class C2>
void
localMaxima(MultiArrayView<N, T1, C1> src,
MultiArrayView<N, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinmaxOptions
());
}
\endcode
pass image iterators explicitly:
\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 Neighborhood = EightNeighborCode>
void void
localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestIterator dul, DestAccessor da,
DestValue marker = NumericTraits<DestValue>::one(), LocalMinmaxOptions const & options = LocalMinmaxOptions
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 DestValue = DestAccessor::value_type,
class Neighborhood = EightNeighborCode>
void void
localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker = NumericTraits<DestValue>::one(), LocalMinmaxOptions const & options = LocalMinmaxOptions
Neighborhood neighborhood = EightNeighborCode()) ());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="localminmax_8hxx-source.html">vigra/loc <b>\#include</b> \<vigra/localminmax.hxx\><br>
alminmax.hxx</a>\><br> <b>\#include</b> \<vigra/multi_localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::BImage src(w,h), maxima(w,h); // 3D examples using MultiArray
vigra::MultiArrayShape<3>::type shape(w,h,d);
vigra::MultiArray<3, unsigned char> src(shape), maxima(shape);
... // fill src
// init destiniation image // use default parameterisation
vigra::localMaxima(src, maxima);
// reset destination image
maxima = 0; maxima = 0;
// use 6-neighborhood and allow maxima at the image border
vigra::localMaxima(src, maxima,
vigra::LocalMinmaxOptions().neighborhood(6).allowAtB
order());
\endcode
\code
// 2D examples using BasicImage
vigra::BImage src(w,h), maxima(w,h);
... // fill src
// use default parameterisation
vigra::localMaxima(srcImageRange(src), destImage(maxima)); vigra::localMaxima(srcImageRange(src), destImage(maxima));
// reset destination image
maxima = 0;
// use 4-neighborhood and allow maxima at the image border
vigra::localMaxima(srcImageRange(src), destImage(maxima),
vigra::LocalMinmaxOptions().neighborhood(4).allowAtB
order());
// reset destination image
maxima = 0;
// allow extended maxima (maximal plateaus) and use value '255' as a ma
rker
vigra::localMaxima(srcImageRange(src), destImage(maxima),
vigra::LocalMinmaxOptions().allowPlateaus().markWith
(255));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestImageIterator 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
DestValue marker;
dest_accessor.set(marker, dest_upperleft);
\endcode \endcode
*/ */
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>
inline void
localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
LocalMinmaxOptions const & options = LocalMinmaxOptions())
{
typedef typename SrcAccessor::value_type SrcType;
typedef typename DestAccessor::value_type DestType;
SrcType threshold = options.use_threshold
? std::max(NumericTraits<SrcType>::min(), (SrcTy
pe)options.thresh)
: NumericTraits<SrcType>::min();
DestType marker = (DestType)options.marker;
if(options.allow_plateaus)
{
if(options.neigh == 0 || options.neigh == 4)
{
detail::extendedLocalMinMax(sul, slr, sa, dul, da, marker, Four
NeighborCode(),
std::greater<SrcType>(), std::equal
_to<SrcType>(),
threshold, options.allow_at_border)
;
}
else if(options.neigh == 1 || options.neigh == 8)
{
detail::extendedLocalMinMax(sul, slr, sa, dul, da, marker, Eigh
tNeighborCode(),
std::greater<SrcType>(), std::equal
_to<SrcType>(),
threshold, options.allow_at_border)
;
}
else
vigra_precondition(false, "localMaxima(): neighborhood must be
4 or 8.");
}
else
{
if(options.neigh == 0 || options.neigh == 4)
{
detail::localMinMax(sul, slr, sa, dul, da, marker, FourNeighbor
Code(),
threshold, std::greater<SrcType>(), options
.allow_at_border);
}
else if(options.neigh == 1 || options.neigh == 8)
{
detail::localMinMax(sul, slr, sa, dul, da, marker, EightNeighbo
rCode(),
threshold, std::greater<SrcType>(), options
.allow_at_border);
}
else
vigra_precondition(false, "localMaxima(): neighborhood must be
4 or 8.");
}
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue, class Neighborhood> class DestValue>
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,
DestValue marker, Neighborhood neighborhood) DestValue marker, FourNeighborCode neighborhood)
{ {
detail::localMinMax(sul, slr, sa, dul, da, marker, neighborhood, detail::localMinMax(sul, slr, sa, dul, da, marker, neighborhood,
std::greater<typename SrcAccessor::value_type>()); NumericTraits<typename SrcAccessor::value_type>::mi
n(),
std::greater<typename SrcAccessor::value_type>());
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class DestValue>
inline void
localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
DestValue marker, EightNeighborCode neighborhood)
{
detail::localMinMax(sul, slr, sa, dul, da, marker, neighborhood,
NumericTraits<typename SrcAccessor::value_type>::mi
n(),
std::greater<typename SrcAccessor::value_type>());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
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,
DestValue marker) DestValue marker)
{ {
localMaxima(sul, slr, sa, dul, da, marker, EightNeighborCode()); localMaxima(sul, slr, sa, dul, da, marker, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor,
class DestValue>
inline void inline void
localMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
DestIterator dul, DestAccessor da) pair<DestIterator, DestAccessor> dest,
DestValue marker, FourNeighborCode neighborhood)
{ {
localMaxima(sul, slr, sa, dul, da, localMaxima(src.first, src.second, src.third,
NumericTraits<typename DestAccessor::value_type>::one(), dest.first, dest.second, marker, neighborhood);
EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestIterator, class DestAccessor,
class DestValue, class Neighborhood> class DestValue>
inline void inline void
localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, Neighborhood neighborhood) DestValue marker, EightNeighborCode neighborhood)
{ {
localMaxima(src.first, src.second, src.third, localMaxima(src.first, src.second, src.third,
dest.first, dest.second, marker, neighborhood); dest.first, dest.second, marker, neighborhood);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor, class DestValue>
inline void inline void
localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, localMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker) DestValue marker)
{ {
localMaxima(src.first, src.second, src.third, localMaxima(src.first, src.second, src.third,
dest.first, dest.second, marker, EightNeighborCode()); dest.first, dest.second, marker, EightNeighborCode());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
inline void inline 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())
{ {
localMaxima(src.first, src.second, src.third, localMaxima(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second, options);
NumericTraits<typename DestAccessor::value_type>::one(),
EightNeighborCode());
} }
namespace detail { /**************************************************************************
/
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue,
class Neighborhood, class Compare, class Equal>
void
extendedLocalMinMax(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestValue marker,
Neighborhood /*neighborhood*/, Compare compare, Equal equal)
{
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); /* localMaxima3D */
/* */
/********************************************************/
BasicImage<int>::traverser ly = labels.upperLeft(); /** \brief Find local maxima in a 3D multi array.
for(y=0; y<h; ++y, ++sul.y, ++ly.y) By default, maxima are defined as points which are not
{ at the array border and whose value is higher than the value
SrcIterator sx = sul; of all indirect neighbors.
BasicImage<int>::traverser lx(ly); The detected points will be marked as specified. See localMaxima() for mor
details.
*/
doxygen_overloaded_function(template <...> void localMaxima3D)
for(x=0; x<w; ++x, ++sx.x, ++lx.x) template<class SrcIterator, class SrcShape, class SrcAccessor,
{ class DestIterator, class DestAccessor, class DestValue>
int lab = *lx; inline void
if(x == 0 || y == 0 || x == w-1 || y == h-1) localMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
{ DestIterator dul, DestAccessor da,
// mark all regions that touch the image border as non-extr DestValue marker,
emum NeighborCode3DSix neighborhood)
isExtremum[lab] = 0; {
continue; detail::localMinMax3D(sul, slr, sa, dul, da, marker, neighborhood,
} NumericTraits<typename SrcAccessor::value_type>::min(),
std::greater<typename SrcAccessor::value_type>());
}
SrcType v = sa(sx); template<class SrcIterator, class SrcShape, class SrcAccessor,
NeighborhoodCirculator<SrcIterator, Neighborhood> sc(sx); class DestIterator, class DestAccessor, class DestValue>
NeighborhoodCirculator<BasicImage<int>::traverser, Neighborhood inline void
> lc(lx); localMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
for(i=0; i<Neighborhood::DirectionCount; ++i, ++sc, ++lc) DestIterator dul, DestAccessor da,
{ DestValue marker,
if(lab != *lc && compare(sa(sc),v)) NeighborCode3DTwentySix neighborhood)
isExtremum[lab] = 0; {
} detail::localMinMax3D(sul, slr, sa, dul, da, marker, neighborhood,
NumericTraits<typename SrcAccessor::value_type>::min(),
std::greater<typename SrcAccessor::value_type>());
}
} template<class SrcIterator, class SrcShape, class SrcAccessor,
} class DestIterator, class DestAccessor, class DestValue>
inline void
localMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
DestValue marker,
NeighborCode3DTwentySix neighborhood)
{
localMaxima3D(src.first, src.second, src.third, dest.first, dest.second
,
marker, neighborhood);
}
ly = labels.upperLeft(); template<class SrcIterator, class SrcShape, class SrcAccessor,
for(y=0; y<h; ++y, ++dul.y, ++ly.y) class DestIterator, class DestAccessor, class DestValue>
{ inline void
DestIterator xd = dul; localMaxima3D(vigra::triple<SrcIterator, SrcShape, SrcAccessor> src,
BasicImage<int>::Iterator lx(ly); std::pair<DestIterator, DestAccessor> dest,
DestValue marker)
{
localMaxima3D(src.first, src.second, src.third, dest.first, dest.second
,
marker, NeighborCode3DSix());
}
for(x=0; x<w; ++x, ++xd.x, ++lx.x) template<class SrcIterator, class SrcShape, class SrcAccessor,
{ class DestIterator, class DestAccessor, class DestValue>
if(isExtremum[*lx]) inline void
da.set(marker, xd); localMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
} pair<DestIterator, DestAccessor> dest,
} DestValue marker,
NeighborCode3DSix neighborhood)
{
localMaxima3D(src.first, src.second, src.third, dest.first, dest.second
,
marker, neighborhood);
} }
} // namespace detail /************************************************************************** /
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMinima */ /* extendedLocalMinima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local minimal regions in an image. /** \brief Find local minimal regions in an image or volume.
Note: the function is not yet implemented for arbitrary dimensional
arrays, but see \ref extendedLocalMinima3D() for 3D.
This function finds regions of uniform pixel value This function finds regions of uniform pixel value
whose neighboring regions are all have smaller values whose neighboring regions are all have smaller values
(minimal plateaus of arbitrary size). By default, the pixels (minimal plateaus of arbitrary size). By default, the pixels
in a plateau have exactly identical values. By passing an <tt>EqualityF unctor</tt> in a plateau have exactly identical values. By passing an <tt>EqualityF unctor</tt>
with tolerance, one can allow for plateaus that are not quite constant with tolerance, one can allow for plateaus that are not quite constant
(this is often necessary with float pixel values). Pass (this is often necessary with float pixel values). Pass
\ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode \ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode
to determine the neighborhood where pixel values are compared. to determine the neighborhood where pixel values are compared.
Minimal regions are Minimal regions are
marked in the destination image with the given marker value marked in the destination image with the given marker value
(default is 1), all other destination pixels remain unchanged. (default is 1), all other destination pixels remain unchanged.
<TT>SrcAccessor::value_type</TT> must be equality-comparable and <TT>SrcAccessor::value_type</TT> must be equality-comparable and
less-comparable. less-comparable. A pixel or region touching the image border will
A pixel or region touching the image border will never be marked as min never be marked as minimum or minimal plateau. Use localMinima() with t
imum or he
minimal plateau. 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. The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use 3-dimensional arrays:
\code
namespace vigra {
template <class T1, class C1, class T2, class C2,
class Neighborhood>
void
extendedLocalMinima(MultiArrayView<3, T1, C1> src,
MultiArrayView<3, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinma
xOptions());
\endcode
pass image iterators explicitly:
\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());
} }
\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());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="localminmax_8hxx-source.html">vigra/loc alminmax.hxx</a>\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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)
skipping to change at line 594 skipping to change at line 1512
u < u u < u
DestValue marker; DestValue marker;
dest_accessor.set(marker, dest_upperleft); dest_accessor.set(marker, dest_upperleft);
\endcode \endcode
*/ */
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 DestValue, 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, DestValue marker, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood, EqualityFunctor equal) Neighborhood neighborhood, EqualityFunctor equal)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
detail::extendedLocalMinMax(sul, slr, sa, dul, da, detail::extendedLocalMinMax(sul, slr, sa, dul, da,
marker, neighborhood, marker, neighborhood,
std::less<SrcType>(), equal); std::less<SrcType>(), equal,
NumericTraits<typename SrcAccessor::value_t
ype>::max());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
inline void inline void
extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMinima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestValue marker, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood) Neighborhood neighborhood)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
extendedLocalMinima(sul, slr, sa, dul, da, extendedLocalMinima(sul, slr, sa, dul, da,
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 DestValue> 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, DestValue marker) DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker)
{ {
typedef typename SrcAccessor::value_type SrcType; 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)
{ {
extendedLocalMinima(sul, slr, sa, dul, da, extendedLocalMinima(sul, slr, sa, dul, da,
NumericTraits<typename DestAccessor::value_type>::one()); NumericTraits<typename DestAccessor::value_type>::one());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue, class DestIterator, class DestAccessor,
class Neighborhood, class EqualityFunctor> class Neighborhood, class EqualityFunctor>
inline void inline void
extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, Neighborhood neighborhood, typename DestAccessor::value_type marker, Neighborhood neighbor hood,
EqualityFunctor equal) EqualityFunctor equal)
{ {
extendedLocalMinima(src.first, src.second, src.third, extendedLocalMinima(src.first, src.second, src.third,
dest.first, dest.second, marker, neighborhood, equal); dest.first, dest.second, marker, neighborhood, equal);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
inline void inline void
extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, Neighborhood neighborhood) typename DestAccessor::value_type marker, Neighborhood neighbor hood)
{ {
extendedLocalMinima(src.first, src.second, src.third, extendedLocalMinima(src.first, src.second, src.third,
dest.first, dest.second, marker, neighborhood); dest.first, dest.second, marker, neighborhood);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor>
inline void inline void
extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker) typename DestAccessor::value_type marker)
{ {
extendedLocalMinima(src.first, src.second, src.third, extendedLocalMinima(src.first, src.second, src.third,
dest.first, dest.second, marker); dest.first, dest.second, 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(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMinima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest) pair<DestIterator, DestAccessor> dest)
{ {
extendedLocalMinima(src.first, src.second, src.third, extendedLocalMinima(src.first, src.second, src.third,
dest.first, dest.second); dest.first, dest.second);
} }
/**************************************************************************
/
/********************************************************/
/* */
/* extendedLocalMinima3D */
/* */
/********************************************************/
/** \brief Find local minimal regions in a volume.
This function finds regions of uniform pixel value
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)
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood,
class EqualityFunctor>
inline void
extendedLocalMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood,
EqualityFunctor equal)
{
typedef typename SrcAccessor::value_type SrcType;
detail::extendedLocalMinMax3D(sul, slr, sa, dul, da, marker, neighborho
od,
std::less<SrcType>(), equal,
NumericTraits<typename SrcAccessor::value_type>::max());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood>
inline void
extendedLocalMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood)
{
typedef typename SrcAccessor::value_type SrcType;
extendedLocalMinima3D(sul, slr, sa, dul, da, marker, neighborhood,
std::equal_to<SrcType>());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
extendedLocalMinima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da)
{
extendedLocalMinima3D(sul, slr, sa, dul, da,
NumericTraits<typename DestAccessor::value_type>:
:one(),
NeighborCode3DSix());
}
template<class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor, class Neighborhood>
inline void
extendedLocalMinima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
typename DestAccessor::value_type marker,
Neighborhood neighborhood)
{
extendedLocalMinima3D(src.first, src.second, src.third,
dest.first, dest.second,
marker, neighborhood);
}
/**************************************************************************
/
/********************************************************/ /********************************************************/
/* */ /* */
/* extendedLocalMaxima */ /* extendedLocalMaxima */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Find local maximal regions in an image. /** \brief Find local maximal regions in an image or volume.
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 finds regions of uniform pixel value
whose neighboring regions are all have smaller values whose neighboring regions are all have smaller values
(maximal plateaus of arbitrary size). By default, the pixels (maximal plateaus of arbitrary size). By default, the pixels
in a plateau have exactly identical values. By passing an <tt>EqualityF unctor</tt> in a plateau have exactly identical values. By passing an <tt>EqualityF unctor</tt>
with tolerance, one can allow for plateaus that are not quite constant with tolerance, one can allow for plateaus that are not quite constant
(this is often necessary with float pixel values). Pass (this is often necessary with float pixel values). Pass
\ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode \ref vigra::EightNeighborCode or \ref vigra::FourNeighborCode
to determine the neighborhood where pixel values are compared. to determine the neighborhood where pixel values are compared.
Maximal regions are Maximal regions are
marked in the destination image with the given marker value marked in the destination image with the given marker value
(default is 1), all other destination pixels remain unchanged. (default is 1), all other destination pixels remain unchanged.
<TT>SrcAccessor::value_type</TT> must be equality-comparable and <TT>SrcAccessor::value_type</TT> must be equality-comparable and
less-comparable. less-comparable. A pixel or region touching the image border will
A pixel or region touching the image border will never be marked as max never be marked as maximum or maximal plateau. Use localMaxima() with t
imum or he
maximal plateau. 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. The function uses accessors.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: use 3-dimensional arrays:
\code
namespace vigra {
template <class T1, class C1, class T2, class C2,
class Neighborhood>
void
extendedLocalMaxima(MultiArrayView<3, T1, C1> src,
MultiArrayView<3, T2, C2> dest,
LocalMinmaxOptions const & options = LocalMinma
xOptions());
\endcode
pass image iterators explicitly:
\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,
skipping to change at line 754 skipping to change at line 1771
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())
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="localminmax_8hxx-source.html">vigra/loc alminmax.hxx</a>\><br> <b>\#include</b> \<vigra/localminmax.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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)
skipping to change at line 812 skipping to change at line 1829
u < u u < u
DestValue marker; DestValue marker;
dest_accessor.set(marker, dest_upperleft); dest_accessor.set(marker, dest_upperleft);
\endcode \endcode
*/ */
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 DestValue, 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, DestValue marker, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood, EqualityFunctor equal) Neighborhood neighborhood, EqualityFunctor equal)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
detail::extendedLocalMinMax(sul, slr, sa, dul, da, detail::extendedLocalMinMax(sul, slr, sa, dul, da,
marker, neighborhood, marker, neighborhood,
std::greater<SrcType>(), equal); std::greater<SrcType>(), equal,
NumericTraits<typename SrcAccessor::value_t
ype>::min());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
inline void inline void
extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa, extendedLocalMaxima(SrcIterator sul, SrcIterator slr, SrcAccessor sa,
DestIterator dul, DestAccessor da, DestValue marker, DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood) Neighborhood neighborhood)
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
extendedLocalMaxima(sul, slr, sa, dul, da, extendedLocalMaxima(sul, slr, sa, dul, da,
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 DestValue> 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, DestValue marker) DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker)
{ {
typedef typename SrcAccessor::value_type SrcType; 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)
{ {
extendedLocalMaxima(sul, slr, sa, dul, da, extendedLocalMaxima(sul, slr, sa, dul, da,
NumericTraits<typename DestAccessor::value_type>::one()); NumericTraits<typename DestAccessor::value_type>::one());
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue, class DestIterator, class DestAccessor,
class Neighborhood, class EqualityFunctor> class Neighborhood, class EqualityFunctor>
inline void inline void
extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, Neighborhood neighborhood, typename DestAccessor::value_type marker, Neighborhood neighbor hood,
EqualityFunctor equal) EqualityFunctor equal)
{ {
extendedLocalMaxima(src.first, src.second, src.third, extendedLocalMaxima(src.first, src.second, src.third,
dest.first, dest.second, marker, neighborhood, equal); dest.first, dest.second, marker, neighborhood, equal);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue, class DestIterator, class DestAccessor,
class Neighborhood> class Neighborhood>
inline void inline void
extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker, Neighborhood neighborhood) typename DestAccessor::value_type marker, Neighborhood neighbor hood)
{ {
extendedLocalMaxima(src.first, src.second, src.third, extendedLocalMaxima(src.first, src.second, src.third,
dest.first, dest.second, marker, neighborhood); dest.first, dest.second, marker, neighborhood);
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor, class DestValue> class DestIterator, class DestAccessor>
inline void inline void
extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
DestValue marker) typename DestAccessor::value_type marker)
{ {
extendedLocalMaxima(src.first, src.second, src.third, extendedLocalMaxima(src.first, src.second, src.third,
dest.first, dest.second, marker); dest.first, dest.second, 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(triple<SrcIterator, SrcIterator, SrcAccessor> src, extendedLocalMaxima(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest) pair<DestIterator, DestAccessor> dest)
{ {
extendedLocalMaxima(src.first, src.second, src.third, extendedLocalMaxima(src.first, src.second, src.third,
dest.first, dest.second); dest.first, dest.second);
} }
/********************************************************/
/* */
/* extendedLocalMaxima3D */
/* */
/********************************************************/
/** \brief Find local maximal regions in 3D multi array.
This function finds regions of uniform pixel value
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)
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood,
class EqualityFunctor>
inline void
extendedLocalMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood,
EqualityFunctor equal)
{
typedef typename SrcAccessor::value_type SrcType;
detail::extendedLocalMinMax3D(sul, slr, sa, dul, da, marker, neighborho
od,
std::greater<SrcType>(), equal,
NumericTraits<typename SrcAccessor::value
_type>::min());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood>
inline void
extendedLocalMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da,
typename DestAccessor::value_type marker,
Neighborhood neighborhood)
{
typedef typename SrcAccessor::value_type SrcType;
extendedLocalMaxima3D(sul, slr, sa, dul, da,
marker, neighborhood,
std::equal_to<SrcType>());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
extendedLocalMaxima3D(SrcIterator sul, SrcShape slr, SrcAccessor sa,
DestIterator dul, DestAccessor da)
{
extendedLocalMaxima3D(sul, slr, sa, dul, da,
NumericTraits<typename DestAccessor::value_type>:
:one(),
NeighborCode3DSix());
}
template<class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class Neighborhood>
inline void
extendedLocalMaxima3D(triple<SrcIterator, SrcShape, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
typename DestAccessor::value_type marker,
Neighborhood neighborhood)
{
extendedLocalMaxima3D(src.first, src.second, src.third,
dest.first, dest.second,
marker, neighborhood);
}
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_LOCALMINMAX_HXX #endif // VIGRA_LOCALMINMAX_HXX
 End of changes. 116 change blocks. 
206 lines changed or deleted 1396 lines changed or added


 mathutil.hxx   mathutil.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 1998-2005 by Ullrich Koethe */ /* Copyright 1998-2011 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 45 skipping to change at line 45
#ifndef VIGRA_MATHUTIL_HXX #ifndef VIGRA_MATHUTIL_HXX
#define VIGRA_MATHUTIL_HXX #define VIGRA_MATHUTIL_HXX
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning (disable: 4996) // hypot/_hypot confusion # pragma warning (disable: 4996) // hypot/_hypot confusion
#endif #endif
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
#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"
/*! \page MathConstants Mathematical Constants /*! \page MathConstants Mathematical Constants
<TT>M_PI, M_SQRT2</TT> <TT>M_PI, M_SQRT2 etc.</TT>
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathutil.h xx</a>\> <b>\#include</b> \<vigra/mathutil.hxx\>
Since <TT>M_PI</TT> and <TT>M_SQRT2</TT> are not officially standardize Since mathematical constants such as <TT>M_PI</TT> and <TT>M_SQRT2</TT>
d, are not officially standardized, we provide definitions here for those
we provide definitions here for those compilers that don't support them compilers that don't support them.
.
\code \code
#ifndef M_PI #ifndef M_PI
# define M_PI 3.14159265358979323846 # define M_PI 3.14159265358979323846
#endif #endif
#ifndef M_SQRT2 #ifndef M_SQRT2
# define M_2_PI 0.63661977236758134308
#endif
#ifndef M_PI_2
# define M_PI_2 1.57079632679489661923
#endif
#ifndef M_PI_4
# define M_PI_4 0.78539816339744830962
#endif
#ifndef M_SQRT2
# define M_SQRT2 1.41421356237309504880 # define M_SQRT2 1.41421356237309504880
#endif #endif
#ifndef M_EULER_GAMMA
# define M_EULER_GAMMA 0.5772156649015329
#endif
\endcode \endcode
*/ */
#ifndef M_PI #ifndef M_PI
# define M_PI 3.14159265358979323846 # define M_PI 3.14159265358979323846
#endif #endif
#ifndef M_2_PI
# define M_2_PI 0.63661977236758134308
#endif
#ifndef M_PI_2
# define M_PI_2 1.57079632679489661923
#endif
#ifndef M_PI_4
# define M_PI_4 0.78539816339744830962
#endif
#ifndef M_SQRT2 #ifndef M_SQRT2
# define M_SQRT2 1.41421356237309504880 # define M_SQRT2 1.41421356237309504880
#endif #endif
#ifndef M_EULER_GAMMA
# define M_EULER_GAMMA 0.5772156649015329
#endif
namespace vigra { namespace vigra {
/** \addtogroup MathFunctions Mathematical Functions /** \addtogroup MathFunctions Mathematical Functions
Useful mathematical functions and functors. Useful mathematical functions and functors.
*/ */
//@{ //@{
// import functions into namespace vigra which VIGRA is going to overload // import functions into namespace vigra which VIGRA is going to overload
using VIGRA_CSTD::pow; using VIGRA_CSTD::pow;
using VIGRA_CSTD::floor; using VIGRA_CSTD::floor;
using VIGRA_CSTD::ceil; using VIGRA_CSTD::ceil;
using VIGRA_CSTD::exp;
// import abs(float), abs(double), abs(long double) from <cmath> // import abs(float), abs(double), abs(long double) from <cmath>
// and abs(int), abs(long), abs(long long) from <cstdlib> // abs(int), abs(long), abs(long long) from <cstdlib>
// abs(std::complex<T>) from <complex>
using std::abs; using std::abs;
// define the missing variants of abs() to avoid 'ambigous overload' // define the missing variants of abs() to avoid 'ambiguous overload'
// errors in template functions // errors in template functions
#define VIGRA_DEFINE_UNSIGNED_ABS(T) \ #define VIGRA_DEFINE_UNSIGNED_ABS(T) \
inline T abs(T t) { return t; } inline T abs(T t) { return t; }
VIGRA_DEFINE_UNSIGNED_ABS(bool) VIGRA_DEFINE_UNSIGNED_ABS(bool)
VIGRA_DEFINE_UNSIGNED_ABS(unsigned char) VIGRA_DEFINE_UNSIGNED_ABS(unsigned char)
VIGRA_DEFINE_UNSIGNED_ABS(unsigned short) VIGRA_DEFINE_UNSIGNED_ABS(unsigned short)
VIGRA_DEFINE_UNSIGNED_ABS(unsigned int) VIGRA_DEFINE_UNSIGNED_ABS(unsigned int)
VIGRA_DEFINE_UNSIGNED_ABS(unsigned long) VIGRA_DEFINE_UNSIGNED_ABS(unsigned long)
VIGRA_DEFINE_UNSIGNED_ABS(unsigned long long) VIGRA_DEFINE_UNSIGNED_ABS(unsigned long long)
#undef VIGRA_DEFINE_UNSIGNED_ABS #undef VIGRA_DEFINE_UNSIGNED_ABS
#define VIGRA_DEFINE_MISSING_ABS(T) \ #define VIGRA_DEFINE_MISSING_ABS(T) \
inline T abs(T t) { return t < 0 ? -t : t; } inline T abs(T t) { return t < 0 ? -t : t; }
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
VIGRA_DEFINE_MISSING_ABS(signed long long)
#endif
#undef VIGRA_DEFINE_MISSING_ABS #undef VIGRA_DEFINE_MISSING_ABS
/*! The rounding function. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
#ifdef DOXYGEN // only for documentation
REAL round(REAL v);
#endif
inline float round(float t) inline float round(float t)
{ {
return t >= 0.0 return t >= 0.0
? floor(t + 0.5f) ? floor(t + 0.5f)
: ceil(t - 0.5f); : ceil(t - 0.5f);
} }
inline double round(double t) inline double round(double t)
{ {
return t >= 0.0 return t >= 0.0
skipping to change at line 151 skipping to change at line 196
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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline UInt32 ceilPower2(UInt32 x) inline UInt32 ceilPower2(UInt32 x)
{ {
if(x == 0) return 0; if(x == 0) return 0;
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);
skipping to change at line 190 skipping to change at line 235
x = x | (x >>16); x = x | (x >>16);
return x + 1; return x + 1;
} }
/*! Round down to the nearest power of 2. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline UInt32 floorPower2(UInt32 x) inline UInt32 floorPower2(UInt32 x)
{ {
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 - (x >> 1); return x - (x >> 1);
skipping to change at line 235 skipping to change at line 280
-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
\ref floorPower2() or \ref ceilPower2() are more efficient and shou ld be preferred when possible. \ref floorPower2() or \ref ceilPower2() are more efficient and shou ld be preferred when possible.
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline Int32 log2i(UInt32 x) inline Int32 log2i(UInt32 x)
{ {
// 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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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)
{ {
return t*t; return t*t;
} }
namespace detail { namespace detail {
skipping to change at line 276 skipping to change at line 321
template <class T> template <class T>
class IntSquareRoot class IntSquareRoot
{ {
public: 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 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55,
, 57, 57,
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81 59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81,
, 83, 83,
84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 1
, 102, 02,
103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 1
, 118, 18,
119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 1
, 132, 32,
133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 1
, 145, 45,
146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 1
, 157, 57,
158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 1
, 168, 68,
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 1
, 178, 78,
179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 1
, 188, 88,
189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197 189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 1
, 197, 97,
198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206 198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 2
, 206, 06,
207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214 207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 2
, 215, 15,
215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 2
, 223, 23,
224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 2
, 231, 31,
231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 2
, 238, 38,
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 2
, 246, 46,
246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 2
, 253, 53,
253, 254, 254, 255 253, 254, 254, 255
}; };
template <class T> template <class T>
UInt32 IntSquareRoot<T>::exec(UInt32 x) UInt32 IntSquareRoot<T>::exec(UInt32 x)
{ {
UInt32 xn; UInt32 xn;
if (x >= 0x10000) if (x >= 0x10000)
if (x >= 0x1000000) if (x >= 0x1000000)
if (x >= 0x10000000) if (x >= 0x10000000)
if (x >= 0x40000000) { if (x >= 0x40000000) {
if (x >= (UInt32)65535*(UInt32)65535) if (x >= (UInt32)65535*(UInt32)65535)
return 65535; return 65535;
xn = sqq_table[x>>24] << 8; xn = sqq_table[x>>24] << 8;
} else } else
xn = sqq_table[x>>22] << 7; xn = sqq_table[x>>22] << 7;
else else
if (x >= 0x4000000) if (x >= 0x4000000)
xn = sqq_table[x>>20] << 6; xn = sqq_table[x>>20] << 6;
else else
xn = sqq_table[x>>18] << 5; xn = sqq_table[x>>18] << 5;
else { else {
if (x >= 0x100000) if (x >= 0x100000)
if (x >= 0x400000) if (x >= 0x400000)
xn = sqq_table[x>>16] << 4; xn = sqq_table[x>>16] << 4;
else else
xn = sqq_table[x>>14] << 3; xn = sqq_table[x>>14] << 3;
else else
if (x >= 0x40000) if (x >= 0x40000)
xn = sqq_table[x>>12] << 2; xn = sqq_table[x>>12] << 2;
else else
xn = sqq_table[x>>10] << 1; xn = sqq_table[x>>10] << 1;
goto nr1; goto nr1;
} }
else else
if (x >= 0x100) { if (x >= 0x100) {
if (x >= 0x1000) if (x >= 0x1000)
if (x >= 0x4000) if (x >= 0x4000)
xn = (sqq_table[x>>8] >> 0) + 1; xn = (sqq_table[x>>8] >> 0) + 1;
else else
xn = (sqq_table[x>>6] >> 1) + 1; xn = (sqq_table[x>>6] >> 1) + 1;
else else
if (x >= 0x400) if (x >= 0x400)
xn = (sqq_table[x>>4] >> 2) + 1; xn = (sqq_table[x>>4] >> 2) + 1;
else else
xn = (sqq_table[x>>2] >> 3) + 1; xn = (sqq_table[x>>2] >> 3) + 1;
goto adj; goto adj;
} else } else
return sqq_table[x] >> 4; return sqq_table[x] >> 4;
/* Run two iterations of the standard convergence formula */ /* Run two iterations of the standard convergence formula */
xn = (xn + 1 + x / xn) / 2; xn = (xn + 1 + x / xn) / 2;
nr1: nr1:
xn = (xn + 1 + x / xn) / 2; xn = (xn + 1 + x / xn) / 2;
adj: adj:
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. /*! Signed integer square root.
Useful for fast fixed-point computations. Useful for fast fixed-point computations.
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! Unsigned integer square root.
Useful for fast fixed-point computations. Useful for fast fixed-point computations.
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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 hypothenuse of a righ t-angled triangle). /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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);
if (absa > absb) if (absa > absb)
return absa * VIGRA_CSTD::sqrt(1.0 + sq(absb/absa)); return absa * VIGRA_CSTD::sqrt(1.0 + sq(absb/absa));
else else
return absb == 0.0 return absb == 0.0
? 0.0 ? 0.0
skipping to change at line 419 skipping to change at line 464
#else #else
using ::hypot; using ::hypot;
#endif #endif
/*! The sign function. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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
/*! Check if an integer is even.
Defined for all integral types.
*/
bool even(int t);
/*! Check if an integer is odd.
Defined for all integral types.
*/
bool odd(int t);
#endif
#define VIGRA_DEFINE_ODD_EVEN(T) \
inline bool even(T t) { return (t&1) == 0; } \
inline bool odd(T t) { return (t&1) == 1; }
VIGRA_DEFINE_ODD_EVEN(char)
VIGRA_DEFINE_ODD_EVEN(short)
VIGRA_DEFINE_ODD_EVEN(int)
VIGRA_DEFINE_ODD_EVEN(long)
VIGRA_DEFINE_ODD_EVEN(long long)
VIGRA_DEFINE_ODD_EVEN(unsigned char)
VIGRA_DEFINE_ODD_EVEN(unsigned short)
VIGRA_DEFINE_ODD_EVEN(unsigned int)
VIGRA_DEFINE_ODD_EVEN(unsigned long)
VIGRA_DEFINE_ODD_EVEN(unsigned long long)
#undef VIGRA_DEFINE_ODD_EVEN
#define VIGRA_DEFINE_NORM(T) \ #define VIGRA_DEFINE_NORM(T) \
inline NormTraits<T>::SquaredNormType squaredNorm(T t) { return sq(t); } \ inline NormTraits<T>::SquaredNormType squaredNorm(T t) { return sq(t); } \
inline NormTraits<T>::NormType norm(T t) { return abs(t); } inline NormTraits<T>::NormType norm(T t) { return abs(t); }
VIGRA_DEFINE_NORM(bool) VIGRA_DEFINE_NORM(bool)
VIGRA_DEFINE_NORM(signed char) VIGRA_DEFINE_NORM(signed char)
VIGRA_DEFINE_NORM(unsigned char) VIGRA_DEFINE_NORM(unsigned char)
VIGRA_DEFINE_NORM(short) VIGRA_DEFINE_NORM(short)
VIGRA_DEFINE_NORM(unsigned short) VIGRA_DEFINE_NORM(unsigned short)
VIGRA_DEFINE_NORM(int) VIGRA_DEFINE_NORM(int)
VIGRA_DEFINE_NORM(unsigned int) VIGRA_DEFINE_NORM(unsigned int)
VIGRA_DEFINE_NORM(long) VIGRA_DEFINE_NORM(long)
VIGRA_DEFINE_NORM(unsigned long) VIGRA_DEFINE_NORM(unsigned long)
VIGRA_DEFINE_NORM(long long)
VIGRA_DEFINE_NORM(unsigned long long)
VIGRA_DEFINE_NORM(float) VIGRA_DEFINE_NORM(float)
VIGRA_DEFINE_NORM(double) VIGRA_DEFINE_NORM(double)
VIGRA_DEFINE_NORM(long double) VIGRA_DEFINE_NORM(long double)
#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)
{ {
skipping to change at line 507 skipping to change at line 586
*/ */
NormTraits<T>::SquaredNormType squaredNorm(T const & t); NormTraits<T>::SquaredNormType squaredNorm(T const & t);
#endif #endif
/*! The norm of a numerical object. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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)));
} }
/*! Find the minimum element in a sequence.
The function returns the iterator refering to the minimum element.
<b>Required Interface:</b>
\code
Iterator is a standard forward iterator.
bool f = *first < NumericTraits<typename std::iterator_traits<Itera
tor>::value_type>::max();
\endcode
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut
il.hxx</a>\><br>
Namespace: vigra
*/
template <class Iterator>
Iterator argMin(Iterator first, Iterator last)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
Value vopt = NumericTraits<Value>::max();
Iterator best = last;
for(; first != last; ++first)
{
if(*first < vopt)
{
vopt = *first;
best = first;
}
}
return best;
}
/*! Find the maximum element in a sequence.
The function returns the iterator refering to the maximum element.
<b>Required Interface:</b>
\code
Iterator is a standard forward iterator.
bool f = NumericTraits<typename std::iterator_traits<Iterator>::val
ue_type>::min() < *first;
\endcode
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut
il.hxx</a>\><br>
Namespace: vigra
*/
template <class Iterator>
Iterator argMax(Iterator first, Iterator last)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
Value vopt = NumericTraits<Value>::min();
Iterator best = last;
for(; first != last; ++first)
{
if(vopt < *first)
{
vopt = *first;
best = first;
}
}
return best;
}
/*! Find the minimum element in a sequence conforming to a condition.
The function returns the iterator refering to the minimum element,
where only elements conforming to the condition (i.e. where
<tt>condition(*iterator)</tt> evaluates to <tt>true</tt>) are consi
dered.
If no element conforms to the condition, or the sequence is empty,
the end iterator \a last is returned.
<b>Required Interface:</b>
\code
Iterator is a standard forward iterator.
bool c = condition(*first);
bool f = *first < NumericTraits<typename std::iterator_traits<Itera
tor>::value_type>::max();
\endcode
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut
il.hxx</a>\><br>
Namespace: vigra
*/
template <class Iterator, class UnaryFunctor>
Iterator argMinIf(Iterator first, Iterator last, UnaryFunctor condition)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
Value vopt = NumericTraits<Value>::max();
Iterator best = last;
for(; first != last; ++first)
{
if(condition(*first) && *first < vopt)
{
vopt = *first;
best = first;
}
}
return best;
}
/*! Find the maximum element in a sequence conforming to a condition.
The function returns the iterator refering to the maximum element,
where only elements conforming to the condition (i.e. where
<tt>condition(*iterator)</tt> evaluates to <tt>true</tt>) are consi
dered.
If no element conforms to the condition, or the sequence is empty,
the end iterator \a last is returned.
<b>Required Interface:</b>
\code
Iterator is a standard forward iterator.
bool c = condition(*first);
bool f = NumericTraits<typename std::iterator_traits<Iterator>::val
ue_type>::min() < *first;
\endcode
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut
il.hxx</a>\><br>
Namespace: vigra
*/
template <class Iterator, class UnaryFunctor>
Iterator argMaxIf(Iterator first, Iterator last, UnaryFunctor condition)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
Value vopt = NumericTraits<Value>::min();
Iterator best = last;
for(; first != last; ++first)
{
if(condition(*first) && vopt < *first)
{
vopt = *first;
best = first;
}
}
return best;
}
/*! Compute the eigenvalues of a 2x2 real symmetric matrix. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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 <em>"Eigensystems for 3
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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); static 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;
skipping to change at line 787 skipping to change at line 726
\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}} dt
\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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! The incomplete elliptic integral of the second kind.
skipping to change at line 811 skipping to change at line 750
\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!
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
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));
} }
skipping to change at line 854 skipping to change at line 793
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".
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double erf(double x) inline double erf(double x)
{ {
return detail::erfImpl(x); return detail::erfImpl(x);
} }
#else #else
using ::erf; using ::erf;
skipping to change at line 974 skipping to change at line 913
} }
} // namespace detail } // namespace detail
/*! Chi square distribution. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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. /*! 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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><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). /*! 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.
<b>\#include</b> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline double noncentralChi2CDFApprox(unsigned int degreesOfFreedom, double noncentrality, double arg) inline double noncentralChi2CDFApprox(unsigned int degreesOfFreedom, double noncentrality, double arg)
{ {
return detail::noncentralChi2CDFApprox(degreesOfFreedom, noncentrality, arg); return detail::noncentralChi2CDFApprox(degreesOfFreedom, noncentrality, arg);
} }
namespace detail {
// computes (l+m)! / (l-m)!
// l and m must be positive
template <class T>
T facLM(T l, T m)
{
T tmp = NumericTraits<T>::one();
for(T f = l-m+1; f <= l+m; ++f)
tmp *= f;
return tmp;
}
} // namespace detail
/*! Associated Legendre polynomial.
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>,
otherwise an exception is thrown. The standard Legendre polynomials
are the
special case <tt>m == 0</tt>.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
template <class REAL>
REAL legendre(unsigned int l, int m, REAL x)
{
vigra_precondition(abs(x) <= 1.0, "legendre(): x must be in [-1.0, 1.0]
.");
if (m < 0)
{
m = -m;
REAL s = odd(m)
? -1.0
: 1.0;
return legendre(l,m,x) * s / detail::facLM<REAL>(l,m);
}
REAL result = 1.0;
if (m > 0)
{
REAL r = std::sqrt( (1.0-x) * (1.0+x) );
REAL f = 1.0;
for (int i=1; i<=m; i++)
{
result *= (-f) * r;
f += 2.0;
}
}
if((int)l == m)
return result;
REAL result_1 = x * (2.0 * m + 1.0) * result;
if((int)l == m+1)
return result_1;
REAL other = 0.0;
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);
result = result_1;
result_1 = other;
}
return other;
}
/*! Legendre polynomial.
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.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
template <class REAL>
REAL legendre(unsigned int l, REAL x)
{
return legendre(l, 0, x);
}
/*! sin(pi*x).
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
<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>
Namespace: vigra
*/
template <class REAL>
REAL sin_pi(REAL x)
{
if(x < 0.0)
return -sin_pi(-x);
if(x < 0.5)
return std::sin(M_PI * x);
bool invert = false;
if(x < 1.0)
{
invert = true;
x = -x;
}
REAL rem = std::floor(x);
if(odd((int)rem))
invert = !invert;
rem = x - rem;
if(rem > 0.5)
rem = 1.0 - rem;
if(rem == 0.5)
rem = NumericTraits<REAL>::one();
else
rem = std::sin(M_PI * rem);
return invert
? -rem
: rem;
}
/*! cos(pi*x).
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>.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
template <class REAL>
REAL cos_pi(REAL x)
{
return sin_pi(x+0.5);
}
namespace detail {
template <class REAL>
REAL gammaImpl(REAL x)
{
int i, k, m, ix = (int)x;
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,
"gamma(): argument cannot exceed 171.0.");
if (x == ix)
{
if (ix > 0)
{
ga = 1.0; // use factorial
for (i=2; i<ix; ++i)
{
ga *= i;
}
}
else
{
vigra_precondition(false,
"gamma(): gamma function is undefined for 0 and negative i
ntegers.");
}
}
else
{
if (abs(x) > 1.0)
{
z = abs(x);
m = (int)z;
r = 1.0;
for (k=1; k<=m; ++k)
{
r *= (z-k);
}
z -= m;
}
else
{
z = x;
}
gr = g[24];
for (k=23; k>=0; --k)
{
gr = gr*z+g[k];
}
ga = 1.0/(gr*z);
if (abs(x) > 1.0)
{
ga *= r;
if (x < 0.0)
{
ga = -M_PI/(x*ga*sin_pi(x));
}
}
}
return ga;
}
/*
* the following code is derived from lgamma_r() by Sun
*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*
*/
template <class REAL>
REAL loggammaImpl(REAL x)
{
vigra_precondition(x > 0.0,
"loggamma(): argument must be positive.");
vigra_precondition(x <= 1.0e307,
"loggamma(): argument must not exceed 1e307.");
double res;
if (x < 4.2351647362715017e-22)
{
res = -std::log(x);
}
else if ((x == 2.0) || (x == 1.0))
{
res = 0.0;
}
else if (x < 2.0)
{
static const double 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 };
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)
{
res = -std::log(x);
if (x >= 0.7316)
{
double y = 1.0-x;
double z = y*y;
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 p = y*p1+p2;
res += (p-0.5*y);
}
else if (x >= 0.23164)
{
double y = x-(tc-1.0);
double z = y*y;
double w = z*y;
double p1 = t[0]+w*(t[3]+w*(t[6]+w*(t[9] +w*t[12])));
double p2 = t[1]+w*(t[4]+w*(t[7]+w*(t[10]+w*t[13])));
double p3 = t[2]+w*(t[5]+w*(t[8]+w*(t[11]+w*t[14])));
double p = z*p1-(tt-w*(p2+y*p3));
res += (tf + p);
}
else
{
double y = x;
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]))));
res += (-0.5*y + p1/p2);
}
}
else
{
res = 0.0;
if (x >= 1.7316)
{
double y = 2.0-x;
double z = y*y;
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 p = y*p1+p2;
res += (p-0.5*y);
}
else if(x >= 1.23164)
{
double y = x-tc;
double z = y*y;
double w = z*y;
double p1 = t[0]+w*(t[3]+w*(t[6]+w*(t[9] +w*t[12])));
double p2 = t[1]+w*(t[4]+w*(t[7]+w*(t[10]+w*t[13])));
double p3 = t[2]+w*(t[5]+w*(t[8]+w*(t[11]+w*t[14])));
double p = z*p1-(tt-w*(p2+y*p3));
res += (tf + p);
}
else
{
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 p2 = 1.0+y*(v[1]+y*(v[2]+y*(v[3]+y*(v[4]+y*v[5]))));
res += (-0.5*y + p1/p2);
}
}
}
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 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 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;
double z = 1.0;
while (i > 2.0)
{
--i;
z *= (y+i);
}
res += std::log(z);
}
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 z = 1.0/x;
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]))))
);
res = (x-0.5)*(t-1.0)+yy;
}
else
{
res = x*(std::log(x) - 1.0);
}
return res;
}
} // namespace detail
/*! The gamma function.
This function implements the algorithm from<br>
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
exception is thrown when these conditions are violated.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
inline double gamma(double x)
{
return detail::gammaImpl(x);
}
/*! The natural logarithm of the gamma function.
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
math functions.
The argument must be positive and < 1e30. An exception is thrown wh
en these conditions are violated.
<b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra
*/
inline double loggamma(double x)
{
return detail::loggammaImpl(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()) ||
skipping to change at line 1075 skipping to change at line 1459
} // namespace detail } // namespace detail
/*! Tolerance based floating-point comparison. /*! Tolerance based floating-point comparison.
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> \<<a href="mathutil_8hxx-source.html">vigra/mathut il.hxx</a>\><br> <b>\#include</b> \<vigra/mathutil.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T1, class T2> template <class T1, class T2>
bool bool
closeAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote epsilo n) closeAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote epsilo n)
{ {
typedef typename PromoteTraits<T1, T2>::Promote T; typedef typename PromoteTraits<T1, T2>::Promote T;
if(l == 0.0) if(l == 0.0)
return VIGRA_CSTD::fabs(r) <= epsilon; return VIGRA_CSTD::fabs(r) <= epsilon;
if(r == 0.0) if(r == 0.0)
skipping to change at line 1098 skipping to change at line 1482
T d1 = detail::safeFloatDivision<T>( diff, VIGRA_CSTD::fabs( r ) ); T d1 = detail::safeFloatDivision<T>( diff, VIGRA_CSTD::fabs( r ) );
T d2 = detail::safeFloatDivision<T>( diff, VIGRA_CSTD::fabs( l ) ); T d2 = detail::safeFloatDivision<T>( diff, VIGRA_CSTD::fabs( l ) );
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, 2.0 * NumericTraits<T>::epsilon()); return closeAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon());
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_MATHUTIL_HXX */ #endif /* VIGRA_MATHUTIL_HXX */
 End of changes. 54 change blocks. 
271 lines changed or deleted 670 lines changed or added


 matlab.hxx   matlab.hxx 
skipping to change at line 15 skipping to change at line 15
/* 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 */
/* files (the "Software"), to deal in the Software without */ /* files (the "Software"), to deal in the Software without */
/* Software is furnished to do so, subject to the following */
/* conditions: */
/* restriction, including without limitation the rights to use, */ /* restriction, including without limitation the rights to use, */
/* copy, modify, merge, publish, distribute, sublicense, and/or */ /* copy, modify, merge, publish, distribute, sublicense, and/or */
/* sell copies of the Software, and to permit persons to whom the */ /* sell copies of the Software, and to permit persons to whom the */
/* Software is furnished to do so, subject to the following */
/* conditions: */
/* */ /* */
/* The above copyright notice and this permission notice shall be */ /* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the */ /* included in all copies or substantial portions of the */
/* Software. */ /* Software. */
/* */ /* */
/* 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_MATLAB_HXX #ifndef VIGRA_MATLAB_HXX
#define VIGRA_MATLAB_HXX #define VIGRA_MATLAB_HXX
#include <string> #include <string>
#include <mex.h>
#include "array_vector.hxx" #include "array_vector.hxx"
#include "sized_int.hxx" #include "sized_int.hxx"
#include "matrix.hxx" #include "matrix.hxx"
#include <map> #include <map>
#include <time.h> #include <time.h>
// This is needed with visual studio 10
#ifdef _CHAR16T
#define CHAR16_T
#endif
#include <mex.h>
#include "matlab_FLEXTYPE.hxx" #include "matlab_FLEXTYPE.hxx"
namespace vigra { namespace vigra {
namespace matlab { namespace matlab {
template <class T> template <class T>
struct ValueType; struct ValueType;
#define VIGRA_MATLAB_VALUETYPE_UTIL(type, functionName, typeID, matTypeName ) \ #define VIGRA_MATLAB_VALUETYPE_UTIL(type, functionName, typeID, matTypeName ) \
skipping to change at line 199 skipping to change at line 204
} }
}; };
ConstCellArray(const mxArray * matPointer = 0) ConstCellArray(const mxArray * matPointer = 0)
: matPointer_(const_cast<mxArray *>(matPointer)), : matPointer_(const_cast<mxArray *>(matPointer)),
size_(0) size_(0)
{ {
if(matPointer != 0 && !mxIsCell(matPointer)) if(matPointer != 0 && !mxIsCell(matPointer))
mexErrMsgTxt("CellArray(mxArray *): Argument must be a Matlab c ell array."); mexErrMsgTxt("CellArray(mxArray *): Argument must be a Matlab c ell array.");
if(matPointer != 0) if(matPointer != 0)
size_ = mxGetNumberOfElements(matPointer); size_ = static_cast<int>(mxGetNumberOfElements(matPointer));
else else
size_ = -1; size_ = -1;
} }
Proxy operator[](int i) const Proxy operator[](int i) const
{ {
if(!isValid(i)) if(!isValid(i))
mexErrMsgTxt("CellArray::operator[]: Index out of range."); mexErrMsgTxt("CellArray::operator[]: Index out of range.");
return Proxy(matPointer_, i); return Proxy(matPointer_, i);
} }
skipping to change at line 296 skipping to change at line 301
mexErrMsgTxt(msg.c_str()); mexErrMsgTxt(msg.c_str());
} }
if(SIZE != mxGetNumberOfElements(t)) if(SIZE != mxGetNumberOfElements(t))
{ {
mexErrMsgTxt("getShape(): Input array has wrong number of elements. "); mexErrMsgTxt("getShape(): Input array has wrong number of elements. ");
} }
TinyVectorView<Int32, SIZE> res((MultiArrayIndex *)mxGetData(t)); TinyVectorView<Int32, SIZE> res((MultiArrayIndex *)mxGetData(t));
return typename MultiArrayShape<SIZE>::type(res); return typename MultiArrayShape<SIZE>::type(res);
} }
template <unsigned int DIM, class T> template <int DIM, class T>
MultiArrayView<DIM, T> MultiArrayView<DIM, T>
getMultiArray(mxArray const * t) getMultiArray(mxArray const * t)
{ {
typedef typename MultiArrayView<DIM, T>::difference_type Shape; typedef typename MultiArrayView<DIM, T>::difference_type Shape;
if(!ValueType<T>::check(t)) if(!ValueType<T>::check(t))
{ {
std::string msg = std::string("getMultiArray(): Input array must ha ve type ") + std::string msg = std::string("getMultiArray(): Input array must ha ve type ") +
ValueType<T>::typeName() + "."; ValueType<T>::typeName() + ".";
mexErrMsgTxt(msg.c_str()); mexErrMsgTxt(msg.c_str());
skipping to change at line 334 skipping to change at line 339
shape[k] = 1; shape[k] = 1;
} }
} }
else else
{ {
shape[0] = static_cast<typename Shape::value_type>(mxGetNumberOfEle ments(t)); shape[0] = static_cast<typename Shape::value_type>(mxGetNumberOfEle ments(t));
} }
return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t)); return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t));
} }
template <unsigned int DIM, class T> template <int DIM, class T>
MultiArrayView<DIM, T> MultiArrayView<DIM, T>
createMultiArray(typename MultiArrayShape<DIM>::type const & shape, mxArray * & t) createMultiArray(typename MultiArrayShape<DIM>::type const & shape, mxArray * & t)
{ {
mwSize matlabShape[DIM]; mwSize matlabShape[DIM];
for(int k=0; k<DIM; ++k) for(int k=0; k<DIM; ++k)
matlabShape[k] = static_cast<mwSize>(shape[k]); matlabShape[k] = static_cast<mwSize>(shape[k]);
t = mxCreateNumericArray(DIM, matlabShape, ValueType<T>::classID, mxREA L); t = mxCreateNumericArray(DIM, matlabShape, ValueType<T>::classID, mxREA L);
return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t)); return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t));
} }
template <unsigned int DIM, class T> template <int DIM, class T>
MultiArrayView<DIM, T> MultiArrayView<DIM, T>
createMultiArray(typename MultiArrayShape<DIM>::type const & shape, CellArr ay::Proxy t) createMultiArray(typename MultiArrayShape<DIM>::type const & shape, CellArr ay::Proxy t)
{ {
mwSize matlabShape[DIM]; mwSize matlabShape[DIM];
for(int k=0; k<DIM; ++k) for(int k=0; k<DIM; ++k)
matlabShape[k] = static_cast<mwSize>(shape[k]); matlabShape[k] = static_cast<mwSize>(shape[k]);
t = mxCreateNumericArray(DIM, matlabShape, ValueType<T>::classID, mxREA L); t = mxCreateNumericArray(DIM, matlabShape, ValueType<T>::classID, mxREA L);
return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t)); return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t));
} }
skipping to change at line 520 skipping to change at line 525
return m; return m;
} }
inline std::string inline std::string
getString(mxArray const * t) getString(mxArray const * t)
{ {
if(mxIsEmpty(t)) if(mxIsEmpty(t))
mexErrMsgTxt("getString() on empty input."); mexErrMsgTxt("getString() on empty input.");
if(!mxIsChar(t)) if(!mxIsChar(t))
mexErrMsgTxt("getString(): argument is not a string."); mexErrMsgTxt("getString(): argument is not a string.");
int size = mxGetNumberOfElements(t) + 1; int size = static_cast<int>(mxGetNumberOfElements(t) + 1);
ArrayVector<char> buf(size); ArrayVector<char> buf(size);
mxGetString(t, buf.begin(), size); mxGetString(t, buf.begin(), size);
return std::string(buf.begin()); return std::string(buf.begin());
} }
class CompileTimeError; class CompileTimeError;
namespace detail { namespace detail {
class Required class Required
skipping to change at line 787 skipping to change at line 792
return matlab::getScalar<T>((*this)[posOrName]); return matlab::getScalar<T>((*this)[posOrName]);
} }
} }
template <class T, class Place, class ReqType, class minClass, class ma xClass> template <class T, class Place, class ReqType, class minClass, class ma xClass>
T getScalarMinMax(Place posOrName, ReqType req, minClass min_, maxClass max_) T getScalarMinMax(Place posOrName, ReqType req, minClass min_, maxClass max_)
{ {
T temp = this->getScalar<T>(posOrName, req); T temp = this->getScalar<T>(posOrName, req);
if (!is_in_range(temp, min_, max_)) if (!is_in_range(temp, min_, max_))
mexErrMsgTxt("Value out of bounds."); mexErrMsgTxt("Value out of bounds.");
else return temp;
return temp;
} }
template <class T, class Place, class ReqType, class iteratorType> template <class T, class Place, class ReqType, class iteratorType>
T getScalarVals(Place posOrName, ReqType req, iteratorType begin_, iter atorType end_) T getScalarVals(Place posOrName, ReqType req, iteratorType begin_, iter atorType end_)
{ {
T temp = this->getScalar<T>(posOrName, req); T temp = this->getScalar<T>(posOrName, req);
for(iteratorType iter = begin_; iter != end_; ++iter) for(iteratorType iter = begin_; iter != end_; ++iter)
{ {
if((*iter) == temp) return temp; if((*iter) == temp) return temp;
} }
skipping to change at line 929 skipping to change at line 932
req.argumentWasProvided(); req.argumentWasProvided();
value_type temp = (*this)[posOrName]; value_type temp = (*this)[posOrName];
return matlab::getCellArray(temp); return matlab::getCellArray(temp);
} }
} }
template<class ReqType> template<class ReqType>
ConstCellArray getCellArray(std::string posOrName, ReqType req) ConstCellArray getCellArray(std::string posOrName, ReqType req)
{ {
CompileTimeError ERROR__Const_Cell_Array_May_Not_Be_In_Option_Struc t; CompileTimeError ERROR__Const_Cell_Array_May_Not_Be_In_Option_Struc t;
return ConstCellArray(); //avoid compiler warning
} }
}; };
class OutputArray class OutputArray
{ {
int size_; int size_;
mxArray ** data_; mxArray ** data_;
std::string createErrMsgOut(int pos) std::string createErrMsgOut(int pos)
{ {
skipping to change at line 1062 skipping to change at line 1066
ConstCellArray createCellArray(int pos, ReqType req, mwSize sze) ConstCellArray createCellArray(int pos, ReqType req, mwSize sze)
{ {
if(!isValid(pos)) if(!isValid(pos))
return errorOrDefault<ConstCellArray>(req, pos); return errorOrDefault<ConstCellArray>(req, pos);
return matlab::createCellArray(sze, (*this)[pos]); return matlab::createCellArray(sze, (*this)[pos]);
} }
}; };
/*********************************** /***********************************
Rahuls code starts here Rahuls code starts here
************************************+*/ ************************************/
using namespace vigra; using namespace vigra;
/*++++++++++++++++++++++++++HELPERFUNC+++++++++++++++++++++++++++++++*/ /*++++++++++++++++++++++++++HELPERFUNC+++++++++++++++++++++++++++++++*
/* This is used for better readibility of the test cases . * This is used for better readability of the test cases .
/* Nothing to be done here. * Nothing to be done here.
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int cantorPair(int x, int y){ int cantorPair(int x, int y){
return (int)(((x+y)*(x+y+1))/2+y); return (int)(((x+y)*(x+y+1))/2+y);
} }
int cantorPair(int x, int y, int z){ int cantorPair(int x, int y, int z){
return cantorPair(cantorPair(x,y),z); return cantorPair(cantorPair(x,y),z);
} }
template <int x, int y> template <int x, int y>
struct cP{ struct cP{
skipping to change at line 1155 skipping to change at line 1159
template<class indexType> template<class indexType>
const T get(indexType i_, indexType j_){ const T get(indexType i_, indexType j_){
Int32 i = static_cast<Int32>(i_); Int32 i = static_cast<Int32>(i_);
Int32 j = static_cast<Int32>(j_); Int32 j = static_cast<Int32>(j_);
TinyVector<int,2> newShape(i, j); TinyVector<int,2> newShape(i, j);
if(data.find(newShape) == data.end()) return 0; if(data.find(newShape) == data.end()) return 0;
else return data.find(newShape)->second; else return data.find(newShape)->second;
} }
//see dokumentation of mxCreateSparse and the mxGet functions to unders tand this. //see documentation of mxCreateSparse and the mxGet functions to unders tand this.
void mapToMxArray(mxArray * & in){ void mapToMxArray(mxArray * & in){
int len = data.size(); int len = data.size();
in = mxCreateSparse(width, length, len, mxREAL); in = mxCreateSparse(width, length, len, mxREAL);
int* jc = mxGetJc(in); int* jc = mxGetJc(in);
int* ir = mxGetIr(in); int* ir = mxGetIr(in);
double* pr = mxGetPr(in); double* pr = mxGetPr(in);
if(len == 0){ if(len == 0){
jc[0] = 1; jc[0] = 1;
return; return;
 End of changes. 14 change blocks. 
17 lines changed or deleted 21 lines changed or added


 matrix.hxx   matrix.hxx 
skipping to change at line 45 skipping to change at line 45
#ifndef VIGRA_MATRIX_HXX #ifndef VIGRA_MATRIX_HXX
#define VIGRA_MATRIX_HXX #define VIGRA_MATRIX_HXX
#include <cmath> #include <cmath>
#include <iosfwd> #include <iosfwd>
#include <iomanip> #include <iomanip>
#include "multi_array.hxx" #include "multi_array.hxx"
#include "mathutil.hxx" #include "mathutil.hxx"
#include "numerictraits.hxx" #include "numerictraits.hxx"
#include "multi_pointoperators.hxx"
namespace vigra namespace vigra
{ {
/** \defgroup LinearAlgebraModule Linear Algebra /** \defgroup LinearAlgebraModule Linear Algebra
\brief Classes and functions for matrix algebra, linear equations syste ms, eigen systems, least squares etc. \brief Classes and functions for matrix algebra, linear equations syste ms, eigen systems, least squares etc.
*/ */
/** \ingroup LinearAlgebraModule /** \ingroup LinearAlgebraModule
skipping to change at line 78 skipping to change at line 79
columnCount(const MultiArrayView<2, T, C> &x); columnCount(const MultiArrayView<2, T, C> &x);
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);
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);
template <class T, class ALLOC> template <class T, class ALLOC = std::allocator<T> >
class TemporaryMatrix; class TemporaryMatrix;
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);
template <class T, class C> template <class T, class C>
bool isSymmetric(const MultiArrayView<2, T, C> &v); bool isSymmetric(const MultiArrayView<2, T, C> &v);
enum RawArrayMemoryLayout { RowMajor, ColumnMajor }; enum RawArrayMemoryLayout { RowMajor, ColumnMajor };
skipping to change at line 100 skipping to change at line 101
/* */ /* */
/* Matrix */ /* Matrix */
/* */ /* */
/********************************************************/ /********************************************************/
/** Matrix class. /** Matrix class.
\ingroup LinearAlgebraModule \ingroup LinearAlgebraModule
This is the basic class for all linear algebra computations. Matrices a re This is the basic class for all linear algebra computations. Matrices a re
strored in a <i>column-major</i> format, i.e. the row index is varying fastest. stored in a <i>column-major</i> format, i.e. the row index is varying f astest.
This is the same format as in the lapack and gmm++ libraries, so it wil l This is the same format as in the lapack and gmm++ libraries, so it wil l
be easy to interface these libraries. In fact, if you need optimized be easy to interface these libraries. In fact, if you need optimized
high performance code, you should use them. The VIGRA linear algebra high performance code, you should use them. The VIGRA linear algebra
functionality is provided for smaller problems and rapid prototyping functionality is provided for smaller problems and rapid prototyping
(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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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;
skipping to change at line 380 skipping to change at line 381
return rowCount()*columnCount(); return rowCount()*columnCount();
} }
/** check whether the matrix is symmetric. /** check whether the matrix is symmetric.
*/ */
bool isSymmetric() const bool isSymmetric() const
{ {
return vigra::linalg::isSymmetric(*this); return vigra::linalg::isSymmetric(*this);
} }
/** sums over the matrix.
*/
TemporaryMatrix<T> sum() const
{
TemporaryMatrix<T> result(1, 1);
vigra::transformMultiArray(srcMultiArrayRange(*this),
destMultiArrayRange(result),
vigra::FindSum<T>() );
return result;
}
/** sums over dimension \a d of the matrix.
*/
TemporaryMatrix<T> sum(difference_type_1 d) const
{
difference_type shape(d==0 ? 1 : this->m_shape[0], d==0 ? this->m_s
hape[1] : 1);
TemporaryMatrix<T> result(shape);
vigra::transformMultiArray(srcMultiArrayRange(*this),
destMultiArrayRange(result),
vigra::FindSum<T>() );
return result;
}
/** sums over the matrix.
*/
TemporaryMatrix<T> mean() const
{
TemporaryMatrix<T> result(1, 1);
vigra::transformMultiArray(srcMultiArrayRange(*this),
destMultiArrayRange(result),
vigra::FindAverage<T>() );
return result;
}
/** calculates mean over dimension \a d of the matrix.
*/
TemporaryMatrix<T> mean(difference_type_1 d) const
{
difference_type shape(d==0 ? 1 : this->m_shape[0], d==0 ? this->m_s
hape[1] : 1);
TemporaryMatrix<T> result(shape);
vigra::transformMultiArray(srcMultiArrayRange(*this),
destMultiArrayRange(result),
vigra::FindAverage<T>() );
return result;
}
#ifdef DOXYGEN #ifdef DOXYGEN
// repeat the following functions for documentation. In real code, they are inherited. // repeat the following functions for documentation. In real code, they are inherited.
/** read/write access to matrix element <tt>(row, column)</tt>. /** read/write access to matrix element <tt>(row, column)</tt>.
Note that the order of the argument is the opposite of the usua l Note that the order of the argument is the opposite of the usua l
VIGRA convention due to column-major matrix order. VIGRA convention due to column-major matrix order.
*/ */
value_type & operator()(difference_type_1 row, difference_type_1 column ); value_type & operator()(difference_type_1 row, difference_type_1 column );
/** read access to matrix element <tt>(row, column)</tt>. /** read access to matrix element <tt>(row, column)</tt>.
skipping to change at line 458 skipping to change at line 505
} }
/** add \a other to each element of this matrix /** add \a other to each element of this matrix
*/ */
Matrix & operator+=(T other) Matrix & operator+=(T other)
{ {
BaseType::operator+=(other); BaseType::operator+=(other);
return *this; return *this;
} }
/** subtraxt \a other from each element of this matrix /** subtract \a other from each element of this matrix
*/ */
Matrix & operator-=(T other) Matrix & operator-=(T other)
{ {
BaseType::operator-=(other); BaseType::operator-=(other);
return *this; return *this;
} }
/** scalar multiply this with \a other /** scalar multiply this with \a other
*/ */
Matrix & operator*=(T other) Matrix & operator*=(T other)
{ {
BaseType::operator*=(other); BaseType::operator*=(other);
return *this; return *this;
} }
/** scalar devide this by \a other /** scalar divide this by \a other
*/ */
Matrix & operator/=(T other) Matrix & operator/=(T other)
{ {
BaseType::operator/=(other); BaseType::operator/=(other);
return *this; return *this;
} }
}; };
// TemporaryMatrix is provided as an optimization: Functions returning a ma trix can // TemporaryMatrix is provided as an optimization: Functions returning a ma trix can
// use TemporaryMatrix to make explicit that it was allocated as a temporar y data structure. // use TemporaryMatrix to make explicit that it was allocated as a temporar y data structure.
// 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 = std::allocator<T> > 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, UnstridedArrayTag> 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;
skipping to change at line 605 skipping to change at line 652
/** \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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 757 skipping to change at line 804
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ a>\> <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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ a>\> <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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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)
r(j, i) = NumericTraits<T>::zero(); r(j, i) = NumericTraits<T>::zero();
r(i, i) = NumericTraits<T>::one(); r(i, i) = NumericTraits<T>::one();
} }
} }
/** create n 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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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.
Usage:
\code
vigra::Matrix<double> m = vigra::ones<double>(rows, cols);
\endcode
<b>\#include</b> \<vigra/matrix.hxx\> or<br>
<b>\#include</b> \<vigra/linear_algebra.hxx\><br>
Namespaces: vigra and vigra::linalg
*/
template <class T>
TemporaryMatrix<T> ones(MultiArrayIndex rows, MultiArrayIndex cols)
{
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)
{ {
const MultiArrayIndex size = v.elementCount(); const MultiArrayIndex size = v.elementCount();
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 witten into the square matrix \a r. row or column. The result is written into the square matrix \a r.
<b>\#include</b> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 857 skipping to change at line 921
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 908 skipping to change at line 972
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 949 skipping to change at line 1013
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 977 skipping to change at line 1041
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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),
skipping to change at line 1007 skipping to change at line 1071
} }
} }
/** 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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1049 skipping to change at line 1113
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1084 skipping to change at line 1148
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1151 skipping to change at line 1215
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1194 skipping to change at line 1258
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1297 skipping to change at line 1361
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1396 skipping to change at line 1460
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1466 skipping to change at line 1530
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1528 skipping to change at line 1592
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1569 skipping to change at line 1633
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1596 skipping to change at line 1660
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1756 skipping to change at line 1820
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 1783 skipping to change at line 1847
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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. /*! 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 truely 2-dimensional matrix, the index can be converte d 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
bool f = a[0] < NumericTraits<T>::max(); bool f = a[0] < NumericTraits<T>::max();
\endcode \endcode
<b>\#include</b> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class C> template <class T, class C>
int argMin(MultiArrayView<2, T, C> const & a) int argMin(MultiArrayView<2, T, C> const & a)
{ {
T vopt = NumericTraits<T>::max(); T vopt = NumericTraits<T>::max();
int best = -1; int best = -1;
for(int k=0; k < a.size(); ++k) for(int k=0; k < a.size(); ++k)
{ {
if(a[k] < vopt) if(a[k] < vopt)
skipping to change at line 1872 skipping to change at line 1936
} }
} }
return best; return best;
} }
/*! Find the index of the maximum element in a matrix. /*! 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 truely 2-dimensional matrix, the index can be converte d 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
bool f = NumericTraits<T>::min() < a[0]; bool f = NumericTraits<T>::min() < a[0];
\endcode \endcode
<b>\#include</b> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class C> template <class T, class C>
int argMax(MultiArrayView<2, T, C> const & a) int argMax(MultiArrayView<2, T, C> const & a)
{ {
T vopt = NumericTraits<T>::min(); T vopt = NumericTraits<T>::min();
int best = -1; int best = -1;
for(int k=0; k < a.size(); ++k) for(int k=0; k < a.size(); ++k)
{ {
if(vopt < a[k]) if(vopt < a[k])
skipping to change at line 1906 skipping to change at line 1970
} }
return best; return best;
} }
/*! Find the index of the minimum element in a matrix subject to a cond ition. /*! Find the index of the minimum element in a matrix subject to a cond ition.
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 truely 2-dimensional matrix, the index can be converte d 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
bool c = condition(a[0]); bool c = condition(a[0]);
bool f = a[0] < NumericTraits<T>::max(); bool f = a[0] < NumericTraits<T>::max();
\endcode \endcode
<b>\#include</b> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class C, class UnaryFunctor> template <class T, class C, class UnaryFunctor>
int argMinIf(MultiArrayView<2, T, C> const & a, UnaryFunctor condition) int argMinIf(MultiArrayView<2, T, C> const & a, UnaryFunctor condition)
{ {
T vopt = NumericTraits<T>::max(); T vopt = NumericTraits<T>::max();
int best = -1; int best = -1;
for(int k=0; k < a.size(); ++k) for(int k=0; k < a.size(); ++k)
{ {
if(condition(a[k]) && a[k] < vopt) if(condition(a[k]) && a[k] < vopt)
skipping to change at line 1941 skipping to change at line 2005
} }
return best; return best;
} }
/*! Find the index of the maximum element in a matrix subject to a cond ition. /*! Find the index of the maximum element in a matrix subject to a cond ition.
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 truely 2-dimensional matrix, the index can be converte d 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
bool c = condition(a[0]); bool c = condition(a[0]);
bool f = NumericTraits<T>::min() < a[0]; bool f = NumericTraits<T>::min() < a[0];
\endcode \endcode
<b>\#include</b> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><br> <b>\#include</b> \<vigra/matrix.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class C, class UnaryFunctor> template <class T, class C, class UnaryFunctor>
int argMaxIf(MultiArrayView<2, T, C> const & a, UnaryFunctor condition) int argMaxIf(MultiArrayView<2, T, C> const & a, UnaryFunctor condition)
{ {
T vopt = NumericTraits<T>::min(); T vopt = NumericTraits<T>::min();
int best = -1; int best = -1;
for(int k=0; k < a.size(); ++k) for(int k=0; k < a.size(); ++k)
{ {
if(condition(a[k]) && vopt < a[k]) if(condition(a[k]) && vopt < a[k])
skipping to change at line 2217 skipping to change at line 2281
} // 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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 2267 skipping to change at line 2331
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.");
// West's algorithm for incremental variance computation // West's algorithm for incremental variance computation
mean.init(NumericTraits<T2>::zero()); mean.init(NumericTraits<T2>::zero());
sumOfSquaredDifferences.init(NumericTraits<T3>::zero()); sumOfSquaredDifferences.init(NumericTraits<T3>::zero());
for(MultiArrayIndex k=0; k<m; ++k) for(MultiArrayIndex k=0; k<m; ++k)
{ {
typedef typename NumericTraits<T2>::RealPromote TmpType;
Matrix<T2> t = rowVector(A, k) - mean; Matrix<T2> t = rowVector(A, k) - mean;
typename NumericTraits<T2>::RealPromote f = 1.0 / (k + 1.0), TmpType f = TmpType(1.0 / (k + 1.0)),
f1 = 1.0 - f; f1 = TmpType(1.0 - f);
mean += f*t; mean += f*t;
sumOfSquaredDifferences += f1*sq(t); sumOfSquaredDifferences += f1*sq(t);
} }
} }
template <class T1, class C1, class T2, class C2, class T3, class C3> template <class T1, class C1, class T2, class C2, class T3, class C3>
void void
columnStatistics2PassImpl(MultiArrayView<2, T1, C1> const & A, columnStatistics2PassImpl(MultiArrayView<2, T1, C1> const & A,
MultiArrayView<2, T2, C2> & mean, MultiArrayView<2, T3, C3 > & sumOfSquaredDifferences) MultiArrayView<2, T2, C2> & mean, MultiArrayView<2, T3, C3 > & sumOfSquaredDifferences)
{ {
skipping to change at line 2347 skipping to change at line 2412
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,
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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
skipping to change at line 2450 skipping to change at line 2515
void void
rowStatistics(MultiArrayView<2, T1, C1> const & A, rowStatistics(MultiArrayView<2, T1, C1> const & A,
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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 2558 skipping to change at line 2623
} }
} }
} // namespace detail } // namespace detail
/*! Compute the covariance matrix between the columns of a matrix \a fe atures. /*! Compute the covariance matrix between the columns of a matrix \a fe atures.
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><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)
{ {
MultiArrayIndex m = rowCount(features), n = columnCount(features); MultiArrayIndex m = rowCount(features), n = columnCount(features);
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;
skipping to change at line 2581 skipping to change at line 2646
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. /*! Compute the covariance matrix between the columns of a matrix \a fe atures.
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><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. /*! Compute the covariance matrix between the rows of a matrix \a featu res.
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><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;
skipping to change at line 2621 skipping to change at line 2686
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(m - 1);
} }
/*! Compute the covariance matrix between the rows of a matrix \a featu res. /*! Compute the covariance matrix between the rows of a matrix \a featu res.
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.h xx</a>\><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)
{ {
TemporaryMatrix<T> res(rowCount(features), rowCount(features)); TemporaryMatrix<T> res(rowCount(features), rowCount(features));
covarianceMatrixOfRows(features, res); covarianceMatrixOfRows(features, res);
return res; return res;
} }
enum DataPreparationGoals { ZeroMean = 1, UnitVariance = 2, UnitNorm = 4 }; enum DataPreparationGoals { ZeroMean = 1, UnitVariance = 2, UnitNorm = 4, U nitSum = 8 };
inline DataPreparationGoals operator|(DataPreparationGoals l, DataPreparati onGoals r) inline DataPreparationGoals operator|(DataPreparationGoals l, DataPreparati onGoals r)
{ {
return DataPreparationGoals(int(l) | int(r)); return DataPreparationGoals(int(l) | int(r));
} }
namespace detail { namespace detail {
template <class T, class C1, class C2, class C3, class C4> template <class T, class C1, class C2, class C3, class C4>
void void
skipping to change at line 2666 skipping to change at line 2731
{ {
res = A; res = A;
offset.init(NumericTraits<T>::zero()); offset.init(NumericTraits<T>::zero());
scaling.init(NumericTraits<T>::one()); scaling.init(NumericTraits<T>::one());
return; return;
} }
bool zeroMean = (goals & ZeroMean) != 0; bool zeroMean = (goals & ZeroMean) != 0;
bool unitVariance = (goals & UnitVariance) != 0; bool unitVariance = (goals & UnitVariance) != 0;
bool unitNorm = (goals & UnitNorm) != 0; bool unitNorm = (goals & UnitNorm) != 0;
bool unitSum = (goals & UnitSum) != 0;
if(unitSum)
{
vigra_precondition(goals == UnitSum,
"prepareData(): Unit sum is not compatible with any other data
preparation goal.");
transformMultiArray(srcMultiArrayRange(A), destMultiArrayRange(scal
ing), FindSum<T>());
offset.init(NumericTraits<T>::zero());
for(MultiArrayIndex k=0; k<n; ++k)
{
if(scaling(0, k) != NumericTraits<T>::zero())
{
scaling(0, k) = NumericTraits<T>::one() / scaling(0, k);
columnVector(res, k) = columnVector(A, k) * scaling(0, k);
}
else
{
scaling(0, k) = NumericTraits<T>::one();
}
}
return;
}
vigra_precondition(!(unitVariance && unitNorm), vigra_precondition(!(unitVariance && unitNorm),
"prepareDataImpl(): Unit variance and unit norm cannot be achieved at the same time."); "prepareData(): Unit variance and unit norm cannot be achieved at t he same time.");
Matrix<T> mean(1, n), sumOfSquaredDifferences(1, n); Matrix<T> mean(1, n), sumOfSquaredDifferences(1, n);
detail::columnStatisticsImpl(A, mean, sumOfSquaredDifferences); detail::columnStatisticsImpl(A, mean, sumOfSquaredDifferences);
for(MultiArrayIndex k=0; k<n; ++k) for(MultiArrayIndex k=0; k<n; ++k)
{ {
T stdDev = std::sqrt(sumOfSquaredDifferences(0, k) / T(m-1)); T stdDev = std::sqrt(sumOfSquaredDifferences(0, k) / T(m-1));
if(closeAtTolerance(stdDev / mean(0,k), NumericTraits<T>::zero())) if(closeAtTolerance(stdDev / mean(0,k), NumericTraits<T>::zero()))
stdDev = NumericTraits<T>::zero(); stdDev = NumericTraits<T>::zero();
if(zeroMean && stdDev > NumericTraits<T>::zero()) if(zeroMean && stdDev > NumericTraits<T>::zero())
skipping to change at line 2727 skipping to change at line 2818
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:
<DL> <DL>
<DT><tt>ZeroMean</tt><DD> Subtract the column mean form every column if the values in the column are not constant. <DT><tt>ZeroMean</tt><DD> Subtract the column mean form every column if the values in the column are not constant.
Do nothing in a constant column. Do nothing in a constant column.
<DT><tt>UnitSum</tt><DD> Scale the columns so that the their sum is one
if the sum was initially non-zero.
Do nothing in a zero-sum column.
<DT><tt>UnitVariance</tt><DD> Divide by the column standard deviation i f the values in the column are not constant. <DT><tt>UnitVariance</tt><DD> Divide by the column standard deviation i f the values in the column are not constant.
Do nothing in a constant column. Do nothing in a constant column.
<DT><tt>UnitNorm</tt><DD> Divide by the column norm if it is non-zero. <DT><tt>UnitNorm</tt><DD> Divide by the column norm if it is non-zero.
<DT><tt>ZeroMean | UnitVariance</tt><DD> First subtact the mean and the n divide by the standard deviation, unless the <DT><tt>ZeroMean | UnitVariance</tt><DD> First subtract the mean and th en divide by the standard deviation, unless the
column is constant (in which c ase the column remains unchanged). column is constant (in which c ase the column remains unchanged).
<DT><tt>ZeroMean | UnitNorm</tt><DD> If the column is non-constant, sub tract the mean. Then divide by the norm <DT><tt>ZeroMean | UnitNorm</tt><DD> If the column is non-constant, sub tract the mean. Then divide by the norm
of the result if the norm is non-z ero. of the result if the norm is non-z ero.
</DL> </DL>
<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 row vectors with as many columns as \a A. The matrices \a offset and \a scaling must be row vectors with as many columns as \a A.
\code \code
skipping to change at line 2765 skipping to change at line 2858
template <class T, class C1, class C2> template <class T, class C1, class C2>
void void
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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
skipping to change at line 2841 skipping to change at line 2934
template <class T, class C1, class C2> template <class T, class C1, class C2>
void void
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> \<<a href="matrix_8hxx-source.html">vigra/matrix.hxx</ <b>\#include</b> \<vigra/matrix.hxx\> or<br>
a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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
skipping to change at line 2877 skipping to change at line 2970
MultiArrayView<2, T, StridedArrayTag> tr = transpose(res), to = transpo se(offset), ts = transpose(scaling); MultiArrayView<2, T, StridedArrayTag> tr = transpose(res), to = transpo se(offset), ts = transpose(scaling);
detail::prepareDataImpl(transpose(A), tr, to, ts, goals); detail::prepareDataImpl(transpose(A), tr, to, ts, goals);
} }
template <class T, class C1, class C2> template <class T, class C1, class C2>
inline void inline void
prepareRows(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> & res, prepareRows(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2> & res,
DataPreparationGoals goals = ZeroMean | UnitVariance) DataPreparationGoals goals = ZeroMean | UnitVariance)
{ {
MultiArrayView<2, T, StridedArrayTag> tr = transpose(res); MultiArrayView<2, T, StridedArrayTag> tr = transpose(res);
Matrix<T> offset(rowCount(A), 1), scaling(rowCount(A), 1); Matrix<T> offset(1, rowCount(A)), scaling(1, rowCount(A));
detail::prepareDataImpl(transpose(A), tr, offset, scaling, goals); detail::prepareDataImpl(transpose(A), tr, offset, scaling, goals);
} }
//@} //@}
} // namespace linalg } // namespace linalg
using linalg::columnStatistics; using linalg::columnStatistics;
using linalg::prepareColumns; using linalg::prepareColumns;
using linalg::rowStatistics; using linalg::rowStatistics;
using linalg::prepareRows; using linalg::prepareRows;
using linalg::ZeroMean; using linalg::ZeroMean;
using linalg::UnitVariance; using linalg::UnitVariance;
using linalg::UnitNorm; using linalg::UnitNorm;
using linalg::UnitSum;
} // namespace vigra } // namespace vigra
#endif // VIGRA_MATRIX_HXX #endif // VIGRA_MATRIX_HXX
 End of changes. 93 change blocks. 
267 lines changed or deleted 246 lines changed or added


 memory.hxx   memory.hxx 
skipping to change at line 62 skipping to change at line 62
namespace detail { namespace detail {
template <class T> template <class T>
inline void destroy_n(T * /* p */, std::ptrdiff_t /* n */, VigraTrueType /* isPOD */) inline void destroy_n(T * /* p */, std::ptrdiff_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::ptrdiff_t n, VigraFalseType /* isPOD */)
{ {
T * end = p + n; T * end = p + n;
for(; p != end; ++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::ptrdiff_t n)
{ {
destroy_n(p, n, typename TypeTraits<T>::isPOD()); destroy_n(p, n, typename TypeTraits<T>::isPOD());
} }
/********************************************************************/ /********************************************************************/
 End of changes. 1 change blocks. 
3 lines changed or deleted 3 lines changed or added


 meshgrid.hxx   meshgrid.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_MESHGRID_HXX #ifndef VIGRA_MESHGRID_HXX
#define VIGRA_MESHGRID_HXX #define VIGRA_MESHGRID_HXX
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "diff2d.hxx" #include "diff2d.hxx"
namespace vigra{ namespace vigra{
/** \addtogroup RangesAndPoints Two-dimensional Ranges and Points /** \addtogroup RangesAndPoints */
Specify a 2D position, extent, or rectangle.
*/
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* MeshGridAccessor */ /* MeshGridAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** Accessor for turning iteration over Diff2D into a mesh grid. /** Accessor for turning iteration over Diff2D into a mesh grid.
The mesh grid concept is adapted from MATLAB. It is a two banded image The mesh grid concept is adapted from MATLAB. It is a two banded image
 End of changes. 1 change blocks. 
4 lines changed or deleted 1 lines changed or added


 metaprogramming.hxx   metaprogramming.hxx 
skipping to change at line 91 skipping to change at line 91
/********************************************************/ /********************************************************/
/* */ /* */
/* StridedArrayTag */ /* StridedArrayTag */
/* */ /* */
/********************************************************/ /********************************************************/
/** tag for marking a MultiArray strided. /** tag for marking a MultiArray strided.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<vigra/multi_array.hxx\>
Namespace: vigra Namespace: vigra
*/ */
struct StridedArrayTag {}; struct StridedArrayTag {};
/********************************************************/ /********************************************************/
/* */ /* */
/* UnstridedArrayTag */ /* UnstridedArrayTag */
/* */ /* */
/********************************************************/ /********************************************************/
/** tag for marking a MultiArray unstrided. /** tag for marking a MultiArray unstrided.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<vigra/multi_array.hxx\>
Namespace: vigra Namespace: vigra
*/ */
struct UnstridedArrayTag {}; struct UnstridedArrayTag {};
template<class T> template<class T>
class TypeTraits class TypeTraits
{ {
public: public:
typedef VigraFalseType isConst; typedef VigraFalseType isConst;
skipping to change at line 504 skipping to change at line 504
typedef VigraTrueType type; typedef VigraTrueType type;
}; };
template <class T> template <class T>
struct IsIterator<T const *> struct IsIterator<T const *>
{ {
static const bool value = true; static const bool value = true;
typedef VigraTrueType type; typedef VigraTrueType type;
}; };
template <class T>
struct IsArray
{
typedef char falseResult[1];
typedef char trueResult[2];
static falseResult * test(...);
template <class U, unsigned n>
static trueResult * test(U (*)[n]);
enum { resultSize = sizeof(*test((T*)0)) };
static const bool value = (resultSize == 2);
typedef typename
IfBool<value, VigraTrueType, VigraFalseType>::type
type;
};
} // namespace vigra } // namespace vigra
#endif /* VIGRA_METAPROGRAMMING_HXX */ #endif /* VIGRA_METAPROGRAMMING_HXX */
 End of changes. 3 change blocks. 
2 lines changed or deleted 20 lines changed or added


 multi_array.hxx   multi_array.hxx 
skipping to change at line 216 skipping to change at line 216
/* */ /* */
/* 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>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<vigra/multi_array.hxx\>
Namespace: vigra::detail Namespace: vigra::detail
*/ */
template <unsigned int N> template <class StrideTag, unsigned int N>
struct MaybeStrided struct MaybeStrided
{ {
typedef UnstridedArrayTag type; typedef StrideTag type;
}; };
template <> template <class StrideTag>
struct MaybeStrided <0> struct MaybeStrided <StrideTag, 0>
{ {
typedef StridedArrayTag type; typedef StridedArrayTag type;
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* 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>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<vigra/multi_array.hxx\>
Namespace: vigra::detail Namespace: vigra::detail
*/ */
template <class O> template <class O>
struct MultiIteratorChooser struct MultiIteratorChooser
{ {
struct Nil {}; struct Nil {};
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
struct Traverser struct Traverser
skipping to change at line 267 skipping to change at line 267
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIteratorChooser <StridedArrayTag> */ /* MultiIteratorChooser <StridedArrayTag> */
/* */ /* */
/********************************************************/ /********************************************************/
/* specialization of the MultiIteratorChooser for strided arrays. /* specialization of the MultiIteratorChooser for strided arrays.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<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;
skipping to change at line 290 skipping to change at line 290
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIteratorChooser <UnstridedArrayTag> */ /* MultiIteratorChooser <UnstridedArrayTag> */
/* */ /* */
/********************************************************/ /********************************************************/
/* specialization of the MultiIteratorChooser for unstrided arrays. /* specialization of the MultiIteratorChooser for unstrided arrays.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<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;
skipping to change at line 407 skipping to change at line 407
void void
uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d , ALLOC & a, MetaInt<N>) uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d , ALLOC & a, MetaInt<N>)
{ {
SrcIterator send = s + shape[N]; SrcIterator send = s + shape[N];
for(; s < send; ++s) for(; s < send; ++s)
{ {
uninitializedCopyMultiArrayData(s.begin(), shape, d, a, MetaInt<N-1 >()); uninitializedCopyMultiArrayData(s.begin(), shape, d, a, MetaInt<N-1 >());
} }
} }
template <class SrcIterator, class Shape, class T> template <class SrcIterator, class Shape, class T, class Functor>
inline void inline void
normMaxOfMultiArray(SrcIterator s, Shape const & shape, T & result, MetaInt <0>) reduceOverMultiArray(SrcIterator s, Shape const & shape, T & result, Functo r const & f, MetaInt<0>)
{ {
SrcIterator send = s + shape[0]; SrcIterator send = s + shape[0];
for(; s < send; ++s) for(; s < send; ++s)
{ {
T v = norm(*s); f(result, *s);
if(result < v)
result = v;
} }
} }
template <class SrcIterator, class Shape, class T, int N> template <class SrcIterator, class Shape, class T, class Functor, int N>
void void
normMaxOfMultiArray(SrcIterator s, Shape const & shape, T & result, MetaInt <N>) reduceOverMultiArray(SrcIterator s, Shape const & shape, T & result, Functo r const & f, MetaInt<N>)
{ {
SrcIterator send = s + shape[N]; SrcIterator send = s + shape[N];
for(; s < send; ++s) for(; s < send; ++s)
{ {
normMaxOfMultiArray(s.begin(), shape, result, MetaInt<N-1>()); reduceOverMultiArray(s.begin(), shape, result, f, MetaInt<N-1>());
} }
} }
template <class T> struct MaxNormReduceFunctor
struct MultiArrayL1Functor
{ {
template <class U> template <class T, class U>
T operator()(U t) const void operator()(T & result, U const & u) const
{ return norm(t); } {
T v = norm(u);
if(result < v)
result = v;
}
}; };
template <class T> struct L1NormReduceFunctor
struct MultiArrayL2Functor
{ {
template <class U> template <class T, class U>
T operator()(U t) const void operator()(T & result, U const & u) const
{ return squaredNorm(t); } {
result += norm(u);
}
};
struct SquaredL2NormReduceFunctor
{
template <class T, class U>
void operator()(T & result, U const & u) const
{
result += squaredNorm(u);
}
}; };
template <class T> template <class T>
struct MultiArrayScaledL2Functor struct WeightedL2NormReduceFunctor
{ {
T scale; T scale;
MultiArrayScaledL2Functor(T s) WeightedL2NormReduceFunctor(T s)
: scale(s) : scale(s)
{} {}
template <class U> template <class U>
T operator()(U t) const void operator()(T & result, U const & u) const
{ return squaredNorm(T(t) / scale); } {
result += squaredNorm(u * scale);
}
}; };
template <class SrcIterator, class Shape, class Functor, class T> struct SumReduceFunctor
inline void
sumOverMultiArray(SrcIterator s, Shape const & shape, Functor f, T & result
, MetaInt<0>)
{ {
SrcIterator send = s + shape[0]; template <class T, class U>
for(; s < send; ++s) void operator()(T & result, U const & u) const
{ {
result += f(*s); result += u;
} }
} };
template <class SrcIterator, class Shape, class Functor, class T, int N> struct ProdReduceFunctor
void
sumOverMultiArray(SrcIterator s, Shape const & shape, Functor f, T & result
, MetaInt<N>)
{ {
SrcIterator send = s + shape[N]; template <class T, class U>
for(; s < send; ++s) void operator()(T & result, U const & u) const
{ {
sumOverMultiArray(s.begin(), shape, f, result, MetaInt<N-1>()); result *= u;
} }
} };
struct MinmaxReduceFunctor
{
template <class T, class U>
void operator()(T & result, U const & u) const
{
if(u < result.first)
result.first = u;
if(result.second < u)
result.second = u;
}
};
struct MeanVarianceReduceFunctor
{
template <class T, class U>
void operator()(T & result, U const & u) const
{
++result.first;
typename T::second_type t1 = u - result.second;
typename T::second_type t2 = t1 / result.first;
result.second += t2;
result.third += (result.first-1.0)*t1*t2;
}
};
struct AllTrueReduceFunctor
{
template <class T, class U>
void operator()(T & result, U const & u) const
{
result = result && (u != NumericTraits<U>::zero());
}
};
struct AnyTrueReduceFunctor
{
template <class T, class U>
void operator()(T & result, U const & u) const
{
result = result || (u != NumericTraits<U>::zero());
}
};
template <class SrcIterator, class Shape, class DestIterator> template <class SrcIterator, class Shape, class DestIterator>
inline bool inline bool
equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, M etaInt<0>) equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, M etaInt<0>)
{ {
SrcIterator send = s + shape[0]; SrcIterator send = s + shape[0];
for(; s < send; ++s, ++d) for(; s < send; ++s, ++d)
{ {
if(!(*s == *d)) if(!(*s == *d))
return false; return false;
skipping to change at line 535 skipping to change at line 587
} }
} // namespace detail } // namespace detail
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiArrayView */ /* MultiArrayView */
/* */ /* */
/********************************************************/ /********************************************************/
// forward declaration // forward declarations
template <unsigned int N, class T, class C = UnstridedArrayTag> template <unsigned int N, class T, class C = UnstridedArrayTag>
class MultiArrayView; class MultiArrayView;
template <unsigned int N, class T, class A = std::allocator<T> > template <unsigned int N, class T, class A = std::allocator<T> >
class MultiArray; class MultiArray;
namespace multi_math {
template <class T>
struct MultiMathOperand;
namespace detail {
template <unsigned int N, class T, class C, class E>
void assign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class C, class E>
void plusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class C, class E>
void minusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class C, class E>
void multiplyAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class C, class E>
void divideAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
template <unsigned int N, class T, class A, class E>
void assignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
template <unsigned int N, class T, class A, class E>
void plusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &)
;
template <unsigned int N, class T, class A, class E>
void minusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &
);
template <unsigned int N, class T, class A, class E>
void multiplyAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> cons
t &);
template <unsigned int N, class T, class A, class E>
void divideAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const
&);
} // namespace detail
} // namespace multi_math
template <class T> class FindSum;
struct UnsuitableTypeForExpandElements {};
template <class T>
struct ExpandElementResult
{
typedef UnsuitableTypeForExpandElements type;
};
template <class T>
struct ExpandElementResult<std::complex<T> >
{
typedef T type;
enum { size = 2 };
};
template <class T>
class FFTWComplex;
template <class T>
struct ExpandElementResult<FFTWComplex<T> >
{
typedef T type;
enum { size = 2 };
};
template <class T, int SIZE>
struct ExpandElementResult<TinyVector<T, SIZE> >
{
typedef T type;
enum { size = SIZE };
};
template <class T, unsigned int R, unsigned int G, unsigned int B>
struct ExpandElementResult<RGBValue<T, R, G, B> >
{
typedef T type;
enum { size = 3 };
};
#define VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(TYPE) \
template <> \
struct ExpandElementResult<TYPE> \
{ \
typedef TYPE type; \
enum { size = 1 }; \
}; \
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(bool)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(char)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed char)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed short)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed int)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed long)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed long long)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned char)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned short)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned int)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned long)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned long long)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(float)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(double)
VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(long double)
#undef VIGRA_DEFINE_EXPAND_ELEMENT_RESULT
/********************************************************/ /********************************************************/
/* */ /* */
/* NormTraits */ /* NormTraits */
/* */ /* */
/********************************************************/ /********************************************************/
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;
skipping to change at line 572 skipping to change at line 733
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 unstrided. If necessary, strided arrays are constructed automatically
by calls to a variant of the bind...() function. by calls to a variant of the bind...() function.
In addition to the member functions described here, <tt>MultiArrayView</tt>
and its subclasses support arithmetic and algebraic functions via the
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.
The template parameter are as follows The template parameter 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
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: UnstridedArrayTag (default), StridedArrayTag
\endcode \endcode
<b>\#include</b> <b>\#include</b>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<vigra/multi_array.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned int N, class T, class C> 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>
\code \code
actual_dimension = (N==0) ? 1 : N actual_dimension = (N==0) ? 1 : N
\endcode \endcode
skipping to change at line 642 skipping to change at line 807
typedef typename MultiArrayShape<actual_dimension>::type difference_typ e; typedef typename MultiArrayShape<actual_dimension>::type difference_typ e;
/** 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
*/
typedef StridedScanOrderIterator<actual_dimension, T, T &, T *> iterato
r;
/** const scan-order iterator (StridedScanOrderIterator) type
*/
typedef StridedScanOrderIterator<actual_dimension, T, T const &, T cons
t *> const_iterator;
/** traverser (MultiIterator) type /** traverser (MultiIterator) type
*/ */
typedef typename vigra::detail::MultiIteratorChooser < typedef typename vigra::detail::MultiIteratorChooser <
C>::template Traverser <actual_dimension, T, T &, T *>::type traver ser; StrideTag>::template Traverser <actual_dimension, T, T &, T *>::typ e traverser;
/** const traverser (MultiIterator) type /** const traverser (MultiIterator) type
*/ */
typedef typename vigra::detail::MultiIteratorChooser < typedef typename vigra::detail::MultiIteratorChooser <
C>::template Traverser <actual_dimension, T, T const &, T const *>: :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, C> 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: 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.
skipping to change at line 692 skipping to change at line 865
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 shape and pointer /** construct from shape and pointer
*/ */
MultiArrayView (const difference_type &shape, pointer ptr) MultiArrayView (const difference_type &shape, pointer ptr)
: m_shape (shape), : m_shape (shape),
m_stride (detail::defaultStride <MultiArrayView<N,T>::actual_dimensio n> (shape)), m_stride (detail::defaultStride <MultiArrayView<N,T>::actual_dimensio n> (shape)),
m_ptr (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 offsets 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) pointer ptr)
: m_shape (shape), : m_shape (shape),
m_stride (stride), m_stride (stride),
m_ptr (ptr) m_ptr (ptr)
{} {
vigra_precondition(checkInnerStride(StrideTag()),
"MultiArrayView<..., UnstridedArrayTag>::MultiArrayView(): Firs
t dimension of given array is not unstrided.");
}
/** Conversion to a strided view.
*/
operator MultiArrayView<N, T, StridedArrayTag>() const
{
return MultiArrayView<N, T, StridedArrayTag>(m_shape, m_stride, m_p
tr);
}
/** 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 rhs. (e.g. after default construction), it becomes a copy of \a rhs.
<li> When the shapes of the two arrays match, the array content s are copied. <li> When the shapes of the two arrays match, the array content s are copied.
<li> Otherwise, a <tt>PreconditionViolation</tt> exception is t hrown. <li> Otherwise, a <tt>PreconditionViolation</tt> exception is t hrown.
</ul> </ul>
*/ */
skipping to change at line 801 skipping to change at line 994
} }
/** Divide-assignment of a scalar. /** Divide-assignment of a scalar.
*/ */
MultiArrayView & operator/=(T const & rhs) MultiArrayView & operator/=(T const & rhs)
{ {
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
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArrayView & operator=(multi_math::MultiMathOperand<Expression> con
st & rhs)
{
multi_math::detail::assign(*this, rhs);
return *this;
}
/** Add-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArrayView & operator+=(multi_math::MultiMathOperand<Expression> co
nst & rhs)
{
multi_math::detail::plusAssign(*this, rhs);
return *this;
}
/** Subtract-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArrayView & operator-=(multi_math::MultiMathOperand<Expression> co
nst & rhs)
{
multi_math::detail::minusAssign(*this, rhs);
return *this;
}
/** Multiply-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArrayView & operator*=(multi_math::MultiMathOperand<Expression> co
nst & rhs)
{
multi_math::detail::multiplyAssign(*this, rhs);
return *this;
}
/** Divide-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArrayView & operator/=(multi_math::MultiMathOperand<Expression> co
nst & rhs)
{
multi_math::detail::divideAssign(*this, rhs);
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)];
} }
/** array access. /** array access.
*/ */
const_reference operator[] (const difference_type &d) const const_reference operator[] (const difference_type &d) const
{ {
VIGRA_ASSERT_INSIDE(d); VIGRA_ASSERT_INSIDE(d);
return m_ptr [dot (d, m_stride)]; return m_ptr [dot (d, m_stride)];
} }
/** equvalent to bindInner(), when M < N. /** equivalent to bindInner(), when M < N.
*/ */
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-M, T, StridedArrayTag> operator[] (const TinyVector<M ultiArrayIndex, M> &d) const MultiArrayView <N-M, T, StridedArrayTag> operator[] (const TinyVector<M ultiArrayIndex, M> &d) const
{ {
return bindInner(d); return bindInner(d);
} }
/** array access in scan-order sense. /** Array access in scan-order sense.
Mostly useful to support standard indexing for 1-dimensional mu lti-arrays, Mostly useful to support standard indexing for 1-dimensional mu lti-arrays,
but works for any N. Use scanOrderIndexToCoordinate() and but works for any N. Use scanOrderIndexToCoordinate() and
coordinateToScanOrderIndex() for conversion between indices and coordinates. coordinateToScanOrderIndex() for conversion between indices and coordinates.
<b>Note:</b> This function should not be used in the inner loop
, because the
conversion of the scan order index into a memory address is exp
ensive
(it must take into account that memory may not be consecutive f
or subarrays
and/or strided arrays). Always prefer operator() if possible.
*/ */
reference operator[](difference_type_1 d) reference operator[](difference_type_1 d)
{ {
VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d)); VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d));
return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)]; return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)];
} }
/** array access in scan-order sense. /** Array access in scan-order sense.
Mostly useful to support standard indexing for 1-dimensional mu lti-arrays, Mostly useful to support standard indexing for 1-dimensional mu lti-arrays,
but works for any N. Use scanOrderIndexToCoordinate() and but works for any N. Use scanOrderIndexToCoordinate() and
coordinateToScanOrderIndex() for conversion between indices and coordinates. coordinateToScanOrderIndex() for conversion between indices and coordinates.
*/
<b>Note:</b> This function should not be used in the inner loop
, because the
conversion of the scan order index into a memory address is exp
ensive
(it must take into account that memory may not be consecutive f
or subarrays
and/or strided arrays). Always prefer operator() if possible.
*/
const_reference operator[](difference_type_1 d) const const_reference operator[](difference_type_1 d) const
{ {
VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d)); VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d));
return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)]; return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)];
} }
/** convert scan-order index to coordinate. /** convert scan-order index to coordinate.
*/ */
difference_type scanOrderIndexToCoordinate(difference_type_1 d) const difference_type scanOrderIndexToCoordinate(difference_type_1 d) const
{ {
skipping to change at line 868 skipping to change at line 1121
difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const
{ {
return detail::CoordinateToScanOrder<actual_dimension>::exec(m_shap e, d); return detail::CoordinateToScanOrder<actual_dimension>::exec(m_shap e, d);
} }
/** 1D array access. Use only if N == 1. /** 1D array access. Use only if N == 1.
*/ */
reference operator() (difference_type_1 x) reference operator() (difference_type_1 x)
{ {
VIGRA_ASSERT_INSIDE(difference_type(x)); VIGRA_ASSERT_INSIDE(difference_type(x));
return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x)]; return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride , x)];
} }
/** 2D array access. Use only if N == 2. /** 2D array access. Use only if N == 2.
*/ */
reference operator() (difference_type_1 x, difference_type_1 y) reference operator() (difference_type_1 x, difference_type_1 y)
{ {
VIGRA_ASSERT_INSIDE(difference_type(x, y)); VIGRA_ASSERT_INSIDE(difference_type(x, y));
return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x, y)] ; return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride , x, y)];
} }
/** 3D array access. Use only if N == 3. /** 3D array access. Use only if N == 3.
*/ */
reference operator() (difference_type_1 x, difference_type_1 y, differe nce_type_1 z) reference operator() (difference_type_1 x, difference_type_1 y, differe nce_type_1 z)
{ {
VIGRA_ASSERT_INSIDE(difference_type(x, y, z)); VIGRA_ASSERT_INSIDE(difference_type(x, y, z));
return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z]; return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
} }
skipping to change at line 910 skipping to change at line 1163
{ {
VIGRA_ASSERT_INSIDE(difference_type(x, y,z, u,v)); VIGRA_ASSERT_INSIDE(difference_type(x, y,z, u,v));
return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_str ide[3]*u + m_stride[4]*v]; return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_str ide[3]*u + m_stride[4]*v];
} }
/** 1D const array access. Use only if N == 1. /** 1D const array access. Use only if N == 1.
*/ */
const_reference operator() (difference_type_1 x) const const_reference operator() (difference_type_1 x) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(x)); VIGRA_ASSERT_INSIDE(difference_type(x));
return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x)]; return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride , x)];
} }
/** 2D const array access. Use only if N == 2. /** 2D const array access. Use only if N == 2.
*/ */
const_reference operator() (difference_type_1 x, difference_type_1 y) c onst const_reference operator() (difference_type_1 x, difference_type_1 y) c onst
{ {
VIGRA_ASSERT_INSIDE(difference_type(x, y)); VIGRA_ASSERT_INSIDE(difference_type(x, y));
return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x, y)] ; return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride , x, y)];
} }
/** 3D const array access. Use only if N == 3. /** 3D const array access. Use only if N == 3.
*/ */
const_reference operator() (difference_type_1 x, difference_type_1 y, d ifference_type_1 z) const const_reference operator() (difference_type_1 x, difference_type_1 y, d ifference_type_1 z) const
{ {
VIGRA_ASSERT_INSIDE(difference_type(x,y,z)); VIGRA_ASSERT_INSIDE(difference_type(x,y,z));
return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z]; return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
} }
skipping to change at line 993 skipping to change at line 1246
/** swap the data between two MultiArrayView objects. /** swap the data between two MultiArrayView objects.
The shapes of the two array must match. The shapes of the two array must match.
*/ */
template <class T2, class C2> template <class T2, class C2>
void swapData(MultiArrayView <N, T2, C2> rhs) void swapData(MultiArrayView <N, T2, C2> rhs)
{ {
swapDataImpl(rhs); swapDataImpl(rhs);
} }
/** check whether the array is unstrided (i.e. has consecutive memo
ry) up
to the given dimension.
\a dimension can range from 0 ... N-1. If a certain dimension i
s unstrided,
all lower dimensions are also unstrided.
*/
bool isUnstrided(unsigned int dimension = N-1) const
{
difference_type p = shape() - difference_type(1);
for(unsigned int k = dimension+1; k < N; ++k)
p[k] = 0;
return (&operator[](p) - m_ptr) == coordinateToScanOrderIndex(p);
}
/** 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;
MultiArray<3, double> array3(Shape(40, 30, 20)); MultiArray<3, double> array3(Shape(40, 30, 20));
// get a 1D array by fixing index 1 to 12, and index 2 to 10 // get a 1D array by fixing index 1 to 12, and index 2 to 10
MultiArrayView <1, double> array1 = array3.bindOuter(TinyVector <int, 2>(12, 10)); MultiArrayView <1, double> array1 = array3.bindOuter(TinyVector <MultiArrayIndex, 2>(12, 10));
\endcode \endcode
*/ */
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-M, T, C> bindOuter (const TinyVector <MultiArrayIndex , M> &d) const; MultiArrayView <N-M, T, StrideTag> bindOuter (const TinyVector <MultiAr rayIndex, M> &d) const;
/** bind the M innermost dimensions to certain indices. /** bind the M innermost 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;
MultiArray<3, double> array3(Shape(40, 30, 20)); MultiArray<3, double> array3(Shape(40, 30, 20));
// get a 1D array by fixing index 0 to 12, and index 1 to 10 // get a 1D array by fixing index 0 to 12, and index 1 to 10
MultiArrayView <1, double, StridedArrayTag> array1 = array3.bin dInner(TinyVector<int, 2>(12, 10)); MultiArrayView <1, double, StridedArrayTag> array1 = array3.bin dInner(TinyVector<MultiArrayIndex, 2>(12, 10));
\endcode \endcode
*/ */
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-M, T, StridedArrayTag> MultiArrayView <N-M, T, StridedArrayTag>
bindInner (const TinyVector <MultiArrayIndex, M> &d) const; bindInner (const TinyVector <MultiArrayIndex, M> &d) const;
/** bind dimension M to index d. /** bind dimension M to index d.
this reduces the dimensionality of the image to this reduces the dimensionality of the image to
max { 1, N-1 }. max { 1, N-1 }.
skipping to change at line 1046 skipping to change at line 1313
MultiArray<3, double> array3(Shape(40, 30, 20)); MultiArray<3, double> array3(Shape(40, 30, 20));
// get a 2D array by fixing index 1 to 12 // get a 2D array by fixing index 1 to 12
MultiArrayView <2, double> array2 = array3.bind<1>(12); MultiArrayView <2, double> array2 = array3.bind<1>(12);
// get a 2D array by fixing index 0 to 23 // get a 2D array by fixing index 0 to 23
MultiArrayView <2, double, StridedArrayTag> array2a = array3.bi nd<0>(23); MultiArrayView <2, double, StridedArrayTag> array2a = array3.bi nd<0>(23);
\endcode \endcode
*/ */
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-1, T, typename vigra::detail::MaybeStrided <M>::type > MultiArrayView <N-1, T, typename vigra::detail::MaybeStrided<StrideTag, M>::type >
bind (difference_type_1 d) const; bind (difference_type_1 d) const;
/** bind the outmost dimension to a certain index. /** bind the outmost dimension to a certain index.
this reduces the dimensionality of the image to this reduces the dimensionality of the image to
max { 1, N-1 }. max { 1, N-1 }.
<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 2D array by fixing the outermost index (i.e. index 2) to 12 // get a 2D array by fixing the outermost index (i.e. index 2) to 12
MultiArrayView <2, double> array2 = array3.bindOuter(12); MultiArrayView <2, double> array2 = array3.bindOuter(12);
\endcode \endcode
*/ */
MultiArrayView <N-1, T, C> bindOuter (difference_type_1 d) const; MultiArrayView <N-1, T, StrideTag> bindOuter (difference_type_1 d) cons t;
/** bind the innermost dimension to a certain index. /** bind the innermost dimension to a certain index.
this reduces the dimensionality of the image to this reduces the dimensionality of the image to
max { 1, N-1 }. max { 1, N-1 }.
<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 1098 skipping to change at line 1365
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 2D array by fixing index 2 to 15 // get a 2D array by fixing index 2 to 15
MultiArrayView <2, double, StridedArrayTag> array2 = array3.bin dAt(2, 15); MultiArrayView <2, double, StridedArrayTag> array2 = array3.bin dAt(2, 15);
\endcode \endcode
*/ */
MultiArrayView <N-1, T, StridedArrayTag> MultiArrayView <N-1, T, StridedArrayTag>
bindAt (difference_type_1 m, difference_type_1 d) const; bindAt (difference_type_1 m, difference_type_1 d) const;
/** Add a singleton dimension (dimension of legth 1). /** Create a view to channel 'i' of a vector-like value type. Possi
ble value types
(of the original array) are: \ref TinyVector, \ref RGBValue, \r
ef FFTWComplex,
and <tt>std::complex</tt>. The list can be extended to any type
whose memory
layout is equivalent to a fixed-size C array, by specializing
<tt>ExpandElementResult</tt>.
<b>Usage:</b>
\code
MultiArray<2, RGBValue<float> > rgb_image(Shape2(w, h));
MultiArrayView<2, float, StridedArrayTag> red = rgb_image
.bindElementChannel(0);
MultiArrayView<2, float, StridedArrayTag> green = rgb_image
.bindElementChannel(1);
MultiArrayView<2, float, StridedArrayTag> blue = rgb_image
.bindElementChannel(2);
\endcode
*/
MultiArrayView <N, typename ExpandElementResult<T>::type, StridedArrayT
ag>
bindElementChannel(difference_type_1 i) const
{
vigra_precondition(0 <= i && i < ExpandElementResult<T>::size,
"MultiArrayView::bindElementChannel(i): 'i' out of range.");
return expandElements(0).bindInner(i);
}
/** Create a view where a vector-like element type is expanded into
a new
array dimension. The new dimension is inserted at index positio
n 'd',
which must be between 0 and N inclusive.
Possible value types of the original array are: \ref TinyVector
, \ref RGBValue,
\ref FFTWComplex, <tt>std::complex</tt>, and the built-in numbe
r types (in this
case, <tt>expandElements</tt> is equivalent to <tt>insertSingle
tonDimension</tt>).
The list of supported types can be extended to any type whose m
emory
layout is equivalent to a fixed-size C array, by specializing
<tt>ExpandElementResult</tt>.
<b>Usage:</b>
\code
MultiArray<2, RGBValue<float> > rgb_image(Shape2(w, h));
MultiArrayView<3, float, StridedArrayTag> multiband_image =
rgb_image.expandElements(2);
\endcode
*/
MultiArrayView <N+1, typename ExpandElementResult<T>::type, StridedArra
yTag>
expandElements(difference_type_1 d) const;
/** Add a singleton dimension (dimension of length 1).
Singleton dimensions don't change the size of the data, but int roduce Singleton dimensions don't change the size of the data, but int roduce
a new index that can only take the value 0. This is mainly usef ul for a new index that can only take the value 0. This is mainly usef ul for
the 'reduce mode' of transformMultiArray() and combineTwoMultiA rrays(), the 'reduce mode' of transformMultiArray() and combineTwoMultiA rrays(),
because these functions require the source and destination arra ys to because these functions require the source and destination arra ys to
have the same number of dimensions. have the same number of dimensions.
The range of \a i must be <tt>0 <= i <= N</tt>. The new dimensi on will become The range of \a i must be <tt>0 <= i <= N</tt>. The new dimensi on will become
the i'th index, and the old indices from i upwards will shift o ne the i'th index, and the old indices from i upwards will shift o ne
place to the right. place to the right.
skipping to change at line 1127 skipping to change at line 1438
typedef MultiArrayShape<1>::type Shape1; typedef MultiArrayShape<1>::type Shape1;
MultiArray<1, double> rowAverages(Shape1(30)); MultiArray<1, double> rowAverages(Shape1(30));
// 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, C> MultiArrayView <N+1, T, StrideTag>
insertSingletonDimension (difference_type_1 i) const; insertSingletonDimension (difference_type_1 i) const;
/** 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.
<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 1153 skipping to change at line 1464
MultiArrayView subarray (const difference_type &p, MultiArrayView subarray (const difference_type &p,
const difference_type &q) const const difference_type &q) const
{ {
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 layed 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] /= s [i];
return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr); return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr);
} }
skipping to change at line 1318 skipping to change at line 1629
/** 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 if the array contains only non-zero elements (or if all e
lements
are 'true' if the value type is 'bool').
*/
bool all() const
{
bool res = true;
detail::reduceOverMultiArray(traverser_begin(), shape(),
res,
detail::AllTrueReduceFunctor(),
MetaInt<actual_dimension-1>());
return res;
}
/** Check if the array contains a non-zero element (or an element
that is 'true' if the value type is 'bool').
*/
bool any() const
{
bool res = false;
detail::reduceOverMultiArray(traverser_begin(), shape(),
res,
detail::AnyTrueReduceFunctor(),
MetaInt<actual_dimension-1>());
return res;
}
/** Find the minimum and maximum element in this array.
*/
void minmax(T * minimum, T * maximum) const
{
std::pair<T, T> res(NumericTraits<T>::max(), NumericTraits<T>::min(
));
detail::reduceOverMultiArray(traverser_begin(), shape(),
res,
detail::MinmaxReduceFunctor(),
MetaInt<actual_dimension-1>());
*minimum = res.first;
*maximum = res.second;
}
/** Compute the mean and variance of the values in this array.
*/
template <class U>
void meanVariance(U * mean, U * variance) const
{
typedef typename NumericTraits<U>::RealPromote R;
triple<R, R, R> res(0.0, 0.0, 0.0);
detail::reduceOverMultiArray(traverser_begin(), shape(),
res,
detail::MeanVarianceReduceFunctor(),
MetaInt<actual_dimension-1>());
*mean = res.second;
*variance = res.third / res.first;
}
/** Compute the sum of the array elements.
You must provide the type of the result by an explicit template
parameter:
\code
MultiArray<2, UInt8> A(width, height);
double sum = A.sum<double>();
\endcode
*/
template <class U>
U sum() const
{
U res = NumericTraits<U>::zero();
detail::reduceOverMultiArray(traverser_begin(), shape(),
res,
detail::SumReduceFunctor(),
MetaInt<actual_dimension-1>());
return res;
}
/** Compute the sum of the array elements over selected axes.
\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
singletons. Note that you must include <tt>multi_pointoperators
.hxx</tt>
for this function to work.
<b>Usage:</b>
\code
#include <vigra/multi_array.hxx>
#include <vigra/multi_pointoperators.hxx>
MultiArray<2, double> A(rows, cols);
... // fill A
// make the first axis a singleton to sum over the first index
MultiArray<2, double> rowSums(1, cols);
A.sum(rowSums);
// this is equivalent to
transformMultiArray(srcMultiArrayRange(A),
destMultiArrayRange(rowSums),
FindSum<double>());
\endcode
*/
template <class U, class S>
void sum(MultiArrayView<N, U, S> sums) const
{
transformMultiArray(srcMultiArrayRange(*this),
destMultiArrayRange(sums),
FindSum<U>());
}
/** Compute the product of the array elements.
You must provide the type of the result by an explicit template
parameter:
\code
MultiArray<2, UInt8> A(width, height);
double prod = A.product<double>();
\endcode
*/
template <class U>
U product() const
{
U res = NumericTraits<U>::one();
detail::reduceOverMultiArray(traverser_begin(), shape(),
res,
detail::ProdReduceFunctor(),
MetaInt<actual_dimension-1>());
return res;
}
/** Compute the squared Euclidean norm of the array (sum of squares of the array elements). /** Compute the squared Euclidean norm of the array (sum of squares of the array elements).
*/ */
typename NormTraits<MultiArrayView>::SquaredNormType squaredNorm() cons typename NormTraits<MultiArrayView>::SquaredNormType
t squaredNorm() const
{ {
typedef typename NormTraits<MultiArrayView>::SquaredNormType Square dNormType; typedef typename NormTraits<MultiArrayView>::SquaredNormType Square dNormType;
SquaredNormType res = NumericTraits<SquaredNormType>::zero(); SquaredNormType res = NumericTraits<SquaredNormType>::zero();
detail::sumOverMultiArray(traverser_begin(), shape(), detail::Multi detail::reduceOverMultiArray(traverser_begin(), shape(),
ArrayL2Functor<SquaredNormType>(), res,
res, MetaInt<actual_dimension-1>()); detail::SquaredL2NormReduceFunctor(),
MetaInt<actual_dimension-1>());
return res; return res;
} }
/** Compute various norms of the array. /** Compute various norms of the array.
The norm is determined by parameter \a type: The norm is determined by parameter \a type:
<ul> <ul>
<li> type == 0: maximum norm (L-infinity): maximum of absolute values of the array elements <li> type == 0: maximum norm (L-infinity): maximum of absolute values of the array elements
<li> type == 1: Manhattan norm (L1): sum of absolute values of the array elements <li> type == 1: Manhattan norm (L1): sum of absolute values of the array elements
<li> type == 2: Euclidean norm (L2): square root of <tt>squared Norm()</tt> when \a useSquaredNorm is <tt>true</tt>,<br> <li> type == 2: Euclidean norm (L2): square root of <tt>squared Norm()</tt> when \a useSquaredNorm is <tt>true</tt>,<br>
or direct algorithm that avoids underflow/overflow otherwi se. or direct algorithm that avoids underflow/overflow otherwi se.
</ul> </ul>
Parameter \a useSquaredNorm has no effect when \a type != 2. De faults: compute L2 norm as square root of Parameter \a useSquaredNorm has no effect when \a type != 2. De faults: compute L2 norm as square root of
<tt>squaredNorm()</tt>. <tt>squaredNorm()</tt>.
*/ */
typename NormTraits<MultiArrayView>::NormType norm(int type = 2, bool u typename NormTraits<MultiArrayView>::NormType
seSquaredNorm = true) const; norm(int type = 2, bool useSquaredNorm = true) const;
/** return the pointer to the image data /** return the pointer to the image data
*/ */
pointer data () const pointer data () const
{ {
return m_ptr; return m_ptr;
} }
/** /**
* returns true iff this view refers to valid data, * returns true iff this view refers to valid data,
* i.e. data() is not a NULL pointer. (this is false after * i.e. data() is not a NULL pointer. (this is false after
* default construction.) * default construction.)
*/ */
bool hasData () const bool hasData () const
{ {
return m_ptr != 0; return m_ptr != 0;
} }
/** returns a scan-order iterator pointing
to the first array element.
*/
iterator begin()
{
return iterator(m_ptr, m_shape, m_stride);
}
/** returns a const scan-order iterator pointing
to the first array element.
*/
const_iterator begin() const
{
return const_iterator(m_ptr, m_shape, m_stride);
}
/** returns a scan-order iterator pointing
beyond the last array element.
*/
iterator end()
{
return begin().getEndIterator();
}
/** returns a const scan-order iterator pointing
beyond the last array element.
*/
const_iterator end() const
{
return begin().getEndIterator();
}
/** returns the N-dimensional MultiIterator pointing /** returns the N-dimensional MultiIterator pointing
to the first element in every dimension. to the first element in every dimension.
*/ */
traverser traverser_begin () traverser traverser_begin ()
{ {
traverser ret (m_ptr, m_stride.begin (), m_shape.begin ()); traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
return ret; return ret;
} }
/** returns the N-dimensional MultiIterator pointing /** returns the N-dimensional MultiIterator pointing
skipping to change at line 1407 skipping to change at line 1881
ret += m_shape [actual_dimension-1]; ret += m_shape [actual_dimension-1];
return ret; return ret;
} }
view_type view () view_type view ()
{ {
return *this; return *this;
} }
}; };
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView<N, T, C> & MultiArrayView<N, T, StrideTag> &
MultiArrayView <N, T, C>::operator=(MultiArrayView<N, T, C> const & rhs) MultiArrayView <N, T, StrideTag>::operator=(MultiArrayView const & rhs)
{ {
if(this == &rhs) if(this == &rhs)
return *this; return *this;
vigra_precondition(this->shape() == rhs.shape() || m_ptr == 0, vigra_precondition(this->shape() == rhs.shape() || m_ptr == 0,
"MultiArrayView::operator=(MultiArrayView const &) size mismatch - use MultiArrayView::reset()."); "MultiArrayView::operator=(MultiArrayView const &) size mismatch.") ;
if(m_ptr == 0) if(m_ptr == 0)
{ {
m_shape = rhs.m_shape; m_shape = rhs.m_shape;
m_stride = rhs.m_stride; m_stride = rhs.m_stride;
m_ptr = rhs.m_ptr; m_ptr = rhs.m_ptr;
} }
else else
this->copyImpl(rhs); this->copyImpl(rhs);
return *this; return *this;
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
template <class CN> template <class CN>
bool bool
MultiArrayView <N, T, C>::arraysOverlap(const MultiArrayView <N, T, CN>& rh s) 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,
last_element = first_element + dot(this->m_shape - differ ence_type(1), this->m_stride); last_element = first_element + dot(this->m_shape - differ ence_type(1), this->m_stride);
typename MultiArrayView <N, T, CN>::const_pointer typename MultiArrayView <N, T, CN>::const_pointer
rhs_first_element = rhs.data(), rhs_first_element = rhs.data(),
rhs_last_element = rhs_first_element + dot(rhs.shape() - differe nce_type(1), rhs.stride()); rhs_last_element = rhs_first_element + dot(rhs.shape() - differe nce_type(1), rhs.stride());
return !(last_element < rhs_first_element || rhs_last_element < first_e lement); return !(last_element < rhs_first_element || rhs_last_element < first_e lement);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
template <class U, class CN> template <class U, class CN>
void void
MultiArrayView <N, T, C>::copyImpl(const MultiArrayView <N, U, CN>& rhs) MultiArrayView <N, T, StrideTag>::copyImpl(const MultiArrayView <N, U, CN>& rhs)
{ {
if(!arraysOverlap(rhs)) if(!arraysOverlap(rhs))
{ {
// no overlap -- can copy directly // no overlap -- can copy directly
detail::copyMultiArrayData(rhs.traverser_begin(), shape(), traverse r_begin(), MetaInt<actual_dimension-1>()); detail::copyMultiArrayData(rhs.traverser_begin(), shape(), traverse r_begin(), MetaInt<actual_dimension-1>());
} }
else else
{ {
// overlap: we got different views to the same data -- copy to inte rmediate memory in order to avoid // overlap: we got different views to the same data -- copy to inte rmediate memory in order to avoid
// overwriting elements that are still needed on the rhs. // overwriting elements that are still needed on the rhs.
MultiArray<N, T> tmp(rhs); MultiArray<N, T> tmp(rhs);
detail::copyMultiArrayData(tmp.traverser_begin(), shape(), traverse r_begin(), MetaInt<actual_dimension-1>()); detail::copyMultiArrayData(tmp.traverser_begin(), shape(), traverse r_begin(), MetaInt<actual_dimension-1>());
} }
} }
#define VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(name, op) \ #define VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(name, op) \
template <unsigned int N, class T, class C> \ template <unsigned int N, class T, class StrideTag> \
template<class U, class C1> \ template<class U, class C1> \
MultiArrayView<N, T, C> & \ MultiArrayView<N, T, StrideTag> & \
MultiArrayView <N, T, C>::operator op(MultiArrayView<N, U, C1> const & rhs) MultiArrayView <N, T, StrideTag>::operator op(MultiArrayView<N, U, C1> cons
\ t & rhs) \
{ \ { \
vigra_precondition(this->shape() == rhs.shape(), "MultiArrayView::opera tor" #op "() size mismatch."); \ vigra_precondition(this->shape() == rhs.shape(), "MultiArrayView::opera tor" #op "() size mismatch."); \
if(!arraysOverlap(rhs)) \ if(!arraysOverlap(rhs)) \
{ \ { \
detail::name##MultiArrayData(rhs.traverser_begin(), shape(), traver ser_begin(), MetaInt<actual_dimension-1>()); \ detail::name##MultiArrayData(rhs.traverser_begin(), shape(), traver ser_begin(), MetaInt<actual_dimension-1>()); \
} \ } \
else \ else \
{ \ { \
MultiArray<N, T> tmp(rhs); \ MultiArray<N, T> tmp(rhs); \
detail::name##MultiArrayData(tmp.traverser_begin(), shape(), traver ser_begin(), MetaInt<actual_dimension-1>()); \ detail::name##MultiArrayData(tmp.traverser_begin(), shape(), traver ser_begin(), MetaInt<actual_dimension-1>()); \
} \ } \
return *this; \ return *this; \
} }
VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copyAdd, +=) VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyAdd, +=)
VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copySub, -=) VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copySub, -=)
VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copyMul, *=) VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyMul, *=)
VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT(copyDiv, /=) VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyDiv, /=)
#undef VIGRA_MULTI_ARRY_COMPUTED_ASSIGNMENT #undef VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
template <class U, class CN> template <class U, class CN>
void void
MultiArrayView <N, T, C>::swapDataImpl(MultiArrayView <N, U, CN> rhs) MultiArrayView <N, T, StrideTag>::swapDataImpl(MultiArrayView <N, U, CN> rh s)
{ {
vigra_precondition (shape () == rhs.shape (), vigra_precondition (shape () == rhs.shape (),
"MultiArrayView::swapData(): shape mismatch."); "MultiArrayView::swapData(): shape mismatch.");
// check for overlap of this and rhs // check for overlap of this and rhs
const_pointer first_element = this->m_ptr, const_pointer first_element = this->m_ptr,
last_element = first_element + dot(this->m_shape - differ ence_type(1), this->m_stride); last_element = first_element + dot(this->m_shape - differ ence_type(1), this->m_stride);
typename MultiArrayView <N, U, CN>::const_pointer typename MultiArrayView <N, U, CN>::const_pointer
rhs_first_element = rhs.data(), rhs_first_element = rhs.data(),
rhs_last_element = rhs_first_element + dot(rhs.shape() - differe nce_type(1), rhs.stride()); rhs_last_element = rhs_first_element + dot(rhs.shape() - differe nce_type(1), rhs.stride());
skipping to change at line 1515 skipping to change at line 1989
else else
{ {
// overlap: we got different views to the same data -- copy to inte rmediate memory in order to avoid // overlap: we got different views to the same data -- copy to inte rmediate memory in order to avoid
// overwriting elements that are still needed. // overwriting elements that are still needed.
MultiArray<N, T> tmp(*this); MultiArray<N, T> tmp(*this);
copy(rhs); copy(rhs);
rhs.copy(tmp); rhs.copy(tmp);
} }
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
MultiArrayView <N, T, C>::permuteDimensions (const difference_type &s) cons t 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::permuteDimensions(): every dimension must occur exa ctly once.");
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 C> template <unsigned int N, class T, class StrideTag>
typename MultiArrayView <N, T, C>::difference_type typename MultiArrayView <N, T, StrideTag>::difference_type
MultiArrayView <N, T, C>::strideOrdering(difference_type stride) MultiArrayView <N, T, StrideTag>::strideOrdering(difference_type stride)
{ {
difference_type permutation; difference_type permutation;
for(unsigned int k=0; k<N; ++k) for(int k=0; k<(int)N; ++k)
permutation[k] = k; permutation[k] = k;
for(unsigned int k=0; k<N-1; ++k) for(int k=0; k<(int)N-1; ++k)
{ {
unsigned int smallest = k; int smallest = k;
for(unsigned int j=k+1; j<N; ++j) for(int j=k+1; j<(int)N; ++j)
{ {
if(stride[j] < stride[smallest]) if(stride[j] < stride[smallest])
smallest = j; smallest = j;
} }
if(smallest != k) if(smallest != k)
{ {
std::swap(stride[k], stride[smallest]); std::swap(stride[k], stride[smallest]);
std::swap(permutation[k], permutation[smallest]); std::swap(permutation[k], permutation[smallest]);
} }
} }
difference_type ordering; difference_type ordering;
for(unsigned int k=0; k<N; ++k) for(unsigned int k=0; k<N; ++k)
ordering[permutation[k]] = k; ordering[permutation[k]] = k;
return ordering; return ordering;
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
MultiArrayView <N, T, C>::permuteStridesAscending() const MultiArrayView <N, T, StrideTag>::permuteStridesAscending() 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[k]] = k; permutation[ordering[k]] = k;
return permuteDimensions(permutation); return permuteDimensions(permutation);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N, T, StridedArrayTag> MultiArrayView <N, T, StridedArrayTag>
MultiArrayView <N, T, C>::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[ordering[N-1-k]] = k;
return permuteDimensions(permutation); return permuteDimensions(permutation);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-M, T, C> MultiArrayView <N-M, T, StrideTag>
MultiArrayView <N, T, C>::bindOuter (const TinyVector <MultiArrayIndex, M> MultiArrayView <N, T, StrideTag>::bindOuter (const TinyVector <MultiArrayIn
&d) const dex, 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] = 0;
} }
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, C> (inner_shape, inner_stride, ptr); return MultiArrayView <N-M, T, StrideTag> (inner_shape, inner_stride, p tr);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
template <unsigned int M> template <unsigned int M>
MultiArrayView <N - M, T, StridedArrayTag> MultiArrayView <N - M, T, StridedArrayTag>
MultiArrayView <N, T, C>::bindInner (const TinyVector <MultiArrayIndex, M> &d) const MultiArrayView <N, T, StrideTag>::bindInner (const TinyVector <MultiArrayIn dex, 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] = 0;
} }
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);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
template <unsigned int M> template <unsigned int M>
MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type > MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type >
MultiArrayView <N, T, C>::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] = 0;
} }
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);
} }
return MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type> return MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type>
(shape, stride, m_ptr + d * m_stride[M]); (shape, stride, m_ptr + d * m_stride[M]);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N - 1, T, C> MultiArrayView <N - 1, T, StrideTag>
MultiArrayView <N, T, C>::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] = 0;
} }
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, C> (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 C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N - 1, T, StridedArrayTag> MultiArrayView <N - 1, T, StridedArrayTag>
MultiArrayView <N, T, C>::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] = 0;
} }
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]);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N - 1, T, StridedArrayTag> MultiArrayView <N - 1, T, StridedArrayTag>
MultiArrayView <N, T, C>::bindAt (difference_type_1 n, difference_type_1 d) const MultiArrayView <N, T, StrideTag>::bindAt (difference_type_1 n, difference_t ype_1 d) const
{ {
vigra_precondition ( vigra_precondition (
n < static_cast <int> (N), n < static_cast <int> (N),
"MultiArrayView <N, T, C>::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] = 0;
} }
else else
{ {
skipping to change at line 1719 skipping to change at line 2193
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);
} }
return MultiArrayView <N-1, T, StridedArrayTag> return MultiArrayView <N-1, T, StridedArrayTag>
(shape, stride, m_ptr + d * m_stride[n]); (shape, stride, m_ptr + d * m_stride[n]);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
MultiArrayView <N + 1, T, C> MultiArrayView <N+1, typename ExpandElementResult<T>::type, StridedArrayTag
MultiArrayView <N, T, C>::insertSingletonDimension (difference_type_1 i) co >
nst MultiArrayView <N, T, StrideTag>::expandElements(difference_type_1 d) const
{
vigra_precondition(0 <= d && d <= static_cast <difference_type_1> (N),
"MultiArrayView<N, ...>::expandElements(d): 0 <= 'd' <= N require
d.");
int elementSize = ExpandElementResult<T>::size;
typename MultiArrayShape<N+1>::type newShape, newStrides;
for(int k=0; k<d; ++k)
{
newShape[k] = m_shape[k];
newStrides[k] = m_stride[k]*elementSize;
}
newShape[d] = elementSize;
newStrides[d] = 1;
for(int k=d; k<N; ++k)
{
newShape[k+1] = m_shape[k];
newStrides[k+1] = m_stride[k]*elementSize;
}
typedef typename ExpandElementResult<T>::type U;
return MultiArrayView<N+1, U, StridedArrayTag>(
newShape, newStrides, reinterpret_cast<U*>(m_ptr));
}
template <unsigned int N, class T, class StrideTag>
MultiArrayView <N+1, T, StrideTag>
MultiArrayView <N, T, StrideTag>::insertSingletonDimension (difference_type
_1 i) const
{ {
vigra_precondition ( vigra_precondition (
0 <= i && i <= static_cast <difference_type_1> (N), 0 <= i && i <= static_cast <difference_type_1> (N),
"MultiArrayView <N, T, C>::insertSingletonDimension(): index out of range."); "MultiArrayView <N, T, StrideTag>::insertSingletonDimension(): inde x out of range.");
TinyVector <MultiArrayIndex, N+1> shape, stride; TinyVector <MultiArrayIndex, N+1> shape, stride;
std::copy (m_shape.begin (), m_shape.begin () + i, shape.begin ()); std::copy (m_shape.begin (), m_shape.begin () + i, shape.begin ());
std::copy (m_shape.begin () + i, m_shape.end (), shape.begin () + i + 1 ); std::copy (m_shape.begin () + i, m_shape.end (), shape.begin () + i + 1 );
std::copy (m_stride.begin (), m_stride.begin () + i, stride.begin ()); std::copy (m_stride.begin (), m_stride.begin () + i, stride.begin ());
std::copy (m_stride.begin () + i, m_stride.end (), stride.begin () + i + 1); std::copy (m_stride.begin () + i, m_stride.end (), stride.begin () + i + 1);
shape[i] = 1; shape[i] = 1;
stride[i] = 1; stride[i] = 1;
return MultiArrayView <N+1, T, C>(shape, stride, m_ptr); return MultiArrayView <N+1, T, StrideTag>(shape, stride, m_ptr);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
typename NormTraits<MultiArrayView <N, T, C> >::NormType typename NormTraits<MultiArrayView <N, T, StrideTag> >::NormType
MultiArrayView <N, T, C>::norm(int type, bool useSquaredNorm) const MultiArrayView <N, T, StrideTag>::norm(int type, bool useSquaredNorm) const
{ {
typedef typename NormTraits<MultiArrayView>::NormType NormType; typedef typename NormTraits<MultiArrayView>::NormType NormType;
switch(type) switch(type)
{ {
case 0: case 0:
{ {
NormType res = NumericTraits<NormType>::zero(); NormType res = NumericTraits<NormType>::zero();
detail::normMaxOfMultiArray(traverser_begin(), shape(), res, MetaIn detail::reduceOverMultiArray(traverser_begin(), shape(),
t<actual_dimension-1>()); res,
detail::MaxNormReduceFunctor(),
MetaInt<actual_dimension-1>());
return res; return res;
} }
case 1: case 1:
{ {
NormType res = NumericTraits<NormType>::zero(); NormType res = NumericTraits<NormType>::zero();
detail::sumOverMultiArray(traverser_begin(), shape(), detail::Multi detail::reduceOverMultiArray(traverser_begin(), shape(),
ArrayL1Functor<NormType>(), res,
res, MetaInt<actual_dimension-1>()); detail::L1NormReduceFunctor(),
MetaInt<actual_dimension-1>());
return res; return res;
} }
case 2: case 2:
{ {
if(useSquaredNorm) if(useSquaredNorm)
{ {
return sqrt((NormType)squaredNorm()); return sqrt((NormType)squaredNorm());
} }
else else
{ {
NormType normMax = NumericTraits<NormType>::zero(); NormType normMax = NumericTraits<NormType>::zero();
detail::normMaxOfMultiArray(traverser_begin(), shape(), normMax detail::reduceOverMultiArray(traverser_begin(), shape(),
, MetaInt<actual_dimension-1>()); normMax,
detail::MaxNormReduceFunctor(),
MetaInt<actual_dimension-1>());
if(normMax == NumericTraits<NormType>::zero()) if(normMax == NumericTraits<NormType>::zero())
return normMax; return normMax;
NormType res = NumericTraits<NormType>::zero(); NormType res = NumericTraits<NormType>::zero();
detail::sumOverMultiArray(traverser_begin(), shape(), detail::M detail::reduceOverMultiArray(traverser_begin(), shape(),
ultiArrayScaledL2Functor<NormType>(normMax), res,
res, MetaInt<actual_dimension-1>()); detail::WeightedL2NormReduceFuncto
r<NormType>(1.0/normMax),
MetaInt<actual_dimension-1>());
return sqrt(res)*normMax; return sqrt(res)*normMax;
} }
} }
default: default:
vigra_precondition(false, "MultiArrayView::norm(): Unknown norm typ e."); vigra_precondition(false, "MultiArrayView::norm(): Unknown norm typ e.");
return NumericTraits<NormType>::zero(); // unreachable return NumericTraits<NormType>::zero(); // unreachable
} }
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* norm */ /* norm */
/* */ /* */
/********************************************************/ /********************************************************/
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
inline typename NormTraits<MultiArrayView <N, T, C> >::SquaredNormType inline typename NormTraits<MultiArrayView <N, T, StrideTag> >::SquaredNormT
squaredNorm(MultiArrayView <N, T, C> const & a) ype
squaredNorm(MultiArrayView <N, T, StrideTag> const & a)
{ {
return a.squaredNorm(); return a.squaredNorm();
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
inline typename NormTraits<MultiArrayView <N, T, C> >::NormType inline typename NormTraits<MultiArrayView <N, T, StrideTag> >::NormType
norm(MultiArrayView <N, T, C> const & a) norm(MultiArrayView <N, T, StrideTag> const & a)
{ {
return a.norm(); return a.norm();
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiArray */ /* MultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 1826 skipping to change at line 2339
\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>
\<<a href="multi__array_8hxx-source.html">vigra/multi_array.hxx</a>\> \<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, T>
{ {
public: public:
using MultiArrayView <N, T>::actual_dimension; using MultiArrayView <N, T>::actual_dimension;
skipping to change at line 1923 skipping to change at line 2436
/** allocate memory for s pixels, write its address into the given /** allocate memory for s pixels, write its address into the given
pointer and initialize the linearized pixels to the values of i nit. pointer and initialize the linearized pixels to the values of i nit.
*/ */
template <class U> template <class U>
void allocate (pointer &ptr, difference_type_1 s, U const * init); void allocate (pointer &ptr, difference_type_1 s, U const * init);
/** allocate memory, write its address into the given /** allocate memory, write its address into the given
pointer and initialize it by copying the data from the given Mu ltiArrayView. pointer and initialize it by copying the data from the given Mu ltiArrayView.
*/ */
template <class U, class C> template <class U, class StrideTag>
void allocate (pointer &ptr, MultiArrayView<N, U, C> const & init); void allocate (pointer &ptr, MultiArrayView<N, U, StrideTag> const & in
it);
/** 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 C> template <class U, class StrideTag>
void copyOrReshape (const MultiArrayView<N, U, C> &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)), : MultiArrayView <N, T> (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
*/ */
skipping to change at line 1972 skipping to change at line 2485
/** copy constructor /** copy constructor
*/ */
MultiArray (const MultiArray &rhs) MultiArray (const MultiArray &rhs)
: MultiArrayView <N, T> (rhs.m_shape, rhs.m_stride, 0), : MultiArrayView <N, T> (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
*/
template<class Expression>
MultiArray (multi_math::MultiMathOperand<Expression> const & rhs,
allocator_type const & alloc = allocator_type())
: MultiArrayView <N, T> (difference_type (diff_zero_t(0)),
difference_type (diff_zero_t(0)), 0),
m_alloc (alloc)
{
multi_math::detail::assignOrResize(*this, rhs);
}
/** construct by copying from a MultiArrayView /** construct by copying from a MultiArrayView
*/ */
template <class U, class C> template <class U, class StrideTag>
MultiArray (const MultiArrayView<N, U, C> &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
the data are copied. Otherwise, new storage is allocated, which invalidates all the data are copied. Otherwise, new storage is allocated, which invalidates all
objects (array views, iterators) depending on the lhs array. objects (array views, iterators) depending on the lhs array.
*/ */
MultiArray & operator= (const MultiArray &rhs) MultiArray & operator= (const MultiArray &rhs)
{ {
if (this != &rhs) if (this != &rhs)
this->copyOrReshape(rhs); this->copyOrReshape(rhs);
return *this; return *this;
} }
/** assignment from arbitrary MultiArrayView.<br> /** assignment from arbitrary MultiArrayView.<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
the data are copied. Otherwise, new storage is allocated, which invalidates all the data are copied. Otherwise, new storage is allocated, which invalidates all
objects (array views, iterators) depending on the lhs array. objects (array views, iterators) depending on the lhs array.
*/ */
template <class U, class C> template <class U, class StrideTag>
MultiArray &operator= (const MultiArrayView<N, U, C> &rhs) MultiArray &operator= (const MultiArrayView<N, U, StrideTag> &rhs)
{ {
this->copyOrReshape(rhs); this->copyOrReshape(rhs);
return *this; return *this;
} }
/** Add-assignment from arbitrary MultiArrayView. Fails with /** Add-assignment from arbitrary MultiArrayView. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template <class U, class C> template <class U, class StrideTag>
MultiArray &operator+= (const MultiArrayView<N, U, C> &rhs) MultiArray &operator+= (const MultiArrayView<N, U, StrideTag> &rhs)
{ {
view_type::operator+=(rhs); view_type::operator+=(rhs);
return *this; return *this;
} }
/** Subtract-assignment from arbitrary MultiArrayView. Fails with /** Subtract-assignment from arbitrary MultiArrayView. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template <class U, class C> template <class U, class StrideTag>
MultiArray &operator-= (const MultiArrayView<N, U, C> &rhs) MultiArray &operator-= (const MultiArrayView<N, U, StrideTag> &rhs)
{ {
view_type::operator-=(rhs); view_type::operator-=(rhs);
return *this; return *this;
} }
/** Multiply-assignment from arbitrary MultiArrayView. Fails with /** Multiply-assignment from arbitrary MultiArrayView. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template <class U, class C> template <class U, class StrideTag>
MultiArray &operator*= (const MultiArrayView<N, U, C> &rhs) MultiArray &operator*= (const MultiArrayView<N, U, StrideTag> &rhs)
{ {
view_type::operator*=(rhs); view_type::operator*=(rhs);
return *this; return *this;
} }
/** Divide-assignment from arbitrary MultiArrayView. Fails with /** Divide-assignment from arbitrary MultiArrayView. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not match. <tt>PreconditionViolation</tt> exception when the shapes do not match.
*/ */
template <class U, class C> template <class U, class StrideTag>
MultiArray &operator/= (const MultiArrayView<N, U, C> &rhs) MultiArray &operator/= (const MultiArrayView<N, U, StrideTag> &rhs)
{ {
view_type::operator/=(rhs); view_type::operator/=(rhs);
return *this; return *this;
} }
/** Add-assignment of a scalar. /** Add-assignment of a scalar.
*/ */
MultiArray &operator+= (const T &rhs) MultiArray &operator+= (const T &rhs)
{ {
view_type::operator+=(rhs); view_type::operator+=(rhs);
skipping to change at line 2073 skipping to change at line 2598
return *this; return *this;
} }
/** Divide-assignment of a scalar. /** Divide-assignment of a scalar.
*/ */
MultiArray &operator/= (const T &rhs) MultiArray &operator/= (const T &rhs)
{ {
view_type::operator/=(rhs); view_type::operator/=(rhs);
return *this; return *this;
} }
/** Assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArray & operator=(multi_math::MultiMathOperand<Expression> const &
rhs)
{
multi_math::detail::assignOrResize(*this, rhs);
return *this;
}
/** Add-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArray & operator+=(multi_math::MultiMathOperand<Expression> const
& rhs)
{
multi_math::detail::plusAssignOrResize(*this, rhs);
return *this;
}
/** Subtract-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArray & operator-=(multi_math::MultiMathOperand<Expression> const
& rhs)
{
multi_math::detail::minusAssignOrResize(*this, rhs);
return *this;
}
/** Multiply-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArray & operator*=(multi_math::MultiMathOperand<Expression> const
& rhs)
{
multi_math::detail::multiplyAssignOrResize(*this, rhs);
return *this;
}
/** Divide-assignment of an array expression. Fails with
<tt>PreconditionViolation</tt> exception when the shapes do not
match.
*/
template<class Expression>
MultiArray & operator/=(multi_math::MultiMathOperand<Expression> const
& rhs)
{
multi_math::detail::divideAssignOrResize(*this, rhs);
return *this;
}
/** destructor /** destructor
*/ */
~MultiArray () ~MultiArray ()
{ {
deallocate (this->m_ptr, this->elementCount ()); deallocate (this->m_ptr, this->elementCount ());
} }
/** init elements with a constant /** init elements with a constant
*/ */
skipping to change at line 2096 skipping to change at line 2670
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, NumericTraits <T>::zero ()); reshape (shape, T());
} }
/** 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,
skipping to change at line 2162 skipping to change at line 2736
: MultiArrayView <N, T> (shape, : MultiArrayView <N, T> (shape,
detail::defaultStride <MultiArrayView<N,T>::actual _dimension> (shape), detail::defaultStride <MultiArrayView<N,T>::actual _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] = 0;
} }
allocate (this->m_ptr, this->elementCount (), NumericTraits<T>::zero () ); allocate (this->m_ptr, this->elementCount (), T());
} }
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, : MultiArrayView <N, T> (shape,
detail::defaultStride <MultiArrayView<N,T>::actual _dimension> (shape), detail::defaultStride <MultiArrayView<N,T>::actual _dimension> (shape),
0), 0),
m_alloc(alloc) m_alloc(alloc)
{ {
skipping to change at line 2198 skipping to change at line 2772
{ {
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] = 0;
} }
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 C> template <class U, class StrideTag>
MultiArray <N, T, A>::MultiArray(const MultiArrayView<N, U, C> &rhs, 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(), : MultiArrayView <N, T> (rhs.shape(),
detail::defaultStride <MultiArrayView<N,T>::actual _dimension>(rhs.shape()), detail::defaultStride <MultiArrayView<N,T>::actual _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 C> template <class U, class StrideTag>
void void
MultiArray <N, T, A>::copyOrReshape(const MultiArrayView<N, U, C> &rhs) MultiArray <N, T, A>::copyOrReshape(const MultiArrayView<N, U, StrideTag> & rhs)
{ {
if (this->shape() == rhs.shape()) if (this->shape() == rhs.shape())
this->copy(rhs); this->copy(rhs);
else else
{ {
MultiArray t(rhs); MultiArray t(rhs);
this->swap(t); this->swap(t);
} }
} }
skipping to change at line 2250 skipping to change at line 2824
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
MultiArray <N, T, A>::swap (MultiArray <N, T, A> &amp; other) MultiArray <N, T, A>::swap (MultiArray & other)
{ {
if (this == &other) if (this == &other)
return; return;
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>
skipping to change at line 2298 skipping to change at line 2872
} }
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 C> template <class U, class StrideTag>
void MultiArray <N, T, A>::allocate (pointer & ptr, MultiArrayView<N, U, C> void MultiArray <N, T, A>::allocate (pointer & ptr, MultiArrayView<N, U, St
const & init) rideTag> const & init)
{ {
difference_type_1 s = init.elementCount(); difference_type_1 s = init.elementCount();
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)
skipping to change at line 2333 skipping to change at line 2907
m_alloc.deallocate (ptr, (typename A::size_type)s); m_alloc.deallocate (ptr, (typename A::size_type)s);
ptr = 0; ptr = 0;
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* argument object factories */ /* argument object factories */
/* */ /* */
/********************************************************/ /********************************************************/
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
inline triple<typename MultiArrayView<N,T,C>::const_traverser, inline triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
typename AccessorTraits<T>::default_const_accessor > typename AccessorTraits<T>::default_const_accessor >
srcMultiArrayRange( MultiArrayView<N,T,C> const & array ) srcMultiArrayRange( MultiArrayView<N,T,StrideTag> const & array )
{ {
return triple<typename MultiArrayView<N,T,C>::const_traverser, return triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
typename AccessorTraits<T>::default_const_accessor > typename AccessorTraits<T>::default_const_accessor >
( array.traverser_begin(), ( array.traverser_begin(),
array.shape(), array.shape(),
typename AccessorTraits<T>::default_const_accessor() ); typename AccessorTraits<T>::default_const_accessor() );
} }
template <unsigned int N, class T, class C, class Accessor> template <unsigned int N, class T, class StrideTag, class Accessor>
inline triple<typename MultiArrayView<N,T,C>::const_traverser, inline triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
Accessor > Accessor >
srcMultiArrayRange( MultiArrayView<N,T,C> const & array, Accessor a ) srcMultiArrayRange( MultiArrayView<N,T,StrideTag> const & array, Accessor a )
{ {
return triple<typename MultiArrayView<N,T,C>::const_traverser, return triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
Accessor > Accessor >
( array.traverser_begin(), ( array.traverser_begin(),
array.shape(), array.shape(),
a); a);
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
inline pair<typename MultiArrayView<N,T,C>::const_traverser, inline pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
typename AccessorTraits<T>::default_const_accessor > typename AccessorTraits<T>::default_const_accessor >
srcMultiArray( MultiArrayView<N,T,C> const & array ) srcMultiArray( MultiArrayView<N,T,StrideTag> const & array )
{ {
return pair<typename MultiArrayView<N,T,C>::const_traverser, return pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
typename AccessorTraits<T>::default_const_accessor > typename AccessorTraits<T>::default_const_accessor >
( array.traverser_begin(), ( array.traverser_begin(),
typename AccessorTraits<T>::default_const_accessor() ); typename AccessorTraits<T>::default_const_accessor() );
} }
template <unsigned int N, class T, class C, class Accessor> template <unsigned int N, class T, class StrideTag, class Accessor>
inline pair<typename MultiArrayView<N,T,C>::const_traverser, inline pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
Accessor > Accessor >
srcMultiArray( MultiArrayView<N,T,C> const & array, Accessor a ) srcMultiArray( MultiArrayView<N,T,StrideTag> const & array, Accessor a )
{ {
return pair<typename MultiArrayView<N,T,C>::const_traverser, return pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
Accessor > Accessor >
( array.traverser_begin(), a ); ( array.traverser_begin(), a );
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
inline triple<typename MultiArrayView<N,T,C>::traverser, inline triple<typename MultiArrayView<N,T,StrideTag>::traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
typename AccessorTraits<T>::default_accessor > typename AccessorTraits<T>::default_accessor >
destMultiArrayRange( MultiArrayView<N,T,C> & array ) destMultiArrayRange( MultiArrayView<N,T,StrideTag> & array )
{ {
return triple<typename MultiArrayView<N,T,C>::traverser, return triple<typename MultiArrayView<N,T,StrideTag>::traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
typename AccessorTraits<T>::default_accessor > typename AccessorTraits<T>::default_accessor >
( array.traverser_begin(), ( array.traverser_begin(),
array.shape(), array.shape(),
typename AccessorTraits<T>::default_accessor() ); typename AccessorTraits<T>::default_accessor() );
} }
template <unsigned int N, class T, class C, class Accessor> template <unsigned int N, class T, class StrideTag, class Accessor>
inline triple<typename MultiArrayView<N,T,C>::traverser, inline triple<typename MultiArrayView<N,T,StrideTag>::traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
Accessor > Accessor >
destMultiArrayRange( MultiArrayView<N,T,C> & array, Accessor a ) destMultiArrayRange( MultiArrayView<N,T,StrideTag> & array, Accessor a )
{ {
return triple<typename MultiArrayView<N,T,C>::traverser, return triple<typename MultiArrayView<N,T,StrideTag>::traverser,
typename MultiArrayView<N,T,C>::difference_type, typename MultiArrayView<N,T,StrideTag>::difference_type,
Accessor > Accessor >
( array.traverser_begin(), ( array.traverser_begin(),
array.shape(), array.shape(),
a ); a );
} }
template <unsigned int N, class T, class C> template <unsigned int N, class T, class StrideTag>
inline pair<typename MultiArrayView<N,T,C>::traverser, inline pair<typename MultiArrayView<N,T,StrideTag>::traverser,
typename AccessorTraits<T>::default_accessor > typename AccessorTraits<T>::default_accessor >
destMultiArray( MultiArrayView<N,T,C> & array ) destMultiArray( MultiArrayView<N,T,StrideTag> & array )
{ {
return pair<typename MultiArrayView<N,T,C>::traverser, return pair<typename MultiArrayView<N,T,StrideTag>::traverser,
typename AccessorTraits<T>::default_accessor > typename AccessorTraits<T>::default_accessor >
( array.traverser_begin(), ( array.traverser_begin(),
typename AccessorTraits<T>::default_accessor() ); typename AccessorTraits<T>::default_accessor() );
} }
template <unsigned int N, class T, class C, class Accessor> template <unsigned int N, class T, class StrideTag, class Accessor>
inline pair<typename MultiArrayView<N,T,C>::traverser, inline pair<typename MultiArrayView<N,T,StrideTag>::traverser,
Accessor > Accessor >
destMultiArray( MultiArrayView<N,T,C> & array, Accessor a ) destMultiArray( MultiArrayView<N,T,StrideTag> & array, Accessor a )
{ {
return pair<typename MultiArrayView<N,T,C>::traverser, return pair<typename MultiArrayView<N,T,StrideTag>::traverser,
Accessor > Accessor >
( array.traverser_begin(), a ); ( array.traverser_begin(), a );
} }
/********************************************************************/ /********************************************************************/
template <class PixelType, class Accessor> template <class PixelType, class Accessor>
inline triple<ConstStridedImageIterator<PixelType>, inline triple<ConstStridedImageIterator<PixelType>,
ConstStridedImageIterator<PixelType>, Accessor> ConstStridedImageIterator<PixelType>, Accessor>
srcImageRange(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Ac cessor a) srcImageRange(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Ac cessor a)
 End of changes. 153 change blocks. 
222 lines changed or deleted 851 lines changed or added


 multi_convolution.hxx   multi_convolution.hxx 
skipping to change at line 50 skipping to change at line 50
#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 "functorexpression.hxx" #include "functorexpression.hxx"
#include "tinyvector.hxx"
#include "algorithm.hxx"
namespace vigra namespace vigra
{ {
namespace detail namespace detail
{ {
struct DoubleYielder
{
const double value;
DoubleYielder(double v, unsigned, const char *const) : value(v) {}
DoubleYielder(double v) : value(v) {}
void operator++() {}
double operator*() const { return value; }
};
template <typename X>
struct IteratorDoubleYielder
{
X it;
IteratorDoubleYielder(X i, unsigned, const char *const) : it(i) {}
IteratorDoubleYielder(X i) : it(i) {}
void operator++() { ++it; }
double operator*() const { return *it; }
};
template <typename X>
struct SequenceDoubleYielder
{
typename X::const_iterator it;
SequenceDoubleYielder(const X & seq, unsigned dim,
const char *const function_name = "SequenceDouble
Yielder")
: it(seq.begin())
{
if (seq.size() == dim)
return;
std::string msg = "(): Parameter number be equal to the number of s
patial dimensions.";
vigra_precondition(false, function_name + msg);
}
void operator++() { ++it; }
double operator*() const { return *it; }
};
template <typename X>
struct WrapDoubleIterator
{
typedef
typename IfBool< IsConvertibleTo<X, double>::value,
DoubleYielder,
typename IfBool< IsIterator<X>::value || IsArray<X>::value,
IteratorDoubleYielder<X>,
SequenceDoubleYielder<X>
>::type
>::type type;
};
template <class Param1, class Param2, class Param3>
struct WrapDoubleIteratorTriple
{
typename WrapDoubleIterator<Param1>::type sigma_eff_it;
typename WrapDoubleIterator<Param2>::type sigma_d_it;
typename WrapDoubleIterator<Param3>::type step_size_it;
WrapDoubleIteratorTriple(Param1 sigma_eff, Param2 sigma_d, Param3 step_
size)
: sigma_eff_it(sigma_eff), sigma_d_it(sigma_d), step_size_it(step_s
ize) {}
void operator++()
{
++sigma_eff_it;
++sigma_d_it;
++step_size_it;
}
double sigma_eff() const { return *sigma_eff_it; }
double sigma_d() const { return *sigma_d_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)
{
if (sigma < 0.0)
{
std::string msg = "(): Scale must be positive.";
vigra_precondition(false, function_name + msg);
}
}
double sigma_scaled(const char *const function_name = "unknown function
") const
{
sigma_precondition(sigma_eff(), function_name);
sigma_precondition(sigma_d(), function_name);
double sigma_squared = sqr(sigma_eff()) - sqr(sigma_d());
if (sigma_squared > 0.0)
{
return std::sqrt(sigma_squared) / step_size();
}
else
{
std::string msg = "(): Scale would be imaginary or zero.";
vigra_precondition(false, function_name + msg);
return 0;
}
}
};
template <unsigned dim>
struct multiArrayScaleParam
{
typedef TinyVector<double, dim> p_vector;
typedef typename p_vector::const_iterator return_type;
p_vector vec;
template <class Param>
multiArrayScaleParam(Param val, const char *const function_name = "mult
iArrayScaleParam")
{
typename WrapDoubleIterator<Param>::type in(val, dim, function_name
);
for (unsigned i = 0; i != dim; ++i, ++in)
vec[i] = *in;
}
return_type operator()() const
{
return vec.begin();
}
static void precondition(unsigned n_par, const char *const function_nam
e = "multiArrayScaleParam")
{
char n[3] = "0.";
n[0] += dim;
std::string msg = "(): dimension parameter must be ";
vigra_precondition(dim == n_par, function_name + msg + n);
}
multiArrayScaleParam(double v0, double v1, const char *const function_n
ame = "multiArrayScaleParam")
{
precondition(2, function_name);
vec = p_vector(v0, v1);
}
multiArrayScaleParam(double v0, double v1, double v2, const char *const
function_name = "multiArrayScaleParam")
{
precondition(3, function_name);
vec = p_vector(v0, v1, v2);
}
multiArrayScaleParam(double v0, double v1, double v2, double v3, const
char *const function_name = "multiArrayScaleParam")
{
precondition(4, function_name);
vec = p_vector(v0, v1, v2, v3);
}
multiArrayScaleParam(double v0, double v1, double v2, double v3, doubl
e v4, const char *const function_name = "multiArrayScaleParam")
{
precondition(5, function_name);
vec = p_vector(v0, v1, v2, v3, v4);
}
};
} // namespace detail
#define VIGRA_CONVOLUTION_OPTIONS(function_name, default_value, member_name
) \
template <class Param> \
ConvolutionOptions & function_name(const Param & val) \
{ \
member_name = ParamVec(val, "ConvolutionOptions::" #function_name);
\
return *this; \
} \
ConvolutionOptions & function_name() \
{ \
member_name = ParamVec(default_value, "ConvolutionOptions::" #funct
ion_name); \
return *this; \
} \
ConvolutionOptions & function_name(double v0, double v1) \
{ \
member_name = ParamVec(v0, v1, "ConvolutionOptions::" #function_nam
e); \
return *this; \
} \
ConvolutionOptions & function_name(double v0, double v1, double v2) \
{ \
member_name = ParamVec(v0, v1, v2, "ConvolutionOptions::" #function
_name); \
return *this; \
} \
ConvolutionOptions & function_name(double v0, double v1, double v2, dou
ble v3) \
{ \
member_name = ParamVec(v0, v1, v2, v3, "ConvolutionOptions::" #func
tion_name); \
return *this; \
} \
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); \
return *this; \
}
/** \brief Options class template for convolutions.
<b>\#include</b> \<vigra/multi_convolution.hxx\>
This class enables the calculation of scale space convolutions
such as \ref gaussianGradientMultiArray() on data with anisotropic
discretization. For these, the result of the ordinary calculation
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
\f$n\f$ is the differential order of the convolution, e.g., 1 for
gaussianGradientMultiArray(), and 0 for gaussianSmoothMultiArray(),
respectively. Also for each dimension in turn, the convolution's scale
parameter \f$\sigma\f$ has to be replaced by
\f$\sqrt{\sigma_\mathrm{eff}^2 - \sigma_\mathrm{D}^2}\Big/w\f$,
where \f$\sigma_\mathrm{eff}\f$ is the resulting effective filtering
scale. The data is assumed to be already filtered by a
gaussian smoothing with the scale parameter \f$\sigma_\mathrm{D}\f$
(such as by measuring equipment). All of the above changes are
automatically employed by the convolution functions for <tt>MultiArray</t
t>s
if a corresponding options object is provided.
The <tt>ConvolutionOptions</tt> class must be parameterized by the dimens
ion
<tt>dim</tt>
of the <tt>MultiArray</tt>s on which it is used. The actual per-axis
options are set by (overloaded) member functions explained below,
or else default to neutral values corresponding to the absence of the
particular option.
All member functions set <tt>dim</tt> values of the respective convolutio
n
option, one for each dimension. They may be set explicitly by multiple
arguments for up to five dimensions, or by a single argument to the same
value for all dimensions. For the general case, a single argument that is
either a C-syle array, an iterator, or a C++ standard library style
sequence (such as <tt>std::vector</tt>, with member functions <tt>begin()
</tt>
and <tt>size()</tt>) supplies the option values for any number of dimensi
ons.
Note that the return value of all member functions is <tt>*this</tt>, whi
ch
provides the mechanism for concatenating member function calls as shown b
elow.
<b>usage with explicit parameters:</b>
\code
ConvolutionOptions<2> opt = ConvolutionOptions<2>().stepSize(1, 2.3);
\endcode
<b>usage with arrays:</b>
\code
const double step_size[3] = { x_scale, y_scale, z_scale };
ConvolutionOptions<3> opt = ConvolutionOptions<3>().stepSize(step_size);
\endcode
<b>usage with C++ standard library style sequences:</b>
\code
TinyVector<double, 4> step_size(1, 1, 2.0, 1.5);
TinyVector<double, 4> r_sigmas(1, 1, 2.3, 3.2);
ConvolutionOptions<4> opt = ConvolutionOptions<4>().stepSize(step_size).r
esolutionStdDev(r_sigmas);
\endcode
<b>usage with iterators:</b>
\code
ArrayVector<double> step_size;
step_size.push_back(0);
step_size.push_back(3);
step_size.push_back(4);
ArrayVector<double>::iterator i = step_size.begin();
++i;
ConvolutionOptions<2> opt = ConvolutionOptions<2>().stepSize(i);
\endcode
<b>general usage in a convolution function call:</b>
\code
MultiArray<3, double> test_image;
MultiArray<3, double> out_image;
gaussianSmoothMultiArray(srcMultiArrayRange(test_image),
destMultiArray(out_image),
5.0,
ConvolutionOptions<3>()
.stepSize (1, 1, 3.2)
.resolutionStdDev(1, 1, 4)
);
\endcode
*/
template <unsigned dim>
class ConvolutionOptions
{
public:
typedef typename MultiArrayShape<dim>::type Shape;
typedef detail::multiArrayScaleParam<dim> ParamVec;
typedef typename ParamVec::return_type ParamIt;
ParamVec sigma_eff;
ParamVec sigma_d;
ParamVec step_size;
ParamVec outer_scale;
double window_ratio;
Shape from_point, to_point;
ConvolutionOptions()
: sigma_eff(0.0),
sigma_d(0.0),
step_size(1.0),
outer_scale(0.0),
window_ratio(0.0)
{}
typedef typename detail::WrapDoubleIteratorTriple<ParamIt, ParamIt, Par
amIt>
ScaleIterator;
typedef typename detail::WrapDoubleIterator<ParamIt>::type
StepIterator;
ScaleIterator scaleParams() const
{
return ScaleIterator(sigma_eff(), sigma_d(), step_size());
}
StepIterator stepParams() const
{
return StepIterator(step_size());
}
ConvolutionOptions outerOptions() const
{
ConvolutionOptions outer = *this;
// backward-compatible values:
return outer.stdDev(outer_scale()).resolutionStdDev(0.0);
}
// Step size per axis.
// Default: dim values of 1.0
VIGRA_CONVOLUTION_OPTIONS(stepSize, 1.0, step_size)
#ifdef DOXYGEN
/** Step size(s) per axis, i.e., the distance between two
adjacent pixels. Required for <tt>MultiArray</tt>
containing anisotropic data.
Note that a convolution containing a derivative operator
of order <tt>n</tt> results in a multiplication by
\f${\rm stepSize}^{-n}\f$ for each axis.
Also, the above standard deviations
are scaled according to the step size of each axis.
Default value for the options object if this member function is
not
used: A value of 1.0 for each dimension.
*/
ConvolutionOptions<dim> & stepSize(...);
#endif
// Resolution standard deviation per axis.
// Default: dim values of 0.0
VIGRA_CONVOLUTION_OPTIONS(resolutionStdDev, 0.0, sigma_d)
#ifdef DOXYGEN
/** Resolution standard deviation(s) per axis, i.e., a supposed
pre-existing gaussian filtering by this value.
The standard deviation actually used by the convolution operato
rs
is \f$\sqrt{{\rm sigma}^{2} - {\rm resolutionStdDev}^{2}}\f$ fo
r each
axis.
Default value for the options object if this member function is
not
used: A value of 0.0 for each dimension.
*/
ConvolutionOptions<dim> & resolutionStdDev(...);
#endif
// Standard deviation of scale space operators.
// Default: dim values of 0.0
VIGRA_CONVOLUTION_OPTIONS(stdDev, 0.0, sigma_eff)
VIGRA_CONVOLUTION_OPTIONS(innerScale, 0.0, sigma_eff)
#ifdef DOXYGEN
/** Standard deviation(s) of scale space operators, or inner scale(
s) for \ref structureTensorMultiArray().
Usually not
needed, since a single value for all axes may be specified as a
parameter
<tt>sigma</tt> to the call of
an convolution operator such as \ref gaussianGradientMultiArray
(), and
anisotropic data requiring the use of the stepSize() member fun
ction.
Default value for the options object if this member function is
not
used: A value of 0.0 for each dimension.
*/
ConvolutionOptions<dim> & stdDev(...);
/** Standard deviation(s) of scale space operators, or inner scale(
s) for \ref structureTensorMultiArray().
Usually not
needed, since a single value for all axes may be specified as a
parameter
<tt>sigma</tt> to the call of
an convolution operator such as \ref gaussianGradientMultiArray
(), and
anisotropic data requiring the use of the stepSize() member fun
ction.
Default value for the options object if this member function is
not
used: A value of 0.0 for each dimension.
*/
ConvolutionOptions<dim> & innerScale(...);
#endif
// Outer scale, for structure tensor.
// Default: dim values of 0.0
VIGRA_CONVOLUTION_OPTIONS(outerScale, 0.0, outer_scale)
#ifdef DOXYGEN
/** Standard deviation(s) of the second convolution of the
structure tensor.
Usually not needed, since a single value for
all axes may be specified as a parameter <tt>outerScale</tt> to
the call of \ref structureTensorMultiArray(), and
anisotropic data requiring the use of the stepSize() member
function.
Default value for the options object if this member function is
not
used: A value of 0.0 for each dimension.
*/
ConvolutionOptions<dim> & outerScale(...);
#endif
/** Size of the filter window as a multiple of the scale parameter.
This option is only used for Gaussian filters and their derivat
ives.
By default, the window size of a Gaussian filter is automatical
ly
determined such that the error resulting from restricting the
infinitely large Gaussian function to a finite size is minimize
d.
In particular, the window radius is determined as
<tt>radius = round(3.0 * sigma + 0.5 * order)</tt>, where 'orde
r' is the
desired derivative order. In some cases, it is desirable to tra
de off
accuracy for speed, and this function can be used to request a
smaller
window radius.
Default: <tt>0.0</tt> (i.e. determine the window size automatic
ally)
*/
ConvolutionOptions<dim> & filterWindowSize(double ratio)
{
vigra_precondition(ratio >= 0.0,
"ConvolutionOptions::filterWindowSize(): ratio must not be nega
tive.");
window_ratio = ratio;
return *this;
}
/** Restrict the filter to a subregion of the input array.
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
of the convolution has the size given in this function.
Default: <tt>from = Shape(), to = Shape()</tt> (i.e. use entire
array)
*/
ConvolutionOptions<dim> & subarray(Shape const & from, Shape const & to
)
{
from_point = from;
to_point = to;
return *this;
}
};
namespace detail
{
/********************************************************/ /********************************************************/
/* */ /* */
/* internalSeparableConvolveMultiArray */ /* internalSeparableConvolveMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
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
internalSeparableConvolveMultiArrayTmp( internalSeparableConvolveMultiArrayTmp(
SrcIterator si, SrcShape const & shape, SrcAccessor s rc, SrcIterator si, SrcShape const & shape, SrcAccessor s rc,
DestIterator di, DestAccessor dest, KernelIterator ki t) DestIterator di, DestAccessor dest, KernelIterator ki t)
{ {
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 typename AccessorTraits<TmpType>::default_accessor TmpAcessor;
// temporay array to hold the current line to enable in-place operation // 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<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator; typedef MultiArrayNavigator<DestIterator, N> DNavigator;
{ // only operate on first dimension here TmpAcessor acc;
{
// only operate on first dimension here
SNavigator snav( si, shape, 0 ); SNavigator snav( si, shape, 0 );
DNavigator dnav( di, shape, 0 ); DNavigator dnav( di, shape, 0 );
for( ; snav.hasMore(); snav++, dnav++ ) for( ; snav.hasMore(); snav++, dnav++ )
{ {
// first copy source to temp for maximum cache efficiency // first copy source to tmp for maximum cache efficiency
copyLine( snav.begin(), snav.end(), src, copyLine(snav.begin(), snav.end(), src, tmp.begin(), acc);
tmp.begin(), typename AccessorTraits<TmpType>::defau
lt_accessor() );
convolveLine( srcIterRange(tmp.begin(), tmp.end(), convolveLine(srcIterRange(tmp.begin(), tmp.end(), acc),
typename AccessorTraits<TmpType>::d destIter( dnav.begin(), dest ),
efault_const_accessor()), kernel1d( *kit ) );
destIter( dnav.begin(), dest ),
kernel1d( *kit ) );
} }
++kit; ++kit;
} }
// operate on further dimensions // operate on further dimensions
for( int d = 1; d < N; ++d, ++kit ) for( int d = 1; d < N; ++d, ++kit )
{ {
DNavigator dnav( di, shape, d ); DNavigator dnav( di, shape, d );
tmp.resize( shape[d] ); tmp.resize( shape[d] );
for( ; dnav.hasMore(); dnav++ ) for( ; dnav.hasMore(); dnav++ )
{ {
// first copy source to temp for maximum cache efficiency // first copy source to tmp since convolveLine() cannot work i
copyLine( dnav.begin(), dnav.end(), dest, n-place
tmp.begin(), typename AccessorTraits<TmpType>::defau copyLine(dnav.begin(), dnav.end(), dest, tmp.begin(), acc);
lt_accessor() );
convolveLine( srcIterRange(tmp.begin(), tmp.end(), convolveLine(srcIterRange(tmp.begin(), tmp.end(), acc),
typename AccessorTraits<TmpType>::d destIter( dnav.begin(), dest ),
efault_const_accessor()), kernel1d( *kit ) );
destIter( dnav.begin(), dest ), }
kernel1d( *kit ) ); }
}
/********************************************************/
/* */
/* internalSeparableConvolveSubarray */
/* */
/********************************************************/
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor, class KernelIterator>
void
internalSeparableConvolveSubarray(
SrcIterator si, SrcShape const & shape, SrcAccessor s
rc,
DestIterator di, DestAccessor dest, KernelIterator ki
t,
SrcShape const & start, SrcShape const & stop)
{
enum { N = 1 + SrcIterator::level };
typedef typename NumericTraits<typename DestAccessor::value_type>::Real
Promote TmpType;
typedef MultiArray<N, TmpType> TmpArray;
typedef typename TmpArray::traverser TmpIterator;
typedef typename AccessorTraits<TmpType>::default_accessor TmpAcessor;
SrcShape sstart, sstop, axisorder, tmpshape;
TinyVector<double, N> overhead;
for(int k=0; k<N; ++k)
{
sstart[k] = start[k] - kit[k].right();
if(sstart[k] < 0)
sstart[k] = 0;
sstop[k] = stop[k] - kit[k].left();
if(sstop[k] > shape[k])
sstop[k] = shape[k];
overhead[k] = double(sstop[k] - sstart[k]) / (stop[k] - start[k]);
}
indexSort(overhead.begin(), overhead.end(), axisorder.begin(), std::gre
ater<double>());
SrcShape dstart, dstop(sstop - sstart);
dstop[axisorder[0]] = stop[axisorder[0]] - start[axisorder[0]];
// temporary array to hold the current line to enable in-place operatio
n
MultiArray<N, TmpType> tmp(dstop);
typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<TmpIterator, N> TNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator;
TmpAcessor acc;
{
// only operate on first dimension here
SNavigator snav( si, sstart, sstop, axisorder[0]);
TNavigator tnav( tmp.traverser_begin(), dstart, dstop, axisorder[0]
);
ArrayVector<TmpType> tmpline(sstop[axisorder[0]] - sstart[axisorder
[0]]);
int lstart = start[axisorder[0]] - sstart[axisorder[0]];
int lstop = lstart + (stop[axisorder[0]] - start[axisorder[0]]);
for( ; snav.hasMore(); snav++, tnav++ )
{
// first copy source to tmp for maximum cache efficiency
copyLine(snav.begin(), snav.end(), src, tmpline.begin(), acc);
convolveLine(srcIterRange(tmpline.begin(), tmpline.end(), acc),
destIter(tnav.begin(), acc),
kernel1d( kit[axisorder[0]] ), lstart, lstop);
} }
} }
// operate on further dimensions
for( int d = 1; d < N; ++d)
{
TNavigator tnav( tmp.traverser_begin(), dstart, dstop, axisorder[d]
);
ArrayVector<TmpType> tmpline(dstop[axisorder[d]] - dstart[axisorder
[d]]);
int lstart = start[axisorder[d]] - sstart[axisorder[d]];
int lstop = lstart + (stop[axisorder[d]] - start[axisorder[d]]);
for( ; tnav.hasMore(); tnav++ )
{
// first copy source to tmp because convolveLine() cannot work
in-place
copyLine(tnav.begin(), tnav.end(), acc, tmpline.begin(), acc );
convolveLine(srcIterRange(tmpline.begin(), tmpline.end(), acc),
destIter( tnav.begin() + lstart, acc ),
kernel1d( kit[axisorder[d]] ), lstart, lstop);
}
dstart[axisorder[d]] = lstart;
dstop[axisorder[d]] = lstop;
}
copyMultiArray(tmp.traverser_begin()+dstart, stop-start, acc, di, dest)
;
}
template <class K>
void
scaleKernel(K & kernel, double a)
{
for(int i = kernel.left(); i <= kernel.right(); ++i)
kernel[i] = detail::RequiresExplicitCast<typename K::value_type>::c
ast(kernel[i] * a);
} }
} // namespace detail } // namespace detail
/** \addtogroup MultiArrayConvolutionFilters Convolution filters for multi- dimensional arrays. /** \addtogroup MultiArrayConvolutionFilters Convolution filters for multi- dimensional arrays.
These functions realize a separable convolution on an arbitrary dimensi onal These functions realize a separable convolution on an arbitrary dimensi onal
array that is specified by iterators (compatible to \ref MultiIteratorP age) 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 and shape objects. It can therefore be applied to a wide range of data structures
(\ref vigra::MultiArrayView, \ref vigra::MultiArray etc.). (\ref vigra::MultiArrayView, \ref vigra::MultiArray etc.).
skipping to change at line 157 skipping to change at line 694
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 to the dimension (e.g. the x-dimension of an image), while the last is applied to the
outermost dimension (e.g. the z-dimension in a 3D image). outermost dimension (e.g. the z-dimension 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>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 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 ealPromote) <tt>typeid(typename NumericTraits<typename DestAccessor::value_type>::R ealPromote)
!= typeid(typename DestAccessor::value_type)</tt>. != typeid(typename DestAccessor::value_type)</tt>.
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
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
<tt>start</tt>).
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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 & stop = SrcShape());
// apply each kernel from the sequence 'kernels' in turn // apply each kernel from the sequence 'kernels' in turn
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 & 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,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape());
// apply each kernel from the sequence 'kernels' in turn // apply each kernel from the sequence 'kernels' in turn
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 & stop = SrcShape());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <b>\#include</b> \<vigra/multi_convolution.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray( dest),
kernels.begin()); kernels.begin());
\endcode \endcode
<b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition:
\code
int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode
\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, KernelItera DestIterator d, DestAccessor dest,
tor kernels ) KernelIterator kernels,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape())
{ {
typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType;
if(!IsSameType<TmpType, typename DestAccessor::value_type>::boolResult) if(stop != SrcShape())
{
enum { N = 1 + SrcIterator::level };
for(int k=0; k<N; ++k)
vigra_precondition(0 <= start[k] && start[k] < stop[k] && stop[
k] <= shape[k],
"separableConvolveMultiArray(): invalid subarray shape.");
detail::internalSeparableConvolveSubarray(s, shape, src, d, dest, k
ernels, start, stop);
}
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);
detail::internalSeparableConvolveMultiArrayTmp( s, shape, src, detail::internalSeparableConvolveMultiArrayTmp( s, shape, src,
tmpArray.traverser_begin(), typename AccessorTraits<TmpType>:: default_accessor(), kernels ); tmpArray.traverser_begin(), typename AccessorTraits<TmpType>:: default_accessor(), kernels );
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> class DestIterator, class DestAccessor, class KernelIterator>
inline inline
void separableConvolveMultiArray( void separableConvolveMultiArray(
triple<SrcIterator, SrcShape, SrcAccessor> const & source, triple<SrcIterator, SrcShape, SrcAccessor> const & source,
pair<DestIterator, DestAccessor> const & dest, KernelIterator kit ) pair<DestIterator, DestAccessor> const & dest,
KernelIterator kit,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape())
{ {
separableConvolveMultiArray( source.first, source.second, source.third, separableConvolveMultiArray( source.first, source.second, source.third,
dest.first, dest.second, kit ); dest.first, dest.second, kit, start, stop );
} }
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
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 & stop = SrcShape())
{ {
ArrayVector<Kernel1D<T> > kernels(shape.size(), kernel); ArrayVector<Kernel1D<T> > kernels(shape.size(), kernel);
separableConvolveMultiArray( s, shape, src, d, dest, kernels.begin() ); 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 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 & 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() ) ; dest.first, dest.second, 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>. 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. already have the correct size.
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
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
<tt>start</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>siter == diter</t t> is allowed.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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> unsigned int dim, vigra::Kernel1D<T>
const & kernel); const & kernel,
SrcShape const & start = 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> unsigned int dim, vigra::Kernel1D<T>
const & kernel); const & kernel,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <b>\#include</b> \<vigra/multi_convolution.hxx\>
\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, 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 dimensions 1 (height)
skipping to change at line 350 skipping to change at line 939
\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,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
unsigned int dim, vigra::Kernel1D<T> const & unsigned int dim, vigra::Kernel1D<T> const &
kernel ) kernel,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape())
{ {
enum { N = 1 + SrcIterator::level }; enum { N = 1 + SrcIterator::level };
vigra_precondition( dim < N, vigra_precondition( dim < N,
"convolveMultiArrayOneDimension(): The dimension nu mber to convolve must be smaller " "convolveMultiArrayOneDimension(): The dimension nu mber to convolve must be smaller "
"than the data dimensionality" ); "than the data dimensionality" );
typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType; typedef typename NumericTraits<typename DestAccessor::value_type>::Real Promote TmpType;
typedef typename AccessorTraits<TmpType>::default_const_accessor TmpAcc essor;
ArrayVector<TmpType> tmp( shape[dim] ); ArrayVector<TmpType> tmp( shape[dim] );
typedef MultiArrayNavigator<SrcIterator, N> SNavigator; typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator; typedef MultiArrayNavigator<DestIterator, N> DNavigator;
SNavigator snav( s, shape, dim ); SrcShape sstart, sstop(shape), dstart, dstop(shape);
DNavigator dnav( d, shape, dim );
if(stop != SrcShape())
{
sstart = start;
sstop = stop;
sstart[dim] = 0;
sstop[dim] = shape[dim];
dstop = stop - start;
}
SNavigator snav( s, sstart, sstop, 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_accessor( ) );
convolveLine( srcIterRange( tmp.begin(), tmp.end(), typename Acces convolveLine(srcIterRange( tmp.begin(), tmp.end(), TmpAccessor()),
sorTraits<TmpType>::default_const_accessor()), destIter( dnav.begin(), dest ),
destIter( dnav.begin(), dest ), kernel1d( kernel), start[dim], stop[dim]);
kernel1d( kernel ) );
} }
} }
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, vigra::Kernel1D<T> const &
kernel ) kernel,
SrcShape const & start = SrcShape(),
SrcShape const & stop = SrcShape())
{ {
convolveMultiArrayOneDimension( source.first, source.second, source.thi convolveMultiArrayOneDimension(source.first, source.second, source.thir
rd, d,
dest.first, dest.second, dim, kernel ); dest.first, dest.second, dim, kernel, st
art, 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 multi-dime nsional 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>siter == diter</tt> is allowed. It is implemented by a call to
\ref separableConvolveMultiArray() with the appropriate kernel. \ref separableConvolveMultiArray() with the appropriate kernel.
If the data are anisotropic (different pixel size along different dimen
sions) Anisotropic data should be passed with appropriate
you should call \ref separableConvolveMultiArray() directly with the ap \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option
propriate al
anisotropic Gaussians. unless the parameter <tt>sigma</tt> is left out.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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); double sigma, const 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
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); double sigma, const ConvolutionOptions<N> & opt);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <b>\#include</b> \<vigra/multi_convolution.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray(des t), sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code
MultiArray<3, unsigned char>::size_type shape(width, height, depth);
MultiArray<3, unsigned char> source(shape);
MultiArray<3, float> dest(shape);
TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas;
...
// perform anisotropic Gaussian smoothing at scale 'sigma'
gaussianSmoothMultiArray(srcMultiArrayRange(source), destMultiArray(des
t), sigma,
ConvolutionOptions<3>().stepSize(step_size).re
solutionStdDev(resolution_sigmas));
\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, double sigma ) DestIterator d, DestAccessor dest,
const ConvolutionOptions<SrcShape::static_size> & opt,
const char *const function_name = "gaussianSmoothMultiAr
ray" )
{ {
Kernel1D<double> gauss; typedef typename DestAccessor::value_type DestType;
gauss.initGaussian( sigma );
separableConvolveMultiArray( s, shape, src, d, dest, gauss); static const int N = SrcShape::static_size;
typename ConvolutionOptions<N>::ScaleIterator params = opt.scaleParams(
);
ArrayVector<Kernel1D<double> > kernels(N);
for (int dim = 0; dim < N; ++dim, ++params)
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);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
gaussianSmoothMultiArray( SrcIterator s, SrcShape const & shape, SrcAccesso
r src,
DestIterator d, DestAccessor dest, double sigma,
const ConvolutionOptions<SrcShape::static_size> & opt =
ConvolutionOptions<SrcShape::static_size>())
{
ConvolutionOptions<SrcShape::static_size> par = opt;
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,
double sigma ) const ConvolutionOptions<SrcShape::static_size> & opt)
{ {
gaussianSmoothMultiArray( source.first, source.second, source.third, gaussianSmoothMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma ); dest.first, dest.second, opt );
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
gaussianSmoothMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const &
source,
pair<DestIterator, DestAccessor> const & dest, double sig
ma,
const ConvolutionOptions<SrcShape::static_size> & opt = C
onvolutionOptions<SrcShape::static_size>())
{
gaussianSmoothMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma, opt );
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* 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 multi-dimensi onal 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 ation arrays in turn, starting with the innermost dimension). Both source and destin ation arrays
are represented by iterators, shape objects and accessors. The destinat ion array 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.
If the data are anisotropic (different pixel size along different dimen
sions) Anisotropic data should be passed with appropriate
you should call \ref separableConvolveMultiArray() directly with the ap \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option
propriate al
anisotropic Gaussian derivatives. unless the parameter <tt>sigma</tt> is left out.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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); double sigma, const 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
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); double sigma, const ConvolutionOptions<N > & opt);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <b>\#include</b> \<vigra/multi_convolution.hxx\>
\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 Gaussian gradient at scale sigma // compute Gaussian gradient at scale sigma
gaussianGradientMultiArray(srcMultiArrayRange(source), destMultiArray(d est), sigma); gaussianGradientMultiArray(srcMultiArrayRange(source), destMultiArray(d est), sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code
MultiArray<3, unsigned char>::size_type shape(width, height, depth);
MultiArray<3, unsigned char> source(shape);
MultiArray<3, TinyVector<float, 3> > dest(shape);
TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas;
...
// compute Gaussian gradient at scale sigma
gaussianGradientMultiArray(srcMultiArrayRange(source), destMultiArray(d
est), sigma,
ConvolutionOptions<3>().stepSize(step_size).
resolutionStdDev(resolution_sigmas));
\endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition: see \ref separableConvolveMultiArray(), in addition:
\code \code
int dimension = 0; int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest); VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode \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, double sigma DestIterator di, DestAccessor dest,
) ConvolutionOptions<SrcShape::static_size> const
& opt,
const char *const function_name = "gaussianGradi
entMultiArray")
{ {
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;
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
typedef typename ConvolutionOptions<N>::ScaleIterator ParamType;
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 == dest.size(di), vigra_precondition(N == (int)dest.size(di),
"gaussianGradientMultiArray(): Wrong number of channels in output a rray."); "gaussianGradientMultiArray(): Wrong number of channels in output a rray.");
vigra_precondition(sigma > 0.0, "gaussianGradientMultiArray(): Scale mu ParamType params = opt.scaleParams();
st be positive."); ParamType params2(params);
Kernel1D<KernelType> gauss, derivative; ArrayVector<Kernel1D<KernelType> > plain_kernels(N);
gauss.initGaussian(sigma); for (int dim = 0; dim < N; ++dim, ++params)
{
double sigma = params.sigma_scaled(function_name);
plain_kernels[dim].initGaussian(sigma, 1.0, opt.window_ratio);
}
typedef VectorElementAccessor<DestAccessor> ElementAccessor; typedef VectorElementAccessor<DestAccessor> ElementAccessor;
// compute gradient components // compute gradient components
for(int d = 0; d < N; ++d ) for (int dim = 0; dim < N; ++dim, ++params2)
{ {
ArrayVector<Kernel1D<KernelType> > kernels(N, gauss); ArrayVector<Kernel1D<KernelType> > kernels(plain_kernels);
kernels[d].initGaussianDerivative(sigma, 1); kernels[dim].initGaussianDerivative(params2.sigma_scaled(), 1, 1.0,
separableConvolveMultiArray( si, shape, src, di, ElementAccessor(d, opt.window_ratio);
dest), kernels.begin()); detail::scaleKernel(kernels[dim], 1.0 / params2.step_size());
separableConvolveMultiArray(si, shape, src, di, ElementAccessor(dim
, dest), kernels.begin(),
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
gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcces
sor src,
DestIterator di, DestAccessor dest, double sigma
,
const ConvolutionOptions<SrcShape::static_size>
& opt = ConvolutionOptions<SrcShape::static_size>())
{
ConvolutionOptions<SrcShape::static_size> par = opt;
gaussianGradientMultiArray(si, shape, src, di, dest, par.stdDev(sigma))
;
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
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, d pair<DestIterator, DestAccessor> const & dest,
ouble sigma ) ConvolutionOptions<SrcShape::static_size> const
& opt )
{ {
gaussianGradientMultiArray( source.first, source.second, source.third, gaussianGradientMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma ); dest.first, dest.second, opt );
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const
& source,
pair<DestIterator, DestAccessor> const & dest,
double sigma,
const ConvolutionOptions<SrcShape::static_size>
& opt = ConvolutionOptions<SrcShape::static_size>())
{
gaussianGradientMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma, opt );
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* 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 multi-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 source and to each dimension in turn, starting with the innermost dimension). Both source and
destination arrays are represented by iterators, shape objects and acce ssors. 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
\ref ConvolutionOptions, the parameter <tt>opt</tt> is optional
otherwise.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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);
} }
\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 pair<DestIterator, DestAccessor> const
& dest); & dest,
const ConvolutionOptions<N> & opt);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <b>\#include</b> \<vigra/multi_convolution.hxx\>
\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>\#include</b> \<vigra/multi_convolution.hxx\>
\code
MultiArray<3, unsigned char>::size_type shape(width, height, depth);
MultiArray<3, unsigned char> source(shape);
MultiArray<3, TinyVector<float, 3> > dest(shape);
TinyVector<float, 3> step_size;
...
// compute gradient
symmetricGradientMultiArray(srcMultiArrayRange(source), destMultiArray(
dest),
ConvolutionOptions<3>().stepSize(step_size)
);
\endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see \ref convolveMultiArrayOneDimension(), in addition: see \ref convolveMultiArrayOneDimension(), in addition:
\code \code
int dimension = 0; int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest); VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode \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>())
{ {
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;
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
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 == 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.initSymmetricGradient();
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 ) for (int d = 0; d < N; ++d, ++step_size_it)
{ {
Kernel1D<KernelType> symmetric(filter);
detail::scaleKernel(symmetric, 1 / *step_size_it);
convolveMultiArrayOneDimension(si, shape, src, convolveMultiArrayOneDimension(si, shape, src,
di, ElementAccessor(d, dest), di, ElementAccessor(d, dest),
d, filter); d, symmetric, 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>
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>())
{ {
symmetricGradientMultiArray(source.first, source.second, source.third, symmetricGradientMultiArray(source.first, source.second, source.third,
dest.first, dest.second); dest.first, dest.second, 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 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 arrays
are represented by iterators, shape objects and accessors. 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
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option
al
unless the parameter <tt>sigma</tt> is left out.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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); double sigma, const ConvolutionOption s<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
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); double sigma, const ConvolutionOption s<N> & opt);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <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);
... ...
// compute Laplacian at scale sigma // compute Laplacian at scale sigma
laplacianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArra y(laplacian), sigma); laplacianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArra y(laplacian), sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code
MultiArray<3, float> source(shape);
MultiArray<3, float> laplacian(shape);
TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas;
...
// compute Laplacian at scale sigma
laplacianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArra
y(laplacian), sigma,
ConvolutionOptions<3>().stepSize(step_siz
e).resolutionStdDev(resolution_sigmas));
\endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition: see \ref separableConvolveMultiArray(), in addition:
\code \code
int dimension = 0; int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest); VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode \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, double si DestIterator di, DestAccessor dest,
gma ) ConvolutionOptions<SrcShape::static_size> con
st & opt )
{ {
using namespace functor; using namespace functor;
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
typedef typename NumericTraits<DestType>::RealPromote KernelType; typedef typename NumericTraits<DestType>::RealPromote KernelType;
typedef typename AccessorTraits<KernelType>::default_accessor Derivativ eAccessor; typedef typename AccessorTraits<KernelType>::default_accessor Derivativ eAccessor;
static const int N = SrcShape::static_size; static const int N = SrcShape::static_size;
typedef typename ConvolutionOptions<N>::ScaleIterator ParamType;
vigra_precondition(sigma > 0.0, "laplacianOfGaussianMultiArray(): Scale ParamType params = opt.scaleParams();
must be positive."); ParamType params2(params);
Kernel1D<KernelType> gauss; ArrayVector<Kernel1D<KernelType> > plain_kernels(N);
gauss.initGaussian(sigma); for (int dim = 0; dim < N; ++dim, ++params)
{
double sigma = params.sigma_scaled("laplacianOfGaussianMultiArray")
;
plain_kernels[dim].initGaussian(sigma, 1.0, opt.window_ratio);
}
MultiArray<N, KernelType> derivative(shape); SrcShape dshape(shape);
if(opt.to_point != SrcShape())
dshape = opt.to_point - opt.from_point;
MultiArray<N, KernelType> derivative(dshape);
// compute 2nd derivatives and sum them up // compute 2nd derivatives and sum them up
for(int d = 0; d < N; ++d ) for (int dim = 0; dim < N; ++dim, ++params2)
{ {
ArrayVector<Kernel1D<KernelType> > kernels(N, gauss); ArrayVector<Kernel1D<KernelType> > kernels(plain_kernels);
kernels[d].initGaussianDerivative(sigma, 2); kernels[dim].initGaussianDerivative(params2.sigma_scaled(), 2, 1.0,
if(d == 0) opt.window_ratio);
detail::scaleKernel(kernels[dim], 1.0 / sq(params2.step_size()));
if (dim == 0)
{ {
separableConvolveMultiArray( si, shape, src, separableConvolveMultiArray( si, shape, src,
di, dest, kernels.begin()); di, dest, kernels.begin(), opt.fro m_point, opt.to_point);
} }
else else
{ {
separableConvolveMultiArray( si, shape, src, separableConvolveMultiArray( si, shape, src,
derivative.traverser_begin(), Deri vativeAccessor(), derivative.traverser_begin(), Deri vativeAccessor(),
kernels.begin()); kernels.begin(), opt.from_point, o
combineTwoMultiArrays(di, shape, dest, derivative.traverser_beg pt.to_point);
in(), DerivativeAccessor(), combineTwoMultiArrays(di, dshape, dest, derivative.traverser_be
gin(), DerivativeAccessor(),
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
laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAc
cessor src,
DestIterator di, DestAccessor dest, double si
gma,
const ConvolutionOptions<SrcShape::static_siz
e> & opt = ConvolutionOptions<SrcShape::static_size>())
{
ConvolutionOptions<SrcShape::static_size> par = opt;
laplacianOfGaussianMultiArray(si, shape, src, di, dest, par.stdDev(sigm
a));
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
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
double sigma ) ,
ConvolutionOptions<SrcShape::static_size> con
st & opt )
{ {
laplacianOfGaussianMultiArray( source.first, source.second, source.thir d, laplacianOfGaussianMultiArray( source.first, source.second, source.thir d,
dest.first, dest.second, sigma ); dest.first, dest.second, opt );
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> co
nst & source,
pair<DestIterator, DestAccessor> const & dest
,
double sigma,
const ConvolutionOptions<SrcShape::static_siz
e> & opt = ConvolutionOptions<SrcShape::static_size>())
{
laplacianOfGaussianMultiArray( source.first, source.second, source.thir
d,
dest.first, dest.second, sigma, opt );
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* 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>. Both source and destination arrays
are represented by iterators, shape objects and accessors. The destinat ion 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 s implemented by calls to upper triangular part of the symmetric Hessian matrix). This function i s implemented by calls to
\ref separableConvolveMultiArray() with the appropriate kernels. \ref separableConvolveMultiArray() with the appropriate kernels.
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 left out.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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); double sigma, const 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
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); double sigma, const ConvolutionOptions< N> & opt);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <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);
... ...
// compute Hessian at scale sigma // compute Hessian at scale sigma
hessianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArray( dest), sigma); hessianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArray( dest), sigma);
\endcode \endcode
<b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code
MultiArray<3, float> source(shape);
MultiArray<3, TinyVector<float, 6> > dest(shape);
TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas;
...
// compute Hessian at scale sigma
hessianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArray(
dest), sigma,
ConvolutionOptions<3>().stepSize(step_size)
.resolutionStdDev(resolution_sigmas));
\endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition: see \ref separableConvolveMultiArray(), in addition:
\code \code
int dimension = 0; int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest); VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode \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, double sigm DestIterator di, DestAccessor dest,
a ) ConvolutionOptions<SrcShape::static_size> const
& opt )
{ {
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;
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 ConvolutionOptions<N>::ScaleIterator ParamType;
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(M == dest.size(di), vigra_precondition(M == (int)dest.size(di),
"hessianOfGaussianMultiArray(): Wrong number of channels in output array."); "hessianOfGaussianMultiArray(): Wrong number of channels in output array.");
vigra_precondition(sigma > 0.0, "hessianOfGaussianMultiArray(): Scale m ust be positive."); ParamType params_init = opt.scaleParams();
Kernel1D<KernelType> gauss; ArrayVector<Kernel1D<KernelType> > plain_kernels(N);
gauss.initGaussian(sigma); ParamType params(params_init);
for (int dim = 0; dim < N; ++dim, ++params)
{
double sigma = params.sigma_scaled("hessianOfGaussianMultiArray");
plain_kernels[dim].initGaussian(sigma, 1.0, opt.window_ratio);
}
typedef VectorElementAccessor<DestAccessor> ElementAccessor; typedef VectorElementAccessor<DestAccessor> ElementAccessor;
// compute elements of the Hessian matrix // compute elements of the Hessian matrix
for(int b=0, i=0; i<N; ++i) ParamType params_i(params_init);
for (int b=0, i=0; i<N; ++i, ++params_i)
{ {
for(int j=i; j<N; ++j, ++b) ParamType params_j(params_i);
for (int j=i; j<N; ++j, ++b, ++params_j)
{ {
ArrayVector<Kernel1D<KernelType> > kernels(N, gauss); ArrayVector<Kernel1D<KernelType> > kernels(plain_kernels);
if(i == j) if(i == j)
{ {
kernels[i].initGaussianDerivative(sigma, 2); kernels[i].initGaussianDerivative(params_i.sigma_scaled(), 2, 1.0, opt.window_ratio);
} }
else else
{ {
kernels[i].initGaussianDerivative(sigma, 1); kernels[i].initGaussianDerivative(params_i.sigma_scaled(),
kernels[j].initGaussianDerivative(sigma, 1); 1, 1.0, opt.window_ratio);
kernels[j].initGaussianDerivative(params_j.sigma_scaled(),
1, 1.0, opt.window_ratio);
} }
detail::scaleKernel(kernels[i], 1 / params_i.step_size());
detail::scaleKernel(kernels[j], 1 / params_j.step_size());
separableConvolveMultiArray(si, shape, src, di, ElementAccessor (b, dest), separableConvolveMultiArray(si, shape, src, di, ElementAccessor (b, dest),
kernels.begin()); 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,
DestIterator di, DestAccessor dest, double sigm
a,
const ConvolutionOptions<SrcShape::static_size>
& opt = ConvolutionOptions<SrcShape::static_size>())
{
ConvolutionOptions<SrcShape::static_size> par = opt;
hessianOfGaussianMultiArray(si, shape, src, di, dest, par.stdDev(sigma)
);
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
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 ) ConvolutionOptions<SrcShape::static_size> const
& opt )
{ {
hessianOfGaussianMultiArray( source.first, source.second, source.third, hessianOfGaussianMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma ); dest.first, dest.second, opt );
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> cons
t & source,
pair<DestIterator, DestAccessor> const & dest,
double sigma,
const ConvolutionOptions<SrcShape::static_size>
& opt = ConvolutionOptions<SrcShape::static_size>())
{
hessianOfGaussianMultiArray( source.first, source.second, source.third,
dest.first, dest.second, sigma, opt );
} }
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;
skipping to change at line 987 skipping to change at line 1829
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 objects and Both source and destination arrays are represented by iterators, shape objects and
accessors. The destination array must have a vector valued pixel type w ith 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). If the source array is also vector valued, th e
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
\ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise option
al
unless the parameters <tt>innerScale</tt> and <tt>outerScale</tt> are
both left out.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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);
} }
\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);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ multi_convolution.hxx</a>\> <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);
... ...
// 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(srcMultiArrayRange(source), destMultiArray(de st), innerScale, outerScale);
\endcode \endcode
<b> Usage with anisotropic data:</b>
<b>\#include</b> \<vigra/multi_convolution.hxx\>
\code
MultiArray<3, RGBValue<float> > source(shape);
MultiArray<3, TinyVector<float, 6> > dest(shape);
TinyVector<float, 3> step_size;
TinyVector<float, 3> resolution_sigmas;
...
// compute structure tensor at scales innerScale and outerScale
structureTensorMultiArray(srcMultiArrayRange(source), destMultiArray(de
st), innerScale, outerScale,
ConvolutionOptions<3>().stepSize(step_size).r
esolutionStdDev(resolution_sigmas));
\endcode
<b> Required Interface:</b> <b> Required Interface:</b>
see \ref separableConvolveMultiArray(), in addition: see \ref separableConvolveMultiArray(), in addition:
\code \code
int dimension = 0; int dimension = 0;
VectorElementAccessor<DestAccessor> elementAccessor(0, dest); VectorElementAccessor<DestAccessor> elementAccessor(0, dest);
\endcode \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,
double innerScale, double outerScale) ConvolutionOptions<SrcShape::static_size> const & 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;
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(M == 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.");
vigra_precondition(innerScale > 0.0 && outerScale >= 0.0, ConvolutionOptions<N> innerOptions = opt;
"structureTensorMultiArray(): Scale must be positive."); ConvolutionOptions<N> outerOptions = opt.outerOptions();
typename ConvolutionOptions<N>::ScaleIterator params = outerOptions.sca
leParams();
MultiArray<N, GradientVector> gradient(shape); SrcShape gradientShape(shape);
if(opt.to_point != SrcShape())
{
for(int k=0; k<N; ++k, ++params)
{
Kernel1D<double> gauss;
gauss.initGaussian(params.sigma_scaled("structureTensorMultiArr
ay"), 1.0, opt.window_ratio);
int dilation = gauss.right();
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);
}
outerOptions.from_point -= innerOptions.from_point;
outerOptions.to_point -= innerOptions.from_point;
gradientShape = innerOptions.to_point - innerOptions.from_point;
}
MultiArray<N, GradientVector> gradient(gradientShape);
MultiArray<N, DestType> gradientTensor(gradientShape);
gaussianGradientMultiArray(si, shape, src, gaussianGradientMultiArray(si, shape, src,
gradient.traverser_begin(), GradientAccessor (), gradient.traverser_begin(), GradientAccessor (),
innerScale); innerOptions,
"structureTensorMultiArray");
transformMultiArray(gradient.traverser_begin(), shape, GradientAccessor transformMultiArray(gradient.traverser_begin(), gradientShape, Gradient
(), Accessor(),
di, dest, gradientTensor.traverser_begin(), GradientTensorAcc
essor(),
detail::StructurTensorFunctor<N, DestType>()); detail::StructurTensorFunctor<N, DestType>());
gaussianSmoothMultiArray(di, shape, dest, di, dest, outerScale); gaussianSmoothMultiArray(gradientTensor.traverser_begin(), gradientShap
e, GradientTensorAccessor(),
di, dest, outerOptions,
"structureTensorMultiArray");
}
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess
or src,
DestIterator di, DestAccessor dest,
double innerScale, double outerScale,
const ConvolutionOptions<SrcShape::static_size> &
opt = ConvolutionOptions<SrcShape::static_size>())
{
ConvolutionOptions<SrcShape::static_size> par = opt;
structureTensorMultiArray(si, shape, src, di, dest,
par.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,
double innerScale, double outerScale) ConvolutionOptions<SrcShape::static_size> const & opt )
{ {
structureTensorMultiArray( source.first, source.second, source.third, structureTensorMultiArray( source.first, source.second, source.third,
dest.first, dest.second, innerScale, outerSc dest.first, dest.second, opt );
ale ); }
template <class SrcIterator, class SrcShape, class SrcAccessor,
class DestIterator, class DestAccessor>
inline void
structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const
& source,
pair<DestIterator, DestAccessor> const & dest,
double innerScale, double outerScale,
const ConvolutionOptions<SrcShape::static_size> &
opt = ConvolutionOptions<SrcShape::static_size>())
{
structureTensorMultiArray( source.first, source.second, source.third,
dest.first, dest.second,
innerScale, outerScale, opt);
} }
//@} //@}
} //-- namespace vigra } //-- namespace vigra
#endif //-- VIGRA_MULTI_CONVOLUTION_H #endif //-- VIGRA_MULTI_CONVOLUTION_H
 End of changes. 129 change blocks. 
158 lines changed or deleted 1203 lines changed or added


 multi_distance.hxx   multi_distance.hxx 
skipping to change at line 321 skipping to change at line 321
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> \<<a href="multi__distance_8hxx-source.html">vigra/mul ti_distance.hxx</a>\> <b>\#include</b> \<vigra/multi_distance.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray(de st), true);
\endcode \endcode
skipping to change at line 491 skipping to change at line 491
} }
\endcode \endcode
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> \<<a href="multi__distance_8hxx-source.html">vigra/mul ti_distance.hxx</a>\> <b>\#include</b> \<vigra/multi_distance.hxx\>
\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, float> dest(shape); MultiArray<3, float> dest(shape);
... ...
// Calculate Euclidean distance squared for all background pixels // Calculate Euclidean distance squared for all background pixels
separableMultiDistance(srcMultiArrayRange(source), destMultiArray(dest) , true); separableMultiDistance(srcMultiArrayRange(source), destMultiArray(dest) , true);
\endcode \endcode
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 multi_impex.hxx   multi_impex.hxx 
skipping to change at line 71 skipping to change at line 71
*/ */
//@{ //@{
/** \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> \<<a href="imageinfo_8hxx-source.html">vigra/multi_imp ex.hxx</a>\><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;
skipping to change at line 192 skipping to change at line 192
/* */ /* */
/* 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> \<<a href="imageinfo_8hxx-source.html">vigra/imageinfo .hxx</a>\><br> <b>\#include</b> \<vigra/imageinfo.hxx\><br>
Namespace: vigra Namespace: vigra
**/ **/
class VolumeExportInfo class VolumeExportInfo
{ {
public: public:
/** Construct VolumeExportInfo object. /** Construct VolumeExportInfo object.
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.
skipping to change at line 265 skipping to change at line 265
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 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 aditionally 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
64 bit double) without conversion. So you will need to use 64 bit double) without conversion. So you will need to use
TIFF or VIFF if you need to store images with high TIFF or VIFF if you need to store images with high
accuracy (the appropriate type to write is automatically accuracy (the appropriate type to write is automatically
derived from the image type to be exported). However, many derived from the image type to be exported). However, many
other programs using TIFF (e.g. ImageMagick) have not other programs using TIFF (e.g. ImageMagick) have not
implemented support for those pixel types. So don't be implemented support for those pixel types. So don't be
surprised if the generated TIFF is not readable in some surprised if the generated TIFF is not readable in some
cases. If this happens, export the image as 'unsigned cases. If this happens, export the image as 'unsigned
char' or 'RGBValue\<unsigned char\>' by calling char' or 'RGBValue\<unsigned char\>' by calling
\ref ImageExportInfo::setPixelType(). \ref ImageExportInfo::setPixelType().
Support to reading and writing ICC color profiles is Support to reading and writing ICC color profiles is
provided for TIFF, JPEG, and PNG images. provided for TIFF, JPEG, and PNG images.
**/ **/
VIGRA_EXPORT VolumeExportInfo & setFileType( const char * ); VIGRA_EXPORT VolumeExportInfo & setFileType( const char * );
VIGRA_EXPORT const char * getFileType() const; VIGRA_EXPORT const char * getFileType() const;
/** Set compression type. /** Set compression type and quality.
Recognized strings: "" (no compression), "LZW",
"RunLength", "1" ... "100". A number is interpreted as the
compression quality for JPEG compression. JPEG compression is
supported by the JPEG and TIFF formats. "LZW" is only available
if libtiff was installed with LZW enabled. By default, libtiff
came
with LZW disabled due to Unisys patent enforcement. In this cas
e,
VIGRA stores the image uncompressed.
Valid Compression for TIFF files: See \ref ImageExportInfo::setCompression() for details.
JPEG jpeg compression, call setQuality as well!
RLE runlength compression
LZW lzw compression
DEFLATE deflate compression
**/ **/
VIGRA_EXPORT VolumeExportInfo & setCompression( const char * ); VIGRA_EXPORT VolumeExportInfo & setCompression( const char * type);
VIGRA_EXPORT const char * getCompression() const; VIGRA_EXPORT const char * getCompression() const;
/** Set the pixel type of the volume file(s). Possible values are: /** Set the pixel type of the volume file(s). 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)
<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)
skipping to change at line 519 skipping to change at line 507
The data are expected to be stored in a by-slice manner, The data are expected to be stored in a by-slice manner,
where the slices are enumerated from <tt>name_base+"[0-9]+"+name_ext</t t>. 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 <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, 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 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 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 same size. The <tt>volume</tt> will be reshaped to match the count and
size of the slices found. size of the slices found.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> \<vigra/multi_impex.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class Allocator> template <class T, class Allocator>
void importVolume (MultiArray <3, T, Allocator> & volume, void importVolume (MultiArray <3, T, Allocator> & volume,
const std::string &name_base, const std::string &name_base,
const std::string &name_ext) const std::string &name_ext)
{ {
VolumeImportInfo info(name_base, name_ext); VolumeImportInfo info(name_base, name_ext);
volume.reshape(info.shape()); volume.reshape(info.shape());
skipping to change at line 567 skipping to change at line 555
<li> datatype = [UNSIGNED_CHAR | UNSIGNED_BYTE] (default: UNSIGNED _CHAR) <li> datatype = [UNSIGNED_CHAR | UNSIGNED_BYTE] (default: UNSIGNED _CHAR)
</UL> </UL>
The voxel type is currently assumed to be binary compatible to the <tt>value_type T</TT> 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. of the <tt>MuliArray</tt>. Lines starting with "#" are ignored.
</UL> </UL>
In either case, the <tt>volume</tt> will be reshaped to match the count and In either case, the <tt>volume</tt> will be reshaped to match the count and
size of the slices found. size of the slices found.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> \<vigra/multi_impex.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class Allocator> template <class T, class Allocator>
void importVolume(MultiArray <3, T, Allocator> &volume, void importVolume(MultiArray <3, T, Allocator> &volume,
const std::string &filename) const std::string &filename)
{ {
VolumeImportInfo info(filename); VolumeImportInfo info(filename);
volume.reshape(info.shape()); volume.reshape(info.shape());
skipping to change at line 590 skipping to change at line 578
/** \brief Function for importing a 3D volume. /** \brief Function for importing a 3D volume.
Read the volume data set <tt>info</tt> refers to. Explicit construction Read the volume data set <tt>info</tt> refers to. Explicit construction
of the info object allows to allocate a <tt>volume</tt> object type who se of the info object allows to allocate a <tt>volume</tt> object type who se
<tt>value_type</tt> matches the voxel type of the stored data. <tt>value_type</tt> matches the voxel type of the stored data.
The <tt>volume</tt> will be reshaped to match the count and The <tt>volume</tt> will be reshaped to match the count and
size of the slices found. size of the slices found.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> \<vigra/multi_impex.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class Stride> template <class T, class Stride>
void importVolume(VolumeImportInfo const & info, MultiArrayView <3, T, Stri de> &volume) void importVolume(VolumeImportInfo const & info, MultiArrayView <3, T, Stri de> &volume)
{ {
info.importImpl(volume); info.importImpl(volume);
} }
namespace detail { namespace detail {
skipping to change at line 688 skipping to change at line 676
/** \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 equals The volume is exported in a by-slice manner, where the number of slices equals
the depth of the volume. The file names will be enumerated like the depth of the volume. The file names will be enumerated like
<tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext</tt> et c. <tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext</tt> et c.
(the actual number of zeros depends on the depth). If the target image type (the actual number of zeros depends on the depth). If the target image type
does not support the source voxel type, all slices will be mapped simul taneously does not support the source voxel type, all slices will be mapped simul taneously
to the appropriate target range. to the appropriate target range.
<b>\#include</b> <b>\#include</b>
\<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> \<vigra/multi_impex.hxx\>
Namespace: vigra Namespace: vigra
*/ */
template <class T, class Tag> template <class T, class Tag>
void exportVolume (MultiArrayView <3, T, Tag> const & volume, void exportVolume (MultiArrayView <3, T, Tag> const & volume,
const VolumeExportInfo & volinfo) const VolumeExportInfo & volinfo)
{ {
std::string name = std::string(volinfo.getFileNameBase()) + std::string (volinfo.getFileNameExt()); std::string name = std::string(volinfo.getFileNameBase()) + std::string (volinfo.getFileNameExt());
ImageExportInfo info(name.c_str()); ImageExportInfo info(name.c_str());
info.setCompression(volinfo.getCompression()); info.setCompression(volinfo.getCompression());
 End of changes. 10 change blocks. 
24 lines changed or deleted 10 lines changed or added


 multi_iterator.hxx   multi_iterator.hxx 
skipping to change at line 58 skipping to change at line 58
template <unsigned int N, class T, template <unsigned int N, class T,
class REFERENCE = T &, class POINTER = T *> class StridedMultiIte rator; class REFERENCE = T &, class POINTER = T *> class StridedMultiIte rator;
/** \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>Iterator for unstrided \ref vigra::MultiArra yView</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
<BR>&nbsp;&nbsp;&nbsp;<em>STL-compatible random access iterator for \r
ef vigra::MultiArrayView</em>
</UL> </UL>
</p> </p>
<p> <p>
The Multidimensional Iterator concept allows navigation on arrays The Multidimensional Iterator concept allows navigation on arrays
of arbitrary dimension. It provides two modes of iteration: of arbitrary dimension. It provides two modes of iteration:
<em>direct traveral</em>, and <em>hierarchical traversal</em>. <em>direct traversal</em>, and <em>hierarchical traversal</em>.
In general, hierarchical traversal will be faster, while only In general, hierarchical traversal will be faster, while only
direct traversal allows for true random access in all dimensions. direct traversal allows for true random access in all dimensions.
Via the <tt>dim<K>()</tt> function, operations applying to a particular Via the <tt>dim<K>()</tt> function, operations applying to a particular
dimension can be used in the direct traversal mode. In contrast, dimension can be used in the direct traversal mode. In contrast,
direct traversal functions should not be used in the hierarchical mode direct traversal functions should not be used in the hierarchical mode
because the hierarchical functions are only well-defined if the because the hierarchical functions are only well-defined if the
iterator points to element 0 in all dimensions below its current dimens ion. iterator points to element 0 in all dimensions below its current dimens ion.
The current dimension of a <tt>MultiIterator<N, ...></tt> is <tt>N-1</t t>. The current dimension of a <tt>MultiIterator<N, ...></tt> is <tt>N-1</t t>.
</p> </p>
<h3>Gerneral Requirements for MultiIterator</h3> <h3>General Requirements for MultiIterator</h3>
<p> <p>
<table border=2 cellspacing=0 cellpadding=2 width="100%"> <table border=2 cellspacing=0 cellpadding=2 width="100%">
<tr><th colspan=2> <tr><th colspan=2>
Local Types Local Types
</th><th> </th><th>
Meaning Meaning
</th> </th>
</tr> </tr>
<tr><td colspan=2> <tr><td colspan=2>
<tt>MultiIterator::value_type</tt></td><td>the underlying arrays's pixe l type</td> <tt>MultiIterator::value_type</tt></td><td>the underlying arrays's pixe l type</td>
skipping to change at line 292 skipping to change at line 294
<td><tt>i - j < 0</tt><br> <td><tt>i - j < 0</tt><br>
<em>Note:</em> The result of this operation is undefined if the iterato r <em>Note:</em> The result of this operation is undefined if the iterato r
doesn't point to element 0 in all dimensions below its current dimensio n.</td> doesn't point to element 0 in all dimensions below its current dimensio n.</td>
</tr> </tr>
<tr> <tr>
<td><tt>i[d]</tt></td><td><tt>MultiIterator::reference</tt></td> <td><tt>i[d]</tt></td><td><tt>MultiIterator::reference</tt></td>
<td>access element by adding offset <tt>d</tt> in current dimension</td > <td>access element by adding offset <tt>d</tt> in current dimension</td >
</tr> </tr>
<tr> <tr>
<td><tt>i.begin()</tt></td><td><tt>next_type</tt></td> <td><tt>i.begin()</tt></td><td><tt>next_type</tt></td>
<td>create the hierarchical iterator poiting to the first element in th e <td>create the hierarchical iterator pointing to the first element in t he
next lower dimension.<br> next lower dimension.<br>
<em>Note:</em> The result of this operation is undefined if the iterato r <em>Note:</em> The result of this operation is undefined if the iterato r
doesn't point to element 0 in all dimensions below its current dimensio n.<br> doesn't point to element 0 in all dimensions below its current dimensio n.<br>
Usage:<br> Usage:<br>
\code \code
MultiIterator<3, int> i3 = ..., end3 = ...; MultiIterator<3, int> i3 = ..., end3 = ...;
for(; i3 != end3; ++i3) for(; i3 != end3; ++i3)
{ {
MultiIterator<3, int>::next_type i2 = i3.begin(), end2 = i3.end(); MultiIterator<3, int>::next_type i2 = i3.begin(), end2 = i3.end();
for(; i2 != end2; ++i2) for(; i2 != end2; ++i2)
skipping to change at line 317 skipping to change at line 319
... // do something with the current element ... // do something with the current element
} }
} }
} }
\endcode \endcode
</td> </td>
</tr> </tr>
<tr> <tr>
<td><tt>i.end()</tt></td><td><tt>next_type</tt></td> <td><tt>i.end()</tt></td><td><tt>next_type</tt></td>
<td>create the hierarchical iterator poiting to the past-the-end locati on in the <td>create the hierarchical iterator pointing to the past-the-end locat ion in the
next lower dimension.<br> next lower dimension.<br>
<em>Note:</em> The result of this operation is undefined if the iterato r <em>Note:</em> The result of this operation is undefined if the iterato r
doesn't point to element 0 in all dimensions below its current dimensio n.</td> doesn't point to element 0 in all dimensions below its current dimensio n.</td>
</tr> </tr>
<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>
skipping to change at line 356 skipping to change at line 358
template <unsigned int N> template <unsigned int N>
class MultiArrayShape class MultiArrayShape
{ {
public: public:
/** The difference type of all MultiIterator, MultiArrayView, and /** The difference type of all MultiIterator, MultiArrayView, and
MultiArray variants. MultiArray variants.
*/ */
typedef TinyVector<MultiArrayIndex, N> type; 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>
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIterator */ /* MultiIterator */
/* */ /* */
/********************************************************/ /********************************************************/
template <unsigned int N, class T, class REFERENCE, class POINTER> template <unsigned int N, class T, class REFERENCE, class POINTER>
class MultiIterator; class MultiIterator;
/********************************************************/ /********************************************************/
skipping to change at line 573 skipping to change at line 581
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiIterator<2> */ /* MultiIterator<2> */
/* */ /* */
/********************************************************/ /********************************************************/
// //
template <class T, class REFERENCE, class POINTER> template <class T, class REFERENCE, class POINTER>
class MultiIterator<2, T, REFERENCE, POINTER> class MultiIterator<2, T, REFERENCE, POINTER>
#ifndef DOXYGEN // doxygen doesn't understand this inheritance
: public MultiIterator<1, T, REFERENCE, POINTER> : public MultiIterator<1, T, REFERENCE, POINTER>
#endif
{ {
public: public:
typedef MultiIterator<1, T, REFERENCE, POINTER> base_type; typedef MultiIterator<1, T, REFERENCE, POINTER> base_type;
enum { level = 1 }; enum { level = 1 };
typedef T value_type; typedef T value_type;
typedef REFERENCE reference; typedef REFERENCE reference;
typedef const value_type &const_reference; typedef const value_type &const_reference;
typedef POINTER pointer; typedef POINTER pointer;
typedef const value_type *const_pointer; typedef const value_type *const_pointer;
skipping to change at line 751 skipping to change at line 761
/* */ /* */
/* 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> \<<a href="multi__iterator_8hxx-source.html">vigra/multi_i terator.hxx</a>\> <b>\#include</b> \<vigra/multi_iterator.hxx\>
Namespace: vigra 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
: public MultiIterator<N-1, T, REFERENCE, POINTER> : public MultiIterator<N-1, T, REFERENCE, POINTER>
#endif
{ {
public: public:
/** the type of the parent in the inheritance hierarchy. /** the type of the parent in the inheritance hierarchy.
*/ */
typedef MultiIterator<N-1, T, REFERENCE, POINTER> base_type; typedef MultiIterator<N-1, T, REFERENCE, POINTER> base_type;
/** the iterator's level in the dimension hierarchy /** the iterator's level in the dimension hierarchy
*/ */
enum { level = N-1 }; enum { level = N-1 };
skipping to change at line 1322 skipping to change at line 1334
/********************************************************/ /********************************************************/
/* */ /* */
/* StridedMultiIterator<2> */ /* StridedMultiIterator<2> */
/* */ /* */
/********************************************************/ /********************************************************/
// //
template <class T, class REFERENCE, class POINTER> template <class T, class REFERENCE, class POINTER>
class StridedMultiIterator<2, T, REFERENCE, POINTER> class StridedMultiIterator<2, T, REFERENCE, POINTER>
#ifndef DOXYGEN // doxygen doesn't understand this inheritance
: public StridedMultiIterator<1, T, REFERENCE, POINTER> : public StridedMultiIterator<1, T, REFERENCE, POINTER>
#endif
{ {
public: public:
typedef StridedMultiIterator<1, T, REFERENCE, POINTER> base_type; typedef StridedMultiIterator<1, T, REFERENCE, POINTER> base_type;
enum { level = 1 }; enum { level = 1 };
typedef T value_type; typedef T value_type;
typedef REFERENCE reference; typedef REFERENCE reference;
typedef const value_type &const_reference; typedef const value_type &const_reference;
typedef POINTER pointer; typedef POINTER pointer;
typedef const value_type *const_pointer; typedef const value_type *const_pointer;
skipping to change at line 1500 skipping to change at line 1514
/* */ /* */
/* 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> \<<a href="multi__iterator_8hxx-source.html">vigra/multi_i terator.hxx</a>\> <b>\#include</b> \<vigra/multi_iterator.hxx\>
Namespace: vigra 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
: public StridedMultiIterator<N-1, T, REFERENCE, POINTER> : public StridedMultiIterator<N-1, T, REFERENCE, POINTER>
#endif
{ {
public: public:
/** the type of the parent in the inheritance hierarchy. /** the type of the parent in the inheritance hierarchy.
*/ */
typedef StridedMultiIterator<N-1, T, REFERENCE, POINTER> base_type; typedef StridedMultiIterator<N-1, T, REFERENCE, POINTER> base_type;
/** the iterator's level in the dimension hierarchy /** the iterator's level in the dimension hierarchy
*/ */
enum { level = N-1 }; enum { level = N-1 };
skipping to change at line 1851 skipping to change at line 1867
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 <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 = 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 = 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 MultiArrayIndex difference_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;
}
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;
}
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>
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>
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];
}
}
};
template <unsigned int N, class T, class REFERENCE, class POINTER>
class StridedScanOrderIterator<N, T, REFERENCE, POINTER, 1>
{
enum { level = 0 };
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 MultiArrayIndex difference_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;
}
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;
}
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);
}
pointer i_;
shape_type point_, shape_, strides_;
MultiArrayIndex index_;
};
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_MULTI_ITERATOR_HXX #endif // VIGRA_MULTI_ITERATOR_HXX
 End of changes. 18 change blocks. 
7 lines changed or deleted 646 lines changed or added


 multi_morphology.hxx   multi_morphology.hxx 
skipping to change at line 57 skipping to change at line 57
#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"
namespace vigra namespace vigra
{ {
namespace detail { namespace detail {
// this class simplfies the design, but more importantly, it makes sure // this class simplifies the design, but more importantly, it makes sure
// that the in-place code doesn't get compiled for boolean arrays // that the in-place code doesn't get compiled for boolean arrays
// (were it would never executed anyway -- see the specializations below) // (were it would never executed anyway -- see the specializations below)
template <class DestType, class TmpType> template <class DestType, class TmpType>
struct MultiBinaryMorphologyImpl struct MultiBinaryMorphologyImpl
{ {
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
exec( SrcIterator s, SrcShape const & shape, SrcAccessor src, exec( SrcIterator s, SrcShape const & shape, SrcAccessor src,
DestIterator d, DestAccessor dest, DestIterator d, DestAccessor dest,
skipping to change at line 153 skipping to change at line 153
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* multiBinaryErosion */ /* multiBinaryErosion */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Binary erosion on multi-dimensional arrays. /** \brief Binary erosion on multi-dimensional arrays.
This function applies a flat circular erosion operator with a given rad ius. The This function applies a flat circular erosion operator with a given rad ius. The
operation is isotropic. The input is intepreted as a binary multi-dimen sional operation is isotropic. The input is interpreted as a binary multi-dime nsional
array where non-zero pixels represent foreground and zero pixels repres ent array where non-zero pixels represent foreground and zero pixels repres ent
background. In the output, foregound is always represented by ones background. In the output, foreground is always represented by ones
(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>
skipping to change at line 193 skipping to change at line 193
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m ulti_morphology.hxx</a>\> <b>\#include</b> \<vigra/multi_morphology.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray(dest), 3) ;
\endcode \endcode
skipping to change at line 251 skipping to change at line 251
/********************************************************/ /********************************************************/
/* */ /* */
/* multiBinaryDilation */ /* multiBinaryDilation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Binary dilation on multi-dimensional arrays. /** \brief Binary dilation on multi-dimensional arrays.
This function applies a flat circular dilation operator with a given ra dius. The This function applies a flat circular dilation operator with a given ra dius. The
operation is isotropic. The input is intepreted as a binary multi-dimen sional operation is isotropic. The input is interpreted as a binary multi-dime nsional
array where non-zero pixels represent foreground and zero pixels repres ent array where non-zero pixels represent foreground and zero pixels repres ent
background. In the output, foregound is always represented by ones background. In the output, foreground is always represented by ones
(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>
skipping to change at line 291 skipping to change at line 291
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m ulti_morphology.hxx</a>\> <b>\#include</b> \<vigra/multi_morphology.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray(dest), 3 );
\endcode \endcode
skipping to change at line 386 skipping to change at line 386
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m ulti_morphology.hxx</a>\> <b>\#include</b> \<vigra/multi_morphology.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray(dest), 3.0);
\endcode \endcode
skipping to change at line 413 skipping to change at line 413
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 };
// temporay array to hold the current line to enable in-place operation // 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<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator; 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;
skipping to change at line 505 skipping to change at line 505
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m ulti_morphology.hxx</a>\> <b>\#include</b> \<vigra/multi_morphology.hxx\>
\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, 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(srcMultiArrayRange(source), destMultiArray(dest) , 3.0);
\endcode \endcode
skipping to change at line 532 skipping to change at line 532
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 };
// temporay array to hold the current line to enable in-place operation // 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<SrcIterator, N> SNavigator;
typedef MultiArrayNavigator<DestIterator, N> DNavigator; 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;
 End of changes. 11 change blocks. 
11 lines changed or deleted 11 lines changed or added


 multi_pointoperators.hxx   multi_pointoperators.hxx 
skipping to change at line 58 skipping to change at line 58
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> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\> <b>\#include</b> \<vigra/multi_pointoperators.hxx\>
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* initMultiArray */ /* initMultiArray */
/* */ /* */
/********************************************************/ /********************************************************/
template <class Iterator, class Shape, class Accessor, template <class Iterator, class Shape, class Accessor,
skipping to change at line 93 skipping to change at line 93
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 pixel in a multi-dimensional array.
This function can be used to init the array which must be represented b y This function can be used to init the array which must be represented b y
a pair of iterators compatible to \ref vigra::MultiIterator. a pair of iterators compatible to \ref vigra::MultiIterator.
It uses an accessor to access the data alements. Note that the iterator range 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 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 the range simultaneously in all dimensions (this is a necessary consequ ence
of the \ref vigra::MultiIterator design). 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 ist 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 arguments explicitly:
\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);
skipping to change at line 134 skipping to change at line 134
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array array(Array::size_type(100, 200, 50)); Array array(Array::size_type(100, 200, 50));
// zero the array // zero the array
vigra::initMultiArray(destMultiArrayRange(array), 0); vigra::initMultiArray(destMultiArrayRange(array), 0);
\endcode \endcode
skipping to change at line 303 skipping to change at line 303
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). The function uses accessors to access the data elemen ts.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 601 skipping to change at line 601
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
(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. The function uses accessors to access the data elements.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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,
skipping to change at line 688 skipping to change at line 688
vigra::transformMultiArray(srcMultiArrayRange(src), vigra::transformMultiArray(srcMultiArrayRange(src),
destMultiArrayRange(dest), destMultiArrayRange(dest),
(float(*)(float))&std::sqrt ); (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 only 1D (it's width and height are 1).
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 intepreted 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. Note that the destination shape
must also be passed for the reduction to work, so we use must also be passed for the reduction to work, so we use
<tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>. <tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>.
\code \code
typedef vigra::MultiArray<3, float> Array; typedef vigra::MultiArray<3, float> Array;
Array src(Array::size_type(100, 200, 50)), Array src(Array::size_type(100, 200, 50)),
dest(Array::size_type(1, 1, 50)); dest(Array::size_type(1, 1, 50));
... ...
skipping to change at line 727 skipping to change at line 727
MultiIterator src_begin, src_end, dest_begin; MultiIterator src_begin, src_end, dest_begin;
SrcAccessor src_accessor; SrcAccessor src_accessor;
DestAccessor dest_accessor; DestAccessor dest_accessor;
Functor functor; Functor functor;
dest_accessor.set(functor(src_accessor(src_begin)), dest_begin); dest_accessor.set(functor(src_accessor(src_begin)), dest_begin);
\endcode \endcode
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 vakue <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.
skipping to change at line 1019 skipping to change at line 1019
must be either equal (standard copy), or the length of this dimension m ust must be either equal (standard copy), or the length of this dimension m ust
be 1 in one or both source arrays be 1 in one or both source arrays
(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. The function uses accessors to access the data elements.
<b> Declarations:</b> <b> Declarations:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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(
skipping to change at line 1120 skipping to change at line 1120
srcMultiArray(src2), srcMultiArray(src2),
destMultiArray(dest), destMultiArray(dest),
std::plus<int>()); 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 1).
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 intepreted 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 absolute difference of the gray values in every pair of to calculate the total absolute difference of the gray values in every pair of
source slices. Note that the shapes of all arrays must be passed 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 to the algorithm in order for the reduction to work, so we use
<tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt> <tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt>
rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>. rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
\code \code
#include <vigra/functorexpression.hxx> #include <vigra/functorexpression.hxx>
skipping to change at line 1144 skipping to change at line 1144
Array src1(Array::size_type(100, 200, 50)), Array src1(Array::size_type(100, 200, 50)),
src2(Array::size_type(100, 200, 50)), src2(Array::size_type(100, 200, 50)),
dest(Array::size_type(1, 1, 50)); dest(Array::size_type(1, 1, 50));
... ...
vigra::combineTwoMultiArrays( vigra::combineTwoMultiArrays(
srcMultiArrayRange(src1), srcMultiArrayRange(src1),
srcMultiArray(src2), srcMultiArray(src2),
destMultiArray(dest), destMultiArray(dest),
reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) ); reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) );
// Arg1() is the sum accumulated so far, initialzed 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> <b> Required Interface:</b>
In standard and expand mode, the functor must be a model of BinaryFunct ion In standard and expand mode, the functor must be a model of BinaryFunct ion
skipping to change at line 1174 skipping to change at line 1174
Functor functor; Functor functor;
dest_accessor.set( dest_accessor.set(
functor(src1_accessor(src1_begin), src2_accessor(src2_begin)), functor(src1_accessor(src1_begin), src2_accessor(src2_begin)),
dest_begin); dest_begin);
\endcode \endcode
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 vakue <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.
skipping to change at line 1352 skipping to change at line 1352
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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(Array::size_type(100, 200, 50)),
src2(Array::size_type(100, 200, 50)), src2(Array::size_type(100, 200, 50)),
src3(Array::size_type(100, 200, 50)), src3(Array::size_type(100, 200, 50)),
dest(Array::size_type(100, 200, 50)); dest(Array::size_type(100, 200, 50));
skipping to change at line 1465 skipping to change at line 1465
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array array(Array::size_type(100, 200, 50)); Array array(Array::size_type(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);
skipping to change at line 1582 skipping to change at line 1582
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__pointoperators_8hxx-source.html">vig ra/multi_pointoperators.hxx</a>\><br> <b>\#include</b> \<vigra/multi_pointoperators.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array array1(Array::size_type(100, 200, 50)), Array array1(Array::size_type(100, 200, 50)),
array2(Array::size_type(100, 200, 50)); array2(Array::size_type(100, 200, 50));
// init functor // init functor
SomeStatisticsFunctor stats(..); SomeStatisticsFunctor stats(..);
 End of changes. 15 change blocks. 
15 lines changed or deleted 15 lines changed or added


 multi_resize.hxx   multi_resize.hxx 
skipping to change at line 81 skipping to change at line 81
Rational<int> ratio(dsize - 1, ssize - 1); Rational<int> ratio(dsize - 1, ssize - 1);
Rational<int> offset(0); Rational<int> offset(0);
resampling_detail::MapTargetToSourceCoordinate mapCoordinate(ratio, off set); resampling_detail::MapTargetToSourceCoordinate mapCoordinate(ratio, off set);
int period = lcm(ratio.numerator(), ratio.denominator()); int period = lcm(ratio.numerator(), ratio.denominator());
ArrayVector<double> const & prefilterCoeffs = spline.prefilterCoefficie nts(); ArrayVector<double> const & prefilterCoeffs = spline.prefilterCoefficie nts();
ArrayVector<Kernel1D<double> > kernels(period); ArrayVector<Kernel1D<double> > kernels(period);
createResamplingKernels(spline, mapCoordinate, kernels); createResamplingKernels(spline, mapCoordinate, kernels);
// temporay array to hold the current line to enable in-place operation // temporary array to hold the current line to enable in-place operatio n
ArrayVector<TmpType> tmp( ssize ); ArrayVector<TmpType> tmp( ssize );
typename ArrayVector<TmpType>::iterator t = tmp.begin(), tend = tmp.end (); typename ArrayVector<TmpType>::iterator t = tmp.begin(), tend = tmp.end ();
typename AccessorTraits<TmpType>::default_accessor ta; typename AccessorTraits<TmpType>::default_accessor ta;
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, t, ta); copyLine( snav.begin(), snav.end(), src, t, ta);
for(unsigned int b = 0; b < prefilterCoeffs.size(); ++b) for(unsigned int b = 0; b < prefilterCoeffs.size(); ++b)
skipping to change at line 152 skipping to change at line 152
Kernel const & spline = BSpline<3, double>()) ; Kernel const & spline = BSpline<3, double>()) ;
} }
\endcode \endcode
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 cion 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
which gives a twice continuously differentiable interpolant. which gives a twice continuously differentiable interpolant.
The implementation ensures that image values are interpolated rather The implementation ensures that image values are interpolated rather
than smoothed by first calling a recursive (sharpening) prefilter as than smoothed by first calling a recursive (sharpening) prefilter as
described in the above paper. Then the actual interpolation is done described in the above paper. Then the actual interpolation is done
using \ref resamplingConvolveLine(). using \ref resamplingConvolveLine().
The range of both the input and output images (resp. regions) The range of both the input and output images (resp. regions)
must be given. The input image must have a size of at must be given. The input image must have a size of at
skipping to change at line 174 skipping to change at line 174
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> \<<a href="multi__resize_8hxx-source.html">vigra/m ulti_resize.hxx</a>\><br> <b>\#include</b> \<vigra/multi_resize.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, float>::difference_type Shape; typedef vigra::MultiArray<3, float>::difference_type Shape;
vigra::MultiArray<3, float> src(Shape(5, 7, 10)), vigra::MultiArray<3, float> src(Shape(5, 7, 10)),
dest(Shape(9, 13, 19)); // double the size dest(Shape(9, 13, 19)); // double the size
// use default cubic spline interpolator // use default cubic spline interpolator
vigra::resizeMultiArraySplineInterpolation( vigra::resizeMultiArraySplineInterpolation(
srcMultiArrayRange(src), srcMultiArrayRange(src),
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 multi_tensorutilities.hxx   multi_tensorutilities.hxx 
skipping to change at line 231 skipping to change at line 231
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__tensorutilities_8hxx-source.html">vi gra/multi_tensorutilities.hxx</a>\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\>
\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 ient), 2.0); gaussianGradientMultiArray(srcMultiArrayRange(vol), destMultiArray(grad ient), 2.0);
vectorToTensorMultiArray(srcMultiArrayRange(gradient), destMultiArray(t ensor)); vectorToTensorMultiArray(srcMultiArrayRange(gradient), destMultiArray(t ensor));
\endcode \endcode
skipping to change at line 261 skipping to change at line 261
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 SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
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 == src.size(si), vigra_precondition(N == (int)src.size(si),
"vectorToTensorMultiArray(): Wrong number of channels in input arra y."); "vectorToTensorMultiArray(): Wrong number of channels in input arra y.");
vigra_precondition(M == dest.size(di), vigra_precondition(M == (int)dest.size(di),
"vectorToTensorMultiArray(): Wrong number of channels in output arr ay."); "vectorToTensorMultiArray(): Wrong number of channels in output arr ay.");
transformMultiArray(si, shape, src, di, dest, transformMultiArray(si, shape, src, di, dest,
detail::OuterProductFunctor<N, SrcType, DestType>() ); detail::OuterProductFunctor<N, SrcType, DestType>() );
} }
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,
skipping to change at line 319 skipping to change at line 319
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__tensorutilities_8hxx-source.html">vi gra/multi_tensorutilities.hxx</a>\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\>
\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 sian), 2.0); hessianOfGaussianMultiArray(srcMultiArrayRange(vol), destMultiArray(hes sian), 2.0);
tensorTraceMultiArray(srcMultiArrayRange(hessian), destMultiArray(trace )); tensorTraceMultiArray(srcMultiArrayRange(hessian), destMultiArray(trace ));
\endcode \endcode
skipping to change at line 396 skipping to change at line 396
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__tensorutilities_8hxx-source.html">vi gra/multi_tensorutilities.hxx</a>\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\>
\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 sian), 2.0); hessianOfGaussianMultiArray(srcMultiArrayRange(vol), destMultiArray(hes sian), 2.0);
tensorEigenvaluesMultiArray(srcMultiArrayRange(hessian), destMultiArray (eigenvalues)); tensorEigenvaluesMultiArray(srcMultiArrayRange(hessian), destMultiArray (eigenvalues));
\endcode \endcode
skipping to change at line 426 skipping to change at line 426
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 SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
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(M == src.size(si), vigra_precondition(M == (int)src.size(si),
"tensorEigenvaluesMultiArray(): Wrong number of channels in input a rray."); "tensorEigenvaluesMultiArray(): Wrong number of channels in input a rray.");
vigra_precondition(N == dest.size(di), vigra_precondition(N == (int)dest.size(di),
"tensorEigenvaluesMultiArray(): Wrong number of channels in output array."); "tensorEigenvaluesMultiArray(): Wrong number of channels in output array.");
transformMultiArray(si, shape, src, di, dest, transformMultiArray(si, shape, src, di, dest,
detail::EigenvaluesFunctor<N, SrcType, DestType>()) ; detail::EigenvaluesFunctor<N, SrcType, DestType>()) ;
} }
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,
skipping to change at line 484 skipping to change at line 484
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="multi__tensorutilities_8hxx-source.html">vi gra/multi_tensorutilities.hxx</a>\> <b>\#include</b> \<vigra/multi_tensorutilities.hxx\>
\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 sian), 2.0); hessianOfGaussianMultiArray(srcMultiArrayRange(vol), destMultiArray(hes sian), 2.0);
tensorDeterminantMultiArray(srcMultiArrayRange(hessian), destMultiArray (determinant)); tensorDeterminantMultiArray(srcMultiArrayRange(hessian), destMultiArray (determinant));
\endcode \endcode
skipping to change at line 513 skipping to change at line 513
{ {
typedef typename SrcAccessor::value_type SrcType; typedef typename SrcAccessor::value_type SrcType;
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;
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(M == src.size(si), vigra_precondition(M == (int)src.size(si),
"tensorDeterminantMultiArray(): Wrong number of channels in output array."); "tensorDeterminantMultiArray(): Wrong number of channels in output array.");
transformMultiArray(si, shape, src, di, dest, transformMultiArray(si, shape, src, di, dest,
detail::DeterminantFunctor<N, SrcType>()); detail::DeterminantFunctor<N, SrcType>());
} }
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,
 End of changes. 9 change blocks. 
9 lines changed or deleted 9 lines changed or added


 navigator.hxx   navigator.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_NAVIGATOR_HXX #define VIGRA_NAVIGATOR_HXX
namespace vigra { namespace vigra {
/********************************************************/ /********************************************************/
/* */ /* */
/* MultiArrayNavigator */ /* MultiArrayNavigator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief A navigator that provides acces 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.
Normally, the innermost loop of an iteration extends over the innermost Normally, the innermost loop of an iteration extends over the innermost
dimension of a given array. Sometimes, however, it is necessary to have dimension of a given array. Sometimes, however, it is necessary to have
some other dimension in the inner loop. For example, instead of iterati ng over some other dimension in the inner loop. For example, instead of iterati ng over
the rows, the inner loop should extend over the columns. The class Mult iArrayNavigator the rows, the inner loop should extend over the columns. The class Mult iArrayNavigator
encapsulates the necessary functionality. Given an arbitrary dimensiona l encapsulates the necessary functionality. Given an arbitrary dimensiona l
array (represented by a vigra::MultiIterator/shape pair), and the desir ed array (represented by a vigra::MultiIterator/shape pair), and the desir ed
inner loop dimension <TT>d</TT>, it moves the encapsulated iterator to all possible inner loop dimension <TT>d</TT>, it moves the encapsulated iterator to all possible
starting points of 1D subsets along the given dimension (e.g. all colum ns). By calling starting points of 1D subsets along the given dimension (e.g. all colum ns). By calling
<TT>begin()</TT> and <TT>end()</TT>, one can then obtain an STL-compati ble 1-dimensional <TT>begin()</TT> and <TT>end()</TT>, one can then obtain an STL-compati ble 1-dimensional
iterator for the current subset. iterator for the current subset.
The template parameters specify the embedded iterator type and its dime nsion. The template parameters specify the embedded iterator type and its dime nsion.
<b>Usage:</b> <b>Usage:</b>
<b>\#include</b> \<<a href="navigator_8hxx-source.html">vigra/navigator .hxx</a>\> <b>\#include</b> \<vigra/navigator.hxx\>
Namespace: vigra Namespace: vigra
\code \code
typedef vigra::MultiArray<3, int> Array; typedef vigra::MultiArray<3, int> Array;
Array a(Array::size_type(X, Y, Z)); Array a(Array::size_type(X, Y, Z));
typedef vigra::MultiArrayNavigator<Array::traverser, 3> Navigator; typedef vigra::MultiArrayNavigator<Array::traverser, 3> Navigator;
for(int d=0; d<3; ++d) for(int d=0; d<3; ++d)
{ {
// create Navigator for dimension d // create Navigator for dimension d
Navigator nav(a.traverser_begin(), a.shape(), d); Navigator nav(a.traverser_begin(), a.shape(), d);
// outer loop: move navigator to all starting points // outer loop: move navigator to all starting points
// of 1D subsets that run parallel to coordinate axis d // of 1D subsets that run parallel to coordinate axis d
for(; nav.hasMore(); ++nav) for(; nav.hasMore(); ++nav)
{ {
// inner loop: linear iteration over current subset // inner loop: linear iteration over current subset
// d == {0, 1, 2}: interate along {x, y, z}-axis re // d == {0, 1, 2}: iterate along {x, y, z}-axis res
spectively pectively
Navigator::iterator i = nav.begin(), end = nav.end(); Navigator::iterator i = nav.begin(), end = nav.end();
for(; i != end; ++i) for(; i != end; ++i)
// do something // do something
} }
} }
\endcode \endcode
*/ */
template <class MULTI_ITERATOR, unsigned int N> template <class MULTI_ITERATOR, unsigned int N>
class MultiArrayNavigator class MultiArrayNavigator
#ifndef DOXYGEN // doxygen doesn't understand this inheritance #ifndef DOXYGEN // doxygen doesn't understand this inheritance
: public MultiArrayNavigator<MULTI_ITERATOR, N-1> : public MultiArrayNavigator<MULTI_ITERATOR, N-1>
skipping to change at line 117 skipping to change at line 117
typedef typename MULTI_ITERATOR::multi_difference_type shape_type; typedef typename MULTI_ITERATOR::multi_difference_type shape_type;
/** The iterator type for the inner loop (result of begin() and end ()). /** The iterator type for the inner loop (result of begin() and end ()).
*/ */
typedef typename MULTI_ITERATOR::iterator iterator; typedef typename MULTI_ITERATOR::iterator iterator;
/** Construct navigator for multi-dimensional iterator <TT>i</TT>, array shape <TT>shape</TT> /** Construct navigator for multi-dimensional iterator <TT>i</TT>, array shape <TT>shape</TT>
and inner loop dimension <TT>inner_dimension</TT>. and inner loop dimension <TT>inner_dimension</TT>.
*/ */
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)
: base_type(i, shape, inner_dimension), : base_type(i, shape, inner_dimension)
i_(i), {}
end_(i)
{ MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & start,
if(inner_dimension != level) shape_type const & stop,
end_.template dim<level>() += shape[level]; unsigned int inner_dimension)
} : base_type(i, start, stop, inner_dimension)
{}
/** Advance to next starting location. /** Advance to next starting location.
*/ */
void operator++() void operator++()
{ {
base_type::operator++(); base_type::operator++();
if(base_type::atEnd() && i_ < end_) // this tests implicitly inner_ dimension_ != level if(this->point_[level-1] == this->stop_[level-1])
{ {
++i_.template dim<level>(); base_type::reset();
if(i_ < end_) ++this->point_[level];
base_type::reset(i_); ++this->i_.template dim<level>();
} }
} }
/** Advance to next starting location. /** Advance to next starting location.
*/ */
void operator++(int) void operator++(int)
{ {
++*this; ++*this;
} }
/** true if there are more elements. /** true if there are more elements.
*/ */
bool hasMore() const bool hasMore() const
{ {
return this->inner_dimension_ == level ? return this->point_[level] < this->stop_[level];
base_type::hasMore() :
i_ < end_;
} }
/** true if iterator is exhausted. /** true if iterator is exhausted.
*/ */
bool atEnd() const bool atEnd() const
{ {
return this->inner_dimension_ == level ? return this->point_[level] >= this->stop_[level];
base_type::atEnd() :
!( i_ < end_);
} }
protected: protected:
void reset(MULTI_ITERATOR const & i) void reset()
{ {
end_ = i_ = i; this->point_[level] = this->start_[level];
if(this->inner_dimension_ != level) this->i_.template dim<level>() -= (this->stop_[level] - this->start
end_.template dim<level>() += this->shape_[level]; _[level]);
base_type::reset(i);
} }
MULTI_ITERATOR i_, end_;
}; };
template <class MULTI_ITERATOR> template <class MULTI_ITERATOR>
class MultiArrayNavigator<MULTI_ITERATOR, 1> class MultiArrayNavigator<MULTI_ITERATOR, 1>
{ {
public: public:
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)
: shape_(shape), : start_(), stop_(shape), point_(start_),
inner_dimension_(inner_dimension), inner_dimension_(inner_dimension),
i_(i), inner_shape_(stop_[inner_dimension] - start_[inner_dimension]),
end_(i) i_(i + start_)
{ {
if(inner_dimension != level) stop_[inner_dimension] = start_[inner_dimension] + 1;
end_.template dim<level>() += shape[level]; }
MultiArrayNavigator(MULTI_ITERATOR const & i, shape_type const & start,
shape_type const & stop,
unsigned int inner_dimension)
: start_(start), stop_(stop), point_(start_),
inner_dimension_(inner_dimension),
inner_shape_(stop_[inner_dimension] - start_[inner_dimension]),
i_(i + start_)
{
stop_[inner_dimension] = start_[inner_dimension] + 1;
} }
void operator++() void operator++()
{ {
++point_[level];
++i_.template dim<level>(); ++i_.template dim<level>();
} }
void operator++(int) void operator++(int)
{ {
++*this; ++*this;
} }
iterator begin() const iterator begin() const
{ {
return i_.iteratorForDimension(inner_dimension_); return i_.iteratorForDimension(inner_dimension_);
} }
iterator end() const iterator end() const
{ {
return begin() + shape_[inner_dimension_]; return begin() + inner_shape_;
} }
bool hasMore() const bool hasMore() const
{ {
return i_ < end_; return point_[level] < stop_[level];
} }
bool atEnd() const bool atEnd() const
{ {
return !( i_ < end_); return point_[level] >= stop_[level];
}
shape_type const & point() const
{
return point_;
} }
protected: protected:
void reset(MULTI_ITERATOR const & i) void reset()
{ {
end_ = i_ = i; point_[level] = start_[level];
if(inner_dimension_ != level) i_.template dim<level>() -= (stop_[level] - start_[level]);
end_.template dim<level>() += shape_[level]; }
shape_type start_, stop_, point_;
unsigned int inner_dimension_, inner_shape_;
MULTI_ITERATOR i_;
};
/********************************************************/
/* */
/* MultiCoordinateNavigator */
/* */
/********************************************************/
/** \brief A navigator that provides access to the 1D subranges of an
n-dimensional range given by an nD shape.
This class works similarly to \ref MultiArrayNavigator, but instead of
a
1-dimensional iterator pair, it returns a pair of shapes whose differen
ce
specifies a 1-dimensional range along the desired dimension. That is, w
hen
the navigator refers to dimension <tt>d</tt>, the difference between
<tt>end()</tt> and <tt>begin()</tt> is <tt>1</tt> along all dimensions
except <tt>d</tt>.
The template parameters specifies the dimension of the shape.
<b>Usage:</b>
<b>\#include</b> \<vigra/navigator.hxx\>
Namespace: vigra
\code
typedef vigra::MultiArrayShape<3>::type Shape;
typedef vigra::MultiArray<3, int> Array;
typedef vigra::MultiCoordinateNavigator<3> Navigator;
Array a(Shape(X, Y, Z));
for(int d=0; d<3; ++d)
{
// create Navigator for dimension d
Navigator nav(a.shape(), d);
// outer loop: move navigator to all starting points
// of 1D subsets that run parallel to coordinate axis d
for(; nav.hasMore(); ++nav)
{
// inner loop: linear iteration over current subset
// d == {0, 1, 2}: iterate along {x, y, z}-axis res
pectively
Shape point = nav.begin(), end = nav.end();
for(; point[d] != end[d]; ++point[d])
a[point] = 5;
}
} }
\endcode
*/
template <unsigned int Dimensions, unsigned int N = Dimensions>
class MultiCoordinateNavigator
#ifndef DOXYGEN // doxygen doesn't understand this inheritance
: public MultiCoordinateNavigator<Dimensions, N-1>
#endif
{
typedef MultiCoordinateNavigator<Dimensions, N-1> base_type;
shape_type shape_; public:
enum { level = N-1 };
/** The shape type for the given iterator type.
*/
typedef typename MultiArrayShape<Dimensions>::type value_type;
/** Construct navigator for multi-dimensional iterator <TT>i</TT>,
array shape <TT>shape</TT>
and inner loop dimension <TT>inner_dimension</TT>.
*/
MultiCoordinateNavigator(value_type const & shape, unsigned int inner_d
imension)
: base_type(shape, inner_dimension)
{
this->end_[level] = (this->inner_dimension_ == level)
? 1
: this->shape_[level];
}
/** Advance to next starting location.
*/
void operator++()
{
base_type::operator++();
if(base_type::atEnd() && this->i_[level] < this->end_[level])
{
++this->i_[level];
if(this->i_[level] < this->end_[level])
base_type::reset();
}
}
/** Advance to next starting location.
*/
void operator++(int)
{
++*this;
}
/** true if there are more elements.
*/
bool hasMore() const
{
return this->inner_dimension_ == level
? base_type::hasMore()
: this->i_[level] < this->end_[level];
}
/** true if iterator is exhausted.
*/
bool atEnd() const
{
return !hasMore();
// return this->inner_dimension_ == level
// ? base_type::atEnd()
// : !(this->i_[level] < this->end_[level]);
}
protected:
void reset()
{
this->i_[level] = 0;
this->end_[level] = (this->inner_dimension_ == level)
? 1
: this->shape_[level];
base_type::reset();
}
};
template <unsigned int Dimensions>
class MultiCoordinateNavigator<Dimensions, 1>
{
public:
enum { level = 0 };
typedef typename MultiArrayShape<Dimensions>::type value_type;
MultiCoordinateNavigator(value_type const & shape, unsigned int inner_d
imension)
: shape_(shape),
inner_dimension_(inner_dimension)
{
end_[level] = (inner_dimension_ == level)
? 1
: shape_[level];
}
void operator++()
{
++i_[level];
}
void operator++(int)
{
++*this;
}
value_type const & begin() const
{
return i_;
}
value_type end() const
{
value_type res = i_ + value_type(MultiArrayIndex(1));
res[inner_dimension_] = shape_[inner_dimension_];
return res;
}
bool hasMore() const
{
return i_[level] < end_[level];
}
bool atEnd() const
{
return !hasMore();
}
protected:
void reset()
{
i_[level] = 0;
end_[level] = (inner_dimension_ == level)
? 1
: shape_[level];
}
value_type shape_, i_, end_;
unsigned int inner_dimension_; unsigned int inner_dimension_;
MULTI_ITERATOR i_, end_;
}; };
} // namespace vigra } // namespace vigra
#endif /* VIGRA_NAVIGATOR_HXX */ #endif /* VIGRA_NAVIGATOR_HXX */
 End of changes. 23 change blocks. 
43 lines changed or deleted 245 lines changed or added


 noise_normalization.hxx   noise_normalization.hxx 
skipping to change at line 74 skipping to change at line 74
/********************************************************/ /********************************************************/
/** \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> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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));
\endcode \endcode
skipping to change at line 169 skipping to change at line 169
{ {
vigra_precondition(quantile > 0.0, vigra_precondition(quantile > 0.0,
"NoiseNormalizationOptions: noise estimation quantile must be > 0."); "NoiseNormalizationOptions: noise estimation quantile must be > 0.");
noise_estimation_quantile = quantile; noise_estimation_quantile = quantile;
return *this; return *this;
} }
/** Set the initial estimate of the noise variance. /** Set the initial estimate of the noise variance.
Robust noise variance estimation is an iterative procedure star ting at the given value.<br> Robust noise variance estimation is an iterative procedure star ting at the given value.<br>
Default: 10.0<br> Default: 10.0<br>
Precondition: 0 < \a quess Precondition: 0 < \a guess
*/ */
NoiseNormalizationOptions & noiseVarianceInitialGuess(double guess) NoiseNormalizationOptions & noiseVarianceInitialGuess(double guess)
{ {
vigra_precondition(guess > 0.0, vigra_precondition(guess > 0.0,
"NoiseNormalizationOptions: noise variance initial guess must b e > 0."); "NoiseNormalizationOptions: noise variance initial guess must b e > 0.");
noise_variance_initial_guess = guess; noise_variance_initial_guess = guess;
return *this; return *this;
} }
unsigned int window_radius, cluster_count; unsigned int window_radius, cluster_count;
skipping to change at line 583 skipping to change at line 583
clusters.push_back(Result(0, noise.size())); clusters.push_back(Result(0, noise.size()));
while(clusters.size() <= maxClusterCount) while(clusters.size() <= maxClusterCount)
{ {
// find biggest cluster // find biggest cluster
unsigned int kMax = 0; unsigned int kMax = 0;
double diffMax = 0.0; double diffMax = 0.0;
for(unsigned int k=0; k < clusters.size(); ++k) for(unsigned int k=0; k < clusters.size(); ++k)
{ {
double diff = noise[clusters[k][1]-1][0] - noise[clusters[k][0] int k1 = clusters[k][0], k2 = clusters[k][1]-1;
][0];
#if 0 // turned the "internal error" in a postcondition message
// for the most likely case
std::string message("noiseVarianceListMedianCut(): internal err
or (");
message += std::string("k: ") + asString(k) + ", ";
message += std::string("k1: ") + asString(k1) + ", ";
message += std::string("k2: ") + asString(k2) + ", ";
message += std::string("noise.size(): ") + asString(noise.size(
)) + ", ";
message += std::string("clusters.size(): ") + asString(clusters
.size()) + ").";
vigra_invariant(k1 >= 0 && k1 < (int)noise.size() && k2 >= 0 &&
k2 < (int)noise.size(), message.c_str());
#endif
vigra_postcondition(k1 >= 0 && k1 < (int)noise.size() &&
k2 >= 0 && k2 < (int)noise.size(),
"noiseVarianceClustering(): Unable to find homogeneous regi
ons.");
double diff = noise[k2][0] - noise[k1][0];
if(diff > diffMax) if(diff > diffMax)
{ {
diffMax = diff; diffMax = diff;
kMax = k; kMax = k;
} }
} }
if(diffMax == 0.0) if(diffMax == 0.0)
return; // all clusters have only one value return; // all clusters have only one value
skipping to change at line 673 skipping to change at line 690
typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType; typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP romote TmpType;
typedef BasicImage<TmpType> TmpImage; typedef BasicImage<TmpType> TmpImage;
TmpImage gradient(w, h); TmpImage gradient(w, h);
symmetricDifferenceSquaredMagnitude(sul, slr, src, gradient.upperLeft() , gradient.accessor()); symmetricDifferenceSquaredMagnitude(sul, slr, src, gradient.upperLeft() , gradient.accessor());
BImage homogeneous(w, h); BImage homogeneous(w, h);
findHomogeneousRegions(gradient.upperLeft(), gradient.lowerRight(), gra dient.accessor(), findHomogeneousRegions(gradient.upperLeft(), gradient.lowerRight(), gra dient.accessor(),
homogeneous.upperLeft(), homogeneous.acc essor()); homogeneous.upperLeft(), homogeneous.acc essor());
// Generate noise of each of the remaining pixels == centers of homogen ous areas (border is not used) // Generate noise of each of the remaining pixels == centers of homogen eous areas (border is not used)
unsigned int windowRadius = options.window_radius; unsigned int windowRadius = options.window_radius;
for(unsigned int y=windowRadius; y<h-windowRadius; ++y) for(unsigned int y=windowRadius; y<h-windowRadius; ++y)
{ {
for(unsigned int x=windowRadius; x<w-windowRadius; ++x) for(unsigned int x=windowRadius; x<w-windowRadius; ++x)
{ {
if (! homogeneous(x, y)) if (! homogeneous(x, y))
continue; continue;
Diff2D center(x, y); Diff2D center(x, y);
double mean = 0.0, variance = options.noise_variance_initial_gu ess; double mean = 0.0, variance = options.noise_variance_initial_gu ess;
skipping to change at line 735 skipping to change at line 752
noiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, noiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src,
DestIterator dul, DestAccessor dest, DestIterator dul, DestAccessor dest,
NoiseNormalizationOptions const & options) NoiseNormalizationOptions const & options)
{ {
ArrayVector<TinyVector<double, 2> > noiseData; ArrayVector<TinyVector<double, 2> > noiseData;
noiseVarianceEstimationImpl(sul, slr, src, noiseData, options); noiseVarianceEstimationImpl(sul, slr, src, noiseData, options);
if(noiseData.size() < 10) if(noiseData.size() < 10)
return false; return false;
std::sort(noiseData.begin(), noiseData.end(), SortNoiseByMean());
ArrayVector<TinyVector<double, 2> > noiseClusters; ArrayVector<TinyVector<double, 2> > noiseClusters;
noiseVarianceClusteringImpl(noiseData, noiseClusters, noiseVarianceClusteringImpl(noiseData, noiseClusters,
options.cluster_count, options.averaging_ quantile); options.cluster_count, options.averaging_ quantile);
transformImage(sul, slr, src, dul, dest, Functor(noiseClusters)); transformImage(sul, slr, src, dul, dest, Functor(noiseClusters));
return true; return true;
} }
skipping to change at line 984 skipping to change at line 999
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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));
skipping to change at line 1086 skipping to change at line 1101
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><br> <b>\#include</b> \<vigra/noise_normalization.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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));
skipping to change at line 1182 skipping to change at line 1197
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><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);
... ...
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
skipping to change at line 1262 skipping to change at line 1277
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());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><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);
... ...
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));
\endcode \endcode
skipping to change at line 1345 skipping to change at line 1360
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, S rcAccessor> src, void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, S rcAccessor> src,
pair<DestIterator, DestAccessor> de st, pair<DestIterator, DestAccessor> de st,
double a0, double a1, double a2); double a0, double a1, double a2);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><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);
... ...
vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest), vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest),
100, 0.02, 1e-6); 100, 0.02, 1e-6);
\endcode \endcode
skipping to change at line 1426 skipping to change at line 1441
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());
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><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);
... ...
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));
\endcode \endcode
skipping to change at line 1509 skipping to change at line 1524
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcA ccessor> src, void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcA ccessor> src,
pair<DestIterator, DestAccessor> dest , pair<DestIterator, DestAccessor> dest ,
double a0, double a1); double a0, double a1);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="noise__normalization_8hxx-source.html"> vigra/noise_normalization.hxx</a>\><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);
... ...
vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest), vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest),
100, 0.02); 100, 0.02);
\endcode \endcode
 End of changes. 12 change blocks. 
14 lines changed or deleted 33 lines changed or added


 nonlineardiffusion.hxx   nonlineardiffusion.hxx 
skipping to change at line 211 skipping to change at line 211
\frac{\partial}{\partial x} \frac{\partial}{\partial x}
\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
propotional 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
skipping to change at line 272 skipping to change at line 272
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="nonlineardiffusion_8hxx-source.html">vigra/ nonlineardiffusion.hxx</a>\> <b>\#include</b> \<vigra/nonlineardiffusion.hxx\>
\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
skipping to change at line 345 skipping to change at line 345
gradientBasedTransform(sul, slr, as, wi, wa, weight); gradientBasedTransform(sul, slr, as, wi, wa, weight);
internalNonlinearDiffusionAOSStep(sul, slr, as, wi, wa, s1, a, rest_tim e); internalNonlinearDiffusionAOSStep(sul, slr, as, wi, wa, s1, a, rest_tim e);
for(int i = 0; i < number_of_steps; ++i) for(int i = 0; i < number_of_steps; ++i)
{ {
gradientBasedTransform(s1, s1+size, a, wi, wa, weight); gradientBasedTransform(s1, s1+size, a, wi, wa, weight);
internalNonlinearDiffusionAOSStep(s1, s1+size, a, wi, wa, s2, a, ti me_step); internalNonlinearDiffusionAOSStep(s1, s1+size, a, wi, wa, s2, a, ti me_step);
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 nonlinearDiffusion( void nonlinearDiffusion(
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 numerictraits.hxx   numerictraits.hxx 
skipping to change at line 85 skipping to change at line 85
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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<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;
return result; return result;
} }
\endcode \endcode
The return type of this function can not be 'unsigned char' because The return type of this function can not be 'unsigned char' because
the summation would very likely overflow. Since we know the source the summation would very likely overflow. Since we know the source
type, we can easily choose 'int' as an appropriate return type. type, we can easily choose 'int' as an appropriate return type.
Likewise, we would have choosen 'float' if we had to sum a Likewise, we would have chosen 'float' if we had to sum a
sequence of floats. If we want to make this sequence of floats. If we want to make this
algorithm generic, we would like to derive the appropriate return algorithm generic, we would like to derive the appropriate return
type automatically. This can be done with NumericTraits. type automatically. This can be done with NumericTraits.
The code would look like this (we use \ref DataAccessors to The code would look like this (we use \ref DataAccessors to
read the data from the sequence): read the data from the sequence):
\code \code
// calculate the sum of any sequence // calculate the sum of any sequence
template <class Iterator, class Accessor> template <class Iterator, class Accessor>
typename vigra::NumericTraits<typename Accessor::value_type>::Promote typename vigra::NumericTraits<typename Accessor::value_type>::Promote
skipping to change at line 314 skipping to change at line 314
<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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<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;
} }
\endcode \endcode
This template is only applicable if both arguments have the same This template is only applicable if both arguments have the same
type. However, sometimes we may want to use the function in cases type. However, sometimes we may want to use the function in cases
where the argument types differ. The we can deduce the approrpiate where the argument types differ. Then we can deduce the appropriate
return type by using <TT>PromoteTraits</TT>: return type by using <TT>PromoteTraits</TT>:
\code \code
template <class T1, class T2> template <class T1, class T2>
typename vigra::PromoteTraits<T1, T2>::Promote typename vigra::PromoteTraits<T1, T2>::Promote
min(T1 t1, T2 t2) min(T1 t1, T2 t2)
{ {
return (t1 < t2) ? vigra::PromoteTraits<T1, T2>::toPromote(t1) : return (t1 < t2) ? vigra::PromoteTraits<T1, T2>::toPromote(t1) :
vigra::PromoteTraits<T1, T2>::toPromote(t2); vigra::PromoteTraits<T1, T2>::toPromote(t2);
} }
skipping to change at line 377 skipping to change at line 377
<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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<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
This approach avoids 'ambigouos overload errors' when taking the square root of This approach avoids 'ambiguous overload errors' when taking the square root of
an integer type. It also takes care of determining the proper result of the an integer type. It also takes care of determining the proper result of the
sqrt() function of \ref vigra::FixedPoint and of the norm() function, w hen sqrt() function of \ref vigra::FixedPoint and of the norm() function, w hen
it is implemented via sqrt(squaredNorm(x)). it is implemented via sqrt(squaredNorm(x)).
The following members are defined in <b> <TT>SquareRootTraits<Arithmeti cType></TT></b>: The following members are defined in <b> <TT>SquareRootTraits<Arithmeti cType></TT></b>:
<table> <table>
<tr><td> <tr><td>
<b> <TT>typedef ArithmeticType Type;</TT></b> <b> <TT>typedef ArithmeticType Type;</TT></b>
</td><td> </td><td>
the type itself the type itself
skipping to change at line 423 skipping to change at line 423
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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<vigra/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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<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 thats suppo rts 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
The following members are defined in <b> <TT>NormTraits<ArithmeticType> </TT></b>: The following members are defined in <b> <TT>NormTraits<ArithmeticType> </TT></b>:
<table> <table>
<tr><td> <tr><td>
skipping to change at line 466 skipping to change at line 466
</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>
\<<a href="numerictraits_8hxx-source.html">vigra/numerictraits.hxx</a>\ > \<vigra/numerictraits.hxx\>
Namespace: vigra Namespace: vigra
*/ */
namespace vigra { namespace vigra {
struct Error_NumericTraits_not_specialized_for_this_case { }; struct Error_NumericTraits_not_specialized_for_this_case { };
struct Error_NumericTraits_char_is_not_a_numeric_type__use_signed_char_or_u nsigned_char { }; struct Error_NumericTraits_char_is_not_a_numeric_type__use_signed_char_or_u nsigned_char { };
template<class A> template<class A>
 End of changes. 12 change blocks. 
12 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
#include <iostream>
#include <algorithm>
#include <complex>
#include <string>
#include <sstream>
#include <map>
#include <vigra/multi_array.hxx>
#include <vigra/array_vector.hxx>
#include <vigra/sized_int.hxx>
#include <vigra/python_utility.hxx>
#include <Python.h> #include <Python.h>
#include <string>
#include <iostream>
#include <numpy/arrayobject.h> #include <numpy/arrayobject.h>
#include "multi_array.hxx"
#include "array_vector.hxx"
#include "python_utility.hxx"
#include "numpy_array_traits.hxx"
#include "numpy_array_taggedshape.hxx"
int _import_array(); int _import_array();
namespace vigra { namespace vigra {
inline void import_vigranumpy()
{
if(_import_array() < 0)
pythonToCppException(0);
python_ptr module(PyImport_ImportModule("vigra.vigranumpycore"), python
_ptr::keep_count);
pythonToCppException(module);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* Singleband and Multiband */ /* MultibandVectorAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
typedef float NumpyValueType;
template <class T>
struct Singleband // the last array dimension is not to be interpreted as
a channel dimension
{
typedef T value_type;
};
template <class T>
struct Multiband // the last array dimension is a channel dimension
{
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));
}
*/
};
template <class T> template <class T>
class MultibandVectorAccessor class MultibandVectorAccessor
{ {
MultiArrayIndex size_, stride_; MultiArrayIndex size_, stride_;
public: public:
MultibandVectorAccessor(MultiArrayIndex size, MultiArrayIndex stride) MultibandVectorAccessor(MultiArrayIndex size, MultiArrayIndex stride)
: size_(size), : size_(size),
stride_(stride) stride_(stride)
{} {}
skipping to change at line 160 skipping to change at line 98
*/ */
template <class ITERATOR> template <class ITERATOR>
component_type const & getComponent(ITERATOR const & i, int idx) const component_type const & getComponent(ITERATOR const & i, int idx) const
{ {
return *(&*i+idx*stride_); return *(&*i+idx*stride_);
} }
/** Set the component data at given vector index /** Set the component data at given vector index
at given iterator position. The type <TT>V</TT> of the passed at given iterator position. The type <TT>V</TT> of the passed
in <TT>value</TT> is automatically converted to <TT>component_t ype</TT>. in <TT>value</TT> is automatically converted to <TT>component_t ype</TT>.
In case of a conversion floating point -> intergral this includ es 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 setComponent(V const & value, ITERATOR const & i, int idx) const void setComponent(V const & value, ITERATOR const & i, int idx) const
{ {
*(&*i+idx*stride_) = detail::RequiresExplicitCast<component_type>:: cast(value); *(&*i+idx*stride_) = detail::RequiresExplicitCast<component_type>:: cast(value);
} }
/** 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 DIFFERENCE>
component_type const & getComponent(ITERATOR const & i, DIFFERENCE cons t & diff, int idx) const component_type const & getComponent(ITERATOR const & i, DIFFERENCE cons t & diff, int idx) const
{ {
return *(&i[diff]+idx*stride_); return *(&i[diff]+idx*stride_);
} }
/** 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 -> intergral this includ es 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 DIFFERENCE>
void void
setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & di ff, int idx) const setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & di ff, int idx) const
{ {
*(&i[diff]+idx*stride_) = detail::RequiresExplicitCast<component_ty pe>::cast(value); *(&i[diff]+idx*stride_) = detail::RequiresExplicitCast<component_ty pe>::cast(value);
} }
template <class U> template <class U>
MultiArrayIndex size(U) const MultiArrayIndex size(U) const
{ {
return size_; return size_;
} }
}; };
/********************************************************/ /********************************************************/
/* */
/* a few Python utilities */
/* */
/********************************************************/
namespace detail {
inline long spatialDimensions(PyObject * obj)
{
static python_ptr key(PyString_FromString("spatialDimensions"), python_
ptr::keep_count);
python_ptr pres(PyObject_GetAttr(obj, key), python_ptr::keep_count);
long res = pres && PyInt_Check(pres)
? PyInt_AsLong(pres)
: -1;
return res;
}
/*
* The registry is used to optionally map specific C++ types to
* specific python sub-classes of numpy.ndarray (for example,
* MultiArray<2, Singleband<int> > to a user-defined Python class 'ScalarIm
age').
*
* One needs to use NUMPY_ARRAY_INITIALIZE_REGISTRY once in a python
* extension module using this technique, in order to actually provide
* the registry (this is done by vigranumpycmodule and will then be
* available for other modules, too). Alternatively,
* NUMPY_ARRAY_DUMMY_REGISTRY may be used to disable this feature
* completely. In both cases, the macro must not be enclosed by any
* namespace, so it is best put right at the beginning of the file
* (e.g. below the #includes).
*/
typedef std::map<std::string, std::pair<python_ptr, python_ptr> > ArrayType
Map;
VIGRA_EXPORT ArrayTypeMap * getArrayTypeMap();
#define NUMPY_ARRAY_INITIALIZE_REGISTRY \
namespace vigra { namespace detail { \
ArrayTypeMap * getArrayTypeMap() \
{ \
static ArrayTypeMap arrayTypeMap; \
return &arrayTypeMap; \
} \
}} // namespace vigra::detail
#define NUMPY_ARRAY_DUMMY_REGISTRY \
namespace vigra { namespace detail { \
ArrayTypeMap * getArrayTypeMap() \
{ \
return NULL; \
} \
}} // namespace vigra::detail
inline
void registerPythonArrayType(std::string const & name, PyObject * obj, PyOb
ject * typecheck)
{
ArrayTypeMap *types = getArrayTypeMap();
vigra_precondition(
types != NULL,
"registerPythonArrayType(): module was compiled without array type
registry.");
vigra_precondition(
obj && PyType_Check(obj) && PyType_IsSubtype((PyTypeObject *)obj, &
PyArray_Type),
"registerPythonArrayType(obj): obj is not a subtype of numpy.ndarra
y.");
if(typecheck && PyCallable_Check(typecheck))
(*types)[name] = std::make_pair(python_ptr(obj), python_ptr(typeche
ck));
else
(*types)[name] = std::make_pair(python_ptr(obj), python_ptr());
// std::cerr << "Registering " << ((PyTypeObject *)obj)->tp_name << " fo
r " << name << "\n";
}
inline
python_ptr getArrayTypeObject(std::string const & name, PyTypeObject * def
= 0)
{
ArrayTypeMap *types = getArrayTypeMap();
if(!types)
// dummy registry -> handle like empty registry
return python_ptr((PyObject *)def);
python_ptr res;
ArrayTypeMap::iterator i = types->find(name);
if(i != types->end())
res = i->second.first;
else
res = python_ptr((PyObject *)def);
// std::cerr << "Requested " << name << ", got " << ((PyTypeObject *)res
.get())->tp_name << "\n";
return res;
}
// there are two cases for the return:
// * if a typecheck function was registered, it is returned
// * a null pointer is returned if nothing was registered for either key, o
r if
// a type was registered without typecheck function
inline python_ptr
getArrayTypecheckFunction(std::string const & keyFull, std::string const &
key)
{
python_ptr res;
ArrayTypeMap *types = getArrayTypeMap();
if(types)
{
ArrayTypeMap::iterator i = types->find(keyFull);
if(i == types->end())
i = types->find(key);
if(i != types->end())
res = i->second.second;
}
return res;
}
inline bool
performCustomizedArrayTypecheck(PyObject * obj, std::string const & keyFull
, std::string const & key)
{
if(obj == 0 || !PyArray_Check(obj))
return false;
python_ptr typecheck = getArrayTypecheckFunction(keyFull, key);
if(typecheck == 0)
return true; // no custom test registered
python_ptr args(PyTuple_Pack(1, obj), python_ptr::keep_count);
pythonToCppException(args);
python_ptr res(PyObject_Call(typecheck.get(), args.get(), 0), python_pt
r::keep_count);
pythonToCppException(res);
vigra_precondition(PyBool_Check(res),
"NumpyArray conversion: registered typecheck function did not re
turn a boolean.");
return res.get() == Py_True;
}
inline
python_ptr constructNumpyArrayImpl(
PyTypeObject * type,
ArrayVector<npy_intp> const & shape, npy_intp *strides,
NPY_TYPES typeCode, bool init)
{
python_ptr array;
if(strides == 0)
{
array = python_ptr(PyArray_New(type, shape.size(), (npy_intp *)shap
e.begin(), typeCode, 0, 0, 0, 1 /* Fortran order */, 0),
python_ptr::keep_count);
}
else
{
int N = shape.size();
ArrayVector<npy_intp> pshape(N);
for(int k=0; k<N; ++k)
pshape[strides[k]] = shape[k];
array = python_ptr(PyArray_New(type, N, pshape.begin(), typeCode, 0
, 0, 0, 1 /* Fortran order */, 0),
python_ptr::keep_count);
pythonToCppException(array);
PyArray_Dims permute = { strides, N };
array = python_ptr(PyArray_Transpose((PyArrayObject*)array.get(), &
permute), python_ptr::keep_count);
}
pythonToCppException(array);
if(init)
PyArray_FILLWBYTE((PyArrayObject *)array.get(), 0);
return array;
}
// strideOrdering will be ignored unless order == "A"
// TODO: this function should receive some refactoring in order to make
// the rules clear from the code rather than from comments
inline python_ptr
constructNumpyArrayImpl(PyTypeObject * type, ArrayVector<npy_intp> const &
shape,
unsigned int spatialDimensions, unsigned int channel
s,
NPY_TYPES typeCode, std::string order, bool init,
ArrayVector<npy_intp> strideOrdering = ArrayVector<n
py_intp>())
{
// shape must have at least length spatialDimensions, but can also have
a channel dimension
vigra_precondition(shape.size() == spatialDimensions || shape.size() ==
spatialDimensions + 1,
"constructNumpyArray(type, shape, ...): shape has wrong length."
);
// if strideOrdering is given, it must have at least length spatialDime
nsions,
// but can also have a channel dimension
vigra_precondition(strideOrdering.size() == 0 || strideOrdering.size()
== spatialDimensions ||
strideOrdering.size() == spatialDimensions + 1,
"constructNumpyArray(type, ..., strideOrdering): strideOrdering
has wrong length.");
if(channels == 0) // if the requested number of channels is not given .
..
{
// ... deduce it
if(shape.size() == spatialDimensions)
channels = 1;
else
channels = shape.back();
}
else
{
// otherwise, if the shape object also contains a channel dimension
, they must be consistent
if(shape.size() > spatialDimensions)
vigra_precondition(channels == (unsigned int)shape[spatialDimen
sions],
"constructNumpyArray(type, ...): shape contradicts reque
sted number of channels.");
}
// if we have only one channel, no explicit channel dimension should be
in the shape
unsigned int shapeSize = channels == 1
? spatialDimensions
: spatialDimensions + 1;
// create the shape object with optional channel dimension
ArrayVector<npy_intp> pshape(shapeSize);
std::copy(shape.begin(), shape.begin()+std::min(shape.size(), pshape.si
ze()), pshape.begin());
if(shapeSize > spatialDimensions)
pshape[spatialDimensions] = channels;
// order "A" means "preserve order" when an array is copied, and
// defaults to "V" when a new array is created without explicit strideO
rdering
//
if(order == "A")
{
if(strideOrdering.size() == 0)
{
order = "V";
}
else if(strideOrdering.size() > shapeSize)
{
// make sure that strideOrdering length matches shape length
ArrayVector<npy_intp> pstride(strideOrdering.begin(), strideOrd
ering.begin()+shapeSize);
// adjust the ordering when the channel dimension has been drop
ped because channel == 1
if(strideOrdering[shapeSize] == 0)
for(unsigned int k=0; k<shapeSize; ++k)
pstride[k] -= 1;
pstride.swap(strideOrdering);
}
else if(strideOrdering.size() < shapeSize)
{
// make sure that strideOrdering length matches shape length
ArrayVector<npy_intp> pstride(shapeSize);
// adjust the ordering when the channel dimension has been drop
ped because channel == 1
for(unsigned int k=0; k<shapeSize-1; ++k)
pstride[k] = strideOrdering[k] + 1;
pstride[shapeSize-1] = 0;
pstride.swap(strideOrdering);
}
}
// create the appropriate strideOrdering objects for the other memory o
rders
// (when strideOrdering already contained data, it is ignored because o
rder != "A")
if(order == "C")
{
strideOrdering.resize(shapeSize);
for(unsigned int k=0; k<shapeSize; ++k)
strideOrdering[k] = shapeSize-1-k;
}
else if(order == "F" || (order == "V" && channels == 1))
{
strideOrdering.resize(shapeSize);
for(unsigned int k=0; k<shapeSize; ++k)
strideOrdering[k] = k;
}
else if(order == "V")
{
strideOrdering.resize(shapeSize);
for(unsigned int k=0; k<shapeSize-1; ++k)
strideOrdering[k] = k+1;
strideOrdering[shapeSize-1] = 0;
}
return constructNumpyArrayImpl(type, pshape, strideOrdering.begin(), ty
peCode, init);
}
inline
python_ptr constructNumpyArrayFromData(
PyTypeObject * type,
ArrayVector<npy_intp> const & shape, npy_intp *strides,
NPY_TYPES typeCode, void *data)
{
python_ptr array(PyArray_New(type, shape.size(), (npy_intp *)shape.begi
n(), typeCode, strides, data, 0, NPY_WRITEABLE, 0),
python_ptr::keep_count);
pythonToCppException(array);
return array;
}
} // namespace detail
/********************************************************/
/* */
/* NumpyArrayValuetypeTraits */
/* */
/********************************************************/
template<class ValueType>
struct ERROR_NumpyArrayValuetypeTraits_not_specialized_for_ { };
template<class ValueType>
struct NumpyArrayValuetypeTraits
{
static bool isValuetypeCompatible(PyArrayObject const * obj)
{
return ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueTy
pe>();
}
static ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType>
typeCode;
static std::string typeName()
{
return std::string("ERROR: NumpyArrayValuetypeTraits not specialize
d for this case");
}
static std::string typeNameImpex()
{
return std::string("ERROR: NumpyArrayValuetypeTraits not specialize
d for this case");
}
static PyObject * typeObject()
{
return (PyObject *)0;
}
};
template<class ValueType>
ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> NumpyArrayV
aluetypeTraits<ValueType>::typeCode;
#define VIGRA_NUMPY_VALUETYPE_TRAITS(type, typeID, numpyTypeName, impexType
Name) \
template <> \
struct NumpyArrayValuetypeTraits<type > \
{ \
static bool isValuetypeCompatible(PyArrayObject const * obj) /* obj mus
t not be NULL */ \
{ \
return PyArray_EquivTypenums(typeID, PyArray_DESCR((PyObject *)obj)
->type_num) && \
PyArray_ITEMSIZE((PyObject *)obj) == sizeof(type); \
} \
\
static NPY_TYPES const typeCode = typeID; \
\
static std::string typeName() \
{ \
return #numpyTypeName; \
} \
\
static std::string typeNameImpex() \
{ \
return impexTypeName; \
} \
\
static PyObject * typeObject() \
{ \
return PyArray_TypeObjectFromType(typeID); \
} \
};
VIGRA_NUMPY_VALUETYPE_TRAITS(bool, NPY_BOOL, bool, "UINT8")
VIGRA_NUMPY_VALUETYPE_TRAITS(signed char, NPY_INT8, int8, "INT16")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned char, NPY_UINT8, uint8, "UINT8")
VIGRA_NUMPY_VALUETYPE_TRAITS(short, NPY_INT16, int16, "INT16")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned short, NPY_UINT16, uint16, "UINT16")
#if VIGRA_BITSOF_LONG == 32
VIGRA_NUMPY_VALUETYPE_TRAITS(long, NPY_INT32, int32, "INT32")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long, NPY_UINT32, uint32, "UINT32")
#elif VIGRA_BITSOF_LONG == 64
VIGRA_NUMPY_VALUETYPE_TRAITS(long, NPY_INT64, int64, "DOUBLE")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long, NPY_UINT64, uint64, "DOUBLE")
#endif
#if VIGRA_BITSOF_INT == 32
VIGRA_NUMPY_VALUETYPE_TRAITS(int, NPY_INT32, int32, "INT32")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned int, NPY_UINT32, uint32, "UINT32")
#elif VIGRA_BITSOF_INT == 64
VIGRA_NUMPY_VALUETYPE_TRAITS(int, NPY_INT64, int64, "DOUBLE")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned int, NPY_UINT64, uint64, "DOUBLE")
#endif
#ifdef PY_LONG_LONG
# if VIGRA_BITSOF_LONG_LONG == 32
VIGRA_NUMPY_VALUETYPE_TRAITS(long long, NPY_INT32, int32, "INT32
")
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long long, NPY_UINT32, uint32, "UIN
T32")
# elif VIGRA_BITSOF_LONG_LONG == 64
VIGRA_NUMPY_VALUETYPE_TRAITS(long long, NPY_INT64, int64, "DOUBLE"
)
VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long long, NPY_UINT64, uint64, "DOUBL
E")
# endif
#endif
VIGRA_NUMPY_VALUETYPE_TRAITS(npy_float32, NPY_FLOAT32, float32, "FLOAT")
VIGRA_NUMPY_VALUETYPE_TRAITS(npy_float64, NPY_FLOAT64, float64, "DOUBLE")
VIGRA_NUMPY_VALUETYPE_TRAITS(npy_longdouble, NPY_LONGDOUBLE, longdouble, ""
)
VIGRA_NUMPY_VALUETYPE_TRAITS(npy_cfloat, NPY_CFLOAT, complex64, "")
VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_float>, NPY_CFLOAT, complex64
, "")
VIGRA_NUMPY_VALUETYPE_TRAITS(npy_cdouble, NPY_CDOUBLE, complex128, "")
VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_double>, NPY_CDOUBLE, complex
128, "")
VIGRA_NUMPY_VALUETYPE_TRAITS(npy_clongdouble, NPY_CLONGDOUBLE, clongdouble,
"")
VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_longdouble>, NPY_CLONGDOUBLE,
clongdouble, "")
#undef VIGRA_NUMPY_VALUETYPE_TRAITS
/********************************************************/
/* */
/* NumpyArrayTraits */
/* */
/********************************************************/
template <class U, int N>
bool stridesAreAscending(TinyVector<U, N> const & strides)
{
for(int k=1; k<N; ++k)
if(strides[k] < strides[k-1])
return false;
return true;
}
template<unsigned int N, class T, class Stride>
struct NumpyArrayTraits;
template<unsigned int N, class T>
struct NumpyArrayTraits<N, T, StridedArrayTag>
{
typedef T dtype;
typedef T value_type;
typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits;
static NPY_TYPES const typeCode = ValuetypeTraits::typeCode;
enum { spatialDimensions = N, channels = 1 };
static bool isArray(PyObject * obj)
{
return obj && PyArray_Check(obj);
}
static bool isClassCompatible(PyObject * obj)
{
return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(),
typeKey());
}
static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not
be NULL */
{
return ValuetypeTraits::isValuetypeCompatible(obj);
}
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return PyArray_NDIM((PyObject *)obj) == N-1 ||
PyArray_NDIM((PyObject *)obj) == N ||
(PyArray_NDIM((PyObject *)obj) == N+1 && PyArray_DIM((PyObje
ct *)obj, N) == 1);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b template <class TYPECODE> // pseudo-template to avoid inline expansion of t
e NULL */ he function
{ // will always be NPY_TYPES
return ValuetypeTraits::isValuetypeCompatible(obj) && PyObject *
isShapeCompatible(obj); constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init,
} python_ptr arraytype = python_ptr());
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N> npyStride(stride * sizeof(T));
return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey()
, shape, ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKey()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", *>";
return key;
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", " +
ValuetypeTraits::typeName() + ", StridedAr
rayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, T, UnstridedArrayTag>
: public NumpyArrayTraits<N, T, StridedArrayTag>
{
typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return BaseType::isShapeCompatible(obj) &&
PyArray_STRIDES((PyObject *)obj)[0] == PyArray_ITEMSIZE((PyO
bject *)obj);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return BaseType::isValuetypeCompatible(obj) &&
isShapeCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N> npyStride(stride * sizeof(T));
return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType:
:typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", " +
ValuetypeTraits::typeName() + ", Unstrided
ArrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, Singleband<T>, StridedArrayTag>
: public NumpyArrayTraits<N, T, StridedArrayTag>
{
typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isClassCompatible(PyObject * obj)
{
return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(),
typeKey());
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N> npyStride(stride * sizeof(T));
return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey()
, shape, ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKey()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", Singleband<*> >";
return key;
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", Singleband<" +
ValuetypeTraits::typeName() + ">, StridedA
rrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, Singleband<T>, UnstridedArrayTag>
: public NumpyArrayTraits<N, Singleband<T>, StridedArrayTag>
{
typedef NumpyArrayTraits<N, T, UnstridedArrayTag> UnstridedTraits;
typedef NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return UnstridedTraits::isShapeCompatible(obj);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return UnstridedTraits::isPropertyCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N> npyStride(stride * sizeof(T));
return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType:
:typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", Singleband<" +
ValuetypeTraits::typeName() + ">, Unstride
dArrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, Multiband<T>, StridedArrayTag>
: public NumpyArrayTraits<N, T, StridedArrayTag>
{
typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
enum { spatialDimensions = N-1, channels = 0 };
static bool isClassCompatible(PyObject * obj)
{
return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(),
typeKey());
}
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return PyArray_NDIM(obj) == N || PyArray_NDIM(obj) == N-1;
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return ValuetypeTraits::isValuetypeCompatible(obj) &&
isShapeCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N> npyStride(stride * sizeof(T));
return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey()
, shape, ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKey()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", Multiband<*> >";
return key;
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", Multiband<" +
ValuetypeTraits::typeName() + ">, StridedA
rrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, Multiband<T>, UnstridedArrayTag>
: public NumpyArrayTraits<N, Multiband<T>, StridedArrayTag>
{
typedef NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> BaseType;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return BaseType::isShapeCompatible(obj) &&
PyArray_STRIDES((PyObject *)obj)[0] == PyArray_ITEMSIZE((PyO
bject *)obj);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return BaseType::isValuetypeCompatible(obj) &&
isShapeCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N> npyStride(stride * sizeof(T));
return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType:
:typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", Multiband<" +
ValuetypeTraits::typeName() + ">, Unstride
dArrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, int M, class T>
struct NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag>
{
typedef T dtype;
typedef TinyVector<T, M> value_type;
typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits;
static NPY_TYPES const typeCode = ValuetypeTraits::typeCode;
enum { spatialDimensions = N, channels = M };
static bool isArray(PyObject * obj)
{
return obj && PyArray_Check(obj);
}
static bool isClassCompatible(PyObject * obj)
{
return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(),
typeKey());
}
static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not
be NULL */
{
return ValuetypeTraits::isValuetypeCompatible(obj);
}
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return PyArray_NDIM((PyObject *)obj) == N+1 &&
PyArray_DIM((PyObject *)obj, N) == M &&
PyArray_STRIDES((PyObject *)obj)[N] == PyArray_ITEMSIZE((PyO
bject *)obj);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return ValuetypeTraits::isValuetypeCompatible(obj) &&
isShapeCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N+1> npyShape;
std::copy(shape.begin(), shape.end(), npyShape.begin());
npyShape[N] = M;
TinyVector<npy_intp, N+1> npyStride;
std::transform(
stride.begin(), stride.end(), npyStride.begin(),
std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type)));
npyStride[N] = sizeof(T);
return detail::constructNumpyArrayFromData(
typeKeyFull(), typeKey(), npyShape,
ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKey()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", TinyVector<*, " + asString(M) + "> >";
return key;
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", TinyVector<" + ValuetypeTraits::typeName() + ", "
+ asString(M) + ">, StridedArrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, int M, class T>
struct NumpyArrayTraits<N, TinyVector<T, M>, UnstridedArrayTag>
: public NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag>
{
typedef NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> BaseType
;
typedef typename BaseType::value_type value_type;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return BaseType::isShapeCompatible(obj) &&
PyArray_STRIDES((PyObject *)obj)[0] == sizeof(TinyVector<T,
M>);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return BaseType::isValuetypeCompatible(obj) &&
isShapeCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N+1> npyShape;
std::copy(shape.begin(), shape.end(), npyShape.begin());
npyShape[N] = M;
TinyVector<npy_intp, N+1> npyStride;
std::transform(
stride.begin(), stride.end(), npyStride.begin(),
std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type)));
npyStride[N] = sizeof(T);
return detail::constructNumpyArrayFromData(
typeKeyFull(), BaseType::typeKey(), npyShape,
ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", TinyVector<" + ValuetypeTraits::typeName() + ", "
+ asString(M) + ">, UnstridedArrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag>
: public NumpyArrayTraits<N, TinyVector<T, 3>, StridedArrayTag>
{
typedef T dtype;
typedef RGBValue<T> value_type;
typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits;
static bool isClassCompatible(PyObject * obj)
{
return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(),
typeKey());
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N+1> npyShape;
std::copy(shape.begin(), shape.end(), npyShape.begin());
npyShape[N] = 3;
TinyVector<npy_intp, N+1> npyStride;
std::transform(
stride.begin(), stride.end(), npyStride.begin(),
std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type)));
npyStride[N] = sizeof(T);
return detail::constructNumpyArrayFromData(
typeKeyFull(), typeKey(), npyShape,
ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKey()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", RGBValue<*> >";
return key;
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", RGBValue<" + ValuetypeTraits::typeName() + ">, Str
idedArrayTag>";
return key;
}
};
/********************************************************/
template<unsigned int N, class T>
struct NumpyArrayTraits<N, RGBValue<T>, UnstridedArrayTag>
: public NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag>
{
typedef NumpyArrayTraits<N, TinyVector<T, 3>, UnstridedArrayTag> Unstri
dedTraits;
typedef NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag> BaseType;
typedef typename BaseType::value_type value_type;
typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be N
ULL */
{
return UnstridedTraits::isShapeCompatible(obj);
}
static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not b
e NULL */
{
return UnstridedTraits::isPropertyCompatible(obj);
}
template <class U>
static python_ptr constructor(TinyVector<U, N> const & shape,
T *data, TinyVector<U, N> const & stride)
{
TinyVector<npy_intp, N+1> npyShape;
std::copy(shape.begin(), shape.end(), npyShape.begin());
npyShape[N] = 3;
TinyVector<npy_intp, N+1> npyStride;
std::transform(
stride.begin(), stride.end(), npyStride.begin(),
std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type)));
npyStride[N] = sizeof(T);
return detail::constructNumpyArrayFromData(
typeKeyFull(), BaseType::typeKey(), npyShape,
ValuetypeTraits::typeCode, data, npyStride.begin());
}
static std::string typeKeyFull()
{
static std::string key = std::string("NumpyArray<") + asString(N) +
", RGBValue<" + ValuetypeTraits::typeName() + ">, Uns
tridedArrayTag>";
return key;
}
};
/********************************************************/ /********************************************************/
/* */ /* */
/* 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
as a smart pointer to these arrays, but some basic access and conversio n functions as a smart pointer to these arrays, but some basic access and conversio n functions
are also provided. are also provided.
<b>\#include</b> \<<a href="numpy__array_8hxx-source.html">vigra/numpy_ array.hxx</a>\><br> <b>\#include</b> \<vigra/numpy_array.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
class NumpyAnyArray class NumpyAnyArray
{ {
protected: protected:
python_ptr pyArray_; python_ptr pyArray_;
// We want to apply broadcasting to the channel dimension.
// Since only leading dimensions can be added during numpy
// broadcasting, we permute the array accordingly.
NumpyAnyArray permuteChannelsToFront() const
{
MultiArrayIndex M = ndim();
ArrayVector<npy_intp> permutation(M);
for(int k=0; k<M; ++k)
permutation[k] = M-1-k;
// explicit cast to int is neede here to avoid gcc c++0x compilatio
n
// error: narrowing conversion of ‘M’ from ‘vigra::MultiArrayIndex’
// to ‘int’ inside { }
// int overflow should not occur here because PyArray_NDIM returns
// an integer which is converted to long in NumpyAnyArray::ndim()
PyArray_Dims permute = { permutation.begin(), (int) M };
python_ptr array(PyArray_Transpose(pyArray(), &permute), python_ptr
::keep_count);
pythonToCppException(array);
return NumpyAnyArray(array.ptr());
}
public: public:
/// difference type /// difference type
typedef ArrayVector<npy_intp> difference_type; typedef ArrayVector<npy_intp> difference_type;
static python_ptr getArrayTypeObject()
{
return detail::getArrayTypeObject();
}
static std::string defaultOrder(std::string defaultValue = "C")
{
return detail::defaultOrder(defaultValue);
}
static python_ptr defaultAxistags(int ndim, std::string order = "")
{
return detail::defaultAxistags(ndim, order);
}
static python_ptr emptyAxistags(int ndim)
{
return detail::emptyAxistags(ndim);
}
/** /**
Construct from a Python object. If \a obj is NULL, or is not a sub class Construct from a Python object. If \a obj is NULL, or is not a sub class
of numpy.ndarray, the resulting NumpyAnyArray will have no data (i .e. of numpy.ndarray, the resulting NumpyAnyArray will have no data (i .e.
hasData() returns false). Otherwise, it creates a new reference to the array hasData() returns false). Otherwise, it creates a new reference to the array
\a obj, unless \a createCopy is true, where a new array is created by calling \a obj, unless \a createCopy is true, where a new array is created by calling
the C-equivalent of obj->copy(). the C-equivalent of obj->copy().
*/ */
explicit NumpyAnyArray(PyObject * obj = 0, bool createCopy = false, PyT ypeObject * type = 0) explicit NumpyAnyArray(PyObject * obj = 0, bool createCopy = false, PyT ypeObject * type = 0)
{ {
if(obj == 0) if(obj == 0)
skipping to change at line 1178 skipping to change at line 243
* dimension. * dimension.
* If the LHS is an empty view, assignment is identical to * If the LHS is an empty view, assignment is identical to
* makeReference(other.pyObject()). * makeReference(other.pyObject()).
*/ */
NumpyAnyArray & operator=(NumpyAnyArray const & other) NumpyAnyArray & operator=(NumpyAnyArray const & other)
{ {
if(hasData()) if(hasData())
{ {
vigra_precondition(other.hasData(), vigra_precondition(other.hasData(),
"NumpyArray::operator=(): Cannot assign from empty array.") ; "NumpyArray::operator=(): Cannot assign from empty array.") ;
if(PyArray_CopyInto(permuteChannelsToFront().pyArray(), other.p
ermuteChannelsToFront().pyArray()) == -1) python_ptr arraytype = getArrayTypeObject();
pythonToCppException(0); python_ptr f(PyString_FromString("_copyValuesImpl"), python_ptr
::keep_count);
if(PyObject_HasAttr(arraytype, f))
{
python_ptr res(PyObject_CallMethodObjArgs(arraytype, f.get(
),
pyArray_.get(), o
ther.pyArray_.get(), NULL),
python_ptr::keep_count);
vigra_postcondition(res.get() != 0,
"NumpyArray::operator=(): VigraArray._copyValuesImpl
() failed.");
}
else
{
PyArrayObject * sarray = (PyArrayObject *)pyArray_.get();
PyArrayObject * tarray = (PyArrayObject *)other.pyArray_.ge
t();
if(PyArray_CopyInto(tarray, sarray) == -1)
pythonToCppException(0);
}
} }
else else
{ {
pyArray_ = other.pyArray_; pyArray_ = other.pyArray_;
} }
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
skipping to change at line 1208 skipping to change at line 290
/** /**
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
{ {
if(!hasData()) if(!hasData())
return 0; return 0;
MultiArrayIndex s = detail::spatialDimensions(pyObject()); return pythonGetAttr(pyObject(), "spatialDimensions", ndim());
if(s == -1) }
s = ndim();
return s; bool hasChannelAxis() const
{
if(!hasData())
return false;
return channelIndex() == ndim();
}
MultiArrayIndex channelIndex() const
{
if(!hasData())
return 0;
return pythonGetAttr(pyObject(), "channelIndex", ndim());
}
MultiArrayIndex innerNonchannelIndex() const
{
if(!hasData())
return 0;
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(pyObject()), PyArray_DIMS(p yObject()) + ndim());
skipping to change at line 1258 skipping to change at line 358
std::swap(stride[k], stride[smallest]); std::swap(stride[k], stride[smallest]);
std::swap(permutation[k], permutation[smallest]); std::swap(permutation[k], permutation[smallest]);
} }
} }
difference_type ordering(N); difference_type ordering(N);
for(MultiArrayIndex k=0; k<N; ++k) for(MultiArrayIndex k=0; k<N; ++k)
ordering[permutation[k]] = k; ordering[permutation[k]] = k;
return ordering; return ordering;
} }
// /**
// Returns the the permutation that will transpose this array into
// canonical ordering (currently: F-order). The size of
// the returned permutation equals ndim().
// */
// difference_type permutationToNormalOrder() const
// {
// if(!hasData())
// return difference_type();
// // difference_type res(detail::getAxisPermutationImpl(pyArray_,
// // "permutationToNormalOr
der", true));
// difference_type res;
// detail::getAxisPermutationImpl(res, pyArray_, "permutationToNorm
alOrder", true);
// if(res.size() == 0)
// {
// res.resize(ndim());
// linearSequence(res.begin(), res.end(), ndim()-1, MultiArrayI
ndex(-1));
// }
// 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(pyObject())->type_num;
return -1; return -1;
} }
/** /**
* Return the AxisTags of this array or a NULL pointer when the att
ribute
'axistags' is missing in the Python object.
*/
python_ptr axistags() const
{
static python_ptr key(PyString_FromString("axistags"), python_ptr::
keep_count);
python_ptr axistags(PyObject_GetAttr(pyObject(), key), python_ptr::
keep_count);
if(!axistags)
PyErr_Clear();
return axistags;
}
/**
* Return a borrowed reference to the internal PyArrayObject. * Return a borrowed reference to the internal PyArrayObject.
*/ */
PyArrayObject * pyArray() const PyArrayObject * pyArray() const
{ {
return (PyArrayObject *)pyArray_.get(); return (PyArrayObject *)pyArray_.get();
} }
/** /**
* Return a borrowed reference to the internal PyArrayObject * Return a borrowed reference to the internal PyArrayObject
* (see pyArray()), cast to PyObject for your convenience. * (see pyArray()), cast to PyObject for your convenience.
skipping to change at line 1337 skipping to change at line 472
Check whether this NumpyAnyArray actually points to a Python arr ay. Check whether this NumpyAnyArray actually points to a Python arr ay.
*/ */
bool hasData() const bool hasData() const
{ {
return pyArray_ != 0; return pyArray_ != 0;
} }
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* constructArray */
/* */
/********************************************************/
namespace detail {
inline bool
nontrivialPermutation(ArrayVector<npy_intp> const & p)
{
for(unsigned int k=0; k<p.size(); ++k)
if(p[k] != k)
return true;
return false;
}
} // namespace detail
template <class TYPECODE> // pseudo-template to avoid inline expansion of t
he function
// will always be NPY_TYPES
PyObject *
constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init, pyth
on_ptr arraytype)
{
ArrayVector<npy_intp> shape = finalizeTaggedShape(tagged_shape);
PyAxisTags axistags(tagged_shape.axistags);
int ndim = (int)shape.size();
ArrayVector<npy_intp> inverse_permutation;
int order = 1; // Fortran order
if(axistags)
{
if(!arraytype)
arraytype = NumpyAnyArray::getArrayTypeObject();
inverse_permutation = axistags.permutationFromNormalOrder();
vigra_precondition(ndim == (int)inverse_permutation.size(),
"axistags.permutationFromNormalOrder(): permutation ha
s wrong size.");
}
else
{
arraytype = python_ptr((PyObject*)&PyArray_Type);
order = 0; // C order
}
// std::cerr << "constructArray: " << shape << "\n" << inverse_permutati
on << "\n";
python_ptr array(PyArray_New((PyTypeObject *)arraytype.get(), ndim, sha
pe.begin(),
typeCode, 0, 0, 0, order, 0),
python_ptr::keep_count);
pythonToCppException(array);
if(detail::nontrivialPermutation(inverse_permutation))
{
PyArray_Dims permute = { inverse_permutation.begin(), ndim };
array = python_ptr(PyArray_Transpose((PyArrayObject*)array.get(), &
permute),
python_ptr::keep_count);
pythonToCppException(array);
}
if(arraytype != (PyObject*)&PyArray_Type && axistags)
pythonToCppException(PyObject_SetAttrString(array, "axistags", axis
tags.axistags) != -1);
if(init)
PyArray_FILLWBYTE((PyArrayObject *)array.get(), 0);
return array.release();
}
// FIXME: reimplement in terms of TaggedShape?
template <class TINY_VECTOR>
inline
python_ptr constructNumpyArrayFromData(
TINY_VECTOR const & shape, npy_intp *strides,
NPY_TYPES typeCode, void *data)
{
ArrayVector<npy_intp> pyShape(shape.begin(), shape.end());
python_ptr array(PyArray_New(&PyArray_Type, shape.size(), pyShape.begin
(),
typeCode, strides, data, 0, NPY_WRITEABLE,
0),
python_ptr::keep_count);
pythonToCppException(array);
return array;
}
/********************************************************/
/* */
/* NumpyArray */ /* NumpyArray */
/* */ /* */
/********************************************************/ /********************************************************/
/** Provide the MultiArrayView interface for a Python array. /** Provide the MultiArrayView interface for a Python array.
This class inherits from both \ref vigra::MultiArrayView and \ref vigra ::NumpyAnyArray This class inherits from both \ref vigra::MultiArrayView and \ref vigra ::NumpyAnyArray
in order to support easy and save application of VIGRA functions to Pyt hon arrays. in order to support easy and save application of VIGRA functions to Pyt hon arrays.
<b>\#include</b> \<<a href="numpy__array_8hxx-source.html">vigra/numpy_ array.hxx</a>\><br> <b>\#include</b> \<vigra/numpy_array.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <unsigned int N, class T, class Stride = StridedArrayTag> template <unsigned int N, class T, class Stride = StridedArrayTag>
class NumpyArray class NumpyArray
: public MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_t ype, Stride>, : public MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_t ype, Stride>,
public NumpyAnyArray public NumpyAnyArray
{ {
public: public:
typedef NumpyArrayTraits<N, T, Stride> ArrayTraits; typedef NumpyArrayTraits<N, T, Stride> ArrayTraits;
typedef typename ArrayTraits::dtype dtype; typedef typename ArrayTraits::dtype dtype;
skipping to change at line 1399 skipping to change at line 621
typedef typename view_type::size_type size_type; typedef typename view_type::size_type size_type;
/** 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;
/** type of an array specifying an axis permutation
*/
typedef typename NumpyAnyArray::difference_type permutation_type;
/** traverser type /** traverser type
*/ */
typedef typename view_type::traverser traverser; typedef typename view_type::traverser traverser;
/** traverser type to const data /** traverser type to const data
*/ */
typedef typename view_type::const_traverser const_traverser; typedef typename view_type::const_traverser const_traverser;
/** sequential (random access) iterator type /** sequential (random access) iterator type
*/ */
skipping to change at line 1424 skipping to change at line 650
using view_type::shape; // resolve ambiguity of multiple inheritance using view_type::shape; // resolve ambiguity of multiple inheritance
using view_type::hasData; // resolve ambiguity of multiple inheritance using view_type::hasData; // resolve ambiguity of multiple inheritance
using view_type::strideOrdering; // resolve ambiguity of multiple inher itance using view_type::strideOrdering; // resolve ambiguity of multiple inher itance
protected: protected:
// this function assumes that pyArray_ has already been set, and compat ibility been checked // this function assumes that pyArray_ has already been set, and compat ibility been checked
void setupArrayView(); void setupArrayView();
static python_ptr getArrayTypeObject() static python_ptr init(difference_type const & shape, bool init = true,
{ std::string const & order = "")
python_ptr type = detail::getArrayTypeObject(ArrayTraits::typeKeyFu
ll());
if(type == 0)
type = detail::getArrayTypeObject(ArrayTraits::typeKey(), &PyAr
ray_Type);
return type;
}
static python_ptr init(difference_type const & shape, bool init = true)
{
ArrayVector<npy_intp> pshape(shape.begin(), shape.end());
return detail::constructNumpyArrayImpl((PyTypeObject *)getArrayType
Object().ptr(), pshape,
ArrayTraits::spatialDimensions, ArrayTraits::channel
s,
typeCode, "V", init);
}
static python_ptr init(difference_type const & shape, difference_type c
onst & strideOrdering, bool init = true)
{ {
ArrayVector<npy_intp> pshape(shape.begin(), shape.end()), vigra_precondition(order == "" || order == "C" || order == "F" ||
pstrideOrdering(strideOrdering.begin(), strid order == "V" || order == "A",
eOrdering.end()); "NumpyArray.init(): order must be in ['C', 'F', 'V', 'A', '']."
return detail::constructNumpyArrayImpl((PyTypeObject *)getArrayType );
Object().ptr(), pshape, return python_ptr(constructArray(ArrayTraits::taggedShape(shape, or
ArrayTraits::spatialDimensions, ArrayTraits::channel der), typeCode, init),
s, python_ptr::keep_count);
typeCode, "A", init, pstrideOrdering);
} }
public: public:
using view_type::init; using view_type::init;
/** /**
* Construct from a given PyObject pointer. When the given * Construct from a given PyObject pointer. When the given
* python object is NULL, the internal python array will be * python object is NULL, the internal python array will be
* NULL and hasData() will return false. * NULL and hasData() will return false.
* *
* Otherwise, the function attempts to create a * Otherwise, the function attempts to create a
* new reference to the given Python object, unless * new reference to the given Python object, unless
* copying is forced by setting \a createCopy to true. * copying is forced by setting \a createCopy to true.
* If either of this fails, the function throws an exception. * If either of this fails, the function throws an exception.
* This will not happen if isStrictlyCompatible(obj) (in case * This will not happen if isReferenceCompatible(obj) (in case
* of creating a new reference) or isCopyCompatible(obj) * of creating a new reference) or isCopyCompatible(obj)
* (in case of copying) have returned true beforehand. * (in case of copying) have returned true beforehand.
*/ */
explicit NumpyArray(PyObject *obj = 0, bool createCopy = false) explicit NumpyArray(PyObject *obj = 0, bool createCopy = false)
{ {
if(obj == 0) if(obj == 0)
return; return;
if(createCopy) if(createCopy)
makeCopy(obj); makeCopy(obj);
else else
skipping to change at line 1484 skipping to change at line 695
"NumpyArray(obj): Cannot construct from incompatible arra y."); "NumpyArray(obj): Cannot construct from incompatible arra y.");
} }
/** /**
* Copy constructor; does not copy the memory, but creates a * Copy constructor; does not copy the memory, but creates a
* new reference to the same underlying python object, unless * new reference to the same underlying python object, unless
* a copy is forced by setting \a createCopy to true. * a copy is forced by setting \a createCopy to true.
* (If the source object has no data, this one will have * (If the source object has no data, this one will have
* no data, too.) * no data, too.)
*/ */
NumpyArray(const NumpyArray &other, bool createCopy = false) : NumpyArray(const NumpyArray &other, bool createCopy = false)
MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::valu : view_type(),
e_type, Stride>(other), NumpyAnyArray()
NumpyAnyArray(other, createCopy)
{ {
if(!other.hasData()) if(!other.hasData())
return; return;
if(createCopy) if(createCopy)
makeCopy(other.pyObject()); makeCopy(other.pyObject());
else else
makeReferenceUnchecked(other.pyObject()); makeReferenceUnchecked(other.pyObject());
} }
/** /**
skipping to change at line 1510 skipping to change at line 721
{ {
if(!other.hasData()) if(!other.hasData())
return; return;
vigra_postcondition(makeReference(init(other.shape(), false)), vigra_postcondition(makeReference(init(other.shape(), false)),
"NumpyArray(view_type): Python constructor did not produc e a compatible array."); "NumpyArray(view_type): Python constructor did not produc e a compatible array.");
static_cast<view_type &>(*this) = other; static_cast<view_type &>(*this) = other;
} }
/** /**
* Construct a new array object, allocating an internal python * Construct a new array object, allocating an internal python
* ndarray of the given shape (in fortran order), initialized * ndarray of the given shape in the given order (default: VIGRA or der), initialized
* with zeros. * with zeros.
* *
* An exception is thrown when construction fails. * An exception is thrown when construction fails.
*/ */
explicit NumpyArray(difference_type const & shape) explicit NumpyArray(difference_type const & shape, std::string const & order = "")
{ {
vigra_postcondition(makeReference(init(shape)), vigra_postcondition(makeReference(init(shape, true, order)),
"NumpyArray(shape): Python constructor did not produce a compatible array."); "NumpyArray(shape): Python constructor did not produce a compatible array.");
} }
/** /**
* Construct a new array object, allocating an internal python * Construct a new array object, allocating an internal python
* ndarray of the given shape and given stride ordering, initialize * ndarray according to the given tagged shape, initialized with ze
d ros.
* with zeros.
* *
* An exception is thrown when construction fails. * An exception is thrown when construction fails.
*/ */
NumpyArray(difference_type const & shape, difference_type const & strid eOrdering) explicit NumpyArray(TaggedShape const & tagged_shape)
{ {
vigra_postcondition(makeReference(init(shape, strideOrdering)), reshapeIfEmpty(tagged_shape,
"NumpyArray(shape): Python constructor did not produce "NumpyArray(tagged_shape): Python constructor did not produce a
a compatible array."); compatible array.");
} }
/** /**
* Constructor from NumpyAnyArray. * Constructor from NumpyAnyArray.
* Equivalent to NumpyArray(other.pyObject()) * Equivalent to NumpyArray(other.pyObject())
*/ */
NumpyArray(const NumpyAnyArray &other, bool createCopy = false) explicit NumpyArray(const NumpyAnyArray &other, bool createCopy = false )
{ {
if(!other.hasData()) if(!other.hasData())
return; return;
if(createCopy) if(createCopy)
makeCopy(other.pyObject()); makeCopy(other.pyObject());
else else
vigra_precondition(makeReference(other.pyObject()), //, false), vigra_precondition(makeReference(other.pyObject()), //, false),
"NumpyArray(NumpyAnyArray): Cannot construct from incomp atible or empty array."); "NumpyArray(NumpyAnyArray): Cannot construct from incomp atible or empty array.");
} }
skipping to change at line 1569 skipping to change at line 779
if(hasData()) if(hasData())
view_type::operator=(other); view_type::operator=(other);
else else
makeReferenceUnchecked(other.pyObject()); makeReferenceUnchecked(other.pyObject());
return *this; return *this;
} }
/** /**
* Assignment operator. If this is already a view with data * Assignment operator. If this is already a view with data
* (i.e. hasData() is true) and the shapes match, the RHS * (i.e. hasData() is true) and the shapes match, the RHS
* array contents are copied. If this is an empty view,
* assignment is identical to makeReferenceUnchecked(other.pyObject
()).
* See MultiArrayView::operator= for further information on
* semantics.
*/
template <class U, class S>
NumpyArray &operator=(const NumpyArray<N, U, S> &other)
{
if(hasData())
{
vigra_precondition(shape() == other.shape(),
"NumpyArray::operator=(): shape mismatch.");
view_type::operator=(other);
}
else if(other.hasData())
{
NumpyArray copy;
copy.reshapeIfEmpty(other.taggedShape(),
"NumpyArray::operator=(): reshape failed unexpectedly.");
copy = other;
makeReferenceUnchecked(copy.pyObject());
}
return *this;
}
/**
* Assignment operator. If this is already a view with data
* (i.e. hasData() is true) and the shapes match, the RHS
* array contents are copied. * array contents are copied.
* If this is an empty view, assignment is identical to * If this is an empty view, assignment is identical to
* makeReference(other.pyObject()). * makeReference(other.pyObject()).
* Otherwise, an exception is thrown. * Otherwise, an exception is thrown.
*/ */
NumpyArray &operator=(const NumpyAnyArray &other) NumpyArray &operator=(const NumpyAnyArray &other)
{ {
if(hasData()) if(hasData())
{ {
NumpyAnyArray::operator=(other); NumpyAnyArray::operator=(other);
} }
else if(isStrictlyCompatible(other.pyObject())) else if(isReferenceCompatible(other.pyObject()))
{ {
makeReferenceUnchecked(other.pyObject()); makeReferenceUnchecked(other.pyObject());
} }
else else
{ {
vigra_precondition(false, vigra_precondition(false,
"NumpyArray::operator=(): Cannot assign from incompatible a rray."); "NumpyArray::operator=(): Cannot assign from incompatible a rray.");
} }
return *this; return *this;
} }
/** /**
Permute the entries of the given array \a data exactly like the ax
es of this NumpyArray
were permuted upon conversion from numpy.
*/
template<class U>
ArrayVector<U>
permuteLikewise(ArrayVector<U> const & data) const
{
vigra_precondition(hasData(),
"NumpyArray::permuteLikewise(): array has no data.");
ArrayVector<U> res(data.size());
ArrayTraits::permuteLikewise(this->pyArray_, data, res);
return res;
}
/**
Permute the entries of the given array \a data exactly like the ax
es of this NumpyArray
were permuted upon conversion from numpy.
*/
template<class U, int K>
TinyVector<U, K>
permuteLikewise(TinyVector<U, K> const & data) const
{
vigra_precondition(hasData(),
"NumpyArray::permuteLikewise(): array has no data.");
TinyVector<U, K> res;
ArrayTraits::permuteLikewise(this->pyArray_, data, res);
return res;
}
/**
* Test whether a given python object is a numpy array that can be * Test whether a given python object is a numpy array that can be
* converted (copied) into an array compatible to this NumpyArray t ype. * converted (copied) into an array compatible to this NumpyArray t ype.
* This means that the array's shape conforms to the requirements o f * This means that the array's shape conforms to the requirements o f
* makeCopy(). * makeCopy().
*/ */
static bool isCopyCompatible(PyObject *obj) static bool isCopyCompatible(PyObject *obj)
{ {
#if VIGRA_CONVERTER_DEBUG
std::cerr << "class " << typeid(NumpyArray).name() << " got " << ob
j->ob_type->tp_name << "\n";
std::cerr << "using traits " << typeid(ArrayTraits).name() << "\n";
std::cerr<<"isArray: "<< ArrayTraits::isArray(obj)<<std::endl;
std::cerr<<"isShapeCompatible: "<< ArrayTraits::isShapeCompatible((
PyArrayObject *)obj)<<std::endl;
#endif
return ArrayTraits::isArray(obj) && return ArrayTraits::isArray(obj) &&
ArrayTraits::isShapeCompatible((PyArrayObject *)obj); ArrayTraits::isShapeCompatible((PyArrayObject *)obj);
} }
/** /**
* Test whether a given python object is a numpy array with a * Test whether a given python object is a numpy array with a
* compatible dtype and the correct shape and strides, so that it * compatible dtype and the correct shape and strides, so that it
* can be referenced as a view by this NumpyArray type (i.e. * can be referenced as a view by this NumpyArray type (i.e.
* it conforms to the requirements of makeReference()). * it conforms to the requirements of makeReference()).
*/ */
static bool isReferenceCompatible(PyObject *obj) static bool isReferenceCompatible(PyObject *obj)
{ {
return ArrayTraits::isArray(obj) && return ArrayTraits::isArray(obj) &&
ArrayTraits::isPropertyCompatible((PyArrayObject *)obj); ArrayTraits::isPropertyCompatible((PyArrayObject *)obj);
} }
/** /**
* Like isReferenceCompatible(obj), but also executes a customized * Deprecated, use isReferenceCompatible(obj) instead.
type compatibility
* check when such a check has been registered for this class via
* registerPythonArrayType().
*
* This facilitates proper overload resolution between
* NumpyArray<3, Multiband<T> > (a multiband image) and NumpyArray<
3, Singleband<T> > (a scalar volume).
*/ */
static bool isStrictlyCompatible(PyObject *obj) static bool isStrictlyCompatible(PyObject *obj)
{ {
#if VIGRA_CONVERTER_DEBUG return isReferenceCompatible(obj);
std::cerr << "class " << typeid(NumpyArray).name() << " got " << ob
j->ob_type->tp_name << "\n";
bool isClassCompatible=ArrayTraits::isClassCompatible(obj);
bool isPropertyCompatible((PyArrayObject *)obj);
std::cerr<<"isClassCompatible: "<<isClassCompatible<<std::endl;
std::cerr<<"isPropertyCompatible: "<<isPropertyCompatible<<std::end
l;
#endif
return ArrayTraits::isClassCompatible(obj) &&
ArrayTraits::isPropertyCompatible((PyArrayObject *)obj);
} }
/** /**
* Create a vector representing the standard stride ordering of a N umpyArray. * Create a vector representing the standard stride ordering of a N umpyArray.
* That is, we get a vector representing the range [0,...,N-1], whi ch * That is, we get a vector representing the range [0,...,N-1], whi ch
* denotes the stride ordering for Fortran order. * denotes the stride ordering for Fortran order.
*/ */
static difference_type standardStrideOrdering() static difference_type standardStrideOrdering()
{ {
difference_type strideOrdering; difference_type strideOrdering;
skipping to change at line 1664 skipping to change at line 928
*/ */
void makeReferenceUnchecked(PyObject *obj) void makeReferenceUnchecked(PyObject *obj)
{ {
NumpyAnyArray::makeReference(obj); NumpyAnyArray::makeReference(obj);
setupArrayView(); setupArrayView();
} }
/** /**
* Try to set up a view referencing the given PyObject. * Try to set up a view referencing the given PyObject.
* Returns false if the python object is not a compatible * Returns false if the python object is not a compatible
* numpy array (see isReferenceCompatible() or * numpy array (see isReferenceCompatible()).
* isStrictlyCompatible(), according to the parameter \a *
* strict). * The parameter \a strict is deprecated and will be ignored
*/ */
bool makeReference(PyObject *obj, bool strict = true) bool makeReference(PyObject *obj, bool strict = false)
{ {
if(strict) if(!isReferenceCompatible(obj))
{ return false;
if(!isStrictlyCompatible(obj))
return false;
}
else
{
if(!isReferenceCompatible(obj))
return false;
}
makeReferenceUnchecked(obj); makeReferenceUnchecked(obj);
return true; return true;
} }
/** /**
* Try to set up a view referencing the same data as the given * Try to set up a view referencing the same data as the given
* NumpyAnyArray. This overloaded variant simply calls * NumpyAnyArray. This overloaded variant simply calls
* makeReference() on array.pyObject(). * makeReference() on array.pyObject(). The parameter \a strict
* is deprecated and will be ignored.
*/ */
bool makeReference(const NumpyAnyArray &array, bool strict = true) bool makeReference(const NumpyAnyArray &array, bool strict = false)
{ {
return makeReference(array.pyObject(), strict); return makeReference(array.pyObject(), strict);
} }
/** /**
* Set up an unsafe reference to the given MultiArrayView. * Set up an unsafe reference to the given MultiArrayView.
* ATTENTION: This creates a numpy.ndarray that points to the * ATTENTION: This creates a numpy.ndarray that points to the
* same data, but does not own it, so it must be ensured by * same data, but does not own it, so it must be ensured by
* other means that the memory does not get freed before the * other means that the memory does not get freed before the
* end of the ndarray's lifetime! (One elegant way would be * end of the ndarray's lifetime! (One elegant way would be
* to set the 'base' attribute of the resulting ndarray to a * to set the 'base' attribute of the resulting ndarray to a
* python object which directly or indirectly holds the memory * python object which directly or indirectly holds the memory
* of the given MultiArrayView.) * of the given MultiArrayView.)
*/ */
void makeReference(const view_type &multiArrayView) void makeUnsafeReference(const view_type &multiArrayView)
{ {
vigra_precondition(!hasData(), "makeReference(): cannot replace exi vigra_precondition(!hasData(),
sting view with given buffer"); "makeUnsafeReference(): cannot replace existing view with given
buffer");
// construct an ndarray that points to our data (taking strides int o account): // construct an ndarray that points to our data (taking strides int o account):
python_ptr array(ArrayTraits::constructor(multiArrayView.shape(), m python_ptr array(ArrayTraits::unsafeConstructorFromData(multiArrayV
ultiArrayView.data(), multiArrayView.stride())); iew.shape(),
multiArrayView.data(), multiArrayView.str
ide()));
view_type::operator=(multiArrayView); view_type::operator=(multiArrayView);
pyArray_ = array; pyArray_ = array;
} }
/** /**
Try to create a copy of the given PyObject. Try to create a copy of the given PyObject.
Raises an exception when obj is not a compatible array Raises an exception when obj is not a compatible array
(see isCopyCompatible() or isStrictlyCompatible(), according to th e (see isCopyCompatible() or isReferenceCompatible(), according to t he
parameter \a strict) or the Python constructor call failed. parameter \a strict) or the Python constructor call failed.
*/ */
void makeCopy(PyObject *obj, bool strict = false) void makeCopy(PyObject *obj, bool strict = false)
{ {
vigra_precondition(strict ? isStrictlyCompatible(obj) : isCopyCompa #if VIGRA_CONVERTER_DEBUG
tible(obj), int ndim = PyArray_NDIM((PyArrayObject *)obj);
npy_intp * s = PyArray_DIMS((PyArrayObject *)obj);
std::cerr << "makeCopy: " << ndim << " " << ArrayVectorView<npy_in
tp>(ndim, s) <<
", strides " << ArrayVectorView<npy_intp>(ndim, PyArra
y_STRIDES((PyArrayObject *)obj)) << "\n";
std::cerr << "for " << typeid(*this).name() << "\n";
#endif
vigra_precondition(strict ? isReferenceCompatible(obj) : isCopyComp
atible(obj),
"NumpyArray::makeCopy(obj): Cannot copy an incompatibl e array."); "NumpyArray::makeCopy(obj): Cannot copy an incompatibl e array.");
int M = PyArray_NDIM(obj); NumpyAnyArray copy(obj, true);
TinyVector<npy_intp, N> shape; makeReferenceUnchecked(copy.pyObject());
std::copy(PyArray_DIMS(obj), PyArray_DIMS(obj)+M, shape.begin());
if(M == N-1)
shape[M] = 1;
vigra_postcondition(makeReference(init(shape, false)),
"NumpyArray::makeCopy(obj): Copy created an incompatib
le array.");
NumpyAnyArray::operator=(NumpyAnyArray(obj));
// if(PyArray_CopyInto(pyArray(), (PyArrayObject*)obj) == -1)
// pythonToCppException(0);
} }
/** /**
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>
If a stride ordering is given, the resulting array will have th is stride If a stride ordering is given, the resulting array will have th is stride
ordering, when it is compatible with the array's memory layout (unstrided ordering, when it is compatible with the array's memory layout (unstrided
arrays only permit the standard ascending stride ordering). arrays only permit the standard ascending stride ordering).
<em>Note:</em> this operation invalidates dependent objects <em>Note:</em> this operation invalidates dependent objects
(MultiArrayViews and iterators) (MultiArrayViews and iterators)
*/ */
void reshape(difference_type const & shape, difference_type const & str ideOrdering = standardStrideOrdering()) void reshape(difference_type const & shape)
{ {
vigra_postcondition(makeReference(init(shape, strideOrdering)), vigra_postcondition(makeReference(init(shape)),
"NumpyArray(shape): Python constructor did not produce "NumpyArray.reshape(shape): Python constructor did not prod
a compatible array."); uce a compatible array.");
} }
/** /**
When this array has no data, allocate new memory with the given \a shape and When this array has no data, allocate new memory with the given \a shape and
initialize with zeros. Otherwise, check if the new shape matche s the old shape initialize with zeros. Otherwise, check if the new shape matche s the old shape
and throw a precondition exception with the given \a message if not. and throw a precondition exception with the given \a message if not.
*/ */
void reshapeIfEmpty(difference_type const & shape, std::string message = "") void reshapeIfEmpty(difference_type const & shape, std::string message = "")
{ {
reshapeIfEmpty(shape, standardStrideOrdering(), message); // FIXME: is this really a good replacement?
// reshapeIfEmpty(shape, standardStrideOrdering(), message);
reshapeIfEmpty(TaggedShape(shape), message);
} }
/** /**
When this array has no data, allocate new memory with the given \a shape and When this array has no data, allocate new memory with the given \a shape and
initialize with zeros. Otherwise, check if the new shape matche s the old shape initialize with zeros. Otherwise, check if the new shape matche s the old shape
and throw a precondition exception with the given \a message if and throw a precondition exception with the given \a message if
not. If strict not.
is true, the given stride ordering must also match that of the
existing data.
*/ */
void reshapeIfEmpty(difference_type const & shape, difference_type cons void reshapeIfEmpty(TaggedShape tagged_shape, std::string message = "")
t & strideOrdering,
std::string message = "", bool strict = false)
{ {
ArrayTraits::finalizeTaggedShape(tagged_shape);
if(hasData()) if(hasData())
{ {
if(strict) vigra_precondition(tagged_shape.compatible(taggedShape()), mess
{ age.c_str());
if(message == "")
message = "NumpyArray::reshapeIfEmpty(shape): array was
not empty, and shape or stride ordering did not match.";
vigra_precondition(shape == this->shape() && strideOrdering
== this->strideOrdering(), message.c_str());
}
else
{
if(message == "")
message = "NumpyArray::reshapeIfEmpty(shape): array was
not empty, and shape did not match.";
vigra_precondition(shape == this->shape(), message.c_str())
;
}
} }
else else
{ {
reshape(shape, strideOrdering); python_ptr array(constructArray(tagged_shape, typeCode, true),
python_ptr::keep_count);
vigra_postcondition(makeReference(NumpyAnyArray(array.get())),
"NumpyArray.reshapeIfEmpty(): Python constructor did not
produce a compatible array.");
} }
} }
TaggedShape taggedShape() const
{
return ArrayTraits::taggedShape(this->shape(), PyAxisTags(this->axi
stags(), true));
}
}; };
// this function assumes that pyArray_ has already been set, and compat ibility been checked // this function assumes that pyArray_ has already been set, and compat ibility been checked
template <unsigned int N, class T, class Stride> template <unsigned int N, class T, class Stride>
void NumpyArray<N, T, Stride>::setupArrayView() void NumpyArray<N, T, Stride>::setupArrayView()
{ {
if(NumpyAnyArray::hasData()) if(NumpyAnyArray::hasData())
{ {
unsigned int dimension = std::min<unsigned int>(actual_dimension, p permutation_type permute;
yArray()->nd); ArrayTraits::permutationToSetupOrder(this->pyArray_, permute);
std::copy(pyArray()->dimensions, pyArray()->dimensions + dimension,
this->m_shape.begin()); vigra_precondition(abs((int)permute.size() - actual_dimension) <= 1
std::copy(pyArray()->strides, pyArray()->strides + dimension, this- ,
>m_stride.begin()); "NumpyArray::setupArrayView(): got array of incompatible shape
if(pyArray()->nd < actual_dimension) (should never happen).");
applyPermutation(permute.begin(), permute.end(),
pyArray()->dimensions, this->m_shape.begin());
applyPermutation(permute.begin(), permute.end(),
pyArray()->strides, this->m_stride.begin());
if((int)permute.size() == actual_dimension - 1)
{ {
this->m_shape[dimension] = 1; this->m_shape[actual_dimension-1] = 1;
this->m_stride[dimension] = 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);
vigra_precondition(checkInnerStride(Stride()),
"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;
} }
} }
typedef NumpyArray<2, float > NumpyFArray2; typedef NumpyArray<2, float > NumpyFArray2;
typedef NumpyArray<3, float > NumpyFArray3; typedef NumpyArray<3, float > NumpyFArray3;
typedef NumpyArray<4, float > NumpyFArray4; typedef NumpyArray<4, float > NumpyFArray4;
typedef NumpyArray<2, Singleband<float> > NumpyFImage; typedef NumpyArray<2, Singleband<float> > NumpyFImage;
typedef NumpyArray<3, Singleband<float> > NumpyFVolume; typedef NumpyArray<3, Singleband<float> > NumpyFVolume;
typedef NumpyArray<2, RGBValue<float> > NumpyFRGBImage; typedef NumpyArray<2, RGBValue<float> > NumpyFRGBImage;
typedef NumpyArray<3, RGBValue<float> > NumpyFRGBVolume; typedef NumpyArray<3, RGBValue<float> > NumpyFRGBVolume;
typedef NumpyArray<3, Multiband<float> > NumpyFMultibandImage; typedef NumpyArray<3, Multiband<float> > NumpyFMultibandImage;
typedef NumpyArray<4, Multiband<float> > NumpyFMultibandVolume; typedef NumpyArray<4, Multiband<float> > NumpyFMultibandVolume;
inline void import_vigranumpy()
{
if(_import_array() < 0)
pythonToCppException(0);
python_ptr module(PyImport_ImportModule("vigra.vigranumpycore"), python
_ptr::keep_count);
pythonToCppException(module);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* NumpyArray Multiband Argument Object Factories */ /* NumpyArray Multiband Argument Object Factories */
/* */ /* */
/********************************************************/ /********************************************************/
template <class PixelType, class Stride> template <class PixelType, class Stride>
inline triple<ConstStridedImageIterator<PixelType>, inline triple<ConstStridedImageIterator<PixelType>,
ConstStridedImageIterator<PixelType>, ConstStridedImageIterator<PixelType>,
MultibandVectorAccessor<PixelType> > MultibandVectorAccessor<PixelType> >
 End of changes. 62 change blocks. 
1255 lines changed or deleted 409 lines changed or added


 numpy_array_converters.hxx   numpy_array_converters.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_CONVERTERS_HXX #ifndef VIGRA_NUMPY_ARRAY_CONVERTERS_HXX
#define VIGRA_NUMPY_ARRAY_CONVERTERS_HXX #define VIGRA_NUMPY_ARRAY_CONVERTERS_HXX
#include <vigra/numpy_array.hxx> #include "numpy_array.hxx"
#include <vigra/metaprogramming.hxx> #include "metaprogramming.hxx"
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/to_python_converter.hpp> #include <boost/python/to_python_converter.hpp>
#include <set> #include <set>
namespace vigra { namespace vigra {
template <class Array> template <class Array>
PyObject * returnNumpyArray(Array const & a) PyObject * returnNumpyArray(Array const & a)
{ {
PyObject * pa = a.pyObject(); PyObject * pa = a.pyObject();
skipping to change at line 89 skipping to change at line 89
{ {
return returnNumpyArray(a); return returnNumpyArray(a);
} }
}; };
template <unsigned int N, class T, class Stride> template <unsigned int N, class T, class Stride>
NumpyArrayConverter<NumpyArray<N, T, Stride> >::NumpyArrayConverter() NumpyArrayConverter<NumpyArray<N, T, Stride> >::NumpyArrayConverter()
{ {
using namespace boost::python; using namespace boost::python;
if(exportedArrayKeys().find(ArrayTraits::typeKeyFull()) == exportedArra converter::registration const * reg = converter::registry::query(type_i
yKeys().end()) d<ArrayType>());
{
exportedArrayKeys().insert(ArrayTraits::typeKey());
exportedArrayKeys().insert(ArrayTraits::typeKeyFull());
// register the to_python_converter only once
// FIXME: I'm not sure if this is correct.
if(!reg || !reg->rvalue_chain)
{
to_python_converter<ArrayType, NumpyArrayConverter>(); to_python_converter<ArrayType, NumpyArrayConverter>();
converter::registry::insert(&convertible, &construct, type_id<Array
Type>());
} }
converter::registry::insert(&convertible, &construct, type_id<ArrayType >());
} }
template <unsigned int N, class T, class Stride> template <unsigned int N, class T, class Stride>
void * NumpyArrayConverter<NumpyArray<N, T, Stride> >::convertible(PyObject * obj) void * NumpyArrayConverter<NumpyArray<N, T, Stride> >::convertible(PyObject * obj)
{ {
return obj == Py_None || ArrayType::isStrictlyCompatible(obj) bool isCompatible = obj == Py_None || ArrayType::isStrictlyCompatible(o
bj);
// std::cerr << "compatible for " << typeid(NumpyArray<N, T, Stride>).n
ame() << ": " << isCompatible << "\n";
return isCompatible
? obj ? obj
: 0; : 0;
} }
// from Python // from Python
template <unsigned int N, class T, class Stride> template <unsigned int N, class T, class Stride>
void NumpyArrayConverter<NumpyArray<N, T, Stride> >::construct(PyObject* ob j, void NumpyArrayConverter<NumpyArray<N, T, Stride> >::construct(PyObject* ob j,
boost::python::converter::rvalue_from_python_stage1_data * data) boost::python::converter::rvalue_from_python_stage1_data * data)
{ {
void* const storage = void* const storage =
skipping to change at line 241 skipping to change at line 243
boost::python::TypeList<void, void> > > > > > > > > > > \ 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
// overload, so that it shows up only once
template <class Head, class Tail> template <class Head, class Tail>
inline void multidef(char const* functor_name, TypeList<Head, Tail>) inline void multidef(char const* functor_name, TypeList<Head, Tail>)
{ {
Head::def(functor_name); Head::def(functor_name);
multidef(functor_name, Tail()); multidef(functor_name, Tail());
} }
template <class Head, class Tail> template <class Head, class Tail>
inline void multidef(char const* functor_name, TypeList<Head, Tail>, const char * help) inline void multidef(char const* functor_name, TypeList<Head, Tail>, const char * help)
{ {
Head::def(functor_name, help); Head::def(functor_name);
multidef(functor_name, Tail()); multidef(functor_name, Tail(), help);
} }
template <class Head, class Tail, class Args> template <class Head, class Tail, class Args>
inline void multidef(char const* functor_name, TypeList<Head, Tail>, Args c onst& args) inline void multidef(char const* functor_name, TypeList<Head, Tail>, Args c onst& args)
{ {
Head::def(functor_name, args); Head::def(functor_name, args);
multidef(functor_name, Tail(), args); multidef(functor_name, Tail(), args);
} }
template <class Head, class Tail, class Args> template <class Head, class Tail, class Args>
inline void multidef(char const* functor_name, TypeList<Head, Tail>, Args c onst& args, char const * help) inline void multidef(char const* functor_name, TypeList<Head, Tail>, Args c onst& args, char const * help)
{ {
Head::def(functor_name, args, help); Head::def(functor_name, args);
multidef(functor_name, Tail(), args); multidef(functor_name, Tail(), args, help);
} }
template <class Head, class Tail> template <class Head, class Tail>
inline void multidef(char const* functor_name, TypeList<Head, TypeList<void , Tail> >) inline void multidef(char const* functor_name, TypeList<Head, TypeList<void , Tail> >)
{ {
Head::def(functor_name); Head::def(functor_name);
} }
template <class Head, class Tail, class Args> template <class Head, class Tail, class Args>
inline void multidef(char const* functor_name, TypeList<Head, TypeList<void , Tail> >, Args const& args) inline void multidef(char const* functor_name, TypeList<Head, TypeList<void , Tail> >, Args const& args)
 End of changes. 9 change blocks. 
15 lines changed or deleted 20 lines changed or added


 orientedtensorfilters.hxx   orientedtensorfilters.hxx 
skipping to change at line 68 skipping to change at line 68
This function implements anisotropic tensor smoothing by an This function implements anisotropic tensor smoothing by an
hourglass-shaped filters as described in hourglass-shaped filters as described in
U. K&ouml;the: <a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe /papers/index.php#cite_structureTensor"> U. K&ouml;the: <a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe /papers/index.php#cite_structureTensor">
<i>"Edge and Junction Detection with an Improved Structure Tensor"</i>< /a>, <i>"Edge and Junction Detection with an Improved Structure Tensor"</i>< /a>,
in: Proc. of 25th DAGM Symposium, Magdeburg 2003, Lecture Notes in Com puter Science 2781, in: Proc. of 25th DAGM Symposium, Magdeburg 2003, Lecture Notes in Com puter Science 2781,
pp. 25-32, Heidelberg: Springer, 2003 pp. 25-32, Heidelberg: Springer, 2003
It is closely related to the structure tensor (see \ref structureTensor ()), but It is closely related to the structure tensor (see \ref structureTensor ()), but
replaces the linear tensor smoothing with a smoothing along edges only. replaces the linear tensor smoothing with a smoothing along edges only.
Smoothing accross edges is largely suppressed. This means that the Smoothing across edges is largely suppressed. This means that the
image structure is preserved much better because nearby features image structure is preserved much better because nearby features
such as parallel edges are not blended into each other. such as parallel edges are not blended into each other.
The hourglass filter is typically applied to a gradient tensor, i.e. th e The hourglass filter is typically applied to a gradient tensor, i.e. th e
Euclidean product of the gradient with itself, which can be obtained by a Euclidean product of the gradient with itself, which can be obtained by a
gradient operator followed with \ref vectorToTensor(), see example belo w. gradient operator followed with \ref vectorToTensor(), see example belo w.
The hourglass shape of the filter can be interpreted as indicating the likely The hourglass shape of the filter can be interpreted as indicating the likely
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
skipping to change at line 111 skipping to change at line 111
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="orientedtensorfilters_8hxx-source.html">vig ra/orientedtensorfilters.hxx</a>\> <b>\#include</b> \<vigra/orientedtensorfilters.hxx\>
\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
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 pixelneighborhood.hxx   pixelneighborhood.hxx 
skipping to change at line 47 skipping to change at line 47
#define VIGRA_PIXELNEIGHBORHOOD_HXX #define VIGRA_PIXELNEIGHBORHOOD_HXX
#include "utilities.hxx" #include "utilities.hxx"
namespace vigra { namespace vigra {
/** \addtogroup PixelNeighborhood Utilities to manage pixel neighborhoods /** \addtogroup PixelNeighborhood Utilities to manage pixel neighborhoods
4- and 8-neighborhood definitions and circulators. 4- and 8-neighborhood definitions and circulators.
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
<b>See also:</b> \ref vigra::NeighborhoodCirculator <b>See also:</b> \ref vigra::NeighborhoodCirculator
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* AtImageBorder */ /* AtImageBorder */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Encode whether a point is near the image border. /** \brief Encode whether a point is near the image border.
This enum is used with \ref isAtImageBorder() and This enum is used with \ref isAtImageBorder() and
\ref vigra::RestrictedNeighborhoodCirculator. \ref vigra::RestrictedNeighborhoodCirculator.
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
enum AtImageBorder enum AtImageBorder
{ {
NotAtBorder = 0, ///< &nbsp; NotAtBorder = 0, ///< &nbsp;
RightBorder = 1, ///< &nbsp; RightBorder = 1, ///< &nbsp;
LeftBorder = 2, ///< &nbsp; LeftBorder = 2, ///< &nbsp;
TopBorder = 4, ///< &nbsp; TopBorder = 4, ///< &nbsp;
BottomBorder = 8, ///< &nbsp; BottomBorder = 8, ///< &nbsp;
skipping to change at line 104 skipping to change at line 104
TopRightRearBorder = TopBorder | RightBorder | RearBorder, //37 TopRightRearBorder = TopBorder | RightBorder | RearBorder, //37
TopLeftRearBorder = TopBorder | LeftBorder | RearBorder, //38 TopLeftRearBorder = TopBorder | LeftBorder | RearBorder, //38
BottomLeftRearBorder = BottomBorder | LeftBorder | RearBorder, //42 BottomLeftRearBorder = BottomBorder | LeftBorder | RearBorder, //42
BottomRightRearBorder = BottomBorder | RightBorder | RearBorder //41 BottomRightRearBorder = BottomBorder | RightBorder | RearBorder //41
}; };
/** \brief Find out whether a point is at the image border. /** \brief Find out whether a point is at the image border.
This function checks if \a x == 0 or \a x == \a width - 1 and This function checks if \a x == 0 or \a x == \a width - 1 and
\a y == 0 or \a y == \a height - 1 and returns the appropriate value \a y == 0 or \a y == \a height - 1 and returns the appropriate value
of \ref vigra::AtImageBorder, or zero when the point is not at te image border. of \ref vigra::AtImageBorder, or zero when the point is not at the imag e border.
The behavior of the function is undefined if (x,y) is not inside the im age. The behavior of the function is undefined if (x,y) is not inside the im age.
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
inline AtImageBorder isAtImageBorder(int x, int y, int width, int height) inline AtImageBorder isAtImageBorder(int x, int y, int width, int height)
{ {
return static_cast<AtImageBorder>((x == 0 return static_cast<AtImageBorder>((x == 0
? LeftBorder ? LeftBorder
: x == width-1 : x == width-1
? RightBorder ? RightBorder
: NotAtBorder) | : NotAtBorder) |
(y == 0 (y == 0
skipping to change at line 161 skipping to change at line 161
\code \code
using namespace FourNeighborhood; using namespace FourNeighborhood;
Direction d = East; Direction d = East;
\endcode \endcode
If you want to pass 4-neighborhood codes as a template parameter, use If you want to pass 4-neighborhood codes as a template parameter, use
the class FourNeighborhood::NeighborCode. the class FourNeighborhood::NeighborCode.
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra::FourNeighborhood Namespace: vigra::FourNeighborhood
*/ */
class NeighborCode class NeighborCode
{ {
public: public:
typedef Diff2D difference_type; typedef Diff2D difference_type;
/** Freeman direction codes for the 4-neighborhood. /** Freeman direction codes for the 4-neighborhood.
<tt>East = 0</tt>, <tt>North = 1</tt> etc. <tt>East = 0</tt>, <tt>North = 1</tt> etc.
skipping to change at line 393 skipping to change at line 393
\code \code
using namespace EightNeighborhood; using namespace EightNeighborhood;
Direction d = East; Direction d = East;
\endcode \endcode
If you want to pass 8-neighborhood codes as a template parameter, use If you want to pass 8-neighborhood codes as a template parameter, use
the class EightNeighborhood::NeighborCode. the class EightNeighborhood::NeighborCode.
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra::EightNeighborhood Namespace: vigra::EightNeighborhood
*/ */
class NeighborCode class NeighborCode
{ {
public: public:
typedef Diff2D difference_type; typedef Diff2D difference_type;
/** Freeman direction codes for the 8-neighborhood. /** Freeman direction codes for the 8-neighborhood.
<tt>East = 0</tt>, <tt>North = 1</tt> etc. <tt>East = 0</tt>, <tt>North = 1</tt> etc.
skipping to change at line 660 skipping to change at line 660
/** \brief Circulator that walks around a given location. /** \brief Circulator that walks around a given location.
The template parameter defines the kind of neighborhood used, e.g. The template parameter defines the kind of neighborhood used, e.g.
\code \code
NeighborOffsetCirculator<EightNeighborCode> eight_circulator; NeighborOffsetCirculator<EightNeighborCode> eight_circulator;
NeighborOffsetCirculator<FourNeighborCode> four_circulator; NeighborOffsetCirculator<FourNeighborCode> four_circulator;
\endcode \endcode
Since this circulator doesn't now about the pixels in any particular im Since this circulator doesn't know about the pixels in any particular i
age, mage,
you usually doesn't use it directly but rather as a base class or helpe you usually don't use it directly but rather as a base class or helper
r for for
neighborhood circulators refering to a particular image (e.g. Neighborh neighborhood circulators referring to a particular image (e.g. Neighbor
oodCirculator) hoodCirculator)
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template<class NEIGHBORCODE> template<class NEIGHBORCODE>
class NeighborOffsetCirculator class NeighborOffsetCirculator
: public NEIGHBORCODE : public NEIGHBORCODE
{ {
public: public:
typedef NEIGHBORCODE NeighborCode; typedef NEIGHBORCODE NeighborCode;
/** return type of direction() /** return type of direction()
skipping to change at line 706 skipping to change at line 706
typedef int difference_type; typedef int difference_type;
/** the circulator tag (random access iterator) /** the circulator tag (random access iterator)
*/ */
typedef random_access_circulator_tag iterator_category; typedef random_access_circulator_tag iterator_category;
protected: protected:
Direction direction_; Direction direction_;
public: public:
/** Create circulator refering to the given direction. /** Create circulator referring to the given direction.
*/ */
NeighborOffsetCirculator(Direction dir = NEIGHBORCODE::InitialDirection ) NeighborOffsetCirculator(Direction dir = NEIGHBORCODE::InitialDirection )
: direction_(dir) : direction_(dir)
{ {
} }
/** pre-increment */ /** pre-increment */
NeighborOffsetCirculator & operator++() NeighborOffsetCirculator & operator++()
{ {
direction_ = static_cast<Direction>((direction_+1) % NEIGHBORCODE:: DirectionCount); direction_ = static_cast<Direction>((direction_+1) % NEIGHBORCODE:: DirectionCount);
skipping to change at line 817 skipping to change at line 817
direction_ = d; direction_ = d;
return *this; return *this;
} }
/** equality */ /** equality */
bool operator==(NeighborOffsetCirculator const & o) const bool operator==(NeighborOffsetCirculator const & o) const
{ {
return direction_ == o.direction_; return direction_ == o.direction_;
} }
/** unequality */ /** inequality */
bool operator!=(NeighborOffsetCirculator const & o) const bool operator!=(NeighborOffsetCirculator const & o) const
{ {
return direction_ != o.direction_; return direction_ != o.direction_;
} }
/** subtraction */ /** subtraction */
difference_type operator-(NeighborOffsetCirculator const & o) const difference_type operator-(NeighborOffsetCirculator const & o) const
{ {
return direction_ - o.direction_; return direction_ - o.direction_;
} }
skipping to change at line 956 skipping to change at line 956
/* NeighborhoodCirculator */ /* NeighborhoodCirculator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Circulator that walks around a given location in a given image. /** \brief Circulator that walks around a given location in a given image.
The template parameters define the kind of neighborhood used and the un derlying The template parameters define the kind of neighborhood used and the un derlying
image. The access functions return the value of the current neighbor pi xel. image. The access functions return the value of the current neighbor pi xel.
Use <tt>center()</tt> to access the center pixel of the neighborhood. Use <tt>center()</tt> to access the center pixel of the neighborhood.
The center can be changed by calling <tt>moveCenterToNeighbor()</tt> The center can be changed by calling <tt>moveCenterToNeighbor()</tt>
or <tt>swapCenterNeighbor()</tt>. Note that this circulator cannot or <tt>swapCenterNeighbor()</tt>. Note that this circulator cannot be u sed
when the center is at the image border. You must then use when the center is at the image border. You must then use
\ref vigra::RestrictedNeighborhoodCirculator \ref vigra::RestrictedNeighborhoodCirculator
<b>Usage:</b><br> <b>Usage:</b><br>
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
BImage::traverser upperleft(...), lowerright(...); BImage::traverser upperleft(...), lowerright(...);
int width = lowerright.x - upperleft.x; int width = lowerright.x - upperleft.x;
int height = lowerright.y - upperleft.y; int height = lowerright.y - upperleft.y;
++upperleft.y; // avoid image border ++upperleft.y; // avoid image border
for(int y=1; y<height-1; ++y, ++upperleft.y) for(int y=1; y<height-1; ++y, ++upperleft.y)
skipping to change at line 1050 skipping to change at line 1050
{ {
IMAGEITERATOR::operator+=(neighborCode_.diff()); IMAGEITERATOR::operator+=(neighborCode_.diff());
} }
/** pre-increment */ /** pre-increment */
NeighborhoodCirculator & operator++() NeighborhoodCirculator & operator++()
{ {
return operator+=(1); return operator+=(1);
} }
/** pre-decrement */ /** post-increment */
NeighborhoodCirculator operator++(int) NeighborhoodCirculator operator++(int)
{ {
NeighborhoodCirculator ret(*this); NeighborhoodCirculator ret(*this);
operator++(); operator++();
return ret; return ret;
} }
/** post-increment */ /** pre-decrement */
NeighborhoodCirculator & operator--() NeighborhoodCirculator & operator--()
{ {
return operator+=(-1); return operator+=(-1);
} }
/** post-decrement */ /** post-decrement */
NeighborhoodCirculator operator--(int) NeighborhoodCirculator operator--(int)
{ {
NeighborhoodCirculator ret(*this); NeighborhoodCirculator ret(*this);
operator--(); operator--();
skipping to change at line 1235 skipping to change at line 1235
return neighborCode_.direction(); return neighborCode_.direction();
} }
/** Get the current direction bit. */ /** Get the current direction bit. */
unsigned int directionBit() const unsigned int directionBit() const
{ {
return neighborCode_.directionBit(); return neighborCode_.directionBit();
} }
/** Get the difference vector (Diff2D) from the center to the curre nt neighbor. */ /** Get the difference vector (Diff2D) from the center to the curre nt neighbor. */
Diff2D const & diff() const typename NEIGHBOROFFSETCIRCULATOR::value_type const & diff() const
{ {
return neighborCode_.diff(); return neighborCode_.diff();
} }
/** Is the current neighbor a diagonal neighbor? */ /** Is the current neighbor a diagonal neighbor? */
bool isDiagonal() const bool isDiagonal() const
{ {
return neighborCode_.isDiagonal(); return neighborCode_.isDiagonal();
} }
skipping to change at line 1257 skipping to change at line 1257
NEIGHBOROFFSETCIRCULATOR neighborCode_; NEIGHBOROFFSETCIRCULATOR neighborCode_;
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* RestrictedNeighborhoodCirculator */ /* RestrictedNeighborhoodCirculator */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Circulator that walks around a given location in a given image, /** \brief Circulator that walks around a given location in a given image,
unsing a restricted neighborhood. using a restricted neighborhood.
This circulator behaves essentially like \ref vigra::NeighborhoodCircul ator, This circulator behaves essentially like \ref vigra::NeighborhoodCircul ator,
but can also be used near the image border, where some of the neighbor points but can also be used near the image border, where some of the neighbor points
would be outside the image und must not be accessed. would be outside the image und must not be accessed.
The template parameters define the kind of neighborhood used (four or e ight) The template parameters define the kind of neighborhood used (four or e ight)
and the underlying image, whereas the required neighbirhood restriction and the underlying image, whereas the required neighborhood restriction
is is
given by the last constructur argument. This below for typical usage. given by the last constructor argument. This below for typical usage.
The access functions return the value of the current neighbor pixel. Us e <tt>center()</tt> to The access functions return the value of the current neighbor pixel. Us e <tt>center()</tt> to
access the center pixel of the neighborhood. access the center pixel of the neighborhood.
<b>Usage:</b><br> <b>Usage:</b><br>
<b>\#include</b> \<<a href="pixelneighborhood_8hxx-source.html">vigra/p ixelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/pixelneighborhood.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
BImage::traverser upperleft(...), lowerright(...); BImage::traverser upperleft(...), lowerright(...);
int width = lowerright.x - upperleft.x; int width = lowerright.x - upperleft.x;
int height = lowerright.y - upperleft.y; int height = lowerright.y - upperleft.y;
for(int y=0; y<height; ++y, ++upperleft.y) for(int y=0; y<height; ++y, ++upperleft.y)
{ {
skipping to change at line 1358 skipping to change at line 1358
count_(NEIGHBORCODE::nearBorderDirectionCount(atBorder)), count_(NEIGHBORCODE::nearBorderDirectionCount(atBorder)),
current_(0) current_(0)
{} {}
/** pre-increment */ /** pre-increment */
RestrictedNeighborhoodCirculator & operator++() RestrictedNeighborhoodCirculator & operator++()
{ {
return operator+=(1); return operator+=(1);
} }
/** pre-decrement */ /** post-increment */
RestrictedNeighborhoodCirculator operator++(int) RestrictedNeighborhoodCirculator operator++(int)
{ {
RestrictedNeighborhoodCirculator ret(*this); RestrictedNeighborhoodCirculator ret(*this);
operator++(); operator++();
return ret; return ret;
} }
/** post-increment */ /** pre-decrement */
RestrictedNeighborhoodCirculator & operator--() RestrictedNeighborhoodCirculator & operator--()
{ {
return operator+=(-1); return operator+=(-1);
} }
/** post-decrement */ /** post-decrement */
RestrictedNeighborhoodCirculator operator--(int) RestrictedNeighborhoodCirculator operator--(int)
{ {
RestrictedNeighborhoodCirculator ret(*this); RestrictedNeighborhoodCirculator ret(*this);
operator--(); operator--();
skipping to change at line 1465 skipping to change at line 1465
return BaseType::direction(); return BaseType::direction();
} }
/** Get the current direction bit. */ /** Get the current direction bit. */
unsigned int directionBit() const unsigned int directionBit() const
{ {
return BaseType::directionBit(); return BaseType::directionBit();
} }
/** Get the difference vector (Diff2D) from the center to the curre nt neighbor. */ /** Get the difference vector (Diff2D) from the center to the curre nt neighbor. */
Diff2D const & diff() const typename NeighborCode::difference_type const & diff() const
{ {
return BaseType::diff(); return BaseType::diff();
} }
/** Is the current neighbor a diagonal neighbor? */ /** Is the current neighbor a diagonal neighbor? */
bool isDiagonal() const bool isDiagonal() const
{ {
return BaseType::isDiagonal(); return BaseType::isDiagonal();
} }
 End of changes. 21 change blocks. 
28 lines changed or deleted 28 lines changed or added


 polynomial.hxx   polynomial.hxx 
skipping to change at line 66 skipping to change at line 66
/* */ /* */
/*****************************************************************/ /*****************************************************************/
/** Polynomial interface for an externally managed array. /** Polynomial interface for an externally managed array.
The coefficient type <tt>T</tt> can be either a scalar or complex The coefficient type <tt>T</tt> can be either a scalar or complex
(compatible to <tt>std::complex</tt>) type. (compatible to <tt>std::complex</tt>) type.
\see vigra::Polynomial, vigra::StaticPolynomial, polynomialRoots() \see vigra::Polynomial, vigra::StaticPolynomial, polynomialRoots()
<b>\#include</b> \<<a href="polynomial_8hxx-source.html">vigra/polynomi al.hxx</a>\><br> <b>\#include</b> \<vigra/polynomial.hxx\><br>
Namespace: vigra Namespace: vigra
\ingroup Polynomials \ingroup Polynomials
*/ */
template <class T> template <class T>
class PolynomialView class PolynomialView
{ {
public: public:
/** Coefficient type of the polynomial /** Coefficient type of the polynomial
skipping to change at line 168 skipping to change at line 168
The behavior of this function is undefined if <tt>r</tt> The behavior of this function is undefined if <tt>r</tt>
is not a root. Forward deflation is best if <tt>r</tt> is is not a root. Forward deflation is best if <tt>r</tt> is
the biggest root (by magnitude). the biggest root (by magnitude).
*/ */
void forwardDeflate(T const & v); void forwardDeflate(T const & v);
/** Forward/backward eflate the polynomial at the root <tt>r</tt>. /** Forward/backward eflate the polynomial at the root <tt>r</tt>.
The behavior of this function is undefined if <tt>r</tt> The behavior of this function is undefined if <tt>r</tt>
is not a root. Combined forward/backward deflation is best is not a root. Combined forward/backward deflation is best
if <tt>r</tt> is an ontermediate root or we don't know if <tt>r</tt> is an intermediate root or we don't know
<tt>r</tt>'s relation to the other roots of the polynomial. <tt>r</tt>'s relation to the other roots of the polynomial.
*/ */
void forwardBackwardDeflate(T v); void forwardBackwardDeflate(T v);
/** Backward-deflate the polynomial at the root <tt>r</tt>. /** Backward-deflate the polynomial at the root <tt>r</tt>.
The behavior of this function is undefined if <tt>r</tt> The behavior of this function is undefined if <tt>r</tt>
is not a root. Backward deflation is best if <tt>r</tt> is is not a root. Backward deflation is best if <tt>r</tt> is
the snallest root (by magnitude). the smallest root (by magnitude).
*/ */
void backwardDeflate(T v); void backwardDeflate(T v);
/** Deflate the polynomial with the complex conjugate roots /** Deflate the polynomial with the complex conjugate roots
<tt>r</tt> and <tt>conj(r)</tt>. <tt>r</tt> and <tt>conj(r)</tt>.
The behavior of this function is undefined if these are not The behavior of this function is undefined if these are not
roots. roots.
*/ */
void deflateConjugatePair(Complex const & v); void deflateConjugatePair(Complex const & v);
skipping to change at line 435 skipping to change at line 435
/* Polynomial */ /* Polynomial */
/* */ /* */
/*****************************************************************/ /*****************************************************************/
/** Polynomial with internally managed array. /** Polynomial with internally managed array.
Most interesting functionality is inherited from \ref vigra::Polynomial View. Most interesting functionality is inherited from \ref vigra::Polynomial View.
\see vigra::PolynomialView, vigra::StaticPolynomial, polynomialRoots() \see vigra::PolynomialView, vigra::StaticPolynomial, polynomialRoots()
<b>\#include</b> \<<a href="polynomial_8hxx-source.html">vigra/polynomi al.hxx</a>\><br> <b>\#include</b> \<vigra/polynomial.hxx\><br>
Namespace: vigra Namespace: vigra
\ingroup Polynomials \ingroup Polynomials
*/ */
template <class T> template <class T>
class Polynomial class Polynomial
: public PolynomialView<T> : public PolynomialView<T>
{ {
typedef PolynomialView<T> BaseType; typedef PolynomialView<T> BaseType;
public: public:
skipping to change at line 566 skipping to change at line 566
/** Polynomial with internally managed array of static length. /** Polynomial with internally managed array of static length.
Most interesting functionality is inherited from \ref vigra::Polynomial View. Most interesting functionality is inherited from \ref vigra::Polynomial View.
This class differs from \ref vigra::Polynomial in that it allocates This class differs from \ref vigra::Polynomial in that it allocates
its memory statically which is much faster. Therefore, <tt>StaticPolyno mial</tt> its memory statically which is much faster. Therefore, <tt>StaticPolyno mial</tt>
can only represent polynomials up to the given <tt>MAXORDER</tt>. can only represent polynomials up to the given <tt>MAXORDER</tt>.
\see vigra::PolynomialView, vigra::Polynomial, polynomialRoots() \see vigra::PolynomialView, vigra::Polynomial, polynomialRoots()
<b>\#include</b> \<<a href="polynomial_8hxx-source.html">vigra/polynomi al.hxx</a>\><br> <b>\#include</b> \<vigra/polynomial.hxx\><br>
Namespace: vigra Namespace: vigra
\ingroup Polynomials \ingroup Polynomials
*/ */
template <unsigned int MAXORDER, class T> template <unsigned int MAXORDER, class T>
class StaticPolynomial class StaticPolynomial
: public PolynomialView<T> : public PolynomialView<T>
{ {
typedef PolynomialView<T> BaseType; typedef PolynomialView<T> BaseType;
skipping to change at line 705 skipping to change at line 705
/************************************************************/ /************************************************************/
namespace detail { namespace detail {
// replacement for complex division (some compilers have numerically // replacement for complex division (some compilers have numerically
// less stable implementations); code from python complexobject.c // less stable implementations); code from python complexobject.c
template <class T> template <class T>
std::complex<T> complexDiv(std::complex<T> const & a, std::complex<T> const & b) std::complex<T> complexDiv(std::complex<T> const & a, std::complex<T> const & b)
{ {
const double abs_breal = b.real() < 0 ? -b.real() : b.real(); const double abs_breal = b.real() < 0 ? -b.real() : b.real();
const double abs_bimag = b.imag() < 0 ? -b.imag() : b.imag(); const double abs_bimag = b.imag() < 0 ? -b.imag() : b.imag();
if (abs_breal >= abs_bimag) if (abs_breal >= abs_bimag)
{ {
/* divide tops and bottom by b.real() */ /* divide tops and bottom by b.real() */
if (abs_breal == 0.0) if (abs_breal == 0.0)
{ {
return std::complex<T>(a.real() / abs_breal, a.imag( return std::complex<T>(a.real() / abs_breal, a.imag() / abs_bre
) / abs_breal); al);
} }
else else
{ {
const double ratio = b.imag() / b.real(); const double ratio = b.imag() / b.real();
const double denom = b.real() + b.imag() * ratio; const double denom = b.real() + b.imag() * ratio;
return std::complex<T>((a.real() + a.imag() * ratio) return std::complex<T>((a.real() + a.imag() * ratio) / denom,
/ denom, (a.imag() - a.real() * ratio) / denom);
(a.imag() - a.real() * ratio) }
/ denom); }
} else
} {
else /* divide tops and bottom by b.imag() */
{ const double ratio = b.real() / b.imag();
/* divide tops and bottom by b.imag() */ const double denom = b.real() * ratio + b.imag();
const double ratio = b.real() / b.imag(); return std::complex<T>((a.real() * ratio + a.imag()) / denom,
const double denom = b.real() * ratio + b.imag();
return std::complex<T>((a.real() * ratio + a.imag()) / denom
,
(a.imag() * ratio - a.real()) / denom); (a.imag() * ratio - a.real()) / denom);
} }
} }
template <class T> template <class T>
std::complex<T> deleteBelowEpsilon(std::complex<T> const & x, double eps) std::complex<T> deleteBelowEpsilon(std::complex<T> const & x, double eps)
{ {
return std::abs(x.imag()) <= 2.0*eps*std::abs(x.real()) return std::abs(x.imag()) <= 2.0*eps*std::abs(x.real())
? std::complex<T>(x.real()) ? std::complex<T>(x.real())
: std::abs(x.real()) <= 2.0*eps*std::abs(x.imag()) : std::abs(x.real()) <= 2.0*eps*std::abs(x.imag())
? std::complex<T>(NumericTraits<T>::zero(), x.imag()) ? std::complex<T>(NumericTraits<T>::zero(), x.imag())
: x; : x;
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> \<<a href="polynomial_8hxx-source.html">vigra/poly nomial.hxx</a>\><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);
skipping to change at line 1056 skipping to change at line 1056
\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> \<<a href="polynomial_8hxx-source.html">vigra/poly nomial.hxx</a>\><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);
 End of changes. 10 change blocks. 
35 lines changed or deleted 32 lines changed or added


 python_utility.hxx   python_utility.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_PYTHON_UTILITY_HXX #ifndef VIGRA_PYTHON_UTILITY_HXX
#define VIGRA_PYTHON_UTILITY_HXX #define VIGRA_PYTHON_UTILITY_HXX
#include <algorithm>
#include <Python.h> #include <Python.h>
#include <algorithm>
#include <string>
#include "vigra/error.hxx" #include "vigra/error.hxx"
#include "vigra/tinyvector.hxx" #include "vigra/tinyvector.hxx"
namespace vigra { namespace vigra {
template <class PYOBJECT_PTR> template <class PYOBJECT_PTR>
void pythonToCppException(PYOBJECT_PTR obj) void pythonToCppException(PYOBJECT_PTR obj)
{ {
if(obj != 0) if(obj != 0)
return; return;
skipping to change at line 67 skipping to change at line 68
{ {
message += std::string(": ") + PyString_AS_STRING(value); message += std::string(": ") + PyString_AS_STRING(value);
} }
Py_XDECREF(type); Py_XDECREF(type);
Py_XDECREF(value); Py_XDECREF(value);
Py_XDECREF(trace); Py_XDECREF(trace);
throw std::runtime_error(message.c_str()); throw std::runtime_error(message.c_str());
} }
/********************************************************/
/* */
/* python_ptr */
/* */
/********************************************************/
class python_ptr class python_ptr
{ {
private: private:
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 };
explicit python_ptr(pointer p = 0, refcount_policy rp = increment_count ) explicit python_ptr(pointer p = 0, refcount_policy rp = increment_count )
skipping to change at line 205 skipping to change at line 212
{ {
return ptr_ != p; return ptr_ != p;
} }
}; };
inline void swap(python_ptr & a, python_ptr & b) inline void swap(python_ptr & a, python_ptr & b)
{ {
a.swap(b); a.swap(b);
} }
/****************************************************************/
inline python_ptr inline python_ptr
getPythonDictionary(char const * k1 = 0, PyObject * a1 = 0, makePythonDictionary(char const * k1 = 0, PyObject * a1 = 0,
char const * k2 = 0, PyObject * a2 = 0, char const * k2 = 0, PyObject * a2 = 0,
char const * k3 = 0, PyObject * a3 = 0) char const * k3 = 0, PyObject * a3 = 0)
{ {
python_ptr dict(PyDict_New(), python_ptr::keep_count); python_ptr dict(PyDict_New(), python_ptr::keep_count);
pythonToCppException(dict); pythonToCppException(dict);
if(k1 && a1) if(k1 && a1)
PyDict_SetItemString(dict, k1, a1); PyDict_SetItemString(dict, k1, a1);
if(k2 && a2) if(k2 && a2)
PyDict_SetItemString(dict, k2, a2); PyDict_SetItemString(dict, k2, a2);
if(k3 && a3) if(k3 && a3)
PyDict_SetItemString(dict, k3, a3); PyDict_SetItemString(dict, k3, a3);
return dict; return dict;
} }
inline python_ptr pythonFromNumber(bool t) /****************************************************************/
inline python_ptr pythonFromData(bool t)
{ {
python_ptr res(PyBool_FromLong(t ? 1 : 0), python_ptr::keep_count); python_ptr res(PyBool_FromLong(t ? 1 : 0), python_ptr::keep_count);
pythonToCppException(res); pythonToCppException(res);
return res; return res;
} }
#define VIGRA_PYTHON_NUMBER_CONVERSION(type, condition, fct1, fct2) \ inline python_ptr pythonFromData(std::string const & s)
inline python_ptr pythonFromNumber(type t) \ {
python_ptr res(PyString_FromString(s.c_str()), python_ptr::keep_count);
pythonToCppException(res);
return res;
}
inline python_ptr pythonFromData(long long t)
{
python_ptr res;
if(t > (long long)NumericTraits<long>::max() || t < (long long)NumericT
raits<long>::min())
res = python_ptr(PyLong_FromLongLong(t), python_ptr::keep_count);
else
res = python_ptr(PyInt_FromLong((long)t), python_ptr::keep_count);
pythonToCppException(res);
return res;
}
inline python_ptr pythonFromData(unsigned long long t)
{
python_ptr res;
if(t > (unsigned long long)NumericTraits<long>::max())
res = python_ptr(PyLong_FromUnsignedLongLong(t), python_ptr::keep_c
ount);
else
res = python_ptr(PyInt_FromLong((long)t), python_ptr::keep_count);
pythonToCppException(res);
return res;
}
#define VIGRA_PYTHON_FROM_DATA(type, fct, cast_type) \
inline python_ptr pythonFromData(type t) \
{ \ { \
python_ptr res; \ python_ptr res(fct((cast_type)t), python_ptr::keep_count); \
if(condition) \
res = python_ptr(fct1(t), python_ptr::keep_count); \
else \
res = python_ptr(fct2(t), python_ptr::keep_count); \
pythonToCppException(res); \ pythonToCppException(res); \
return res; \ return res; \
} }
VIGRA_PYTHON_NUMBER_CONVERSION(signed char, true, PyInt_FromLong, PyInt_Fro VIGRA_PYTHON_FROM_DATA(signed char, PyInt_FromLong, long)
mLong) VIGRA_PYTHON_FROM_DATA(unsigned char, PyInt_FromLong, long)
VIGRA_PYTHON_NUMBER_CONVERSION(unsigned char, true, PyInt_FromLong, PyInt_F VIGRA_PYTHON_FROM_DATA(short, PyInt_FromLong, long)
romLong) VIGRA_PYTHON_FROM_DATA(unsigned short, PyInt_FromLong, long)
VIGRA_PYTHON_NUMBER_CONVERSION(short, true, PyInt_FromLong, PyInt_FromLong) VIGRA_PYTHON_FROM_DATA(long, PyInt_FromLong, long)
VIGRA_PYTHON_NUMBER_CONVERSION(unsigned short, true, PyInt_FromLong, PyInt_ VIGRA_PYTHON_FROM_DATA(unsigned long, PyInt_FromSize_t, size_t)
FromLong) VIGRA_PYTHON_FROM_DATA(int, PyInt_FromSsize_t, Py_ssize_t)
VIGRA_PYTHON_NUMBER_CONVERSION(long, true, PyInt_FromLong, PyInt_FromLong) VIGRA_PYTHON_FROM_DATA(unsigned int, PyInt_FromSize_t, size_t)
VIGRA_PYTHON_NUMBER_CONVERSION(unsigned long, sizeof(unsigned long) < sizeo VIGRA_PYTHON_FROM_DATA(float, PyFloat_FromDouble, double)
f(Py_ssize_t), PyInt_FromSsize_t, PyLong_FromUnsignedLongLong) VIGRA_PYTHON_FROM_DATA(double, PyFloat_FromDouble, double)
VIGRA_PYTHON_NUMBER_CONVERSION(int, sizeof(long) < sizeof(Py_ssize_t), PyIn VIGRA_PYTHON_FROM_DATA(char const *, PyString_FromString, char const *)
t_FromSsize_t, PyInt_FromLong)
VIGRA_PYTHON_NUMBER_CONVERSION(unsigned int, sizeof(unsigned int) < sizeof(
Py_ssize_t), PyInt_FromSsize_t, PyLong_FromUnsignedLongLong)
VIGRA_PYTHON_NUMBER_CONVERSION(long long, true, PyLong_FromLongLong, PyLong
_FromLongLong)
VIGRA_PYTHON_NUMBER_CONVERSION(unsigned long long, true, PyLong_FromUnsigne
dLongLong, PyLong_FromUnsignedLongLong)
VIGRA_PYTHON_NUMBER_CONVERSION(float, true, PyFloat_FromDouble, PyFloat_Fro
mDouble)
VIGRA_PYTHON_NUMBER_CONVERSION(double, true, PyFloat_FromDouble, PyFloat_Fr
omDouble)
#undef VIGRA_PYTHON_NUMBER_CONVERSION #undef VIGRA_PYTHON_FROM_DATA
/****************************************************************/
#define VIGRA_DATA_FROM_PYTHON(type, check, extract) \
inline type dataFromPython(PyObject * data, type const & defaultVal) \
{ \
return data && check(data) \
? (type)extract(data) \
: defaultVal; \
}
VIGRA_DATA_FROM_PYTHON(signed char, PyInt_Check, PyInt_AsLong)
VIGRA_DATA_FROM_PYTHON(unsigned char, PyInt_Check, PyInt_AsLong)
VIGRA_DATA_FROM_PYTHON(short, PyInt_Check, PyInt_AsLong)
VIGRA_DATA_FROM_PYTHON(unsigned short, PyInt_Check, PyInt_AsLong)
VIGRA_DATA_FROM_PYTHON(long, PyInt_Check, PyInt_AsLong)
VIGRA_DATA_FROM_PYTHON(unsigned long, PyInt_Check, PyInt_AsUnsignedLongMask
)
VIGRA_DATA_FROM_PYTHON(int, PyInt_Check, PyInt_AsLong)
VIGRA_DATA_FROM_PYTHON(unsigned int, PyInt_Check, PyInt_AsUnsignedLongMask)
VIGRA_DATA_FROM_PYTHON(long long, PyInt_Check, PyInt_AsSsize_t)
VIGRA_DATA_FROM_PYTHON(unsigned long long, PyInt_Check, PyInt_AsUnsignedLon
gLongMask)
VIGRA_DATA_FROM_PYTHON(float, PyFloat_Check, PyFloat_AsDouble)
VIGRA_DATA_FROM_PYTHON(double, PyFloat_Check, PyFloat_AsDouble)
inline std::string dataFromPython(PyObject * data, const char * defaultVal)
{
return data && PyString_Check(data)
? std::string(PyString_AsString(data))
: std::string(defaultVal);
}
inline std::string dataFromPython(PyObject * data, std::string const & defa
ultVal)
{
return data && PyString_Check(data)
? std::string(PyString_AsString(data))
: defaultVal;
}
inline python_ptr dataFromPython(PyObject * data, python_ptr defaultVal)
{
return data
? python_ptr(data)
: defaultVal;
}
#undef VIGRA_DATA_FROM_PYTHON
/****************************************************************/
template <class T>
T pythonGetAttr(PyObject * obj, const char * key, T defaultValue)
{
if(!obj)
return defaultValue;
python_ptr k(PyString_FromString(key), python_ptr::keep_count);
pythonToCppException(k);
python_ptr pres(PyObject_GetAttr(obj, k), python_ptr::keep_count);
if(!pres)
PyErr_Clear();
return dataFromPython(pres, defaultValue);
}
inline std::string
pythonGetAttr(PyObject * obj, const char * key, const char * defaultValue)
{
if(!obj)
return std::string(defaultValue);
python_ptr k(PyString_FromString(key), python_ptr::keep_count);
pythonToCppException(k);
python_ptr pres(PyObject_GetAttr(obj, k), python_ptr::keep_count);
if(!pres)
PyErr_Clear();
return dataFromPython(pres, defaultValue);
}
/****************************************************************/
template <class T, int N> template <class T, int N>
python_ptr shapeToPythonTuple(TinyVector<T, N> const & shape) python_ptr shapeToPythonTuple(TinyVector<T, N> const & shape)
{ {
python_ptr tuple(PyTuple_New(N), python_ptr::keep_count); python_ptr tuple(PyTuple_New(N), python_ptr::keep_count);
pythonToCppException(tuple); pythonToCppException(tuple);
for(unsigned int k=0; k<N; ++k) for(unsigned int k=0; k<N; ++k)
{ {
PyTuple_SET_ITEM((PyTupleObject *)tuple.get(), k, pythonFromNumber( shape[k]).release()); PyTuple_SET_ITEM((PyTupleObject *)tuple.get(), k, pythonFromData(sh ape[k]).release());
} }
return tuple; return tuple;
} }
template <class T> template <class T>
python_ptr shapeToPythonTuple(ArrayVectorView<T> const & shape) python_ptr shapeToPythonTuple(ArrayVectorView<T> const & shape)
{ {
python_ptr tuple(PyTuple_New(shape.size()), python_ptr::keep_count); python_ptr tuple(PyTuple_New(shape.size()), python_ptr::keep_count);
pythonToCppException(tuple); pythonToCppException(tuple);
for(unsigned int k=0; k<shape.size(); ++k) for(unsigned int k=0; k<shape.size(); ++k)
{ {
PyTuple_SET_ITEM((PyTupleObject *)tuple.get(), k, pythonFromNumber( shape[k]).release()); PyTuple_SET_ITEM((PyTupleObject *)tuple.get(), k, pythonFromData(sh ape[k]).release());
} }
return tuple; return tuple;
} }
/****************************************************************/
class PyAllowThreads
{
PyThreadState * save_;
// make it non-copyable
PyAllowThreads(PyAllowThreads const &);
PyAllowThreads & operator=(PyAllowThreads const &);
public:
PyAllowThreads()
: save_(PyEval_SaveThread())
{}
~PyAllowThreads()
{
PyEval_RestoreThread(save_);
}
};
} // namespace vigra } // namespace vigra
#endif // VIGRA_PYTHON_UTILITY_HXX #endif // VIGRA_PYTHON_UTILITY_HXX
 End of changes. 15 change blocks. 
37 lines changed or deleted 166 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> \<<a href="quadprog_8hxx-source.html">vigra/quadprog. hxx</a>\> <b>\#include</b> \<vigra/quadprog.hxx\>
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,
skipping to change at line 207 skipping to change at line 207
choleskyDecomposition(G, L); choleskyDecomposition(G, L);
// find unconstrained minimizer of the quadratic form 0.5 * x G x + g' x // find unconstrained minimizer of the quadratic form 0.5 * x G x + g' x
choleskySolve(L, -g, x); choleskySolve(L, -g, x);
// compute the inverse of the factorized matrix G^-1, this is the i nitial value for J // compute the inverse of the factorized matrix G^-1, this is the i nitial value for J
linearSolveLowerTriangular(L, J, J); linearSolveLowerTriangular(L, J, J);
} }
// current solution value // current solution value
T f_value = 0.5 * dot(g, x); T f_value = 0.5 * dot(g, x);
T epsilonZ = NumericTraits<T>::epsilon() * sq(J.norm(0)), T epsilonZ = NumericTraits<T>::epsilon() * sq(J.norm(0)),
epsilonPsi = NumericTraits<T>::epsilon() * trace(G)*trace(J)*100.0,
inf = std::numeric_limits<T>::infinity(); inf = std::numeric_limits<T>::infinity();
Matrix<T> R(n, n), r(constraintCount, 1), u(constraintCount,1); Matrix<T> R(n, n), r(constraintCount, 1), u(constraintCount,1);
T R_norm = NumericTraits<T>::one(); T R_norm = NumericTraits<T>::one();
// incorporate equality constraints // incorporate equality constraints
for (int i=0; i < me; ++i) for (int i=0; i < me; ++i)
{ {
MultiArrayView<2, T, C3> np = rowVector(CE, i); MultiArrayView<2, T, C3> np = rowVector(CE, i);
Matrix<T> d = J*transpose(np); Matrix<T> d = J*transpose(np);
skipping to change at line 243 skipping to change at line 242
vigra_precondition(vigra::detail::quadprogAddConstraint(R, J, d, i, R_norm), vigra_precondition(vigra::detail::quadprogAddConstraint(R, J, d, i, R_norm),
"quadraticProgramming(): Equality constraints are linearly depe ndent."); "quadraticProgramming(): Equality constraints are linearly depe ndent.");
} }
int activeConstraintCount = me; int activeConstraintCount = me;
// determine optimum solution and corresponding active inequality const raints // determine optimum solution and corresponding active inequality const raints
ArrayVector<int> activeSet(mi); ArrayVector<int> activeSet(mi);
for (int i = 0; i < mi; ++i) for (int i = 0; i < mi; ++i)
activeSet[i] = i; activeSet[i] = i;
int constraintToBeAdded; int constraintToBeAdded = 0;
T ss = 0.0; T ss = 0.0;
for (int i = activeConstraintCount-me; i < mi; ++i) for (int i = activeConstraintCount-me; i < mi; ++i)
{ {
T s = dot(rowVector(CI, activeSet[i]), x) - ci(activeSet[i], 0); T s = dot(rowVector(CI, activeSet[i]), x) - ci(activeSet[i], 0);
if (s < ss) if (s < ss)
{ {
ss = s; ss = s;
constraintToBeAdded = i; constraintToBeAdded = i;
} }
} }
skipping to change at line 279 skipping to change at line 278
subVector(r, 0, activeConstraintCount)); subVector(r, 0, activeConstraintCount));
// determine minimum step length in primal space such that activeSe t[constraintToBeAdded] becomes feasible // determine minimum step length in primal space such that activeSe t[constraintToBeAdded] becomes feasible
T primalStep = (squaredNorm(z) <= epsilonZ) // i.e. z == 0 T primalStep = (squaredNorm(z) <= epsilonZ) // i.e. z == 0
? inf ? inf
: -ss / dot(z, np); : -ss / dot(z, np);
// determine maximum step length in dual space that doesn't violate dual feasibility // determine maximum step length in dual space that doesn't violate dual feasibility
// and the corresponding index // and the corresponding index
T dualStep = inf; T dualStep = inf;
int constraintToBeRemoved; int constraintToBeRemoved = 0;
for (int k = me; k < activeConstraintCount; ++k) for (int k = me; k < activeConstraintCount; ++k)
{ {
if (r(k,0) > 0.0) if (r(k,0) > 0.0)
{ {
if (u(k,0) / r(k,0) < dualStep) if (u(k,0) / r(k,0) < dualStep)
{ {
dualStep = u(k,0) / r(k,0); dualStep = u(k,0) / r(k,0);
constraintToBeRemoved = k; constraintToBeRemoved = k;
} }
} }
} }
// the step is chosen as the minimum of dualStep and primalStep // the step is chosen as the minimum of dualStep and primalStep
T step = std::min(dualStep, primalStep); T step = std::min(dualStep, primalStep);
// take step and update matrizes // take step and update matrices
if (step == inf) if (step == inf)
{ {
// case (i): no step in primal or dual space possible // case (i): no step in primal or dual space possible
return inf; // QPP is infeasible return inf; // QPP is infeasible
} }
if (primalStep == inf) if (primalStep == inf)
{ {
// case (ii): step in dual space // case (ii): step in dual space
subVector(u, 0, activeConstraintCount) -= step * subVector(r, 0 , activeConstraintCount); subVector(u, 0, activeConstraintCount) -= step * subVector(r, 0 , activeConstraintCount);
 End of changes. 5 change blocks. 
5 lines changed or deleted 4 lines changed or added


 random.hxx   random.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_RANDOM_HXX #ifndef VIGRA_RANDOM_HXX
#define VIGRA_RANDOM_HXX #define VIGRA_RANDOM_HXX
#include "mathutil.hxx" #include "mathutil.hxx"
#include "functortraits.hxx" #include "functortraits.hxx"
#include <time.h> #include <ctime>
namespace vigra { namespace vigra {
enum RandomSeedTag { RandomSeed }; enum RandomSeedTag { RandomSeed };
namespace detail { namespace detail {
enum RandomEngineTag { TT800, MT19937 }; enum RandomEngineTag { TT800, MT19937 };
template<RandomEngineTag EngineTag> template<RandomEngineTag EngineTag>
skipping to change at line 108 skipping to change at line 108
i=1; i=1;
} }
} }
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)
{ {
UInt32 init[2] = { (UInt32)time(0), (UInt32)clock() }; static UInt32 globalCount = 0;
seed(init, 2, engine); UInt32 init[3] = { (UInt32)time(0), (UInt32)clock(), ++globalCount };
seed(init, 3, engine);
} }
/* Tempered twister TT800 by M. Matsumoto */ /* Tempered twister TT800 by M. Matsumoto */
template<> template<>
struct RandomState<TT800> struct RandomState<TT800>
{ {
static const UInt32 N = 25, M = 7; static const UInt32 N = 25, M = 7;
mutable UInt32 state_[N]; mutable UInt32 state_[N];
mutable UInt32 current_; mutable UInt32 current_;
RandomState() RandomState()
: current_(0) : current_(0)
{ {
UInt32 seeds[N] = { UInt32 seeds[N] = {
0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23, 0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23,
0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825, 0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825,
0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f, 0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f,
0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9, 0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9,
0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb 0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb
}; };
for(UInt32 i=0; i<N; ++i) for(UInt32 i=0; i<N; ++i)
state_[i] = seeds[i]; state_[i] = seeds[i];
} }
protected: protected:
UInt32 get() const UInt32 get() const
{ {
skipping to change at line 176 skipping to change at line 177
} }
}; };
template <class DUMMY> template <class DUMMY>
void RandomState<TT800>::generateNumbers() const void RandomState<TT800>::generateNumbers() const
{ {
UInt32 mag01[2]= { 0x0, 0x8ebfd028 }; UInt32 mag01[2]= { 0x0, 0x8ebfd028 };
for(UInt32 i=0; i<N-M; ++i) for(UInt32 i=0; i<N-M; ++i)
{ {
state_[i] = state_[i+M] ^ (state_[i] >> 1) ^ mag01[state_[i] % 2]; state_[i] = state_[i+M] ^ (state_[i] >> 1) ^ mag01[state_[i] % 2];
} }
for (UInt32 i=N-M; i<N; ++i) for (UInt32 i=N-M; i<N; ++i)
{ {
state_[i] = state_[i+(M-N)] ^ (state_[i] >> 1) ^ mag01[state_[i] % 2]; state_[i] = state_[i+(M-N)] ^ (state_[i] >> 1) ^ mag01[state_[i] % 2];
} }
current_ = 0; current_ = 0;
} }
/* Mersenne twister MT19937 by M. Matsumoto */ /* Mersenne twister MT19937 by M. Matsumoto */
template<> template<>
skipping to change at line 280 skipping to change at line 281
are currently available: are currently available:
<ul> <ul>
<li> <tt>RandomMT19937</tt>: The state-of-the-art <a href="http://www.m ath.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">Mersenne Twister</a> with a s tate length of 2<sup>19937</sup> and very high statistical quality. <li> <tt>RandomMT19937</tt>: The state-of-the-art <a href="http://www.m ath.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">Mersenne Twister</a> with a s tate length of 2<sup>19937</sup> and very high statistical quality.
<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>
<tt>FunctorTraits<RandomNumberGenerator<Engine> >::isInitializer</tt> i \verbatim FunctorTraits<RandomNumberGenerator<Engine> >::isInitializer
s true (<tt>VigraTrueType</tt>). \endverbatim
is true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = detail::RandomState<detail::TT800> > template <class Engine = detail::RandomState<detail::TT800> >
class RandomNumberGenerator class RandomNumberGenerator
: public Engine : public Engine
{ {
mutable double normalCached_; mutable double normalCached_;
mutable bool normalCachedValid_; mutable bool normalCachedValid_;
public: public:
skipping to change at line 447 skipping to change at line 449
return res % beyond; return res % beyond;
} }
/** 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. All 53-bit bits of the mantissa are random (two 32-bit integers are used to That is, 0.0 &lt;= i &lt; 1.0. All 53-bit bits of the mantissa are random (two 32-bit integers are used to
create this number). create this number).
*/ */
double uniform53() const double uniform53() const
{ {
// make full use of the entire 53-bit mantissa of a double, by I // make full use of the entire 53-bit mantissa of a double, by Isak
saku Wada u Wada
return ( (this->get() >> 5) * 67108864.0 + (this->get() >> 6)) * return ( (this->get() >> 5) * 67108864.0 + (this->get() >> 6)) * (1
(1.0/9007199254740992.0); .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 nuber is computed by <tt>u niformInt()</tt> / 2<sup>32</sup>, That is, 0.0 &lt;= i &lt;= 1.0. This number is computed by <tt> uniformInt()</tt> / 2<sup>32</sup>,
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 (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
skipping to change at line 542 skipping to change at line 544
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<> RandomTT800;
/** Shorthand for the TT800 random number generator class (same as Rand
omTT800).
*/
typedef RandomNumberGenerator<> TemperedTwister;
/** 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).
*/
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.
*/ */
inline RandomTT800 & randomTT800() { return RandomTT800::global(); } inline RandomTT800 & randomTT800() { return RandomTT800::global(); }
/** Access the global (program-wide) instance of the MT19937 random num ber generator. /** Access the global (program-wide) instance of the MT19937 random num ber generator.
*/ */
inline RandomMT19937 & randomMT19937() { return RandomMT19937::global(); } inline RandomMT19937 & randomMT19937() { return RandomMT19937::global(); }
template <class Engine> template <class Engine>
class FunctorTraits<RandomNumberGenerator<Engine> > class FunctorTraits<RandomNumberGenerator<Engine> >
skipping to change at line 571 skipping to change at line 581
typedef VigraFalseType isUnaryFunctor; typedef VigraFalseType isUnaryFunctor;
typedef VigraFalseType isBinaryFunctor; typedef VigraFalseType isBinaryFunctor;
typedef VigraFalseType isTernaryFunctor; typedef VigraFalseType isTernaryFunctor;
typedef VigraFalseType isUnaryAnalyser; typedef VigraFalseType isUnaryAnalyser;
typedef VigraFalseType isBinaryAnalyser; typedef VigraFalseType isBinaryAnalyser;
typedef VigraFalseType isTernaryAnalyser; typedef VigraFalseType isTernaryAnalyser;
}; };
/** Functor to create uniformely distributed integer random numbers. /** Functor to create uniformly distributed integer random numbers.
This functor encapsulates the appropriate functions of the given random number This functor encapsulates the appropriate functions 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>
<tt>FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitializer</tt> \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize
and r \endverbatim
<tt>FunctorTraits<UniformIntRandomFunctor<Engine> >::isUnaryFunctor</tt and
> are true (<tt>VigraTrueType</tt>). \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isUnaryFunct
or \endverbatim
are true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = RandomTT800> template <class Engine = RandomTT800>
class UniformIntRandomFunctor class UniformIntRandomFunctor
{ {
UInt32 lower_, difference_, factor_; UInt32 lower_, difference_, factor_;
Engine const & generator_; Engine const & generator_;
bool useLowBits_; bool useLowBits_;
public: public:
skipping to change at line 678 skipping to change at line 690
typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isUnaryFunctor;
typedef VigraFalseType isBinaryFunctor; typedef VigraFalseType isBinaryFunctor;
typedef VigraFalseType isTernaryFunctor; typedef VigraFalseType isTernaryFunctor;
typedef VigraFalseType isUnaryAnalyser; typedef VigraFalseType isUnaryAnalyser;
typedef VigraFalseType isBinaryAnalyser; typedef VigraFalseType isBinaryAnalyser;
typedef VigraFalseType isTernaryAnalyser; typedef VigraFalseType isTernaryAnalyser;
}; };
/** Functor to create uniformely distributed double-precision random number s. /** Functor to create uniformly distributed double-precision random numbers .
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>
<tt>FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitializer</tt> \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize
is true (<tt>VigraTrueType</tt>). r \endverbatim
is true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = RandomTT800> template <class Engine = RandomTT800>
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
skipping to change at line 757 skipping to change at line 770
}; };
/** Functor to create normal variate random numbers. /** Functor to create normal variate random numbers.
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>
<tt>FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitializer</tt> \verbatim FunctorTraits<UniformIntRandomFunctor<Engine> >::isInitialize
is true (<tt>VigraTrueType</tt>). r \endverbatim
is true (<tt>VigraTrueType</tt>).
*/ */
template <class Engine = RandomTT800> template <class Engine = RandomTT800>
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
skipping to change at line 780 skipping to change at line 794
using the given engine. using the given engine.
That is, mean is 0.0 and standard deviation is 1.0. That is, mean is 0.0 and standard deviation is 1.0.
*/ */
NormalRandomFunctor(Engine const & generator = Engine::global()) NormalRandomFunctor(Engine const & generator = Engine::global())
: mean_(0.0), : mean_(0.0),
stddev_(1.0), stddev_(1.0),
generator_(generator) generator_(generator)
{} {}
/** Create functor for normal random numbers with goven mean and st andard deviation /** Create functor for normal random numbers with given mean and st andard deviation
using the given engine. using the given engine.
*/ */
NormalRandomFunctor(double mean, double stddev, NormalRandomFunctor(double mean, double stddev,
Engine & generator = Engine::global()) Engine & generator = Engine::global())
: mean_(mean), : mean_(mean),
stddev_(stddev), stddev_(stddev),
generator_(generator) generator_(generator)
{ {
vigra_precondition(stddev > 0.0, vigra_precondition(stddev > 0.0,
"NormalRandomFunctor(): standard deviation must be positive."); "NormalRandomFunctor(): standard deviation must be positive.");
 End of changes. 15 change blocks. 
27 lines changed or deleted 44 lines changed or added


 random_forest.hxx   random_forest.hxx 
skipping to change at line 57 skipping to change at line 57
#include "sized_int.hxx" #include "sized_int.hxx"
#include "matrix.hxx" #include "matrix.hxx"
#include "random.hxx" #include "random.hxx"
#include "functorexpression.hxx" #include "functorexpression.hxx"
#include "random_forest/rf_common.hxx" #include "random_forest/rf_common.hxx"
#include "random_forest/rf_nodeproxy.hxx" #include "random_forest/rf_nodeproxy.hxx"
#include "random_forest/rf_split.hxx" #include "random_forest/rf_split.hxx"
#include "random_forest/rf_decisionTree.hxx" #include "random_forest/rf_decisionTree.hxx"
#include "random_forest/rf_visitors.hxx" #include "random_forest/rf_visitors.hxx"
#include "random_forest/rf_region.hxx" #include "random_forest/rf_region.hxx"
#include "random_forest/rf_sampling.hxx" #include "sampling.hxx"
#include "random_forest/rf_preprocessing.hxx" #include "random_forest/rf_preprocessing.hxx"
#include "random_forest/rf_online_prediction_set.hxx" #include "random_forest/rf_online_prediction_set.hxx"
#include "random_forest/rf_earlystopping.hxx" #include "random_forest/rf_earlystopping.hxx"
#include "random_forest/rf_ridge_split.hxx"
namespace vigra namespace vigra
{ {
/** \addtogroup MachineLearning Machine Learning /** \addtogroup MachineLearning Machine Learning
This module provides classification algorithms that map This module provides classification algorithms that map
features to labels or label probablities. features to labels or label probabilities.
Look at the RandomForest class first for a overview of most of the
functionality provided as well as use cases.
**/ **/
//@{ //@{
namespace detail namespace detail
{ {
/* todo - remove and make the labels parameter in the sampling options
* const*/
class staticMultiArrayViewHelper
{
public:
static vigra::MultiArrayView<2, Int32> array;
public:
friend SamplingOptions
createSamplingOptions(vigra::RandomForestOptions& RF_opt,
vigra::MultiArrayView<2, int> & labels);
};
/* \brief sampling option factory function /* \brief sampling option factory function
*/ */
SamplingOptions make_sampler_opt ( RF_Traits::Options_t & RF_opt, inline SamplerOptions make_sampler_opt ( RandomForestOptions & RF_opt)
MultiArrayView<2, Int32> & labels
= staticMultiArrayViewHelper::array
)
{ {
SamplingOptions return_opt; SamplerOptions return_opt;
return_opt.sample_with_replacement = RF_opt.sample_with_replacement_; return_opt.withReplacement(RF_opt.sample_with_replacement_);
if(labels.data() != 0) return_opt.stratified(RF_opt.stratification_method_ == RF_EQUAL);
{
if(RF_opt.stratification_method_ == RF_EQUAL)
return_opt
.sampleClassesIndividually(
ArrayVectorView<int>(labels.size(),
labels.data()));
else if(RF_opt.stratification_method_ == RF_PROPORTIONAL)
return_opt
.sampleStratified(
ArrayVectorView<int>(labels.size(),
labels.data()));
}
return return_opt; return return_opt;
} }
}//namespace detail }//namespace detail
/** Random Forest class /** Random Forest class
* *
* \tparam <PrprocessorTag = ClassificationTag> Class used to preprocess * \tparam <PrprocessorTag = 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, How to make a Split Functor * \sa Preprocessor
*
* simple usage for classification (regression is not yet supported):
* look at RandomForest::learn() as well as RandomForestOptions() for addi
tional
* options.
*
* \code
* using namespace vigra;
* using namespace rf;
* typedef xxx feature_t; \\ replace xxx with whichever type
* typedef yyy label_t; \\ likewise
*
* // allocate the training data
* MultiArrayView<2, feature_t> f = get_training_features();
* MultiArrayView<2, label_t> l = get_training_labels();
*
* RandomForest<> rf;
*
* // construct visitor to calculate out-of-bag error
* visitors::OOB_Error oob_v;
*
* // perform training
* rf.learn(f, l, visitors::create_visitor(oob_v));
*
* std::cout << "the out-of-bag error is: " << oob_v.oob_breiman << "\n";
*
* // get features for new data to be used for prediction
* MultiArrayView<2, feature_t> pf = get_features();
*
* // 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, double> prob(pf.shape(0), rf.class_count());
*
* // perform prediction on new data
* rf.predict_labels(pf, prediction);
* rf.predict_probabilities(pf, prob);
* *
* \endcode
* *
* Additional information such as Variable Importance measures are accesse
d
* via Visitors defined in rf::visitors.
* Have a look at rf::split for other splitting methods.
* *
*/ */
template <class LabelType , class PreprocessorTag > template <class LabelType = double , class PreprocessorTag = Classification Tag >
class RandomForest class RandomForest
{ {
public: public:
//public typedefs //public typedefs
typedef RF_Traits::Options_t Options_t; typedef RandomForestOptions Options_t;
typedef RF_Traits::DecisionTree_t DecisionTree_t; typedef detail::DecisionTree DecisionTree_t;
typedef ProblemSpec<LabelType> ProblemSpec_t; typedef ProblemSpec<LabelType> ProblemSpec_t;
typedef RF_Traits::Default_Split_t Default_Split_t; typedef GiniSplit Default_Split_t;
typedef RF_Traits::Default_Stop_t Default_Stop_t; typedef EarlyStoppStd Default_Stop_t;
typedef RF_Traits::Default_Visitor_t Default_Visitor_t; typedef rf::visitors::StopVisiting Default_Visitor_t;
typedef DT_StackEntry<ArrayVectorView<Int32>::iterator>
StackEntry_t;
typedef LabelType LabelT; typedef LabelType LabelT;
protected: protected:
/** optimisation for predictLabels /** optimisation for predictLabels
* */ * */
mutable MultiArray<2, double> garbage_prediction_; mutable MultiArray<2, double> garbage_prediction_;
public: 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> ArrayVector<DecisionTree_t> trees_;
trees_; ProblemSpec_t ext_param_;
ProblemSpec_t ext_param_; /*mutable ArrayVector<int> tree_indices_;*/
mutable ArrayVector<int> tree_indices_; rf::visitors::OnlineLearnVisitor online_visitor_;
OnlineLearnVisitor online_visitor_;
void reset() void reset()
{ {
ext_param_.clear(); ext_param_.clear();
trees_.clear(); trees_.clear();
} }
public: public:
/** \name Contructors /** \name Constructors
* Note: No copy Constructor specified as no pointers are manipulated * Note: No copy Constructor specified as no pointers are manipulated
* in this class * in this class
*/ */
/*\{*/ /*\{*/
/**\brief default constructor /**\brief default constructor
* *
* \param options general options to the Random Forest. Must be of Ty pe * \param options general options to the Random Forest. Must be of Ty pe
* Options_t * Options_t
* \param ext_param problem specific values that can be supplied * \param ext_param problem specific values that can be supplied
* additionally. (class weights , labels etc) * additionally. (class weights , labels etc)
* \sa ProblemSpec_t * \sa RandomForestOptions, ProblemSpec
*
*
* simple usage for classification (regression is not yet supported):
* \code
* typedef xxx feature_t \\ replace xxx with whichever type
* typedef yyy label_t \\ meme chose.
* MultiArrayView<2, feature_t> f = get_some_features();
* MultiArrayView<2, label_t> l = get_some_labels)(
* RandomForest<> rf()
* double oob_error = rf.learn(f, l);
*
* MultiArrayView<2, feature_t> pf = get_some_unknown_features();
* MultiArrayView<2, label_t> prediction
* = allocate_space_for_response()
;
* MultiArrayView<2, double> prob = allocate_space_for_probabilit
y();
*
* rf.predict_labels(pf, prediction);
* rf.predict_probabilities(pf, prob);
*
* \endcode
* *
* - Default Response/Label type is double
*/ */
RandomForest(Options_t const & options = Options_t(), RandomForest(Options_t const & options = Options_t(),
ProblemSpec_t const & ext_param = ProblemSpec_t()) ProblemSpec_t const & ext_param = ProblemSpec_t())
: :
options_(options), options_(options),
ext_param_(ext_param), ext_param_(ext_param)/*,
tree_indices_(options.tree_count_,0) tree_indices_(options.tree_count_,0)*/
{ {
for(int ii = 0 ; ii < int(tree_indices_.size()); ++ii) /*for(int ii = 0 ; ii < int(tree_indices_.size()); ++ii)
tree_indices_[ii] = ii; tree_indices_[ii] = ii;*/
} }
/**\brief Create RF from external source /**\brief Create RF from external source
* \param treeCount Number of trees to add. * \param treeCount Number of trees to add.
* \param trees Iterator to a Container where the topology_ data * \param topology_begin
* of the trees are stored. * Iterator to a Container where the topology_ data
* \param weights iterator to a Container where the parameters_ data
* of the trees are stored. * of the trees are stored.
* Iterator should support at least treeCount forward
* iterations. (i.e. topology_end - topology_begin >=
treeCount
* \param parameter_begin
* iterator to a Container where the parameters_ data
* of the trees are stored. Iterator should support at
* least treeCount forward iterations.
* \param problem_spec * \param problem_spec
* Extrinsic parameters that specify the problem e.g. * Extrinsic parameters that specify the problem e.g.
* ClassCount, featureCount etc. * ClassCount, featureCount etc.
* \param options (optional) specify options used to train the origin al * \param options (optional) specify options used to train the origin al
* Random forest. This parameter is not used anywhere * Random forest. This parameter is not used anywhere
* during prediction and thus is optional. * during prediction and thus is optional.
* *
* TODO: */
* Note: This constructor may be replaced by a Constructor using /* TODO: This constructor may be replaced by a Constructor using
* NodeProxy iterators to encapsulate the underlying data type. * NodeProxy iterators to encapsulate the underlying data type.
*/ */
template<class TreeIterator, class WeightIterator> template<class TopologyIterator, class ParameterIterator>
RandomForest(int treeCount, RandomForest(int treeCount,
TreeIterator trees, TopologyIterator topology_begin,
WeightIterator weights, ParameterIterator parameter_begin,
ProblemSpec_t const & problem_spec, ProblemSpec_t const & problem_spec,
Options_t const & options = Options_t()) Options_t const & options = Options_t())
: :
trees_(treeCount, DecisionTree_t(problem_spec)), trees_(treeCount, DecisionTree_t(problem_spec)),
ext_param_(problem_spec), ext_param_(problem_spec),
options_(options) options_(options)
{ {
for(unsigned int k=0; k<treeCount; ++k, ++trees, ++weights) for(unsigned int k=0; k<treeCount; ++k, ++topology_begin, ++paramet er_begin)
{ {
trees_[k].topology_ = *trees; trees_[k].topology_ = *topology_begin;
trees_[k].parameters_ = *weights; trees_[k].parameters_ = *parameter_begin;
} }
} }
/*\}*/ /*\}*/
/** \name Data Access /** \name Data Access
* data access interface - usage of member objects is deprecated * data access interface - usage of member variables is deprecated
* (I like the word deprecated)
*/ */
/*\{*/ /*\{*/
/**\brief return external parameters for viewing /**\brief return external parameters for viewing
* \return ProblemSpec_t * \return ProblemSpec_t
*/ */
ProblemSpec_t const & ext_param() const ProblemSpec_t const & ext_param() const
{ {
vigra_precondition(ext_param_.used() == true, vigra_precondition(ext_param_.used() == true,
skipping to change at line 273 skipping to change at line 273
/**\brief set external parameters /**\brief set external parameters
* *
* \param in external parameters to be set * \param in external parameters to be set
* *
* set external parameters explicitly. * set external parameters explicitly.
* If Random Forest has not been trained the preprocessor will * If Random Forest has not been trained the preprocessor will
* either ignore filling values set this way or will throw an exception * either ignore filling values set this way or will throw an exception
* if values specified manually do not match the value calculated * if values specified manually do not match the value calculated
& during the preparation step. & during the preparation step.
* \sa Option_t::presupplied_ext_param member for further details.
*/ */
void set_ext_param(ProblemSpec_t const & in) void set_ext_param(ProblemSpec_t const & in)
{ {
vigra_precondition(ext_param_.used() == false, vigra_precondition(ext_param_.used() == false,
"RandomForest::set_ext_param():" "RandomForest::set_ext_param():"
"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
skipping to change at line 316 skipping to change at line 315
} }
/**\brief access trees /**\brief access trees
*/ */
DecisionTree_t & tree(int index) DecisionTree_t & tree(int index)
{ {
return trees_[index]; return trees_[index];
} }
/*\}*/ /*\}*/
/**\brief return number of features used while
* training.
*/
int feature_count() const
{
return ext_param_.column_count_;
}
/**\brief return number of features used while
* training.
*
* deprecated. Use feature_count() instead.
*/
int column_count() const int column_count() const
{ {
return ext_param_.column_count_; return ext_param_.column_count_;
} }
/**\brief return number of classes used while
* training.
*/
int class_count() const int class_count() const
{ {
return ext_param_.class_count_; return ext_param_.class_count_;
} }
/**\brief return number of trees
*/
int tree_count() const int tree_count() const
{ {
return options_.tree_count_; return options_.tree_count_;
} }
template<class U,class C1,
class U2, class C2,
class Split_t,
class Stop_t,
class Visitor_t,
class Random_t>
void onlineLearn( MultiArrayView<2,U,C1> const & features,
MultiArrayView<2,U2,C2> const & response,
int new_start_index,
Visitor_t visitor_,
Split_t split_,
Stop_t stop_,
Random_t & random,
bool adjust_thresholds=false);
template <class U, class C1, class U2,class C2>
void onlineLearn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & labels,int new_st
art_index,bool adjust_thresholds=false)
{
RandomNumberGenerator<> rnd = RandomNumberGenerator<>(RandomSeed);
onlineLearn(features,
labels,
new_start_index,
rf_default(),
rf_default(),
rf_default(),
rnd,
adjust_thresholds);
}
template<class U,class C1,
class U2, class C2,
class Split_t,
class Stop_t,
class Visitor_t,
class Random_t>
void reLearnTree(MultiArrayView<2,U,C1> const & features,
MultiArrayView<2,U2,C2> const & response,
int treeId,
Visitor_t visitor_,
Split_t split_,
Stop_t stop_,
Random_t & random);
template<class U, class C1, class U2, class C2>
void reLearnTree(MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2, C2> const & labels,
int treeId)
{
RandomNumberGenerator<> rnd = RandomNumberGenerator<>(RandomSeed);
reLearnTree(features,
labels,
treeId,
rf_default(),
rf_default(),
rf_default(),
rnd);
}
/**\name Learning /**\name Learning
* Following functions differ in the degree of customization * Following functions differ in the degree of customization
* allowed * allowed
*/ */
/*\{*/ /*\{*/
/**\brief learn on data with custom config and random number generator /**\brief learn on data with custom config and random number generator
* *
* \param features a N x M matrix containing N samples with M * \param features a N x M matrix containing N samples with M
* features * features
* \param response a N x D matrix containing the corresponding * \param response a N x D matrix containing the corresponding
* 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.
* \sa 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. * default value. (No Visitors)
* \sa visitor * 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. * use rf_default() for using default value. (GiniSpli
t)
* 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. * 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. * rf_default() to use default value.(RandomMT19337)
* \return oob_error.
* *
*\sa OOB_Visitor, VariableImportanceVisitor
* *
*/ */
template <class U, class C1, template <class U, class C1,
class U2,class C2, class U2,class C2,
class Split_t, class Split_t,
class Stop_t, class Stop_t,
class Visitor_t, class Visitor_t,
class Random_t> class Random_t>
double learn( MultiArrayView<2, U, C1> const & features, void learn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & response, MultiArrayView<2, U2,C2> const & response,
Visitor_t visitor, Visitor_t visitor,
Split_t split, Split_t split,
Stop_t stop, Stop_t stop,
Random_t const & random); Random_t const & random);
template <class U, class C1, template <class U, class C1,
class U2,class C2, class U2,class C2,
class Split_t, class Split_t,
class Stop_t, class Stop_t,
class Visitor_t> class Visitor_t>
double learn( MultiArrayView<2, U, C1> const & features, void learn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & response, MultiArrayView<2, U2,C2> const & response,
Visitor_t visitor, Visitor_t visitor,
Split_t split, Split_t split,
Stop_t stop) Stop_t stop)
{
RandomNumberGenerator<> rnd = RandomNumberGenerator<>(RandomSeed);
return learn(features, response,
visitor, split, stop,
rnd);
}
template<class U,class C1,
class U2, class C2,
class Split_t,
class Stop_t,
class Visitor_t,
class Random_t>
double onlineLearn(MultiArrayView<2,U,C1> const & features,
MultiArrayView<2,U2,C2> const & response,
int new_start_index,
Visitor_t visitor_,
Split_t split_,
Stop_t stop_,
Random_t & random,
bool adjust_thresholds=false);
template <class U, class C1, class U2,class C2>
double onlineLearn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & labels,int new_start_
index,bool adjust_thresholds=false)
{
RandomNumberGenerator<> rnd = RandomNumberGenerator<>(RandomSeed);
return onlineLearn(features,
labels,
new_start_index,
rf_default(),
rf_default(),
rf_default(),
rnd,
adjust_thresholds);
}
template<class U,class C1,
class U2, class C2,
class Split_t,
class Stop_t,
class Visitor_t,
class Random_t>
void reLearnTree(MultiArrayView<2,U,C1> const & features,
MultiArrayView<2,U2,C2> const & response,
int treeId,
Visitor_t visitor_,
Split_t split_,
Stop_t stop_,
Random_t & random);
template<class U, class C1, class U2, class C2>
void reLearnTree(MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2, C2> const & labels,
int treeId)
{ {
RandomNumberGenerator<> rnd = RandomNumberGenerator<>(RandomSeed); RandomNumberGenerator<> rnd = RandomNumberGenerator<>(RandomSeed);
reLearnTree(features, learn( features,
labels, response,
treeId, visitor,
rf_default(), split,
rf_default(), stop,
rf_default(), rnd);
rnd);
} }
template <class U, class C1, class U2,class C2, class Visitor_t> template <class U, class C1, class U2,class C2, class Visitor_t>
double learn( MultiArrayView<2, U, C1> const & features, void learn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & labels, MultiArrayView<2, U2,C2> const & labels,
Visitor_t visitor) Visitor_t visitor)
{ {
return learn(features, learn( features,
labels, labels,
visitor, visitor,
rf_default(), rf_default(),
rf_default()); rf_default());
} }
template <class U, class C1, class U2,class C2, template <class U, class C1, class U2,class C2,
class Visitor_t, class Split_t> class Visitor_t, class Split_t>
double learn( MultiArrayView<2, U, C1> const & features, void learn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & labels, MultiArrayView<2, U2,C2> const & labels,
Visitor_t visitor, Visitor_t visitor,
Split_t split) Split_t split)
{ {
return learn(features, learn( features,
labels, labels,
visitor, visitor,
split, split,
rf_default()); rf_default());
} }
/**\brief learn on data with default configuration /**\brief learn on data with default configuration
* *
* \param features a N x M matrix containing N samples with M * \param features a N x M matrix containing N samples with M
* features * features
* \param labels a N x D matrix containing the corresponding * \param labels a N x D matrix containing the corresponding
* N labels. Current split functors assume D to * N labels. 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. * for uncertain labels.
* \return out of bag error estimate.
* *
* learning is done with: * learning is done with:
* *
* \sa GiniSplit, EarlyStoppingStd, OOB_Visitor * \sa rf::split, EarlyStoppStd
* *
* - Randomly seeded random number generator * - Randomly seeded random number generator
* - default gini split functor as described by Breiman * - default gini split functor as described by Breiman
* - default The standard early stopping criterion * - default The standard early stopping criterion
* - the oob visitor, whose value is returned.
*/ */
template <class U, class C1, class U2,class C2> template <class U, class C1, class U2,class C2>
double learn( MultiArrayView<2, U, C1> const & features, void learn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & labels) MultiArrayView<2, U2,C2> const & labels)
{ {
return learn(features, learn( features,
labels, labels,
rf_default(), rf_default(),
rf_default(), rf_default(),
rf_default()); rf_default());
} }
/*\}*/ /*\}*/
/**\name prediction /**\name prediction
*/ */
/*\{*/ /*\{*/
/** \brief predict a label given a feature. /** \brief predict a label given a feature.
* *
* \param features: a 1 by featureCount matrix containing * \param features: a 1 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 stop: early stopping critierion * \param stop: early stopping criterion
* \return double value representing class. You can use the * \return double value representing class. You can use the
* predictLabels() function together with the * predictLabels() function together with the
* rf.external_parameter().class_type_ attribute * rf.external_parameter().class_type_ attribute
* to get back the same type used during learning. * to get back the same type used during learning.
*/ */
template <class U, class C, class Stop> template <class U, class C, class Stop>
LabelType predictLabel(MultiArrayView<2, U, C>const & features, Stop & stop) const; LabelType predictLabel(MultiArrayView<2, U, C>const & features, Stop & stop) const;
template <class U, class C> template <class U, class C>
LabelType predictLabel(MultiArrayView<2, U, C>const & features) LabelType predictLabel(MultiArrayView<2, U, C>const & features)
skipping to change at line 603 skipping to change at line 621
* \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
*/ */
template <class U, class C1, class T, class C2> template <class U, class C1, class T, class C2>
void predictProbabilities(MultiArrayView<2, U, C1>const & features, void predictProbabilities(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & prob) cons t MultiArrayView<2, T, C2> & prob) cons t
{ {
predictProbabilities(features, prob, rf_default()); predictProbabilities(features, prob, rf_default());
} }
template <class U, class C1, class T, class C2>
void predictRaw(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & prob) const;
/*\}*/ /*\}*/
}; };
template <class LabelType, class PreprocessorTag> template <class LabelType, class PreprocessorTag>
template<class U,class C1, template<class U,class C1,
class U2, class C2, class U2, class C2,
class Split_t, class Split_t,
class Stop_t, class Stop_t,
class Visitor_t, class Visitor_t,
class Random_t> class Random_t>
double RandomForest<LabelType, PreprocessorTag>::onlineLearn(MultiArrayView <2,U,C1> const & features, void RandomForest<LabelType, PreprocessorTag>::onlineLearn(MultiArrayView<2 ,U,C1> const & features,
MultiArrayView <2,U2,C2> const & response, MultiArrayView <2,U2,C2> const & response,
int new_start_ index, int new_start_ index,
Visitor_t visi tor_, Visitor_t visi tor_,
Split_t split_ , Split_t split_ ,
Stop_t stop_, Stop_t stop_,
Random_t & ran dom, Random_t & ran dom,
bool adjust_th resholds) bool adjust_th resholds)
{ {
online_visitor_.activate(); online_visitor_.activate();
online_visitor_.adjust_thresholds=adjust_thresholds; online_visitor_.adjust_thresholds=adjust_thresholds;
using namespace rf; using namespace rf;
//typedefs //typedefs
typedef typename Split_t::StackEntry_t StackEntry_t;
typedef Processor<PreprocessorTag,LabelType,U,C1,U2,C2> Preprocessor_t; typedef Processor<PreprocessorTag,LabelType,U,C1,U2,C2> Preprocessor_t;
typedef UniformIntRandomFunctor<Random_t> typedef UniformIntRandomFunctor<Random_t>
RandFunctor_t; RandFunctor_t;
// 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);
StopVisiting stopvisiting; rf::visitors::StopVisiting stopvisiting;
OOB_Visitor oob; typedef rf::visitors::detail::VisitorNode
typedef VisitorNode<OnlineLearnVisitor, typename RF_CHOOSER(Visitor_t) <rf::visitors::OnlineLearnVisitor,
::type> IntermedVis; typename RF_CHOOSER(Visitor_t)::type>
IntermedVis;
IntermedVis IntermedVis
inter(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, stop visitor(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, st
visiting)); opvisiting));
VisitorNode<OOB_Visitor, IntermedVis>
visitor(oob,inter);
#undef RF_CHOOSER #undef RF_CHOOSER
// 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_);
skipping to change at line 741 skipping to change at line 762
/*visitor /*visitor
.visit_after_tree( *this, .visit_after_tree( *this,
preprocessor, preprocessor,
poisson_sampler, poisson_sampler,
stack_entry, stack_entry,
ii);*/ ii);*/
} }
//visitor.visit_at_end(*this, preprocessor); //visitor.visit_at_end(*this, preprocessor);
online_visitor_.deactivate(); online_visitor_.deactivate();
return visitor.return_val();
} }
template<class LabelType, class PreprocessorTag> template<class LabelType, class PreprocessorTag>
template<class U,class C1, template<class U,class C1,
class U2, class C2, class U2, class C2,
class Split_t, class Split_t,
class Stop_t, class Stop_t,
class Visitor_t, class Visitor_t,
class Random_t> class Random_t>
void RandomForest<LabelType, PreprocessorTag>::reLearnTree(MultiArrayView<2 ,U,C1> const & features, void RandomForest<LabelType, PreprocessorTag>::reLearnTree(MultiArrayView<2 ,U,C1> const & features,
MultiArrayView<2,U2,C2> const & response, MultiArrayView<2,U2,C2> const & response,
int treeId, int treeId,
Visitor_t visitor_, Visitor_t visitor_,
Split_t split_, Split_t split_,
Stop_t stop_, Stop_t stop_,
Random_t & random) Random_t & random)
{ {
using namespace rf; using namespace rf;
//We store as a local variable, beacause there is no global interest ?!
?
typedef typename Split_t::StackEntry_t StackEntry_t;
typedef UniformIntRandomFunctor<Random_t> typedef UniformIntRandomFunctor<Random_t>
RandFunctor_t; RandFunctor_t;
// See rf_preprocessing.hxx for more info on this // See rf_preprocessing.hxx for more info on this
ext_param_.class_count_=0; ext_param_.class_count_=0;
typedef Processor<PreprocessorTag,LabelType, U, C1, U2, C2> Preprocesso r_t; typedef Processor<PreprocessorTag,LabelType, U, C1, U2, C2> Preprocesso r_t;
// 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);
StopVisiting stopvisiting; rf::visitors::StopVisiting stopvisiting;
OOB_Visitor oob; typedef rf::visitors::detail::VisitorNode
typedef VisitorNode<OnlineLearnVisitor, typename RF_CHOOSER(Visitor_t) <rf::visitors::OnlineLearnVisitor,
::type> IntermedVis; typename RF_CHOOSER(Visitor_t)::type> IntermedVis;
IntermedVis IntermedVis
inter(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, stop visitor(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, st
visiting)); opvisiting));
VisitorNode<OOB_Visitor, IntermedVis>
visitor(oob,inter);
#undef RF_CHOOSER #undef RF_CHOOSER
vigra_precondition(options_.prepare_online_learning_,"reLearnTree: Re l earning trees only makes sense, if online learning is enabled"); vigra_precondition(options_.prepare_online_learning_,"reLearnTree: Re l earning trees only makes sense, if online learning is enabled");
online_visitor_.activate(); online_visitor_.activate();
// Make stl compatible random functor. // Make stl compatible random functor.
RandFunctor_t randint ( random); RandFunctor_t randint ( random);
// 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
skipping to change at line 811 skipping to change at line 828
options_, ext_param_); options_, ext_param_);
// Give the Split functor information about the data. // Give the Split functor information about the data.
split.set_external_parameters(ext_param_); split.set_external_parameters(ext_param_);
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<RandFunctor_t > sampler(ext_param().row_count_, Sampler<Random_t > sampler(preprocessor.strata().begin(),
ext_param().actual_msample_, preprocessor.strata().end(),
detail::make_sampler_opt(options_, detail::make_sampler_opt(options_)
preprocessor.strata()) .sampleSize(ext_param().actual_msam
, ple_),
randint); 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.used_indices().begin(), first_stack_entry( sampler.sampledIndices().begin(),
sampler.used_indices().end(), sampler.sampledIndices().end(),
ext_param_.class_count_); ext_param_.class_count_);
first_stack_entry first_stack_entry
.set_oob_range( sampler.unused_indices().begin(), .set_oob_range( sampler.oobIndices().begin(),
sampler.unused_indices().end()); sampler.oobIndices().end());
online_visitor_.reset_tree(treeId); online_visitor_.reset_tree(treeId);
online_visitor_.tree_id=treeId; online_visitor_.tree_id=treeId;
trees_[treeId].reset(); trees_[treeId].reset();
trees_[treeId] trees_[treeId]
.learn( preprocessor.features(), .learn( preprocessor.features(),
preprocessor.response(), preprocessor.response(),
first_stack_entry, first_stack_entry,
split, split,
stop, stop,
visitor, visitor,
skipping to change at line 856 skipping to change at line 872
online_visitor_.deactivate(); online_visitor_.deactivate();
} }
template <class LabelType, class PreprocessorTag> template <class LabelType, class PreprocessorTag>
template <class U, class C1, template <class U, class C1,
class U2,class C2, class U2,class C2,
class Split_t, class Split_t,
class Stop_t, class Stop_t,
class Visitor_t, class Visitor_t,
class Random_t> class Random_t>
double RandomForest<LabelType, PreprocessorTag>:: void RandomForest<LabelType, PreprocessorTag>::
learn( MultiArrayView<2, U, C1> const & features, learn( MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, U2,C2> const & response, MultiArrayView<2, U2,C2> const & response,
Visitor_t visitor_, Visitor_t visitor_,
Split_t split_, Split_t split_,
Stop_t stop_, Stop_t stop_,
Random_t const & random) Random_t const & random)
{ {
using namespace rf; using namespace rf;
//this->reset(); //this->reset();
//typedefs //typedefs
typedef typename Split_t::StackEntry_t StackEntry_t;
typedef UniformIntRandomFunctor<Random_t> typedef UniformIntRandomFunctor<Random_t>
RandFunctor_t; RandFunctor_t;
// 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),
"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);
StopVisiting stopvisiting; rf::visitors::StopVisiting stopvisiting;
OOB_Visitor oob; typedef rf::visitors::detail::VisitorNode<
typedef VisitorNode<OnlineLearnVisitor, typename RF_CHOOSER(Visitor_t) rf::visitors::OnlineLearnVisitor,
::type> IntermedVis; typename RF_CHOOSER(Visitor_t)::type> IntermedVis;
IntermedVis IntermedVis
inter(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, stop visitor(online_visitor_, RF_CHOOSER(Visitor_t)::choose(visitor_, st
visiting)); opvisiting));
VisitorNode<OOB_Visitor, IntermedVis>
visitor(oob,inter);
#undef RF_CHOOSER #undef RF_CHOOSER
if(options_.prepare_online_learning_) if(options_.prepare_online_learning_)
online_visitor_.activate(); online_visitor_.activate();
else else
online_visitor_.deactivate(); online_visitor_.deactivate();
// Make stl compatible random functor. // Make stl compatible random functor.
RandFunctor_t randint ( random); RandFunctor_t randint ( random);
// Preprocess the data to get something the split functor can work // Preprocess the data to get something the split functor can work
skipping to change at line 916 skipping to change at line 933
Preprocessor_t preprocessor( features, response, Preprocessor_t preprocessor( features, response,
options_, ext_param_); options_, ext_param_);
// Give the Split functor information about the data. // Give the Split functor information about the data.
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_));
/**\todo replace this crappy class out. It uses function pointers. Sampler<Random_t > sampler(preprocessor.strata().begin(),
* and is making code slower according to me preprocessor.strata().end(),
*/ detail::make_sampler_opt(options_)
Sampler<RandFunctor_t > sampler(ext_param().actual_msample_, .sampleSize(ext_param().actual_msam
ext_param().row_count_, ple_),
detail::make_sampler_opt(options_, random);
preprocessor.strata())
,
randint);
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 < (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.used_indices().begin(), first_stack_entry( sampler.sampledIndices().begin(),
sampler.used_indices().end(), sampler.sampledIndices().end(),
ext_param_.class_count_); ext_param_.class_count_);
first_stack_entry first_stack_entry
.set_oob_range( sampler.unused_indices().begin(), .set_oob_range( sampler.oobIndices().begin(),
sampler.unused_indices().end()); sampler.oobIndices().end());
trees_[ii] trees_[ii]
.learn( preprocessor.features(), .learn( preprocessor.features(),
preprocessor.response(), preprocessor.response(),
first_stack_entry, first_stack_entry,
split, split,
stop, stop,
visitor, visitor,
randint); randint);
visitor visitor
.visit_after_tree( *this, .visit_after_tree( *this,
preprocessor, preprocessor,
sampler, sampler,
first_stack_entry, first_stack_entry,
ii); ii);
} }
visitor.visit_at_end(*this, preprocessor); visitor.visit_at_end(*this, preprocessor);
// Only for online learning?
online_visitor_.deactivate(); online_visitor_.deactivate();
return visitor.return_val();
} }
template <class LabelType, class Tag> template <class LabelType, class Tag>
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.");
skipping to change at line 1011 skipping to change at line 1024
return d; return d;
} }
template<class LabelType,class PreprocessorTag> template<class LabelType,class PreprocessorTag>
template <class T1,class T2, class C> template <class T1,class T2, class C>
void RandomForest<LabelType,PreprocessorTag> void RandomForest<LabelType,PreprocessorTag>
::predictProbabilities(OnlinePredictionSet<T1> & predictionSet, ::predictProbabilities(OnlinePredictionSet<T1> & predictionSet,
MultiArrayView<2, T2, C> & prob) MultiArrayView<2, T2, C> & prob)
{ {
//Features are n xp //Features are n xp
//prob is n x NumOfLabel probaility for each feature in each class //prob is n x NumOfLabel probability for each feature in each class
vigra_precondition(rowCount(predictionSet.features) == rowCount(prob), vigra_precondition(rowCount(predictionSet.features) == rowCount(prob),
"RandomFroest::predictProbabilities():" "RandomFroest::predictProbabilities():"
" Feature matrix and probability matrix size misnmat ch."); " 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_, == (MultiArrayIndex)ext_param_.class_count_,
"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);
skipping to change at line 1039 skipping to change at line 1052
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();
typedef std::set<SampleRange<T1> > my_set; typedef std::set<SampleRange<T1> > my_set;
typedef typename my_set::iterator set_it; typedef typename my_set::iterator set_it;
//typedef std::set<std::pair<int,SampleRange<T1> > >::iterator set_ it; //typedef std::set<std::pair<int,SampleRange<T1> > >::iterator set_ it;
//Build a stack with all the ranges we have //Build a stack with all the ranges we have
std::vector<std::pair<int,set_it> > stack; std::vector<std::pair<int,set_it> > stack;
stack.clear(); stack.clear();
set_it i; for(set_it i=predictionSet.ranges[set_id].begin();
for(i=predictionSet.ranges[set_id].begin();i!=predictionSet.ranges[ i!=predictionSet.ranges[set_id].end();++i)
set_id].end();++i)
stack.push_back(std::pair<int,set_it>(2,i)); stack.push_back(std::pair<int,set_it>(2,i));
//get weights predicted by single tree //get weights predicted by single tree
int num_decisions=0; int num_decisions=0;
while(!stack.empty()) while(!stack.empty())
{ {
set_it range=stack.back().second; set_it range=stack.back().second;
int index=stack.back().first; int index=stack.back().first;
stack.pop_back(); stack.pop_back();
++num_decisions; ++num_decisions;
skipping to change at line 1176 skipping to change at line 1189
"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());
/* This code was originally there for testing early stopping
* - 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)
{ {
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_[tree_indices_[k]].predict(rowVector(features, 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) += (T)cur_w;
//every weight in totalWeight. //every weight in totalWeight.
totalWeight += cur_w; totalWeight += cur_w;
skipping to change at line 1223 skipping to change at line 1239
//Normalise votes in each row by total VoteCount (totalWeight //Normalise votes in each row by total VoteCount (totalWeight
for(int l=0; l< ext_param_.class_count_; ++l) for(int l=0; l< ext_param_.class_count_; ++l)
{ {
prob(row, l) /= detail::RequiresExplicitCast<T>::cast(totalWeig ht); prob(row, l) /= detail::RequiresExplicitCast<T>::cast(totalWeig ht);
} }
} }
} }
template <class LabelType, class PreprocessorTag>
template <class U, class C1, class T, class C2>
void RandomForest<LabelType, PreprocessorTag>
::predictRaw(MultiArrayView<2, U, C1>const & features,
MultiArrayView<2, T, C2> & prob) const
{
//Features are n xp
//prob is n x NumOfLabel probability for each feature in each class
vigra_precondition(rowCount(features) == rowCount(prob),
"RandomForestn::predictProbabilities():"
" Feature matrix and probability matrix size mismatch.");
// num of features must be bigger than num of features in Random forest
training
// but why bigger?
vigra_precondition( columnCount(features) >= ext_param_.column_count_,
"RandomForestn::predictProbabilities():"
" Too few columns in feature matrix.");
vigra_precondition( columnCount(prob)
== (MultiArrayIndex)ext_param_.class_count_,
"RandomForestn::predictProbabilities():"
" Probability matrix must have as many columns as there are classes."
);
#define RF_CHOOSER(type_) detail::Value_Chooser<type_, Default_##type_>
prob.init(NumericTraits<T>::zero());
/* This code was originally there for testing early stopping
* - we wanted the order of the trees to be randomized
if(tree_indices_.size() != 0)
{
std::random_shuffle(tree_indices_.begin(),
tree_indices_.end());
}
*/
//Classify for each row.
for(int row=0; row < rowCount(features); ++row)
{
ArrayVector<double>::const_iterator weights;
//totalWeight == totalVoteCount!
double totalWeight = 0.0;
//Let each tree classify...
for(int k=0; k<options_.tree_count_; ++k)
{
//get weights predicted by single tree
weights = trees_[k /*tree_indices_[k]*/].predict(rowVector(feat
ures, row));
//update votecount.
int weighted = options_.predict_weighted_;
for(int l=0; l<ext_param_.class_count_; ++l)
{
double cur_w = weights[l] * (weighted * (*(weights-1))
+ (1-weighted));
prob(row, l) += (T)cur_w;
//every weight in totalWeight.
totalWeight += cur_w;
}
}
}
prob/= options_.tree_count_;
}
//@} //@}
} // namespace vigra } // namespace vigra
#include "random_forest/rf_algorithm.hxx"
#endif // VIGRA_RANDOM_FOREST_HXX #endif // VIGRA_RANDOM_FOREST_HXX
 End of changes. 80 change blocks. 
266 lines changed or deleted 347 lines changed or added


 random_forest_deprec.hxx   random_forest_deprec.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 VIGRA_RANDOM_FOREST_HXX #ifndef VIGRA_RANDOM_FOREST_DEPREC_HXX
#define VIGRA_RANDOM_FOREST_HXX #define VIGRA_RANDOM_FOREST_DEPREC_HXX
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <iostream> #include <iostream>
#include <ctime>
#include <cstdlib>
#include "vigra/mathutil.hxx" #include "vigra/mathutil.hxx"
#include "vigra/array_vector.hxx" #include "vigra/array_vector.hxx"
#include "vigra/sized_int.hxx" #include "vigra/sized_int.hxx"
#include "vigra/matrix.hxx" #include "vigra/matrix.hxx"
#include "vigra/random.hxx" #include "vigra/random.hxx"
#include "vigra/functorexpression.hxx" #include "vigra/functorexpression.hxx"
#define RandomForest RandomForestDeprec
#define DecisionTree DecisionTreeDeprec
namespace vigra namespace vigra
{ {
/** \addtogroup MachineLearning /** \addtogroup MachineLearning
**/ **/
//@{ //@{
namespace detail namespace detail
{ {
template<class DataMatrix> template<class DataMatrix>
class RandomForestFeatureSorter class RandomForestDeprecFeatureSorter
{ {
DataMatrix const & data_; DataMatrix const & data_;
MultiArrayIndex sortColumn_; MultiArrayIndex sortColumn_;
public: public:
RandomForestFeatureSorter(DataMatrix const & data, MultiArrayIndex sort Column) RandomForestDeprecFeatureSorter(DataMatrix const & data, MultiArrayInde x sortColumn)
: data_(data), : data_(data),
sortColumn_(sortColumn) sortColumn_(sortColumn)
{} {}
void setColumn(MultiArrayIndex sortColumn) void setColumn(MultiArrayIndex sortColumn)
{ {
sortColumn_ = sortColumn; sortColumn_ = sortColumn;
} }
bool operator()(MultiArrayIndex l, MultiArrayIndex r) const bool operator()(MultiArrayIndex l, MultiArrayIndex r) const
{ {
return data_(l, sortColumn_) < data_(r, sortColumn_); return data_(l, sortColumn_) < data_(r, sortColumn_);
} }
}; };
template<class LabelArray> template<class LabelArray>
class RandomForestLabelSorter class RandomForestDeprecLabelSorter
{ {
LabelArray const & labels_; LabelArray const & labels_;
public: public:
RandomForestLabelSorter(LabelArray const & labels) RandomForestDeprecLabelSorter(LabelArray const & labels)
: labels_(labels) : labels_(labels)
{} {}
bool operator()(MultiArrayIndex l, MultiArrayIndex r) const bool operator()(MultiArrayIndex l, MultiArrayIndex r) const
{ {
return labels_[l] < labels_[r]; return labels_[l] < labels_[r];
} }
}; };
template <class CountArray> template <class CountArray>
class RandomForestClassCounter class RandomForestDeprecClassCounter
{ {
ArrayVector<int> const & labels_; ArrayVector<int> const & labels_;
CountArray & counts_; CountArray & counts_;
public: public:
RandomForestClassCounter(ArrayVector<int> const & labels, CountArray & counts) RandomForestDeprecClassCounter(ArrayVector<int> const & labels, CountAr ray & counts)
: labels_(labels), : labels_(labels),
counts_(counts) counts_(counts)
{ {
reset(); reset();
} }
void reset() void reset()
{ {
counts_.init(0); counts_.init(0);
} }
void operator()(MultiArrayIndex l) const void operator()(MultiArrayIndex l) const
{ {
++counts_[labels_[l]]; ++counts_[labels_[l]];
} }
}; };
struct DecisionTreeCountNonzeroFunctor struct DecisionTreeDeprecCountNonzeroFunctor
{ {
double operator()(double old, double other) const double operator()(double old, double other) const
{ {
if(other != 0.0) if(other != 0.0)
++old; ++old;
return old; return old;
} }
}; };
struct DecisionTreeNode struct DecisionTreeDeprecNode
{ {
DecisionTreeNode(int t, MultiArrayIndex bestColumn) DecisionTreeDeprecNode(int t, MultiArrayIndex bestColumn)
: thresholdIndex(t), splitColumn(bestColumn) : thresholdIndex(t), splitColumn(bestColumn)
{} {}
int children[2]; int children[2];
int thresholdIndex; int thresholdIndex;
Int32 splitColumn; Int32 splitColumn;
}; };
template <class INT> template <class INT>
struct DecisionTreeNodeProxy struct DecisionTreeDeprecNodeProxy
{ {
DecisionTreeNodeProxy(ArrayVector<INT> const & tree, INT n) DecisionTreeDeprecNodeProxy(ArrayVector<INT> const & tree, INT n)
: node(const_cast<ArrayVector<INT> &>(tree).begin()+n) : node(const_cast<ArrayVector<INT> &>(tree).begin()+n)
{} {}
INT & child(INT l) const INT & child(INT l) const
{ {
return node[l]; return node[l];
} }
INT & decisionWeightsIndex() const INT & decisionWeightsIndex() const
{ {
skipping to change at line 176 skipping to change at line 175
} }
typename ArrayVector<INT>::iterator decisionColumns() const typename ArrayVector<INT>::iterator decisionColumns() const
{ {
return node+3; return node+3;
} }
mutable typename ArrayVector<INT>::iterator node; mutable typename ArrayVector<INT>::iterator node;
}; };
struct DecisionTreeAxisSplitFunctor struct DecisionTreeDeprecAxisSplitFunctor
{ {
ArrayVector<Int32> splitColumns; ArrayVector<Int32> splitColumns;
ArrayVector<double> classCounts, currentCounts[2], bestCounts[2], class Weights; ArrayVector<double> classCounts, currentCounts[2], bestCounts[2], class Weights;
double threshold; double threshold;
double totalCounts[2], bestTotalCounts[2]; double totalCounts[2], bestTotalCounts[2];
int mtry, classCount, bestSplitColumn; int mtry, classCount, bestSplitColumn;
bool pure[2], isWeighted; bool pure[2], isWeighted;
void init(int mtry, int cols, int classCount, ArrayVector<double> const & weights) void init(int mtry, int cols, int classCount, ArrayVector<double> const & weights)
{ {
skipping to change at line 258 skipping to change at line 257
template <class U, class C, class IndexIterator, class Random> template <class U, class C, class IndexIterator, class Random>
IndexIterator findBestSplit(MultiArrayView<2, U, C> const & features, IndexIterator findBestSplit(MultiArrayView<2, U, C> const & features,
ArrayVector<int> const & labels, ArrayVector<int> const & labels,
IndexIterator indices, int exampleCount, IndexIterator indices, int exampleCount,
Random & randint); Random & randint);
}; };
template <class U, class C, class IndexIterator, class Random> template <class U, class C, class IndexIterator, class Random>
IndexIterator IndexIterator
DecisionTreeAxisSplitFunctor::findBestSplit(MultiArrayView<2, U, C> const & features, DecisionTreeDeprecAxisSplitFunctor::findBestSplit(MultiArrayView<2, U, C> c onst & features,
ArrayVector<int> const & labels , ArrayVector<int> const & labels ,
IndexIterator indices, int exam pleCount, IndexIterator indices, int exam pleCount,
Random & randint) Random & randint)
{ {
// select columns to be tried for split // select columns to be tried for split
for(int k=0; k<mtry; ++k) for(int k=0; k<mtry; ++k)
std::swap(splitColumns[k], splitColumns[k+randint(columnCount(featu res)-k)]); std::swap(splitColumns[k], splitColumns[k+randint(columnCount(featu res)-k)]);
RandomForestFeatureSorter<MultiArrayView<2, U, C> > sorter(features, 0) RandomForestDeprecFeatureSorter<MultiArrayView<2, U, C> > sorter(featur
; es, 0);
RandomForestClassCounter<ArrayVector<double> > counter(labels, classCou RandomForestDeprecClassCounter<ArrayVector<double> > counter(labels, cl
nts); assCounts);
std::for_each(indices, indices+exampleCount, counter); std::for_each(indices, indices+exampleCount, counter);
// find the best gini index // find the best gini index
double minGini = NumericTraits<double>::max(); double minGini = NumericTraits<double>::max();
IndexIterator bestSplit; IndexIterator bestSplit = indices;
for(int k=0; k<mtry; ++k) for(int k=0; k<mtry; ++k)
{ {
sorter.setColumn(splitColumns[k]); sorter.setColumn(splitColumns[k]);
std::sort(indices, indices+exampleCount, sorter); std::sort(indices, indices+exampleCount, sorter);
currentCounts[0].init(0); currentCounts[0].init(0);
std::transform(classCounts.begin(), classCounts.end(), classWeights .begin(), std::transform(classCounts.begin(), classCounts.end(), classWeights .begin(),
currentCounts[1].begin(), std::multiplies<double>()) ; currentCounts[1].begin(), std::multiplies<double>()) ;
totalCounts[0] = 0; totalCounts[0] = 0;
totalCounts[1] = std::accumulate(currentCounts[1].begin(), currentC ounts[1].end(), 0.0); totalCounts[1] = std::accumulate(currentCounts[1].begin(), currentC ounts[1].end(), 0.0);
for(int m = 0; m < exampleCount-1; ++m) for(int m = 0; m < exampleCount-1; ++m)
{ {
int label = labels[indices[m]]; int label = labels[indices[m]];
double w = classWeights[label]; double w = classWeights[label];
currentCounts[0][label] += w; currentCounts[0][label] += w;
totalCounts[0] += w; totalCounts[0] += w;
currentCounts[1][label] -= w; currentCounts[1][label] -= w;
totalCounts[1] -= w; totalCounts[1] -= w;
if (m < exampleCount-2 && if (m < exampleCount-2 &&
features(indices[m], splitColumns[k]) == features(indices[m +1], splitColumns[k])) features(indices[m], splitColumns[k]) == features(indices[m +1], splitColumns[k]))
continue ; continue ;
double gini = 0.0; double gini = 0.0;
if(classCount == 2) if(classCount == 2)
{ {
gini = currentCounts[0][0]*currentCounts[0][1] / totalCount s[0] + gini = currentCounts[0][0]*currentCounts[0][1] / totalCount s[0] +
currentCounts[1][0]*currentCounts[1][1] / totalCount s[1]; currentCounts[1][0]*currentCounts[1][1] / totalCount s[1];
} }
else else
{ {
for(int l=0; l<classCount; ++l) for(int l=0; l<classCount; ++l)
skipping to change at line 321 skipping to change at line 320
minGini = gini; minGini = gini;
bestSplit = indices+m; bestSplit = indices+m;
bestSplitColumn = splitColumns[k]; bestSplitColumn = splitColumns[k];
bestCounts[0] = currentCounts[0]; bestCounts[0] = currentCounts[0];
bestCounts[1] = currentCounts[1]; bestCounts[1] = currentCounts[1];
} }
} }
} }
//std::cerr << minGini << " " << bestSplitColumn << std::endl; //std::cerr << minGini << " " << bestSplitColumn << std::endl;
// split using the best feature // split using the best feature
sorter.setColumn(bestSplitColumn); sorter.setColumn(bestSplitColumn);
std::sort(indices, indices+exampleCount, sorter); std::sort(indices, indices+exampleCount, sorter);
for(int k=0; k<2; ++k) for(int k=0; k<2; ++k)
{ {
bestTotalCounts[k] = std::accumulate(bestCounts[k].begin(), bestCou nts[k].end(), 0.0); bestTotalCounts[k] = std::accumulate(bestCounts[k].begin(), bestCou nts[k].end(), 0.0);
} }
threshold = (features(bestSplit[0], bestSplitColumn) + features(bestSpl it[1], bestSplitColumn)) / 2.0; threshold = (features(bestSplit[0], bestSplitColumn) + features(bestSpl it[1], bestSplitColumn)) / 2.0;
++bestSplit; ++bestSplit;
counter.reset(); counter.reset();
std::for_each(indices, bestSplit, counter); std::for_each(indices, bestSplit, counter);
pure[0] = 1.0 == std::accumulate(classCounts.begin(), classCounts.end() , 0.0, DecisionTreeCountNonzeroFunctor()); pure[0] = 1.0 == std::accumulate(classCounts.begin(), classCounts.end() , 0.0, DecisionTreeDeprecCountNonzeroFunctor());
counter.reset(); counter.reset();
std::for_each(bestSplit, indices+exampleCount, counter); std::for_each(bestSplit, indices+exampleCount, counter);
pure[1] = 1.0 == std::accumulate(classCounts.begin(), classCounts.end() , 0.0, DecisionTreeCountNonzeroFunctor()); pure[1] = 1.0 == std::accumulate(classCounts.begin(), classCounts.end() , 0.0, DecisionTreeDeprecCountNonzeroFunctor());
return bestSplit; return bestSplit;
} }
enum { DecisionTreeNoParent = -1 }; enum { DecisionTreeDeprecNoParent = -1 };
template <class Iterator> template <class Iterator>
struct DecisionTreeStackEntry struct DecisionTreeDeprecStackEntry
{ {
DecisionTreeStackEntry(Iterator i, int c, DecisionTreeDeprecStackEntry(Iterator i, int c,
int lp = DecisionTreeNoParent, int rp = Decision int lp = DecisionTreeDeprecNoParent, int rp = De
TreeNoParent) cisionTreeDeprecNoParent)
: indices(i), exampleCount(c), : indices(i), exampleCount(c),
leftParent(lp), rightParent(rp) leftParent(lp), rightParent(rp)
{} {}
Iterator indices; Iterator indices;
int exampleCount, leftParent, rightParent; int exampleCount, leftParent, rightParent;
}; };
class DecisionTree class DecisionTreeDeprec
{ {
public: public:
typedef Int32 TreeInt; typedef Int32 TreeInt;
ArrayVector<TreeInt> tree_; ArrayVector<TreeInt> tree_;
ArrayVector<double> terminalWeights_; ArrayVector<double> terminalWeights_;
unsigned int classCount_; unsigned int classCount_;
DecisionTreeAxisSplitFunctor split; DecisionTreeDeprecAxisSplitFunctor split;
public: public:
DecisionTree(unsigned int classCount) DecisionTreeDeprec(unsigned int classCount)
: classCount_(classCount) : classCount_(classCount)
{} {}
void reset(unsigned int classCount = 0) void reset(unsigned int classCount = 0)
{ {
if(classCount) if(classCount)
classCount_ = classCount; classCount_ = classCount;
tree_.clear(); tree_.clear();
terminalWeights_.clear(); terminalWeights_.clear();
} }
skipping to change at line 395 skipping to change at line 394
Options const & options, Options const & options,
Random & randint); Random & randint);
template <class U, class C> template <class U, class C>
ArrayVector<double>::const_iterator ArrayVector<double>::const_iterator
predict(MultiArrayView<2, U, C> const & features) const predict(MultiArrayView<2, U, C> const & features) const
{ {
int nodeindex = 0; int nodeindex = 0;
for(;;) for(;;)
{ {
DecisionTreeNodeProxy<TreeInt> node(tree_, nodeindex); DecisionTreeDeprecNodeProxy<TreeInt> node(tree_, nodeindex);
nodeindex = split.decideAtNode(features, node.decisionColumns() , nodeindex = split.decideAtNode(features, node.decisionColumns() ,
terminalWeights_.begin() + node.deci sionWeightsIndex()) terminalWeights_.begin() + node.deci sionWeightsIndex())
? node.child(0) ? node.child(0)
: node.child(1); : node.child(1);
if(nodeindex <= 0) if(nodeindex <= 0)
return terminalWeights_.begin() + (-nodeindex); return terminalWeights_.begin() + (-nodeindex);
} }
} }
template <class U, class C> template <class U, class C>
skipping to change at line 420 skipping to change at line 419
return argMax(weights, weights+classCount_) - weights; return argMax(weights, weights+classCount_) - weights;
} }
template <class U, class C> template <class U, class C>
int int
leafID(MultiArrayView<2, U, C> const & features) const leafID(MultiArrayView<2, U, C> const & features) const
{ {
int nodeindex = 0; int nodeindex = 0;
for(;;) for(;;)
{ {
DecisionTreeNodeProxy<TreeInt> node(tree_, nodeindex); DecisionTreeDeprecNodeProxy<TreeInt> node(tree_, nodeindex);
nodeindex = split.decideAtNode(features, node.decisionColumns() , nodeindex = split.decideAtNode(features, node.decisionColumns() ,
terminalWeights_.begin() + node.deci sionWeightsIndex()) terminalWeights_.begin() + node.deci sionWeightsIndex())
? node.child(0) ? node.child(0)
: node.child(1); : node.child(1);
if(nodeindex <= 0) if(nodeindex <= 0)
return -nodeindex; return -nodeindex;
} }
} }
void depth(int & maxDep, int & interiorCount, int & leafCount, int k = 0, int d = 1) const void depth(int & maxDep, int & interiorCount, int & leafCount, int k = 0, int d = 1) const
{ {
DecisionTreeNodeProxy<TreeInt> node(tree_, k); DecisionTreeDeprecNodeProxy<TreeInt> node(tree_, k);
++interiorCount; ++interiorCount;
++d; ++d;
for(int l=0; l<2; ++l) for(int l=0; l<2; ++l)
{ {
int child = node.child(l); int child = node.child(l);
if(child > 0) if(child > 0)
depth(maxDep, interiorCount, leafCount, child, d); depth(maxDep, interiorCount, leafCount, child, d);
else else
{ {
++leafCount; ++leafCount;
skipping to change at line 461 skipping to change at line 460
int maxDep = 0, interiorCount = 0, leafCount = 0; int maxDep = 0, interiorCount = 0, leafCount = 0;
depth(maxDep, interiorCount, leafCount); depth(maxDep, interiorCount, leafCount);
o << "interior nodes: " << interiorCount << o << "interior nodes: " << interiorCount <<
", terminal nodes: " << leafCount << ", terminal nodes: " << leafCount <<
", depth: " << maxDep << "\n"; ", depth: " << maxDep << "\n";
} }
void print(std::ostream & o, int k = 0, std::string s = "") const void print(std::ostream & o, int k = 0, std::string s = "") const
{ {
DecisionTreeNodeProxy<TreeInt> node(tree_, k); DecisionTreeDeprecNodeProxy<TreeInt> node(tree_, k);
o << s << (*node.decisionColumns()) << " " << terminalWeights_[node .decisionWeightsIndex()] << "\n"; o << s << (*node.decisionColumns()) << " " << terminalWeights_[node .decisionWeightsIndex()] << "\n";
for(int l=0; l<2; ++l) for(int l=0; l<2; ++l)
{ {
int child = node.child(l); int child = node.child(l);
if(child <= 0) if(child <= 0)
o << s << " weights " << terminalWeights_[-child] << " " o << s << " weights " << terminalWeights_[-child] << " "
<< terminalWeights_[-child+1] << "\n" ; << terminalWeights_[-child+1] << "\n" ;
else else
print(o, child, s+" "); print(o, child, s+" ");
} }
} }
}; };
template <class U, class C, class Iterator, class Options, class Random> template <class U, class C, class Iterator, class Options, class Random>
void DecisionTree::learn(MultiArrayView<2, U, C> const & features, void DecisionTreeDeprec::learn(MultiArrayView<2, U, C> const & features,
ArrayVector<int> const & labels, ArrayVector<int> const & labels,
Iterator indices, int exampleCount, Iterator indices, int exampleCount,
Options const & options, Options const & options,
Random & randint) Random & randint)
{ {
ArrayVector<double> const & classLoss = options.class_weights; ArrayVector<double> const & classLoss = options.class_weights;
vigra_precondition(classLoss.size() == 0 || classLoss.size() == classCo unt_, vigra_precondition(classLoss.size() == 0 || classLoss.size() == classCo unt_,
"DecisionTree2::learn(): class weights array has wrong size."); "DecisionTreeDeprec2::learn(): class weights array has wrong size." );
reset(); reset();
unsigned int mtry = options.mtry; unsigned int mtry = options.mtry;
MultiArrayIndex cols = columnCount(features); MultiArrayIndex cols = columnCount(features);
split.init(mtry, cols, classCount_, classLoss); split.init(mtry, cols, classCount_, classLoss);
typedef DecisionTreeStackEntry<Iterator> Entry; typedef DecisionTreeDeprecStackEntry<Iterator> Entry;
ArrayVector<Entry> stack; ArrayVector<Entry> stack;
stack.push_back(Entry(indices, exampleCount)); stack.push_back(Entry(indices, exampleCount));
while(!stack.empty()) while(!stack.empty())
{ {
// std::cerr << "*"; // std::cerr << "*";
indices = stack.back().indices; indices = stack.back().indices;
exampleCount = stack.back().exampleCount; exampleCount = stack.back().exampleCount;
int leftParent = stack.back().leftParent, int leftParent = stack.back().leftParent,
rightParent = stack.back().rightParent; rightParent = stack.back().rightParent;
stack.pop_back(); stack.pop_back();
Iterator bestSplit = split.findBestSplit(features, labels, indices, exampleCount, randint); Iterator bestSplit = split.findBestSplit(features, labels, indices, exampleCount, randint);
int currentNode = split.writeSplitParameters(tree_, terminalWeights _); int currentNode = split.writeSplitParameters(tree_, terminalWeights _);
if(leftParent != DecisionTreeNoParent) if(leftParent != DecisionTreeDeprecNoParent)
DecisionTreeNodeProxy<TreeInt>(tree_, leftParent).child(0) = cu DecisionTreeDeprecNodeProxy<TreeInt>(tree_, leftParent).child(0
rrentNode; ) = currentNode;
if(rightParent != DecisionTreeNoParent) if(rightParent != DecisionTreeDeprecNoParent)
DecisionTreeNodeProxy<TreeInt>(tree_, rightParent).child(1) = c DecisionTreeDeprecNodeProxy<TreeInt>(tree_, rightParent).child(
urrentNode; 1) = currentNode;
leftParent = currentNode; leftParent = currentNode;
rightParent = DecisionTreeNoParent; rightParent = DecisionTreeDeprecNoParent;
for(int l=0; l<2; ++l) for(int l=0; l<2; ++l)
{ {
if(!split.isPure(l) && split.totalCount(l) >= options.min_split _node_size) if(!split.isPure(l) && split.totalCount(l) >= options.min_split _node_size)
{ {
// sample is still large enough and not yet perfectly separ ated => split // sample is still large enough and not yet perfectly separ ated => split
stack.push_back(Entry(indices, split.totalCount(l), leftPar ent, rightParent)); stack.push_back(Entry(indices, split.totalCount(l), leftPar ent, rightParent));
} }
else else
{ {
DecisionTreeNodeProxy<TreeInt>(tree_, currentNode).child(l) = -(TreeInt)terminalWeights_.size(); DecisionTreeDeprecNodeProxy<TreeInt>(tree_, currentNode).ch ild(l) = -(TreeInt)terminalWeights_.size();
split.writeWeights(l, terminalWeights_); split.writeWeights(l, terminalWeights_);
} }
std::swap(leftParent, rightParent); std::swap(leftParent, rightParent);
indices = bestSplit; indices = bestSplit;
} }
} }
// std::cerr << "\n"; // std::cerr << "\n";
} }
} // namespace detail } // namespace detail
class RandomForestOptions class RandomForestOptionsDeprec
{ {
public: public:
/** Initialize all options with default values. /** Initialize all options with default values.
*/ */
RandomForestOptions() RandomForestOptionsDeprec()
: training_set_proportion(1.0), : training_set_proportion(1.0),
mtry(0), mtry(0),
min_split_node_size(1), min_split_node_size(1),
training_set_size(0), training_set_size(0),
sample_with_replacement(true), sample_with_replacement(true),
sample_classes_individually(false), sample_classes_individually(false),
treeCount(255) treeCount(255)
{} {}
/** Number of features considered in each node. /** Number of features considered in each node.
If \a n is 0 (the default), the number of features tried in eve ry node If \a n is 0 (the default), the number of features tried in eve ry node
is determined by the square root of the total number of feature s. is determined by the square root of the total number of feature s.
According to Breiman, this quantity should slways be optimized by means According to Breiman, this quantity should always be optimized by means
of the out-of-bag error.<br> of the out-of-bag error.<br>
Default: 0 (use <tt>sqrt(columnCount(featureMatrix))</tt>) Default: 0 (use <tt>sqrt(columnCount(featureMatrix))</tt>)
*/ */
RandomForestOptions & featuresPerNode(unsigned int n) RandomForestOptionsDeprec & featuresPerNode(unsigned int n)
{ {
mtry = n; mtry = n;
return *this; return *this;
} }
/** How to sample the subset of the training data for each tree. /** How to sample the subset of the training data for each tree.
Each tree is only trained with a subset of the entire training data. Each tree is only trained with a subset of the entire training data.
If \a r is <tt>true</tt>, this subset is sampled from the entir e training set with If \a r is <tt>true</tt>, this subset is sampled from the entir e training set with
replacement.<br> replacement.<br>
Default: <tt>true</tt> (use sampling with replacement)) Default: <tt>true</tt> (use sampling with replacement))
*/ */
RandomForestOptions & sampleWithReplacement(bool r) RandomForestOptionsDeprec & sampleWithReplacement(bool r)
{ {
sample_with_replacement = r; sample_with_replacement = r;
return *this; return *this;
} }
RandomForestOptions & setTreeCount(unsigned int cnt) RandomForestOptionsDeprec & setTreeCount(unsigned int cnt)
{ {
treeCount = cnt; treeCount = cnt;
return *this; return *this;
} }
/** Proportion of training examples used for each tree. /** Proportion of training examples used for each tree.
If \a p is 1.0 (the default), and samples are drawn with replac ement, If \a p is 1.0 (the default), and samples are drawn with replac ement,
the training set of each tree will contain as many examples as the entire the training set of each tree will contain as many examples as the entire
training set, but some are drawn multiply and others not at all . On average, training set, but some are drawn multiply and others not at all . On average,
each tree is actually trained on about 65% of the examples in t he full each tree is actually trained on about 65% of the examples in t he full
training set. Changing the proportion makes mainly sense when training set. Changing the proportion makes mainly sense when
sampleWithReplacement() is set to <tt>false</tt>. trainingSetSi zeProportional() gets sampleWithReplacement() is set to <tt>false</tt>. trainingSetSi zeProportional() gets
overridden by trainingSetSizeAbsolute().<br> overridden by trainingSetSizeAbsolute().<br>
Default: 1.0 Default: 1.0
*/ */
RandomForestOptions & trainingSetSizeProportional(double p) RandomForestOptionsDeprec & trainingSetSizeProportional(double p)
{ {
vigra_precondition(p >= 0.0 && p <= 1.0, vigra_precondition(p >= 0.0 && p <= 1.0,
"RandomForestOptions::trainingSetSizeProportional(): proportion must be in [0, 1]."); "RandomForestOptionsDeprec::trainingSetSizeProportional(): prop ortion must be in [0, 1].");
if(training_set_size == 0) // otherwise, absolute size gets priorit y if(training_set_size == 0) // otherwise, absolute size gets priorit y
training_set_proportion = p; training_set_proportion = p;
return *this; return *this;
} }
/** Size of the training set for each tree. /** Size of the training set for each tree.
If this option is set, it overrides the proportion set by If this option is set, it overrides the proportion set by
trainingSetSizeProportional(). When classes are sampled individ ually, trainingSetSizeProportional(). When classes are sampled individ ually,
the number of examples is divided by the number of classes (rou nded upwards) the number of examples is divided by the number of classes (rou nded upwards)
to determine the number of examples drawn from every class.<br> to determine the number of examples drawn from every class.<br>
Default: <tt>0</tt> (determine size by proportion) Default: <tt>0</tt> (determine size by proportion)
*/ */
RandomForestOptions & trainingSetSizeAbsolute(unsigned int s) RandomForestOptionsDeprec & trainingSetSizeAbsolute(unsigned int s)
{ {
training_set_size = s; training_set_size = s;
if(s > 0) if(s > 0)
training_set_proportion = 0.0; training_set_proportion = 0.0;
return *this; return *this;
} }
/** Are the classes sampled individually? /** Are the classes sampled individually?
If \a s is <tt>false</tt> (the default), the training set for e ach tree is sampled If \a s is <tt>false</tt> (the default), the training set for e ach tree is sampled
without considering class labels. Otherwise, samples are drawn from each without considering class labels. Otherwise, samples are drawn from each
class independently. The latter is especially useful in connect ion class independently. The latter is especially useful in connect ion
with the specification of an absolute training set size: then, the same number of with the specification of an absolute training set size: then, the same number of
examples is drawn from every class. This can be used as a count er-measure when the examples is drawn from every class. This can be used as a count er-measure when the
classes are very unbalanced in size.<br> classes are very unbalanced in size.<br>
Default: <tt>false</tt> Default: <tt>false</tt>
*/ */
RandomForestOptions & sampleClassesIndividually(bool s) RandomForestOptionsDeprec & sampleClassesIndividually(bool s)
{ {
sample_classes_individually = s; sample_classes_individually = s;
return *this; return *this;
} }
/** Number of examples required for a node to be split. /** Number of examples required for a node to be split.
When the number of examples in a node is below this number, the node is not When the number of examples in a node is below this number, the node is not
split even if class separation is not yet perfect. Instead, the node returns split even if class separation is not yet perfect. Instead, the node returns
the proportion of each class (among the remaining examples) dur ing the the proportion of each class (among the remaining examples) dur ing the
prediction phase.<br> prediction phase.<br>
Default: 1 (complete growing) Default: 1 (complete growing)
*/ */
RandomForestOptions & minSplitNodeSize(unsigned int n) RandomForestOptionsDeprec & minSplitNodeSize(unsigned int n)
{ {
if(n == 0) if(n == 0)
n = 1; n = 1;
min_split_node_size = n; min_split_node_size = n;
return *this; return *this;
} }
/** Use a weighted random forest. /** Use a weighted random forest.
This is usually used to penalize the errors for the minority cl ass. This is usually used to penalize the errors for the minority cl ass.
Weights must be convertible to <tt>double</tt>, and the array o f weights Weights must be convertible to <tt>double</tt>, and the array o f weights
must contain as many entries as there are classes.<br> must contain as many entries as there are classes.<br>
Default: do not use weights Default: do not use weights
*/ */
template <class WeightIterator> template <class WeightIterator>
RandomForestOptions & weights(WeightIterator weights, unsigned int clas sCount) RandomForestOptionsDeprec & weights(WeightIterator weights, unsigned in t classCount)
{ {
class_weights.clear(); class_weights.clear();
if(weights != 0) if(weights != 0)
class_weights.insert(weights, classCount); class_weights.insert(weights, classCount);
return *this; return *this;
} }
RandomForestOptions & oobData(MultiArrayView<2, UInt8>& data) RandomForestOptionsDeprec & oobData(MultiArrayView<2, UInt8>& data)
{ {
oob_data =data; oob_data =data;
return *this; return *this;
} }
MultiArrayView<2, UInt8> oob_data; MultiArrayView<2, UInt8> oob_data;
ArrayVector<double> class_weights; ArrayVector<double> class_weights;
double training_set_proportion; double training_set_proportion;
unsigned int mtry, min_split_node_size, training_set_size; unsigned int mtry, min_split_node_size, training_set_size;
bool sample_with_replacement, sample_classes_individually; bool sample_with_replacement, sample_classes_individually;
unsigned int treeCount; unsigned int treeCount;
}; };
/*****************************************************************/ /*****************************************************************/
/* */ /* */
/* RandomForest */ /* RandomForestDeprec */
/* */ /* */
/*****************************************************************/ /*****************************************************************/
template <class ClassLabelType> template <class ClassLabelType>
class RandomForest class RandomForestDeprec
{ {
public: public:
ArrayVector<ClassLabelType> classes_; ArrayVector<ClassLabelType> classes_;
ArrayVector<detail::DecisionTree> trees_; ArrayVector<detail::DecisionTreeDeprec> trees_;
MultiArrayIndex columnCount_; MultiArrayIndex columnCount_;
RandomForestOptions options_; RandomForestOptionsDeprec options_;
public: public:
//First two constructors are straight forward. //First two constructors are straight forward.
//they take either the iterators to an Array of Classlabels or the v //they take either the iterators to an Array of Classlabels or the valu
alues es
template<class ClassLabelIterator> template<class ClassLabelIterator>
RandomForest(ClassLabelIterator cl, ClassLabelIterator cend, RandomForestDeprec(ClassLabelIterator cl, ClassLabelIterator cend,
unsigned int treeCount = 255, unsigned int treeCount = 255,
RandomForestOptions const & options = RandomForestOptions ()) RandomForestOptionsDeprec const & options = RandomForestO ptionsDeprec())
: classes_(cl, cend), : classes_(cl, cend),
trees_(treeCount, detail::DecisionTree(classes_.size())), trees_(treeCount, detail::DecisionTreeDeprec(classes_.size())),
columnCount_(0), columnCount_(0),
options_(options) options_(options)
{ {
vigra_precondition(options.training_set_proportion == 0.0 || vigra_precondition(options.training_set_proportion == 0.0 ||
options.training_set_size == 0, options.training_set_size == 0,
"RandomForestOptions: absolute and proprtional training set siz es " "RandomForestOptionsDeprec: absolute and proportional training set sizes "
"cannot be specified at the same time."); "cannot be specified at the same time.");
vigra_precondition(classes_.size() > 1, vigra_precondition(classes_.size() > 1,
"RandomForestOptions::weights(): need at least two classes."); "RandomForestOptionsDeprec::weights(): need at least two classe s.");
vigra_precondition(options.class_weights.size() == 0 || options.cla ss_weights.size() == classes_.size(), vigra_precondition(options.class_weights.size() == 0 || options.cla ss_weights.size() == classes_.size(),
"RandomForestOptions::weights(): wrong number of classes."); "RandomForestOptionsDeprec::weights(): wrong number of classes. ");
} }
RandomForest(ClassLabelType const & c1, ClassLabelType const & c2, RandomForestDeprec(ClassLabelType const & c1, ClassLabelType const & c2 ,
unsigned int treeCount = 255, unsigned int treeCount = 255,
RandomForestOptions const & options = RandomForestOptions ()) RandomForestOptionsDeprec const & options = RandomForestO ptionsDeprec())
: classes_(2), : classes_(2),
trees_(treeCount, detail::DecisionTree(2)), trees_(treeCount, detail::DecisionTreeDeprec(2)),
columnCount_(0), columnCount_(0),
options_(options) options_(options)
{ {
vigra_precondition(options.class_weights.size() == 0 || options.cla ss_weights.size() == 2, vigra_precondition(options.class_weights.size() == 0 || options.cla ss_weights.size() == 2,
"RandomForestOptions::weights(): wrong number of classes."); "RandomForestOptionsDeprec::weights(): wrong number of classes. ");
classes_[0] = c1; classes_[0] = c1;
classes_[1] = c2; classes_[1] = c2;
} }
//This is esp. For the CrosValidator Class //This is esp. For the CrosValidator Class
template<class ClassLabelIterator> template<class ClassLabelIterator>
RandomForest(ClassLabelIterator cl, ClassLabelIterator cend, RandomForestDeprec(ClassLabelIterator cl, ClassLabelIterator cend,
RandomForestOptions const & options ) RandomForestOptionsDeprec const & options )
: classes_(cl, cend), : classes_(cl, cend),
trees_(options.treeCount , detail::DecisionTree(classes_.size())), trees_(options.treeCount , detail::DecisionTreeDeprec(classes_.size() )),
columnCount_(0), columnCount_(0),
options_(options) options_(options)
{ {
vigra_precondition(options.training_set_proportion == 0.0 || vigra_precondition(options.training_set_proportion == 0.0 ||
options.training_set_size == 0, options.training_set_size == 0,
"RandomForestOptions: absolute and proprtional training set siz es " "RandomForestOptionsDeprec: absolute and proportional training set sizes "
"cannot be specified at the same time."); "cannot be specified at the same time.");
vigra_precondition(classes_.size() > 1, vigra_precondition(classes_.size() > 1,
"RandomForestOptions::weights(): need at least two classes."); "RandomForestOptionsDeprec::weights(): need at least two classe s.");
vigra_precondition(options.class_weights.size() == 0 || options.cla ss_weights.size() == classes_.size(), vigra_precondition(options.class_weights.size() == 0 || options.cla ss_weights.size() == classes_.size(),
"RandomForestOptions::weights(): wrong number of classes."); "RandomForestOptionsDeprec::weights(): wrong number of classes. ");
} }
//Not understood yet //Not understood yet
//Does not use the options object but the columnCount object. //Does not use the options object but the columnCount object.
template<class ClassLabelIterator, class TreeIterator, class WeightIter ator> template<class ClassLabelIterator, class TreeIterator, class WeightIter ator>
RandomForest(ClassLabelIterator cl, ClassLabelIterator cend, RandomForestDeprec(ClassLabelIterator cl, ClassLabelIterator cend,
unsigned int treeCount, unsigned int columnCount, unsigned int treeCount, unsigned int columnCount,
TreeIterator trees, WeightIterator weights) TreeIterator trees, WeightIterator weights)
: classes_(cl, cend), : classes_(cl, cend),
trees_(treeCount, detail::DecisionTree(classes_.size())), trees_(treeCount, detail::DecisionTreeDeprec(classes_.size())),
columnCount_(columnCount) columnCount_(columnCount)
{ {
for(unsigned int k=0; k<treeCount; ++k, ++trees, ++weights) for(unsigned int k=0; k<treeCount; ++k, ++trees, ++weights)
{ {
trees_[k].tree_ = *trees; trees_[k].tree_ = *trees;
trees_[k].terminalWeights_ = *weights; trees_[k].terminalWeights_ = *weights;
} }
} }
int featureCount() const int featureCount() const
{ {
vigra_precondition(columnCount_ > 0, vigra_precondition(columnCount_ > 0,
"RandomForest::featureCount(): Random forest has not been traine d yet."); "RandomForestDeprec::featureCount(): Random forest has not been trained yet.");
return columnCount_; return columnCount_;
} }
int labelCount() const int labelCount() const
{ {
return classes_.size(); return classes_.size();
} }
int treeCount() const int treeCount() const
{ {
skipping to change at line 801 skipping to change at line 800
} }
// loss == 0.0 means unweighted random forest // loss == 0.0 means unweighted random forest
template <class U, class C, class Array, class Random> template <class U, class C, class Array, class Random>
double learn(MultiArrayView<2, U, C> const & features, Array const & la bels, double learn(MultiArrayView<2, U, C> const & features, Array const & la bels,
Random const& random); Random const& random);
template <class U, class C, class Array> template <class U, class C, class Array>
double learn(MultiArrayView<2, U, C> const & features, Array const & la bels) double learn(MultiArrayView<2, U, C> const & features, Array const & la bels)
{ {
return learn(features, labels, RandomTT800::global()); RandomNumberGenerator<> generator(RandomSeed);
return learn(features, labels, generator);
} }
template <class U, class C> template <class U, class C>
ClassLabelType predictLabel(MultiArrayView<2, U, C> const & features) c onst; ClassLabelType predictLabel(MultiArrayView<2, U, C> const & features) c onst;
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."); "RandomForestDeprec::predictLabels(): Label array has wrong siz e.");
for(int k=0; k<features.shape(0); ++k) for(int k=0; k<features.shape(0); ++k)
labels(k,0) = predictLabel(rowVector(features, k)); labels(k,0) = predictLabel(rowVector(features, k));
} }
template <class U, class C, class Iterator> template <class U, class C, class Iterator>
ClassLabelType predictLabel(MultiArrayView<2, U, C> const & features, ClassLabelType predictLabel(MultiArrayView<2, U, C> const & features,
Iterator priors) const; Iterator priors) const;
template <class U, class C1, class T, class C2> template <class U, class C1, class T, class C2>
void predictProbabilities(MultiArrayView<2, U, C1> const & features, void predictProbabilities(MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, T, C2> & prob) const; MultiArrayView<2, T, C2> & prob) const;
template <class U, class C1, class T, class C2> template <class U, class C1, class T, class C2>
void predictNodes(MultiArrayView<2, U, C1> const & features, void predictNodes(MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, T, C2> & NodeIDs) const; MultiArrayView<2, T, C2> & NodeIDs) const;
}; };
template <class ClassLabelType> template <class ClassLabelType>
template <class U, class C1, class Array, class Random> template <class U, class C1, class Array, class Random>
double double
RandomForest<ClassLabelType>::learn(MultiArrayView<2, U, C1> const & featur es, RandomForestDeprec<ClassLabelType>::learn(MultiArrayView<2, U, C1> const & features,
Array const & labels, Array const & labels,
Random const& random) Random const& random)
{ {
unsigned int classCount = classes_.size(); unsigned int classCount = classes_.size();
unsigned int m = rowCount(features); unsigned int m = rowCount(features);
unsigned int n = columnCount(features); unsigned int n = columnCount(features);
vigra_precondition((unsigned int)(m) == (unsigned int)labels.size(), vigra_precondition((unsigned int)(m) == (unsigned int)labels.size(),
"RandomForest::learn(): Label array has wrong size."); "RandomForestDeprec::learn(): Label array has wrong size.");
vigra_precondition(options_.training_set_size <= m || options_.sample_w ith_replacement, vigra_precondition(options_.training_set_size <= m || options_.sample_w ith_replacement,
"RandomForest::learn(): Requested training set size exceeds total nu mber of examples."); "RandomForestDeprec::learn(): Requested training set size exceeds to tal number of examples.");
MultiArrayIndex mtry = (options_.mtry == 0) MultiArrayIndex mtry = (options_.mtry == 0)
? int(std::floor(std::sqrt(double(n)) + 0.5 )) ? int(std::floor(std::sqrt(double(n)) + 0.5 ))
: options_.mtry; : options_.mtry;
vigra_precondition(mtry <= (MultiArrayIndex)n, vigra_precondition(mtry <= (MultiArrayIndex)n,
"RandomForest::learn(): mtry must be less than number of features.") ; "RandomForestDeprec::learn(): mtry must be less than number of featu res.");
MultiArrayIndex msamples = options_.training_set_size; MultiArrayIndex msamples = options_.training_set_size;
if(options_.sample_classes_individually) if(options_.sample_classes_individually)
msamples = int(std::ceil(double(msamples) / classCount)); msamples = int(std::ceil(double(msamples) / classCount));
ArrayVector<int> intLabels(m), classExampleCounts(classCount); ArrayVector<int> intLabels(m), classExampleCounts(classCount);
// verify the input labels // verify the input labels
int minClassCount; int minClassCount;
{ {
typedef std::map<ClassLabelType, int > LabelChecker; typedef std::map<ClassLabelType, int > LabelChecker;
typedef typename LabelChecker::iterator LabelCheckerIterator; typedef typename LabelChecker::iterator LabelCheckerIterator;
LabelChecker labelChecker; LabelChecker labelChecker;
for(unsigned int k=0; k<classCount; ++k) for(unsigned int k=0; k<classCount; ++k)
labelChecker[classes_[k]] = k; labelChecker[classes_[k]] = k;
for(unsigned int k=0; k<m; ++k) for(unsigned int k=0; k<m; ++k)
{ {
LabelCheckerIterator found = labelChecker.find(labels[k]); LabelCheckerIterator found = labelChecker.find(labels[k]);
vigra_precondition(found != labelChecker.end(), vigra_precondition(found != labelChecker.end(),
"RandomForest::learn(): Unknown class label encountered."); "RandomForestDeprec::learn(): Unknown class label encounter ed.");
intLabels[k] = found->second; intLabels[k] = found->second;
++classExampleCounts[intLabels[k]]; ++classExampleCounts[intLabels[k]];
} }
minClassCount = *argMin(classExampleCounts.begin(), classExampleCou nts.end()); minClassCount = *argMin(classExampleCounts.begin(), classExampleCou nts.end());
vigra_precondition(minClassCount > 0, vigra_precondition(minClassCount > 0,
"RandomForest::learn(): At least one class is missing in the t raining set."); "RandomForestDeprec::learn(): At least one class is missing in the training set.");
if(msamples > 0 && options_.sample_classes_individually && if(msamples > 0 && options_.sample_classes_individually &&
!options_.sample_with_replacement) !options_.sample_with_replacement)
{ {
vigra_precondition(msamples <= minClassCount, vigra_precondition(msamples <= minClassCount,
"RandomForest::learn(): Too few examples in smallest class to reach " "RandomForestDeprec::learn(): Too few examples in smallest class to reach "
"requested training set size."); "requested training set size.");
} }
} }
columnCount_ = n; columnCount_ = n;
ArrayVector<int> indices(m); ArrayVector<int> indices(m);
for(unsigned int k=0; k<m; ++k) for(unsigned int k=0; k<m; ++k)
indices[k] = k; indices[k] = k;
if(options_.sample_classes_individually) if(options_.sample_classes_individually)
{ {
detail::RandomForestLabelSorter<ArrayVector<int> > sorter(intLabels ); detail::RandomForestDeprecLabelSorter<ArrayVector<int> > sorter(int Labels);
std::sort(indices.begin(), indices.end(), sorter); std::sort(indices.begin(), indices.end(), sorter);
} }
ArrayVector<int> usedIndices(m), oobCount(m), oobErrorCount(m); ArrayVector<int> usedIndices(m), oobCount(m), oobErrorCount(m);
UniformIntRandomFunctor<Random> randint(0, m-1, random); UniformIntRandomFunctor<Random> randint(0, m-1, random);
//std::cerr << "Learning a RF \n"; //std::cerr << "Learning a RF \n";
for(unsigned int k=0; k<trees_.size(); ++k) for(unsigned int k=0; k<trees_.size(); ++k)
{ {
//std::cerr << "Learning tree " << k << " ...\n"; //std::cerr << "Learning tree " << k << " ...\n";
skipping to change at line 984 skipping to change at line 984
// ++oobErrorCount[l]; // ++oobErrorCount[l];
// } // }
// } // }
for(unsigned int l=0; l<m; ++l) for(unsigned int l=0; l<m; ++l)
{ {
if(!usedIndices[l]) if(!usedIndices[l])
{ {
++oobCount[l]; ++oobCount[l];
if(trees_[k].predictLabel(rowVector(features, l)) != intLab els[l]) if(trees_[k].predictLabel(rowVector(features, l)) != intLab els[l])
{ {
++oobErrorCount[l]; ++oobErrorCount[l];
if(options_.oob_data.data() != 0) if(options_.oob_data.data() != 0)
options_.oob_data(l, k) = 2; options_.oob_data(l, k) = 2;
} }
else if(options_.oob_data.data() != 0) else if(options_.oob_data.data() != 0)
{ {
options_.oob_data(l, k) = 1; options_.oob_data(l, k) = 1;
} }
} }
} }
// TODO: default value for oob_data // TODO: default value for oob_data
// TODO: implement variable importance // TODO: implement variable importance
//if(!options_.sample_with_replacement){ //if(!options_.sample_with_replacement){
//std::cerr << "done\n"; //std::cerr << "done\n";
//trees_[k].print(std::cerr); //trees_[k].print(std::cerr);
#ifdef VIGRA_RF_VERBOSE #ifdef VIGRA_RF_VERBOSE
trees_[k].printStatistics(std::cerr); trees_[k].printStatistics(std::cerr);
#endif #endif
skipping to change at line 1018 skipping to change at line 1018
{ {
oobError += double(oobErrorCount[l]) / oobCount[l]; oobError += double(oobErrorCount[l]) / oobCount[l];
++totalOobCount; ++totalOobCount;
} }
return oobError / totalOobCount; return oobError / totalOobCount;
} }
template <class ClassLabelType> template <class ClassLabelType>
template <class U, class C> template <class U, class C>
ClassLabelType ClassLabelType
RandomForest<ClassLabelType>::predictLabel(MultiArrayView<2, U, C> const & features) const RandomForestDeprec<ClassLabelType>::predictLabel(MultiArrayView<2, U, C> co nst & features) const
{ {
vigra_precondition(columnCount(features) >= featureCount(), vigra_precondition(columnCount(features) >= featureCount(),
"RandomForest::predictLabel(): Too few columns in feature matrix.") ; "RandomForestDeprec::predictLabel(): Too few columns in feature mat rix.");
vigra_precondition(rowCount(features) == 1, vigra_precondition(rowCount(features) == 1,
"RandomForest::predictLabel(): Feature matrix must have a single ro w."); "RandomForestDeprec::predictLabel(): Feature matrix must have a sin gle row.");
Matrix<double> prob(1, classes_.size()); Matrix<double> prob(1, classes_.size());
predictProbabilities(features, prob); predictProbabilities(features, prob);
return classes_[argMax(prob)]; return classes_[argMax(prob)];
} }
//Same thing as above with priors for each label !!! //Same thing as above with priors for each label !!!
template <class ClassLabelType> template <class ClassLabelType>
template <class U, class C, class Iterator> template <class U, class C, class Iterator>
ClassLabelType ClassLabelType
RandomForest<ClassLabelType>::predictLabel(MultiArrayView<2, U, C> const & features, RandomForestDeprec<ClassLabelType>::predictLabel(MultiArrayView<2, U, C> co nst & features,
Iterator priors) const Iterator priors) const
{ {
using namespace functor; using namespace functor;
vigra_precondition(columnCount(features) >= featureCount(), vigra_precondition(columnCount(features) >= featureCount(),
"RandomForest::predictLabel(): Too few columns in feature matrix.") ; "RandomForestDeprec::predictLabel(): Too few columns in feature mat rix.");
vigra_precondition(rowCount(features) == 1, vigra_precondition(rowCount(features) == 1,
"RandomForest::predictLabel(): Feature matrix must have a single ro w."); "RandomForestDeprec::predictLabel(): Feature matrix must have a sin gle row.");
Matrix<double> prob(1,classes_.size()); Matrix<double> prob(1,classes_.size());
predictProbabilities(features, prob); predictProbabilities(features, prob);
std::transform(prob.begin(), prob.end(), priors, prob.begin(), Arg1()*A rg2()); std::transform(prob.begin(), prob.end(), priors, prob.begin(), Arg1()*A rg2());
return classes_[argMax(prob)]; return classes_[argMax(prob)];
} }
template <class ClassLabelType> template <class ClassLabelType>
template <class U, class C1, class T, class C2> template <class U, class C1, class T, class C2>
void void
RandomForest<ClassLabelType>::predictProbabilities(MultiArrayView<2, U, C1> const & features, RandomForestDeprec<ClassLabelType>::predictProbabilities(MultiArrayView<2, U, C1> const & features,
MultiArrayView<2, T, C2> & prob) const MultiArrayView<2, T, C2> & prob) const
{ {
//Features are n xp //Features are n xp
//prob is n x NumOfLabel probability for each feature in each class //prob is n x NumOfLabel probability for each feature in each class
vigra_precondition(rowCount(features) == rowCount(prob), vigra_precondition(rowCount(features) == rowCount(prob),
"RandomForest::predictProbabilities(): Feature matrix and probability matrix size mismatch."); "RandomForestDeprec::predictProbabilities(): Feature matrix and proba bility matrix size mismatch.");
// num of features must be bigger than num of features in Random for // num of features must be bigger than num of features in Random forest
est training training
// but why bigger? // but why bigger?
vigra_precondition(columnCount(features) >= featureCount(), vigra_precondition(columnCount(features) >= featureCount(),
"RandomForest::predictProbabilities(): Too few columns in feature mat rix."); "RandomForestDeprec::predictProbabilities(): Too few columns in featu re matrix.");
vigra_precondition(columnCount(prob) == (MultiArrayIndex)labelCount(), vigra_precondition(columnCount(prob) == (MultiArrayIndex)labelCount(),
"RandomForest::predictProbabilities(): Probability matrix must have a s many columns as there are classes."); "RandomForestDeprec::predictProbabilities(): Probability matrix must have as many columns as there are classes.");
//Classify for each row. //Classify for each row.
for(int row=0; row < rowCount(features); ++row) for(int row=0; row < rowCount(features); ++row)
{ {
//contains the weights returned by a single tree??? //contains the weights returned by a single tree???
//thought that one tree has only one vote??? //thought that one tree has only one vote???
//Pruning??? //Pruning???
ArrayVector<double>::const_iterator weights; ArrayVector<double>::const_iterator weights;
//totalWeight == totalVoteCount! //totalWeight == totalVoteCount!
double totalWeight = 0.0; double totalWeight = 0.0;
//Set each VoteCount = 0 - prob(row,l) contains vote counts until //Set each VoteCount = 0 - prob(row,l) contains vote counts until
//further normalisation //further normalisation
for(unsigned int l=0; l<classes_.size(); ++l) for(unsigned int l=0; l<classes_.size(); ++l)
prob(row, l) = 0.0; prob(row, l) = 0.0;
//Let each tree classify... //Let each tree classify...
for(unsigned int k=0; k<trees_.size(); ++k) for(unsigned int k=0; k<trees_.size(); ++k)
{ {
//get weights predicted by single tree //get weights predicted by single tree
weights = trees_[k].predict(rowVector(features, row)); weights = trees_[k].predict(rowVector(features, row));
//update votecount. //update votecount.
for(unsigned int l=0; l<classes_.size(); ++l) for(unsigned int l=0; l<classes_.size(); ++l)
{ {
prob(row, l) += detail::RequiresExplicitCast<T>::cast(weigh ts[l]); prob(row, l) += detail::RequiresExplicitCast<T>::cast(weigh ts[l]);
//every weight in totalWeight. //every weight in totalWeight.
totalWeight += weights[l]; totalWeight += weights[l];
} }
} }
//Normalise votes in each row by total VoteCount (totalWeight //Normalise votes in each row by total VoteCount (totalWeight
for(unsigned int l=0; l<classes_.size(); ++l) for(unsigned int l=0; l<classes_.size(); ++l)
prob(row, l) /= detail::RequiresExplicitCast<T>::cast(total Weight); prob(row, l) /= detail::RequiresExplicitCast<T>::cast(total Weight);
} }
} }
template <class ClassLabelType> template <class ClassLabelType>
template <class U, class C1, class T, class C2> template <class U, class C1, class T, class C2>
void void
RandomForest<ClassLabelType>::predictNodes(MultiArrayView<2, U, C1> const & features, RandomForestDeprec<ClassLabelType>::predictNodes(MultiArrayView<2, U, C1> c onst & features,
MultiArrayView<2, T, C2> & NodeIDs) const MultiArrayView<2, T, C2> & NodeIDs) const
{ {
vigra_precondition(columnCount(features) >= featureCount(), vigra_precondition(columnCount(features) >= featureCount(),
"RandomForest::getNodesRF(): Too few columns in feature matrix."); "RandomForestDeprec::getNodesRF(): Too few columns in feature matrix. ");
vigra_precondition(rowCount(features) <= rowCount(NodeIDs), vigra_precondition(rowCount(features) <= rowCount(NodeIDs),
"RandomForest::getNodesRF(): Too few rows in NodeIds matrix"); "RandomForestDeprec::getNodesRF(): Too few rows in NodeIds matrix");
vigra_precondition(columnCount(NodeIDs) >= treeCount(), vigra_precondition(columnCount(NodeIDs) >= treeCount(),
"RandomForest::getNodesRF(): Too few columns in NodeIds matrix."); "RandomForestDeprec::getNodesRF(): Too few columns in NodeIds matrix. ");
NodeIDs.init(0); NodeIDs.init(0);
for(unsigned int k=0; k<trees_.size(); ++k) for(unsigned int k=0; k<trees_.size(); ++k)
{ {
for(int row=0; row < rowCount(features); ++row) for(int row=0; row < rowCount(features); ++row)
{ {
NodeIDs(row,k) = trees_[k].leafID(rowVector(features, row)); NodeIDs(row,k) = trees_[k].leafID(rowVector(features, row));
} }
} }
} }
//@} //@}
} // namespace vigra } // namespace vigra
#undef RandomForest
#undef DecisionTree
#endif // VIGRA_RANDOM_FOREST_HXX #endif // VIGRA_RANDOM_FOREST_HXX
 End of changes. 116 change blocks. 
144 lines changed or deleted 141 lines changed or added


 random_forest_hdf5_impex.hxx   random_forest_hdf5_impex.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_RANDOM_FOREST_IMPEX_HDF5_HXX #ifndef VIGRA_RANDOM_FOREST_IMPEX_HDF5_HXX
#define VIGRA_RANDOM_FOREST_IMPEX_HDF5_HXX #define VIGRA_RANDOM_FOREST_IMPEX_HDF5_HXX
#include "config.hxx"
#include "random_forest.hxx" #include "random_forest.hxx"
#include "hdf5impex.hxx" #include "hdf5impex.hxx"
#include <cstdio>
#include <string> #include <string>
#ifdef HasHDF5
namespace vigra namespace vigra
{ {
static const char *const rf_hdf5_options = "_options";
static const char *const rf_hdf5_ext_param = "_ext_param";
static const char *const rf_hdf5_labels = "labels";
static const char *const rf_hdf5_topology = "topology";
static const char *const rf_hdf5_parameters = "parameters";
static const char *const rf_hdf5_tree = "Tree_";
static const char *const rf_hdf5_version_group = ".";
static const char *const rf_hdf5_version_tag = "vigra_random_forest_versi
on";
static const double rf_hdf5_version = 0.1;
namespace detail namespace detail
{ {
/** shallow search the hdf5 group for containing elements VIGRA_EXPORT void options_import_HDF5(HDF5File &, RandomForestOptions &,
* returns negative value if unsuccessful const std::string &);
* \param grp_id hid_t containing path to group.
* \param cont reference to container that supports
* insert(). valuetype of cont must be
* std::string
*/
template<class Container>
bool find_groups_hdf5(hid_t grp_id, Container &cont)
{
//get group info VIGRA_EXPORT void options_export_HDF5(HDF5File &, const RandomForestOptions
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6) &,
hsize_t size; const std::string &);
H5Gget_num_objs(grp_id, &size);
#else
hsize_t size;
H5G_info_t ginfo;
herr_t status;
status = H5Gget_info (grp_id , &ginfo);
if(status < 0)
std::runtime_error("find_groups_hdf5():"
"problem while getting gr
oup info");
size = ginfo.nlinks;
#endif
for(hsize_t ii = 0; ii < size; ++ii)
{
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
ssize_t buffer_size =
H5Gget_objname_by_idx(grp_id,
ii
, NULL, 0 ) + 1;
#else
std::ptrdiff_t buffer_size =
H5Lget_name_by_idx(grp_id, ".",
H5_INDEX_
NAME,
H5_ITER_I
NC,
ii, 0, 0,
H5P_DEFAULT)+1;
#endif
ArrayVector<char> buffer(buffer_size);
#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
buffer_size =
H5Gget_objname_by_idx(grp_id,
ii
, buffer.data(),
(s
ize_t)buffer_size );
#else
buffer_size =
H5Lget_name_by_idx(grp_id, ".",
H5_INDEX_
NAME,
H5_ITER_I
NC,
ii, buffe
r.data(),
(size_t)b
uffer_size,
H5P_DEFAU
LT);
#endif
cont.insert(cont.end(), std::string(buffer.data()));
}
return true;
}
/** shallow search the hdf5 group for containing elements VIGRA_EXPORT void dt_import_HDF5(HDF5File &, detail::DecisionTree &,
* returns negative value if unsuccessful const std::string &);
* \param filename name of hdf5 file
* \param groupname path in hdf5 file
* \param cont reference to container that supports
* insert(). valuetype of cont must be
* std::string
*/
template<class Container>
bool find_groups_hdf5(std::string filename,
std::string groupn
ame,
Container &cont)
{
//check if file exists
FILE* pFile;
pFile = fopen ( filename.c_str(), "r" );
if ( pFile == NULL)
{
return 0;
}
//open the file
HDF5Handle file_id(H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEF
AULT),
&H5Fclose, "Unable to open HDF5 file");
HDF5Handle grp_id;
if(groupname == "")
{
grp_id = HDF5Handle(file_id, 0, "");
}
else
{
grp_id = HDF5Handle(H5Gopen(file_id, groupname.c_str(), H5P_
DEFAULT),
&H5Gclose, "Unable to open group");
} VIGRA_EXPORT void dt_export_HDF5(HDF5File &, const detail::DecisionTree &,
bool res = find_groups_hdf5(grp_id, cont); const std::string &);
return res;
}
inline int get_number_of_digits(int in) template<class X>
void rf_import_HDF5_to_map(HDF5File & h5context, X & param,
const char *const ignored_label = 0)
{ {
int num = 0; // read a map containing all the double fields
int i = 1; typedef typename X::map_type map_type;
while(double(in) / double(i) >= 1) typedef std::pair<typename map_type::iterator, bool> inserter_type;
{ typedef typename map_type::value_type value_type;
i *= 10; typedef typename map_type::mapped_type mapped_type;
num += 1;
}
if(num == 0)
num = 1;
return num;
}
inline std::string make_padded_number(int number, int max_number) map_type serialized_param;
{ bool ignored_seen = ignored_label == 0;
int max_digit_ct = get_number_of_digits(max_number);
char buffer [50];
std::sprintf(buffer, "%d", number);
std::string padding = "";
std::string numeral = buffer;
int digit_ct = get_number_of_digits(number);
for(int gg = 0; gg < max_digit_ct - digit_ct; ++ gg)
padding = padding + "0";
return padding + numeral;
}
/** write a ArrayVector to a hdf5 dataset. std::vector<std::string> names = h5context.ls();
*/ std::vector<std::string>::const_iterator j;
template<class U, class T> for (j = names.begin(); j != names.end(); ++j)
void write_array_2_hdf5(hid_t & id, {
ArrayVector<U> const & arr, if (ignored_label && *j == ignored_label)
std::string const & name, {
T type) ignored_seen = true;
{ continue;
hsize_t size = arr.size(); }
vigra_postcondition(H5LTmake_dataset (id, // get sort of an iterator to a new empty array vector in the map .
..
name.c_str(), inserter_type new_array
= serialized_param.insert(value_type(*j, mapped_type()));
1, // ... and read the data into that place.
h5context.readAndResize(*j, (*(new_array.first)).second);
&size, }
vigra_precondition(ignored_seen, "rf_import_HDF5_to_map(): "
type, "labels are missin
g.");
arr.begin()) param.make_from_map(serialized_param);
>= 0,
"write_array_2_hdf5():"
"unable to write dataset");
} }
template<class U, class T> template<class T>
void write_hdf5_2_array(hid_t & id, void problemspec_import_HDF5(HDF5File & h5context, ProblemSpec<T> & param,
ArrayVector<U> & arr, const std::string & name)
std::string const & name,
T type)
{ {
// The last three values of get_dataset_info can be NULL h5context.cd(name);
// my EFFING FOOT! that is valid for HDF5 1.8 but not for rf_import_HDF5_to_map(h5context, param, rf_hdf5_labels);
// 1.6 - but documented the other way around AAARRHGHGHH // load_class_labels
hsize_t size; ArrayVector<T> labels;
H5T_class_t a; h5context.readAndResize(rf_hdf5_labels, labels);
size_t b; param.classes_(labels.begin(), labels.end());
vigra_postcondition(H5LTget_dataset_info(id, h5context.cd_up();
name.c_str(),
&size,
&a,
&b) >= 0,
"write_hdf5_2_array(): "
"Unable to locate dataset");
arr.resize((typename ArrayVector<U>::size_type)size);
vigra_postcondition(H5LTread_dataset (id,
name.c_str(),
type,
arr.data()) >= 0,
"write_array_2_hdf5():"
"unable to read dataset");
} }
inline void options_import_HDF5(hid_t & group_id, template<class X>
RandomForestOptions & opt, void rf_export_map_to_HDF5(HDF5File & h5context, const X & param)
std::string name)
{ {
ArrayVector<double> serialized_options; typedef typename X::map_type map_type;
write_hdf5_2_array(group_id, serialized_options, map_type serialized_param;
name, H5T_NATIVE_DOUBLE); // get a map containing all the double fields
opt.unserialize(serialized_options.begin(), param.make_map(serialized_param);
serialized_options.end()); typename map_type::const_iterator j;
for (j = serialized_param.begin(); j != serialized_param.end(); ++j)
h5context.write(j->first, j->second);
} }
inline void options_export_HDF5(hid_t & group_id, template<class T>
RandomForestOptions const & void problemspec_export_HDF5(HDF5File & h5context, ProblemSpec<T> const & p
opt, aram,
std::string name) const std::string & name)
{ {
ArrayVector<double> serialized_options(opt.serialized_size()); h5context.cd_mk(name);
opt.serialize(serialized_options.begin(), rf_export_map_to_HDF5(h5context, param);
serialized_options.end()); h5context.write(rf_hdf5_labels, param.classes);
write_array_2_hdf5(group_id, serialized_options, h5context.cd_up();
name, H5T_NATIVE_DOUBLE);
} }
struct MyT struct padded_number_string_data;
class VIGRA_EXPORT padded_number_string
{ {
enum type { INT8 = 1, INT16 = 2, INT32 =3, INT64=4, private:
UINT8 = 5, UINT16 = 6, UINT32= 7, UINT64= padded_number_string_data* padded_number;
8, protected:
FLOAT = 9, DOUBLE = 10, OTHER = 3294}; padded_number_string(const padded_number_string &);
void operator=(const padded_number_string &);
public:
padded_number_string(int n);
std::string operator()(int k) const;
~padded_number_string();
}; };
#define create_type_of(TYPE, ENUM) \ inline std::string get_cwd(HDF5File & h5context)
inline MyT::type type_of(TYPE)\
{\
return MyT::ENUM; \
}
create_type_of(Int8, INT8)
create_type_of(Int16, INT16)
create_type_of(Int32, INT32)
create_type_of(Int64, INT64)
create_type_of(UInt8, UINT8)
create_type_of(UInt16, UINT16)
create_type_of(UInt32, UINT32)
create_type_of(UInt64, UINT64)
create_type_of(float, FLOAT)
create_type_of(double, DOUBLE)
#undef create_type_of
inline MyT::type type_of_hid_t(hid_t group_id, std::string name)
{ {
hid_t m_dataset_handle = return h5context.get_absolute_path(h5context.pwd());
H5Dopen(group_id, name.c_str(), H5P_DEFAULT);
hid_t datatype = H5Dget_type(m_dataset_handle);
H5T_class_t dataclass = H5Tget_class(datatype);
size_t datasize = H5Tget_size(datatype);
H5T_sign_t datasign = H5Tget_sign(datatype);
MyT::type result = MyT::OTHER;
if(dataclass == H5T_FLOAT)
{
if(datasize == 4)
result = MyT::FLOAT;
else if(datasize == 8)
result = MyT::DOUBLE;
}
else if(dataclass == H5T_INTEGER)
{
if(datasign == H5T_SGN_NONE)
{
if(datasize == 1)
result = MyT::UINT8;
else if(datasize == 2)
result = MyT::UINT16;
else if(datasize == 4)
result = MyT::UINT32;
else if(datasize == 8)
result = MyT::UINT64;
}
else
{
if(datasize == 1)
result = MyT::INT8;
else if(datasize == 2)
result = MyT::INT16;
else if(datasize == 4)
result = MyT::INT32;
else if(datasize == 8)
result = MyT::INT64;
}
}
H5Tclose(datatype);
H5Dclose(m_dataset_handle);
return result;
} }
template<class T> } // namespace detail
void problemspec_import_HDF5(hid_t & group_id,
ProblemSpec<T> & p
aram,
std::string name)
{
hid_t param_id = H5Gopen (group_id,
name.c_str(),
H5P_DEFAULT);
vigra_postcondition(param_id >= 0, /** \brief Save a random forest to an HDF5File object into a specified HDF5
"problemspec_import_HDF5():" group.
" Unable to open external pa
rameters");
//get a map containing all the double fields The random forest is saved as a set of HDF5 datasets, groups, and
std::set<std::string> ext_set; attributes below a certain HDF5 group (default: current group of the
find_groups_hdf5(param_id, ext_set); HDF5File object). No additional data should be stored in that group.
std::map<std::string, ArrayVector <double> > ext_map;
std::set<std::string>::iterator iter;
if(ext_set.find(std::string("labels")) == ext_set.end())
std::runtime_error("labels are missing");
for(iter = ext_set.begin(); iter != ext_set.end(); ++ iter)
{
if(*iter != std::string("labels"))
{
ext_map[*iter] = ArrayVector<double>();
write_hdf5_2_array(param_id, ext_map[*iter],
*iter, H5T_NATIVE
_DOUBLE);
}
}
param.make_from_map(ext_map);
//load_class_labels
switch(type_of_hid_t(param_id,"labels" ))
{
#define SOME_CASE(type_, enum_) \
case MyT::enum_ :\
{\
ArrayVector<type_> tmp;\
write_hdf5_2_array(param_id, tmp, "labels", H5T_NATI
VE_##enum_);\
param.classes_(tmp.begin(), tmp.end());\
}\
break;
SOME_CASE(UInt8, UINT8);
SOME_CASE(UInt16, UINT16);
SOME_CASE(UInt32, UINT32);
SOME_CASE(UInt64, UINT64);
SOME_CASE(Int8, INT8);
SOME_CASE(Int16, INT16);
SOME_CASE(Int32, INT32);
SOME_CASE(Int64, INT64);
SOME_CASE(double, DOUBLE);
SOME_CASE(float, FLOAT);
default:
std::runtime_error("exportRF_HDF5(): unknown class t
ype");
#undef SOME_CASE
}
H5Gclose(param_id);
}
template<class T> \param rf Random forest object to be exported
void problemspec_export_HDF5(hid_t & group_id, \param h5context HDF5File object to use
ProblemSpec<T> cons \param pathname If empty or not supplied, save the random forest to th
t & param, e
std::string name) current group of the HDF5File object. Otherwise, save
to a
new-created group specified by the path name, which ma
y
be either relative or absolute.
*/
template<class T, class Tag>
void rf_export_HDF5(const RandomForest<T, Tag> & rf,
HDF5File & h5context,
const std::string & pathname = "")
{ {
hid_t param_id = H5Gcreate(group_id, name.c_str(), std::string cwd;
if (pathname.size()) {
H5P_DEFAULT, cwd = detail::get_cwd(h5context);
h5context.cd_mk(pathname);
H5P_DEFAULT, }
// version attribute
H5P_DEFAULT); h5context.writeAttribute(rf_hdf5_version_group, rf_hdf5_version_tag,
vigra_postcondition(param_id >= 0, rf_hdf5_version);
"problemspec_export_HDF5():" // save serialized options
" Unable to create external detail::options_export_HDF5(h5context, rf.options(), rf_hdf5_options);
parameters"); // save external parameters
detail::problemspec_export_HDF5(h5context, rf.ext_param(),
//get a map containing all the double fields rf_hdf5_ext_param);
std::map<std::string, ArrayVector<double> > serialized_param; // save trees
param.make_map(serialized_param); int tree_count = rf.options_.tree_count_;
std::map<std::string, ArrayVector<double> >::iterator iter; detail::padded_number_string tree_number(tree_count);
for(iter = serialized_param.begin(); iter != serialized_param.end(); for (int i = 0; i < tree_count; ++i)
++iter) detail::dt_export_HDF5(h5context, rf.tree(i),
write_array_2_hdf5(param_id, iter->second, iter->first, H5T_ rf_hdf5_tree + tree_number
NATIVE_DOUBLE); (i));
//save class_labels if (pathname.size())
switch(type_of(param.classes[0])) h5context.cd(cwd);
{
#define SOME_CASE(type) \
case MyT::type:\
write_array_2_hdf5(param_id, param.classes, "labels"
, H5T_NATIVE_##type);\
break;
SOME_CASE(UINT8);
SOME_CASE(UINT16);
SOME_CASE(UINT32);
SOME_CASE(UINT64);
SOME_CASE(INT8);
SOME_CASE(INT16);
SOME_CASE(INT32);
SOME_CASE(INT64);
SOME_CASE(DOUBLE);
SOME_CASE(FLOAT);
default:
std::runtime_error("exportRF_HDF5(): unknown class t
ype");
#undef SOME_CASE
}
H5Gclose(param_id);
} }
inline void dt_import_HDF5( hid_t & group_id, /** \brief Save a random forest to a named HDF5 file into a specified HDF5
RF_Traits::DecisionT group.
ree_t & tree,
std::string name)
{
//check if ext_param was written and write it if not
if(tree.ext_param_.actual_msample_ == 0)
{
problemspec_import_HDF5(group_id, tree.ext_param_, "_ext_par
am");
tree.classCount_ = tree.ext_param_.class_count_;
}
hid_t tree_id =H5Gopen (group_id, name.c_str(), H5P_DEFAULT); The random forest is saved as a set of HDF5 datasets, groups, and
//write down topology attributes below a certain HDF5 group (default: root). No additional da
write_hdf5_2_array(tree_id, ta
tree.topology_, should be stored in that group.
"topology",
H5T_NATIVE_INT);
//write down parameters
write_hdf5_2_array(tree_id,
tree.parameters_,
"parameters",
H5T_NATIVE_DOUBLE);
H5Gclose(tree_id);
}
inline void dt_export_HDF5( hid_t & group_id, \param rf Random forest object to be exported
RF_Traits::DecisionT \param filename Name of an HDF5 file to open
ree_t const & tree, \param pathname If empty or not supplied, save the random forest to the
std::string name) 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,
const std::string & filename,
const std::string & pathname = "")
{ {
//check if ext_param was written and write it if not HDF5File h5context(filename , HDF5File::Open);
hid_t e_id = H5Gopen (group_id, rf_export_HDF5(rf, h5context, pathname);
"_ext_param",
H5P_DEFAULT);
if(e_id < 0)
{
problemspec_export_HDF5(group_id,
tree.ext_par
am_,
"_ext_param"
);
}
else H5Gclose(e_id);
//make the folder for the tree.
hid_t tree_id = H5Gcreate(group_id, name.c_str(),
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
//write down topology
write_array_2_hdf5(tree_id,
tree.topology_,
"topology",
H5T_NATIVE_INT);
//write down parameters
write_array_2_hdf5(tree_id,
tree.parameters_,
"parameters",
H5T_NATIVE_DOUBLE);
H5Gclose(tree_id);
} }
} //namespace detail
template<class T>
bool rf_export_HDF5(RandomForest<T> const &rf,
std::string filename,
std::string pathname = "",
bool overwriteflag = false)
{
using detail::make_padded_number;
using detail::options_export_HDF5;
using detail::problemspec_export_HDF5;
using detail::dt_export_HDF5;
//if file exists delete it.
FILE* pFile = fopen ( filename.c_str(), "r" );
if ( pFile != NULL && !overwriteflag)
return 0;
else if(pFile != 0 &&std::remove(filename.c_str()) != 0)
return 0;
//create a new file and group. /** \brief Read a random forest from an HDF5File object's specified group.
hid_t file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC,
H5P_DEFAULT,
H5P_DEFAULT);
vigra_postcondition(file_id >= 0,
"rf_export_HDF5(): Unable to
open file.");
std::cerr << pathname.c_str();
hid_t group_id = pathname== "" ?
file_id
: H5Gcreate(file_id, pathname.
c_str(),
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
vigra_postcondition(group_id >= 0,
"rf_export_HDF5(): Unable to
create group");
//save serialized options
options_export_HDF5(group_id, rf.options(), "_options");
//save external parameters
problemspec_export_HDF5(group_id, rf.ext_param(), "_ext_para
m");
//save trees
int tree_count = rf.options_.tree_count_;
for(int ii = 0; ii < tree_count; ++ii)
{
std::string treename = "Tree_" +
make_padded_
number(ii, tree_count -1);
dt_export_HDF5(group_id, rf.tree(ii), treename);
}
//clean up the mess
if(pathname != "")
H5Gclose(group_id);
H5Fclose(file_id);
return 1; 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
attributes. No additional data should be present in that group.
template<class T> \param rf Random forest object to be imported
bool rf_import_HDF5(RandomForest<T> &rf, \param h5context HDF5File object to use
std::string filename, \param pathname If empty or not supplied, read from the random forest
std::string pathname = "") from the current group of the HDF5File object. Otherwi
se,
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,
HDF5File & h5context,
const std::string & pathname = "")
{ {
using detail::find_groups_hdf5; std::string cwd;
using detail::options_import_HDF5; if (pathname.size()) {
using detail::problemspec_import_HDF5; cwd = detail::get_cwd(h5context);
using detail::dt_export_HDF5; h5context.cd(pathname);
//if file exists delete it. }
FILE* pFile = fopen ( filename.c_str(), "r" ); // version attribute
if ( pFile == NULL) if (h5context.existsAttribute(rf_hdf5_version_group, rf_hdf5_version_ta
return 0; g))
{
//open file double read_version;
hid_t file_id = H5Fopen (filename.c_str(), h5context.readAttribute(rf_hdf5_version_group, rf_hdf5_version_tag,
H5F_ACC_RDONLY, read_version);
H5P_DEFAULT); vigra_precondition(read_version <= rf_hdf5_version,
"rf_import_HDF5(): unexpected file format version
vigra_postcondition(file_id >= 0, .");
"rf_import_HDF5(): Unable to }
open file."); // get serialized options
hid_t group_id = pathname== "" ? detail::options_import_HDF5(h5context, rf.options_, rf_hdf5_options);
file_id // get external parameters
: H5Gopen (file_id, detail::problemspec_import_HDF5(h5context, rf.ext_param_,
pathname.c_ rf_hdf5_ext_param);
str(), // get all groups in base path
H5P_DEFAULT // no check for the rf_hdf5_tree prefix...
); std::vector<std::string> names = h5context.ls();
std::vector<std::string>::const_iterator j;
vigra_postcondition(group_id >= 0, for (j = names.begin(); j != names.end(); ++j)
"rf_export_HDF5(): Unable to {
create group"); if ((*j->rbegin() == '/') && (*j->begin() != '_')) // skip the abov
e
//get serialized options {
options_import_HDF5(group_id, rf.options_, "_options"); rf.trees_.push_back(detail::DecisionTree(rf.ext_param_));
//save external parameters detail::dt_import_HDF5(h5context, rf.trees_.back(), *j);
problemspec_import_HDF5(group_id, rf.ext_param_, "_ext_param }
"); }
// TREE SAVING TIME if (pathname.size())
// get all groups in base path h5context.cd(cwd);
return true;
}
std::set<std::string> tree_set; /** \brief Read a random forest from a named HDF5 file's specified group.
std::set<std::string>::iterator iter;
find_groups_hdf5(filename, pathname, tree_set);
for(iter = tree_set.begin(); iter != tree_set.end(); ++iter) The random forest is read from a certain HDF5 group (default: root grou
{ p
if((*iter)[0] != '_') of the HDF5 file) as a set of HDF5 datasets, groups, and attributes.
{ No additional data should be present in that group.
rf.trees_.push_back(RF_Traits::DecisionTree_t(rf.ext
_param_));
dt_import_HDF5(group_id, rf.trees_.back(), *iter);
}
}
//clean up the mess \param rf Random forest object to be imported
if(pathname != "") \param filename Name of an HDF5 file to open
H5Gclose(group_id); \param pathname If empty or not supplied, read from the random forest
H5Fclose(file_id); from the current group of the HDF5 file. Otherwise,
rf.tree_indices_.resize(rf.tree_count()); use the group specified by the path name, which may
for(int ii = 0; ii < rf.tree_count(); ++ii) be either relative or absolute.
rf.tree_indices_[ii] = ii; */
return 1; template<class T, class Tag>
bool rf_import_HDF5(RandomForest<T, Tag> & rf,
const std::string & filename,
const std::string & pathname = "")
{
HDF5File h5context(filename, HDF5File::Open);
return rf_import_HDF5(rf, h5context, pathname);
} }
} // namespace vigra
#endif // HasHDF5 } // namespace vigra
#endif // VIGRA_RANDOM_FOREST_HDF5_IMPEX_HXX #endif // VIGRA_RANDOM_FOREST_HDF5_IMPEX_HXX
 End of changes. 42 change blocks. 
569 lines changed or deleted 227 lines changed or added


 rational.hxx   rational.hxx 
skipping to change at line 75 skipping to change at line 75
/* */ /* */
/* 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> \<<a href="rational_8hxx-source.html">vigra/rational.h xx</a>\><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)
{ {
// Avoid repeated construction // Avoid repeated construction
IntType zero(0); IntType zero(0);
// This is abs() - given the existence of broken compilers with Koenig // This is abs() - given the existence of broken compilers with Koenig
// lookup issues and other problems, I code this explicitly. (Remember, // lookup issues and other problems, I code this explicitly. (Remember,
skipping to change at line 116 skipping to change at line 116
/* */ /* */
/* 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> \<<a href="rational_8hxx-source.html">vigra/rational.h xx</a>\><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)
{ {
// Avoid repeated construction // Avoid repeated construction
IntType zero(0); IntType zero(0);
if (n == zero || m == zero) if (n == zero || m == zero)
return zero; return zero;
skipping to change at line 186 skipping to change at line 186
\ref AlgebraicField and the required \ref RationalTraits "numeric and \ref AlgebraicField and the required \ref RationalTraits "numeric and
promotion traits". All arithmetic and comparison operators, as well promotion traits". All arithmetic and comparison operators, as well
as the relevant algebraic functions are supported . as the relevant algebraic functions are supported .
<b>See also:</b> <b>See also:</b>
<ul> <ul>
<li> \ref RationalTraits <li> \ref RationalTraits
<li> \ref RationalOperations <li> \ref RationalOperations
</ul> </ul>
<b>\#include</b> \<<a href="rational_8hxx-source.html">vigra/rational.h xx</a>\><br> <b>\#include</b> \<vigra/rational.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <typename IntType> template <typename IntType>
class Rational class Rational
{ {
public: public:
/** The type of numerator and denominator /** The type of numerator and denominator
*/ */
typedef IntType value_type; typedef IntType value_type;
skipping to change at line 276 skipping to change at line 276
param_type numerator() const { return num; } param_type numerator() const { return num; }
/** Access denominator. /** Access denominator.
*/ */
param_type denominator() const { return den; } param_type denominator() const { return den; }
/** Add-assignment from <tt>Rational</tt> /** Add-assignment from <tt>Rational</tt>
<tt>throws bad_rational</tt> if indeterminate expression. <tt>throws bad_rational</tt> if indeterminate expression.
*/ */
Rational& operator+= (const Rational& r); Rational& operator+= (const Rational & r);
/** Subtract-assignment from <tt>Rational</tt> /** Subtract-assignment from <tt>Rational</tt>
<tt>throws bad_rational</tt> if indeterminate expression. <tt>throws bad_rational</tt> if indeterminate expression.
*/ */
Rational& operator-= (const Rational& r); Rational& operator-= (const Rational & r);
/** Multiply-assignment from <tt>Rational</tt> /** Multiply-assignment from <tt>Rational</tt>
<tt>throws bad_rational</tt> if indeterminate expression. <tt>throws bad_rational</tt> if indeterminate expression.
*/ */
Rational& operator*= (const Rational& r); Rational& operator*= (const Rational & r);
/** Divide-assignment from <tt>Rational</tt> /** Divide-assignment from <tt>Rational</tt>
<tt>throws bad_rational</tt> if indeterminate expression. <tt>throws bad_rational</tt> if indeterminate expression.
*/ */
Rational& operator/= (const Rational& r); Rational& operator/= (const Rational & r);
/** Add-assignment from <tt>IntType</tt> /** Add-assignment from <tt>IntType</tt>
<tt>throws bad_rational</tt> if indeterminate expression. <tt>throws bad_rational</tt> if indeterminate expression.
*/ */
Rational& operator+= (param_type i); Rational& operator+= (param_type i);
/** Subtract-assignment from <tt>IntType</tt> /** Subtract-assignment from <tt>IntType</tt>
<tt>throws bad_rational</tt> if indeterminate expression. <tt>throws bad_rational</tt> if indeterminate expression.
skipping to change at line 399 skipping to change at line 399
{ {
num = n; num = n;
den = d; den = d;
if(doNormalize) if(doNormalize)
normalize(); normalize();
return *this; return *this;
} }
// Arithmetic assignment operators // Arithmetic assignment operators
template <typename IntType> template <typename IntType>
Rational<IntType>& Rational<IntType>::operator+= (const Rational<IntType>& r) Rational<IntType>& Rational<IntType>::operator+= (const Rational & r)
{ {
IntType zero(0); IntType zero(0);
// handle the Inf and NaN cases // handle the Inf and NaN cases
if(den == zero) if(den == zero)
{ {
if(r.den == zero && sign()*r.sign() < 0) if(r.den == zero && sign()*r.sign() < 0)
throw bad_rational(); throw bad_rational();
return *this; return *this;
} }
skipping to change at line 449 skipping to change at line 449
den /= g; // = b1 from the calculations above den /= g; // = b1 from the calculations above
num = num * (r_den / g) + r_num * den; num = num * (r_den / g) + r_num * den;
g = gcd(num, g); g = gcd(num, g);
num /= g; num /= g;
den *= r_den/g; den *= r_den/g;
return *this; return *this;
} }
template <typename IntType> template <typename IntType>
Rational<IntType>& Rational<IntType>::operator-= (const Rational<IntType>& r) Rational<IntType>& Rational<IntType>::operator-= (const Rational & r)
{ {
IntType zero(0); IntType zero(0);
// handle the Inf and NaN cases // handle the Inf and NaN cases
if(den == zero) if(den == zero)
{ {
if(r.den == zero && sign()*r.sign() > 0) if(r.den == zero && sign()*r.sign() > 0)
throw bad_rational(); throw bad_rational();
return *this; return *this;
} }
skipping to change at line 483 skipping to change at line 483
den /= g; den /= g;
num = num * (r_den / g) - r_num * den; num = num * (r_den / g) - r_num * den;
g = gcd(num, g); g = gcd(num, g);
num /= g; num /= g;
den *= r_den/g; den *= r_den/g;
return *this; return *this;
} }
template <typename IntType> template <typename IntType>
Rational<IntType>& Rational<IntType>::operator*= (const Rational<IntType>& r) Rational<IntType>& Rational<IntType>::operator*= (const Rational & r)
{ {
IntType zero(0); IntType zero(0);
// handle the Inf and NaN cases // handle the Inf and NaN cases
if(den == zero) if(den == zero)
{ {
if(r.num == zero) if(r.num == zero)
throw bad_rational(); throw bad_rational();
num *= r.sign(); num *= r.sign();
return *this; return *this;
skipping to change at line 517 skipping to change at line 517
// Avoid overflow and preserve normalization // Avoid overflow and preserve normalization
IntType gcd1 = gcd<IntType>(num, r_den); IntType gcd1 = gcd<IntType>(num, r_den);
IntType gcd2 = gcd<IntType>(r_num, den); IntType gcd2 = gcd<IntType>(r_num, den);
num = (num/gcd1) * (r_num/gcd2); num = (num/gcd1) * (r_num/gcd2);
den = (den/gcd2) * (r_den/gcd1); den = (den/gcd2) * (r_den/gcd1);
return *this; return *this;
} }
template <typename IntType> template <typename IntType>
Rational<IntType>& Rational<IntType>::operator/= (const Rational<IntType>& r) Rational<IntType>& Rational<IntType>::operator/= (const Rational & r)
{ {
IntType zero(0); IntType zero(0);
// handle the Inf and NaN cases // handle the Inf and NaN cases
if(den == zero) if(den == zero)
{ {
if(r.den == zero) if(r.den == zero)
throw bad_rational(); throw bad_rational();
if(r.num != zero) if(r.num != zero)
num *= r.sign(); num *= r.sign();
skipping to change at line 731 skipping to change at line 731
typedef Type NormType; typedef Type NormType;
}; };
template <class T1, class T2> template <class T1, class T2>
struct PromoteTraits<Rational<T1>, Rational<T2> > struct PromoteTraits<Rational<T1>, Rational<T2> >
{ {
typedef Rational<typename PromoteTraits<T1, T2>::Promote> Promote; typedef Rational<typename PromoteTraits<T1, T2>::Promote> Promote;
}; };
\endcode \endcode
<b>\#include</b> \<<a href="rational_8hxx-source.html">vigra/rational.h xx</a>\><br> <b>\#include</b> \<vigra/rational.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
template<class T> template<class T>
struct NumericTraits<Rational<T> > struct NumericTraits<Rational<T> >
{ {
typedef Rational<T> Type; typedef Rational<T> Type;
typedef Rational<typename NumericTraits<T>::Promote> Promote; typedef Rational<typename NumericTraits<T>::Promote> Promote;
skipping to change at line 817 skipping to change at line 817
#endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION #endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION
/********************************************************/ /********************************************************/
/* */ /* */
/* RationalOperations */ /* RationalOperations */
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup RationalOperations Functions for Rational /** \addtogroup RationalOperations Functions for Rational
\brief <b>\#include</b> \<<a href="rational_8hxx-source.html">vigra /rational.hxx</a>\><br> \brief <b>\#include</b> \<vigra/rational.hxx\><br>
These functions fulfill the requirements of an \ref AlgebraicField. These functions fulfill the requirements of an \ref AlgebraicField.
Namespace: vigra Namespace: vigra
<p> <p>
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
 End of changes. 13 change blocks. 
13 lines changed or deleted 13 lines changed or added


 recursiveconvolution.hxx   recursiveconvolution.hxx 
skipping to change at line 45 skipping to change at line 45
#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"
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 117 skipping to change at line 118
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAcce ssor as, void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAcce ssor as,
DestIterator id, DestAccessor ad, DestIterator id, DestAccessor ad,
double b1, double b2) double b1, double b2)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><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; vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
vigra::recursiveFilterLine(src.begin(), src.end(), FAccessor(), vigra::recursiveFilterLine(src.begin(), src.end(), FAccessor(),
dest.begin(), FAccessor(), dest.begin(), FAccessor(),
skipping to change at line 173 skipping to change at line 174
DestIterator id, DestAccessor ad, double b, Border TreatmentMode border) DestIterator id, DestAccessor ad, double b, Border TreatmentMode border)
{ {
int w = isend - is; int w = isend - is;
SrcIterator istart = is; SrcIterator istart = is;
int x; int x;
vigra_precondition(-1.0 < b && b < 1.0, vigra_precondition(-1.0 < b && b < 1.0,
"recursiveFilterLine(): -1 < factor < 1 required.\n"); "recursiveFilterLine(): -1 < factor < 1 required.\n");
// trivial case: b == 0.0 is an identity filter => simply copy the data and return
if(b == 0.0) if(b == 0.0)
{ {
for(; is != isend; ++is, ++id) for(; is != isend; ++is, ++id)
{ {
ad.set(as(is), id); ad.set(as(is), id);
} }
return; return;
} }
double eps = 0.00001; double eps = 0.00001;
skipping to change at line 222 skipping to change at line 224
is = isend - kernelw; is = isend - kernelw;
old = TempType((1.0 / (1.0 - b)) * as(is)); old = TempType((1.0 / (1.0 - b)) * as(is));
for(x = 0; x < kernelw; ++x, ++is) for(x = 0; x < kernelw; ++x, ++is)
old = TempType(as(is) + b * old); old = TempType(as(is) + b * old);
} }
else if(border == BORDER_TREATMENT_CLIP) else if(border == BORDER_TREATMENT_CLIP)
{ {
old = NumericTraits<TempType>::zero(); old = NumericTraits<TempType>::zero();
} }
else else
{
vigra_fail("recursiveFilterLine(): Unknown border treatment mode.\n "); vigra_fail("recursiveFilterLine(): Unknown border treatment mode.\n ");
old = NumericTraits<TempType>::zero(); // fix a stupid warning
}
// left side of filter // left side of filter
for(x=0, is = istart; x < w; ++x, ++is) for(x=0, is = istart; x < w; ++x, ++is)
{ {
old = TempType(as(is) + b * old); old = TempType(as(is) + b * old);
line[x] = old; line[x] = old;
} }
// right side of the filter // right side of the filter
if(border == BORDER_TREATMENT_REPEAT || if(border == BORDER_TREATMENT_REPEAT ||
skipping to change at line 356 skipping to change at line 361
--id; --id;
for(x=w-3; x>=0; --x, --id, --is) for(x=w-3; x>=0; --x, --id, --is)
{ {
line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line [x] + b1 * line[x+1] + b2 * line[x+2]); line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line [x] + b1 * line[x+1] + b2 * line[x+2]);
ad.set(line[x], id); ad.set(line[x], id);
} }
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveGaussianFilterLine */
/* */
/********************************************************/
// AUTHOR: Sebastian Boppel
/** \brief Compute a 1-dimensional recursive approximation of Gaussian smoo
thing.
The function applies a causal and an anti-causal third order recursive
filter
which optimally approximates the Gaussian filter, as proposed in
I. Young, L. van Vliet: <i>Recursive implementation of the Gaussian fil
ter</i><br>
Signal Processing 44:139-151, 1995
The formulas for transforming the given scale parameter <tt>sigma</tt>
into the actual filter coefficients
are taken from Luigi Rosa's Matlab implementation.
The signal's value_type (SrcAccessor::value_type) must be a
linear space over <TT>double</TT>, i.e. addition of source values, mult
iplication with <TT>double</TT>,
and <TT>NumericTraits</TT> must be defined.
<b> Declaration:</b>
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void
recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcA
ccessor as,
DestIterator id, DestAccessor ad,
double sigma);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra
\code
vector<float> src, dest;
...
vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
double sigma = 2.5;
vigra::recursiveGaussianFilterLine(src.begin(), src.end(), FAccessor(),
dest.begin(), FAccessor(),
sigma);
\endcode
<b> Required Interface:</b>
\code
RandomAccessIterator is, isend;
RandomAccessIterator id;
SrcAccessor src_accessor;
DestAccessor dest_accessor;
NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is
);
double d;
s = s + s;
s = d * s;
dest_accessor.set(
NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
\endcode
<b> Preconditions:</b>
\code
0 <= sigma (absolute values are used for negative sigma)
\endcode
*/
doxygen_overloaded_function(template <...> void recursiveGaussianFilterLine
)
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
void
recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor
as,
DestIterator id, DestAccessor ad,
double sigma)
{
//coefficients taken out Luigi Rosa's implementation for Matlab
double q = 1.31564 * (std::sqrt(1.0 + 0.490811 * sigma*sigma) - 1.0);
double qq = q*q;
double qqq = qq*q;
double b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
double b1 = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
double b2 = (-1.4281*qq - 1.26661*qqq)*b0;
double b3 = 0.422205*qqq*b0;
double B = 1.0 - (b1 + b2 + b3);
int w = isend - is;
vigra_precondition(w >= 4,
"recursiveGaussianFilterLine(): line must have at least length 4.")
;
int kernelw = std::min(w-4, (int)(4.0*sigma));
int x;
typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote TempTy
pe;
typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
// speichert das Ergebnis der linkseitigen Filterung.
std::vector<TempType> yforward(w);
std::vector<TempType> ybackward(w, 0.0);
// initialise the filter for reflective boundary conditions
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]));
}
//from left to right - causal - forward
yforward[0] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (
b1*ybackward[1]+b2*ybackward[2]+b3*ybackward[3]));
++is;
yforward[1] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (
b1*yforward[0]+b2*ybackward[1]+b3*ybackward[2]));
++is;
yforward[2] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (
b1*yforward[1]+b2*yforward[0]+b3*ybackward[1]));
++is;
for(x=3; x < w; ++x, ++is)
{
yforward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is)
+ (b1*yforward[x-1]+b2*yforward[x-2]+b3*yforward[x-3]));
}
//from right to left - anticausal - backward
ybackward[w-1] = detail::RequiresExplicitCast<TempType>::cast(B*yforwar
d[w-1] + (b1*yforward[w-2]+b2*yforward[w-3]+b3*yforward[w-4]));
ybackward[w-2] = detail::RequiresExplicitCast<TempType>::cast(B*yforwar
d[w-2] + (b1*ybackward[w-1]+b2*yforward[w-2]+b3*yforward[w-3]));
ybackward[w-3] = detail::RequiresExplicitCast<TempType>::cast(B*yforwar
d[w-3] + (b1*ybackward[w-2]+b2*ybackward[w-1]+b3*yforward[w-2]));
for(x=w-4; x>=0; --x)
{
ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*yforw
ard[x]+(b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
}
// output
for(x=0; x < w; ++x, ++id)
{
ad.set(ybackward[x], id);
}
}
/********************************************************/
/* */
/* recursiveSmoothLine */ /* recursiveSmoothLine */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Convolves the image with a 1-dimensional exponential filter. /** \brief Convolves the image with a 1-dimensional exponential filter.
This function calls \ref recursiveFilterLine() with <TT>b = exp(-1.0/sc ale)</TT> This function calls \ref recursiveFilterLine() with <TT>b = exp(-1.0/sc ale)</TT>
and <TT>border = BORDER_TREATMENT_REPEAT</TT>. See and <TT>border = BORDER_TREATMENT_REPEAT</TT>. See
\ref recursiveFilterLine() for more documentation. \ref recursiveFilterLine() for more documentation.
skipping to change at line 379 skipping to change at line 540
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAcce ssor as, void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAcce ssor as,
DestIterator id, DestAccessor ad, double scale) DestIterator id, DestAccessor ad, double scale)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><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; vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
vigra::recursiveSmoothLine(src.begin(), src.end(), FAccessor(), vigra::recursiveSmoothLine(src.begin(), src.end(), FAccessor(),
dest.begin(), FAccessor(), 3.0); dest.begin(), FAccessor(), 3.0);
skipping to change at line 465 skipping to change at line 626
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend , SrcAccessor as, void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend , SrcAccessor as,
DestIterator id, DestAccessor ad, double scale) DestIterator id, DestAccessor ad, double scale)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><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; vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor() , vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor() ,
dest.begin(), FAccessor(), 3.0); dest.begin(), FAccessor(), 3.0);
skipping to change at line 584 skipping to change at line 745
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isen d, SrcAccessor as, void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isen d, SrcAccessor as,
DestIterator id, DestAccessor ad, double scale) DestIterator id, DestAccessor ad, double scale)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><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; vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor( ), vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor( ),
dest.begin(), FAccessor(), 3.0); dest.begin(), FAccessor(), 3.0);
skipping to change at line 734 skipping to change at line 895
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage src(w,h), dest(w,h);
... ...
vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), vigra::recursiveSmoothX(srcImageRange(src), destImage(dest),
0.5, BORDER_TREATMENT_REFLECT); 0.5, BORDER_TREATMENT_REFLECT);
\endcode \endcode
skipping to change at line 825 skipping to change at line 986
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)
{ {
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);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveGaussianFilterX */
/* */
/********************************************************/
// AUTHOR: Sebastian Boppel
/** \brief Compute 1 dimensional recursive approximation of Gaussian smooth
ing in y direction.
It calls \ref recursiveGaussianFilterLine() for every column of the
image. See \ref recursiveGaussianFilterLine() for more information abou
t
required interfaces and vigra_preconditions.
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
void
recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageItera
tor slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor
ad,
double sigma);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
void
recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator,
SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest
,
double sigma);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra
\code
vigra::FImage src(w,h), dest(w,h);
...
vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3.
0);
\endcode
*/
doxygen_overloaded_function(template <...> void recursiveGaussianFilterX)
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
void
recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slow
erright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad,
double sigma)
{
int w = slowerright.x - supperleft.x;
int h = slowerright.y - supperleft.y;
int y;
for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
{
typename SrcImageIterator::row_iterator rs = supperleft.rowIterator
();
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato
r();
recursiveGaussianFilterLine(rs, rs+w, as,
rd, ad,
sigma);
}
}
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
inline void
recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAcce
ssor> src,
pair<DestImageIterator, DestAccessor> dest,
double sigma)
{
recursiveGaussianFilterX(src.first, src.second, src.third,
dest.first, dest.second, 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.
skipping to change at line 863 skipping to change at line 1114
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
*/ */
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)
{ {
int w = slowerright.x - supperleft.x; int w = slowerright.x - supperleft.x;
int h = slowerright.y - supperleft.y; int h = slowerright.y - supperleft.y;
int y; int y;
for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y) for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
{ {
typename SrcImageIterator::row_iterator rs = supperleft.rowIterator (); typename SrcImageIterator::row_iterator rs = supperleft.rowIterator ();
typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r(); typename DestImageIterator::row_iterator rd = dupperleft.rowIterato r();
skipping to change at line 969 skipping to change at line 1220
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1059 skipping to change at line 1310
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)
{ {
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);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* recursiveGaussianFilterY */
/* */
/********************************************************/
// AUTHOR: Sebastian Boppel
/** \brief Compute 1 dimensional recursive approximation of Gaussian smooth
ing in y direction.
It calls \ref recursiveGaussianFilterLine() for every column of the
image. See \ref recursiveGaussianFilterLine() for more information abou
t
required interfaces and vigra_preconditions.
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
void
recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageItera
tor slowerright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor
ad,
double sigma);
}
\endcode
use argument objects in conjunction with \ref ArgumentObjectFactories :
\code
namespace vigra {
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
void
recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator,
SrcAccessor> src,
pair<DestImageIterator, DestAccessor> dest
,
double sigma);
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra
\code
vigra::FImage src(w,h), dest(w,h);
...
vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3.
0);
\endcode
*/
doxygen_overloaded_function(template <...> void recursiveGaussianFilterY)
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
void
recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slow
erright, SrcAccessor as,
DestImageIterator dupperleft, DestAccessor ad,
double sigma)
{
int w = slowerright.x - supperleft.x;
int h = slowerright.y - supperleft.y;
int x;
for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
{
typename SrcImageIterator::column_iterator cs = supperleft.columnIt
erator();
typename DestImageIterator::column_iterator cd = dupperleft.columnI
terator();
recursiveGaussianFilterLine(cs, cs+h, as,
cd, ad,
sigma);
}
}
template <class SrcImageIterator, class SrcAccessor,
class DestImageIterator, class DestAccessor>
inline void
recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAcce
ssor> src,
pair<DestImageIterator, DestAccessor> dest,
double sigma)
{
recursiveGaussianFilterY(src.first, src.second, src.third,
dest.first, dest.second, 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.
skipping to change at line 1097 skipping to change at line 1438
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1186 skipping to change at line 1527
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1275 skipping to change at line 1616
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1364 skipping to change at line 1705
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 1453 skipping to change at line 1794
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="recursiveconvolution_8hxx-source.html">vigr a/recursiveconvolution.hxx</a>\><br> <b>\#include</b> \<vigra/recursiveconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
 End of changes. 20 change blocks. 
13 lines changed or deleted 396 lines changed or added


 regression.hxx   regression.hxx 
skipping to change at line 73 skipping to change at line 73
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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 115
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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; typedef T Real;
skipping to change at line 175 skipping to change at line 175
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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; typedef T Real;
const unsigned int rows = rowCount(A); const unsigned int rows = rowCount(A);
skipping to change at line 200 skipping to change at line 200
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,
"ridgeRegression(): lambda >= 0.0 required."); "ridgeRegression(): lambda >= 0.0 required.");
unsigned int m = rows; unsigned int m = rows;
unsigned int n = cols; unsigned int n = cols;
Matrix<T> u(m, n), s(n, 1), v(n, n); Matrix<T> u(m, n), s(n, 1), v(n, n);
unsigned int rank = singularValueDecomposition(A, u, s, v); unsigned int rank = singularValueDecomposition(A, u, s, v);
if(rank < n && lambda == 0.0) if(rank < n && lambda == 0.0)
return false; return false;
Matrix<T> t = transpose(u)*b; Matrix<T> t = transpose(u)*b;
for(unsigned int k=0; k<cols; ++k) for(unsigned int k=0; k<cols; ++k)
for(unsigned int l=0; l<rhsCount; ++l) for(unsigned int l=0; l<rhsCount; ++l)
t(k,l) *= s(k,0) / (sq(s(k,0)) + lambda); t(k,l) *= s(k,0) / (sq(s(k,0)) + lambda);
x = v*t; x = v*t;
skipping to change at line 248 skipping to change at line 248
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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; typedef T Real;
skipping to change at line 302 skipping to change at line 302
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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; typedef T Real;
const unsigned int rows = rowCount(A); const unsigned int rows = rowCount(A);
skipping to change at line 325 skipping to change at line 325
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.");
unsigned int m = rows; unsigned int m = rows;
unsigned int n = cols; unsigned int n = cols;
Matrix<T> u(m, n), s(n, 1), v(n, n); Matrix<T> u(m, n), s(n, 1), v(n, n);
unsigned int rank = singularValueDecomposition(A, u, s, v); unsigned int rank = singularValueDecomposition(A, u, s, v);
Matrix<T> xl = transpose(u)*b; Matrix<T> xl = transpose(u)*b;
Matrix<T> xt(cols,1); Matrix<T> xt(cols,1);
for(unsigned int i=0; i<lambdaCount; ++i) for(unsigned int i=0; i<lambdaCount; ++i)
{ {
vigra_precondition(lambda[i] >= 0.0, vigra_precondition(lambda[i] >= 0.0,
"ridgeRegressionSeries(): lambda >= 0.0 required."); "ridgeRegressionSeries(): lambda >= 0.0 required.");
if(lambda[i] == 0.0 && rank < rows) if(lambda[i] == 0.0 && rank < rows)
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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()
skipping to change at line 516 skipping to change at line 516
const MultiArrayIndex cols = columnCount(d.R); const MultiArrayIndex cols = columnCount(d.R);
const MultiArrayIndex maxRank = std::min(rows, cols); const MultiArrayIndex maxRank = std::min(rows, cols);
MultiArrayIndex maxSolutionCount = options.max_solution_count; MultiArrayIndex maxSolutionCount = options.max_solution_count;
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, columnToBeRemoved; MultiArrayIndex columnToBeAdded = 0, columnToBeRemoved = 0;
MultiArrayIndex currentSolutionCount = 0; MultiArrayIndex currentSolutionCount = 0;
while(currentSolutionCount < maxSolutionCount) while(currentSolutionCount < maxSolutionCount)
{ {
ColumnSet activeSet = d.columnPermutation.subarray(0, (unsigned int )d.activeSetSize); ColumnSet activeSet = d.columnPermutation.subarray(0, (unsigned int )d.activeSetSize);
ColumnSet inactiveSet = d.columnPermutation.subarray((unsigned int) d.activeSetSize, (unsigned int)cols); ColumnSet inactiveSet = d.columnPermutation.subarray((unsigned int) d.activeSetSize, (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
skipping to change at line 607 skipping to change at line 607
// write the current solution // write the current solution
++currentSolutionCount; ++currentSolutionCount;
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, (Array2*)0, leastAngleRegressionMainLoop(nnd, nnactiveSets, &nnresults, (Array2*)0,
LeastAngleRegressionOptions(). leastSquaresSolutions(false).nnlasso()); LeastAngleRegressionOptions(). leastSquaresSolutions(false).nnlasso());
Matrix<T> nnlsq_solution(d.activeSetSize, 1); Matrix<T> nnlsq_solution(d.activeSetSize, 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);
} }
skipping to change at line 686 skipping to change at line 686
// 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 (unsigned int)currentSolutionCount;
} }
#if 0
// old version, keep it until we are sure that the new version works
template <class T, class C1, class C2, class Array1, class Array2>
unsigned int leastAngleRegressionMainLoop(LarsData<T, C1, C2> & d,
Array1 & activeSets, Array2 * lars_solutions, Array2 * ls
q_solutions,
LeastAngleRegressionOptions const & options)
{
using namespace vigra::functor;
typedef typename MultiArrayShape<2>::type Shape;
typedef typename Matrix<T>::view_type Subarray;
typedef ArrayVector<MultiArrayIndex> Permutation;
typedef typename Permutation::view_type ColumnSet;
vigra_precondition(d.activeSetSize > 0,
"leastAngleRegressionMainLoop() must not be called with empty active
set.");
bool enforce_positive = (options.mode == LeastAngleRegressionOptions::N
NLASSO);
bool lasso_modification = (options.mode != LeastAngleRegressionOptions:
:LARS);
const MultiArrayIndex rows = rowCount(d.R);
const MultiArrayIndex cols = columnCount(d.R);
const MultiArrayIndex maxRank = std::min(rows, cols);
MultiArrayIndex maxSolutionCount = options.max_solution_count;
if(maxSolutionCount == 0)
maxSolutionCount = lasso_modification
? 10*maxRank
: maxRank;
bool needToRemoveColumn = false;
MultiArrayIndex columnToBeAdded, columnToBeRemoved;
MultiArrayIndex currentSolutionCount = 0;
while(currentSolutionCount < maxSolutionCount)
{
ColumnSet activeSet = d.columnPermutation.subarray(0, (unsigned int
)d.activeSetSize);
ColumnSet inactiveSet = d.columnPermutation.subarray((unsigned int)
d.activeSetSize, (unsigned int)cols);
// find next dimension to be activated
Matrix<T> lars_residual = d.b - d.lars_prediction;
Matrix<T> lsq_residual = lars_residual - d.searchVector;
Matrix<T> c = transpose(d.A) * lars_residual;
// In theory, all vecors in the active set should have the same cor
relation C, and
// 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
// determine C from the entire set of variables.
MultiArrayIndex cmaxIndex = enforce_positive
? argMax(c)
: argMax(abs(c));
T C = abs(c(cmaxIndex, 0));
Matrix<T> ac(cols - d.activeSetSize, 1);
for(MultiArrayIndex k = 0; k<cols-d.activeSetSize; ++k)
{
T a = dot(columnVector(d.A, inactiveSet[k]), d.searchVector),
a1 = (C - c(inactiveSet[k], 0)) / (C - a),
a2 = (C + c(inactiveSet[k], 0)) / (C + a);
if(enforce_positive)
ac(k, 0) = a1;
else if(std::min(a1, a2) < 0.0)
ac(k, 0) = std::max(a1, a2);
else
ac(k, 0) = std::min(a1, a2);
}
// in the non-negative case: make sure that a column just removed c
annot re-enter right away
// (in standard LASSO, this is allowed, because the variable may re
-enter with opposite sign)
if(enforce_positive && needToRemoveColumn)
ac(columnToBeRemoved-d.activeSetSize,0) = -1.0;
// find candidate
// Note: R uses Arg1() > epsilon, but this is only possible because
it allows several variables to
// join the active set simultaneously, so that gamma = 0 cann
ot occur.
columnToBeAdded = argMinIf(ac, Arg1() < Param(1.0) && Arg1() >= Par
am(NumericTraits<T>::zero()));
// if no new column can be added, we do a full step gamma = 1.0 and
then stop, unless a column is removed below
T gamma = (columnToBeAdded == -1 || d.activeSetSize == maxRank)
? 1.0
: ac(columnToBeAdded, 0);
// adjust columnToBeAdded: we skipped the active set
if(columnToBeAdded >= 0)
columnToBeAdded += d.activeSetSize;
// check whether we have to remove a column from the active set
needToRemoveColumn = false;
if(lasso_modification)
{
// find dimensions whose weight changes sign below gamma*search
Direction
Matrix<T> s(Shape(d.activeSetSize, 1), NumericTraits<T>::max())
;
for(MultiArrayIndex k=0; k<d.activeSetSize; ++k)
{
if(( enforce_positive && d.next_lsq_solution(k,0) < 0.0) ||
(!enforce_positive && sign(d.lars_solution(k,0))*sign(d.
next_lsq_solution(k,0)) == -1.0))
s(k,0) = d.lars_solution(k,0) / (d.lars_solution(k,
0) - d.next_lsq_solution(k,0));
}
columnToBeRemoved = argMinIf(s, Arg1() < Param(gamma) && Arg1()
>= Param(NumericTraits<T>::zero()));
if(columnToBeRemoved >= 0)
{
needToRemoveColumn = true; // remove takes precedence over
add
gamma = s(columnToBeRemoved, 0);
}
}
// compute the current solutions
d.lars_prediction += gamma * d.searchVector;
d.lars_solution = gamma * d.next_lsq_solution + (1.0 - gamma) *
d.lars_solution;
if(needToRemoveColumn)
d.lars_solution(columnToBeRemoved, 0) = 0.0; // turn possible
epsilon into an exact zero
// write the current solution
++currentSolutionCount;
activeSets.push_back(typename Array1::value_type(d.columnPermutatio
n.begin(), d.columnPermutation.begin()+d.activeSetSize));
if(lsq_solutions != 0)
{
if(enforce_positive)
{
ArrayVector<Matrix<T> > nnresults;
ArrayVector<ArrayVector<MultiArrayIndex> > nnactiveSets;
LarsData<T, C1, C2> nnd(d, d.activeSetSize);
leastAngleRegressionMainLoop(nnd, nnactiveSets, &nnresults,
(Array2*)0,
LeastAngleRegressionOptions().
leastSquaresSolutions(false).nnlasso());
Matrix<T> nnlsq_solution(d.activeSetSize, 1);
for(unsigned int k=0; k<nnactiveSets.back().size(); ++k)
{
nnlsq_solution(nnactiveSets.back()[k],0) = nnresults.ba
ck()[k];
}
lsq_solutions->push_back(nnlsq_solution);
}
else
{
lsq_solutions->push_back(d.next_lsq_solution.subarray(Shape
(0,0), Shape(d.activeSetSize, 1)));
}
}
if(lars_solutions != 0)
{
lars_solutions->push_back(d.lars_solution.subarray(Shape(0,0),
Shape(d.activeSetSize, 1)));
}
// no further solutions possible
if(gamma == 1.0)
break;
if(needToRemoveColumn)
{
--d.activeSetSize;
if(columnToBeRemoved != d.activeSetSize)
{
// remove column 'columnToBeRemoved' and restore triangular
form of R
// note: columnPermutation is automatically swapped here
detail::upperTriangularSwapColumns(columnToBeRemoved, d.act
iveSetSize, d.R, d.qtb, d.columnPermutation);
// swap solution entries
std::swap(d.lars_solution(columnToBeRemoved, 0), d.lars_sol
ution(d.activeSetSize,0));
std::swap(d.next_lsq_solution(columnToBeRemoved, 0), d.next
_lsq_solution(d.activeSetSize,0));
columnToBeRemoved = d.activeSetSize; // keep track of remov
ed column
}
d.lars_solution(d.activeSetSize,0) = 0.0;
d.next_lsq_solution(d.activeSetSize,0) = 0.0;
}
else
{
vigra_invariant(columnToBeAdded >= 0,
"leastAngleRegression(): internal error (columnToBeAdded <
0)");
// add column 'columnToBeAdded'
if(d.activeSetSize != columnToBeAdded)
{
std::swap(d.columnPermutation[d.activeSetSize], d.columnPer
mutation[columnToBeAdded]);
columnVector(d.R, d.activeSetSize).swapData(columnVector(d.
R, columnToBeAdded));
columnToBeAdded = d.activeSetSize; // keep track of added c
olumn
}
// zero the corresponding entries of the solutions
d.next_lsq_solution(d.activeSetSize,0) = 0.0;
d.lars_solution(d.activeSetSize,0) = 0.0;
// reduce R (i.e. its newly added column) to triangular form
detail::qrColumnHouseholderStep(d.activeSetSize, d.R, d.qtb);
++d.activeSetSize;
}
// compute the LSQ solution of the new active set
Subarray Ractive = d.R.subarray(Shape(0,0), Shape(d.activeSetSize,
d.activeSetSize));
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));
linearSolveUpperTriangular(Ractive, qtbactive, next_lsq_solution_vi
ew);
// compute the LSQ prediction of the new active set
Matrix<T> lsq_prediction(rows, 1);
for(MultiArrayIndex k=0; k<d.activeSetSize; ++k)
lsq_prediction += next_lsq_solution_view(k,0)*columnVector(d.A,
d.columnPermutation[k]);
// finally, the new search direction
d.searchVector = lsq_prediction - d.lars_prediction;
}
return (unsigned int)currentSolutionCount;
}
#endif
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;
const MultiArrayIndex rows = rowCount(A); const MultiArrayIndex rows = rowCount(A);
skipping to change at line 931 skipping to change at line 726
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> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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 sqaures 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 Array2>
unsigned int unsigned int
leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray View<2, T, C2> const &b, leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray View<2, T, C2> const &b,
Array1 & activeSets, Array2 & solutions, Array1 & activeSets, Array2 & solutions,
LeastAngleRegressionOptions const & options = LeastAngleRegressionOptions()); LeastAngleRegressionOptions const & options = LeastAngleRegressionOptions());
// compute LASSO and least sqaures solutions // compute LASSO and least squares solutions
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
leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray View<2, T, C2> const &b, leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray View<2, T, C2> const &b,
Array1 & activeSets, Array2 & lasso_solutions, Array2 & lsq_solutions, Array1 & activeSets, Array2 & lasso_solutions, Array2 & lsq_solutions,
LeastAngleRegressionOptions const & options = LeastAngleRegressionOptions()); LeastAngleRegressionOptions const & options = LeastAngleRegressionOptions());
} }
using linalg::leastAngleRegression; using linalg::leastAngleRegression;
} }
\endcode \endcode
skipping to change at line 1024 skipping to change at line 819
<b>Note:</b> The second form of leastAngleRe gression() ignores this option and <b>Note:</b> The second form of leastAngleRe gression() ignores this option and
does always compute both constrained and unc onstrained solutions (returned in does always compute both constrained and unc onstrained solutions (returned in
\a lasso_solutions and \a lsq_solutions resp ectively). \a lasso_solutions and \a lsq_solutions resp ectively).
<DT><b>maxSolutionCount(unsigned int n)</b> (default: n = 0, i.e. c ompute all solutions) <DT><b>maxSolutionCount(unsigned int n)</b> (default: n = 0, i.e. c ompute all solutions)
<DD> Compute at most <tt>n</tt> solutions. <DD> Compute at most <tt>n</tt> solutions.
</DL> </DL>
<b>Usage:</b> <b>Usage:</b>
\code \code
int m = ..., n = ...; int m = ..., n = ...;
Matrix<double> A(m, n), b(m, 1); Matrix<double> A(m, n), b(m, 1);
... // fill A and b ... // fill A and b
// normalize the input // normalize the input
Matrix<double> offset(1,n), scaling(1,n); Matrix<double> offset(1,n), scaling(1,n);
prepareColumns(A, A, offset, scaling, DataPreparationGoals(ZeroM prepareColumns(A, A, offset, scaling, DataPreparationGoals(ZeroMean
ean|UnitVariance)); |UnitVariance));
prepareColumns(b, b, DataPreparationGoals(ZeroMean)); prepareColumns(b, b, DataPreparationGoals(ZeroMean));
// arrays to hold the output // arrays to hold the output
ArrayVector<ArrayVector<int> > activeSets; ArrayVector<ArrayVector<int> > activeSets;
ArrayVector<Matrix<double> > solutions; ArrayVector<Matrix<double> > solutions;
// run leastAngleRegression() in non-negative LASSO mode // run leastAngleRegression() in non-negative LASSO mode
int numSolutions = leastAngleRegression(A, b, activeSets, soluti int numSolutions = leastAngleRegression(A, b, activeSets, solutions
ons, ,
LeastAngleRegressionOptions().nnlass LeastAngleRegressionOptions().nnlasso()
o()); );
// print results // print results
Matrix<double> denseSolution(1, n); Matrix<double> denseSolution(1, n);
for (MultiArrayIndex k = 0; k < numSolutions; ++k) for (MultiArrayIndex k = 0; k < numSolutions; ++k)
{ {
// transform the sparse solution into a dense vector // transform the sparse solution into a dense vector
denseSolution.init(0.0); // ensure that inactive variabl denseSolution.init(0.0); // ensure that inactive variables are
es are zero zero
for (unsigned int i = 0; i < activeSets[k].size(); ++i) for (unsigned int i = 0; i < activeSets[k].size(); ++i)
{ {
// set the values of the active variables; // set the values of the active variables;
// activeSets[k][i] is the true index of the i-t // activeSets[k][i] is the true index of the i-th variable
h variable in the active set in the active set
denseSolution(0, activeSets[k][i]) = solutions[k denseSolution(0, activeSets[k][i]) = solutions[k](i,0);
](i,0); }
}
// invert the input normalization // invert the input normalization
denseSolution = denseSolution * pointWise(scaling); denseSolution = denseSolution * pointWise(scaling);
// output the solution // output the solution
std::cout << "solution " << k << ":\n" << denseSolution << std: :endl; std::cout << "solution " << k << ":\n" << denseSolution << std: :endl;
} }
\endcode \endcode
<b>Required Interface:</b> <b>Required Interface:</b>
<ul> <ul>
<li> <tt>T</tt> must be numeric type (compatible to double) <li> <tt>T</tt> must be numeric type (compatible to double)
<li> <tt>Array1 a1;</tt><br> <li> <tt>Array1 a1;</tt><br>
<tt>a1.push_back(ArrayVector\<int\>());</tt> <tt>a1.push_back(ArrayVector\<int\>());</tt>
<li> <tt>Array2 a2;</tt><br> <li> <tt>Array2 a2;</tt><br>
<tt>a2.push_back(Matrix\<T\>());</tt> <tt>a2.push_back(Matrix\<T\>());</tt>
skipping to change at line 1110 skipping to change at line 905
\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 t|\right|_2^2 \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\righ t|\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< /tt> column). Both \a b and \a x must be column vectors (i.e. matrices with <tt>1< /tt> column).
Note that all matrices must already have the correct shape. The solu tion is computed by means Note that all matrices must already have the correct shape. The solu tion is computed by means
of \ref leastAngleRegression() with non-negativity constraint. of \ref leastAngleRegression() with non-negativity constraint.
<b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi on.hxx</a>\> <b>\#include</b> \<vigra/regression.hxx\>
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 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) == r vigra_precondition(columnCount(A) == rowCount(x) && rowCount(A) == rowC
owCount(b), 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. "nonnegativeLeastSquares(): RHS and solution must be vectors (i.e.
e. columnCount == 1)."); columnCount == 1).");
ArrayVector<ArrayVector<MultiArrayIndex> > activeSets; ArrayVector<ArrayVector<MultiArrayIndex> > activeSets;
ArrayVector<Matrix<T> > results; ArrayVector<Matrix<T> > results;
leastAngleRegression(A, b, activeSets, results, leastAngleRegression(A, b, activeSets, results,
LeastAngleRegressionOptions().leastSquaresSolution s(false).nnlasso()); LeastAngleRegressionOptions().leastSquaresSolution s(false).nnlasso());
x.init(NumericTraits<T>::zero()); x.init(NumericTraits<T>::zero());
if(activeSets.size() > 0) if(activeSets.size() > 0)
for(unsigned int k=0; k<activeSets.back().size(); ++k) for(unsigned int k=0; k<activeSets.back().size(); ++k)
x(activeSets.back()[k],0) = results.back()[k]; x(activeSets.back()[k],0) = results.back()[k];
} }
 End of changes. 25 change blocks. 
304 lines changed or deleted 55 lines changed or added


 resampling_convolution.hxx   resampling_convolution.hxx 
skipping to change at line 229 skipping to change at line 229
sum += *k * src(ss); sum += *k * src(ss);
} }
} }
dest.set(sum, d); dest.set(sum, d);
} }
} }
/** \addtogroup ResamplingConvolutionFilters Resampling Convolution Filters /** \addtogroup ResamplingConvolutionFilters Resampling Convolution Filters
These functions implement the convolution operation when the source and target images These functions implement the convolution operation when the source and target images
have different sizes. This is realized by accessing a continous kernel at the have different sizes. This is realized by accessing a continuous kernel at the
appropriate non-integer positions. The technique is, for example, descr ibed in appropriate non-integer positions. The technique is, for example, descr ibed in
D. Schumacher: <i>General Filtered Image Rescaling</i>, in: Graphics Ge ms III, D. Schumacher: <i>General Filtered Image Rescaling</i>, in: Graphics Ge ms III,
Academic Press, 1992. Academic Press, 1992.
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* resamplingConvolveLine */ /* resamplingConvolveLine */
/* */ /* */
/********************************************************/ /********************************************************/
/** \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> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\> <b>\#include</b> \<vigra/resampling_convolution.hxx\>
\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 424 skipping to change at line 424
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\> <b>\#include</b> \<vigra/resampling_convolution.hxx\>
\code \code
Rational<int> ratio(2), offset(0); 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);
... ...
// simpultaneously 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()
skipping to change at line 561 skipping to change at line 561
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\> <b>\#include</b> \<vigra/resampling_convolution.hxx\>
\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);
... ...
// simpultaneously 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()
skipping to change at line 685 skipping to change at line 685
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\> <b>\#include</b> \<vigra/resampling_convolution.hxx\>
\code \code
Rational<int> xratio(2), yratio(3), offset(0); Rational<int> xratio(2), yratio(3), offset(0);
FImage src(w,h), FImage src(w,h),
dest(rational_cast<int>(xratio*w), rational_cast<int>(yratio*h)) ; dest(rational_cast<int>(xratio*w), rational_cast<int>(yratio*h)) ;
float sigma = 2.0; float sigma = 2.0;
Gaussian<float> smooth(sigma); Gaussian<float> smooth(sigma);
... ...
// simpultaneously enlarge and smooth source image // simultaneously enlarge and smooth source image
resamplingConvolveImage(srcImageRange(src), destImageRange(dest), resamplingConvolveImage(srcImageRange(src), destImageRange(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,
skipping to change at line 754 skipping to change at line 754
kx, samplingRatioX, offsetX, kx, samplingRatioX, offsetX,
ky, samplingRatioY, offsetY); 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> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\><br> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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);
skipping to change at line 877 skipping to change at line 877
for(int i=fromLevel+1; i <= toLevel; ++i) for(int i=fromLevel+1; i <= toLevel; ++i)
pyramidReduceBurtFilter(srcImageRange(pyramid[i-1]), destImageRange (pyramid[i]), centerValue); pyramidReduceBurtFilter(srcImageRange(pyramid[i-1]), destImageRange (pyramid[i]), centerValue);
} }
/** \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> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\><br> <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
Namespace: vigra Namespace: vigra
pass arguments explicitly: pass arguments explicitly:
\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);
skipping to change at line 999 skipping to change at line 999
"pyramidExpandBurtFilter(): fromLevel and toLevel must be between th e lowest and highest pyramid levels (inclusive)."); "pyramidExpandBurtFilter(): fromLevel and toLevel must be between th e lowest and highest pyramid levels (inclusive).");
for(int i=fromLevel-1; i >= toLevel; --i) for(int i=fromLevel-1; i >= toLevel; --i)
pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange (pyramid[i]), centerValue); pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange (pyramid[i]), centerValue);
} }
/** \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> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\><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 pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int f romLevel, int toLevel, void pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int f romLevel, 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);
skipping to change at line 1023 skipping to change at line 1023
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());
} }
} }
/** \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> \<<a href="resampling__convolution_8hxx-source.html">v igra/resampling_convolution.hxx</a>\><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 pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int f romLevel, int toLevel, void pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int f romLevel, int toLevel,
double centerValue = 0.4) double centerValue = 0.4)
{ {
using namespace functor; using namespace functor;
vigra_precondition(fromLevel > toLevel, vigra_precondition(fromLevel > toLevel,
 End of changes. 12 change blocks. 
12 lines changed or deleted 12 lines changed or added


 resizeimage.hxx   resizeimage.hxx 
skipping to change at line 74 skipping to change at line 74
\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}
\end{array}\right. \end{array}\right.
\f] \f]
It can be used as a functor, and as a kernel for It can be used as a functor, and as a kernel for
\ref resamplingConvolveImage() to create a differentiable interpolant \ref resamplingConvolveImage() to create a differentiable interpolant
of an image. of an image.
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/resizei mage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\ingroup MathFunctions \ingroup MathFunctions
*/ */
template <class T> template <class T>
class CoscotFunction class CoscotFunction
{ {
public: public:
/** the kernel's value type /** the kernel's value type
skipping to change at line 147 skipping to change at line 147
unsigned int m_; unsigned int m_;
double h_; double h_;
}; };
/** \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> \<<a href="stdimagefunctions_8hxx-source.html">vigra/s tdimagefunctions.hxx</a>\><br> <b>\#include</b> \<vigra/stdimagefunctions.hxx\><br>
<b>or</b><br> <b>or</b><br>
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/resizei mage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* resizeLineNoInterpolation */ /* resizeLineNoInterpolation */
/* */ /* */
/********************************************************/ /********************************************************/
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
skipping to change at line 229 skipping to change at line 229
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/res izeimage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\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>
skipping to change at line 278 skipping to change at line 278
DestIterator id, DestIterator idend, DestAccessor da) DestIterator id, DestIterator idend, DestAccessor da)
{ {
int w = iend.x - is.x; int w = iend.x - is.x;
int h = iend.y - is.y; int h = iend.y - is.y;
int wnew = idend.x - id.x; int wnew = idend.x - id.x;
int hnew = idend.y - id.y; int hnew = idend.y - id.y;
vigra_precondition((w > 1) && (h > 1), vigra_precondition((w > 1) && (h > 1),
"resizeImageNoInterpolation(): " "resizeImageNoInterpolation(): "
"Source image to small.\n"); "Source image too small.\n");
vigra_precondition((wnew > 1) && (hnew > 1), vigra_precondition((wnew > 1) && (hnew > 1),
"resizeImageNoInterpolation(): " "resizeImageNoInterpolation(): "
"Destination image to small.\n"); "Destination image too small.\n");
typedef BasicImage<typename SrcAccessor::value_type> TmpImage; typedef BasicImage<typename SrcAccessor::value_type> TmpImage;
typedef typename TmpImage::traverser TmpImageIterator; typedef typename TmpImage::traverser TmpImageIterator;
TmpImage tmp(w, hnew); TmpImage tmp(w, hnew);
TmpImageIterator yt = tmp.upperLeft(); TmpImageIterator yt = tmp.upperLeft();
for(int x=0; x<w; ++x, ++is.x, ++yt.x) for(int x=0; x<w; ++x, ++is.x, ++yt.x)
{ {
skipping to change at line 373 skipping to change at line 373
/********************************************************/ /********************************************************/
/* */ /* */
/* resizeImageLinearInterpolation */ /* resizeImageLinearInterpolation */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Resize image using linear interpolation. /** \brief Resize image using linear interpolation.
The function uses the standard separable bilinear interpolation algorit hm to The function uses the standard separable bilinear interpolation algorit hm to
obtain a good compromize 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. The function uses accessors.
skipping to change at line 413 skipping to change at line 413
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/res izeimage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\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>
skipping to change at line 472 skipping to change at line 472
DestIterator id, DestIterator idend, DestAccessor da) DestIterator id, DestIterator idend, DestAccessor da)
{ {
int w = iend.x - is.x; int w = iend.x - is.x;
int h = iend.y - is.y; int h = iend.y - is.y;
int wnew = idend.x - id.x; int wnew = idend.x - id.x;
int hnew = idend.y - id.y; int hnew = idend.y - id.y;
vigra_precondition((w > 1) && (h > 1), vigra_precondition((w > 1) && (h > 1),
"resizeImageLinearInterpolation(): " "resizeImageLinearInterpolation(): "
"Source image to small.\n"); "Source image too small.\n");
vigra_precondition((wnew > 1) && (hnew > 1), vigra_precondition((wnew > 1) && (hnew > 1),
"resizeImageLinearInterpolation(): " "resizeImageLinearInterpolation(): "
"Destination image to small.\n"); "Destination image too small.\n");
double const scale = 2.0; double const scale = 2.0;
typedef typename SrcAccessor::value_type SRCVT; typedef typename SrcAccessor::value_type SRCVT;
typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE; typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
typedef BasicImage<TMPTYPE> TmpImage; typedef BasicImage<TMPTYPE> TmpImage;
typedef typename TmpImage::traverser TmpImageIterator; typedef typename TmpImage::traverser TmpImageIterator;
BasicImage<TMPTYPE> tmp(w, hnew); BasicImage<TMPTYPE> tmp(w, hnew);
BasicImage<TMPTYPE> line((h > w) ? h : w, 1); BasicImage<TMPTYPE> line((h > w) ? h : w, 1);
skipping to change at line 560 skipping to change at line 560
/***************************************************************/ /***************************************************************/
/** \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
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 cion 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
which gives a twice continuously differentiable interpolant. which gives a twice continuously differentiable interpolant.
The implementation ensures that image values are interpolated rather The implementation ensures that image values are interpolated rather
than smoothed by first calling a recursive (sharpening) prefilter as than smoothed by first calling a recursive (sharpening) prefilter as
described in the above paper. Then the actual interpolation is done described in the above paper. Then the actual interpolation is done
using \ref resamplingConvolveLine(). using \ref resamplingConvolveLine().
The range of both the input and output images (resp. regions) The range of both the input and output images (resp. regions)
must be given. The input image must have a size of at must be given. The input image must have a size of at
skipping to change at line 612 skipping to change at line 612
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/res izeimage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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>
skipping to change at line 679 skipping to change at line 679
{ {
int width_old = src_iter_end.x - src_iter.x; int width_old = src_iter_end.x - src_iter.x;
int height_old = src_iter_end.y - src_iter.y; int height_old = src_iter_end.y - src_iter.y;
int width_new = dest_iter_end.x - dest_iter.x; int width_new = dest_iter_end.x - dest_iter.x;
int height_new = dest_iter_end.y - dest_iter.y; int height_new = dest_iter_end.y - dest_iter.y;
vigra_precondition((width_old > 1) && (height_old > 1), vigra_precondition((width_old > 1) && (height_old > 1),
"resizeImageSplineInterpolation(): " "resizeImageSplineInterpolation(): "
"Source image to small.\n"); "Source image too small.\n");
vigra_precondition((width_new > 1) && (height_new > 1), vigra_precondition((width_new > 1) && (height_new > 1),
"resizeImageSplineInterpolation(): " "resizeImageSplineInterpolation(): "
"Destination image to small.\n"); "Destination image too small.\n");
Rational<int> xratio(width_new - 1, width_old - 1); Rational<int> xratio(width_new - 1, width_old - 1);
Rational<int> yratio(height_new - 1, height_old - 1); Rational<int> yratio(height_new - 1, height_old - 1);
Rational<int> offset(0); Rational<int> offset(0);
resampling_detail::MapTargetToSourceCoordinate xmapCoordinate(xratio, o ffset); resampling_detail::MapTargetToSourceCoordinate xmapCoordinate(xratio, o ffset);
resampling_detail::MapTargetToSourceCoordinate ymapCoordinate(yratio, o ffset); resampling_detail::MapTargetToSourceCoordinate ymapCoordinate(yratio, o ffset);
int xperiod = lcm(xratio.numerator(), xratio.denominator()); int xperiod = lcm(xratio.numerator(), xratio.denominator());
int yperiod = lcm(yratio.numerator(), yratio.denominator()); int yperiod = lcm(yratio.numerator(), yratio.denominator());
double const scale = 2.0; double const scale = 2.0;
skipping to change at line 881 skipping to change at line 881
\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
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/resizei mage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
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)
skipping to change at line 922 skipping to change at line 922
/* */ /* */
/*****************************************************************/ /*****************************************************************/
/** \brief Resize image using the cardinal B-spline interpolation function. /** \brief Resize image using the cardinal B-spline interpolation function.
The function calls like \ref resizeImageSplineInterpolation() with The function calls like \ref resizeImageSplineInterpolation() with
\ref vigra::BSpline<3, double> and prefiltering as an interpolation ker nel. \ref vigra::BSpline<3, double> and prefiltering as an interpolation ker nel.
The interpolated function has two continuous derivatives. The interpolated function has two continuous derivatives.
(See \ref resizeImageSplineInterpolation() for more documentation) (See \ref resizeImageSplineInterpolation() for more documentation)
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/resizei mage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void void
resizeImageCubicInterpolation(SrcIterator src_iter, SrcIterator src_iter_en d, SrcAccessor src_acc, resizeImageCubicInterpolation(SrcIterator src_iter, SrcIterator src_iter_en d, 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,
skipping to change at line 985 skipping to change at line 985
\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
<b>\#include</b> \<<a href="resizeimage_8hxx-source.html">vigra/resizei mage.hxx</a>\><br> <b>\#include</b> \<vigra/resizeimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
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)
skipping to change at line 1333 skipping to change at line 1333
DestIterator id, DestIterator idend, DestAccessor da) DestIterator id, DestIterator idend, DestAccessor da)
{ {
int w = iend.x - is.x; int w = iend.x - is.x;
int h = iend.y - is.y; int h = iend.y - is.y;
int wnew = idend.x - id.x; int wnew = idend.x - id.x;
int hnew = idend.y - id.y; int hnew = idend.y - id.y;
vigra_precondition((w > 3) && (h > 3), vigra_precondition((w > 3) && (h > 3),
"resizeImageSplineInterpolation(): " "resizeImageSplineInterpolation(): "
"Source image to small.\n"); "Source image too small.\n");
vigra_precondition((wnew > 1) && (hnew > 1), vigra_precondition((wnew > 1) && (hnew > 1),
"resizeImageSplineInterpolation(): " "resizeImageSplineInterpolation(): "
"Destination image to small.\n"); "Destination image too small.\n");
double scale = 2.0; double scale = 2.0;
if(wnew < w || hnew < h) if(wnew < w || hnew < h)
{ {
typedef typename SrcAccessor::value_type SRCVT; typedef typename SrcAccessor::value_type SRCVT;
typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE; typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
typedef typename BasicImage<TMPTYPE>::Iterator TMPITER; typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
BasicImage<TMPTYPE> t(w,h); BasicImage<TMPTYPE> t(w,h);
skipping to change at line 1385 skipping to change at line 1385
template <class SrcIterator, class SrcAccessor, 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, DestAccessor> 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);
} }
#endif // old alghorithm version #endif // old algorithm version
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_RESIZEIMAGE_HXX #endif // VIGRA_RESIZEIMAGE_HXX
 End of changes. 20 change blocks. 
20 lines changed or deleted 20 lines changed or added


 rf_common.hxx   rf_common.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_RF_COMMON_HXX #ifndef VIGRA_RF_COMMON_HXX
#define VIGRA_RF_COMMON_HXX #define VIGRA_RF_COMMON_HXX
namespace vigra namespace vigra
{ {
// FORWARD DECLARATIONS struct ClassificationTag
// TODO : DECIDE WHETHER THIS IS A GOOD IDEA {};
struct ClassificationTag{};
struct RegressionTag{};
class GiniCriterion;
template<class T>
class BestGiniOfColumn;
template<class T, class U = ClassificationTag>
class ThresholdSplit;
typedef ThresholdSplit<BestGiniOfColumn<GiniCriterion> > GiniSplit;
namespace rf
{
class StopVisiting;
}
class OOB_Visitor;
class RandomForestOptions;
template<class T= double>
class ProblemSpec;
template<class LabelT = double, class Tag = ClassificationTag>
class RandomForest;
class EarlyStoppStd; struct RegressionTag
{};
namespace detail namespace detail
{ {
class RF_DEFAULT; class RF_DEFAULT;
class DecisionTree;
} }
inline detail::RF_DEFAULT& rf_default();
detail::RF_DEFAULT& rf_default();
template <class T>
class DT_StackEntry;
/**\brief Traits Class for the Random Forest
*
* refer to the typedefs in this class when using the default
* objects as the names may change in future.
*/
class RF_Traits
{
public:
typedef RandomForestOptions Options_t;
typedef detail::DecisionTree DecisionTree_t;
typedef ClassificationTag Preprocessor_t;
typedef GiniSplit Default_Split_t;
typedef EarlyStoppStd Default_Stop_t;
typedef rf::StopVisiting
Default_Visitor_t;
typedef rf::StopVisiting StopVisiting_t;
};
/**\brief Standard early stopping criterion
*
* Stop if region.size() < min_split_node_size_;
*/
class EarlyStoppStd
{
public:
int min_split_node_size_;
template<class Opt>
EarlyStoppStd(Opt opt)
: min_split_node_size_(opt.min_split_node_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)
{
return region.size() < min_split_node_size_;
}
template<class WeightIter, class T, class C>
bool after_prediction(WeightIter, int /* k */, MultiArrayView<2, T, C>
/* prob */, double /* totalCt */)
{
return false;
}
};
namespace detail namespace detail
{ {
/**\brief singleton default tag class - /* \brief singleton default tag class -
* *
* use the rf_default() factory function to use the tag. * use the rf_default() factory function to use the tag.
* \sa RandomForest<>::learn(); * \sa RandomForest<>::learn();
*/ */
class RF_DEFAULT class RF_DEFAULT
{ {
private: private:
RF_DEFAULT() RF_DEFAULT()
{} {}
public: public:
friend RF_DEFAULT& ::vigra::rf_default(); friend RF_DEFAULT& ::vigra::rf_default();
/** ok workaround for automatic choice of the decisiontree /** ok workaround for automatic choice of the decisiontree
* stackentry. * stackentry.
*/ */
typedef DT_StackEntry<ArrayVectorView<Int32>::iterator>
StackEntry_t;
}; };
/**\brief chooses between default type and type supplied /* \brief chooses between default type and type supplied
* *
* This is an internal class and you shouldn't really care about it. * This is an internal class and you shouldn't really care about it.
* Just pass on used in RandomForest.learn() * Just pass on used in RandomForest.learn()
* Usage: * Usage:
*\code *\code
* // example: use container type supplied by user or ArrayVector if * // example: use container type supplied by user or ArrayVector if
* // rf_default() was specified as argument; * // rf_default() was specified as argument;
* template<class Container_t> * template<class Container_t>
* void do_some_foo(Container_t in) * void do_some_foo(Container_t in)
* { * {
skipping to change at line 228 skipping to change at line 144
enum RF_OptionTag { RF_EQUAL, enum RF_OptionTag { RF_EQUAL,
RF_PROPORTIONAL, RF_PROPORTIONAL,
RF_EXTERNAL, RF_EXTERNAL,
RF_NONE, RF_NONE,
RF_FUNCTION, RF_FUNCTION,
RF_LOG, RF_LOG,
RF_SQRT, RF_SQRT,
RF_CONST, RF_CONST,
RF_ALL}; RF_ALL};
/** \addtogroup MachineLearning
**/
//@{
/**\brief Options object for the random forest /**\brief Options object for the random forest
* *
* usage: * usage:
* RandomForestOptions a = RandomForestOptions() * RandomForestOptions a = RandomForestOptions()
* .param1(value1) * .param1(value1)
* .param2(value2) * .param2(value2)
* ... * ...
* *
* This class only contains options/parameters that are not problem * This class only contains options/parameters that are not problem
* dependent. The ProblemSpec class contains methods to set class weights * dependent. The ProblemSpec class contains methods to set class weights
skipping to change at line 275 skipping to change at line 195
RF_OptionTag mtry_switch_; RF_OptionTag mtry_switch_;
int mtry_; int mtry_;
int (*mtry_func_)(int) ; int (*mtry_func_)(int) ;
bool predict_weighted_; bool predict_weighted_;
int tree_count_; int tree_count_;
int min_split_node_size_; int min_split_node_size_;
bool prepare_online_learning_; bool prepare_online_learning_;
/*\}*/ /*\}*/
typedef ArrayVector<double> double_array;
typedef std::map<std::string, double_array> map_type;
int serialized_size() const int serialized_size() const
{ {
return 12; return 12;
} }
bool operator==(RandomForestOptions & rhs) const bool operator==(RandomForestOptions & rhs) const
{ {
bool result = true; bool result = true;
#define COMPARE(field) result = result && (this->field == rhs.field ); #define COMPARE(field) result = result && (this->field == rhs.field );
COMPARE(training_set_proportion_); COMPARE(training_set_proportion_);
skipping to change at line 306 skipping to change at line 229
return result; return result;
} }
bool operator!=(RandomForestOptions & rhs_) const bool operator!=(RandomForestOptions & rhs_) const
{ {
return !(*this == rhs_); return !(*this == rhs_);
} }
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(static_cast<size_t>(end - begin) == serialized_s ize(), vigra_precondition(static_cast<int>(end - begin) == serialized_size (),
"RandomForestOptions::unserialize():" "RandomForestOptions::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(training_set_proportion_, double); PULL(training_set_proportion_, double);
PULL(training_set_size_, int); PULL(training_set_size_, int);
++iter; //PULL(training_set_func_, double); ++iter; //PULL(training_set_func_, double);
PULL(training_set_calc_switch_, (RF_OptionTag)int); PULL(training_set_calc_switch_, (RF_OptionTag)int);
PULL(sample_with_replacement_, 0 != ); PULL(sample_with_replacement_, 0 != );
PULL(stratification_method_, (RF_OptionTag)int); PULL(stratification_method_, (RF_OptionTag)int);
PULL(mtry_switch_, (RF_OptionTag)int); PULL(mtry_switch_, (RF_OptionTag)int);
skipping to change at line 328 skipping to change at line 251
++iter; //PULL(mtry_func_, double); ++iter; //PULL(mtry_func_, double);
PULL(tree_count_, int); PULL(tree_count_, int);
PULL(min_split_node_size_, int); PULL(min_split_node_size_, int);
PULL(predict_weighted_, 0 !=); PULL(predict_weighted_, 0 !=);
#undef PULL #undef PULL
} }
template<class Iter> template<class Iter>
void serialize(Iter const & begin, Iter const & end) const void serialize(Iter const & begin, Iter const & end) const
{ {
Iter iter = begin; Iter iter = begin;
vigra_precondition(static_cast<size_t>(end - begin) == serialized_s ize(), vigra_precondition(static_cast<int>(end - begin) == serialized_size (),
"RandomForestOptions::serialize():" "RandomForestOptions::serialize():"
"wrong number of parameters"); "wrong number of parameters");
#define PUSH(item_) *iter = double(item_); ++iter; #define PUSH(item_) *iter = double(item_); ++iter;
PUSH(training_set_proportion_); PUSH(training_set_proportion_);
PUSH(training_set_size_); PUSH(training_set_size_);
if(training_set_func_ != 0) if(training_set_func_ != 0)
{ {
PUSH(1); PUSH(1);
} }
else else
skipping to change at line 361 skipping to change at line 284
else else
{ {
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
{
typedef MultiArrayShape<2>::type Shp;
#define PULL(item_, type_) item_ = type_(in[#item_][0]);
#define PULLBOOL(item_, type_) item_ = type_(in[#item_][0] > 0);
PULL(training_set_proportion_,double);
PULL(training_set_size_, int);
PULL(mtry_, int);
PULL(tree_count_, int);
PULL(min_split_node_size_, int);
PULLBOOL(sample_with_replacement_, bool);
PULLBOOL(prepare_online_learning_, bool);
PULLBOOL(predict_weighted_, bool);
PULL(training_set_calc_switch_, (RF_OptionTag)(int));
PULL(stratification_method_, (RF_OptionTag)(int));
PULL(mtry_switch_, (RF_OptionTag)(int));
/*don't pull*/
//PULL(mtry_func_!=0, int);
//PULL(training_set_func,int);
#undef PULL
#undef PULLBOOL
}
void make_map(map_type & in) const
{
typedef MultiArrayShape<2>::type Shp;
#define PUSH(item_, type_) in[#item_] = double_array(1, double(item
_));
#define PUSHFUNC(item_, type_) in[#item_] = double_array(1, double(
item_!=0));
PUSH(training_set_proportion_,double);
PUSH(training_set_size_, int);
PUSH(mtry_, int);
PUSH(tree_count_, int);
PUSH(min_split_node_size_, int);
PUSH(sample_with_replacement_, bool);
PUSH(prepare_online_learning_, bool);
PUSH(predict_weighted_, bool);
PUSH(training_set_calc_switch_, RF_OptionTag);
PUSH(stratification_method_, RF_OptionTag);
PUSH(mtry_switch_, RF_OptionTag);
PUSHFUNC(mtry_func_, int);
PUSHFUNC(training_set_func_,int);
#undef PUSH
#undef PUSHFUNC
}
/**\brief create a RandomForestOptions object with default initialisati on. /**\brief create a RandomForestOptions object with default initialisati on.
* *
* look at the other member functions for more information on default * look at the other member functions for more information on default
* values * values
*/ */
RandomForestOptions() RandomForestOptions()
: :
training_set_proportion_(1.0), training_set_proportion_(1.0),
training_set_size_(0), training_set_size_(0),
training_set_func_(0), training_set_func_(0),
skipping to change at line 488 skipping to change at line 460
in == RF_SQRT|| in == RF_SQRT||
in == RF_ALL, in == RF_ALL,
"RandomForestOptions()::features_per_node():" "RandomForestOptions()::features_per_node():"
"input must be of type RF_LOG or RF_SQRT"); "input must be of type RF_LOG or RF_SQRT");
mtry_switch_ = in; mtry_switch_ = in;
return *this; return *this;
} }
/**\brief Set mtry to a constant value /**\brief Set mtry to a constant value
* *
* mtry is the number of columns/variates/variables randomly choosen * mtry is the number of columns/variates/variables randomly chosen
* to select the best split from. * to select the best split from.
* *
*/ */
RandomForestOptions & features_per_node(int in) RandomForestOptions & features_per_node(int in)
{ {
mtry_ = in; mtry_ = in;
mtry_switch_ = RF_CONST; mtry_switch_ = RF_CONST;
return *this; return *this;
} }
skipping to change at line 550 skipping to change at line 522
/** \brief problem specification class for the random forest. /** \brief problem specification class for the random forest.
* *
* This class contains all the problem specific parameters the random * This class contains all the problem specific parameters the random
* forest needs for learning. Specification of an instance of this class * forest needs for learning. Specification of an instance of this class
* is optional as all necessary fields will be computed prior to learning * is optional as all necessary fields will be computed prior to learning
* if not specified. * if not specified.
* *
* if needed usage is similar to that of RandomForestOptions * if needed usage is similar to that of RandomForestOptions
*/ */
template<class LabelType> template<class LabelType = double>
class ProblemSpec class ProblemSpec
{ {
public: public:
/** \brief problem class /** \brief problem class
*/ */
typedef LabelType Label_t; typedef LabelType Label_t;
ArrayVector<Label_t> classes; ArrayVector<Label_t> classes;
typedef ArrayVector<double> double_array;
typedef std::map<std::string, double_array> map_type;
int column_count_; int column_count_; // number of features
int class_count_; int class_count_; // number of classes
int row_count_; int row_count_; // number of samples
int actual_mtry_; int actual_mtry_; // mtry used in training
int actual_msample_; int actual_msample_; // number if in-bag samples p
er tree
Problem_t problem_type_; Problem_t problem_type_; // classification or regressi on
int used_; int used_; // this ProblemSpec is valid
ArrayVector<double> class_weights_; ArrayVector<double> class_weights_; // if classes have different
int is_weighted; importance
double precision_; int is_weighted_; // class_weights_ are used
double precision_; // termination criterion for
regression loss
int response_size_;
template<class T> template<class T>
void to_classlabel(int index, T & out) const void to_classlabel(int index, T & out) const
{ {
out = T(classes[index]); out = T(classes[index]);
} }
template<class T> template<class T>
int to_classIndex(T index) const int to_classIndex(T index) const
{ {
return std::find(classes.begin(), classes.end(), index) - classes.b egin(); return std::find(classes.begin(), classes.end(), index) - classes.b egin();
skipping to change at line 598 skipping to change at line 573
ProblemSpec(ProblemSpec const & rhs) ProblemSpec(ProblemSpec const & rhs)
: :
EQUALS(column_count_), EQUALS(column_count_),
EQUALS(class_count_), EQUALS(class_count_),
EQUALS(row_count_), EQUALS(row_count_),
EQUALS(actual_mtry_), EQUALS(actual_mtry_),
EQUALS(actual_msample_), EQUALS(actual_msample_),
EQUALS(problem_type_), EQUALS(problem_type_),
EQUALS(used_), EQUALS(used_),
EQUALS(class_weights_), EQUALS(class_weights_),
EQUALS(is_weighted), EQUALS(is_weighted_),
EQUALS(precision_) EQUALS(precision_),
EQUALS(response_size_)
{ {
std::back_insert_iterator<ArrayVector<Label_t> > std::back_insert_iterator<ArrayVector<Label_t> >
iter(classes); iter(classes);
std::copy(rhs.classes.begin(), rhs.classes.end(), iter); std::copy(rhs.classes.begin(), rhs.classes.end(), iter);
} }
#undef EQUALS #undef EQUALS
#define EQUALS(field) field(rhs.field) #define EQUALS(field) field(rhs.field)
template<class T> template<class T>
ProblemSpec(ProblemSpec<T> const & rhs) ProblemSpec(ProblemSpec<T> const & rhs)
: :
EQUALS(column_count_), EQUALS(column_count_),
EQUALS(class_count_), EQUALS(class_count_),
EQUALS(row_count_), EQUALS(row_count_),
EQUALS(actual_mtry_), EQUALS(actual_mtry_),
EQUALS(actual_msample_), EQUALS(actual_msample_),
EQUALS(problem_type_), EQUALS(problem_type_),
EQUALS(used_), EQUALS(used_),
EQUALS(class_weights_), EQUALS(class_weights_),
EQUALS(is_weighted), EQUALS(is_weighted_),
EQUALS(precision_) EQUALS(precision_),
EQUALS(response_size_)
{ {
std::back_insert_iterator<ArrayVector<Label_t> > std::back_insert_iterator<ArrayVector<Label_t> >
iter(classes); iter(classes);
std::copy(rhs.classes.begin(), rhs.classes.end(), iter); std::copy(rhs.classes.begin(), rhs.classes.end(), iter);
} }
#undef EQUALS #undef EQUALS
// for some reason the function below does not match
// the default copy constructor
#define EQUALS(field) (this->field = rhs.field); #define EQUALS(field) (this->field = rhs.field);
ProblemSpec & operator=(ProblemSpec const & rhs) ProblemSpec & operator=(ProblemSpec const & rhs)
{ {
EQUALS(column_count_); EQUALS(column_count_);
EQUALS(class_count_); EQUALS(class_count_);
EQUALS(row_count_); EQUALS(row_count_);
EQUALS(actual_mtry_); EQUALS(actual_mtry_);
EQUALS(actual_msample_); EQUALS(actual_msample_);
EQUALS(problem_type_); EQUALS(problem_type_);
EQUALS(used_); EQUALS(used_);
EQUALS(is_weighted); EQUALS(is_weighted_);
EQUALS(precision_); EQUALS(precision_);
EQUALS(response_size_)
class_weights_.clear(); class_weights_.clear();
std::back_insert_iterator<ArrayVector<double> > std::back_insert_iterator<ArrayVector<double> >
iter2(class_weights_); iter2(class_weights_);
std::copy(rhs.class_weights_.begin(), rhs.class_weights_.end(), ite r2); std::copy(rhs.class_weights_.begin(), rhs.class_weights_.end(), ite r2);
classes.clear(); classes.clear();
std::back_insert_iterator<ArrayVector<Label_t> > std::back_insert_iterator<ArrayVector<Label_t> >
iter(classes); iter(classes);
std::copy(rhs.classes.begin(), rhs.classes.end(), iter); std::copy(rhs.classes.begin(), rhs.classes.end(), iter);
return *this; return *this;
} }
skipping to change at line 662 skipping to change at line 638
template<class T> template<class T>
ProblemSpec<Label_t> & operator=(ProblemSpec<T> const & rhs) ProblemSpec<Label_t> & operator=(ProblemSpec<T> const & rhs)
{ {
EQUALS(column_count_); EQUALS(column_count_);
EQUALS(class_count_); EQUALS(class_count_);
EQUALS(row_count_); EQUALS(row_count_);
EQUALS(actual_mtry_); EQUALS(actual_mtry_);
EQUALS(actual_msample_); EQUALS(actual_msample_);
EQUALS(problem_type_); EQUALS(problem_type_);
EQUALS(used_); EQUALS(used_);
EQUALS(is_weighted); EQUALS(is_weighted_);
EQUALS(precision_); EQUALS(precision_);
EQUALS(response_size_)
class_weights_.clear(); class_weights_.clear();
std::back_insert_iterator<ArrayVector<double> > std::back_insert_iterator<ArrayVector<double> >
iter2(class_weights_); iter2(class_weights_);
std::copy(rhs.class_weights_.begin(), rhs.class_weights_.end(), ite r2); std::copy(rhs.class_weights_.begin(), rhs.class_weights_.end(), ite r2);
classes.clear(); classes.clear();
std::back_insert_iterator<ArrayVector<Label_t> > std::back_insert_iterator<ArrayVector<Label_t> >
iter(classes); iter(classes);
std::copy(rhs.classes.begin(), rhs.classes.end(), iter); std::copy(rhs.classes.begin(), rhs.classes.end(), iter);
return *this; return *this;
} }
skipping to change at line 687 skipping to change at line 664
bool operator==(ProblemSpec<T> const & rhs) bool operator==(ProblemSpec<T> const & rhs)
{ {
bool result = true; bool result = true;
#define COMPARE(field) result = result && (this->field == rhs.field ); #define COMPARE(field) result = result && (this->field == rhs.field );
COMPARE(column_count_); COMPARE(column_count_);
COMPARE(class_count_); COMPARE(class_count_);
COMPARE(row_count_); COMPARE(row_count_);
COMPARE(actual_mtry_); COMPARE(actual_mtry_);
COMPARE(actual_msample_); COMPARE(actual_msample_);
COMPARE(problem_type_); COMPARE(problem_type_);
COMPARE(is_weighted); COMPARE(is_weighted_);
COMPARE(precision_); COMPARE(precision_);
COMPARE(used_); COMPARE(used_);
COMPARE(class_weights_); COMPARE(class_weights_);
COMPARE(classes); COMPARE(classes);
COMPARE(response_size_)
#undef COMPARE #undef COMPARE
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 9 + 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 >= 9,
"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 >= 9 + 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);
if(is_weighted) PULL(response_size_, int);
if(is_weighted_)
{ {
vigra_precondition(end - begin == 9 + 2*class_count_, vigra_precondition(end - begin == 9 + 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 753 skipping to change at line 732
vigra_precondition(end - begin == serialized_size(), vigra_precondition(end - begin == serialized_size(),
"RandomForestOptions::serialize():" "RandomForestOptions::serialize():"
"wrong number of parameters"); "wrong number of parameters");
#define PUSH(item_) *iter = double(item_); ++iter; #define PUSH(item_) *iter = double(item_); ++iter;
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_);
if(is_weighted) PUSH(response_size_);
if(is_weighted_)
{ {
std::copy(class_weights_.begin(), std::copy(class_weights_.begin(),
class_weights_.end(), class_weights_.end(),
iter); iter);
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(std::map<std::string, ArrayVector<double> > & in) void make_from_map(map_type & in) // -> const: .operator[] -> .find
{ {
typedef MultiArrayShape<2>::type Shp; 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);
class_weights_ = in["class_weights_"]; class_weights_ = in["class_weights_"];
#undef PUSH #undef PUSH
} }
void make_map(std::map<std::string, ArrayVector<double> > & in) const void make_map(map_type & in) const
{ {
typedef MultiArrayShape<2>::type Shp; typedef MultiArrayShape<2>::type Shp;
#define PUSH(item_) in[#item_] = ArrayVector<double>(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_);
PUSH(response_size_);
in["class_weights_"] = class_weights_; in["class_weights_"] = class_weights_;
#undef PUSH #undef PUSH
} }
/**\brief set default values (-> values not set) /**\brief set default values (-> values not set)
*/ */
ProblemSpec() ProblemSpec()
: column_count_(0), : column_count_(0),
class_count_(0), class_count_(0),
row_count_(0), row_count_(0),
actual_mtry_(0), actual_mtry_(0),
actual_msample_(0), actual_msample_(0),
problem_type_(CHECKLATER), problem_type_(CHECKLATER),
used_(false), used_(false),
is_weighted(false), is_weighted_(false),
precision_(0.0) precision_(0.0),
response_size_(1)
{} {}
ProblemSpec & column_count(int in) ProblemSpec & column_count(int in)
{ {
column_count_ = in; column_count_ = in;
return *this; return *this;
} }
/**\brief supply with class labels - /**\brief supply with class labels -
* *
skipping to change at line 845 skipping to change at line 828
/** \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_.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();
column_count_ = 0 ; column_count_ = 0 ;
class_count_ = 0; class_count_ = 0;
actual_mtry_ = 0; actual_mtry_ = 0;
actual_msample_ = 0; actual_msample_ = 0;
problem_type_ = CHECKLATER; problem_type_ = CHECKLATER;
is_weighted = false; is_weighted_ = false;
precision_ = 0.0; precision_ = 0.0;
response_size_ = 0;
} }
bool used() const bool used() const
{ {
return used_ != 0; return used_ != 0;
} }
}; };
//@}
/**\brief Standard early stopping criterion
*
* Stop if region.size() < min_split_node_size_;
*/
class EarlyStoppStd
{
public:
int min_split_node_size_;
template<class Opt>
EarlyStoppStd(Opt opt)
: min_split_node_size_(opt.min_split_node_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)
{
return region.size() < min_split_node_size_;
}
template<class WeightIter, class T, class C>
bool after_prediction(WeightIter, int /* k */, MultiArrayView<2, T, C>
/* prob */, double /* totalCt */)
{
return false;
}
};
} // namespace vigra } // namespace vigra
#endif //VIGRA_RF_COMMON_HXX #endif //VIGRA_RF_COMMON_HXX
 End of changes. 45 change blocks. 
131 lines changed or deleted 153 lines changed or added


 rf_decisionTree.hxx   rf_decisionTree.hxx 
skipping to change at line 52 skipping to change at line 52
#include "vigra/multi_array.hxx" #include "vigra/multi_array.hxx"
#include "vigra/mathutil.hxx" #include "vigra/mathutil.hxx"
#include "vigra/array_vector.hxx" #include "vigra/array_vector.hxx"
#include "vigra/sized_int.hxx" #include "vigra/sized_int.hxx"
#include "vigra/matrix.hxx" #include "vigra/matrix.hxx"
#include "vigra/random.hxx" #include "vigra/random.hxx"
#include "vigra/functorexpression.hxx" #include "vigra/functorexpression.hxx"
#include <vector> #include <vector>
#include "rf_common.hxx" #include "rf_common.hxx"
#include "rf_visitors.hxx"
#include "rf_nodeproxy.hxx" #include "rf_nodeproxy.hxx"
namespace vigra namespace vigra
{ {
namespace detail namespace detail
{ {
// todo FINALLY DECIDE TO USE CAMEL CASE OR UNDERSCORES !!!!!! // todo FINALLY DECIDE TO USE CAMEL CASE OR UNDERSCORES !!!!!!
/** decisiontree classifier. /* decisiontree classifier.
* *
* This class is actually meant to be used in conjunction with the * This class is actually meant to be used in conjunction with the
* Random Forest Classifier * Random Forest Classifier
* - My suggestion would be to use the RandomForest classifier with * - My suggestion would be to use the RandomForest classifier with
* following parameters instead of directly using this * following parameters instead of directly using this
* class (Preprocessing default values etc is handled in there): * class (Preprocessing default values etc is handled in there):
* *
* \code * \code
* RandomForest decisionTree(RF_Traits::Options_t() * RandomForest decisionTree(RF_Traits::Options_t()
* .features_per_node(RF_ALL) * .features_per_node(RF_ALL)
* .tree_count(1) ); * .tree_count(1) );
* \endcode * \endcode
* *
* \todo remove the classCount and featurecount from the topology * \todo remove the classCount and featurecount from the topology
* array. Pass ext_param_ to the nodes! * array. Pass ext_param_ to the nodes!
* \todo Use relative addressing of nodes? * \todo Use relative addressing of nodes?
*/ */
class DecisionTree class DecisionTree
{ {
/**\todo make private?*/ /* \todo make private?*/
public: public:
/** value type of container array. use whenever referencing it /* value type of container array. use whenever referencing it
*/ */
typedef Int32 TreeInt; typedef Int32 TreeInt;
ArrayVector<TreeInt> topology_; ArrayVector<TreeInt> topology_;
ArrayVector<double> parameters_; ArrayVector<double> parameters_;
ProblemSpec<> ext_param_; ProblemSpec<> ext_param_;
unsigned int classCount_; unsigned int classCount_;
public: public:
/** \brief Create tree with parameters */ /* \brief Create tree with parameters */
template<class T> template<class T>
DecisionTree(ProblemSpec<T> ext_param) DecisionTree(ProblemSpec<T> ext_param)
: :
ext_param_(ext_param), ext_param_(ext_param),
classCount_(ext_param.class_count_) classCount_(ext_param.class_count_)
{} {}
/**clears all memory used. /* clears all memory used.
*/ */
void reset(unsigned int classCount = 0) void reset(unsigned int classCount = 0)
{ {
if(classCount) if(classCount)
classCount_ = classCount; classCount_ = classCount;
topology_.clear(); topology_.clear();
parameters_.clear(); parameters_.clear();
} }
/** learn a Tree /* learn a Tree
* *
* \tparam StackEntry_t The Stackentry containing Node/StackEntry_t * \tparam StackEntry_t The Stackentry containing Node/StackEntry_t
* Information used during learing. Each Split functor has a * Information used during learning. Each Split functor has a
* Stack entry associated with it (Split_t::StackEntry_t) * Stack entry associated with it (Split_t::StackEntry_t)
* \sa RandomForest::learn() * \sa RandomForest::learn()
*/ */
template < class U, class C, template < class U, class C,
class U2, class C2, class U2, class C2,
class StackEntry_t, class StackEntry_t,
class Stop_t, class Stop_t,
class Split_t, class Split_t,
class Visitor_t, class Visitor_t,
class Random_t > class Random_t >
skipping to change at line 149 skipping to change at line 150
void continueLearn( MultiArrayView<2, U, C> const & features, void continueLearn( MultiArrayView<2, U, C> const & features,
MultiArrayView<2, U2, C2> const & labels, MultiArrayView<2, U2, C2> const & labels,
StackEntry_t const & stack_entry , StackEntry_t const & stack_entry ,
Split_t split, Split_t split,
Stop_t stop, Stop_t stop,
Visitor_t & visitor, Visitor_t & visitor,
Random_t & randint, Random_t & randint,
//an index to which the last created exterior nod e will be moved (because it is not used anymore) //an index to which the last created exterior nod e will be moved (because it is not used anymore)
int garbaged_ch ild=-1); int garbaged_ch ild=-1);
/** is a node a Leaf Node? */ /* is a node a Leaf Node? */
inline bool isLeafNode(TreeInt in) const inline bool isLeafNode(TreeInt in) const
{ {
return (in & LeafNodeTag) == LeafNodeTag; return (in & LeafNodeTag) == LeafNodeTag;
} }
/** data driven traversal from root to leaf /* data driven traversal from root to leaf
* *
* traverse through tree with data given in features. Use Visitors to * traverse through tree with data given in features. Use Visitors to
* collect statistics along the way. * collect statistics along the way.
*/ */
template<class U, class C, class Visitor_t> template<class U, class C, class Visitor_t>
TreeInt getToLeaf(MultiArrayView<2, U, C> const & features, TreeInt getToLeaf(MultiArrayView<2, U, C> const & features,
Visitor_t & visitor) const Visitor_t & visitor) const
{ {
TreeInt index = 2; TreeInt index = 2;
while(!isLeafNode(topology_[index])) while(!isLeafNode(topology_[index]))
skipping to change at line 208 skipping to change at line 209
} }
#endif #endif
default: default:
vigra_fail("DecisionTree::getToLeaf():" vigra_fail("DecisionTree::getToLeaf():"
"encountered unknown internal Node Type"); "encountered unknown internal Node Type");
} }
} }
visitor.visit_external_node(*this, index, topology_[index],features ); visitor.visit_external_node(*this, index, topology_[index],features );
return index; return index;
} }
/** traverse tree to get statistics /* traverse tree to get statistics
* *
* Tree is traversed in order the Nodes are in memory (i.e. if no * Tree is traversed in order the Nodes are in memory (i.e. if no
* relearning//pruning scheme is utilized this will be pre order) * relearning//pruning scheme is utilized this will be pre order)
*/ */
template<class Visitor_t> template<class Visitor_t>
void traverse_mem_order(Visitor_t visitor) const void traverse_mem_order(Visitor_t visitor) const
{ {
TreeInt index = 2; TreeInt index = 2;
Int32 ii = 0; Int32 ii = 0;
while(index < topology_.size()) while(index < topology_.size())
skipping to change at line 280 skipping to change at line 281
{ {
stack.back()[1] = 1; stack.back()[1] = 1;
stack.push_back(Entry(node.child(0), 0)); stack.push_back(Entry(node.child(0), 0));
stack.push_back(Entry(node.child(1), 0)); stack.push_back(Entry(node.child(1), 0));
} }
} }
} }
} }
/** same thing as above, without any visitors */ /* same thing as above, without any visitors */
template<class U, class C> template<class U, class C>
TreeInt getToLeaf(MultiArrayView<2, U, C> const & features) const TreeInt getToLeaf(MultiArrayView<2, U, C> const & features) const
{ {
RF_Traits::StopVisiting_t stop; ::vigra::rf::visitors::StopVisiting stop;
return getToLeaf(features, stop); return getToLeaf(features, stop);
} }
template <class U, class C> template <class U, class C>
ArrayVector<double>::iterator ArrayVector<double>::iterator
predict(MultiArrayView<2, U, C> const & features) const predict(MultiArrayView<2, U, C> const & features) const
{ {
TreeInt nodeindex = getToLeaf(features); TreeInt nodeindex = getToLeaf(features);
switch(topology_[nodeindex]) switch(topology_[nodeindex])
{ {
skipping to change at line 386 skipping to change at line 387
// Make sure no data from the last round has remained in Pipeline; // Make sure no data from the last round has remained in Pipeline;
child_stack_entry[0].reset(); child_stack_entry[0].reset();
child_stack_entry[1].reset(); child_stack_entry[1].reset();
split.reset(); split.reset();
//Either the Stopping criterion decides that the split should //Either the Stopping criterion decides that the split should
//produce a Terminal Node or the Split itself decides what //produce a Terminal Node or the Split itself decides what
//kind of node to make //kind of node to make
TreeInt NodeID; TreeInt NodeID;
if(stop(top)) if(stop(top))
NodeID = split.makeTerminalNode(features, NodeID = split.makeTerminalNode(features,
labels, labels,
top, top,
randint); randint);
else else
{
//TIC;
NodeID = split.findBestSplit(features, NodeID = split.findBestSplit(features,
labels, labels,
top, top,
child_stack_entry, child_stack_entry,
randint); randint);
//std::cerr << TOC <<" " << NodeID << ";" <<std::endl;
}
// do some visiting yawn - just added this comment as eye candy // do some visiting yawn - just added this comment as eye candy
// (looks odd otherwise with my syntax highlighting.... // (looks odd otherwise with my syntax highlighting....
visitor.visit_after_split(*this, split, top, visitor.visit_after_split(*this, split, top,
child_stack_entry[0], child_stack_entry[0],
child_stack_entry[1], child_stack_entry[1],
features, features,
labels); labels);
// Update the Child entries of the parent // Update the Child entries of the parent
 End of changes. 16 change blocks. 
12 lines changed or deleted 18 lines changed or added


 rf_earlystopping.hxx   rf_earlystopping.hxx 
skipping to change at line 22 skipping to change at line 22
template<class T> template<class T>
T power(T const & in, int n) T power(T const & in, int n)
{ {
T result = NumericTraits<T>::one(); T result = NumericTraits<T>::one();
for(int ii = 0; ii < n ;++ii) for(int ii = 0; ii < n ;++ii)
result *= in; result *= in;
return result; return result;
} }
} }
#endif #endif
/**Base class from which all EarlyStopping Functors derive.
*/
class StopBase class StopBase
{ {
protected: protected:
ProblemSpec<> ext_param_; ProblemSpec<> ext_param_;
int tree_count_ ; int tree_count_ ;
bool is_weighted_; bool is_weighted_;
public: public:
template<class T> template<class T>
void set_external_parameters(ProblemSpec<T> const &prob, int tree_coun t = 0, bool is_weighted = false) void set_external_parameters(ProblemSpec<T> const &prob, int tree_coun t = 0, bool is_weighted = false)
{ {
ext_param_ = prob; ext_param_ = prob;
is_weighted_ = is_weighted; is_weighted_ = is_weighted;
tree_count_ = tree_count; tree_count_ = tree_count;
} }
#ifdef DOXYGEN
/** called after the prediction of a tree was added to the total pr
ediction
* \param weightIter Iterator to the weights delivered by current t
ree.
* \param k after kth tree
* \param prob Total probability array
* \param totalCt sum of probability array.
*/
template<class WeightIter, class T, class C>
bool after_prediction(WeightIter weightIter, int k, MultiArrayView<2, T
, C> const & prob , double totalCt)
#else
template<class WeightIter, class T, class C>
bool after_prediction(WeightIter, int /* k */, MultiArrayView<2, T, C>
const & /* prob */, double /* totalCt */)
{return false;}
#endif //DOXYGEN
}; };
/**Stop predicting after a set number of trees /**Stop predicting after a set number of trees
*/ */
class StopAfterTree : public StopBase class StopAfterTree : public StopBase
{ {
public: public:
double max_tree_p; double max_tree_p;
int max_tree_; int max_tree_;
typedef StopBase SB; typedef StopBase SB;
ArrayVector<double> depths; ArrayVector<double> depths;
/** Constructor
* \param max_tree number of trees to be used for prediction
*/
StopAfterTree(double max_tree) StopAfterTree(double max_tree)
: :
max_tree_p(max_tree) max_tree_p(max_tree)
{} {}
template<class T> template<class T>
void set_external_parameters(ProblemSpec<T> const &prob, int tree_coun t = 0, bool is_weighted = false) void set_external_parameters(ProblemSpec<T> const &prob, int tree_coun t = 0, bool is_weighted = false)
{ {
max_tree_ = ceil(max_tree_p * tree_count); max_tree_ = ceil(max_tree_p * tree_count);
SB::set_external_parameters(prob, tree_count, is_weighted); SB::set_external_parameters(prob, tree_count, is_weighted);
skipping to change at line 78 skipping to change at line 100
} }
if(k < max_tree_) if(k < max_tree_)
return false; return false;
depths.push_back(double(k+1)/double(SB::tree_count_)); depths.push_back(double(k+1)/double(SB::tree_count_));
return true; return true;
} }
}; };
/** Stop predicting after a certain amount of votes exceed certain proporti on. /** Stop predicting after a certain amount of votes exceed certain proporti on.
* case unweighted voting: stop if the leading class exceeds proportion * SB::tree_count_ * case unweighted voting: stop if the leading class exceeds proportion * SB::tree_count_
* case weighted votion: stop if the leading class exceeds proportion * ms ample_ * SB::tree_count_ ; * case weighted voting: stop if the leading class exceeds proportion * ms ample_ * SB::tree_count_ ;
* (maximal number of votes possible in both cases ) * (maximal number of votes possible in both cases )
*/ */
class StopAfterVoteCount : public StopBase class StopAfterVoteCount : public StopBase
{ {
public: public:
double proportion_; double proportion_;
typedef StopBase SB; typedef StopBase SB;
ArrayVector<double> depths; ArrayVector<double> depths;
/** Constructor
* \param proportion specify proportion to be used.
*/
StopAfterVoteCount(double proportion) StopAfterVoteCount(double proportion)
: :
proportion_(proportion) proportion_(proportion)
{} {}
template<class WeightIter, class T, class C> template<class WeightIter, class T, class C>
bool after_prediction(WeightIter, int k, MultiArrayView<2, T, C> const & prob, double /* totalCt */) bool after_prediction(WeightIter, int k, MultiArrayView<2, T, C> const & prob, double /* totalCt */)
{ {
if(k == SB::tree_count_ -1) if(k == SB::tree_count_ -1)
{ {
skipping to change at line 134 skipping to change at line 160
{ {
public: public:
double thresh_; double thresh_;
int num_; int num_;
MultiArray<2, double> last_; MultiArray<2, double> last_;
MultiArray<2, double> cur_; MultiArray<2, double> cur_;
ArrayVector<double> depths; ArrayVector<double> depths;
typedef StopBase SB; typedef StopBase SB;
/** Constructor
* \param thresh: If the two norm of the probabilities changes less the
n thresh then stop
* \param num : look at atleast num trees before stopping
*/
StopIfConverging(double thresh, int num = 10) StopIfConverging(double thresh, int num = 10)
: :
thresh_(thresh), thresh_(thresh),
num_(num) num_(num)
{} {}
template<class T> template<class T>
void set_external_parameters(ProblemSpec<T> const &prob, int tree_coun t = 0, bool is_weighted = false) void set_external_parameters(ProblemSpec<T> const &prob, int tree_coun t = 0, bool is_weighted = false)
{ {
last_.reshape(MultiArrayShape<2>::type(1, prob.class_count_), 0); last_.reshape(MultiArrayShape<2>::type(1, prob.class_count_), 0);
skipping to change at line 183 skipping to change at line 213
{ {
last_ = cur_; last_ = cur_;
} }
} }
return false; return false;
} }
}; };
/** Stop predicting if the margin prob(leading class) - prob(second class) exceeds a proportion /** Stop predicting if the margin prob(leading class) - prob(second class) exceeds a proportion
* case unweighted voting: stop if margin exceeds proportion * SB::tree_co unt_ * case unweighted voting: stop if margin exceeds proportion * SB::tree_co unt_
* case weighted votion: stop if margin exceeds proportion * msample_ * SB ::tree_count_ ; * case weighted voting: stop if margin exceeds proportion * msample_ * SB ::tree_count_ ;
* (maximal number of votes possible in both cases ) * (maximal number of votes possible in both cases )
*/ */
class StopIfMargin : public StopBase class StopIfMargin : public StopBase
{ {
public: public:
double proportion_; double proportion_;
typedef StopBase SB; typedef StopBase SB;
ArrayVector<double> depths; ArrayVector<double> depths;
/** Constructor
* \param proportion specify proportion to be used.
*/
StopIfMargin(double proportion) StopIfMargin(double proportion)
: :
proportion_(proportion) proportion_(proportion)
{} {}
template<class WeightIter, class T, class C> template<class WeightIter, class T, class C>
bool after_prediction(WeightIter, int k, MultiArrayView<2, T, C> prob, double /* totalCt */) bool after_prediction(WeightIter, int k, MultiArrayView<2, T, C> prob, double /* totalCt */)
{ {
if(k == SB::tree_count_ -1) if(k == SB::tree_count_ -1)
{ {
skipping to change at line 232 skipping to change at line 265
if(prob[argMax(prob)] > proportion_ * SB::tree_count_) if(prob[argMax(prob)] > proportion_ * SB::tree_count_)
{ {
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;
} }
}; };
/**Probabilistic Stopping criterion (binomial test)
*
* Can only be used in a two class setting
*
* Stop if the Parameters estimated for the underlying binomial distributio
n
* can be estimated with certainty over 1-alpha.
* (Thesis, Rahul Nair Page 80 onwards: called the "binomial" criterion
*/
class StopIfBinTest : public StopBase class StopIfBinTest : public StopBase
{ {
public: public:
double alpha_; double alpha_;
MultiArrayView<2, double> n_choose_k; MultiArrayView<2, double> n_choose_k;
/** Constructor
* \param alpha specify alpha (=proportion) value for binomial test.
* \param nck_ Matrix with precomputed values for n choose k
* nck_(n, k) is n choose k.
*/
StopIfBinTest(double alpha, MultiArrayView<2, double> nck_) StopIfBinTest(double alpha, MultiArrayView<2, double> nck_)
: :
alpha_(alpha), alpha_(alpha),
n_choose_k(nck_) n_choose_k(nck_)
{} {}
typedef StopBase SB; typedef StopBase SB;
/**ArrayVector that will contain the fraction of trees that was visited
before terminating
*/
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> prob, double totalCt) bool after_prediction(WeightIter iter, int k, MultiArrayView<2, T, C> prob, double totalCt)
skipping to change at line 295 skipping to change at line 344
if(c < n_a) if(c < n_a)
{ {
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;
} }
}; };
/**Probabilistic Stopping criteria. (toChange)
*
* Can only be used in a two class setting
*
* Stop if the probability that the decision will change after seeing all t
rees falls under
* a specified value alpha.
* (Thesis, Rahul Nair Page 80 onwards: called the "toChange" criterion
*/
class StopIfProb : public StopBase class StopIfProb : public StopBase
{ {
public: public:
double alpha_; double alpha_;
MultiArrayView<2, double> n_choose_k; MultiArrayView<2, double> n_choose_k;
/** Constructor
* \param alpha specify alpha (=proportion) value
* \param nck_ Matrix with precomputed values for n choose k
* nck_(n, k) is n choose k.
*/
StopIfProb(double alpha, MultiArrayView<2, double> nck_) StopIfProb(double alpha, MultiArrayView<2, double> nck_)
: :
alpha_(alpha), alpha_(alpha),
n_choose_k(nck_) n_choose_k(nck_)
{} {}
typedef StopBase SB; typedef StopBase SB;
/**ArrayVector that will contain the fraction of trees that was visited
before terminating
*/
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> prob, double totalCt) bool after_prediction(WeightIter iter, int k, MultiArrayView<2, T, C> prob, double totalCt)
 End of changes. 14 change blocks. 
2 lines changed or deleted 76 lines changed or added


 rf_nodeproxy.hxx   rf_nodeproxy.hxx 
skipping to change at line 98 skipping to change at line 98
typedef ArrayVector<double> P_Container_type; typedef ArrayVector<double> P_Container_type;
typedef T_Container_type::iterator Topology_type; typedef T_Container_type::iterator Topology_type;
typedef P_Container_type::iterator Parameter_type; typedef P_Container_type::iterator Parameter_type;
mutable Topology_type topology_; mutable Topology_type topology_;
int topology_size_; int topology_size_;
mutable Parameter_type parameters_; mutable Parameter_type parameters_;
int parameter_size_ ; int parameter_size_ ;
/** if numColumns = 0 then xrange is used as split axis
**/
static T_Container_type xrange;
// Tree Parameters // Tree Parameters
int featureCount_; int featureCount_;
int classCount_; int classCount_;
// Node Parameters // Node Parameters
bool hasData_; bool hasData_;
/** get Node Weight /** get Node Weight
*/ */
double & weights() double & weights()
skipping to change at line 241 skipping to change at line 237
/** Default Constructor**/ /** Default Constructor**/
NodeBase() NodeBase()
: :
hasData_(false) hasData_(false)
{} {}
void copy(const NodeBase& o) void copy(const NodeBase& o)
{ {
vigra_precondition(topology_size_==o.topology_size_,"Cannot copy no des of different sizes"); vigra_precondition(topology_size_==o.topology_size_,"Cannot copy no des of different sizes");
vigra_precondition(featureCount_==o.featureCount_,"Cannot copy node s with different feature count"); vigra_precondition(featureCount_==o.featureCount_,"Cannot copy node s with different feature count");
vigra_precondition(classCount_==o.classCount_,"Cannot copy nodes wi th different class counts"); vigra_precondition(classCount_==o.classCount_,"Cannot copy nodes wi th different class counts");
vigra_precondition(parameters_size() ==o.parameters_size(),"Cannot copy nodes with different paremater sizes"); vigra_precondition(parameters_size() ==o.parameters_size(),"Cannot copy nodes with different parameter sizes");
std::copy(o.topology_begin(), o.topology_end(), topology_); std::copy(o.topology_begin(), o.topology_end(), topology_);
std::copy(o.parameters_begin(),o.parameters_end(), parameters_); std::copy(o.parameters_begin(),o.parameters_end(), parameters_);
} }
/** create ReadOnly Base Node at position n (actual length is unknown) /** create ReadOnly Base Node at position n (actual length is unknown)
* only common features i.e. children etc are accessible. * only common features i.e. children etc are accessible.
*/ */
NodeBase( T_Container_type const & topology, NodeBase( T_Container_type const & topology,
P_Container_type const & parameter, P_Container_type const & parameter,
INT n) INT n)
skipping to change at line 324 skipping to change at line 320
: :
topology_size_(tLen), topology_size_(tLen),
parameter_size_(pLen), parameter_size_(pLen),
featureCount_(topology[0]), featureCount_(topology[0]),
classCount_(topology[1]), classCount_(topology[1]),
hasData_(true) hasData_(true)
{ {
/*while((int)xrange.size() < featureCount_) /*while((int)xrange.size() < featureCount_)
xrange.push_back(xrange.size());*/ xrange.push_back(xrange.size());*/
int n = topology.size(); size_t n = topology.size();
for(int ii = 0; ii < tLen; ++ii) for(int ii = 0; ii < tLen; ++ii)
topology.push_back(0); topology.push_back(0);
//topology.resize (n + tLen); //topology.resize (n + tLen);
topology_ = topology.begin()+ n; topology_ = topology.begin()+ n;
typeID() = UnFilledNode; typeID() = UnFilledNode;
parameter_addr() = parameter.size(); parameter_addr() = static_cast<int>(parameter.size());
//parameter.resize(parameter.size() + pLen); //parameter.resize(parameter.size() + pLen);
for(int ii = 0; ii < pLen; ++ii) for(int ii = 0; ii < pLen; ++ii)
parameter.push_back(0); parameter.push_back(0);
parameters_ = parameter.begin()+ parameter_addr(); parameters_ = parameter.begin()+ parameter_addr();
weights() = 1; weights() = 1;
} }
/** PseudoCopy Constructor - /** PseudoCopy Constructor -
skipping to change at line 362 skipping to change at line 358
: :
topology_size_(toCopy.topology_size()), topology_size_(toCopy.topology_size()),
parameter_size_(toCopy.parameters_size()), parameter_size_(toCopy.parameters_size()),
featureCount_(topology[0]), featureCount_(topology[0]),
classCount_(topology[1]), classCount_(topology[1]),
hasData_(true) hasData_(true)
{ {
/*while((int)xrange.size() < featureCount_) /*while((int)xrange.size() < featureCount_)
xrange.push_back(xrange.size());*/ xrange.push_back(xrange.size());*/
int n = topology.size(); size_t n = topology.size();
for(int ii = 0; ii < toCopy.topology_size(); ++ii) for(int ii = 0; ii < toCopy.topology_size(); ++ii)
topology.push_back(toCopy.topology_begin()[ii]); topology.push_back(toCopy.topology_begin()[ii]);
// topology.insert(topology.end(), toCopy.topology_begin(), toCopy.t opology_end()); // topology.insert(topology.end(), toCopy.topology_begin(), toCopy.t opology_end());
topology_ = topology.begin()+ n; topology_ = topology.begin()+ n;
parameter_addr() = parameter.size(); parameter_addr() = static_cast<int>(parameter.size());
for(int ii = 0; ii < toCopy.parameters_size(); ++ii) for(int ii = 0; ii < toCopy.parameters_size(); ++ii)
parameter.push_back(toCopy.parameters_begin()[ii]); parameter.push_back(toCopy.parameters_begin()[ii]);
// parameter.insert(parameter.end(), toCopy.parameters_begin(), toCo py.parameters_end()); // parameter.insert(parameter.end(), toCopy.parameters_begin(), toCo py.parameters_end());
parameters_ = parameter.begin()+ parameter_addr(); parameters_ = parameter.begin()+ parameter_addr();
} }
}; };
NodeBase::T_Container_type NodeBase::xrange;
template<NodeTags NodeType> template<NodeTags NodeType>
class Node; class Node;
template<> template<>
class Node<i_ThresholdNode> class Node<i_ThresholdNode>
: public NodeBase : public NodeBase
{ {
public: public:
typedef NodeBase BT; typedef NodeBase BT;
 End of changes. 7 change blocks. 
11 lines changed or deleted 5 lines changed or added


 rf_online_prediction_set.hxx   rf_online_prediction_set.hxx 
skipping to change at line 43 skipping to change at line 45
OnlinePredictionSet(MultiArrayView<2,T,U>& features,int num_sets) OnlinePredictionSet(MultiArrayView<2,T,U>& features,int num_sets)
{ {
this->features=features; this->features=features;
std::vector<int> init(features.shape(0)); std::vector<int> init(features.shape(0));
for(unsigned int i=0;i<init.size();++i) for(unsigned int i=0;i<init.size();++i)
init[i]=i; init[i]=i;
indices.resize(num_sets,init); indices.resize(num_sets,init);
std::set<SampleRange<T> > set_init; std::set<SampleRange<T> > set_init;
set_init.insert(SampleRange<T>(0,init.size(),features.shape(1))); set_init.insert(SampleRange<T>(0,init.size(),features.shape(1)));
ranges.resize(num_sets,set_init); ranges.resize(num_sets,set_init);
cumulativePredTime.resize(num_sets,0); cumulativePredTime.resize(num_sets,0);
} }
int get_worsed_tree() int get_worsed_tree()
{ {
int result=0; int result=0;
for(unsigned int i=0;i<cumulativePredTime.size();++i) for(unsigned int i=0;i<cumulativePredTime.size();++i)
{ {
if(cumulativePredTime[i]>cumulativePredTime[result]) if(cumulativePredTime[i]>cumulativePredTime[result])
{ {
result=i; result=i;
} }
} }
return result; return result;
} }
void reset_tree(int index) void reset_tree(int index)
{ {
index=index % ranges.size(); index=index % ranges.size();
std::set<SampleRange<T> > set_init; std::set<SampleRange<T> > set_init;
set_init.insert(SampleRange<T>(0,features.shape(0),features.shape(1 ))); set_init.insert(SampleRange<T>(0,features.shape(0),features.shape(1 )));
ranges[index]=set_init; ranges[index]=set_init;
cumulativePredTime[index]=0; cumulativePredTime[index]=0;
} }
std::vector<std::set<SampleRange<T> > > ranges; std::vector<std::set<SampleRange<T> > > ranges;
std::vector<std::vector<int> > indices; std::vector<std::vector<int> > indices;
std::vector<int> cumulativePredTime; std::vector<int> cumulativePredTime;
MultiArray<2,T> features; MultiArray<2,T> features;
}; };
} }
 End of changes. 6 change blocks. 
10 lines changed or deleted 13 lines changed or added


 rf_preprocessing.hxx   rf_preprocessing.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_RF_PREPROCESSING_HXX #ifndef VIGRA_RF_PREPROCESSING_HXX
#define VIGRA_RF_PREPROCESSING_HXX #define VIGRA_RF_PREPROCESSING_HXX
#include <limits>
#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 66 skipping to change at line 67
* RegressionTag specialisation for the basic interface if you ever happen * RegressionTag specialisation for the basic interface if you ever happen
* to care.... - or need some sort of vague new preprocessor. * to care.... - or need some sort of vague new preprocessor.
* new preprocessor ( Soft labels or whatever) * new preprocessor ( Soft labels or whatever)
*/ */
template<class Tag, class LabelType, class T1, class C1, class T2, class C2 > template<class Tag, class LabelType, class T1, class C1, class T2, class C2 >
class Processor; class Processor;
namespace detail namespace detail
{ {
/** Common helper function used in all Processors. /* Common helper function used in all Processors.
* This function analyses the options struct and calculates the real * This function analyses the options struct and calculates the real
* values needed for the current problem (data) * values needed for the current problem (data)
*/ */
template<class T> template<class T>
void fill_external_parameters(RF_Traits::Options_t & options, void fill_external_parameters(RandomForestOptions const & options,
ProblemSpe ProblemSpec<T> & ext_param)
c<T> & ext_param) {
{ // set correct value for mtry
// set correct value for mtry switch(options.mtry_switch_)
switch(options.mtry_switch_) {
{ case RF_SQRT:
case RF_SQRT:
ext_param.actual_mtry_ = ext_param.actual_mtry_ =
int(std::floor( int(std::floor(
std::sqrt(double(ext_param.column_count_)) std::sqrt(double(ext_param.column_count_))
+ 0.5)); + 0.5));
break; break;
case RF_LOG: case RF_LOG:
// this is in Breimans original paper // this is in Breimans original paper
ext_param.actual_mtry_ = ext_param.actual_mtry_ =
int(1+(std::log(double(ext_param.column_count_)) int(1+(std::log(double(ext_param.column_count_))
/std::log(2.0))); /std::log(2.0)));
break; break;
case RF_FUNCTION: case RF_FUNCTION:
ext_param.actual_mtry_ = ext_param.actual_mtry_ =
options.mtry_func_(ext_param.column_count_); options.mtry_func_(ext_param.column_count_);
break; break;
case RF_ALL: case RF_ALL:
ext_param.actual_mtry_ = ext_param.column_co ext_param.actual_mtry_ = ext_param.column_count_;
unt_; break;
break;
default: default:
ext_param.actual_mtry_ = ext_param.actual_mtry_ =
options.mtry_; options.mtry_;
} }
// 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_ * (int)std::ceil( options.training_set_proportion_ *
ext_param.row_count_); 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
*/
template<unsigned int N, class T, class C>
bool contains_nan(MultiArrayView<N, T, C> const & in)
{
for(int ii = 0; ii < in.size(); ++ii)
if(in[ii] != in[ii])
return true;
return false;
}
/* Returns true if MultiArray contains Infs
*/
template<unsigned int N, class T, class C>
bool contains_inf(MultiArrayView<N, T, C> const & in)
{
if(!std::numeric_limits<T>::has_infinity)
return false;
for(int ii = 0; ii < in.size(); ++ii)
if(in[ii] == std::numeric_limits<T>::infinity())
return true;
return false;
}
} // 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.
*/ */
template<class LabelType, class T1, class C1, class T2, class C2> template<class LabelType, class T1, class C1, class T2, class C2>
class Processor<ClassificationTag, LabelType, T1, C1, T2, C2> class Processor<ClassificationTag, LabelType, T1, C1, T2, C2>
{ {
public: public:
typedef Int32 LabelInt; typedef Int32 LabelInt;
typedef MultiArrayView<2, T1, C1> Feature_t; typedef MultiArrayView<2, T1, C1> Feature_t;
typedef MultiArrayView<2,LabelInt> Label_t; typedef MultiArray<2, T1> FeatureWithMemory_t;
MultiArrayView<2, T1, C1>const & features_; typedef MultiArrayView<2,LabelInt> Label_t;
MultiArray<2, LabelInt> intLabels_; MultiArrayView<2, T1, C1>const & features_;
MultiArrayView<2, LabelInt> strata_; MultiArray<2, LabelInt> intLabels_;
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,
RF_Traits::Options_t &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.
{ {
// set some of the problem specific parameters vigra_precondition(!detail::contains_nan(features), "Processor(): F
eature Matrix "
"Contains NaNs")
;
vigra_precondition(!detail::contains_nan(response), "Processor(): R
esponse "
"Contains NaNs")
;
vigra_precondition(!detail::contains_inf(features), "Processor(): F
eature Matrix "
"Contains inf");
vigra_precondition(!detail::contains_inf(response), "Processor(): R
esponse "
"Contains inf");
// 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)
{ {
// fill up a map with the current labels and then cr // fill up a map with the current labels and then create the
eate the // integral labels.
// integral labels. 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("unknown label type");
} }
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((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_;
} }
/** 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 intLabels_;
} }
/** Access processed strata /** Access processed strata
*/ */
MultiArrayView<2, LabelInt>& strata() ArrayVectorView < LabelInt> strata()
{ {
return intLabels_; return ArrayVectorView<LabelInt>(intLabels_.size(), intLabels_.data
} ());
}
/** Access strata fraction sized - not used currently /** Access strata fraction sized - not used currently
*/ */
ArrayVectorView< double> strata_prob() ArrayVectorView< double> strata_prob()
{ {
return ArrayVectorView< double>(); return ArrayVectorView< double>();
} }
}; };
/** Regression Preprocessor - This basically does not do anything with the /** Regression Preprocessor - This basically does not do anything with the
* data. * data.
*/ */
template<class LabelType, class T1, class C1, class T2, class C2> template<class LabelType, class T1, class C1, class T2, class C2>
class Processor<RegressionTag,LabelType, T1, C1, T2, C2> class Processor<RegressionTag,LabelType, T1, C1, T2, C2>
{ {
public: public:
// only views are created - no data copied. // only views are created - no data copied.
MultiArrayView<2, T1, C1> features_; MultiArrayView<2, T1, C1> features_;
MultiArrayView<2, T2, C2> response_; MultiArrayView<2, T2, C2> response_;
RF_Traits::Options_t const & options_; RandomForestOptions const & options_;
ProblemSpec<LabelType> const & ProblemSpec<LabelType> const &
ext_param_; ext_param_;
// will only be filled if needed // will only be filled if needed
MultiArray<2, int> strata_; MultiArray<2, int> strata_;
bool strata_filled; bool strata_filled;
// copy the views. // copy the views.
template<class T> template<class T>
Processor( MultiArrayView<2, T1, C1> feats, Processor( MultiArrayView<2, T1, C1> features,
MultiArrayView<2, T2, C2> response, MultiArrayView<2, T2, C2> response,
RF_Traits::Options_t opti RandomForestOptions const & options,
ons, ProblemSpec<T>& ext_param)
ProblemSpec<T> ext_param) :
: features_(features),
features_(feats), response_(response),
response_(response), options_(options),
options_(options), ext_param_(ext_param)
ext_param_(ext_param) {
{ // set some of the problem specific parameters
detail::fill_external_parameters(options, ext_param); ext_param.column_count_ = features.shape(1);
strata_ = MultiArray<2, int> (MultiArrayShape<2>::type(respo ext_param.row_count_ = features.shape(0);
nse_.shape(0), 1)); ext_param.problem_type_ = REGRESSION;
} ext_param.used_ = true;
detail::fill_external_parameters(options, ext_param);
vigra_precondition(!detail::contains_nan(features), "Processor(): F
eature Matrix "
"Contains NaNs")
;
vigra_precondition(!detail::contains_nan(response), "Processor(): R
esponse "
"Contains NaNs")
;
vigra_precondition(!detail::contains_inf(features), "Processor(): F
eature Matrix "
"Contains inf");
vigra_precondition(!detail::contains_inf(response), "Processor(): R
esponse "
"Contains inf");
strata_ = MultiArray<2, int> (MultiArrayShape<2>::type(response_.sh
ape(0), 1));
ext_param.response_size_ = response.shape(1);
ext_param.class_count_ = response_.shape(1);
std::vector<T2> tmp_(ext_param.class_count_, 0);
ext_param.classes_(tmp_.begin(), tmp_.end());
}
/** access preprocessed features /** access preprocessed features
*/ */
MultiArrayView<2, T1, C1> & features() MultiArrayView<2, T1, C1> & features()
{ {
return features_; return features_;
} }
/** access preprocessed response /** access preprocessed response
*/ */
MultiArrayView<2, T2, C2> & response() MultiArrayView<2, T2, C2> & response()
{ {
return response_; return response_;
} }
/** acess strata - this is not used currently /** access strata - this is not used currently
*/ */
MultiArrayView<2, int> & strata() MultiArray<2, int> & strata()
{ {
return strata_; return strata_;
} }
}; };
} }
#endif //VIGRA_RF_PREPROCESSING_HXX #endif //VIGRA_RF_PREPROCESSING_HXX
 End of changes. 23 change blocks. 
112 lines changed or deleted 172 lines changed or added


 rf_region.hxx   rf_region.hxx 
skipping to change at line 73 skipping to change at line 73
/** Address of left and Right parent in the topology container /** Address of left and Right parent in the topology container
*/ */
Int32 leftParent; Int32 leftParent;
Int32 rightParent; Int32 rightParent;
/** rule associated with current node /** rule associated with current node
*/ */
ArrayVector<std::pair<Int32, double> > rule; ArrayVector<std::pair<Int32, double> > rule;
// RegionSpecificStuff // RegionSpecificStuff
ArrayVector<Int32> classCounts_; ArrayVector<double> classCounts_;
ArrayVector<double> weightedClassCounts_; ArrayVector<double> weightedClassCounts_;
bool classCountsIsValid; bool classCountsIsValid;
bool weightedClassCountsIsValid; bool weightedClassCountsIsValid;
IndexIterator begin_, end_; IndexIterator begin_, end_;
int size_; int size_;
IndexIterator oob_begin_, oob_end_; IndexIterator oob_begin_, oob_end_;
int oob_size_; int oob_size_;
Int32 depth() Int32 depth()
{ {
skipping to change at line 144 skipping to change at line 144
} }
IndexIterator & oob_begin() IndexIterator & oob_begin()
{ {
return oob_begin_; return oob_begin_;
} }
IndexIterator & oob_end() IndexIterator & oob_end()
{ {
return oob_end_; return oob_end_;
} }
ArrayVector<Int32> & classCounts() ArrayVector<double> & classCounts()
{ {
return classCounts_; return classCounts_;
} }
ArrayVector<Int32> & weightedClassCounts() ArrayVector<double> & weightedClassCounts()
{ {
return classCounts_; return classCounts_;
} }
bool classCountsValid(bool u) bool classCountsValid(bool u)
{ {
classCountsIsValid = u; classCountsIsValid = u;
return classCountsIsValid; return classCountsIsValid;
} }
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 rf_split.hxx   rf_split.hxx 
skipping to change at line 38 skipping to change at line 38
/* 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_RANDOM_FOREST_SPLIT_HXX #ifndef VIGRA_RANDOM_FOREST_SPLIT_HXX
#define VIGRA_RANDOM_FOREST_SPLIT_HXX #define VIGRA_RANDOM_FOREST_SPLIT_HXX
#include <algorithm> #include <algorithm>
#include <cstddef>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <math.h>
#include "../mathutil.hxx" #include "../mathutil.hxx"
#include "../array_vector.hxx" #include "../array_vector.hxx"
#include "../sized_int.hxx" #include "../sized_int.hxx"
#include "../matrix.hxx" #include "../matrix.hxx"
#include "../random.hxx" #include "../random.hxx"
#include "../functorexpression.hxx" #include "../functorexpression.hxx"
#include "rf_nodeproxy.hxx" #include "rf_nodeproxy.hxx"
#include "rf_sampling.hxx" //#include "rf_sampling.hxx"
#include "rf_region.hxx"
//#include "../hokashyap.hxx" //#include "../hokashyap.hxx"
//#include "vigra/rf_helpers.hxx" //#include "vigra/rf_helpers.hxx"
namespace vigra namespace vigra
{ {
// Incomplete Class to ensure that findBestSplit is always implemented in // Incomplete Class to ensure that findBestSplit is always implemented in
// the derived classes of SplitBase // the derived classes of SplitBase
class CompileTimeError; class CompileTimeError;
namespace detail namespace detail
{ {
template<class Tag> template<class Tag>
class Normalise class Normalise
{ {
public: public:
template<class Iter> template<class Iter>
static void exec(Iter begin, Iter end) static void exec(Iter begin, Iter end)
{} {}
}; };
template<> template<>
class Normalise<ClassificationTag> class Normalise<ClassificationTag>
{ {
public: public:
template<class Iter> template<class Iter>
static void exec (Iter begin, Iter end) static void exec (Iter begin, Iter end)
{ {
double bla = std::accumulate(begin, end, 0.0); double bla = std::accumulate(begin, end, 0.0);
for(int ii = 0; ii < end - begin; ++ii) for(int ii = 0; ii < end - begin; ++ii)
begin[ii] = begin[ii]/bla ; begin[ii] = begin[ii]/bla ;
} }
}; };
} }
skipping to change at line 103 skipping to change at line 106
StackEntry_t; StackEntry_t;
ProblemSpec<> ext_param_; ProblemSpec<> ext_param_;
NodeBase::T_Container_type t_data; NodeBase::T_Container_type t_data;
NodeBase::P_Container_type p_data; NodeBase::P_Container_type p_data;
NodeBase node_; NodeBase node_;
/** returns the DecisionTree Node created by /** returns the DecisionTree Node created by
\ref findBestSplit or \ref makeTerminalNode. \ref SplitBase::findBestSplit() or \ref SplitBase::makeTerminalNode ().
**/ **/
template<class T> template<class T>
void set_external_parameters(ProblemSpec<T> const & in) void set_external_parameters(ProblemSpec<T> const & in)
{ {
ext_param_ = in; ext_param_ = in;
t_data.push_back(in.column_count_); t_data.push_back(in.column_count_);
t_data.push_back(in.class_count_); t_data.push_back(in.class_count_);
} }
skipping to change at line 138 skipping to change at line 141
/** resets internal data. Should always be called before /** resets internal data. Should always be called before
calling findBestSplit or makeTerminalNode calling findBestSplit or makeTerminalNode
**/ **/
void reset() void reset()
{ {
t_data.resize(2); t_data.resize(2);
p_data.resize(0); p_data.resize(0);
} }
/** findBestSplit has to be implemented in derived split functor. /** findBestSplit has to be re-implemented in derived split functor.
these functions only insures That a CompileTime error is issued The defaut implementation only insures that a CompileTime error is
issued
if no such method was defined. if no such method was defined.
**/ **/
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> labels, MultiArrayView<2, T2, C2> labels,
Region region, Region region,
ArrayVector<Region> childs, ArrayVector<Region> childs,
Random randint) Random randint)
{ {
#ifndef __clang__
// FIXME: This compile-time checking trick does not work for clang.
CompileTimeError SplitFunctor__findBestSplit_member_was_not_defined ; CompileTimeError SplitFunctor__findBestSplit_member_was_not_defined ;
#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
{ {
std::transform( region.classCounts().begin(), std::transform(region.classCounts().begin(),
region.classCounts().end(), region.classCounts().end(),
ext_param_.class_weights_.begin(), ext_param_.class_weights_.begin(),
ret.prob_begin(), std::multiplies<double>()); ret.prob_begin(), std::multiplies<double>());
} }
detail::Normalise<RF_Tag>::exec(ret.prob_begin(), ret.prob_end()); detail::Normalise<RF_Tag>::exec(ret.prob_begin(), ret.prob_end());
// std::copy(ret.prob_begin(), ret.prob_end(), std::ostream_iterator
<double>(std::cerr, ", " ));
// std::cerr << std::endl;
ret.weights() = region.size(); ret.weights() = region.size();
return e_ConstProbNode; return e_ConstProbNode;
} }
}; };
/** Functor to sort the indices of a feature Matrix by a certain dimension /** Functor to sort the indices of a feature Matrix by a certain dimension
**/ **/
template<class DataMatrix> template<class DataMatrix>
class SortSamplesByDimensions class SortSamplesByDimensions
skipping to change at line 260 skipping to change at line 268
{ {
DataMatrix const & data_; DataMatrix const & data_;
Node<i_HyperplaneNode> const & node_; Node<i_HyperplaneNode> const & node_;
public: public:
SortSamplesByHyperplane(DataMatrix const & data, SortSamplesByHyperplane(DataMatrix const & data,
Node<i_HyperplaneNode> const & node) Node<i_HyperplaneNode> const & node)
: :
data_(data), data_(data),
node_() node_(node)
{} {}
/** calculate the distance of a sample point to a hyperplane /** calculate the distance of a sample point to a hyperplane
*/ */
double operator[](MultiArrayIndex l) const double operator[](MultiArrayIndex l) const
{ {
double result_l = -1 * node_.intercept(); double result_l = -1 * node_.intercept();
for(int ii = 0; ii < node_.columns_size(); ++ii) for(int ii = 0; ii < node_.columns_size(); ++ii)
{ {
result_l += rowVector(data_, l)[node_.columns_begin()[ii]] result_l += rowVector(data_, l)[node_.columns_begin()[ii]]
skipping to change at line 337 skipping to change at line 345
{ {
public: public:
double operator[](size_t) const double operator[](size_t) const
{ {
return (double)N; return (double)N;
} }
}; };
} }
/** Functor to calculate the entropy based impurity
*/
class EntropyCriterion
{
public:
/**calculate the weighted gini impurity based on class histogram
* and class weights
*/
template<class Array, class Array2>
double operator() (Array const & hist,
Array2 const & weights,
double total = 1.0) const
{
return impurity(hist, weights, total);
}
/** calculate the gini based impurity based on class histogram
*/
template<class Array>
double operator()(Array const & hist, double total = 1.0) const
{
return impurity(hist, total);
}
/** static version of operator(hist total)
*/
template<class Array>
static double impurity(Array const & hist, double total)
{
return impurity(hist, detail::ConstArr<1>(), total);
}
/** static version of operator(hist, weights, total)
*/
template<class Array, class Array2>
static double impurity (Array const & hist,
Array2 const & weights,
double total)
{
int class_count = hist.size();
double entropy = 0.0;
if(class_count == 2)
{
double p0 = (hist[0]/total);
double p1 = (hist[1]/total);
entropy = 0 - weights[0]*p0*std::log(p0) - weights[
1]*p1*std::log(p1);
}
else
{
for(int ii = 0; ii < class_count; ++ii)
{
double w = weights[ii];
double pii = hist[ii]/total;
entropy -= w*( pii*std::log(pii));
}
}
entropy = total * entropy;
return entropy;
}
};
/** Functor to calculate the gini impurity /** Functor to calculate the gini impurity
*/ */
class GiniCriterion class GiniCriterion
{ {
public: public:
/**caculate the weighted gini impurity based on class histogram /**calculate the weighted gini impurity based on class histogram
* and class weights * and class weights
*/ */
template<class Array, class Array2> template<class Array, class Array2>
double operator() (Array const & hist, double operator() (Array const & hist,
Array2 const & weights, Array2 const & weights,
double total = 1.0) const double total = 1.0) const
{ {
return impurity(hist, weights, total); return impurity(hist, weights, total);
} }
skipping to change at line 378 skipping to change at line 448
/** static version of operator(hist, weights, total) /** static version of operator(hist, weights, total)
*/ */
template<class Array, class Array2> template<class Array, class Array2>
static double impurity (Array const & hist, static double impurity (Array const & hist,
Array2 const & weights, Array2 const & weights,
double total) double total)
{ {
int class_count = hist.size(); int class_count = hist.size();
double gini = 0; double gini = 0.0;
if(class_count == 2) if(class_count == 2)
{ {
double w = weights[0] * weights[1]; double w = weights[0] * weights[1];
gini = w * (hist[0] * hist[1] / total); gini = w * (hist[0] * hist[1] / total);
} }
else else
{ {
for(int ii = 0; ii < class_count; ++ii) for(int ii = 0; ii < class_count; ++ii)
{ {
double w = weights[ii]; double w = weights[ii];
skipping to change at line 402 skipping to change at line 472
return gini; return gini;
} }
}; };
template <class DataSource, class Impurity= GiniCriterion> template <class DataSource, class Impurity= GiniCriterion>
class ImpurityLoss class ImpurityLoss
{ {
DataSource const & labels_; DataSource const & labels_;
ArrayVector<double> counts_; ArrayVector<double> counts_;
ArrayVector<double> const & class_weights_; ArrayVector<double> const class_weights_;
double total_counts_; double total_counts_;
Impurity impurity_; Impurity impurity_;
public: public:
template<class T> template<class T>
ImpurityLoss(DataSource const & labels, ImpurityLoss(DataSource const & labels,
ProblemSpec<T> const & ext_) ProblemSpec<T> const & ext_)
: labels_(labels), : labels_(labels),
counts_(ext_.class_count_, 0.0), counts_(ext_.class_count_, 0.0),
skipping to change at line 452 skipping to change at line 522
counts_.end(), counts_.end(),
0.0); 0.0);
return impurity_(counts_, class_weights_, total_counts_); return impurity_(counts_, class_weights_, total_counts_);
} }
template<class Iter> template<class Iter>
double increment(Iter begin, Iter end) double increment(Iter begin, Iter end)
{ {
for(Iter iter = begin; iter != end; ++iter) for(Iter iter = begin; iter != end; ++iter)
{ {
counts_[labels_[*iter]] +=1; counts_[labels_(*iter, 0)] +=1.0;
total_counts_ +=1; total_counts_ +=1.0;
} }
return impurity_(counts_, class_weights_, total_counts_); return impurity_(counts_, class_weights_, total_counts_);
} }
template<class Iter> template<class Iter>
double decrement(Iter begin, Iter end) double decrement(Iter const & begin, Iter const & end)
{ {
for(Iter iter = begin; iter != end; ++iter) for(Iter iter = begin; iter != end; ++iter)
{ {
counts_[labels_[*iter]] -=1; counts_[labels_(*iter,0)] -=1.0;
total_counts_ -=1; total_counts_ -=1.0;
} }
return impurity_(counts_, class_weights_, total_counts_); return impurity_(counts_, class_weights_, total_counts_);
} }
template<class Iter, class Resp_t> template<class Iter, class Resp_t>
double init (Iter begin, Iter end, Resp_t resp) double init (Iter begin, Iter end, Resp_t resp)
{ {
reset(); reset();
std::copy(resp.begin(), resp.end(), counts_.begin()); std::copy(resp.begin(), resp.end(), counts_.begin());
total_counts_ = std::accumulate(counts_.begin(), counts_.end(), 0.0 ); total_counts_ = std::accumulate(counts_.begin(), counts_.end(), 0.0 );
return impurity_(counts_,class_weights_, total_counts_); return impurity_(counts_,class_weights_, total_counts_);
} }
ArrayVector<double> const & response() ArrayVector<double> const & response()
{ {
return counts_; return counts_;
} }
}; };
template <class DataSource>
class RegressionForestCounter
{
public:
typedef MultiArrayShape<2>::type Shp;
DataSource const & labels_;
ArrayVector <double> mean_;
ArrayVector <double> variance_;
ArrayVector <double> tmp_;
size_t count_;
int* end_;
template<class T>
RegressionForestCounter(DataSource const & labels,
ProblemSpec<T> const & ext_)
:
labels_(labels),
mean_(ext_.response_size_, 0.0),
variance_(ext_.response_size_, 0.0),
tmp_(ext_.response_size_),
count_(0)
{}
template<class Iter>
double increment (Iter begin, Iter end)
{
for(Iter iter = begin; iter != end; ++iter)
{
++count_;
for(unsigned int ii = 0; ii < mean_.size(); ++ii)
tmp_[ii] = labels_(*iter, ii) - mean_[ii];
double f = 1.0 / count_,
f1 = 1.0 - f;
for(unsigned int ii = 0; ii < mean_.size(); ++ii)
mean_[ii] += f*tmp_[ii];
for(unsigned int ii = 0; ii < mean_.size(); ++ii)
variance_[ii] += f1*sq(tmp_[ii]);
}
double res = std::accumulate(variance_.begin(),
variance_.end(),
0.0,
std::plus<double>());
//std::cerr << res << " ) = ";
return res;
}
template<class Iter> //This is BROKEN
double decrement (Iter begin, Iter end)
{
for(Iter iter = begin; iter != end; ++iter)
{
--count_;
}
begin = end;
end = end + count_;
for(unsigned int ii = 0; ii < mean_.size(); ++ii)
{
mean_[ii] = 0;
for(Iter iter = begin; iter != end; ++iter)
{
mean_[ii] += labels_(*iter, ii);
}
mean_[ii] /= count_;
variance_[ii] = 0;
for(Iter iter = begin; iter != end; ++iter)
{
variance_[ii] += (labels_(*iter, ii) - mean_[ii])*(labe
ls_(*iter, ii) - mean_[ii]);
}
}
double res = std::accumulate(variance_.begin(),
variance_.end(),
0.0,
std::plus<double>());
//std::cerr << res << " ) = ";
return res;
}
template<class Iter, class Resp_t>
double init (Iter begin, Iter end, Resp_t resp)
{
reset();
return this->increment(begin, end);
}
ArrayVector<double> const & response()
{
return mean_;
}
void reset()
{
mean_.init(0.0);
variance_.init(0.0);
count_ = 0;
}
};
template <class DataSource> template <class DataSource>
class RegressionForestCounter class RegressionForestCounter2
{ {
public:
typedef MultiArrayShape<2>::type Shp; typedef MultiArrayShape<2>::type Shp;
DataSource const & labels_; DataSource const & labels_;
ArrayVector <double> mean_; ArrayVector <double> mean_;
ArrayVector <double> variance_; ArrayVector <double> variance_;
ArrayVector <double> tmp_; ArrayVector <double> tmp_;
size_t count_; size_t count_;
template<class T> template<class T>
RegressionForestCounter(DataSource const & labels, RegressionForestCounter2(DataSource const & labels,
ProblemSpec<T> const & ext_) ProblemSpec<T> const & ext_)
: :
labels_(labels), labels_(labels),
mean_(ext_.response_size, 0.0), mean_(ext_.response_size_, 0.0),
variance_(ext_.response_size, 0.0), variance_(ext_.response_size_, 0.0),
tmp_(ext_.response_size), tmp_(ext_.response_size_),
count_(0) count_(0)
{} {}
// west's alorithm for incremental variance template<class Iter>
double increment (Iter begin, Iter end)
{
for(Iter iter = begin; iter != end; ++iter)
{
++count_;
for(int ii = 0; ii < mean_.size(); ++ii)
tmp_[ii] = labels_(*iter, ii) - mean_[ii];
double f = 1.0 / count_,
f1 = 1.0 - f;
for(int ii = 0; ii < mean_.size(); ++ii)
mean_[ii] += f*tmp_[ii];
for(int ii = 0; ii < mean_.size(); ++ii)
variance_[ii] += f1*sq(tmp_[ii]);
}
double res = std::accumulate(variance_.begin(),
variance_.end(),
0.0,
std::plus<double>())
/((count_ == 1)? 1:(count_ -1));
//std::cerr << res << " ) = ";
return res;
}
template<class Iter> //This is BROKEN
double decrement (Iter begin, Iter end)
{
for(Iter iter = begin; iter != end; ++iter)
{
double f = 1.0 / count_,
f1 = 1.0 - f;
for(int ii = 0; ii < mean_.size(); ++ii)
mean_[ii] = (mean_[ii] - f*labels_(*iter,ii))/(1-f);
for(int ii = 0; ii < mean_.size(); ++ii)
variance_[ii] -= f1*sq(labels_(*iter,ii) - mean_[ii]);
--count_;
}
double res = std::accumulate(variance_.begin(),
variance_.end(),
0.0,
std::plus<double>())
/((count_ == 1)? 1:(count_ -1));
//std::cerr << "( " << res << " + ";
return res;
}
/* west's algorithm for incremental variance
// calculation // calculation
template<class Iter> template<class Iter>
double increment (Iter begin, Iter end) double increment (Iter begin, Iter end)
{ {
for(Iter iter = begin; iter != end; ++iter) for(Iter iter = begin; iter != end; ++iter)
{ {
++count_; ++count_;
for(int ii = 0; ii < mean_.size(); ++ii) for(int ii = 0; ii < mean_.size(); ++ii)
tmp_[ii] = labels_(*iter, ii) - mean_[ii]; tmp_[ii] = labels_(*iter, ii) - mean_[ii];
double f = 1.0 / count_, double f = 1.0 / count_,
skipping to change at line 549 skipping to change at line 765
for(int ii = 0; ii < mean_.size(); ++ii) for(int ii = 0; ii < mean_.size(); ++ii)
mean_[ii] -= f*tmp_[ii]; mean_[ii] -= f*tmp_[ii];
for(int ii = 0; ii < mean_.size(); ++ii) for(int ii = 0; ii < mean_.size(); ++ii)
variance_[ii] -= f1*sq(tmp_[ii]); variance_[ii] -= f1*sq(tmp_[ii]);
} }
return std::accumulate(variance_.begin(), return std::accumulate(variance_.begin(),
variance_.end(), variance_.end(),
0.0, 0.0,
std::plus<double>()) std::plus<double>())
/(count_ -1); /(count_ -1);
} }*/
template<class Iter, class Resp_t> template<class Iter, class Resp_t>
double init (Iter begin, Iter end, Resp_t resp) double init (Iter begin, Iter end, Resp_t resp)
{ {
reset(); reset();
return increment(begin, end); return this->increment(begin, end, resp);
} }
ArrayVector<double> const & response() ArrayVector<double> const & response()
{ {
return mean_; return mean_;
} }
void reset() void reset()
{ {
mean_.init(0.0); mean_.init(0.0);
skipping to change at line 584 skipping to change at line 800
struct LSQLoss struct LSQLoss
{}; {};
template<class Datatype> template<class Datatype>
struct LossTraits<GiniCriterion, Datatype> struct LossTraits<GiniCriterion, Datatype>
{ {
typedef ImpurityLoss<Datatype, GiniCriterion> type; typedef ImpurityLoss<Datatype, GiniCriterion> type;
}; };
template<class Datatype> template<class Datatype>
struct LossTraits<EntropyCriterion, Datatype>
{
typedef ImpurityLoss<Datatype, EntropyCriterion> type;
};
template<class Datatype>
struct LossTraits<LSQLoss, Datatype> struct LossTraits<LSQLoss, Datatype>
{ {
typedef RegressionForestCounter<Datatype> type; typedef RegressionForestCounter<Datatype> type;
}; };
/** Given a column, choose a split that minimizes some loss
*/
template<class LineSearchLossTag> template<class LineSearchLossTag>
class BestGiniOfColumn class BestGiniOfColumn
{ {
public: public:
ArrayVector<double> class_weights_; ArrayVector<double> class_weights_;
ArrayVector<double> bestCurrentCounts[2]; ArrayVector<double> bestCurrentCounts[2];
double min_gini_; double min_gini_;
ptrdiff_t min_index_; std::ptrdiff_t min_index_;
double min_threshold_; double min_threshold_;
ProblemSpec<> ext_param_; ProblemSpec<> ext_param_;
BestGiniOfColumn() BestGiniOfColumn()
{} {}
template<class T> template<class T>
BestGiniOfColumn(ProblemSpec<T> const & ext) BestGiniOfColumn(ProblemSpec<T> const & ext)
: :
class_weights_(ext.class_weights_), class_weights_(ext.class_weights_),
skipping to change at line 621 skipping to change at line 845
} }
template<class T> template<class T>
void set_external_parameters(ProblemSpec<T> const & ext) void set_external_parameters(ProblemSpec<T> const & ext)
{ {
class_weights_ = ext.class_weights_; class_weights_ = ext.class_weights_;
ext_param_ = ext; ext_param_ = ext;
bestCurrentCounts[0].resize(ext.class_count_); bestCurrentCounts[0].resize(ext.class_count_);
bestCurrentCounts[1].resize(ext.class_count_); bestCurrentCounts[1].resize(ext.class_count_);
} }
/** calculate the best gini split along a Feature Column /** calculate the best gini split along a Feature Column
* \param column, the feature vector - has to support the [] operator * \param column the feature vector - has to support the [] operator
* \param labels, the label vector * \param labels the label vector
* \param begin * \param begin
* \param end (in and out) * \param end (in and out)
* begin and end iterators to the indices of the * begin and end iterators to the indices of the
* samples in the current region. * samples in the current region.
* the range begin - end is sorted by the column supplie d * the range begin - end is sorted by the column supplie d
* during function execution. * during function execution.
* \param class_counts * \param region_response
* ???
* class histogram of the range. * class histogram of the range.
* *
* precondition: begin, end valid range, * precondition: begin, end valid range,
* class_counts positive integer valued array with the * class_counts positive integer valued array with the
* class counts in the current range. * class counts in the current range.
* labels.size() >= max(begin, end); * labels.size() >= max(begin, end);
* postcondition: * postcondition:
* begin, end sorted by column given. * begin, end sorted by column given.
* min_gini_ contains the minimum gini found or * min_gini_ contains the minimum gini found or
* NumericTraits<double>::max if no split was found. * NumericTraits<double>::max if no split was found.
* min_index_ countains the splitting index in the range * min_index_ contains the splitting index in the range
* or invalid data if no split was found. * or invalid data if no split was found.
* BestCirremtcounts[0] and [1] contain the * BestCirremtcounts[0] and [1] contain the
* class histogram of the left and right region of * class histogram of the left and right region of
* the left and right regions. * the left and right regions.
*/ */
template< class DataSourceF_t, template< class DataSourceF_t,
class DataSource_t, class DataSource_t,
class I_Iter, class I_Iter,
class Array> class Array>
void operator()(DataSourceF_t const & column, void operator()(DataSourceF_t const & column,
DataSource_t const & labels, DataSource_t const & labels,
I_Iter & begin, I_Iter & begin,
I_Iter & end, I_Iter & end,
Array const & region_response) Array const & region_response)
{ {
std::sort(begin, end, std::sort(begin, end,
SortSamplesByDimensions<DataSourceF_t>(column, 0)); SortSamplesByDimensions<DataSourceF_t>(column, 0));
typedef typename typedef typename
LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos s; LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos s;
LineSearchLoss left(labels, ext_param_); LineSearchLoss left(labels, ext_param_); //initialize left and righ t region
LineSearchLoss right(labels, ext_param_); LineSearchLoss right(labels, ext_param_);
min_gini_ = right.init(begin, end, region_response); min_gini_ = right.init(begin, end, region_response);
min_threshold_ = *begin; min_threshold_ = *begin;
min_index_ = 0; min_index_ = 0; //the starting point where to split
DimensionNotEqual<DataSourceF_t> comp(column, 0); DimensionNotEqual<DataSourceF_t> comp(column, 0);
I_Iter iter = begin; I_Iter iter = begin;
I_Iter next = std::adjacent_find(iter, end, comp); I_Iter next = std::adjacent_find(iter, end, comp);
//std::cerr << std::distance(begin, end) << std::endl;
while( next != end) while( next != end)
{ {
double lr = right.decrement(iter, next + 1);
double loss = right.decrement(iter, next + 1) double ll = left.increment(iter , next + 1);
+ left.increment(iter , next + 1); double loss = lr +ll;
//std::cerr <<lr << " + "<< ll << " " << loss << " ";
#ifdef CLASSIFIER_TEST
if(loss < min_gini_ && !closeAtTolerance(loss, min_gini_)) if(loss < min_gini_ && !closeAtTolerance(loss, min_gini_))
#else
if(loss < min_gini_ )
#endif
{ {
bestCurrentCounts[0] = left.response(); bestCurrentCounts[0] = left.response();
bestCurrentCounts[1] = right.response(); bestCurrentCounts[1] = right.response();
#ifdef CLASSIFIER_TEST
min_gini_ = loss < min_gini_? loss : min_gini_; min_gini_ = loss < min_gini_? loss : min_gini_;
#else
min_gini_ = loss;
#endif
min_index_ = next - begin +1 ; min_index_ = next - begin +1 ;
min_threshold_ = (column[*next] + column[*(next +1)])/2; min_threshold_ = (double(column(*next,0)) + double(column( *(next +1), 0)))/2.0;
} }
iter = next +1 ; iter = next +1 ;
next = std::adjacent_find(iter, end, comp); next = std::adjacent_find(iter, end, comp);
} }
//std::cerr << std::endl << " 000 " << std::endl;
//int in;
//std::cin >> in;
} }
template<class DataSource_t, class Iter, class Array> template<class DataSource_t, class Iter, class Array>
double loss_of_region(DataSource_t const & labels, double loss_of_region(DataSource_t const & labels,
Iter & begin, Iter & begin,
Iter & end, Iter & end,
Array const & region_response) const Array const & region_response) const
{ {
typedef typename typedef typename
LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos s; LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos s;
LineSearchLoss region_loss(labels, ext_param_); LineSearchLoss region_loss(labels, ext_param_);
return return
region_loss.init(begin, end, region_response); region_loss.init(begin, end, region_response);
} }
}; };
template<class ColumnDecisionFunctor, class Tag> namespace detail
{
template<class T>
struct Correction
{
template<class Region, class LabelT>
static void exec(Region & in, LabelT & labels)
{}
};
template<>
struct Correction<ClassificationTag>
{
template<class Region, class LabelT>
static void exec(Region & region, LabelT & labels)
{
if(std::accumulate(region.classCounts().begin(),
region.classCounts().end(), 0.0) != region.s
ize())
{
RandomForestClassCounter< LabelT,
ArrayVector<double> >
counter(labels, region.classCounts());
std::for_each( region.begin(), region.end(), counter);
region.classCountsIsValid = true;
}
}
};
}
/** Chooses mtry columns and applies ColumnDecisionFunctor to each of the
* columns. Then Chooses the column that is best
*/
template<class ColumnDecisionFunctor, class Tag = ClassificationTag>
class ThresholdSplit: public SplitBase<Tag> class ThresholdSplit: public SplitBase<Tag>
{ {
public: public:
typedef SplitBase<Tag> SB; typedef SplitBase<Tag> SB;
ArrayVector<Int32> splitColumns; ArrayVector<Int32> splitColumns;
ColumnDecisionFunctor bgfunc; ColumnDecisionFunctor bgfunc;
double region_gini_; double region_gini_;
ArrayVector<double> min_gini_; ArrayVector<double> min_gini_;
ArrayVector<ptrdiff_t> min_indices_; ArrayVector<std::ptrdiff_t> min_indices_;
ArrayVector<double> min_thresholds_; ArrayVector<double> min_thresholds_;
int bestSplitIndex; int bestSplitIndex;
double minGini() const double minGini() const
{ {
return min_gini_[bestSplitIndex]; return min_gini_[bestSplitIndex];
} }
int bestSplitColumn() const int bestSplitColumn() const
{ {
skipping to change at line 763 skipping to change at line 1032
Random & randint) Random & randint)
{ {
typedef typename Region::IndexIterator IndexIterator; typedef typename Region::IndexIterator IndexIterator;
if(region.size() == 0) if(region.size() == 0)
{ {
std::cerr << "SplitFunctor::findBestSplit(): stackentry with 0 e xamples encountered\n" std::cerr << "SplitFunctor::findBestSplit(): stackentry with 0 e xamples encountered\n"
"continuing learning process...."; "continuing learning process....";
} }
// calculate things that haven't been calculated yet. // calculate things that haven't been calculated yet.
detail::Correction<Tag>::exec(region, labels);
if(std::accumulate(region.classCounts().begin(),
region.classCounts().end(), 0) != region.size())
{
RandomForestClassCounter< MultiArrayView<2,T2, C2>,
ArrayVector<Int32> >
counter(labels, region.classCounts());
std::for_each( region.begin(), region.end(), counter);
region.classCountsIsValid = true;
}
// Is the region pure already? // Is the region pure already?
region_gini_ = bgfunc.loss_of_region(labels, region_gini_ = bgfunc.loss_of_region(labels,
region.begin(), region.begin(),
region.end(), region.end(),
region.classCounts()); region.classCounts());
if(region_gini_ <= SB::ext_param_.precision_) if(region_gini_ <= SB::ext_param_.precision_)
return makeTerminalNode(features, labels, region, randint); return this->makeTerminalNode(features, labels, region, randin t);
// 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)]);
// find the best gini index // find the best gini index
bestSplitIndex = 0; bestSplitIndex = 0;
double current_min_gini = region_gini_; double current_min_gini = region_gini_;
int num2try = features.shape(1); int num2try = features.shape(1);
for(int k=0; k<num2try; ++k) for(int k=0; k<num2try; ++k)
{ {
//this functor does all the work //this functor does all the work
bgfunc(columnVector(features, splitColumns[k]), bgfunc(columnVector(features, splitColumns[k]),
labels, labels,
region.begin(), region.end(), region.begin(), region.end(),
region.classCounts()); region.classCounts());
min_gini_[k] = bgfunc.min_gini_; min_gini_[k] = bgfunc.min_gini_;
min_indices_[k] = bgfunc.min_index_; min_indices_[k] = bgfunc.min_index_;
min_thresholds_[k] = bgfunc.min_threshold_; min_thresholds_[k] = bgfunc.min_threshold_;
#ifdef CLASSIFIER_TEST
if( bgfunc.min_gini_ < current_min_gini if( bgfunc.min_gini_ < current_min_gini
&& !closeAtTolerance(bgfunc.min_gini_, current_min_gini)) && !closeAtTolerance(bgfunc.min_gini_, current_min_gini))
#else
if(bgfunc.min_gini_ < current_min_gini)
#endif
{ {
current_min_gini = bgfunc.min_gini_; current_min_gini = bgfunc.min_gini_;
childRegions[0].classCounts() = bgfunc.bestCurrentCounts[0] ; childRegions[0].classCounts() = bgfunc.bestCurrentCounts[0] ;
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;
// did not find any suitable split // did not find any suitable split
if(closeAtTolerance(current_min_gini, region_gini_)) if(closeAtTolerance(current_min_gini, region_gini_))
return makeTerminalNode(features, labels, region, randint); 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
SortSamplesByDimensions<MultiArrayView<2, T, C> > SortSamplesByDimensions<MultiArrayView<2, T, C> >
sorter(features, node.column(), node.threshold()); sorter(features, node.column(), node.threshold());
skipping to change at line 843 skipping to change at line 1106
childRegions[0].rule = region.rule; childRegions[0].rule = region.rule;
childRegions[0].rule.push_back(std::make_pair(1, 1.0)); childRegions[0].rule.push_back(std::make_pair(1, 1.0));
childRegions[1].setRange( bestSplit , region.end() ); childRegions[1].setRange( bestSplit , region.end() );
childRegions[1].rule = region.rule; childRegions[1].rule = region.rule;
childRegions[1].rule.push_back(std::make_pair(1, 1.0)); childRegions[1].rule.push_back(std::make_pair(1, 1.0));
return i_ThresholdNode; return i_ThresholdNode;
} }
}; };
typedef ThresholdSplit<BestGiniOfColumn<GiniCriterion> > G typedef ThresholdSplit<BestGiniOfColumn<GiniCriterion> >
iniSplit; GiniSplit;
typedef ThresholdSplit<BestGiniOfColumn<LSQLoss>, RegressionTag> R typedef ThresholdSplit<BestGiniOfColumn<EntropyCriterion> >
egressionSplit; EntropySplit;
typedef ThresholdSplit<BestGiniOfColumn<LSQLoss>, RegressionTag>
RegressionSplit;
namespace rf
{
/** This namespace contains additional Splitfunctors.
*
* The Split functor classes are designed in a modular fashion because new
split functors may
* share a lot of code with existing ones.
*
* ThresholdSplit implements the functionality needed for any split functor
, that makes its
* decision via one dimensional axis-parallel cuts. The Template parameter
defines how the split
* along one dimension is chosen.
*
* The BestGiniOfColumn class chooses a split that minimizes one of the Los
s functions supplied
* (GiniCriterion for classification and LSQLoss for regression). Median ch
ooses the Split in a
* kD tree fashion.
*
*
* Currently defined typedefs:
* \code
* typedef ThresholdSplit<BestGiniOfColumn<GiniCriterion> >
GiniSplit;
* typedef ThresholdSplit<BestGiniOfColumn<LSQLoss>, RegressionTag>
RegressionSplit;
* typedef ThresholdSplit<Median> MedianSplit;
* \endcode
*/
namespace split
{
/** This Functor chooses the median value of a column
*/
class Median
{
public:
typedef GiniCriterion LineSearchLossTag;
ArrayVector<double> class_weights_;
ArrayVector<double> bestCurrentCounts[2];
double min_gini_;
std::ptrdiff_t min_index_;
double min_threshold_;
ProblemSpec<> ext_param_;
Median()
{}
template<class T>
Median(ProblemSpec<T> const & ext)
:
class_weights_(ext.class_weights_),
ext_param_(ext)
{
bestCurrentCounts[0].resize(ext.class_count_);
bestCurrentCounts[1].resize(ext.class_count_);
}
template<class T>
void set_external_parameters(ProblemSpec<T> const & ext)
{
class_weights_ = ext.class_weights_;
ext_param_ = ext;
bestCurrentCounts[0].resize(ext.class_count_);
bestCurrentCounts[1].resize(ext.class_count_);
}
template< class DataSourceF_t,
class DataSource_t,
class I_Iter,
class Array>
void operator()(DataSourceF_t const & column,
DataSource_t const & labels,
I_Iter & begin,
I_Iter & end,
Array const & region_response)
{
std::sort(begin, end,
SortSamplesByDimensions<DataSourceF_t>(column, 0));
typedef typename
LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos
s;
LineSearchLoss left(labels, ext_param_);
LineSearchLoss right(labels, ext_param_);
right.init(begin, end, region_response);
min_gini_ = NumericTraits<double>::max();
min_index_ = floor(double(end - begin)/2.0);
min_threshold_ = column[*(begin + min_index_)];
SortSamplesByDimensions<DataSourceF_t>
sorter(column, 0, min_threshold_);
I_Iter part = std::partition(begin, end, sorter);
DimensionNotEqual<DataSourceF_t> comp(column, 0);
if(part == begin)
{
part= std::adjacent_find(part, end, comp)+1;
}
if(part >= end)
{
return;
}
else
{
min_threshold_ = column[*part];
}
min_gini_ = right.decrement(begin, part)
+ left.increment(begin , part);
bestCurrentCounts[0] = left.response();
bestCurrentCounts[1] = right.response();
min_index_ = part - begin;
}
template<class DataSource_t, class Iter, class Array>
double loss_of_region(DataSource_t const & labels,
Iter & begin,
Iter & end,
Array const & region_response) const
{
typedef typename
LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos
s;
LineSearchLoss region_loss(labels, ext_param_);
return
region_loss.init(begin, end, region_response);
}
};
typedef ThresholdSplit<Median> MedianSplit;
/** This Functor chooses a random value of a column
*/
class RandomSplitOfColumn
{
public:
typedef GiniCriterion LineSearchLossTag;
ArrayVector<double> class_weights_;
ArrayVector<double> bestCurrentCounts[2];
double min_gini_;
std::ptrdiff_t min_index_;
double min_threshold_;
ProblemSpec<> ext_param_;
typedef RandomMT19937 Random_t;
Random_t random;
RandomSplitOfColumn()
{}
template<class T>
RandomSplitOfColumn(ProblemSpec<T> const & ext)
:
class_weights_(ext.class_weights_),
ext_param_(ext),
random(RandomSeed)
{
bestCurrentCounts[0].resize(ext.class_count_);
bestCurrentCounts[1].resize(ext.class_count_);
}
template<class T>
RandomSplitOfColumn(ProblemSpec<T> const & ext, Random_t & random_)
:
class_weights_(ext.class_weights_),
ext_param_(ext),
random(random_)
{
bestCurrentCounts[0].resize(ext.class_count_);
bestCurrentCounts[1].resize(ext.class_count_);
}
template<class T>
void set_external_parameters(ProblemSpec<T> const & ext)
{
class_weights_ = ext.class_weights_;
ext_param_ = ext;
bestCurrentCounts[0].resize(ext.class_count_);
bestCurrentCounts[1].resize(ext.class_count_);
}
template< class DataSourceF_t,
class DataSource_t,
class I_Iter,
class Array>
void operator()(DataSourceF_t const & column,
DataSource_t const & labels,
I_Iter & begin,
I_Iter & end,
Array const & region_response)
{
std::sort(begin, end,
SortSamplesByDimensions<DataSourceF_t>(column, 0));
typedef typename
LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos
s;
LineSearchLoss left(labels, ext_param_);
LineSearchLoss right(labels, ext_param_);
right.init(begin, end, region_response);
min_gini_ = NumericTraits<double>::max();
int tmp_pt = random.uniformInt(std::distance(begin, end));
min_index_ = tmp_pt;
min_threshold_ = column[*(begin + min_index_)];
SortSamplesByDimensions<DataSourceF_t>
sorter(column, 0, min_threshold_);
I_Iter part = std::partition(begin, end, sorter);
DimensionNotEqual<DataSourceF_t> comp(column, 0);
if(part == begin)
{
part= std::adjacent_find(part, end, comp)+1;
}
if(part >= end)
{
return;
}
else
{
min_threshold_ = column[*part];
}
min_gini_ = right.decrement(begin, part)
+ left.increment(begin , part);
bestCurrentCounts[0] = left.response();
bestCurrentCounts[1] = right.response();
min_index_ = part - begin;
}
template<class DataSource_t, class Iter, class Array>
double loss_of_region(DataSource_t const & labels,
Iter & begin,
Iter & end,
Array const & region_response) const
{
typedef typename
LossTraits<LineSearchLossTag, DataSource_t>::type LineSearchLos
s;
LineSearchLoss region_loss(labels, ext_param_);
return
region_loss.init(begin, end, region_response);
}
};
typedef ThresholdSplit<RandomSplitOfColumn> RandomSplit;
}
}
} //namespace vigra } //namespace vigra
#endif // VIGRA_RANDOM_FOREST_SPLIT_HXX #endif // VIGRA_RANDOM_FOREST_SPLIT_HXX
 End of changes. 53 change blocks. 
63 lines changed or deleted 588 lines changed or added


 rf_visitors.hxx   rf_visitors.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 RF_VISITORS_HXX #ifndef RF_VISITORS_HXX
#define RF_VISITORS_HXX #define RF_VISITORS_HXX
#ifdef HasHDF5 #ifdef HasHDF5
# include "vigra/hdf5impex.hxx" # include "vigra/hdf5impex.hxx"
#endif // HasHDF5 #endif // HasHDF5
#include <vigra/windows.h>
#include <iostream>
#include <iomanip>
#include <vigra/multi_pointoperators.hxx>
#include <vigra/timing.hxx>
namespace vigra namespace vigra
{ {
namespace rf
{
/** \addtogroup MachineLearning Machine Learning
**/
//@{
/** Base Class from which all Visitors derive /**
This namespace contains all classes and methods related to extracting i
nformation during
learning of the random forest. All Visitors share the same interface de
fined in
visitors::VisitorBase. The member methods are invoked at certain points
of the main code in
the order they were supplied.
For the Random Forest the Visitor concept is implemented as a statical
ly linked list
(Using templates). Each Visitor object is encapsulated in a detail::Vis
itorNode object. The
VisitorNode object calls the Next Visitor after one of its visit() meth
ods have terminated.
To simplify usage create_visitor() factory methods are supplied.
Use the create_visitor() method to supply visitor objects to the Random
Forest::learn() method.
It is possible to supply more than one visitor. They will then be invok
ed in serial order.
The calculated information are stored as public data members of the cla
ss. - see documentation
of the individual visitors
While creating a new visitor the new class should therefore publicly in
herit from this class
(i.e.: see visitors::OOB_Error).
\code
typedef xxx feature_t \\ replace xxx with whichever type
typedef yyy label_t \\ meme chose.
MultiArrayView<2, feature_t> f = get_some_features();
MultiArrayView<2, label_t> l = get_some_labels();
RandomForest<> rf()
//calculate OOB Error
visitors::OOB_Error oob_v;
//calculate Variable Importance
visitors::VariableImportanceVisitor varimp_v;
double oob_error = rf.learn(f, l, visitors::create_visitor(oob_v, var
imp_v);
//the data can be found in the attributes of oob_v and varimp_v now
\endcode
*/
namespace visitors
{
/** Base Class from which all Visitors derive. Can be used as a template to
create new
* Visitors.
*/ */
class VisitorBase class VisitorBase
{ {
public: public:
bool active_; bool active_;
bool is_active() bool is_active()
{ {
return active_; return active_;
} }
skipping to change at line 135 skipping to change at line 188
*/ */
template<class RF, class PR> template<class RF, class PR>
void visit_at_beginning(RF const & rf, PR const & pr) void visit_at_beginning(RF const & rf, PR const & pr)
{} {}
/** do some thing while traversing tree after it has been learned /** do some thing while traversing tree after it has been learned
* (external nodes) * (external nodes)
* *
* \param tr reference to the tree object that called this visit or * \param tr reference to the tree object that called this visit or
* \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 weight Node weight of current node. * \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 & featur es)
{} {}
/** 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>
skipping to change at line 167 skipping to change at line 220
* 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()
{ {
return -1.0; return -1.0;
} }
}; };
namespace rf
{
/** Last Visitor that should be called to stop the recursion. /** Last Visitor that should be called to stop the recursion.
*/ */
class StopVisiting: public VisitorBase class StopVisiting: public VisitorBase
{ {
public: public:
bool has_value() bool has_value()
{ {
return true; return true;
} }
double return_val() double return_val()
{ {
return -1.0; return -1.0;
} }
}; };
namespace detail
{
/** Container elements of the statically linked Visitor list. /** Container elements of the statically linked Visitor list.
* *
* use the create_visitor() factory functions to create visitors up to size 10; * use the create_visitor() factory functions to create visitors up to size 10;
* *
*/ */
template <class Visitor, class Next = StopVisiting> template <class Visitor, class Next = StopVisiting>
class VisitorNode class VisitorNode
{ {
public: public:
skipping to change at line 270 skipping to change at line 322
} }
double return_val() double return_val()
{ {
if(visitor_.is_active() && visitor_.has_value()) if(visitor_.is_active() && visitor_.has_value())
return visitor_.return_val(); return visitor_.return_val();
return next_.return_val(); return next_.return_val();
} }
}; };
} //namespace rf } //namespace detail
/////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////// ///
// Visitor Factory function up to 10 visitors // // Visitor Factory function up to 10 visitors //
/////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////// ///
/** factory method to to be used with RandomForest::learn()
*/
template<class A> template<class A>
rf::VisitorNode<A> detail::VisitorNode<A>
create_visitor(A & a) create_visitor(A & a)
{ {
typedef rf::VisitorNode<A> _0_t; typedef detail::VisitorNode<A> _0_t;
_0_t _0(a); _0_t _0(a);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B> template<class A, class B>
rf::VisitorNode<A, rf::VisitorNode<B> > detail::VisitorNode<A, detail::VisitorNode<B> >
create_visitor(A & a, B & b) create_visitor(A & a, B & b)
{ {
typedef rf::VisitorNode<B> _1_t; typedef detail::VisitorNode<B> _1_t;
_1_t _1(b); _1_t _1(b);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C> template<class A, class B, class C>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C> > > detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C> > >
create_visitor(A & a, B & b, C & c) create_visitor(A & a, B & b, C & c)
{ {
typedef rf::VisitorNode<C> _2_t; typedef detail::VisitorNode<C> _2_t;
_2_t _2(c); _2_t _2(c);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D> template<class A, class B, class C, class D>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D> > > > detail::VisitorNode<D> > > >
create_visitor(A & a, B & b, C & c, D & d) create_visitor(A & a, B & b, C & c, D & d)
{ {
typedef rf::VisitorNode<D> _3_t; typedef detail::VisitorNode<D> _3_t;
_3_t _3(d); _3_t _3(d);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D, class E> template<class A, class B, class C, class D, class E>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D, rf::VisitorNode<E> > > > > detail::VisitorNode<D, detail::VisitorNode<E> > > > >
create_visitor(A & a, B & b, C & c, create_visitor(A & a, B & b, C & c,
D & d, E & e) D & d, E & e)
{ {
typedef rf::VisitorNode<E> _4_t; typedef detail::VisitorNode<E> _4_t;
_4_t _4(e); _4_t _4(e);
typedef rf::VisitorNode<D, _4_t> _3_t; typedef detail::VisitorNode<D, _4_t> _3_t;
_3_t _3(d, _4); _3_t _3(d, _4);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D, class E, template<class A, class B, class C, class D, class E,
class F> class F>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D, rf::VisitorNode<E, rf::VisitorNode<F> > > > > > detail::VisitorNode<D, detail::VisitorNode<E, detail::VisitorNode<F> >
> > > >
create_visitor(A & a, B & b, C & c, create_visitor(A & a, B & b, C & c,
D & d, E & e, F & f) D & d, E & e, F & f)
{ {
typedef rf::VisitorNode<F> _5_t; typedef detail::VisitorNode<F> _5_t;
_5_t _5(f); _5_t _5(f);
typedef rf::VisitorNode<E, _5_t> _4_t; typedef detail::VisitorNode<E, _5_t> _4_t;
_4_t _4(e, _5); _4_t _4(e, _5);
typedef rf::VisitorNode<D, _4_t> _3_t; typedef detail::VisitorNode<D, _4_t> _3_t;
_3_t _3(d, _4); _3_t _3(d, _4);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D, class E, template<class A, class B, class C, class D, class E,
class F, class G> class F, class G>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D, rf::VisitorNode<E, rf::VisitorNode<F, detail::VisitorNode<D, detail::VisitorNode<E, detail::VisitorNode<F,
rf::VisitorNode<G> > > > > > > detail::VisitorNode<G> > > > > > >
create_visitor(A & a, B & b, C & c, create_visitor(A & a, B & b, C & c,
D & d, E & e, F & f, G & g) D & d, E & e, F & f, G & g)
{ {
typedef rf::VisitorNode<G> _6_t; typedef detail::VisitorNode<G> _6_t;
_6_t _6(g); _6_t _6(g);
typedef rf::VisitorNode<F, _6_t> _5_t; typedef detail::VisitorNode<F, _6_t> _5_t;
_5_t _5(f, _6); _5_t _5(f, _6);
typedef rf::VisitorNode<E, _5_t> _4_t; typedef detail::VisitorNode<E, _5_t> _4_t;
_4_t _4(e, _5); _4_t _4(e, _5);
typedef rf::VisitorNode<D, _4_t> _3_t; typedef detail::VisitorNode<D, _4_t> _3_t;
_3_t _3(d, _4); _3_t _3(d, _4);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D, class E, template<class A, class B, class C, class D, class E,
class F, class G, class H> class F, class G, class H>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D, rf::VisitorNode<E, rf::VisitorNode<F, detail::VisitorNode<D, detail::VisitorNode<E, detail::VisitorNode<F,
rf::VisitorNode<G, rf::VisitorNode<H> > > > > > > > detail::VisitorNode<G, detail::VisitorNode<H> > > > > > > >
create_visitor(A & a, B & b, C & c, create_visitor(A & a, B & b, C & c,
D & d, E & e, F & f, D & d, E & e, F & f,
G & g, H & h) G & g, H & h)
{ {
typedef rf::VisitorNode<H> _7_t; typedef detail::VisitorNode<H> _7_t;
_7_t _7(h); _7_t _7(h);
typedef rf::VisitorNode<G, _7_t> _6_t; typedef detail::VisitorNode<G, _7_t> _6_t;
_6_t _6(g, _7); _6_t _6(g, _7);
typedef rf::VisitorNode<F, _6_t> _5_t; typedef detail::VisitorNode<F, _6_t> _5_t;
_5_t _5(f, _6); _5_t _5(f, _6);
typedef rf::VisitorNode<E, _5_t> _4_t; typedef detail::VisitorNode<E, _5_t> _4_t;
_4_t _4(e, _5); _4_t _4(e, _5);
typedef rf::VisitorNode<D, _4_t> _3_t; typedef detail::VisitorNode<D, _4_t> _3_t;
_3_t _3(d, _4); _3_t _3(d, _4);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D, class E, template<class A, class B, class C, class D, class E,
class F, class G, class H, class I> class F, class G, class H, class I>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D, rf::VisitorNode<E, rf::VisitorNode<F, detail::VisitorNode<D, detail::VisitorNode<E, detail::VisitorNode<F,
rf::VisitorNode<G, rf::VisitorNode<H, rf::VisitorNode<I> > > > > > > > detail::VisitorNode<G, detail::VisitorNode<H, detail::VisitorNode<I> >
> > > > > > > >
create_visitor(A & a, B & b, C & c, create_visitor(A & a, B & b, C & c,
D & d, E & e, F & f, D & d, E & e, F & f,
G & g, H & h, I & i) G & g, H & h, I & i)
{ {
typedef rf::VisitorNode<I> _8_t; typedef detail::VisitorNode<I> _8_t;
_8_t _8(i); _8_t _8(i);
typedef rf::VisitorNode<H, _8_t> _7_t; typedef detail::VisitorNode<H, _8_t> _7_t;
_7_t _7(h, _8); _7_t _7(h, _8);
typedef rf::VisitorNode<G, _7_t> _6_t; typedef detail::VisitorNode<G, _7_t> _6_t;
_6_t _6(g, _7); _6_t _6(g, _7);
typedef rf::VisitorNode<F, _6_t> _5_t; typedef detail::VisitorNode<F, _6_t> _5_t;
_5_t _5(f, _6); _5_t _5(f, _6);
typedef rf::VisitorNode<E, _5_t> _4_t; typedef detail::VisitorNode<E, _5_t> _4_t;
_4_t _4(e, _5); _4_t _4(e, _5);
typedef rf::VisitorNode<D, _4_t> _3_t; typedef detail::VisitorNode<D, _4_t> _3_t;
_3_t _3(d, _4); _3_t _3(d, _4);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/** factory method to to be used with RandomForest::learn()
*/
template<class A, class B, class C, class D, class E, template<class A, class B, class C, class D, class E,
class F, class G, class H, class I, class J> class F, class G, class H, class I, class J>
rf::VisitorNode<A, rf::VisitorNode<B, rf::VisitorNode<C, detail::VisitorNode<A, detail::VisitorNode<B, detail::VisitorNode<C,
rf::VisitorNode<D, rf::VisitorNode<E, rf::VisitorNode<F, detail::VisitorNode<D, detail::VisitorNode<E, detail::VisitorNode<F,
rf::VisitorNode<G, rf::VisitorNode<H, rf::VisitorNode<I, detail::VisitorNode<G, detail::VisitorNode<H, detail::VisitorNode<I,
rf::VisitorNode<J> > > > > > > > > > detail::VisitorNode<J> > > > > > > > > >
create_visitor(A & a, B & b, C & c, create_visitor(A & a, B & b, C & c,
D & d, E & e, F & f, D & d, E & e, F & f,
G & g, H & h, I & i, G & g, H & h, I & i,
J & j) J & j)
{ {
typedef rf::VisitorNode<J> _9_t; typedef detail::VisitorNode<J> _9_t;
_9_t _9(j); _9_t _9(j);
typedef rf::VisitorNode<I, _9_t> _8_t; typedef detail::VisitorNode<I, _9_t> _8_t;
_8_t _8(i, _9); _8_t _8(i, _9);
typedef rf::VisitorNode<H, _8_t> _7_t; typedef detail::VisitorNode<H, _8_t> _7_t;
_7_t _7(h, _8); _7_t _7(h, _8);
typedef rf::VisitorNode<G, _7_t> _6_t; typedef detail::VisitorNode<G, _7_t> _6_t;
_6_t _6(g, _7); _6_t _6(g, _7);
typedef rf::VisitorNode<F, _6_t> _5_t; typedef detail::VisitorNode<F, _6_t> _5_t;
_5_t _5(f, _6); _5_t _5(f, _6);
typedef rf::VisitorNode<E, _5_t> _4_t; typedef detail::VisitorNode<E, _5_t> _4_t;
_4_t _4(e, _5); _4_t _4(e, _5);
typedef rf::VisitorNode<D, _4_t> _3_t; typedef detail::VisitorNode<D, _4_t> _3_t;
_3_t _3(d, _4); _3_t _3(d, _4);
typedef rf::VisitorNode<C, _3_t> _2_t; typedef detail::VisitorNode<C, _3_t> _2_t;
_2_t _2(c, _3); _2_t _2(c, _3);
typedef rf::VisitorNode<B, _2_t> _1_t; typedef detail::VisitorNode<B, _2_t> _1_t;
_1_t _1(b, _2); _1_t _1(b, _2);
typedef rf::VisitorNode<A, _1_t> _0_t; typedef detail::VisitorNode<A, _1_t> _0_t;
_0_t _0(a, _1); _0_t _0(a, _1);
return _0; return _0;
} }
/////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////// ///
// Visitors of communal interest. Do not spam this file with stuff // Visitors of communal interest.
// //
// nobody wants.
//
/////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////// ///
/** Vistior to gain information, later needed for online learning. /** Visitor to gain information, later needed for online learning.
*/ */
class OnlineLearnVisitor: public VisitorBase class OnlineLearnVisitor: public VisitorBase
{ {
public: public:
//Set if we adjust thresholds //Set if we adjust thresholds
bool adjust_thresholds; bool adjust_thresholds;
//Current tree id //Current tree id
int tree_id; int tree_id;
//Last node id for finding parent //Last node id for finding parent
int last_node_id; int last_node_id;
//Need to now the label for interior node visiting //Need to now the label for interior node visiting
vigra::Int32 current_label; vigra::Int32 current_label;
//marginal distribution for interior nodes //marginal distribution for interior nodes
//
OnlineLearnVisitor():
adjust_thresholds(false), tree_id(0), last_node_id(0), current_labe
l(0)
{}
struct MarginalDistribution struct MarginalDistribution
{ {
ArrayVector<Int32> leftCounts; ArrayVector<Int32> leftCounts;
Int32 leftTotalCounts; Int32 leftTotalCounts;
ArrayVector<Int32> rightCounts; ArrayVector<Int32> rightCounts;
Int32 rightTotalCounts; Int32 rightTotalCounts;
double gap_left; double gap_left;
double gap_right; double gap_right;
}; };
typedef ArrayVector<vigra::Int32> IndexList; typedef ArrayVector<vigra::Int32> IndexList;
//All information for one tree //All information for one tree
struct TreeOnlineInformation struct TreeOnlineInformation
{ {
std::vector<MarginalDistribution> mag_distributions; std::vector<MarginalDistribution> mag_distributions;
std::vector<IndexList> index_lists; std::vector<IndexList> index_lists;
//map for linear index of mag_distiributions //map for linear index of mag_distributions
std::map<int,int> interior_to_index; std::map<int,int> interior_to_index;
//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;
/** Initilize, 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
*/ */
skipping to change at line 555 skipping to change at line 631
/** 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)
{ {
skipping to change at line 670 skipping to change at line 746
++m.rightCounts[current_label]; ++m.rightCounts[current_label];
} }
} }
} }
/** do something when visiting a extern node during getToLeaf /** do something when visiting a extern node during getToLeaf
* *
* Store the new index! * Store the new index!
*/ */
}; };
/** Visitor that calculates the oob error of the random forest. ///////////////////////////////////////////////////////////////////////////
* this is the default visitor used. ///
// Out of Bag Error estimates
//
///////////////////////////////////////////////////////////////////////////
///
/** Visitor that calculates the oob error of each individual randomized
* decision tree.
* *
* To bored to comment each line of this class - trust me it works. * After training a tree, all those samples that are OOB for this particula
r tree
* are put down the tree and the error estimated.
* the per tree oob error is the average of the individual error estimates.
* (oobError = average error of one randomized tree)
* Note: This is Not the OOB - Error estimate suggested by Breiman (See OOB
_Error
* visitor)
*/ */
class OOB_Visitor:public VisitorBase class OOB_PerTreeError:public VisitorBase
{ {
public: public:
/** Average error of one randomized decision tree
*/
double oobError; double oobError;
int totalOobCount; int totalOobCount;
ArrayVector<int> oobCount,oobErrorCount; ArrayVector<int> oobCount,oobErrorCount;
OOB_Visitor() OOB_PerTreeError()
: oobError(0.0), : oobError(0.0),
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);
} }
skipping to change at line 733 skipping to change at line 822
{ {
// do some normalisation // do some normalisation
for(int l=0; l < (int)rf.ext_param_.row_count_; ++l) for(int l=0; l < (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;
} }
//returns value of the learn function. };
double return_val()
/** Visitor that calculates the oob error of the ensemble
* This rate should be used to estimate the crossvalidation
* error rate.
* Here each sample is put down those trees, for which this sample
* is OOB i.e. if sample #1 is OOB for trees 1, 3 and 5 we calculate
* the output using the ensemble consisting only of trees 1 3 and 5.
*
* Using normal bagged sampling each sample is OOB for approx. 33% of tree
s
* The error rate obtained as such therefore corresponds to crossvalidatio
n
* rate obtained using a ensemble containing 33% of the trees.
*/
class OOB_Error : public VisitorBase
{
typedef MultiArrayShape<2>::type Shp;
int class_count;
bool is_weighted;
MultiArray<2,double> tmp_prob;
public:
MultiArray<2, double> prob_oob;
/** Ensemble oob error rate
*/
double oob_breiman;
MultiArray<2, double> oobCount;
ArrayVector< int> indices;
OOB_Error() : VisitorBase(), oob_breiman(0.0) {}
#ifdef HasHDF5
void save(std::string filen, std::string pathn)
{ {
return oobError/totalOobCount; if(*(pathn.end()-1) != '/')
pathn += "/";
const char* filename = filen.c_str();
MultiArray<2, double> temp(Shp(1,1), 0.0);
temp[0] = oob_breiman;
writeHDF5(filename, (pathn + "breiman_error").c_str(), temp);
}
#endif
// negative value if sample was ib, number indicates how often.
// value >=0 if sample was oob, 0 means fail 1, correct
template<class RF, class PR>
void visit_at_beginning(RF & rf, PR & pr)
{
class_count = rf.class_count();
tmp_prob.reshape(Shp(1, class_count), 0);
prob_oob.reshape(Shp(rf.ext_param().row_count_,class_count), 0);
is_weighted = rf.options().predict_weighted_;
indices.resize(rf.ext_param().row_count_);
if(int(oobCount.size()) != rf.ext_param_.row_count_)
{
oobCount.reshape(Shp(rf.ext_param_.row_count_, 1), 0);
}
for(int ii = 0; ii < rf.ext_param().row_count_; ++ii)
{
indices[ii] = ii;
}
}
template<class RF, class PR, class SM, class ST>
void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index)
{
// go through the samples
int total_oob =0;
// FIXME: magic number 10000: invoke special treatment when when ms
ample << sample_count
// (i.e. the OOB sample ist very large)
// 40000: use at most 40000 OOB samples per cla
ss for OOB error estimate
if(rf.ext_param_.actual_msample_ < pr.features().shape(0) - 10000)
{
ArrayVector<int> oob_indices;
ArrayVector<int> cts(class_count, 0);
std::random_shuffle(indices.begin(), indices.end());
for(int ii = 0; ii < rf.ext_param_.row_count_; ++ii)
{
if(!sm.is_used()[indices[ii]] && cts[pr.response()(indices[
ii], 0)] < 40000)
{
oob_indices.push_back(indices[ii]);
++cts[pr.response()(indices[ii], 0)];
}
}
for(unsigned int ll = 0; ll < oob_indices.size(); ++ll)
{
// update number of trees in which current sample is oob
++oobCount[oob_indices[ll]];
// update number of oob samples in this tree.
++total_oob;
// get the predicted votes ---> tmp_prob;
int pos = rf.tree(index).getToLeaf(rowVector(pr.features()
,oob_indices[ll]));
Node<e_ConstProbNode> node ( rf.tree(index).topology_,
rf.tree(index).paramete
rs_,
pos);
tmp_prob.init(0);
for(int ii = 0; ii < class_count; ++ii)
{
tmp_prob[ii] = node.prob_begin()[ii];
}
if(is_weighted)
{
for(int ii = 0; ii < class_count; ++ii)
tmp_prob[ii] = tmp_prob[ii] * (*(node.prob_begin()-
1));
}
rowVector(prob_oob, oob_indices[ll]) += tmp_prob;
}
}else
{
for(int ll = 0; ll < rf.ext_param_.row_count_; ++ll)
{
// if the lth sample is oob...
if(!sm.is_used()[ll])
{
// update number of trees in which current sample is oo
b
++oobCount[ll];
// update number of oob samples in this tree.
++total_oob;
// get the predicted votes ---> tmp_prob;
int pos = rf.tree(index).getToLeaf(rowVector(pr.featur
es(),ll));
Node<e_ConstProbNode> node ( rf.tree(index).topology_,
rf.tree(index).para
meters_,
pos);
tmp_prob.init(0);
for(int ii = 0; ii < class_count; ++ii)
{
tmp_prob[ii] = node.prob_begin()[ii];
}
if(is_weighted)
{
for(int ii = 0; ii < class_count; ++ii)
tmp_prob[ii] = tmp_prob[ii] * (*(node.prob_begi
n()-1));
}
rowVector(prob_oob, ll) += tmp_prob;
}
}
}
// go through the ib samples;
}
/** Normalise variable importance after the number of trees is known.
*/
template<class RF, class PR>
void visit_at_end(RF & rf, PR & pr)
{
// ullis original metric and breiman style stuff
int totalOobCount =0;
int breimanstyle = 0;
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
{
if(oobCount[ll])
{
if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0))
++breimanstyle;
++totalOobCount;
}
}
oob_breiman = double(breimanstyle)/totalOobCount;
}
};
/** Visitor that calculates different OOB error statistics
*/
class CompleteOOBInfo : public VisitorBase
{
typedef MultiArrayShape<2>::type Shp;
int class_count;
bool is_weighted;
MultiArray<2,double> tmp_prob;
public:
/** OOB Error rate of each individual tree
*/
MultiArray<2, double> oob_per_tree;
/** Mean of oob_per_tree
*/
double oob_mean;
/**Standard deviation of oob_per_tree
*/
double oob_std;
MultiArray<2, double> prob_oob;
/** Ensemble OOB error
*
* \sa OOB_Error
*/
double oob_breiman;
MultiArray<2, double> oobCount;
MultiArray<2, double> oobErrorCount;
/** Per Tree OOB error calculated as in OOB_PerTreeError
* (Ulli's version)
*/
double oob_per_tree2;
/**Column containing the development of the Ensemble
* error rate with increasing number of trees
*/
MultiArray<2, double> breiman_per_tree;
/** 4 dimensional array containing the development of confusion matrice
s
* with number of trees - can be used to estimate ROC curves etc.
*
* oobroc_per_tree(ii,jj,kk,ll)
* corresponds true label = ii
* predicted label = jj
* confusion matrix after ll trees
*
* explanation of third index:
*
* Two class case:
* kk = 0 - (treeCount-1)
* Threshold is on Probability for class 0 is kk/(treeCount-1)
;
* More classes:
* kk = 0. Threshold on probability set by argMax of the probability ar
ray.
*/
MultiArray<4, double> oobroc_per_tree;
CompleteOOBInfo() : VisitorBase(), oob_mean(0), oob_std(0), oob_per_tre
e2(0) {}
#ifdef HasHDF5
/** save to HDF5 file
*/
void save(std::string filen, std::string pathn)
{
if(*(pathn.end()-1) != '/')
pathn += "/";
const char* filename = filen.c_str();
MultiArray<2, double> temp(Shp(1,1), 0.0);
writeHDF5(filename, (pathn + "oob_per_tree").c_str(), oob_per_tree)
;
writeHDF5(filename, (pathn + "oobroc_per_tree").c_str(), oobroc_per
_tree);
writeHDF5(filename, (pathn + "breiman_per_tree").c_str(), breiman_p
er_tree);
temp[0] = oob_mean;
writeHDF5(filename, (pathn + "per_tree_error").c_str(), temp);
temp[0] = oob_std;
writeHDF5(filename, (pathn + "per_tree_error_std").c_str(), temp);
temp[0] = oob_breiman;
writeHDF5(filename, (pathn + "breiman_error").c_str(), temp);
temp[0] = oob_per_tree2;
writeHDF5(filename, (pathn + "ulli_error").c_str(), temp);
}
#endif
// negative value if sample was ib, number indicates how often.
// value >=0 if sample was oob, 0 means fail 1, correct
template<class RF, class PR>
void visit_at_beginning(RF & rf, PR & pr)
{
class_count = rf.class_count();
if(class_count == 2)
oobroc_per_tree.reshape(MultiArrayShape<4>::type(2,2,rf.tree_co
unt(), rf.tree_count()));
else
oobroc_per_tree.reshape(MultiArrayShape<4>::type(rf.class_count
(),rf.class_count(),1, rf.tree_count()));
tmp_prob.reshape(Shp(1, class_count), 0);
prob_oob.reshape(Shp(rf.ext_param().row_count_,class_count), 0);
is_weighted = rf.options().predict_weighted_;
oob_per_tree.reshape(Shp(1, rf.tree_count()), 0);
breiman_per_tree.reshape(Shp(1, rf.tree_count()), 0);
//do the first time called.
if(int(oobCount.size()) != rf.ext_param_.row_count_)
{
oobCount.reshape(Shp(rf.ext_param_.row_count_, 1), 0);
oobErrorCount.reshape(Shp(rf.ext_param_.row_count_,1), 0);
}
}
template<class RF, class PR, class SM, class ST>
void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index)
{
// go through the samples
int total_oob =0;
int wrong_oob =0;
for(int ll = 0; ll < rf.ext_param_.row_count_; ++ll)
{
// if the lth sample is oob...
if(!sm.is_used()[ll])
{
// update number of trees in which current sample is oob
++oobCount[ll];
// update number of oob samples in this tree.
++total_oob;
// get the predicted votes ---> tmp_prob;
int pos = rf.tree(index).getToLeaf(rowVector(pr.features()
,ll));
Node<e_ConstProbNode> node ( rf.tree(index).topology_,
rf.tree(index).paramete
rs_,
pos);
tmp_prob.init(0);
for(int ii = 0; ii < class_count; ++ii)
{
tmp_prob[ii] = node.prob_begin()[ii];
}
if(is_weighted)
{
for(int ii = 0; ii < class_count; ++ii)
tmp_prob[ii] = tmp_prob[ii] * (*(node.prob_begin()-
1));
}
rowVector(prob_oob, ll) += tmp_prob;
int label = argMax(tmp_prob);
if(label != pr.response()(ll, 0))
{
// update number of wrong oob samples in this tree.
++wrong_oob;
// update number of trees in which current sample is wr
ong oob
++oobErrorCount[ll];
}
}
}
int breimanstyle = 0;
int totalOobCount = 0;
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
{
if(oobCount[ll])
{
if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0))
++breimanstyle;
++totalOobCount;
if(oobroc_per_tree.shape(2) == 1)
{
oobroc_per_tree(pr.response()(ll,0), argMax(rowVector(p
rob_oob, ll)),0 ,index)++;
}
}
}
if(oobroc_per_tree.shape(2) == 1)
oobroc_per_tree.bindOuter(index)/=totalOobCount;
if(oobroc_per_tree.shape(2) > 1)
{
MultiArrayView<3, double> current_roc
= oobroc_per_tree.bindOuter(index);
for(int gg = 0; gg < current_roc.shape(2); ++gg)
{
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
{
if(oobCount[ll])
{
int pred = prob_oob(ll, 1) > (double(gg)/double(cur
rent_roc.shape(2)))?
1 : 0;
current_roc(pr.response()(ll, 0), pred, gg)+= 1;
}
}
current_roc.bindOuter(gg)/= totalOobCount;
}
}
breiman_per_tree[index] = double(breimanstyle)/double(totalOobCount
);
oob_per_tree[index] = double(wrong_oob)/double(total_oob);
// go through the ib samples;
}
/** Normalise variable importance after the number of trees is known.
*/
template<class RF, class PR>
void visit_at_end(RF & rf, PR & pr)
{
// ullis original metric and breiman style stuff
oob_per_tree2 = 0;
int totalOobCount =0;
int breimanstyle = 0;
for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
{
if(oobCount[ll])
{
if(argMax(rowVector(prob_oob, ll)) != pr.response()(ll, 0))
++breimanstyle;
oob_per_tree2 += double(oobErrorCount[ll]) / oobCount[ll];
++totalOobCount;
}
}
oob_per_tree2 /= totalOobCount;
oob_breiman = double(breimanstyle)/totalOobCount;
// mean error of each tree
MultiArrayView<2, double> mean(Shp(1,1), &oob_mean);
MultiArrayView<2, double> stdDev(Shp(1,1), &oob_std);
rowStatistics(oob_per_tree, mean, stdDev);
} }
}; };
/** calculate variable importance while learning. /** calculate variable importance while learning.
*/ */
class VariableImportanceVisitor : public VisitorBase class VariableImportanceVisitor : public VisitorBase
{ {
public: public:
/** This Array has the same entries as the R - random forest variable /** This Array has the same entries as the R - random forest variable
* importance * importance.
* Matrix is featureCount by (classCount +2)
* variable_importance_(ii,jj) is the variable importance measure of
* the ii-th variable according to:
* jj = 0 - (classCount-1)
* classwise permutation importance
* jj = rowCount(variable_importance_) -2
* permutation importance
* jj = rowCount(variable_importance_) -1
* gini decrease importance.
*
* permutation importance:
* The difference between the fraction of OOB samples classified corre
ctly
* before and after permuting (randomizing) the ii-th column is calcul
ated.
* The ii-th column is permuted rep_cnt times.
*
* class wise permutation importance:
* same as permutation importance. We only look at those OOB samples w
hose
* response corresponds to class jj.
*
* gini decrease importance:
* row ii corresponds to the sum of all gini decreases induced by vari
able ii
* in each node of the random forest.
*/ */
MultiArray<2, double> variable_importance_; MultiArray<2, double> variable_importance_;
int repetition_count_; int repetition_count_;
bool in_place_; bool in_place_;
#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
* \param rep_cnt (defautl: 10) how often should
* the permutation take place. Set to 1 to make calculation faster (but
* 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,
skipping to change at line 815 skipping to change at line 1302
* *
* \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 index)
{ {
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
* 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.
typename PR::Feature_t & features //typename PR::Feature_t & features
= const_cast<typename PR::Feature_t &>(pr.features()); // = const_cast<typename PR::Feature_t &>(pr.features());
typedef typename PR::FeatureWithMemory_t FeatureArray;
typedef typename FeatureArray::value_type FeatureValue;
FeatureArray features = pr.features();
//find the oob indices of current tree. //find the oob indices of current tree.
ArrayVector<Int32> oob_indices; ArrayVector<Int32> oob_indices;
ArrayVector<Int32>::iterator ArrayVector<Int32>::iterator
iter; iter;
for(int ii = 0; ii < rf.ext_param_.row_count_; ++ii) for(int ii = 0; ii < rf.ext_param_.row_count_; ++ii)
if(!sm.is_used()[ii]) if(!sm.is_used()[ii])
oob_indices.push_back(ii); oob_indices.push_back(ii);
//create space to back up a column //create space to back up a column
std::vector<double> backup_column; ArrayVector<FeatureValue> backup_column;
// Random foo // Random foo
#ifdef CLASSIFIER_TEST #ifdef CLASSIFIER_TEST
RandomMT19937 random(1); RandomMT19937 random(1);
#else #else
RandomMT19937 random(RandomSeed); RandomMT19937 random(RandomSeed);
#endif #endif
UniformIntRandomFunctor<RandomMT19937> UniformIntRandomFunctor<RandomMT19937>
randint(random); randint(random);
skipping to change at line 865 skipping to change at line 1360
//per class //per class
++oob_right[pr.response()(*iter,0)]; ++oob_right[pr.response()(*iter,0)];
//total //total
++oob_right[class_count]; ++oob_right[class_count];
} }
} }
//get the oob rate after permuting the ii'th dimension. //get the oob rate after permuting the ii'th dimension.
for(int ii = 0; ii < column_count; ++ii) for(int ii = 0; ii < column_count; ++ii)
{ {
perm_oob_right.init(0.0); perm_oob_right.init(0.0);
//make backup of orinal column //make backup of original column
backup_column.clear(); backup_column.clear();
for(iter = oob_indices.begin(); for(iter = oob_indices.begin();
iter != oob_indices.end(); iter != oob_indices.end();
++iter) ++iter)
{ {
backup_column.push_back(features(*iter,ii)); backup_column.push_back(features(*iter,ii));
} }
//get the oob rate after permuting the ii'th dimension. //get the oob rate after permuting the ii'th dimension.
for(int rr = 0; rr < repetition_count_; ++rr) for(int rr = 0; rr < repetition_count_; ++rr)
{ {
//permute dimension. //permute dimension.
int n = oob_indices.size(); int n = oob_indices.size();
for(int jj = 1; jj < n; ++jj) for(int jj = 1; jj < n; ++jj)
std::swap(features(oob_indices[jj], ii), std::swap(features(oob_indices[jj], ii),
features(oob_indices[randint(jj+1)], ii)); features(oob_indices[randint(jj+1)], ii));
//get the oob sucess rate after permuting //get the oob success rate after permuting
for(iter = oob_indices.begin(); for(iter = oob_indices.begin();
iter != oob_indices.end(); iter != oob_indices.end();
++iter) ++iter)
{ {
if(rf.tree(index) if(rf.tree(index)
.predictLabel(rowVector(features, *iter)) .predictLabel(rowVector(features, *iter))
== pr.response()(*iter, 0)) == pr.response()(*iter, 0))
{ {
//per class //per class
++perm_oob_right[pr.response()(*iter, 0)]; ++perm_oob_right[pr.response()(*iter, 0)];
skipping to change at line 934 skipping to change at line 1429
/** 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
*/
class RandomForestProgressVisitor : public VisitorBase {
public:
RandomForestProgressVisitor() : VisitorBase() {}
template<class RF, class PR, class SM, class ST>
void visit_after_tree(RF& rf, PR & pr, SM & sm, ST & st, int index){
if(index != rf.options().tree_count_-1) {
std::cout << "\r[" << std::setw(10) << (index+1)/static_cast<do
uble>(rf.options().tree_count_)*100 << "%]"
<< " (" << index+1 << " of " << rf.options().tree_cou
nt_ << ") done" << std::flush;
}
else {
std::cout << "\r[" << std::setw(10) << 100.0 << "%]" << std::en
dl;
}
}
template<class RF, class PR>
void visit_at_end(RF const & rf, PR const & pr) {
std::string a = TOCS;
std::cout << "all " << rf.options().tree_count_ << " trees have bee
n learned in " << a << std::endl;
}
template<class RF, class PR>
void visit_at_beginning(RF const & rf, PR const & pr) {
TIC;
std::cout << "growing random forest, which will have " << rf.option
s().tree_count_ << " trees" << std::endl;
}
private:
USETICTOC;
};
/** Computes Correlation/Similarity Matrix of features while learning
* random forest.
*/
class CorrelationVisitor : public VisitorBase
{
public:
/** gini_missc(ii, jj) describes how well variable jj can describe a pa
rtition
* created on variable ii(when variable ii was chosen)
*/
MultiArray<2, double> gini_missc;
MultiArray<2, int> tmp_labels;
/** additional noise features.
*/
MultiArray<2, double> noise;
MultiArray<2, double> noise_l;
/** how well can a noise column describe a partition created on variabl
e ii.
*/
MultiArray<2, double> corr_noise;
MultiArray<2, double> corr_l;
/** Similarity Matrix
*
* (numberOfFeatures + 1) by (number Of Features + 1) Matrix
* gini_missc
* - row normalized by the number of times the column was chosen
* - mean of corr_noise subtracted
* - and symmetrised.
*
*/
MultiArray<2, double> similarity;
/** Distance Matrix 1-similarity
*/
MultiArray<2, double> distance;
ArrayVector<int> tmp_cc;
/** How often was variable ii chosen
*/
ArrayVector<int> numChoices;
typedef BestGiniOfColumn<GiniCriterion> ColumnDecisionFunctor;
BestGiniOfColumn<GiniCriterion> bgfunc;
void save(std::string file, std::string prefix)
{
/*
std::string tmp;
#define VAR_WRITE(NAME) \
tmp = #NAME;\
tmp += "_";\
tmp += prefix;\
vigra::writeToHDF5File(file.c_str(), tmp.c_str(), NAME);
VAR_WRITE(gini_missc);
VAR_WRITE(corr_noise);
VAR_WRITE(distance);
VAR_WRITE(similarity);
vigra::writeToHDF5File(file.c_str(), "nChoices", MultiArrayView<2,
int>(MultiArrayShape<2>::type(numChoices.size(),1), numChoices.data()));
#undef VAR_WRITE
*/
}
template<class RF, class PR>
void visit_at_beginning(RF const & rf, PR & pr)
{
typedef MultiArrayShape<2>::type Shp;
int n = rf.ext_param_.column_count_;
gini_missc.reshape(Shp(n +1,n+ 1));
corr_noise.reshape(Shp(n + 1, 10));
corr_l.reshape(Shp(n +1, 10));
noise.reshape(Shp(pr.features().shape(0), 10));
noise_l.reshape(Shp(pr.features().shape(0), 10));
RandomMT19937 random(RandomSeed);
for(int ii = 0; ii < noise.size(); ++ii)
{
noise[ii] = random.uniform53();
noise_l[ii] = random.uniform53() > 0.5;
}
bgfunc = ColumnDecisionFunctor( rf.ext_param_);
tmp_labels.reshape(pr.response().shape());
tmp_cc.resize(2);
numChoices.resize(n+1);
// look at all axes
}
template<class RF, class PR>
void visit_at_end(RF const & rf, PR const & pr)
{
typedef MultiArrayShape<2>::type Shp;
similarity.reshape(gini_missc.shape());
similarity = gini_missc;;
MultiArray<2, double> mean_noise(Shp(corr_noise.shape(0), 1));
rowStatistics(corr_noise, mean_noise);
mean_noise/= MultiArrayView<2, int>(mean_noise.shape(), numChoices.
data());
int rC = similarity.shape(0);
for(int jj = 0; jj < rC-1; ++jj)
{
rowVector(similarity, jj) /= numChoices[jj];
rowVector(similarity, jj) -= mean_noise(jj, 0);
}
for(int jj = 0; jj < rC; ++jj)
{
similarity(rC -1, jj) /= numChoices[jj];
}
rowVector(similarity, rC - 1) -= mean_noise(rC-1, 0);
similarity = abs(similarity);
FindMinMax<double> minmax;
inspectMultiArray(srcMultiArrayRange(similarity), minmax);
for(int jj = 0; jj < rC; ++jj)
similarity(jj, jj) = minmax.max;
similarity.subarray(Shp(0,0), Shp(rC-1, rC-1))
+= similarity.subarray(Shp(0,0), Shp(rC-1, rC-1)).transpose();
similarity.subarray(Shp(0,0), Shp(rC-1, rC-1))/= 2;
columnVector(similarity, rC-1) = rowVector(similarity, rC-1).transp
ose();
for(int jj = 0; jj < rC; ++jj)
similarity(jj, jj) = 0;
FindMinMax<double> minmax2;
inspectMultiArray(srcMultiArrayRange(similarity), minmax2);
for(int jj = 0; jj < rC; ++jj)
similarity(jj, jj) = minmax2.max;
distance.reshape(gini_missc.shape(), minmax2.max);
distance -= similarity;
}
template<class Tree, class Split, class Region, class Feature_t, class
Label_t>
void visit_after_split( Tree & tree,
Split & split,
Region & parent,
Region & leftChild,
Region & rightChild,
Feature_t & features,
Label_t & labels)
{
if(split.createNode().typeID() == i_ThresholdNode)
{
double wgini;
tmp_cc.init(0);
for(int ii = 0; ii < parent.size(); ++ii)
{
tmp_labels[parent[ii]]
= (features(parent[ii], split.bestSplitColumn()) < spli
t.bestSplitThreshold());
++tmp_cc[tmp_labels[parent[ii]]];
}
double region_gini = bgfunc.loss_of_region(tmp_labels,
parent.begin(),
parent.end(),
tmp_cc);
int n = split.bestSplitColumn();
++numChoices[n];
++(*(numChoices.end()-1));
//this functor does all the work
for(int k = 0; k < features.shape(1); ++k)
{
bgfunc(columnVector(features, k),
tmp_labels,
parent.begin(), parent.end(),
tmp_cc);
wgini = (region_gini - bgfunc.min_gini_);
gini_missc(n, k)
+= wgini;
}
for(int k = 0; k < 10; ++k)
{
bgfunc(columnVector(noise, k),
tmp_labels,
parent.begin(), parent.end(),
tmp_cc);
wgini = (region_gini - bgfunc.min_gini_);
corr_noise(n, k)
+= wgini;
}
for(int k = 0; k < 10; ++k)
{
bgfunc(columnVector(noise_l, k),
tmp_labels,
parent.begin(), parent.end(),
tmp_cc);
wgini = (region_gini - bgfunc.min_gini_);
corr_l(n, k)
+= wgini;
}
bgfunc(labels, tmp_labels, parent.begin(), parent.end(),tmp_cc)
;
wgini = (region_gini - bgfunc.min_gini_);
gini_missc(n, columnCount(gini_missc)-1)
+= wgini;
region_gini = split.region_gini_;
#if 1
Node<i_ThresholdNode> node(split.createNode());
gini_missc(rowCount(gini_missc)-1,
node.column())
+=split.region_gini_ - split.minGini();
#endif
for(int k = 0; k < 10; ++k)
{
split.bgfunc(columnVector(noise, k),
labels,
parent.begin(), parent.end(),
parent.classCounts());
corr_noise(rowCount(gini_missc)-1,
k)
+= wgini;
}
#if 0
for(int k = 0; k < tree.ext_param_.actual_mtry_; ++k)
{
wgini = region_gini - split.min_gini_[k];
gini_missc(rowCount(gini_missc)-1,
split.splitColumns[k])
+= wgini;
}
for(int k=tree.ext_param_.actual_mtry_; k<features.shape(1); ++
k)
{
split.bgfunc(columnVector(features, split.splitColumns[k]),
labels,
parent.begin(), parent.end(),
parent.classCounts());
wgini = region_gini - split.bgfunc.min_gini_;
gini_missc(rowCount(gini_missc)-1,
split.splitColumns[k]) += wgini;
}
#endif
// remember to partition the data according to the best.
gini_missc(rowCount(gini_missc)-1,
columnCount(gini_missc)-1)
+= region_gini;
SortSamplesByDimensions<Feature_t>
sorter(features, split.bestSplitColumn(), split.bestSplitTh
reshold());
std::partition(parent.begin(), parent.end(), sorter);
}
}
};
} // namespace visitors
} // namespace rf
} // namespace vigra } // namespace vigra
//@}
#endif // RF_VISITORS_HXX #endif // RF_VISITORS_HXX
 End of changes. 108 change blocks. 
108 lines changed or deleted 940 lines changed or added


 rgbvalue.hxx   rgbvalue.hxx 
skipping to change at line 120 skipping to change at line 120
\ref RGBValueOperators "Arithmetic operations" are defined as component -wise applications of these \ref RGBValueOperators "Arithmetic operations" are defined as component -wise applications of these
operations. Addition, subtraction, and multiplication of two RGBValues operations. Addition, subtraction, and multiplication of two RGBValues
(+=, -=, *=, +, -, *, unary -), multiplication and division of an (+=, -=, *=, +, -, *, unary -), multiplication and division of an
RGBValue with a double, and NumericTraits/PromoteTraits are defined, RGBValue with a double, and NumericTraits/PromoteTraits are defined,
so that RGBValue fulfills the requirements of a \ref LinearAlgebraConce pt "Linear Algebra". so that RGBValue fulfills the requirements of a \ref LinearAlgebraConce pt "Linear Algebra".
A number of \ref RGBValueAccessors "accessors" are provided A number of \ref RGBValueAccessors "accessors" are provided
that support access to RGBValues as a whole, to a selected that support access to RGBValues as a whole, to a selected
color component, or to the luminance value. color component, or to the luminance value.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VALUETYPE, unsigned int RED_IDX = 0, unsigned int GREEN_IDX = 1, unsigned int BLUE_IDX = 2> template <class VALUETYPE, unsigned int RED_IDX = 0, unsigned int GREEN_IDX = 1, unsigned int BLUE_IDX = 2>
class RGBValue class RGBValue
: public TinyVector<VALUETYPE, 3> : public TinyVector<VALUETYPE, 3>
{ {
typedef TinyVector<VALUETYPE, 3> Base; typedef TinyVector<VALUETYPE, 3> Base;
// inverse mapping from index to color // inverse mapping from index to color
enum { enum {
skipping to change at line 356 skipping to change at line 356
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup RGBValueOperators Functions for RGBValue /** \addtogroup RGBValueOperators Functions for RGBValue
\brief Implement basic arithmetic and equality for RGBValue. \brief Implement basic arithmetic and equality for RGBValue.
These functions fulfill the requirements of a Linear Algebra. These functions fulfill the requirements of a Linear Algebra.
Return types are determined according to \ref RGBValueTraits. Return types are determined according to \ref RGBValueTraits.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
<p> <p>
*/ */
//@{ //@{
/// component-wise equal /// component-wise equal
template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BI DX1, template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BI DX1,
class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BI DX2> class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BI DX2>
inline inline
bool bool
skipping to change at line 448 skipping to change at line 448
typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> P romote; typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> P romote;
}; };
template <class T, unsigned int R, unsigned int G, unsigned int B> template <class T, unsigned int R, unsigned int G, unsigned int B>
struct PromoteTraits<double, RGBValue<T, R, G, B> > struct PromoteTraits<double, RGBValue<T, R, G, B> >
{ {
typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> P romote; typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> P romote;
}; };
\endcode \endcode
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
#if !defined(NO_PARTIAL_TEMPLATE_SPECIALIZATION) #if !defined(NO_PARTIAL_TEMPLATE_SPECIALIZATION)
template <class T, unsigned int R, unsigned int G, unsigned int B> template <class T, unsigned int R, unsigned int G, unsigned int B>
struct NumericTraits<RGBValue<T, R, G, B> > struct NumericTraits<RGBValue<T, R, G, B> >
{ {
typedef RGBValue<T, R, G, B> Type; typedef RGBValue<T, R, G, B> Type;
skipping to change at line 921 skipping to change at line 921
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup DataAccessors /** \addtogroup DataAccessors
*/ */
//@{ //@{
/** \defgroup RGBValueAccessors Accessors for RGBValue */ /** \defgroup RGBValueAccessors Accessors for RGBValue */
//@{ //@{
/** Encapsulate access to rgb values. /** Encapsulate access to rgb values.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class RGBVALUE> template <class RGBVALUE>
class RGBAccessor class RGBAccessor
: public VectorAccessor<RGBVALUE> : public VectorAccessor<RGBVALUE>
{ {
public: public:
typedef typename RGBVALUE::value_type component_type; typedef typename RGBVALUE::value_type component_type;
skipping to change at line 1050 skipping to change at line 1050
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* RedAccessor */ /* RedAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** Encapsulate access to red band of an rgb value. /** Encapsulate access to red band of an rgb value.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class RGBVALUE> template <class RGBVALUE>
class RedAccessor class RedAccessor
{ {
public: public:
typedef typename RGBVALUE::value_type value_type; typedef typename RGBVALUE::value_type value_type;
/** Get value of the red component /** Get value of the red component
*/ */
skipping to change at line 1100 skipping to change at line 1100
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* GreenAccessor */ /* GreenAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** Encapsulate access to green band of an rgb value. /** Encapsulate access to green band of an rgb value.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class RGBVALUE> template <class RGBVALUE>
class GreenAccessor class GreenAccessor
{ {
public: public:
typedef typename RGBVALUE::value_type value_type; typedef typename RGBVALUE::value_type value_type;
/** Get value of the green component /** Get value of the green component
*/ */
skipping to change at line 1150 skipping to change at line 1150
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* BlueAccessor */ /* BlueAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** Encapsulate access to blue band of an rgb value. /** Encapsulate access to blue band of an rgb value.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class RGBVALUE> template <class RGBVALUE>
class BlueAccessor class BlueAccessor
{ {
public: public:
typedef typename RGBVALUE::value_type value_type; typedef typename RGBVALUE::value_type value_type;
/** Get value of the blue component /** Get value of the blue component
*/ */
skipping to change at line 1200 skipping to change at line 1200
}; };
/********************************************************/ /********************************************************/
/* */ /* */
/* RGBToGrayAccessor */ /* RGBToGrayAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** Encapsulate access to luminance of an rgb value. /** Encapsulate access to luminance of an rgb value.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class RGBVALUE> template <class RGBVALUE>
class RGBToGrayAccessor class RGBToGrayAccessor
{ {
public: public:
typedef typename RGBVALUE::value_type value_type; typedef typename RGBVALUE::value_type value_type;
/** Get value of the luminance /** Get value of the luminance
*/ */
skipping to change at line 1233 skipping to change at line 1233
/********************************************************/ /********************************************************/
/* */ /* */
/* GrayToRGBAccessor */ /* GrayToRGBAccessor */
/* */ /* */
/********************************************************/ /********************************************************/
/** Create an RGB view for a grayscale image by making all three channe ls /** Create an RGB view for a grayscale image by making all three channe ls
equal. equal.
<b>\#include</b> \<<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.h xx</a>\><br> <b>\#include</b> \<vigra/rgbvalue.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class VALUETYPE> template <class VALUETYPE>
class GrayToRGBAccessor class GrayToRGBAccessor
{ {
public: public:
typedef typename vigra::RGBValue<VALUETYPE> value_type; typedef typename vigra::RGBValue<VALUETYPE> value_type;
/** Get RGB value for the given pixel. /** Get RGB value for the given pixel.
*/ */
 End of changes. 9 change blocks. 
9 lines changed or deleted 9 lines changed or added


 seededregiongrowing.hxx   seededregiongrowing.hxx 
skipping to change at line 46 skipping to change at line 46
#ifndef VIGRA_SEEDEDREGIONGROWING_HXX #ifndef VIGRA_SEEDEDREGIONGROWING_HXX
#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"
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 163 skipping to change at line 164
struct UnlabelWatersheds struct UnlabelWatersheds
{ {
int operator()(int label) const int operator()(int label) const
{ {
return label < 0 ? 0 : label; return label < 0 ? 0 : label;
} }
}; };
} // namespace detail } // namespace detail
enum SRGType { CompleteGrow = 0, KeepContours = 1, StopAtThreshold = 2, SRG
WatershedLabel = -1 };
/** \addtogroup SeededRegionGrowing Region Segmentation Algorithms /** \addtogroup SeededRegionGrowing Region Segmentation Algorithms
Region growing, watersheds, and voronoi tesselation Region growing, watersheds, and voronoi tesselation
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* seededRegionGrowing */ /* seededRegionGrowing */
/* */ /* */
/********************************************************/ /********************************************************/
/** Choose between different types of Region Growing */
enum SRGType {
CompleteGrow = 0,
KeepContours = 1,
StopAtThreshold = 2,
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).
The highest seed label found in the seed image is returned by the algor
ithm.
Seed regions can be as large as you wish and as small as one pixel. If Seed regions can be as large as you wish and as small as one pixel. If
there are no candidates, the algorithm will simply copy the seed image there are no candidates, the algorithm will simply copy the seed image
into the output image. Otherwise it will aggregate the candidates into into the output image. Otherwise it will aggregate the candidates into
the existing regions so that a cost function is minimized. the existing regions so that a cost function is minimized.
Candidates are taken from the neighborhood of the already assigned pixe ls, Candidates are taken from the neighborhood of the already assigned pixe ls,
where the type of neighborhood is determined by parameter <tt>neighborh ood</tt> where the type of neighborhood is determined by parameter <tt>neighborh ood</tt>
which can take the values <tt>FourNeighborCode()</tt> (the default) which can take the values <tt>FourNeighborCode()</tt> (the default)
or <tt>EightNeighborCode()</tt>. The algorithm basically works as follo ws or <tt>EightNeighborCode()</tt>. The algorithm basically works as follo ws
(illustrated for 4-neighborhood, but 8-neighborhood works in the same w ay): (illustrated for 4-neighborhood, but 8-neighborhood works in the same w ay):
<ol> <ol>
<li> Find all candidate pixels that are 4-adjacent to a seed region. <li> Find all candidate pixels that are 4-adjacent to a seed region.
Calculate the cost for aggregating each candidate into its adajacent re gion Calculate the cost for aggregating each candidate into its adjacent reg ion
and put the candidates into a priority queue. and put the candidates into a priority queue.
<li> While( priority queue is not empty and termination criterion is no t fulfilled) <li> While( priority queue is not empty and termination criterion is no t fulfilled)
<ol> <ol>
<li> Take the candidate with least cost from the queue. If it has n ot <li> Take the candidate with least cost from the queue. If it has n ot
already been merged, merge it with it's adjacent region. already been merged, merge it with it's adjacent region.
<li> Put all candidates that are 4-adjacent to the pixel just proce ssed <li> Put all candidates that are 4-adjacent to the pixel just proce ssed
skipping to change at line 244 skipping to change at line 253
update statistics for each region and to calculate the cost for each update statistics for each region and to calculate the cost for each
candidate. The <TT>RegionStatisticsArray</TT> must be compatible to the candidate. The <TT>RegionStatisticsArray</TT> must be compatible to the
\ref ArrayOfRegionStatistics functor and contains an <em> array</em> of \ref ArrayOfRegionStatistics functor and contains an <em> array</em> of
statistics objects for each region. The indices must correspond to the statistics objects for each region. The indices must correspond to the
labels of the seed regions. The statistics for the initial regions must have labels of the seed regions. The statistics for the initial regions must have
been calculated prior to calling <TT>seededRegionGrowing()</TT> (for ex ample by been calculated prior to calling <TT>seededRegionGrowing()</TT> (for ex ample by
means of \ref inspectTwoImagesIf()). means of \ref inspectTwoImagesIf()).
For each candidate For each candidate
<TT>x</TT> that is adjacent to region <TT>i</TT>, the algorithm will ca ll <TT>x</TT> that is adjacent to region <TT>i</TT>, the algorithm will ca ll
<TT>stats[i].cost(as(x))</TT> to get the cost (where <TT>x</TT> is a <T T>SrcImageIterator</TT> <TT>stats[i].cost(as(x))</TT> to get the cost (where <TT>x</TT> is a <T T>SrcIterator</TT>
and <TT>as</TT> is and <TT>as</TT> is
the SrcAccessor). When a candidate has been merged with a region, the the SrcAccessor). When a candidate has been merged with a region, the
statistics are updated by calling <TT>stats[i].operator()(as(x))</TT>. Since statistics are updated by calling <TT>stats[i].operator()(as(x))</TT>. Since
the <TT>RegionStatisticsArray</TT> is passed by reference, this will ov erwrite the <TT>RegionStatisticsArray</TT> is passed by reference, this will ov erwrite
the original statistics. the original statistics.
If a candidate could be merged into more than one regions with identica l If a candidate could be merged into more than one regions with identica l
cost, the algorithm will favour the nearest region. If <tt>StopAtThresh old</tt> is active, cost, the algorithm will favour the nearest region. If <tt>StopAtThresh old</tt> is active,
and the cost of the current candidate at any point in the algorithm exc eeds the optional and the cost of the current candidate at any point in the algorithm exc eeds the optional
<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>),
skipping to change at line 268 skipping to change at line 277
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 arguments explicitly:
\code \code
namespace vigra { namespace vigra {
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
void typename SeedAccessor::value_type
seededRegionGrowing(SrcImageIterator srcul, SrcImageIterator srclr, seededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccess
SrcAccessor as, or as,
SeedImageIterator seedsul, SeedAccessor aseeds, SeedImageIterator seedsul, SeedAccessor aseeds,
DestImageIterator 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 SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
void typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcA seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> s
ccessor> src, rc,
pair<SeedImageIterator, SeedAccessor> seeds, pair<SeedImageIterator, SeedAccessor> seeds,
pair<DestImageIterator, 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="seededregiongrowing_8hxx-source.html">vigra /seededregiongrowing.hxx</a>\><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
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;
skipping to change at line 330 skipping to change at line 339
points(w * rand() / RAND_MAX , h * rand() / RAND_MAX) = i; points(w * rand() / RAND_MAX , h * rand() / RAND_MAX) = i;
// calculate Euclidean distance transform // calculate Euclidean distance transform
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
SrcImageIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
SeedImageIterator seed_upperleft; SeedImageIterator seed_upperleft;
DestImageIterator 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;
// calculate costs // calculate costs
RegionStatisticsArray::value_type::cost_type cost = RegionStatisticsArray::value_type::cost_type cost =
stats[seed_accessor(seed_upperleft)].cost(src_accessor(src_upperlef t)); stats[seed_accessor(seed_upperleft)].cost(src_accessor(src_upperlef t));
skipping to change at line 365 skipping to change at line 374
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
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 SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
void seededRegionGrowing(SrcImageIterator srcul, typename SeedAccessor::value_type
SrcImageIterator srclr, SrcAccessor as, seededRegionGrowing(SrcIterator srcul,
SeedImageIterator seedsul, SeedAccessor aseeds, SrcIterator srclr, SrcAccessor as,
DestImageIterator destul, DestAccessor ad, SeedImageIterator seedsul, SeedAccessor aseeds,
RegionStatisticsArray & stats, DestIterator destul, DestAccessor ad,
SRGType srgType, RegionStatisticsArray & stats,
Neighborhood, SRGType srgType,
double max_cost) Neighborhood,
double max_cost)
{ {
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 count = 0; int count = 0;
SrcImageIterator isy = srcul, isx = srcul; // iterators for the src im age SrcIterator isy = srcul, isx = srcul; // iterators for the src image
typedef typename SeedAccessor::value_type LabelType;
typedef typename RegionStatisticsArray::value_type RegionStatistics; typedef typename RegionStatisticsArray::value_type RegionStatistics;
typedef typename RegionStatistics::cost_type CostType; typedef typename RegionStatistics::cost_type CostType;
typedef detail::SeedRgPixel<CostType> Pixel; typedef detail::SeedRgPixel<CostType> Pixel;
typename Pixel::Allocator allocator; typename Pixel::Allocator allocator;
typedef std::priority_queue<Pixel *, std::vector<Pixel *>, typedef std::priority_queue<Pixel *, std::vector<Pixel *>,
typename Pixel::Compare> SeedRgPixelHeap; typename Pixel::Compare> SeedRgPixelHeap;
// copy seed image in an image with border // copy seed image in an image with border
IImage regions(w+2, h+2); IImage regions(w+2, h+2);
IImage::Iterator ir = regions.upperLeft() + Diff2D(1,1); IImage::Iterator ir = regions.upperLeft() + Diff2D(1,1);
IImage::Iterator iry, irx; IImage::Iterator iry, irx;
initImageBorder(destImageRange(regions), 1, SRGWatershedLabel); initImageBorder(destImageRange(regions), 1, SRGWatershedLabel);
copyImage(seedsul, seedsul+Diff2D(w,h), aseeds, ir, regions.accessor()) ; copyImage(seedsul, seedsul+Diff2D(w,h), aseeds, ir, regions.accessor()) ;
// allocate and init memory for the results // allocate and init memory for the results
SeedRgPixelHeap pheap; SeedRgPixelHeap pheap;
int cneighbor; int cneighbor, maxRegionLabel = 0;
typedef typename Neighborhood::Direction Direction; typedef typename Neighborhood::Direction Direction;
int directionCount = Neighborhood::DirectionCount; int directionCount = Neighborhood::DirectionCount;
Point2D pos(0,0); Point2D pos(0,0);
for(isy=srcul, iry=ir, pos.y=0; pos.y<h; for(isy=srcul, iry=ir, pos.y=0; pos.y<h;
++pos.y, ++isy.y, ++iry.y) ++pos.y, ++isy.y, ++iry.y)
{ {
for(isx=isy, irx=iry, pos.x=0; pos.x<w; for(isx=isy, irx=iry, pos.x=0; pos.x<w;
++pos.x, ++isx.x, ++irx.x) ++pos.x, ++isx.x, ++irx.x)
skipping to change at line 433 skipping to change at line 444
if(cneighbor > 0) if(cneighbor > 0)
{ {
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
{
vigra_precondition((LabelType)*irx <= stats.maxRegionLabel(
),
"seededRegionGrowing(): Largest label exceeds size of R
egionStatisticsArray.");
if(maxRegionLabel < *irx)
maxRegionLabel = *irx;
}
} }
} }
// perform region growing // perform region growing
while(pheap.size() != 0) while(pheap.size() != 0)
{ {
Pixel * pixel = pheap.top(); Pixel * pixel = pheap.top();
pheap.pop(); pheap.pop();
if((srgType & StopAtThreshold) != 0 && pixel->cost_ > max_cost)
break;
Point2D pos = pixel->location_; Point2D pos = pixel->location_;
Point2D nearest = pixel->nearest_; Point2D nearest = pixel->nearest_;
int lab = pixel->label_; int lab = pixel->label_;
CostType cost = pixel->cost_;
allocator.dismiss(pixel); allocator.dismiss(pixel);
if((srgType & StopAtThreshold) != 0 && cost > max_cost)
break;
irx = ir + pos; irx = ir + pos;
isx = srcul + pos; isx = srcul + pos;
if(*irx) // already labelled region / watershed? if(*irx) // already labelled region / watershed?
continue; continue;
if((srgType & KeepContours) != 0) if((srgType & KeepContours) != 0)
{ {
for(int i=0; i<directionCount; i++) for(int i=0; i<directionCount; i++)
{ {
skipping to change at line 493 skipping to change at line 512
CostType cost = stats[lab].cost(as(isx, Neighborhood::d iff((Direction)i))); CostType cost = stats[lab].cost(as(isx, Neighborhood::d iff((Direction)i)));
Pixel * new_pixel = Pixel * new_pixel =
allocator.create(pos+Neighborhood::diff((Direction) i), nearest, cost, count++, lab); allocator.create(pos+Neighborhood::diff((Direction) i), nearest, cost, count++, lab);
pheap.push(new_pixel); pheap.push(new_pixel);
} }
} }
} }
} }
// free temporary memory
while(pheap.size() != 0)
{
allocator.dismiss(pheap.top());
pheap.pop();
}
// write result // write result
transformImage(ir, ir+Point2D(w,h), regions.accessor(), destul, ad, transformImage(ir, ir+Point2D(w,h), regions.accessor(), destul, ad,
detail::UnlabelWatersheds()); detail::UnlabelWatersheds());
return (LabelType)maxRegionLabel;
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(SrcImageIterator srcul, seededRegionGrowing(SrcIterator srcul,
SrcImageIterator srclr, SrcAccessor as, SrcIterator srclr, SrcAccessor as,
SeedImageIterator seedsul, SeedAccessor aseeds, SeedImageIterator seedsul, SeedAccessor aseeds,
DestImageIterator destul, DestAccessor ad, DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType, SRGType srgType,
Neighborhood n) Neighborhood n)
{ {
seededRegionGrowing(srcul, srclr, as, return seededRegionGrowing(srcul, srclr, as,
seedsul, aseeds, seedsul, aseeds,
destul, ad, destul, ad,
stats, srgType, n, NumericTraits<double>::max()); stats, srgType, n, NumericTraits<double>::m
ax());
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray> class RegionStatisticsArray>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(SrcImageIterator srcul, seededRegionGrowing(SrcIterator srcul,
SrcImageIterator srclr, SrcAccessor as, SrcIterator srclr, SrcAccessor as,
SeedImageIterator seedsul, SeedAccessor aseeds, SeedImageIterator seedsul, SeedAccessor aseeds,
DestImageIterator destul, DestAccessor ad, DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType) SRGType srgType)
{ {
seededRegionGrowing(srcul, srclr, as, return seededRegionGrowing(srcul, srclr, as,
seedsul, aseeds, seedsul, aseeds,
destul, ad, destul, ad,
stats, srgType, FourNeighborCode()); stats, srgType, FourNeighborCode());
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray> class RegionStatisticsArray>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(SrcImageIterator srcul, seededRegionGrowing(SrcIterator srcul,
SrcImageIterator srclr, SrcAccessor as, SrcIterator srclr, SrcAccessor as,
SeedImageIterator seedsul, SeedAccessor aseeds, SeedImageIterator seedsul, SeedAccessor aseeds,
DestImageIterator destul, DestAccessor ad, DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats) RegionStatisticsArray & stats)
{ {
seededRegionGrowing(srcul, srclr, as, return seededRegionGrowing(srcul, srclr, as,
seedsul, aseeds, seedsul, aseeds,
destul, ad, destul, ad,
stats, CompleteGrow); stats, CompleteGrow);
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
img1,
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestImageIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType, SRGType srgType,
Neighborhood n, Neighborhood n,
double max_cost) double max_cost)
{ {
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 SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood> class RegionStatisticsArray, class Neighborhood>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
img1,
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestImageIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType, SRGType srgType,
Neighborhood n) Neighborhood n)
{ {
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, NumericTraits<double>::max()); stats, srgType, n, NumericTraits<double>::m
ax());
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray> class RegionStatisticsArray>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
img1,
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestImageIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats, RegionStatisticsArray & stats,
SRGType srgType) SRGType srgType)
{ {
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, FourNeighborCode()); stats, srgType, FourNeighborCode());
} }
template <class SrcImageIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class SeedImageIterator, class SeedAccessor, class SeedImageIterator, class SeedAccessor,
class DestImageIterator, class DestAccessor, class DestIterator, class DestAccessor,
class RegionStatisticsArray> class RegionStatisticsArray>
inline void inline typename SeedAccessor::value_type
seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> seededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> img1,
img1,
pair<SeedImageIterator, SeedAccessor> img3, pair<SeedImageIterator, SeedAccessor> img3,
pair<DestImageIterator, DestAccessor> img4, pair<DestIterator, DestAccessor> img4,
RegionStatisticsArray & stats) RegionStatisticsArray & stats)
{ {
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 SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood>
typename DestAccessor::value_type
fastSeededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccessor a
s,
DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats,
SRGType srgType,
Neighborhood,
double max_cost,
std::ptrdiff_t bucket_count = 256)
{
typedef typename DestAccessor::value_type LabelType;
vigra_precondition((srgType & KeepContours) == 0,
"fastSeededRegionGrowing(): the turbo algorithm doesn't support 'Kee
pContours', sorry.");
int w = srclr.x - srcul.x;
int h = srclr.y - srcul.y;
SrcIterator isy = srcul, isx = srcul; // iterators for the src image
DestIterator idy = destul, idx = destul; // iterators for the dest ima
ge
BucketQueue<Point2D, true> pqueue(bucket_count);
LabelType maxRegionLabel = 0;
Point2D pos(0,0);
for(isy=srcul, idy = destul, pos.y=0; pos.y<h; ++pos.y, ++isy.y, ++idy.
y)
{
for(isx=isy, idx=idy, pos.x=0; pos.x<w; ++pos.x, ++isx.x, ++idx.x)
{
LabelType label = ad(idx);
if(label != 0)
{
vigra_precondition(label <= stats.maxRegionLabel(),
"fastSeededRegionGrowing(): Largest label exceeds size
of RegionStatisticsArray.");
if(maxRegionLabel < label)
maxRegionLabel = label;
AtImageBorder atBorder = isAtImageBorder(pos.x, pos.y, w, h
);
if(atBorder == NotAtBorder)
{
NeighborhoodCirculator<DestIterator, Neighborhood> c(id
x), cend(c);
do
{
if(ad(c) == 0)
{
std::ptrdiff_t priority = (std::ptrdiff_t)stats
[label].cost(as(isx));
pqueue.push(pos, priority);
break;
}
}
while(++c != cend);
}
else
{
RestrictedNeighborhoodCirculator<DestIterator, Neighbor
hood>
c(idx, atBorder
), cend(c);
do
{
if(ad(c) == 0)
{
std::ptrdiff_t priority = (std::ptrdiff_t)stats
[label].cost(as(isx));
pqueue.push(pos, priority);
break;
}
}
while(++c != cend);
}
}
}
}
// perform region growing
while(!pqueue.empty())
{
Point2D pos = pqueue.top();
std::ptrdiff_t cost = pqueue.topPriority();
pqueue.pop();
if((srgType & StopAtThreshold) != 0 && cost > max_cost)
break;
idx = destul + pos;
isx = srcul + pos;
std::ptrdiff_t label = ad(idx);
AtImageBorder atBorder = isAtImageBorder(pos.x, pos.y, w, h);
if(atBorder == NotAtBorder)
{
NeighborhoodCirculator<DestIterator, Neighborhood> c(idx), cend
(c);
do
{
std::ptrdiff_t nlabel = ad(c);
if(nlabel == 0)
{
ad.set(label, idx, c.diff());
std::ptrdiff_t priority =
std::max((std::ptrdiff_t)stats[label].cost(as(is
x, c.diff())), cost);
pqueue.push(pos+c.diff(), priority);
}
}
while(++c != cend);
}
else
{
RestrictedNeighborhoodCirculator<DestIterator, Neighborhood>
c(idx, atBorder), cend(
c);
do
{
std::ptrdiff_t nlabel = ad(c);
if(nlabel == 0)
{
ad.set(label, idx, c.diff());
std::ptrdiff_t priority =
std::max((std::ptrdiff_t)stats[label].cost(as(is
x, c.diff())), cost);
pqueue.push(pos+c.diff(), priority);
}
}
while(++c != cend);
}
}
return maxRegionLabel;
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood>
inline typename DestAccessor::value_type
fastSeededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccessor a
s,
DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats,
SRGType srgType,
Neighborhood n)
{
return fastSeededRegionGrowing(srcul, srclr, as,
destul, ad,
stats, srgType, n, NumericTraits<double
>::max(), 256);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class RegionStatisticsArray>
inline typename DestAccessor::value_type
fastSeededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccessor a
s,
DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats,
SRGType srgType)
{
return fastSeededRegionGrowing(srcul, srclr, as,
destul, ad,
stats, srgType, FourNeighborCode());
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class RegionStatisticsArray>
inline typename DestAccessor::value_type
fastSeededRegionGrowing(SrcIterator srcul, SrcIterator srclr, SrcAccessor a
s,
DestIterator destul, DestAccessor ad,
RegionStatisticsArray & stats)
{
return fastSeededRegionGrowing(srcul, srclr, as,
destul, ad,
stats, CompleteGrow);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class RegionStatisticsArray, class Neighborhood>
inline typename DestAccessor::value_type
fastSeededRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
RegionStatisticsArray & stats,
SRGType srgType,
Neighborhood n,
double max_cost,
std::ptrdiff_t bucket_count = 256)
{
return fastSeededRegionGrowing(src.first, src.second, src.third,
dest.first, dest.second,
stats, srgType, n, max_cost, bucket_cou
nt);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* 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> \<<a href="seededregiongrowing_8hxx-source.html">vigra /seededregiongrowing.hxx</a>\><br> <b>\#include</b> \<vigra/seededregiongrowing.hxx\><br>
Namespace: vigra Namespace: vigra
<b> Required Interface:</b> <b> Required Interface:</b>
no requirements no requirements
*/ */
template <class Value> template <class Value>
class SeedRgDirectValueFunctor class SeedRgDirectValueFunctor
{ {
public: public:
 End of changes. 66 change blocks. 
107 lines changed or deleted 343 lines changed or added


 seededregiongrowing3d.hxx   seededregiongrowing3d.hxx 
skipping to change at line 166 skipping to change at line 166
freelist_.push(p); freelist_.push(p);
} }
std::stack<SeedRgVoxel<COST,Diff_type> *> freelist_; std::stack<SeedRgVoxel<COST,Diff_type> *> freelist_;
}; };
}; };
} // namespace detail } // namespace detail
/** \addtogroup SeededRegionGrowing /** \addtogroup SeededRegionGrowing
Region segmentation and voronoi tesselation
*/ */
//@{ //@{
/********************************************************/ /********************************************************/
/* */ /* */
/* seededRegionGrowing3D */ /* seededRegionGrowing3D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Three-dimensional Region Segmentation by means of Seeded Region Growing. /** \brief Three-dimensional Region Segmentation by means of Seeded Region Growing.
skipping to change at line 195 skipping to change at line 194
the existing regions so that a cost function is minimized. the existing regions so that a cost function is minimized.
Candidates are taken from the neighborhood of the already assigned pixe ls, Candidates are taken from the neighborhood of the already assigned pixe ls,
where the type of neighborhood is determined by parameter <tt>neighborh ood</tt> where the type of neighborhood is determined by parameter <tt>neighborh ood</tt>
which can take the values <tt>NeighborCode3DSix()</tt> (the default) which can take the values <tt>NeighborCode3DSix()</tt> (the default)
or <tt>NeighborCode3DTwentySix()</tt>. The algorithm basically works as follows or <tt>NeighborCode3DTwentySix()</tt>. The algorithm basically works as follows
(illustrated for 6-neighborhood, but 26-neighborhood works in the same way): (illustrated for 6-neighborhood, but 26-neighborhood works in the same way):
<ol> <ol>
<li> Find all candidate pixels that are 6-adjacent to a seed region. <li> Find all candidate pixels that are 6-adjacent to a seed region.
Calculate the cost for aggregating each candidate into its adajacent re gion Calculate the cost for aggregating each candidate into its adjacent reg ion
and put the candidates into a priority queue. and put the candidates into a priority queue.
<li> While( priority queue is not empty) <li> While( priority queue is not empty)
<ol> <ol>
<li> Take the candidate with least cost from the queue. If it has n ot <li> Take the candidate with least cost from the queue. If it has n ot
already been merged, merge it with it's adjacent region. already been merged, merge it with it's adjacent region.
<li> Put all candidates that are 4-adjacent to the pixel just proce ssed <li> Put all candidates that are 4-adjacent to the pixel just proce ssed
skipping to change at line 399 skipping to change at line 398
} }
} }
} }
// perform region growing // perform region growing
while(pheap.size() != 0) while(pheap.size() != 0)
{ {
Voxel * voxel = pheap.top(); Voxel * voxel = pheap.top();
pheap.pop(); pheap.pop();
if((srgType & StopAtThreshold) != 0 && voxel->cost_ > max_cost)
break;
Diff_type pos = voxel->location_; Diff_type pos = voxel->location_;
Diff_type nearest = voxel->nearest_; Diff_type nearest = voxel->nearest_;
int lab = voxel->label_; int lab = voxel->label_;
CostType cost = voxel->cost_;
allocator.dismiss(voxel); allocator.dismiss(voxel);
if((srgType & StopAtThreshold) != 0 && cost > max_cost)
break;
irx = ir + pos; irx = ir + pos;
isx = srcul + pos; isx = srcul + pos;
if(*irx) // already labelled region / watershed? if(*irx) // already labelled region / watershed?
continue; continue;
if((srgType & KeepContours) != 0) if((srgType & KeepContours) != 0)
{ {
for(int i=0; i<directionCount; i++) for(int i=0; i<directionCount; i++)
{ {
skipping to change at line 450 skipping to change at line 450
CostType cost = stats[lab].cost(as(isx, Neighborhood::d iff((Direction)i))); CostType cost = stats[lab].cost(as(isx, Neighborhood::d iff((Direction)i)));
Voxel * new_voxel = Voxel * new_voxel =
allocator.create(pos+Neighborhood::diff((Direction) i), nearest, cost, count++, lab); allocator.create(pos+Neighborhood::diff((Direction) i), nearest, cost, count++, lab);
pheap.push(new_voxel); pheap.push(new_voxel);
} }
} }
} }
} }
// free temporary memory
while(pheap.size() != 0)
{
allocator.dismiss(pheap.top());
pheap.pop();
}
// write result // write result
transformMultiArray(ir, Diff_type(w,h,d), AccessorTraits<int>::default_ accessor(), transformMultiArray(ir, Diff_type(w,h,d), AccessorTraits<int>::default_ accessor(),
destul, ad, detail::UnlabelWatersheds()); destul, ad, detail::UnlabelWatersheds());
} }
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 >
inline void inline void
 End of changes. 6 change blocks. 
5 lines changed or deleted 12 lines changed or added


 separableconvolution.hxx   separableconvolution.hxx 
skipping to change at line 61 skipping to change at line 61
/* internalConvolveLineWrap */ /* internalConvolveLineWrap */
/* */ /* */
/********************************************************/ /********************************************************/
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 internalConvolveLineWrap(SrcIterator is, SrcIterator iend, SrcAccessor sa, void internalConvolveLineWrap(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator kernel, KernelAccessor ka, KernelIterator kernel, KernelAccessor ka,
int kleft, int kright) int kleft, int kright,
int start = 0, int stop = 0)
{ {
// int w = iend - is;
int w = std::distance( is, iend ); int w = std::distance( is, iend );
typedef typename PromoteTraits< typedef typename PromoteTraits<
typename SrcAccessor::value_type, typename SrcAccessor::value_type,
typename KernelAccessor::value_type>::Promote SumType; typename KernelAccessor::value_type>::Promote SumType;
SrcIterator ibegin = is; SrcIterator ibegin = is;
for(int x=0; x<w; ++x, ++is, ++id) if(stop == 0)
stop = w;
is += start;
for(int x=start; x<stop; ++x, ++is, ++id)
{ {
KernelIterator ik = kernel + kright; KernelIterator ik = kernel + kright;
SumType sum = NumericTraits<SumType>::zero(); SumType sum = NumericTraits<SumType>::zero();
if(x < kright) if(x < kright)
{ {
int x0 = x - kright; int x0 = x - kright;
SrcIterator iss = iend + x0; SrcIterator iss = iend + x0;
for(; x0; ++x0, --ik, ++iss) for(; x0; ++x0, --ik, ++iss)
skipping to change at line 139 skipping to change at line 143
/* */ /* */
/********************************************************/ /********************************************************/
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,
class Norm> class Norm>
void internalConvolveLineClip(SrcIterator is, SrcIterator iend, SrcAccessor sa, void internalConvolveLineClip(SrcIterator is, SrcIterator iend, SrcAccessor sa,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator kernel, KernelAccessor ka, KernelIterator kernel, KernelAccessor ka,
int kleft, int kright, Norm norm) int kleft, int kright, Norm norm,
int start = 0, int stop = 0)
{ {
// int w = iend - is;
int w = std::distance( is, iend ); int w = std::distance( is, iend );
typedef typename PromoteTraits< typedef typename PromoteTraits<
typename SrcAccessor::value_type, typename SrcAccessor::value_type,
typename KernelAccessor::value_type>::Promote SumType; typename KernelAccessor::value_type>::Promote SumType;
SrcIterator ibegin = is; SrcIterator ibegin = is;
for(int x=0; x<w; ++x, ++is, ++id) if(stop == 0)
stop = w;
is += start;
for(int x=start; x<stop; ++x, ++is, ++id)
{ {
KernelIterator ik = kernel + kright; KernelIterator ik = kernel + kright;
SumType sum = NumericTraits<SumType>::zero(); SumType sum = NumericTraits<SumType>::zero();
if(x < kright) if(x < kright)
{ {
int x0 = x - kright; int x0 = x - kright;
Norm clipped = NumericTraits<Norm>::zero(); Norm clipped = NumericTraits<Norm>::zero();
for(; x0; ++x0, --ik) for(; x0; ++x0, --ik)
skipping to change at line 221 skipping to change at line 229
/* internalConvolveLineReflect */ /* internalConvolveLineReflect */
/* */ /* */
/********************************************************/ /********************************************************/
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 internalConvolveLineReflect(SrcIterator is, SrcIterator iend, SrcAcces sor sa, void internalConvolveLineReflect(SrcIterator is, SrcIterator iend, SrcAcces sor sa,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator kernel, KernelAccessor ka, KernelIterator kernel, KernelAccessor ka,
int kleft, int kright) int kleft, int kright,
int start = 0, int stop = 0)
{ {
// int w = iend - is;
int w = std::distance( is, iend ); int w = std::distance( is, iend );
typedef typename PromoteTraits< typedef typename PromoteTraits<
typename SrcAccessor::value_type, typename SrcAccessor::value_type,
typename KernelAccessor::value_type>::Promote SumType; typename KernelAccessor::value_type>::Promote SumType;
SrcIterator ibegin = is; SrcIterator ibegin = is;
for(int x=0; x<w; ++x, ++is, ++id) if(stop == 0)
stop = w;
is += start;
for(int x=start; x<stop; ++x, ++is, ++id)
{ {
KernelIterator ik = kernel + kright; KernelIterator ik = kernel + kright;
SumType sum = NumericTraits<SumType>::zero(); SumType sum = NumericTraits<SumType>::zero();
if(x < kright) if(x < kright)
{ {
int x0 = x - kright; int x0 = x - kright;
SrcIterator iss = ibegin - x0; SrcIterator iss = ibegin - x0;
for(; x0; ++x0, --ik, --iss) for(; x0; ++x0, --ik, --iss)
skipping to change at line 297 skipping to change at line 309
/* internalConvolveLineRepeat */ /* internalConvolveLineRepeat */
/* */ /* */
/********************************************************/ /********************************************************/
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 internalConvolveLineRepeat(SrcIterator is, SrcIterator iend, SrcAccess or sa, void internalConvolveLineRepeat(SrcIterator is, SrcIterator iend, SrcAccess or sa,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator kernel, KernelAccessor ka, KernelIterator kernel, KernelAccessor ka,
int kleft, int kright) int kleft, int kright,
int start = 0, int stop = 0)
{ {
// int w = iend - is;
int w = std::distance( is, iend ); int w = std::distance( is, iend );
typedef typename PromoteTraits< typedef typename PromoteTraits<
typename SrcAccessor::value_type, typename SrcAccessor::value_type,
typename KernelAccessor::value_type>::Promote SumType; typename KernelAccessor::value_type>::Promote SumType;
SrcIterator ibegin = is; SrcIterator ibegin = is;
for(int x=0; x<w; ++x, ++is, ++id) if(stop == 0)
stop = w;
is += start;
for(int x=start; x<stop; ++x, ++is, ++id)
{ {
KernelIterator ik = kernel + kright; KernelIterator ik = kernel + kright;
SumType sum = NumericTraits<SumType>::zero(); SumType sum = NumericTraits<SumType>::zero();
if(x < kright) if(x < kright)
{ {
int x0 = x - kright; int x0 = x - kright;
SrcIterator iss = ibegin; SrcIterator iss = ibegin;
for(; x0; ++x0, --ik) for(; x0; ++x0, --ik)
skipping to change at line 373 skipping to change at line 389
/* internalConvolveLineAvoid */ /* internalConvolveLineAvoid */
/* */ /* */
/********************************************************/ /********************************************************/
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 internalConvolveLineAvoid(SrcIterator is, SrcIterator iend, SrcAccesso r sa, void internalConvolveLineAvoid(SrcIterator is, SrcIterator iend, SrcAccesso r sa,
DestIterator id, DestAccessor da, DestIterator id, DestAccessor da,
KernelIterator kernel, KernelAccessor ka, KernelIterator kernel, KernelAccessor ka,
int kleft, int kright) int kleft, int kright,
int start = 0, int stop = 0)
{ {
// int w = iend - is;
int w = std::distance( is, iend ); int w = std::distance( is, iend );
if(start < stop) // we got a valid subrange
{
if(w + kleft < stop)
stop = w + kleft;
if(start < kright)
{
id += kright - start;
start = kright;
}
}
else
{
id += kright;
start = kright;
stop = w + kleft;
}
typedef typename PromoteTraits< typedef typename PromoteTraits<
typename SrcAccessor::value_type, typename SrcAccessor::value_type,
typename KernelAccessor::value_type>::Promote SumType; typename KernelAccessor::value_type>::Promote SumType;
is += kright; is += start;
id += kright;
for(int x=kright; x<w+kleft; ++x, ++is, ++id) for(int x=start; x<stop; ++x, ++is, ++id)
{ {
KernelIterator ik = kernel + kright; KernelIterator ik = kernel + kright;
SumType sum = NumericTraits<SumType>::zero(); SumType sum = NumericTraits<SumType>::zero();
SrcIterator iss = is + (-kright); SrcIterator iss = is + (-kright);
SrcIterator isend = is + (1 - kleft); SrcIterator isend = is + (1 - kleft);
for(; iss != isend ; --ik, ++iss) for(; iss != isend ; --ik, ++iss)
{ {
sum += ka(ik) * sa(iss); sum += ka(ik) * sa(iss);
} }
skipping to change at line 437 skipping to change at line 468
applied. applied.
The signal's value_type (SrcAccessor::value_type) must be a The signal's value_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.
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>
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 (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
(the default), the entire array is convolved.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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 )
} }
\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)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="separableconvolution_8hxx-source.html">vigr a/separableconvolution.hxx</a>\> <b>\#include</b> \<vigra/separableconvolution.hxx\>
\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 539 skipping to change at line 580
*/ */
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)
{ {
typedef typename KernelAccessor::value_type KernelValue; 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 >= kright - kleft + 1, vigra_precondition(w >= std::max(kright, -kleft) + 1,
"convolveLine(): kernel longer than line\n"); "convolveLine(): kernel longer than line.\n");
if(stop != 0)
vigra_precondition(0 <= start && start < stop && stop <= w,
"convolveLine(): invalid subrange (start, stop).\n"
);
switch(border) switch(border)
{ {
case BORDER_TREATMENT_WRAP: case BORDER_TREATMENT_WRAP:
{ {
internalConvolveLineWrap(is, iend, sa, id, da, ik, ka, kleft, krigh t); internalConvolveLineWrap(is, iend, sa, id, da, ik, ka, kleft, krigh t, start, stop);
break; break;
} }
case BORDER_TREATMENT_AVOID: case BORDER_TREATMENT_AVOID:
{ {
internalConvolveLineAvoid(is, iend, sa, id, da, ik, ka, kleft, krig ht); internalConvolveLineAvoid(is, iend, sa, id, da, ik, ka, kleft, krig ht, start, stop);
break; break;
} }
case BORDER_TREATMENT_REFLECT: case BORDER_TREATMENT_REFLECT:
{ {
internalConvolveLineReflect(is, iend, sa, id, da, ik, ka, kleft, kr ight); internalConvolveLineReflect(is, iend, sa, id, da, ik, ka, kleft, kr ight, start, stop);
break; break;
} }
case BORDER_TREATMENT_REPEAT: case BORDER_TREATMENT_REPEAT:
{ {
internalConvolveLineRepeat(is, iend, sa, id, da, ik, ka, kleft, kri ght); internalConvolveLineRepeat(is, iend, sa, id, da, ik, ka, kleft, kri ght, start, stop);
break; break;
} }
case BORDER_TREATMENT_CLIP: case BORDER_TREATMENT_CLIP:
{ {
// find norm of kernel // find norm of kernel
typedef typename KernelAccessor::value_type KT; typedef typename KernelAccessor::value_type KT;
KT norm = NumericTraits<KT>::zero(); KT norm = NumericTraits<KT>::zero();
KernelIterator iik = ik + kleft; KernelIterator iik = ik + kleft;
for(int i=kleft; i<=kright; ++i, ++iik) norm += ka(iik); for(int i=kleft; i<=kright; ++i, ++iik)
norm += ka(iik);
vigra_precondition(norm != NumericTraits<KT>::zero(), vigra_precondition(norm != NumericTraits<KT>::zero(),
"convolveLine(): Norm of kernel must be != 0" "convolveLine(): Norm of kernel must be != 0"
" in mode BORDER_TREATMENT_CLIP.\n"); " in mode BORDER_TREATMENT_CLIP.\n");
internalConvolveLineClip(is, iend, sa, id, da, ik, ka, kleft, krigh t, norm); internalConvolveLineClip(is, iend, sa, id, da, ik, ka, kleft, krigh t, norm, start, stop);
break; break;
} }
default: default:
{ {
vigra_precondition(0, vigra_precondition(0,
"convolveLine(): Unknown border treatment mode.\n"); "convolveLine(): Unknown border treatment mode.\n");
} }
} }
} }
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 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)
{ {
convolveLine(src.first, src.second, src.third, convolveLine(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, start, stop);
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* separableConvolveX */ /* separableConvolveX */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Performs a 1 dimensional convolution in x direction. /** \brief Performs a 1 dimensional convolution in x direction.
skipping to change at line 656 skipping to change at line 704
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="separableconvolution_8hxx-source.html">vigr a/separableconvolution.hxx</a>\> <b>\#include</b> \<vigra/separableconvolution.hxx\>
\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);
vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d (kernel)); vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d (kernel));
skipping to change at line 692 skipping to change at line 740
typedef typename KernelAccessor::value_type KernelValue; 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 >= kright - kleft + 1, vigra_precondition(w >= std::max(kright, -kleft) + 1,
"separableConvolveX(): kernel longer than line\n"); "separableConvolveX(): kernel longer than line\n");
int y; int y;
for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y) for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
{ {
typename SrcIterator::row_iterator rs = supperleft.rowIterator(); typename SrcIterator::row_iterator rs = supperleft.rowIterator();
typename DestIterator::row_iterator rd = dupperleft.rowIterator(); typename DestIterator::row_iterator rd = dupperleft.rowIterator();
convolveLine(rs, rs+w, sa, rd, da, convolveLine(rs, rs+w, sa, rd, da,
skipping to change at line 764 skipping to change at line 812
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="separableconvolution_8hxx-source.html">vigr a/separableconvolution.hxx</a>\> <b>\#include</b> \<vigra/separableconvolution.hxx\>
\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::separableConvolveY(srcImageRange(src), destImage(dest), kernel1d (kernel)); vigra::separableConvolveY(srcImageRange(src), destImage(dest), kernel1d (kernel));
skipping to change at line 800 skipping to change at line 848
typedef typename KernelAccessor::value_type KernelValue; 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 >= kright - kleft + 1, vigra_precondition(h >= std::max(kright, -kleft) + 1,
"separableConvolveY(): kernel longer than line\n"); "separableConvolveY(): kernel longer than line\n");
int x; int x;
for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x) for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
{ {
typename SrcIterator::column_iterator cs = supperleft.columnIterato r(); typename SrcIterator::column_iterator cs = supperleft.columnIterato r();
typename DestIterator::column_iterator cd = dupperleft.columnIterat or(); typename DestIterator::column_iterator cd = dupperleft.columnIterat or();
convolveLine(cs, cs+h, sa, cd, da, convolveLine(cs, cs+h, sa, cd, da,
skipping to change at line 843 skipping to change at line 891
/* */ /* */
/* Kernel1D */ /* Kernel1D */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Generic 1 dimensional convolution kernel. /** \brief Generic 1 dimensional convolution kernel.
This kernel may be used for convolution of 1 dimensional signals or for This kernel may be used for convolution of 1 dimensional signals or for
separable convolution of multidimensional signals. separable convolution of multidimensional signals.
Convlution functions access the kernel via a 1 dimensional random acces s 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 The kernel defines a factory function kernel1d() to create an argument object
(see \ref KernelArgumentObjectFactories). (see \ref KernelArgumentObjectFactories).
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="stdconvolution_8hxx-source.html">vigra/stdc onvolution.hxx</a>\> <b>\#include</b> \<vigra/stdconvolution.hxx\>
\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));
skipping to change at line 1047 skipping to change at line 1095
~Kernel1D() ~Kernel1D()
{} {}
/** /**
Init as a sampled Gaussian function. The radius of the kernel i s Init as a sampled Gaussian function. The radius of the kernel i s
always 3*std_dev. '<tt>norm</tt>' denotes the sum of all bins o f the kernel always 3*std_dev. '<tt>norm</tt>' denotes the sum of all bins o f the kernel
(i.e. the kernel is corrected for the normalization error intro duced (i.e. the kernel is corrected for the normalization error intro duced
by windowing the Gaussian to a finite interval). However, by windowing the Gaussian to a finite interval). However,
if <tt>norm</tt> is 0.0, the kernel is normalized to 1 by the a nalytic if <tt>norm</tt> is 0.0, the kernel is normalized to 1 by the a nalytic
expression for the Gaussian, and <b>no</b> correction for the w indowing expression for the Gaussian, and <b>no</b> correction for the w indowing
error is performed. error is performed. If <tt>windowRatio = 0.0</tt>, the radius o
f the filter
window is <tt>radius = round(3.0 * std_dev)</tt>, otherwise it
is
<tt>radius = round(windowRatio * std_dev)</tt> (where <tt>windo
wRatio > 0.0</tt>
is required).
Precondition: Precondition:
\code \code
std_dev >= 0.0 std_dev >= 0.0
\endcode \endcode
Postconditions: Postconditions:
\code \code
1. left() == -(int)(3.0*std_dev + 0.5) 1. left() == -(int)(3.0*std_dev + 0.5)
2. right() == (int)(3.0*std_dev + 0.5) 2. right() == (int)(3.0*std_dev + 0.5)
3. borderTreatment() == BORDER_TREATMENT_REFLECT 3. borderTreatment() == BORDER_TREATMENT_REFLECT
4. norm() == norm 4. norm() == norm
\endcode \endcode
*/ */
void initGaussian(double std_dev, value_type norm); void initGaussian(double std_dev, value_type norm, double windowRatio = 0.0);
/** Init as a Gaussian function with norm 1. /** Init as a Gaussian function with norm 1.
*/ */
void initGaussian(double std_dev) void initGaussian(double std_dev)
{ {
initGaussian(std_dev, one()); initGaussian(std_dev, one());
} }
/** /**
Init as Lindeberg's discrete analog of the Gaussian function. T he radius of the kernel is Init as Lindeberg's discrete analog of the Gaussian function. T he radius of the kernel is
skipping to change at line 1112 skipping to change at line 1163
following condition is fulfilled: following condition is fulfilled:
\f[ \sum_{i=left()}^{right()} \f[ \sum_{i=left()}^{right()}
\frac{(-i)^{order}kernel[i]}{order!} = norm \frac{(-i)^{order}kernel[i]}{order!} = norm
\f] \f]
Thus, the kernel will be corrected for the error introduced Thus, the kernel will be corrected for the error introduced
by windowing the Gaussian to a finite interval. However, by windowing the Gaussian to a finite interval. However,
if <tt>norm</tt> is 0.0, the kernel is normalized to 1 by the a nalytic if <tt>norm</tt> is 0.0, the kernel is normalized to 1 by the a nalytic
expression for the Gaussian derivative, and <b>no</b> correctio n for the expression for the Gaussian derivative, and <b>no</b> correctio n for the
windowing error is performed. windowing error is performed. If <tt>windowRatio = 0.0</tt>, th
e radius
of the filter window is <tt>radius = round(3.0 * std_dev + 0.5
* order)</tt>,
otherwise it is <tt>radius = round(windowRatio * std_dev)</tt>
(where
<tt>windowRatio > 0.0</tt> is required).
Preconditions: Preconditions:
\code \code
1. std_dev >= 0.0 1. std_dev >= 0.0
2. order >= 1 2. order >= 1
\endcode \endcode
Postconditions: Postconditions:
\code \code
1. left() == -(int)(3.0*std_dev + 0.5*order + 0.5) 1. left() == -(int)(3.0*std_dev + 0.5*order + 0.5)
2. right() == (int)(3.0*std_dev + 0.5*order + 0.5) 2. right() == (int)(3.0*std_dev + 0.5*order + 0.5)
3. borderTreatment() == BORDER_TREATMENT_REFLECT 3. borderTreatment() == BORDER_TREATMENT_REFLECT
4. norm() == norm 4. norm() == norm
\endcode \endcode
*/ */
void initGaussianDerivative(double std_dev, int order, value_type norm) ; void initGaussianDerivative(double std_dev, int order, value_type norm, double windowRatio = 0.0);
/** Init as a Gaussian derivative with norm 1. /** Init as a Gaussian derivative with norm 1.
*/ */
void initGaussianDerivative(double std_dev, int order) void initGaussianDerivative(double std_dev, int order)
{ {
initGaussianDerivative(std_dev, order, one()); initGaussianDerivative(std_dev, order, one());
} }
/** /**
Init an optimal 3-tap smoothing filter. Init an optimal 3-tap smoothing filter.
skipping to change at line 1539 skipping to change at line 1593
A comma-separated initializer list is given after the assignmen t A comma-separated initializer list is given after the assignmen t
operator. This function is used like this: operator. This function is used like this:
\code \code
// define horizontal Roberts filter // define horizontal Roberts filter
vigra::Kernel1D<float> roberts_gradient_x; vigra::Kernel1D<float> roberts_gradient_x;
roberts_gradient_x.initExplicitly(0, 1) = 1.0, -1.0; roberts_gradient_x.initExplicitly(0, 1) = 1.0, -1.0;
\endcode \endcode
The norm is set to the sum of the initialzer values. If the wro ng 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::Kernel1D<float> average5x1; vigra::Kernel1D<float> average5x1;
average5x1.initExplicitly(-2, 2) = 1.0/5.0; average5x1.initExplicitly(-2, 2) = 1.0/5.0;
\endcode \endcode
Here, the norm is set to value*size(). Here, the norm is set to value*size().
skipping to change at line 1714 skipping to change at line 1768
*k = *k * sum; *k = *k * sum;
} }
norm_ = norm; norm_ = norm;
} }
/***********************************************************************/ /***********************************************************************/
template <class ARITHTYPE> template <class ARITHTYPE>
void Kernel1D<ARITHTYPE>::initGaussian(double std_dev, void Kernel1D<ARITHTYPE>::initGaussian(double std_dev,
value_type norm) 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,
"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);
// first calculate required kernel sizes // first calculate required kernel sizes
int radius = (int)(3.0 * std_dev + 0.5); int radius;
if (windowRatio == 0.0)
radius = (int)(3.0 * std_dev + 0.5);
else
radius = (int)(windowRatio * std_dev + 0.5);
if(radius == 0) if(radius == 0)
radius = 1; radius = 1;
// allocate the kernel // allocate the kernel
kernel_.erase(kernel_.begin(), kernel_.end()); kernel_.erase(kernel_.begin(), kernel_.end());
kernel_.reserve(radius*2+1); kernel_.reserve(radius*2+1);
for(ARITHTYPE x = -(ARITHTYPE)radius; x <= (ARITHTYPE)radius; ++x) for(ARITHTYPE x = -(ARITHTYPE)radius; x <= (ARITHTYPE)radius; ++x)
{ {
kernel_.push_back(gauss(x)); kernel_.push_back(gauss(x));
skipping to change at line 1831 skipping to change at line 1892
// 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 void
Kernel1D<ARITHTYPE>::initGaussianDerivative(double std_dev, Kernel1D<ARITHTYPE>::initGaussianDerivative(double std_dev,
int order, int order,
value_type norm) value_type norm,
double windowRatio)
{ {
vigra_precondition(order >= 0, vigra_precondition(order >= 0,
"Kernel1D::initGaussianDerivative(): Order must be >= 0."); "Kernel1D::initGaussianDerivative(): Order must be >= 0.");
if(order == 0) if(order == 0)
{ {
initGaussian(std_dev, norm); initGaussian(std_dev, norm, windowRatio);
return; return;
} }
vigra_precondition(std_dev > 0.0, vigra_precondition(std_dev > 0.0,
"Kernel1D::initGaussianDerivative(): " "Kernel1D::initGaussianDerivative(): "
"Standard deviation must be > 0."); "Standard deviation must be > 0.");
vigra_precondition(windowRatio >= 0.0,
"Kernel1D::initGaussianDerivative(): windowRatio must be >= 0
.");
Gaussian<ARITHTYPE> gauss((ARITHTYPE)std_dev, order); Gaussian<ARITHTYPE> gauss((ARITHTYPE)std_dev, order);
// first calculate required kernel sizes // first calculate required kernel sizes
int radius = (int)(3.0 * std_dev + 0.5 * order + 0.5); int radius;
if(windowRatio == 0.0)
radius = (int)(3.0 * std_dev + 0.5 * order + 0.5);
else
radius = (int)(windowRatio * std_dev + 0.5);
if(radius == 0) if(radius == 0)
radius = 1; radius = 1;
// allocate the kernels // allocate the kernels
kernel_.clear(); kernel_.clear();
kernel_.reserve(radius*2+1); kernel_.reserve(radius*2+1);
// fill the kernel and calculate the DC component // fill the kernel and calculate the DC component
// introduced by truncation of the Gaussian // introduced by truncation of the Gaussian
ARITHTYPE dc = 0.0; ARITHTYPE dc = 0.0;
 End of changes. 49 change blocks. 
49 lines changed or deleted 126 lines changed or added


 singular_value_decomposition.hxx   singular_value_decomposition.hxx 
skipping to change at line 64 skipping to change at line 64
To save memory, this functions stores the matrix \a S in a column vector of To save memory, this functions stores the matrix \a S in a column vector of
appropriate length (a diagonal matrix can be obtained by <tt>diagonalMat rix(S)</tt>). appropriate length (a diagonal matrix can be obtained by <tt>diagonalMat rix(S)</tt>).
The singular values, sigma[k] = S(k, 0), are ordered so that The singular values, sigma[k] = S(k, 0), are ordered so that
sigma[0] >= sigma[1] >= ... >= sigma[n-1]. sigma[0] >= sigma[1] >= ... >= sigma[n-1].
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/ja by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama)
ma). .
<b>\#include</b> \<<a href="singular__value__decomposition_8hxx-source. <b>\#include</b> \<vigra/singular_value_decomposition.hxx\> or<br>
html">vigra/singular_value_decomposition.hxx</a>\> or<br> <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
<b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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; typedef MultiArrayShape<2>::type Shape;
 End of changes. 2 change blocks. 
7 lines changed or deleted 5 lines changed or added


 slanted_edge_mtf.hxx   slanted_edge_mtf.hxx 
skipping to change at line 76 skipping to change at line 76
/** \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> \<<a href="slanted__edge__mtf_8hxx-source.html">vi gra/slanted_edge_mtf.hxx</a>\><br> <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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,
vigra::SlantedEdgeMTFOptions().mtfSmoothingScale( 1.0)); vigra::SlantedEdgeMTFOptions().mtfSmoothingScale( 1.0));
skipping to change at line 145 skipping to change at line 145
Default: 5 Default: 5
*/ */
SlantedEdgeMTFOptions & minimumEdgeWidth(unsigned int n) SlantedEdgeMTFOptions & minimumEdgeWidth(unsigned int n)
{ {
minimum_edge_width = n; minimum_edge_width = n;
return *this; return *this;
} }
/** Amount of smoothing of the computed MTF. /** Amount of smoothing of the computed MTF.
If the datais noisy, so will be the MTF. Thus, some smoothing i s useful.<br> If the data is noisy, so will be the MTF. Thus, some smoothing is useful.<br>
Default: 2.0 Default: 2.0
*/ */
SlantedEdgeMTFOptions & mtfSmoothingScale(double scale) SlantedEdgeMTFOptions & mtfSmoothingScale(double scale)
{ {
vigra_precondition(scale >= 0.0, vigra_precondition(scale >= 0.0,
"SlantedEdgeMTFOptions: MTF smoothing scale must not be < 0."); "SlantedEdgeMTFOptions: MTF smoothing scale must not be < 0.");
mtf_smoothing_scale = scale; mtf_smoothing_scale = scale;
return *this; return *this;
} }
skipping to change at line 233 skipping to change at line 233
// angle is now between pi/4 and 3*pi/4 // angle is now between pi/4 and 3*pi/4
double slope = VIGRA_CSTD::tan(M_PI/2.0 - angle); double slope = VIGRA_CSTD::tan(M_PI/2.0 - angle);
vigra_precondition(slope != 0.0, vigra_precondition(slope != 0.0,
"slantedEdgeMTF(): Input edge is not slanted"); "slantedEdgeMTF(): Input edge is not slanted");
// trim image so that the edge only intersects the top and bottom borde r // trim image so that the edge only intersects the top and bottom borde r
unsigned int minimumNumberOfLines = options.minimum_number_of_lines, // 20, unsigned int minimumNumberOfLines = options.minimum_number_of_lines, // 20,
edgeWidth = options.desired_edge_width, // 10 edgeWidth = options.desired_edge_width, // 10
minimumEdgeWidth = options.minimum_edge_width; // 5 minimumEdgeWidth = options.minimum_edge_width; // 5
int y0, y1; int y0 = 0, y1 = h;
for(; edgeWidth >= minimumEdgeWidth; --edgeWidth) for(; edgeWidth >= minimumEdgeWidth; --edgeWidth)
{ {
y0 = int(VIGRA_CSTD::floor((edgeWidth - xc) / slope + yc + 0.5)); y0 = int(VIGRA_CSTD::floor((edgeWidth - xc) / slope + yc + 0.5));
y1 = int(VIGRA_CSTD::floor((w - edgeWidth - 1 - xc) / slope + yc + 0.5)); y1 = int(VIGRA_CSTD::floor((w - edgeWidth - 1 - xc) / slope + yc + 0.5));
if(slope < 0.0) if(slope < 0.0)
std::swap(y0, y1); std::swap(y0, y1);
if(y1 - y0 >= (int)minimumNumberOfLines) if(y1 - y0 >= (int)minimumNumberOfLines)
break; break;
} }
skipping to change at line 503 skipping to change at line 503
/** \brief Determine the magnitude transfer function of the camera. /** \brief Determine the magnitude transfer function of the camera.
This operator estimates the magnitude transfer function (MTF) of a came ra by means of the This operator estimates the magnitude transfer function (MTF) of a came ra by means of the
slanted edge method described in: slanted edge method described in:
ISO Standard No. 12233: <i>"Photography - Electronic still picture came ras - Resolution measurements"</i>, 2000 ISO Standard No. 12233: <i>"Photography - Electronic still picture came ras - Resolution measurements"</i>, 2000
The input must be an image that contains a single step edge with bright pixels on one side and dark pixels on The input must be an image that contains a single step edge with bright pixels on one side and dark pixels on
the other. However, the intensity values must be neither saturated nor zero. The algorithms computes the MTF the other. However, the intensity values must be neither saturated nor zero. The algorithms computes the MTF
from the Fourier transform of the edge's derivative. Thus, if the actua l MTF is unisotropic, the estimated from the Fourier transform of the edge's derivative. Thus, if the actua l MTF is anisotropic, the estimated
MTF does actually only apply in the direction perpendicular to the edge - several edges at different MTF does actually only apply in the direction perpendicular to the edge - several edges at different
orientations are required to estimate an unisotropic MTF. orientations are required to estimate an anisotropic MTF.
The algorithm returns a sequence of frequency / attenuation pairs. The frequency axis is normalized so that the The algorithm returns a sequence of frequency / attenuation pairs. The frequency axis is normalized so that the
Nyquist frequency of the original image is 0.5. Since the edge's deriva tive is computed with subpixel accuracy, Nyquist frequency of the original image is 0.5. Since the edge's deriva tive is computed with subpixel accuracy,
the attenuation can usually be computed for frequencies significantly a bove the Nyquist frequency as well. The the attenuation can usually be computed for frequencies significantly a bove the Nyquist frequency as well. The
MTF estimate ends at either the first zero crossing of the MTF or at fr equency 1, whichever comes earlier. MTF estimate ends at either the first zero crossing of the MTF or at fr equency 1, whichever comes earlier.
The present implementation improves the original slanted edge algorithm according to ISO 12233 in a number of The present implementation improves the original slanted edge algorithm according to ISO 12233 in a number of
ways: ways:
<ul> <ul>
<li> The edge is not required to run nearly vertically or horizontally (i.e. with a slant of approximately 5 degrees). <li> The edge is not required to run nearly vertically or horizontally (i.e. with a slant of approximately 5 degrees).
The algorithm will automatically compute the edge's actual angle a nd adjust estimates accordingly. The algorithm will automatically compute the edge's actual angle a nd adjust estimates accordingly.
However, it is still necessary for the edge to be somewhat slanted , because subpixel-accurate estimation However, it is still necessary for the edge to be somewhat slanted , because subpixel-accurate estimation
of the derivative is impossible otherwise (i.e. the edge position perpendicular to the edge direction must of the derivative is impossible otherwise (i.e. the edge position perpendicular to the edge direction must
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 algrit hm. 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 ar type which is convertible to <tt>double</tt>. The source value type (<TT>SrcAccessor::value_type</TT>) must be a scal ar type which is convertible 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. 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
skipping to change at line 559 skipping to change at line 559
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="slanted__edge__mtf_8hxx-source.html">vi gra/slanted_edge_mtf.hxx</a>\><br> <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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
skipping to change at line 629 skipping to change at line 629
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* mtfFitGaussian */ /* mtfFitGaussian */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Fit a Gaussian function to a given MTF. /** \brief Fit a Gaussian function to a given MTF.
This function expects a squence of frequency / attenuation pairs as pro duced 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
of the PSF of many real cameras). It returns the standard deviation (sc ale) of this function. The algorithm of the PSF of many real cameras). It returns the standard deviation (sc ale) of this function. The algorithm
computes the standard deviation by means of a linear least square on th e logarithm of the MTF, i.e. computes the standard deviation by means of a linear least square on th e logarithm of the MTF, i.e.
an algebraic fit rather than a Euclidean fit - thus, the resulting Gaus sian may not be the one that an algebraic fit rather than a Euclidean fit - thus, the resulting Gaus sian may not be the one that
intuitively fits the data optimally. intuitively fits the data optimally.
<b> Declaration:</b> <b> Declaration:</b>
\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> \<<a href="slanted__edge__mtf_8hxx-source.html">vi gra/slanted_edge_mtf.hxx</a>\><br> <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
double scale = vigra::mtfFitGaussian(mtf) double scale = vigra::mtfFitGaussian(mtf)
 End of changes. 9 change blocks. 
9 lines changed or deleted 9 lines changed or added


 splineimageview.hxx   splineimageview.hxx 
skipping to change at line 76 skipping to change at line 76
The <tt>SplineImageView</tt> template is explicitly specialized to make it as efficient as possible. The <tt>SplineImageView</tt> template is explicitly specialized to make it as efficient as possible.
In particular, unnecessary copying of the image is avoided when the ite rators passed In particular, unnecessary copying of the image is avoided when the ite rators passed
in the constructor originate from a \ref vigra::BasicImage. In addition , these specializations in the constructor originate from a \ref vigra::BasicImage. In addition , these specializations
provide function <tt>unchecked(...)</tt> that do not perform bounds che cking. If the original image provide function <tt>unchecked(...)</tt> that do not perform bounds che cking. If the original image
is not a variant of \ref vigra::BasicImage, one can customize the inter nal representation by is not a variant of \ref vigra::BasicImage, one can customize the inter nal representation by
using \ref vigra::SplineImageView0 or \ref vigra::SplineImageView1. using \ref vigra::SplineImageView0 or \ref vigra::SplineImageView1.
<b>Usage:</b> <b>Usage:</b>
<b>\#include</b> \<<a href="splineimageview_8hxx-source.html">vigra/spl ineimageview.hxx</a>\><br> <b>\#include</b> \<vigra/splineimageview.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
BImage img(w,h); BImage img(w,h);
... // fill img ... // fill img
// construct spline view for quadratic interpolation // construct spline view for quadratic interpolation
SplineImageView<2, double> spi2(srcImageRange(img)); SplineImageView<2, double> spi2(srcImageRange(img));
double x = ..., y = ...; double x = ..., y = ...;
skipping to change at line 468 skipping to change at line 468
/** Check if x and y are in the original image range. /** Check if x and y are in the original image range.
Equivalent to <tt>0 <= x <= width()-1</tt> and <tt>0 <= y <= he ight()-1</tt>. Equivalent to <tt>0 <= x <= width()-1</tt> and <tt>0 <= y <= he ight()-1</tt>.
*/ */
bool isInside(double x, double y) const bool isInside(double x, double y) const
{ {
return isInsideX(x) && isInsideY(y); return isInsideX(x) && isInsideY(y);
} }
/** Check if x and y are in the valid range. Points outside the ori ginal image range are computed /** Check if x and y are in the valid range. Points outside the ori ginal image range are computed
by reflcective boundary conditions, but only within the first r eflection. by reflective boundary conditions, but only within the first re flection.
Equivalent to <tt>-width() + ORDER/2 + 2 < x < 2*width() - ORDE R/2 - 2</tt> and Equivalent to <tt>-width() + ORDER/2 + 2 < x < 2*width() - ORDE R/2 - 2</tt> and
<tt>-height() + ORDER/2 + 2 < y < 2*height() - ORDER/2 - 2</tt> . <tt>-height() + ORDER/2 + 2 < y < 2*height() - ORDER/2 - 2</tt> .
*/ */
bool isValid(double x, double y) const bool isValid(double x, double y) const
{ {
return x < w1_ + x1_ && x > -x1_ && y < h1_ + y1_ && y > -y1_; return x < w1_ + x1_ && x > -x1_ && y < h1_ + y1_ && y > -y1_;
} }
/** Check whether the points <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt > are in /** Check whether the points <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt > are in
the same spline facet. For odd order splines, facets span the r ange the same spline facet. For odd order splines, facets span the r ange
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 splines.hxx   splines.hxx 
skipping to change at line 53 skipping to change at line 53
#include "array_vector.hxx" #include "array_vector.hxx"
#include "fixedpoint.hxx" #include "fixedpoint.hxx"
namespace vigra { namespace vigra {
/** \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> \<<a href="splines_8hxx-source.html">vigra/splines.hxx </a>\><br> <b>\#include</b> \<vigra/splines.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
/** Basic interface of the spline functors. /** Basic interface of the spline functors.
Implements the spline functions defined by the recursion Implements the spline functions defined by the recursion
\f[ B_0(x) = \left\{ \begin{array}{ll} \f[ B_0(x) = \left\{ \begin{array}{ll}
1 & -\frac{1}{2} \leq x < \frac{1}{2} \\ 1 & -\frac{1}{2} \leq x < \frac{1}{2} \\
skipping to change at line 79 skipping to change at line 79
\f[ B_n(x) = B_0(x) * B_{n-1}(x) \f[ B_n(x) = B_0(x) * B_{n-1}(x)
\f] \f]
where * denotes convolution, and <i>n</i> is the spline order given by the where * denotes convolution, and <i>n</i> is the spline order given by the
template parameter <tt>ORDER</tt>. These spline classes can be used as template parameter <tt>ORDER</tt>. These spline classes can be used as
unary and binary functors, as kernels for \ref resamplingConvolveImage( ), unary and binary functors, as kernels for \ref resamplingConvolveImage( ),
and as arguments for \ref vigra::SplineImageView. Note that the spline order and as arguments for \ref vigra::SplineImageView. Note that the spline order
is given as a template argument. is given as a template argument.
<b>\#include</b> \<<a href="splines_8hxx-source.html">vigra/splines.hxx </a>\><br> <b>\#include</b> \<vigra/splines.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <int ORDER, class T = double> template <int ORDER, class T = double>
class BSplineBase class BSplineBase
{ {
public: public:
/** the value type if used as a kernel in \ref resamplingConvolveIm age(). /** the value type if used as a kernel in \ref resamplingConvolveIm age().
*/ */
typedef T value_type; typedef T value_type;
skipping to change at line 106 skipping to change at line 106
/** the functor's second binary argument type /** the functor's second binary argument type
*/ */
typedef unsigned int second_argument_type; typedef unsigned int second_argument_type;
/** the functor's result type (unary and binary) /** the functor's result type (unary and binary)
*/ */
typedef T result_type; typedef T result_type;
/** the spline order /** the spline order
*/ */
enum StaticOrder { order = ORDER }; enum StaticOrder { order = ORDER };
/** Create functor for gevine derivative of the spline. The spline' s order /** Create functor for given derivative of the spline. The spline's order
is specified spline by the template argument <TT>ORDER</tt>. is specified spline by the template argument <TT>ORDER</tt>.
*/ */
explicit BSplineBase(unsigned int derivativeOrder = 0) explicit BSplineBase(unsigned int derivativeOrder = 0)
: s1_(derivativeOrder) : s1_(derivativeOrder)
{} {}
/** Unary function call. /** Unary function call.
Returns the value of the spline with the derivative order given in the Returns the value of the spline with the derivative order given in the
constructor. Note that only derivatives up to <tt>ORDER-1</tt> are constructor. Note that only derivatives up to <tt>ORDER-1</tt> are
continous, and derivatives above <tt>ORDER+1</tt> are zero. continuous, and derivatives above <tt>ORDER+1</tt> are zero.
*/ */
result_type operator()(argument_type x) const result_type operator()(argument_type x) const
{ {
return exec(x, derivativeOrder()); return exec(x, derivativeOrder());
} }
/** Binary function call. /** Binary function call.
The given derivative order is added to the derivative order The given derivative order is added to the derivative order
specified in the constructor. Note that only derivatives up to <tt>ORDER-1</tt> are specified in the constructor. Note that only derivatives up to <tt>ORDER-1</tt> are
continous, and derivatives above <tt>ORDER+1</tt> are zero. continuous, and derivatives above <tt>ORDER+1</tt> are zero.
*/ */
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);
} }
/** Index operator. Same as unary function call. /** Index operator. Same as unary function call.
*/ */
value_type operator[](value_type x) const value_type operator[](value_type x) const
{ return operator()(x); } { return operator()(x); }
skipping to change at line 1156 skipping to change at line 1156
0 & \mbox{otherwise} 0 & \mbox{otherwise}
\end{array}\right. \end{array}\right.
\f] \f]
It can be used as a functor, and as a kernel for It can be used as a functor, and as a kernel for
\ref resamplingConvolveImage() to create a differentiable interpolant \ref resamplingConvolveImage() to create a differentiable interpolant
of an image. However, it should be noted that a twice differentiable of an image. However, it should be noted that a twice differentiable
interpolant can be created with only slightly more effort by recursive interpolant can be created with only slightly more effort by recursive
prefiltering followed by convolution with a 3rd order B-spline. prefiltering followed by convolution with a 3rd order B-spline.
<b>\#include</b> \<<a href="splines_8hxx-source.html">vigra/splines.hxx </a>\><br> <b>\#include</b> \<vigra/splines.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
template <class T = double> template <class T = double>
class CatmullRomSpline class CatmullRomSpline
{ {
public: public:
/** the kernel's value type /** the kernel's value type
*/ */
typedef T value_type; typedef T value_type;
/** the unary functor's argument type /** the unary functor's argument type
 End of changes. 6 change blocks. 
6 lines changed or deleted 6 lines changed or added


 stdconvolution.hxx   stdconvolution.hxx 
skipping to change at line 48 skipping to change at line 48
#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"
namespace vigra { namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor,
class KSumType>
void internalPixelEvaluationByClip(int x, int y, int w, int h, SrcIterator
xs,
SrcAccessor src_acc, DestIterator xd, De
stAccessor dest_acc,
KernelIterator ki, Diff2D kul, Diff2D kl
r, KernelAccessor ak,
KSumType norm)
{
typedef typename
PromoteTraits<typename SrcAccessor::value_type,
typename KernelAccessor::value_type>::Promote SumType
;
typedef typename DestAccessor::value_type DestType;
// calculate width and height of the kernel
int kernel_width = klr.x - kul.x + 1;
int kernel_height = klr.y - kul.y + 1;
SumType sum = NumericTraits<SumType>::zero();
int xx, yy;
int x0, y0, x1, y1;
y0 = (y<klr.y) ? -y : -klr.y;
y1 = (h-y-1<-kul.y) ? h-y-1 : -kul.y;
x0 = (x<klr.x) ? -x : -klr.x;
x1 = (w-x-1<-kul.x) ? w-x-1 : -kul.x;
SrcIterator yys = xs + Diff2D(x0, y0);
KernelIterator yk = ki - Diff2D(x0, y0);
KSumType ksum = NumericTraits<KSumType>::zero();
kernel_width = x1 - x0 + 1;
kernel_height = y1 - y0 + 1;
//es wird zuerst abgeschnitten und dann gespigelt!
for(yy=0; yy<kernel_height; ++yy, ++yys.y, --yk.y)
{
SrcIterator xxs = yys;
KernelIterator xk = yk;
for(xx=0; xx<kernel_width; ++xx, ++xxs.x, --xk.x)
{
sum += ak(xk) * src_acc(xxs);
ksum += ak(xk);
}
}
// store average in destination pixel
dest_acc.set(detail::RequiresExplicitCast<DestType>::cast((norm / ksum)
* sum), xd);
}
#if 0
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class KernelIterator, class KernelAccessor>
void internalPixelEvaluationByWrapReflectRepeat(int x, int y, int src_width
, int src_height, SrcIterator xs,
SrcAccessor src_acc, DestIt
erator xd, DestAccessor dest_acc,
KernelIterator ki, Diff2D k
ul, Diff2D klr, KernelAccessor ak,
BorderTreatmentMode border)
{
typedef typename
NumericTraits<typename SrcAccessor::value_type>::RealPromote SumTyp
e;
typedef
NumericTraits<typename DestAccessor::value_type> DestTraits;
SumType sum = NumericTraits<SumType>::zero();
SrcIterator src_ul = xs - Diff2D(x, y);
SrcIterator src_lr = src_ul + Diff2D(src_width, src_height);
SrcIterator yys = xs;
KernelIterator yk = ki;
// calculate width and height of the kernel
int kernel_width = klr.x - kul.x + 1;
int kernel_height = klr.y - kul.y + 1;
// where the kernel is beyond the borders:
bool top_to_much = (y<klr.y) ? true : false;
bool down_to_much = (src_height-y-1<-kul.y)? true : false;
bool left_to_much = (x<klr.x)? true : false;
bool right_to_much = (src_width-x-1<-kul.x)? true : false;
// direction of iteration,
// e.g. (-1, +1) for ll->ur or (-1, -1) for lr->ul
Diff2D way_increment;
/* Iteration is always done from valid to invalid range.
The following tuple is composed as such:
- If an invalid range is reached while iterating in X,
a jump of border_increment.first is performed and
border_increment.third is used for further iterating.
- If an invalid range is reached while iterating in Y,
a jump of border_increment.second is performed and
border_increment.fourth is used for further iterating.
*/
tuple4<int, int, int, int> border_increment;
if (border == BORDER_TREATMENT_REPEAT){
border_increment = tuple4<int, int, int, int>(1, 1, 0, 0);
}else if (border == BORDER_TREATMENT_REFLECT){
border_increment = tuple4<int, int, int, int>(2, 2, -1, -1);
}else{ // BORDER_TREATMENT_WRAP
border_increment = tuple4<int, int, int, int>(src_width, src_height
, 1, 1);
}
pair<int, int> valid_step_count;
if(left_to_much && !top_to_much && !down_to_much)
{
yys += klr;
yk += kul;
way_increment = Diff2D(-1, -1);
border_increment.third = -border_increment.third;
border_increment.fourth = -border_increment.fourth;
valid_step_count = std::make_pair((yys - src_ul).x + 1, kernel_heig
ht);
}
else if(top_to_much && !left_to_much && !right_to_much)
{
yys += klr;
yk += kul;
way_increment = Diff2D(-1, -1);
border_increment.third = -border_increment.third;
border_increment.fourth = -border_increment.fourth;
valid_step_count = std::make_pair(kernel_width, (yys - src_ul).y +
1);
}
else if(right_to_much && !top_to_much && !down_to_much)
{
yys += kul;
yk += klr;
way_increment = Diff2D(1, 1);
border_increment.first = -border_increment.first;
border_increment.second = -border_increment.second;
valid_step_count = std::make_pair((src_lr - yys).x, kernel_height);
}
else if(down_to_much && !left_to_much && !right_to_much)
{
yys += kul;
yk += klr;
way_increment = Diff2D(1, 1);
border_increment.first = -border_increment.first;
border_increment.second = -border_increment.second;
valid_step_count = std::make_pair(kernel_width, (src_lr - yys).y);
}
else if(down_to_much && left_to_much)
{
yys += kul + Diff2D(kernel_width - 1, 0);
yk += kul + Diff2D(0, kernel_height - 1);
way_increment = Diff2D(-1, 1);
border_increment.second = -border_increment.second;
border_increment.third = -border_increment.third;
valid_step_count = std::make_pair((yys - src_ul).x + 1, (src_lr - y
ys).y);
}
else if(down_to_much && right_to_much)
{
yys += kul;
yk += klr;
way_increment = Diff2D(1, 1);
border_increment.first = -border_increment.first;
border_increment.second = -border_increment.second;
valid_step_count = std::make_pair((src_lr - yys).x, (src_lr - yys).
y);
}
else if(top_to_much && left_to_much)
{
yys += klr;
yk += kul;
way_increment = Diff2D(-1, -1);
border_increment.third = -border_increment.third;
border_increment.fourth = -border_increment.fourth;
valid_step_count = std::make_pair((yys - src_ul).x + 1, (yys - src_
ul).y + 1);
}
else
{ //top_to_much && right_to_much
yys += kul + Diff2D(0, kernel_height - 1);
yk += kul + Diff2D(kernel_width - 1, 0);
way_increment = Diff2D(1, -1);
border_increment.first = -border_increment.first;
border_increment.fourth = -border_increment.fourth;
valid_step_count = std::make_pair((src_lr - yys).x, (yys - src_ul).
y + 1);
}
int yy = 0, xx;
//laeuft den zul
for(; yy < valid_step_count.second; ++yy, yys.y += way_increment.y, yk.
y -= way_increment.y )
{
SrcIterator xxs = yys;
KernelIterator xk = yk;
//laeuft den zul
for(xx = 0; xx < valid_step_count.first; ++xx, xxs.x += way_increme
nt.x, xk.x -= way_increment.x)
{
sum += ak(xk) * src_acc(xxs);
}
//N
//bringen => Sprung in zulaessigen Bereich
xxs.x += border_increment.first;
for( ; xx < kernel_width; ++xx, xxs.x += border_increment.third, xk
.x -= way_increment.x )
{
sum += ak(xk) * src_acc(xxs);
}
}
//N
//bringen => Sprung in zulaessigen Bereich
yys.y += border_increment.second;
for( ; yy < kernel_height; ++yy, yys.y += border_increment.third, yk.y
-= way_increment.y)
{
SrcIterator xxs = yys;
KernelIterator xk = yk;
for(xx=0; xx < valid_step_count.first; ++xx, xxs.x += way_increment
.x, xk.x -= way_increment.x)
{
sum += ak(xk) * src_acc(xxs);
}
//Sprung in den zulaessigen Bereich
xxs.x += border_increment.first;
for( ; xx < kernel_width; ++xx, xxs.x += border_increment.third, xk
.x -= way_increment.x )
{
sum += ak(xk) * src_acc(xxs);
}
}
// store average in destination pixel
dest_acc.set(DestTraits::fromRealPromote(sum), xd);
}// end of internalPixelEvaluationByWrapReflectRepeat
#endif /* #if 0 */
template <class SrcIterator, class SrcAccessor,
class KernelIterator, class KernelAccessor,
class SumType>
void
internalPixelEvaluationByWrapReflectRepeat(SrcIterator xs, SrcAccessor src_
acc,
KernelIterator xk, KernelAccessor ak,
int left, int right, int kleft, int kright,
int borderskipx, int borderinc, SumType & sum)
{
SrcIterator xxs = xs + left;
KernelIterator xxk = xk - left;
for(int xx = left; xx <= right; ++xx, ++xxs, --xxk)
{
sum += ak(xxk) * src_acc(xxs);
}
xxs = xs + left - borderskipx;
xxk = xk - left + 1;
for(int xx = left - 1; xx >= -kright; --xx, xxs -= borderinc, ++xxk)
{
sum += ak(xxk) * src_acc(xxs);
}
xxs = xs + right + borderskipx;
xxk = xk - right - 1;
for(int xx = right + 1; xx <= -kleft; ++xx, xxs += borderinc, --xxk)
{
sum += ak(xxk) * src_acc(xxs);
}
}
/** \addtogroup StandardConvolution Two-dimensional convolution functions /** \addtogroup StandardConvolution Two-dimensional convolution functions
Perform 2D non-separable convolution, with and without ROI mask. Perform 2D non-separable convolution, with and without ROI mask.
These generic convolution functions implement These generic convolution functions implement
the standard 2D convolution operation for images that fit the standard 2D convolution operation for images that fit
into the required interface. Arbitrary ROI's are supported into the required interface. Arbitrary ROI's are supported
by the mask version of the algorithm. by the mask version of the algorithm.
The functions need a suitable 2D kernel to operate. The functions need a suitable 2D kernel to operate.
*/ */
skipping to change at line 383 skipping to change at line 114
class KernelIterator, class KernelAccessor> class KernelIterator, class KernelAccessor>
void convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> sr c, void convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> sr c,
pair<DestIterator, DestAccessor> dest, pair<DestIterator, DestAccessor> dest,
tuple5<KernelIterator, KernelAccessor, Diff2D, D iff2D, tuple5<KernelIterator, KernelAccessor, Diff2D, D iff2D,
BorderTreatmentMode> kernel); BorderTreatmentMode> kernel);
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="stdconvolution_8hxx-source.html">vigra/stdc onvolution.hxx</a>\><br> <b>\#include</b> \<vigra/stdconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage 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
skipping to change at line 489 skipping to change at line 220
typedef typename DestAccessor::value_type DestType; typedef typename DestAccessor::value_type DestType;
// calculate width and height of the image // calculate width and height of the image
int w = src_lr.x - src_ul.x; int w = src_lr.x - src_ul.x;
int h = src_lr.y - src_ul.y; int h = src_lr.y - src_ul.y;
// calculate width and height of the kernel // calculate width and height of the kernel
int kernel_width = klr.x - kul.x + 1; int kernel_width = klr.x - kul.x + 1;
int kernel_height = klr.y - kul.y + 1; int kernel_height = klr.y - kul.y + 1;
vigra_precondition(w >= kernel_width && h >= kernel_height, vigra_precondition(w >= std::max(klr.x, -kul.x) + 1 && h >= std::max(kl r.y, -kul.y) + 1,
"convolveImage(): kernel larger than image."); "convolveImage(): kernel larger than image.");
KernelSumType norm = NumericTraits<KernelSumType>::zero(); KernelSumType norm = NumericTraits<KernelSumType>::zero();
if(border == BORDER_TREATMENT_CLIP) if(border == BORDER_TREATMENT_CLIP)
{ {
// calculate the sum of the kernel elements for renormalization // calculate the sum of the kernel elements for renormalization
KernelIterator yk = ki + klr; KernelIterator yk = ki + klr;
// determine sum within kernel (= norm) // determine sum within kernel (= norm)
for(int y = 0; y < kernel_height; ++y, --yk.y) for(int y = 0; y < kernel_height; ++y, --yk.y)
skipping to change at line 511 skipping to change at line 242
KernelIterator xk = yk; KernelIterator xk = yk;
for(int x = 0; x < kernel_width; ++x, --xk.x) for(int x = 0; x < kernel_width; ++x, --xk.x)
{ {
norm += ak(xk); norm += ak(xk);
} }
} }
vigra_precondition(norm != NumericTraits<KernelSumType>::zero(), vigra_precondition(norm != NumericTraits<KernelSumType>::zero(),
"convolveImage(): Cannot use BORDER_TREATMENT_CLIP with a DC-fr ee kernel"); "convolveImage(): Cannot use BORDER_TREATMENT_CLIP with a DC-fr ee kernel");
} }
// create iterators for the interior part of the image (where the kerne DestIterator yd = dest_ul;
l always fits into the image) SrcIterator ys = src_ul;
DestIterator yd = dest_ul + Diff2D(klr.x, klr.y); SrcIterator send = src_lr;
SrcIterator ys = src_ul + Diff2D(klr.x, klr.y);
SrcIterator send = src_lr + Diff2D(kul.x, kul.y);
// iterate over the interior part // iterate over the interior part
for(; ys.y < send.y; ++ys.y, ++yd.y) for(int y=0; y<h; ++y, ++ys.y, ++yd.y)
{ {
// create x iterators // create x iterators
DestIterator xd(yd); DestIterator xd(yd);
SrcIterator xs(ys); SrcIterator xs(ys);
for(; xs.x < send.x; ++xs.x, ++xd.x) for(int x=0; x < w; ++x, ++xs.x, ++xd.x)
{ {
// init the sum // init the sum
SumType sum = NumericTraits<SumType>::zero(); SumType sum = NumericTraits<SumType>::zero();
KernelIterator ykernel = ki + klr;
SrcIterator yys = xs - klr; if(x >= klr.x && y >= klr.y && x < w + kul.x && y < h + kul.y)
SrcIterator yyend = xs - kul;
KernelIterator yk = ki + klr;
for(; yys.y <= yyend.y; ++yys.y, --yk.y)
{ {
typename SrcIterator::row_iterator xxs = yys.rowIterator(); // kernel is entirely inside the image
typename SrcIterator::row_iterator xxe = xxs + kernel_width SrcIterator yys = xs - klr;
; SrcIterator yyend = xs - kul;
typename KernelIterator::row_iterator xk = yk.rowIterator(
);
for(; xxs < xxe; ++xxs, --xk) for(; yys.y <= yyend.y; ++yys.y, --ykernel.y)
{ {
sum += ak(xk) * src_acc(xxs); typename SrcIterator::row_iterator xxs = yys.rowIterato
} r();
} typename SrcIterator::row_iterator xxe = xxs + kernel_w
idth;
// store convolution result in destination pixel typename KernelIterator::row_iterator xkernel= ykernel.
dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(sum), rowIterator();
xd);
}
}
if(border == BORDER_TREATMENT_AVOID)
return; // skip processing near the border
int interiorskip = w + kul.x - klr.x - 1;
int borderskipx = 0;
int borderskipy = 0;
int borderinc = 0;
if(border == BORDER_TREATMENT_REPEAT)
{
borderskipx = 0;
borderskipy = 0;
borderinc = 0;
}
else if(border == BORDER_TREATMENT_REFLECT)
{
borderskipx = -1;
borderskipy = -1;
borderinc = -1;
}
else if(border == BORDER_TREATMENT_WRAP)
{
borderskipx = -w+1;
borderskipy = -h+1;
borderinc = 1;
}
// create iterators for the entire image
yd = dest_ul;
ys = src_ul;
// work on entire image (but skip the already computed points in the lo
op)
for(int y = 0; y < h; ++y, ++ys.y, ++yd.y)
{
int top = int(std::max(static_cast<IntBiggest>(-klr.y),
static_cast<IntBiggest>(src_ul.y - ys.y))
);
int bottom = int(std::min(static_cast<IntBiggest>(-kul.y),
static_cast<IntBiggest>(src_lr.y - ys.y -
1)));
// create x iterators
DestIterator xd(yd);
SrcIterator xs(ys);
for(int x = 0; x < w; ++x, ++xs.x, ++xd.x) for(; xxs < xxe; ++xxs, --xkernel)
{ {
// check if we are away from the border sum += ak(xkernel) * src_acc(xxs);
if(y >= klr.y && y < h+kul.y && x == klr.x) }
{ }
// yes => skip the already computed points
x += interiorskip;
xs.x += interiorskip;
xd.x += interiorskip;
continue;
} }
if (border == BORDER_TREATMENT_CLIP) else if(border == BORDER_TREATMENT_REPEAT)
{ {
internalPixelEvaluationByClip(x, y, w, h, xs, src_acc, xd, Diff2D diff;
dest_acc, ki, kul, klr, ak, norm); for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
{
diff.y = std::min(std::max(y - yk, 0), h-1);
typename KernelIterator::row_iterator xkernel = ykerne
l.rowIterator();
for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
{
diff.x = std::min(std::max(x - xk, 0), w-1);
sum += ak(xkernel) * src_acc(src_ul, diff);
}
}
} }
else else if(border == BORDER_TREATMENT_REFLECT)
{ {
int left = std::max(-klr.x, src_ul.x - xs.x); Diff2D diff;
int right = std::min(-kul.x, src_lr.x - xs.x - 1); for(int yk = klr.y; yk >= kul.y; --yk , --ykernel.y)
// init the sum
SumType sum = NumericTraits<SumType>::zero();
// create iterators for the part of the kernel that fits in
to the image
SrcIterator yys = xs + Size2D(0, top);
KernelIterator yk = ki - Size2D(0, top);
int yy;
for(yy = top; yy <= bottom; ++yy, ++yys.y, --yk.y)
{ {
internalPixelEvaluationByWrapReflectRepeat(yys.rowItera diff.y = abs(y - yk);
tor(), src_acc, yk.rowIterator(), ak, if(diff.y >= h)
left, right, kul.x, klr.x, borderskipx, borderinc, diff.y = 2*h - 2 - diff.y;
sum); typename KernelIterator::row_iterator xkernel = ykerne
l.rowIterator();
for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
{
diff.x = abs(x - xk);
if(diff.x >= w)
diff.x = 2*w - 2 - diff.x;
sum += ak(xkernel) * src_acc(src_ul, diff);
}
} }
yys = xs + Size2D(0, top - borderskipy); }
yk = ki - Size2D(0, top - 1); else if(border == BORDER_TREATMENT_WRAP)
for(yy = top - 1; yy >= -klr.y; --yy, yys.y -= borderinc, + {
+yk.y) Diff2D diff;
for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
{ {
internalPixelEvaluationByWrapReflectRepeat(yys.rowItera diff.y = (y - yk + h) % h;
tor(), src_acc, yk.rowIterator(), ak, typename KernelIterator::row_iterator xkernel = ykerne
left, right, kul.x, klr.x, borderskipx, borderinc, l.rowIterator();
sum);
for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
{
diff.x = (x - xk + w) % w;
sum += ak(xkernel) * src_acc(src_ul, diff);
}
} }
yys = xs + Size2D(0, bottom + borderskipy); }
yk = ki - Size2D(0, bottom + 1); else if(border == BORDER_TREATMENT_CLIP)
for(yy = bottom + 1; yy <= -kul.y; ++yy, yys.y += borderinc {
, --yk.y) KernelSumType ksum = NumericTraits<KernelSumType>::zero();
Diff2D diff;
for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
{ {
internalPixelEvaluationByWrapReflectRepeat(yys.rowItera diff.y = y - yk;
tor(), src_acc, yk.rowIterator(), ak, if(diff.y < 0 || diff.y >= h)
left, right, kul.x, klr.x, borderskipx, borderinc, continue;
sum); typename KernelIterator::row_iterator xkernel = ykerne
} l.rowIterator();
// store convolution result in destination pixel for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(s {
um), xd); diff.x = x - xk;
if(diff.x < 0 || diff.x >= w)
continue;
ksum += ak(xkernel);
sum += ak(xkernel) * src_acc(src_ul, diff);
}
}
// internalPixelEvaluationByWrapReflectRepeat(x, y, w, h, xs sum *= norm / ksum;
, src_acc, xd, dest_acc, ki, kul, klr, ak, border); }
else if(border == BORDER_TREATMENT_AVOID)
{
continue;
} }
// store convolution result in destination pixel
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 convolveImage( void convolveImage(
triple<SrcIterator, SrcIterator, SrcAccessor> src, triple<SrcIterator, SrcIterator, SrcAccessor> src,
skipping to change at line 735 skipping to change at line 447
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="stdconvolution_8hxx-source.html">vigra/stdc onvolution.hxx</a>\><br> <b>\#include</b> \<vigra/stdconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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;
skipping to change at line 882 skipping to change at line 594
// how much of the kernel fits into the image ? // how much of the kernel fits into the image ?
int x0, y0, x1, y1; int x0, y0, x1, y1;
y0 = (y<klr.y) ? -y : -klr.y; y0 = (y<klr.y) ? -y : -klr.y;
y1 = (h-y-1<-kul.y) ? h-y-1 : -kul.y; y1 = (h-y-1<-kul.y) ? h-y-1 : -kul.y;
x0 = (x<klr.x) ? -x : -klr.x; x0 = (x<klr.x) ? -x : -klr.x;
x1 = (w-x-1<-kul.x) ? w-x-1 : -kul.x; x1 = (w-x-1<-kul.x) ? w-x-1 : -kul.x;
bool first = true; bool first = true;
// init the sum // init the sum
SumType sum; SumType sum = NumericTraits<SumType>::zero();
KSumType ksum; KSumType ksum = NumericTraits<KSumType>::zero();
SrcIterator yys = xs + Diff2D(x0, y0); SrcIterator yys = xs + Diff2D(x0, y0);
MaskIterator yym = xm + Diff2D(x0, y0); MaskIterator yym = xm + Diff2D(x0, y0);
KernelIterator yk = ki - Diff2D(x0, y0); KernelIterator yk = ki - Diff2D(x0, y0);
int xx, kernel_width, kernel_height; int xx, kernel_width, kernel_height;
kernel_width = x1 - x0 + 1; kernel_width = x1 - x0 + 1;
kernel_height = y1 - y0 + 1; kernel_height = y1 - y0 + 1;
for(yy=0; yy<kernel_height; ++yy, ++yys.y, --yk.y, ++yym.y) for(yy=0; yy<kernel_height; ++yy, ++yys.y, --yk.y, ++yym.y)
{ {
skipping to change at line 917 skipping to change at line 629
first = false; first = false;
} }
else else
{ {
sum = detail::RequiresExplicitCast<SumType>::cast(s um + ak(xk) * src_acc(xxs)); sum = detail::RequiresExplicitCast<SumType>::cast(s um + ak(xk) * src_acc(xxs));
ksum += ak(xk); ksum += ak(xk);
} }
} }
} }
// store average in destination pixel // store average in destination pixel
if(!first && if(ksum != NumericTraits<KSumType>::zero())
ksum != NumericTraits<KSumType>::zero())
{ {
dest_acc.set(DestTraits::fromRealPromote( dest_acc.set(DestTraits::fromRealPromote(
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,
skipping to change at line 1051 skipping to change at line 762
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 The kernel defines a factory function kernel2d() to create an argument object
(see \ref KernelArgumentObjectFactories). (see \ref KernelArgumentObjectFactories).
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="stdconvolution_8hxx-source.html">vigra/stdc onvolution.hxx</a>\><br> <b>\#include</b> \<vigra/stdconvolution.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
vigra::FImage src(w,h), dest(w,h); vigra::FImage 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
skipping to change at line 1151 skipping to change at line 862
static value_type one() { return NumericTraits<value_type>::one(); } static value_type one() { return NumericTraits<value_type>::one(); }
/** Default constructor. /** Default constructor.
Creates a kernel of size 1x1 which would copy the signal Creates a kernel of size 1x1 which would copy the signal
unchanged. unchanged.
*/ */
Kernel2D() Kernel2D()
: kernel_(1, 1, one()), : kernel_(1, 1, one()),
left_(0, 0), left_(0, 0),
right_(0, 0), right_(0, 0),
norm_(one()), norm_(one()),
border_treatment_(BORDER_TREATMENT_CLIP) border_treatment_(BORDER_TREATMENT_REFLECT)
{} {}
/** Copy constructor. /** Copy constructor.
*/ */
Kernel2D(Kernel2D const & k) Kernel2D(Kernel2D const & k)
: kernel_(k.kernel_), : kernel_(k.kernel_),
left_(k.left_), left_(k.left_),
right_(k.right_), right_(k.right_),
norm_(k.norm_), norm_(k.norm_),
border_treatment_(k.border_treatment_) border_treatment_(k.border_treatment_)
{} {}
/** Copy assignment. /** Copy assignment.
*/ */
Kernel2D & operator=(Kernel2D const & k) Kernel2D & operator=(Kernel2D const & k)
{ {
if(this != &k) if(this != &k)
{ {
kernel_ = k.kernel_; kernel_ = k.kernel_;
left_ = k.left_; left_ = k.left_;
right_ = k.right_; right_ = k.right_;
norm_ = k.norm_; norm_ = k.norm_;
border_treatment_ = k.border_treatment_; border_treatment_ = k.border_treatment_;
} }
return *this; return *this;
} }
/** Initialization. /** Initialization.
This initializes the kernel with the given constant. The norm b ecomes This initializes the kernel with the given constant. The norm b ecomes
v*width()*height(). v*width()*height().
Instead of a single value an initializer list of length width() *height() Instead of a single value an initializer list of length width() *height()
can be used like this: can be used like this:
skipping to change at line 1411 skipping to change at line 1122
\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 initialzer values. If the wro ng 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(Diff2D(-1,-1), Diff2D(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().
 End of changes. 32 change blocks. 
430 lines changed or deleted 107 lines changed or added


 stdimage.hxx   stdimage.hxx 
skipping to change at line 58 skipping to change at line 58
/** \addtogroup StandardImageTypes Standard Image Types /** \addtogroup StandardImageTypes Standard Image Types
\brief The most common instantiations of the \ref vigra::BasicImage tem plate \brief The most common instantiations of the \ref vigra::BasicImage tem plate
*/ */
//@{ //@{
/** Byte (8-bit unsigned) image. /** Byte (8-bit unsigned) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<UInt8> BImage; typedef BasicImage<UInt8> BImage;
/** Byte (8-bit unsigned) image. /** Byte (8-bit unsigned) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<UInt8> UInt8Image; typedef BasicImage<UInt8> UInt8Image;
/** Signed byte (8-bit signed) image. /** Signed byte (8-bit signed) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<Int8> Int8Image; typedef BasicImage<Int8> Int8Image;
/** Short integer (16-bit signed) image. /** Short integer (16-bit signed) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<Int16> SImage; typedef BasicImage<Int16> SImage;
/** Short integer (16-bit unsigned) image. /** Short integer (16-bit unsigned) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<UInt16> UInt16Image; typedef BasicImage<UInt16> UInt16Image;
/** Short integer (16-bit signed) image. /** Short integer (16-bit signed) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<Int16> Int16Image; typedef BasicImage<Int16> Int16Image;
/** Integer (32-bit signed) image. /** Integer (32-bit signed) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<Int32> IImage; typedef BasicImage<Int32> IImage;
/** Integer (32-bit unsigned) image. /** Integer (32-bit unsigned) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<UInt32> UInt32Image; typedef BasicImage<UInt32> UInt32Image;
/** Integer (32-bit signed) image. /** Integer (32-bit signed) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<Int32> Int32Image; typedef BasicImage<Int32> Int32Image;
/** Float (float) image. /** Float (float) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<float> FImage; typedef BasicImage<float> FImage;
/** Double (double) image. /** Double (double) image.
It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and It uses \ref vigra::BasicImageIterator and \ref vigra::StandardAcce ssor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdimag e.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<double> DImage; typedef BasicImage<double> DImage;
/** Byte (3x 8-bit unsigned) RGB image. /** Byte (3x 8-bit unsigned) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::UInt 8>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::UInt 8>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<UInt8> > BRGBImage; typedef BasicImage<RGBValue<UInt8> > BRGBImage;
/** Byte (3x 8-bit unsigned) RGB image. /** Byte (3x 8-bit unsigned) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::UInt 8>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::UInt 8>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<UInt8> > UInt8RGBImage; typedef BasicImage<RGBValue<UInt8> > UInt8RGBImage;
/** Byte (3x 8-bit signed) RGB image. /** Byte (3x 8-bit signed) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::UInt 8>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::UInt 8>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<Int8> > Int8RGBImage; typedef BasicImage<RGBValue<Int8> > Int8RGBImage;
/** Short (3x 16-bit signed) RGB image. /** Short (3x 16-bit signed) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int1 6>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int1 6>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<Int16> > SRGBImage; typedef BasicImage<RGBValue<Int16> > SRGBImage;
/** Short (3x 16-bit unsigned) RGB image. /** Short (3x 16-bit unsigned) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int1 6>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int1 6>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<UInt16> > UInt16RGBImage; typedef BasicImage<RGBValue<UInt16> > UInt16RGBImage;
/** Short (3x 16-bit signed) RGB image. /** Short (3x 16-bit signed) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int1 6>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int1 6>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<Int16> > Int16RGBImage; typedef BasicImage<RGBValue<Int16> > Int16RGBImage;
/** Integer (3x 32-bit signed) RGB image. /** Integer (3x 32-bit signed) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int3 2>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int3 2>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<Int32> > IRGBImage; typedef BasicImage<RGBValue<Int32> > IRGBImage;
/** Integer (3x 32-bit unsigned) RGB image. /** Integer (3x 32-bit unsigned) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int3 2>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int3 2>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<UInt32> > UInt32RGBImage; typedef BasicImage<RGBValue<UInt32> > UInt32RGBImage;
/** Integer (3x 32-bit signed) RGB image. /** Integer (3x 32-bit signed) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int3 2>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<vigra::Int3 2>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<Int32> > Int32RGBImage; typedef BasicImage<RGBValue<Int32> > Int32RGBImage;
/** Floating-point (3x float) RGB image. /** Floating-point (3x float) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<float>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<float>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<float> > FRGBImage; typedef BasicImage<RGBValue<float> > FRGBImage;
/** Double-precision floating-point (3x double) RGB image. /** Double-precision floating-point (3x double) RGB image.
The pixel type is \ref vigra::RGBValue "vigra::RGBValue<double>". The pixel type is \ref vigra::RGBValue "vigra::RGBValue<double>".
It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and It uses \ref vigra::BasicImageIterator and \ref vigra::RGBAccessor and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<RGBValue<double> > DRGBImage; typedef BasicImage<RGBValue<double> > DRGBImage;
/** Floating-point TinyVector image. /** Floating-point TinyVector image.
The pixel type is \ref vigra::TinyVector "vigra::TinyVector<float, 2>". The pixel type is \ref vigra::TinyVector "vigra::TinyVector<float, 2>".
It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<TinyVector<float, 2> > FVector2Image; typedef BasicImage<TinyVector<float, 2> > FVector2Image;
/** Floating-point TinyVector image. /** Floating-point TinyVector image.
The pixel type is \ref vigra::TinyVector "vigra::TinyVector<float, 3>". The pixel type is \ref vigra::TinyVector "vigra::TinyVector<float, 3>".
It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<TinyVector<float, 3> > FVector3Image; typedef BasicImage<TinyVector<float, 3> > FVector3Image;
/** Floating-point TinyVector image. /** Floating-point TinyVector image.
The pixel type is \ref vigra::TinyVector "vigra::TinyVector<float, 4>". The pixel type is \ref vigra::TinyVector "vigra::TinyVector<float, 4>".
It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<TinyVector<float, 4> > FVector4Image; typedef BasicImage<TinyVector<float, 4> > FVector4Image;
/** Floating-point TinyVector image. /** Floating-point TinyVector image.
The pixel type is \ref vigra::TinyVector "vigra::TinyVector<double, 2>". The pixel type is \ref vigra::TinyVector "vigra::TinyVector<double, 2>".
It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<TinyVector<double, 2> > DVector2Image; typedef BasicImage<TinyVector<double, 2> > DVector2Image;
/** Floating-point TinyVector image. /** Floating-point TinyVector image.
The pixel type is \ref vigra::TinyVector "vigra::TinyVector<double, 3>". The pixel type is \ref vigra::TinyVector "vigra::TinyVector<double, 3>".
It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
//typedef BasicImage<TinyVector<double, 3> > DVector3Image; //typedef BasicImage<TinyVector<double, 3> > DVector3Image;
typedef BasicImage<TinyVector<double, 3> > DVector3Image; typedef BasicImage<TinyVector<double, 3> > DVector3Image;
/** Floating-point TinyVector image. /** Floating-point TinyVector image.
The pixel type is \ref vigra::TinyVector "vigra::TinyVector<double, 4>". The pixel type is \ref vigra::TinyVector "vigra::TinyVector<double, 4>".
It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and It uses \ref vigra::BasicImageIterator and \ref vigra::VectorAccess or and
their const counterparts to access the data. their const counterparts to access the data.
<b>\#include</b> \<<a href="stdimage_8hxx-source.html">vigra/stdima ge.hxx</a>\><br> <b>\#include</b> \<vigra/stdimage.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
typedef BasicImage<TinyVector<double, 4> > DVector4Image; typedef BasicImage<TinyVector<double, 4> > DVector4Image;
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_STDIMAGE_HXX #endif // VIGRA_STDIMAGE_HXX
 End of changes. 28 change blocks. 
28 lines changed or deleted 28 lines changed or added


 stdimagefunctions.hxx   stdimagefunctions.hxx 
skipping to change at line 62 skipping to change at line 62
<LI> \ref TransformFunctor <LI> \ref TransformFunctor
<BR>&nbsp;&nbsp;&nbsp; <em>frequently used unary transformation fu nctors</em> <BR>&nbsp;&nbsp;&nbsp; <em>frequently used unary transformation fu nctors</em>
<LI> \ref CombineAlgo <LI> \ref CombineAlgo
<BR>&nbsp;&nbsp;&nbsp; <em>apply functor to calculate a pixelwise transformation from several image</em> <BR>&nbsp;&nbsp;&nbsp; <em>apply functor to calculate a pixelwise transformation from several image</em>
<LI> \ref CombineFunctor <LI> \ref CombineFunctor
<BR>&nbsp;&nbsp;&nbsp; <em>frequently used binary transformations functors</em> <BR>&nbsp;&nbsp;&nbsp; <em>frequently used binary transformations functors</em>
<LI> \ref MultiPointoperators <LI> \ref MultiPointoperators
<BR>&nbsp;&nbsp;&nbsp; <em>Point operators on multi-dimensional ar rays</em> <BR>&nbsp;&nbsp;&nbsp; <em>Point operators on multi-dimensional ar rays</em>
</UL> </UL>
<b>\#include</b> \<<a href="stdimagefunctions_8hxx-source.html">vigra/s tdimagefunctions.hxx</a>\><br> <b>\#include</b> \<vigra/stdimagefunctions.hxx\><br>
Namespace: vigra Namespace: vigra
see also: \ref FunctorExpressions "Automatic Functor Creation" see also: \ref FunctorExpressions "Automatic Functor Creation"
*/ */
#include "initimage.hxx" #include "initimage.hxx"
#include "inspectimage.hxx" #include "inspectimage.hxx"
#include "copyimage.hxx" #include "copyimage.hxx"
#include "transformimage.hxx" #include "transformimage.hxx"
#include "combineimages.hxx" #include "combineimages.hxx"
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 symmetry.hxx   symmetry.hxx 
skipping to change at line 76 skipping to change at line 76
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 arguments explicitly:
\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 a DestIterator dul, DestAccessor ad,
d, 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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="symmetry_8hxx-source.html">vigra/symmet ry.hxx</a>\><br> <b>\#include</b> \<vigra/symmetry.hxx\><br>
Namespace: vigra Namespace: vigra
\code \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);
skipping to change at line 148 skipping to change at line 148
dest_accessor.set(u, dest_upperleft); dest_accessor.set(u, dest_upperleft);
\endcode \endcode
*/ */
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)
{ {
vigra_precondition(scale > 0.0, vigra_precondition(scale > 0.0,
"radialSymmetryTransform(): Scale must be > 0"); "radialSymmetryTransform(): Scale must be > 0");
int w = slr.x - sul.x; int w = slr.x - sul.x;
int h = slr.y - sul.y; int h = slr.y - sul.y;
if(w <= 0 || h <= 0) return; if(w <= 0 || h <= 0) return;
typedef typename typedef typename
skipping to change at line 251 skipping to change at line 251
} }
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 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)
{ {
radialSymmetryTransform(src.first, src.second, src.third, radialSymmetryTransform(src.first, src.second, src.third,
dest.first, dest.second, dest.first, dest.second,
scale); scale);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif /* VIGRA_SYMMETRY_HXX */ #endif /* VIGRA_SYMMETRY_HXX */
 End of changes. 8 change blocks. 
13 lines changed or deleted 12 lines changed or added


 tensorutilities.hxx   tensorutilities.hxx 
skipping to change at line 59 skipping to change at line 59
/********************************************************/ /********************************************************/
/* */ /* */
/* vectorToTensor */ /* vectorToTensor */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Calculate the tensor (outer) product of a 2D vector with itself. /** \brief Calculate the tensor (outer) product of a 2D vector with itself.
This function is useful to transform vector images into a tensor repres entation This function is useful to transform vector images into a tensor repres entation
that can be used as input to tensor based processing and analysis funct ions that can be used as input to tensor based processing and analysis funct ions
(e.g. tensor smoothing). The imput pixel type must be vectors of length 2, whereas (e.g. tensor smoothing). The input pixel type must be vectors of length 2, whereas
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>
skipping to change at line 94 skipping to change at line 94
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tensorutilities_8hxx-source.html">vigra/ten sorutilities.hxx</a>\> <b>\#include</b> \<vigra/tensorutilities.hxx\>
\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
skipping to change at line 216 skipping to change at line 216
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tensorutilities_8hxx-source.html">vigra/ten sorutilities.hxx</a>\> <b>\#include</b> \<vigra/tensorutilities.hxx\>
\code \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
*/ */
doxygen_overloaded_function(template <...> void tensorEigenRepresentation) doxygen_overloaded_function(template <...> void tensorEigenRepresentation)
skipping to change at line 314 skipping to change at line 314
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tensorutilities_8hxx-source.html">vigra/ten sorutilities.hxx</a>\> <b>\#include</b> \<vigra/tensorutilities.hxx\>
\code \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
*/ */
doxygen_overloaded_function(template <...> void tensorTrace) doxygen_overloaded_function(template <...> void tensorTrace)
skipping to change at line 402 skipping to change at line 402
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tensorutilities_8hxx-source.html">vigra/ten sorutilities.hxx</a>\> <b>\#include</b> \<vigra/tensorutilities.hxx\>
\code \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
*/ */
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 tiff.hxx   tiff.hxx 
skipping to change at line 102 skipping to change at line 102
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tiff_8hxx-source.html">vigra/tiff.hxx</a>\> <b>\#include</b> \<vigra/tiff.hxx\>
\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); vigra::BImage img(w,h);
vigra::importTiffImage(tiff, destImage(img)); vigra::importTiffImage(tiff, destImage(img));
skipping to change at line 191 skipping to change at line 191
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tiff_8hxx-source.html">vigra/tiff.hxx</a>\> <b>\#include</b> \<vigra/tiff.hxx\>
\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_MINISWHITE && if(photometric != PHOTOMETRIC_MINISWHITE &&
skipping to change at line 551 skipping to change at line 551
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tiff_8hxx-source.html">vigra/tiff.hxx</a>\> <b>\#include</b> \<vigra/tiff.hxx\>
\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 &&
skipping to change at line 600 skipping to change at line 600
\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 // unlass 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
*/ */
skipping to change at line 1042 skipping to change at line 1042
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tiff_8hxx-source.html">vigra/tiff.hxx</a>\> <b>\#include</b> \<vigra/tiff.hxx\>
\code \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);
skipping to change at line 1119 skipping to change at line 1119
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tiff_8hxx-source.html">vigra/tiff.hxx</a>\> <b>\#include</b> \<vigra/tiff.hxx\>
\code \code
vigra::BImage img(width, height); 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);
skipping to change at line 1528 skipping to change at line 1528
\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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="tiff_8hxx-source.html">vigra/tiff.hxx</a>\> <b>\#include</b> \<vigra/tiff.hxx\>
\code \code
vigra::BRGBImage img(width, height); 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);
 End of changes. 7 change blocks. 
7 lines changed or deleted 7 lines changed or added


 timing.hxx   timing.hxx 
/************************************************************************/ /************************************************************************/
/* */ /* */
/* Copyright 2008-2009 by Ullrich Koethe */ /* Copyright 2008-2011 by Ullrich Koethe */
/* Cognitive Systems Group, University of Hamburg, Germany */
/* */ /* */
/* 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://kogs-www.informatik.uni-hamburg.de/~koethe/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 */
/* files (the "Software"), to deal in the Software without */ /* files (the "Software"), to deal in the Software without */
/* restriction, including without limitation the rights to use, */ /* restriction, including without limitation the rights to use, */
/* copy, modify, merge, publish, distribute, sublicense, and/or */ /* copy, modify, merge, publish, distribute, sublicense, and/or */
/* sell copies of the Software, and to permit persons to whom the */ /* sell copies of the Software, and to permit persons to whom the */
skipping to change at line 38 skipping to change at line 39
/* 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_TIMING_HXX #ifndef VIGRA_TIMING_HXX
#define VIGRA_TIMING_HXX #define VIGRA_TIMING_HXX
#ifndef VIGRA_NO_TIMING
#ifndef NDEBUG #include <iostream>
#include <sstream> #include <sstream>
#include <vector>
// usage: /*! \page TimingMacros Timing macros for runtime measurements
// void time_it()
// { <b>\#include</b> \<vigra/timing.hxx\>
// USETICTOC;
// TIC; These macros allow to perform execution speed measurements. Results are
// ... reported
// std::cerr << TOC << " for time_it\n"; in <i>milliseconds</i>.
// } However, note that timings below 1 msec are generally subject to round-
off errors.
Under LINUX, you can \#define VIGRA_HIRES_TIMING to get better
accuracy, but this requires linking against librt.
Basic usage:
\code
void time_it()
{
USETICTOC
TIC
... code to be timed
TOC
... untimed code
TIC
... other code to be timed
TOC
}
\endcode
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)
or TOCS (the time difference as a std::string).
Alternatively, you can perform nested timing like so:
\code
void time_it()
{
USE_NESTED_TICTOC
TICPUSH
... code to be timed
TICPUSH
... nested code to be timed
TOC print time for nested code
... more code to be timed
TOC print total time
}
\endcode
*/
/*! \file timing.hxx Timing macros for runtime measurements
This header defines timing macros for runtime measurements. See \ref Timi
ngMacros for examples.
\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.
\hideinitializer
\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.
\hideinitializer
\def TIC
Start timing. Requires USE_TICTOC to be defined in the current context.
\hideinitializer
\def TOC
Stop timing and output result (the time difference w.r.t. the last TIC or
TICPUSH
instance) to std::cerr.
\hideinitializer
\def TICPUSH
Start timing, possibly a nested block of code within some other timed cod
e block.
Requires USE_NESTED_TICTOC to be defined once in the current context.
\hideinitializer
\def TOCN
Stop timing. This macro evaluates to the time difference (w.r.t. the last
TIC
or TICPUSH) in msec as a double.
\hideinitializer
\def TOCS
Stop timing. This macro evaluates to the time difference (w.r.t. the last
TIC
or TICPUSH) as a std::string (including units).
\hideinitializer
\def TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions)
Executes the code block up to TICTOCLOOP_END outer_repetitions x
inner_repetitions times. The measurement is averaged over the
inner_repetitions, and the best result of the outer_repetitions is
reported to std::cerr.
\hideinitializer
\def TICTOCLOOP_END
Ends the timing loop started with the TICTOCLOOP_BEGIN macro
and outputs the result.
\hideinitializer
*/
#ifdef WIN32 #ifdef WIN32
#include "windows.h" #include "windows.h"
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;
} }
inline std::string tic_toc_diff(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(); static double unit = queryTimerUnit();
return ((toc.QuadPart - tic.QuadPart) * unit);
}
inline std::string tic_toc_diff_string(LARGE_INTEGER const & tic)
{
double diff = tic_toc_diff_num(tic);
std::stringstream s; std::stringstream s;
s << ((toc.QuadPart - tic.QuadPart) * unit) << " msec"; s << diff << " msec";
return s.str(); return s.str();
} }
inline void tic_toc_diff(LARGE_INTEGER const & tic)
{
std::cerr << tic_toc_diff_string(tic) <<std::endl;
}
inline double tic_toc_diff_num(std::vector<LARGE_INTEGER> & tic)
{
double res = tic_toc_diff_num(tic.back());
tic.pop_back();
return res;
}
inline std::string tic_toc_diff_string(std::vector<LARGE_INTEGER> & tic
)
{
std::string res = tic_toc_diff_string(tic.back());
tic.pop_back();
return res;
}
inline void tic_toc_diff(std::vector<LARGE_INTEGER> & tic)
{
tic_toc_diff(tic.back());
tic.pop_back();
}
} // unnamed namespace } // unnamed namespace
#define USETICTOC LARGE_INTEGER tic_timer #define USETICTOC LARGE_INTEGER tic_timer;
#define TIC QueryPerformanceCounter(&tic_timer) #define USE_NESTED_TICTOC std::vector<LARGE_INTEGER> tic_timer;
#define TOC tic_toc_diff(tic_timer) #define TIC QueryPerformanceCounter(&tic_timer);
#define TICPUSH tic_timer.push_back(LARGE_INTEGER());\
QueryPerformanceCounter(&(tic_timer.back()));
#define TOC tic_toc_diff (tic_timer);
#define TOCN tic_toc_diff_num (tic_timer)
#define TOCS tic_toc_diff_string(tic_timer)
#else #else
#if defined(VIGRA_HIRES_TIMING) && !defined(__CYGWIN__) #if defined(VIGRA_HIRES_TIMING) && !defined(__CYGWIN__)
// requires linking against librt // requires linking against librt
#include <time.h> #include <time.h>
namespace { namespace {
inline std::string tic_toc_diff(timespec const & tic) inline double tic_toc_diff_num(timespec const & tic)
{ {
timespec toc; timespec toc;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &toc); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &toc);
return ((toc.tv_sec*1000.0 + toc.tv_nsec/1000000.0) -
(tic.tv_sec*1000.0 + tic.tv_nsec/1000000.0));
}
inline std::string tic_toc_diff_string(timespec const & tic)
{
double diff = tic_toc_diff_num(tic);
std::stringstream s; std::stringstream s;
s << ((toc.tv_sec*1000.0 + toc.tv_nsec/1000000.0) - s << diff << " msec";
(tic.tv_sec*1000.0 + tic.tv_nsec/1000000.0)) << " msec";
return s.str(); return s.str();
} }
inline void tic_toc_diff(timespec const & tic)
{
std::cerr << tic_toc_diff_string(tic) << std::endl;
}
inline double tic_toc_diff_num(std::vector<timespec> & tic)
{
double res = tic_toc_diff_num(tic.back());
tic.pop_back();
return res;
}
inline std::string tic_toc_diff_string(std::vector<timespec> & tic)
{
std::string res = tic_toc_diff_string(tic.back());
tic.pop_back();
return res;
}
inline void tic_toc_diff(std::vector<timespec> & tic)
{
tic_toc_diff(tic.back());
tic.pop_back();
}
} // unnamed namespace } // unnamed namespace
#define USETICTOC timespec tic_timer #define USETICTOC timespec tic_timer;
#define TIC clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tic_timer) #define TIC clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tic_timer);
#define TOC tic_toc_diff(tic_timer) #define TOC tic_toc_diff (tic_timer);
#define TOCN tic_toc_diff_num (tic_timer)
#define TOCS tic_toc_diff_string(tic_timer)
#define USE_NESTED_TICTOC std::vector<timespec> tic_timer;
#define TICPUSH tic_timer.push_back(timespec());\
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(tic_timer
.back()));
#else #else
#include <sys/time.h> #include <sys/time.h>
namespace { namespace {
inline std::string tic_toc_diff(timeval const & tic) inline double tic_toc_diff_num(timeval const & tic)
{ {
timeval toc; timeval toc;
gettimeofday(&toc, NULL); gettimeofday(&toc, NULL);
return ((toc.tv_sec*1000.0 + toc.tv_usec/1000.0) -
(tic.tv_sec*1000.0 + tic.tv_usec/1000.0));
}
inline std::string tic_toc_diff_string(timeval const & tic)
{
double diff = tic_toc_diff_num(tic);
std::stringstream s; std::stringstream s;
s << ((toc.tv_sec*1000.0 + toc.tv_usec/1000.0) - s << diff << " msec";
(tic.tv_sec*1000.0 + tic.tv_usec/1000.0)) << " msec";
return s.str(); return s.str();
} }
inline void tic_toc_diff(timeval const & tic)
{
std::cerr << tic_toc_diff_string(tic)<< std::endl;
}
inline double tic_toc_diff_num(std::vector<timeval> & tic)
{
double res = tic_toc_diff_num(tic.back());
tic.pop_back();
return res;
}
inline std::string tic_toc_diff_string(std::vector<timeval> & tic)
{
std::string res = tic_toc_diff_string(tic.back());
tic.pop_back();
return res;
}
inline void tic_toc_diff(std::vector<timeval> & tic)
{
tic_toc_diff(tic.back());
tic.pop_back();
}
} // unnamed namespace } // unnamed namespace
#define USETICTOC timeval tic_timer #define USETICTOC timeval tic_timer;
#define TIC gettimeofday(&tic_timer, NULL) #define TIC gettimeofday (&tic_timer, NULL);
#define TOC tic_toc_diff(tic_timer) #define TOC tic_toc_diff (tic_timer);
#define TOCN tic_toc_diff_num (tic_timer)
#define TOCS tic_toc_diff_string(tic_timer)
#define USE_NESTED_TICTOC std::vector<timeval> tic_timer;
#define TICPUSH tic_timer.push_back(timeval());\
gettimeofday(&(tic_timer.back()), NULL);
#endif // VIGRA_HIRES_TIMING #endif // VIGRA_HIRES_TIMING
#endif // WIN32 #endif // WIN32
// TICTOCLOOP runs the body inner_repetitions times, and minimizes the resu
lt over a number of outer_repetitions runs,
// outputting the final minimal average to std::cerr
#define TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions) \
{ \
USETICTOC \
double tictoc_best_, tictoc_inner_repetitions_=inner_repetitions; s
ize_t tictoc_outer_repetitions_=outer_repetitions; \
for (size_t tictoccounter_=0; tictoccounter_<tictoc_outer_repetitio
ns_; ++tictoccounter_) { \
TIC \
for (size_t tictocinnercounter_=0; tictocinnercounter_<inner_repeti
tions; ++tictocinnercounter_) { \
#define TICTOCLOOP_END \
} \
const double tictoc_cur_ = TOCN; \
if ((tictoccounter_==0) || (tictoc_cur_ < tictoc_best_)) \
tictoc_best_ = tictoc_cur_; \
} \
std::cerr << tictoc_best_/tictoc_inner_repetitions_ \
<< " msec (best-of-" << tictoc_outer_repetitions_ << ")" << st
d::endl; \
}\
#else // NDEBUG #else // NDEBUG
#define USETICTOC #define USETICTOC
#define TIC #define TIC
#define TOC #define TOC
#define TOCN 0.0
#define TICS ""
#define USE_NESTED_TICTOC
#define TICPUSH
#define TICTOCLOOP_BEGIN {
#define TICTOCLOOP_END }
#endif // NDEBUG #endif // NDEBUG
#endif // VIGRA_TIMING_HXX #endif // VIGRA_TIMING_HXX
 End of changes. 23 change blocks. 
30 lines changed or deleted 271 lines changed or added


 tinyvector.hxx   tinyvector.hxx 
skipping to change at line 213 skipping to change at line 213
template <int LEVEL> template <int LEVEL>
struct UnrollSquaredNorm struct UnrollSquaredNorm
{ {
template <class T> template <class T>
static typename NormTraits<T>::SquaredNormType static typename NormTraits<T>::SquaredNormType
squaredNorm(T const * d) squaredNorm(T const * d)
{ {
return vigra::squaredNorm(*d) + UnrollSquaredNorm<LEVEL-1>::squared Norm(d+1); return vigra::squaredNorm(*d) + UnrollSquaredNorm<LEVEL-1>::squared Norm(d+1);
} }
static std::ptrdiff_t
squaredNorm(std::ptrdiff_t const * d)
{
return (*d)*(*d) + UnrollSquaredNorm<LEVEL-1>::squaredNorm(d+1);
}
}; };
template <> template <>
struct UnrollSquaredNorm<1> struct UnrollSquaredNorm<1>
{ {
template <class T> template <class T>
static typename NormTraits<T>::SquaredNormType static typename NormTraits<T>::SquaredNormType
squaredNorm(T const * d) squaredNorm(T const * d)
{ {
return vigra::squaredNorm(*d); return vigra::squaredNorm(*d);
} }
static std::ptrdiff_t
squaredNorm(std::ptrdiff_t const * d)
{
return (*d)*(*d);
}
}; };
#undef VIGRA_EXEC_LOOP #undef VIGRA_EXEC_LOOP
#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) \
{ \ { \
(*left) OPER (*right); \ (*left) OPER (*right); \
skipping to change at line 384 skipping to change at line 396
/* TinyVectorBase */ /* TinyVectorBase */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Base class for fixed size vectors. /** \brief Base class for fixed size vectors.
This class contains functionality shared by This class contains functionality shared by
\ref TinyVector and \ref TinyVectorView, and enables these classes \ref TinyVector and \ref TinyVectorView, and enables these classes
to be freely mixed within expressions. It is typically not used directl y. to be freely mixed within expressions. It is typically not used directl y.
<b>\#include</b> \<<a href="tinyvector_8hxx-source.html">vigra/tinyvect or.hxx</a>\><br> <b>\#include</b> \<vigra/tinyvector.hxx\><br>
Namespace: vigra Namespace: vigra
**/ **/
template <class VALUETYPE, int SIZE, class DATA, class DERIVED> template <class VALUETYPE, int SIZE, class DATA, class DERIVED>
class TinyVectorBase class TinyVectorBase
{ {
TinyVectorBase(TinyVectorBase const &); // do not use TinyVectorBase(TinyVectorBase const &); // do not use
TinyVectorBase & operator=(TinyVectorBase const & other); // do not use TinyVectorBase & operator=(TinyVectorBase const & other); // do not use
protected: protected:
skipping to change at line 459 skipping to change at line 471
/** the vector's size /** the vector's size
*/ */
enum { static_size = SIZE }; enum { static_size = SIZE };
/** Initialize from another sequence (must have length SIZE!) /** Initialize from another sequence (must have length SIZE!)
*/ */
template <class Iterator> template <class Iterator>
void init(Iterator i, Iterator end) void init(Iterator i, Iterator end)
{ {
vigra_precondition(end-i == SIZE, vigra_precondition(end-i == SIZE,
"TinyVector::init(): Sequence has wrong size."); "TinyVector::init(): Sequence has wrong size.");
Loop::assignCast(data_, i); Loop::assignCast(data_, i);
} }
/** Initialize with constant value /** Initialize with constant value
*/ */
void init(value_type initial) void init(value_type initial)
{ {
Loop::assignScalar(data_, initial); Loop::assignScalar(data_, initial);
} }
skipping to change at line 583 skipping to change at line 595
pointer data() { return data_; } pointer data() { return data_; }
const_pointer data() const { return data_; } const_pointer data() const { return data_; }
protected: protected:
DATA data_; DATA data_;
}; };
/** \brief Class for fixed size vectors. /** \brief Class for fixed size vectors.
\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
(+=, -=, +, -, unary -), multiplication and division of an (+=, -=, +, -, unary -), multiplication and division of an
TinyVector with a double, and NumericTraits/PromoteTraits are defined, TinyVector with a double, and NumericTraits/PromoteTraits are defined,
skipping to change at line 606 skipping to change at line 619
TinyVectors as a whole, or specific components of them. TinyVectors as a whole, or specific components of them.
See also:<br> See also:<br>
<UL style="list-style-image:url(documents/bullet.gif)"> <UL style="list-style-image:url(documents/bullet.gif)">
<LI> \ref vigra::TinyVectorBase <LI> \ref vigra::TinyVectorBase
<LI> \ref vigra::TinyVectorView <LI> \ref vigra::TinyVectorView
<LI> \ref TinyVectorTraits <LI> \ref TinyVectorTraits
<LI> \ref TinyVectorOperators <LI> \ref TinyVectorOperators
</UL> </UL>
<b>\#include</b> \<<a href="tinyvector_8hxx-source.html">vigra/tinyvect or.hxx</a>\><br> <b>\#include</b> \<vigra/tinyvector.hxx\><br>
Namespace: vigra Namespace: vigra
**/ **/
template <class T, int SIZE> template <class T, int SIZE>
class TinyVector class TinyVector
: public TinyVectorBase<T, SIZE, T[SIZE], TinyVector<T, SIZE> > : public TinyVectorBase<T, SIZE, T[SIZE], TinyVector<T, SIZE> >
{ {
typedef TinyVectorBase<T, SIZE, T[SIZE], TinyVector<T, SIZE> > BaseType ; typedef TinyVectorBase<T, SIZE, T[SIZE], TinyVector<T, SIZE> > BaseType ;
typedef typename BaseType::Loop Loop; typedef typename BaseType::Loop Loop;
public: public:
skipping to change at line 815 skipping to change at line 828
TinyVectorViews as a whole, or specific components of them. TinyVectorViews as a whole, or specific components of them.
<b>See also:</b> <b>See also:</b>
<ul> <ul>
<li> \ref vigra::TinyVectorBase <li> \ref vigra::TinyVectorBase
<li> \ref vigra::TinyVector <li> \ref vigra::TinyVector
<li> \ref TinyVectorTraits <li> \ref TinyVectorTraits
<li> \ref TinyVectorOperators <li> \ref TinyVectorOperators
</ul> </ul>
<b>\#include</b> \<<a href="tinyvector_8hxx-source.html">vigra/tinyvect or.hxx</a>\><br> <b>\#include</b> \<vigra/tinyvector.hxx\><br>
Namespace: vigra Namespace: vigra
**/ **/
template <class T, int SIZE> template <class T, int SIZE>
class TinyVectorView class TinyVectorView
: public TinyVectorBase<T, SIZE, T *, TinyVectorView<T, SIZE> > : public TinyVectorBase<T, SIZE, T *, TinyVectorView<T, SIZE> >
{ {
typedef TinyVectorBase<T, SIZE, T *, TinyVectorView<T, SIZE> > BaseType ; typedef TinyVectorBase<T, SIZE, T *, TinyVectorView<T, SIZE> > BaseType ;
typedef typename BaseType::Loop Loop; typedef typename BaseType::Loop Loop;
public: public:
skipping to change at line 905 skipping to change at line 918
/* */ /* */
/********************************************************/ /********************************************************/
/** \addtogroup TinyVectorOperators Functions for TinyVector /** \addtogroup TinyVectorOperators Functions for TinyVector
\brief Implement basic arithmetic and equality for TinyVector. \brief Implement basic arithmetic and equality for TinyVector.
These functions fulfill the requirements of a Linear Space (vector spac e). These functions fulfill the requirements of a Linear Space (vector spac e).
Return types are determined according to \ref TinyVectorTraits. Return types are determined according to \ref TinyVectorTraits.
<b>\#include</b> \<<a href="tinyvector_8hxx-source.html">vigra/tinyvect or.hxx</a>\><br> <b>\#include</b> \<vigra/tinyvector.hxx\><br>
Namespace: vigra Namespace: vigra
*/ */
//@{ //@{
/// component-wise equal /// component-wise 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)
{ {
return !(l != r); return !(l != r);
skipping to change at line 990 skipping to change at line 1003
typedef typename Type::NormType NormType; typedef typename Type::NormType NormType;
}; };
template <class T1, class T2, SIZE> template <class T1, class T2, SIZE>
struct PromoteTraits<TinyVector<T1, SIZE>, TinyVector<T2, SIZE> > struct PromoteTraits<TinyVector<T1, SIZE>, TinyVector<T2, SIZE> >
{ {
typedef TinyVector<typename PromoteTraits<T1, T2>::Promote, SIZE> P romote; typedef TinyVector<typename PromoteTraits<T1, T2>::Promote, SIZE> P romote;
}; };
\endcode \endcode
<b>\#include</b> \<<a href="tinyvector_8hxx-source.html">vigra/tinyvect or.hxx</a>\><br> <b>\#include</b> \<vigra/tinyvector.hxx\><br>
Namespace: vigra Namespace: vigra
On compilers that don't support pertial template specialization (e.g. On compilers that don't support partial template specialization (e.g.
MS VisualC++), the traits classes are explicitly specialized for MS VisualC++), the traits classes are explicitly specialized for
<TT>TinyVector<VALUETYPE, SIZE></TT> with <TT>TinyVector<VALUETYPE, SIZE></TT> with
<TT>VALUETYPE = unsigned char | int | float | double</TT> and <TT>SIZE = 2 | 3 | 4</TT>. <TT>VALUETYPE = unsigned char | int | float | double</TT> and <TT>SIZE = 2 | 3 | 4</TT>.
*/ */
#if !defined(NO_PARTIAL_TEMPLATE_SPECIALIZATION) #if !defined(NO_PARTIAL_TEMPLATE_SPECIALIZATION)
template <class T, int SIZE> template <class T, int SIZE>
struct NumericTraits<TinyVector<T, SIZE> > struct NumericTraits<TinyVector<T, SIZE> >
skipping to change at line 1343 skipping to change at line 1356
/// component-wise scalar division /// component-wise 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
template <class V, int SIZE, class D1, class D2>
inline
TinyVector<V, SIZE>
div(TinyVectorBase<V, SIZE, D1, D2> const & l, V v)
{
TinyVector<V, SIZE> result(l);
typedef typename detail::LoopType<SIZE>::type Loop;
Loop::divScalar(result.data(), v);
return result;
}
/** Unary negation (construct TinyVector with negative values) /** Unary negation (construct TinyVector with negative values)
*/ */
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>
operator-(TinyVectorBase<V, SIZE, D1, D2> const & v) operator-(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::neg(res.begin(), v.begin()); ltype::neg(res.begin(), v.begin());
skipping to change at line 1419 skipping to change at line 1444
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<V1, V2>::Promote typename PromoteTraits<V1, V2>::Promote
dot(TinyVectorBase<V1, SIZE, D1, D2> const & l, dot(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::dot(l.begin(), r.begin()); return ltype::dot(l.begin(), r.begin());
} }
/// sum of the vector's elements
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<V>::Promote
sum(TinyVectorBase<V, SIZE, D1, D2> const & l)
{
typename NumericTraits<V>::Promote res = l[0];
for(int k=1; k<SIZE; ++k)
res += l[k];
return res;
}
/// cumulative sum of the vector's elements
template <class V, int SIZE, class D1, class D2>
inline
TinyVector<typename NumericTraits<V>::Promote, SIZE>
cumsum(TinyVectorBase<V, SIZE, D1, D2> const & l)
{
TinyVector<typename NumericTraits<V>::Promote, SIZE> res(l);
for(int k=1; k<SIZE; ++k)
res[k] += res[k-1];
return res;
}
/// product of the vector's elements
template <class V, int SIZE, class D1, class D2>
inline
typename NumericTraits<V>::Promote
prod(TinyVectorBase<V, SIZE, D1, D2> const & l)
{
typename NumericTraits<V>::Promote res = l[0];
for(int k=1; k<SIZE; ++k)
res *= l[k];
return res;
}
/// cumulative sum of the vector's elements
template <class V, int SIZE, class D1, class D2>
inline
TinyVector<typename NumericTraits<V>::Promote, SIZE>
cumprod(TinyVectorBase<V, SIZE, D1, D2> const & l)
{
TinyVector<typename NumericTraits<V>::Promote, SIZE> res(l);
for(int k=1; k<SIZE; ++k)
res[k] *= res[k-1];
return res;
}
/// element-wise minimum
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline
TinyVector<typename PromoteTraits<V1, V2>::Promote, SIZE>
min(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
TinyVector<typename PromoteTraits<V1, V2>::Promote, SIZE> res(l);
for(int k=0; k<SIZE; ++k)
if(r[k] < res[k])
res[k] = r[k];
return res;
}
/// element-wise maximum
template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4>
inline
TinyVector<typename PromoteTraits<V1, V2>::Promote, SIZE>
max(TinyVectorBase<V1, SIZE, D1, D2> const & l,
TinyVectorBase<V2, SIZE, D3, D4> const & r)
{
TinyVector<typename PromoteTraits<V1, V2>::Promote, SIZE> res(l);
for(int k=0; k<SIZE; ++k)
if(res[k] < r[k])
res[k] = r[k];
return res;
}
/// squared norm /// squared norm
template <class V1, int SIZE, class D1, class D2> template <class V1, int SIZE, class D1, class D2>
inline inline
typename TinyVectorBase<V1, SIZE, D1, D2>::SquaredNormType typename TinyVectorBase<V1, SIZE, D1, D2>::SquaredNormType
squaredNorm(TinyVectorBase<V1, SIZE, D1, D2> const & t) squaredNorm(TinyVectorBase<V1, SIZE, D1, D2> const & t)
{ {
return t.squaredMagnitude(); return t.squaredMagnitude();
} }
/// squared norm /// squared norm
 End of changes. 12 change blocks. 
7 lines changed or deleted 110 lines changed or added


 transformimage.hxx   transformimage.hxx 
skipping to change at line 44 skipping to change at line 44
/************************************************************************/ /************************************************************************/
#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"
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 131 skipping to change at line 132
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="transformimage_8hxx-source.html">vigra/tran sformimage.hxx</a>\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <cmath> // for sqrt() #include <cmath> // for sqrt()
vigra::transformImage(srcImageRange(src), vigra::transformImage(srcImageRange(src),
destImage(dest), destImage(dest),
(double(*)(double))&std::sqrt ); (double(*)(double))&std::sqrt );
skipping to change at line 204 skipping to change at line 205
/********************************************************/ /********************************************************/
/* */ /* */
/* 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).
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 vlaue 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 arguments explicitly:
skipping to change at line 247 skipping to change at line 248
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><br> <b>\#include</b> \<vigra/transformimage.hxx\><br>
Namespace: vigra Namespace: vigra
\code \code
#include <cmath> // for sqrt() #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 );
skipping to change at line 364 skipping to change at line 365
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
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="transformimage_8hxx-source.html">vigra/tran sformimage.hxx</a>\> <b>\#include</b> \<vigra/transformimage.hxx\>
\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>
skipping to change at line 640 skipping to change at line 641
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> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><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
vigra::transformImage(srcImageRange(src), destImage(dest), vigra::transformImage(srcImageRange(src), destImage(dest),
linearIntensityTransform( linearIntensityTransform(
255.0 / (minmax.max - minmax.min), // scaling 255.0 / (minmax.max - minmax.min), // scaling
- minmax.min)); // offset - minmax.min)); // offset
\endcode \endcode
The one-parameter version can be used like this: The one-parameter version can be used like this:
\code \code
// scale from 0..255 to 0..1.0 // scale from 0..255 to 0..1.0
FImage dest(src.size()); FImage dest(src.size());
vigra::transformImage(srcImageRange(src), destImage(dest), vigra::transformImage(srcImageRange(src), destImage(dest),
linearIntensityTransform<float>(1.0 / 255)); linearIntensityTransform<float>(1.0 / 255));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
The source and destination value types must be models of \ref LinearSpa ce in both cases. The source and destination value types must be models of \ref LinearSpa ce in both cases.
*/ */
skipping to change at line 702 skipping to change at line 703
/** \brief Map a source intensity range linearly to a destination range. /** \brief Map a source intensity range linearly to a destination range.
Factory function for a functor that linearly transforms the Factory function for a functor that linearly transforms the
source pixel values. The functor applies the transform source pixel values. The functor applies the transform
'<TT>destvalue = scale * (srcvalue + offset)</TT>' to every pixel, '<TT>destvalue = scale * (srcvalue + offset)</TT>' to every pixel,
where <tt>scale = (dest_max - dest_min) / (src_max - src_min)</tt> where <tt>scale = (dest_max - dest_min) / (src_max - src_min)</tt>
and <tt>offset = dest_min / scale - src_min</tt>. As a result, and <tt>offset = dest_min / scale - src_min</tt>. As a result,
the pixel values <tt>src_max</tt>, <tt>src_min</tt> in the source image the pixel values <tt>src_max</tt>, <tt>src_min</tt> in the source image
are mapped onto <tt>dest_max</tt>, <tt>dest_min</tt> respectively. are mapped onto <tt>dest_max</tt>, <tt>dest_min</tt> respectively.
This works for scalar as well as vector pixel types. This works for scalar as well as vector pixel types. Instead of
<tt>src_min</tt> and <tt>src_max</tt>, you may also pass a functor
\ref FindMinMax.
<b> Declaration:</b> <b> Declaration:</b>
\code \code
namespace vigra { namespace vigra {
template <class SrcValueType, class DestValueType> template <class SrcValueType, class DestValueType>
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 ) ;
template <class SrcValueType, class DestValueTyp
e>
LinearIntensityTransform<DestValueType, typename NumericTraits<Dest
ValueType>::RealPromote>
linearRangeMapping(SrcValueType src_min, SrcValueType src_max,
DestValueType dest_min, DestValueType dest_max )
;
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><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
vigra::transformImage(srcImageRange(src), destImage(dest), vigra::transformImage(srcImageRange(src), destImage(dest),
linearRangeTransform( linearRangeMapping(
minmax.min, minmax.max, // src ra minmax.min, minmax.max, // src range
nge 0, 255) // dest range
(unsigned char)0, (unsigned char)255) // dest r );
ange
// equivalent, but shorter
vigra::transformImage(srcImageRange(src), destImage(dest),
linearRangeMapping(
minmax, // src range
0, 255) // dest range
); );
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
The source and destination value types must be models of \ref LinearSpa ce in both cases. The source and destination value types must be models of \ref LinearSpa ce in both cases.
*/ */
template <class SrcValueType, class DestValueType> template <class SrcValueType, class DestValueType>
LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueTyp e>::RealPromote> LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueTyp e>::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 )
{ {
return linearRangeMapping(src_min, src_max, dest_min, dest_max, return linearRangeMapping(src_min, src_max, dest_min, dest_max,
typename NumericTraits<DestValueType>::isScalar()); typename NumericTraits<DestValueType>::isScalar());
} }
template <class SrcValueType, class DestValueType> template <class SrcValueType, class DestValueType>
LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueTyp e>::RealPromote> LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueTyp e>::RealPromote>
linearRangeMapping(FindMinMax<SrcValueType> const & src,
DestValueType dest_min, DestValueType dest_max )
{
return linearRangeMapping(src.min, src.max, dest_min, dest_max,
typename NumericTraits<DestValueType>::isScalar());
}
template <class SrcValueType, class DestValueType>
LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueTyp
e>::RealPromote>
linearRangeMapping( linearRangeMapping(
SrcValueType src_min, SrcValueType src_max, SrcValueType src_min, SrcValueType src_max,
DestValueType dest_min, DestValueType dest_max, DestValueType dest_min, DestValueType dest_max,
VigraTrueType /* isScalar */ ) VigraTrueType /* isScalar */ )
{ {
typedef typename NumericTraits<DestValueType>::RealPromote Multiplier; typedef typename NumericTraits<DestValueType>::RealPromote Multiplier;
Multiplier diff = src_max - src_min; Multiplier diff = src_max - src_min;
Multiplier scale = diff == NumericTraits<Multiplier>::zero() Multiplier scale = diff == NumericTraits<Multiplier>::zero()
? NumericTraits<Multiplier>::one() ? NumericTraits<Multiplier>::one()
: (dest_max - dest_min) / diff; : (dest_max - dest_min) / diff;
skipping to change at line 797 skipping to change at line 821
/********************************************************/ /********************************************************/
/* */ /* */
/* Threshold */ /* Threshold */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Threshold an image. /** \brief Threshold an image.
If a source pixel is above or equal the lower and below If a source pixel is above or equal the lower and below
or equal the higher threshold (i.e. within the closed interval or equal the higher threshold (i.e. within the closed interval
[lower, heigher]) 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> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><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));
skipping to change at line 921 skipping to change at line 945
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> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><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);
... ...
vigra::FindMinmax<float> minmax; vigra::FindMinMax<float> minmax;
vigra::inspectImage(srcImageRange(fimage), minmax); vigra::inspectImage(srcImageRange(fimage), minmax);
vigra::transformImage(srcImageRange(fimage), destImage(fimage), vigra::transformImage(srcImageRange(fimage), destImage(fimage),
vigra::BrightnessContrastFunctor<float>(brightness, contrast, minmax .min, minmax.max)); vigra::BrightnessContrastFunctor<float>(brightness, contrast, minmax .min, minmax.max));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
Scalar types: must be a linear algebra (+, - *, NumericTraits), Scalar types: must be a linear algebra (+, - *, NumericTraits),
skipping to change at line 1183 skipping to change at line 1207
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> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><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);
... ...
vigra::FindMinmax<float> minmax; vigra::FindMinMax<float> minmax;
vigra::inspectImage(srcImageRange(fimage), minmax); vigra::inspectImage(srcImageRange(fimage), minmax);
vigra::transformImage(srcImageRange(fimage), destImage(fimage), vigra::transformImage(srcImageRange(fimage), destImage(fimage),
vigra::GammaFunctor<float>(gamma, minmax.min, minmax.max)); vigra::GammaFunctor<float>(gamma, minmax.min, minmax.max));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
Scalar types: must be a linear algebra (+, - *, NumericTraits), Scalar types: must be a linear algebra (+, - *, NumericTraits),
skipping to change at line 1416 skipping to change at line 1440
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> \<<a href="transformimage_8hxx-source.html">vigra/ transformimage.hxx</a>\><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>()
); );
 End of changes. 20 change blocks. 
22 lines changed or deleted 48 lines changed or added


 tuple.hxx   tuple.hxx 
skipping to change at line 47 skipping to change at line 47
#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> \<<a href="utilities_8hxx-source.html">vigra/utilities .hxx</a>\><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:
<ul> <ul>
<li> They are parameterized by the respective number of types. For each tuple, <li> They are parameterized by the respective number of types. For each tuple,
a constructor is defined that takes that many arguments, e.g.: a constructor is defined that takes that many arguments, e.g.:
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 utilities.hxx   utilities.hxx 
skipping to change at line 81 skipping to change at line 81
VIGRA_AS_STRING(unsigned long long) VIGRA_AS_STRING(unsigned long long)
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
} // namespace std template <class T>
std::string & operator<<(std::string & s, T const & t)
{
std::stringstream ss;
ss << t;
return s += ss.str();
}
} // namespace vigra
/*! \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</em> <BR>&nbsp;&nbsp;&nbsp;<em>replacement for std::vector (always uses
consecutive memory)</em>
<LI> \ref vigra::BucketQueue and \ref vigra::MappedBucketQueue
<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-dimensional positions, extents, and re ctangles</em> <BR>&nbsp;&nbsp;&nbsp;<em>2-D and N-D positions, extents, and boxe s</em>
<LI> \ref PixelNeighborhood <LI> \ref PixelNeighborhood
<BR>&nbsp;&nbsp;&nbsp;<em>4- and 8-neighborhood definitions and ci rculators</em> <BR>&nbsp;&nbsp;&nbsp;<em>4- and 8-neighborhood definitions and ci rculators</em>
<LI> \ref VoxelNeighborhood
<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
<BR>&nbsp;&nbsp;&nbsp;<em>Macros for taking execution speed measur
ements</em>
</UL> </UL>
*/ */
#endif // VIGRA_BASICS_HXX #endif // VIGRA_BASICS_HXX
 End of changes. 5 change blocks. 
3 lines changed or deleted 21 lines changed or added


 voxelneighborhood.hxx   voxelneighborhood.hxx 
skipping to change at line 48 skipping to change at line 48
#include "tinyvector.hxx" #include "tinyvector.hxx"
#include "pixelneighborhood.hxx" #include "pixelneighborhood.hxx"
namespace vigra { namespace vigra {
/** \addtogroup VoxelNeighborhood Utilities to manage voxel neighborhoods /** \addtogroup VoxelNeighborhood Utilities to manage voxel neighborhoods
6- and 26-neighborhood definitions and circulators. 6- and 26-neighborhood definitions and circulators.
<b>\#include</b> \<<a href="voxelneighborhood_8hxx-source.html">vigra/v oxelneighborhood.hxx</a>\><br> <b>\#include</b> \<vigra/voxelneighborhood.hxx\><br>
<b>See also:</b> \ref vigra::NeighborhoodCirculator <b>See also:</b> \ref vigra::NeighborhoodCirculator
*/ */
//@{ //@{
/// 3-dimensional difference vector /// 3-dimensional difference vector
typedef vigra::TinyVector<int, 3> Diff3D; typedef vigra::TinyVector<int, 3> Diff3D;
/********************************************************/ /********************************************************/
/* */ /* */
/* AtVolumeBorder */ /* AtVolumeBorder */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Encode whether a voxel is near the volume border. /** \brief Encode whether a voxel is near the volume border.
// This enum is used with \ref isAtVolumeBorder() and // This enum is used with \ref isAtVolumeBorder() and
// \ref vigra::RestrictedNeighborhoodCirculator. // \ref vigra::RestrictedNeighborhoodCirculator.
//<b>\#include</b> \<<a href="voxelneighborhood_8hxx-source.html">v igra/voxelneighborhood.hxx</a>\><br> //<b>\#include</b> \<vigra/voxelneighborhood.hxx\><br>
//Namespace: vigra //Namespace: vigra
*/ */
typedef AtImageBorder AtVolumeBorder; typedef AtImageBorder AtVolumeBorder;
/** \brief Find out whether a voxel is at the volume border. /** \brief Find out whether a voxel is at the volume border.
This function checks if \a x == 0 or \a x == \a width - 1 and This function checks if \a x == 0 or \a x == \a width - 1 and
\a y == 0 or \a y == \a height - 1 and so on and returns the appropriat e value \a y == 0 or \a y == \a height - 1 and so on and returns the appropriat e value
of \ref vigra::AtVolumeBorder, or zero when the voxel is not at te volu me border. of \ref vigra::AtVolumeBorder, or zero when the voxel is not at te volu me border.
skipping to change at line 111 skipping to change at line 111
{ {
return isAtVolumeBorder(p[0], p[1], p[2], shape[0], shape[1], shape[2]) ; return isAtVolumeBorder(p[0], p[1], p[2], shape[0], shape[1], shape[2]) ;
} }
/** \brief Find out whether a voxel is at a scan-order relevant volume bord er. /** \brief Find out whether a voxel is at a scan-order relevant volume bord er.
This function checks if \a x == 0 or \a y == 0 or \a z == \a 0 and retu rns the This function checks if \a x == 0 or \a y == 0 or \a z == \a 0 and retu rns the
appropriate value of \ref vigra::AtVolumeBorder, or zero when the v oxel is appropriate value of \ref vigra::AtVolumeBorder, or zero when the v oxel is
not at te volume border. not at te volume border.
The behavior of the function is undefined if (x,y,z) is not inside the volume. The behavior of the function is undefined if (x,y,z) is not inside the volume.
*/ */
inline AtVolumeBorder isAtVolumeBorderCausal(int x, int y, int z, int /* wi dth */, int /* height */, int /* depth */) inline AtVolumeBorder isAtVolumeBorderCausal(int x, int y, int z, int width , int height, int /* depth */)
{ {
return static_cast<AtVolumeBorder>((x == 0 return static_cast<AtVolumeBorder>((x == 0
? LeftBorder ? LeftBorder
: NotAtBorder) | : x == width-1
? RightBorder
: NotAtBorder) |
(y == 0 (y == 0
? TopBorder ? TopBorder
: NotAtBorder) | : y == height-1
? BottomBorder
: NotAtBorder) |
(z == 0 (z == 0
? FrontBorder ? FrontBorder
: NotAtBorder)); : NotAtBorder));
} }
/** TODO: Write new comment \brief Find out whether a voxel is at a scan-or der relevant volume border. /** TODO: Write new comment \brief Find out whether a voxel is at a scan-or der relevant volume border.
This function checks if \a x == 0 or \a y == 0 or \a z == \a 0 and retu rns the This function checks if \a x == 0 or \a y == 0 or \a z == \a 0 and retu rns the
appropriate value of \ref vigra::AtVolumeBorder, or zero when the v oxel is appropriate value of \ref vigra::AtVolumeBorder, or zero when the v oxel is
not at te volume border. not at te volume border.
The behavior of the function is undefined if (x,y,z) is not inside the volume. The behavior of the function is undefined if (x,y,z) is not inside the volume.
*/ */
inline AtVolumeBorder isAtVolumeBorderAntiCausal(int x, int y, int z, int w idth, int height, int depth) inline AtVolumeBorder isAtVolumeBorderAntiCausal(int x, int y, int z, int w idth, int height, int depth)
{ {
return static_cast<AtVolumeBorder>((x == width-1 return static_cast<AtVolumeBorder>((x == 0
? RightBorder ? LeftBorder
: NotAtBorder) | : x == width-1
(y == height-1 ? RightBorder
? BottomBorder : NotAtBorder) |
: NotAtBorder) | (y == 0
? TopBorder
: y == height-1
? BottomBorder
: NotAtBorder) |
(z == depth-1 (z == depth-1
? RearBorder ? RearBorder
: NotAtBorder)); : NotAtBorder));
} }
/********************************************************/ /********************************************************/
/* */ /* */
/* Neighborhood3DSix */ /* Neighborhood3DSix */
/* */ /* */
/********************************************************/ /********************************************************/
skipping to change at line 268 skipping to change at line 276
/** 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] = { static Direction c[43][3] = {
{ InFront, North, West}, // 0 - NotAtBorder { InFront, North, West}, // 0 - NotAtBorder
-----> should never be used { InFront, North, West}, // 1 - AtRightBorde
{ InFront, North, West}, // 1 - AtRightBorde r
r -----> should never be used
{ InFront, North, Error}, // 2 - AtLeftBorder { InFront, North, Error}, // 2 - AtLeftBorder
{ Error, Error, Error}, { Error, Error, Error},
{ InFront, West, Error}, // 4 - AtTopBorder { InFront, West, Error}, // 4 - AtTopBorder
{ InFront, West, Error}, // 5 - AtTopRightBo rder { InFront, West, Error}, // 5 - AtTopRightBo rder
{ InFront, Error,Error}, // 6 - AtTopLeftBor der { InFront, Error,Error}, // 6 - AtTopLeftBor der
{ Error, Error, Error}, { Error, Error, Error},
{ InFront, North, West}, // 8 - AtBottomBord { InFront, North, West}, // 8 - AtBottomBord
er -----> should never be used er
{ InFront, North, West}, // 9 - AtBottomRigh { InFront, North, West}, // 9 - AtBottomRigh
tBorder -----> should never be used tBorder
{ InFront, North, Error}, //10- AtBottomLeftB order { InFront, North, Error}, //10- AtBottomLeftB order
{ 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, Error}, //16 - AtFrontBorde r { North, West, Error}, //16 - AtFrontBorde r
{ North, West, Error}, //17 - AtFrontRight Border { North, West, Error}, //17 - AtFrontRight Border
{ North, Error, Error}, //18 - AtFrontLeftB order { North, Error, Error}, //18 - AtFrontLeftB order
{ Error, Error, Error}, { Error, Error, Error},
skipping to change at line 300 skipping to change at line 308
{ Error, Error, Error}, //22 - AtTopLeftFro ntBorder { Error, Error, Error}, //22 - AtTopLeftFro ntBorder
{ Error, Error, Error}, { Error, Error, Error},
{ North, West, Error}, //24 - AtBottomFron tBorder { North, West, Error}, //24 - AtBottomFron tBorder
{ North, West, Error}, //25 - AtBottomRigh tFrontBorder { North, West, Error}, //25 - AtBottomRigh tFrontBorder
{ North, Error, Error}, //26 - AtBottomLeft FrontBorder { North, Error, Error}, //26 - AtBottomLeft FrontBorder
{ 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}, //32 - AtRearBorder { InFront, North, West}, //32 - AtRearBorder
-----> should never be used { InFront, North, West}, //33 - AtRearRightB
{ InFront, North, West}, //33 - AtRearRightB order
order -----> should never be used
{ InFront, North, Error}, //34 - AtRearLeftBo rder { InFront, North, Error}, //34 - AtRearLeftBo rder
{ Error, Error, Error}, { Error, Error, Error},
{ InFront, West, Error}, //36 - AtTopRearBor der { InFront, West, Error}, //36 - AtTopRearBor der
{ InFront, West, Error}, //37 - AtTopRightRe arBorder { InFront, West, Error}, //37 - AtTopRightRe arBorder
{ InFront, Error, Error}, //38 - AtTopLeftRea rBorder { InFront, Error, Error}, //38 - AtTopLeftRea rBorder
{ Error, Error, Error}, { Error, Error, Error},
{ InFront, North, West}, //40 - AtBottomRear { InFront, North, West}, //40 - AtBottomRear
Border -----> should never be used Border
{ InFront, North, West}, //41 - AtBottomRigh { InFront, North, West}, //41 - AtBottomRigh
tRearBorder -----> should never be used tRearBorder
{ InFront, North, Error} //42 - AtBottomLeft RearBorder { InFront, North, Error} //42 - AtBottomLeft RearBorder
}; };
return c[b][index]; 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)
{ {
skipping to change at line 1034 skipping to change at line 1042
static Direction nearBorderDirectionsCausal(AtVolumeBorder b, int index ) static Direction nearBorderDirectionsCausal(AtVolumeBorder b, int index )
{ {
static Direction c[43][13] = { static Direction c[43][13] = {
//0 - NotAtBorder -----> should never be used //0 - NotAtBorder -----> should never be used
{ InFrontNorthWest, InFrontNorth, InFron tNorthEast, { InFrontNorthWest, InFrontNorth, InFron tNorthEast,
InFrontWest, InFront, InFron tEast, InFrontWest, InFront, InFron tEast,
InFrontSouthWest, InFrontSouth, InFron tSouthEast, InFrontSouthWest, InFrontSouth, InFron tSouthEast,
NorthWest, North, NorthE ast, NorthWest, North, NorthE ast,
West}, West},
//1 - AtRightBorder -----> should never be used //1 - AtRightBorder
{ InFrontNorthWest, InFrontNorth, InFron { InFrontNorthWest, InFrontNorth, /* InF
tNorthEast, rontNorthEast, */
InFrontWest, InFront, InFron InFrontWest, InFront, /* InF
tEast, rontEast, */
InFrontSouthWest, InFrontSouth, InFron InFrontSouthWest, InFrontSouth, /* InF
tSouthEast, rontSouthEast, */
NorthWest, North, NorthE NorthWest, North, /* Nor
ast, thEast, */
West}, West,
Error, Error, Error, Error},
//2 - AtLeftBorder //2 - AtLeftBorder
{ /*InFrontNorthWest,*/ InFrontNorth,InFron tNorthEast, { /*InFrontNorthWest,*/ InFrontNorth,InFron tNorthEast,
/*InFrontWest,*/ InFront, InFron tEast, /*InFrontWest,*/ InFront, InFron tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast, /*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast,
/*NorthWest,*/ North, NorthE ast, /*NorthWest,*/ North, NorthE ast,
/*West*/ /*West*/
Error, Error, Error, Error, Error}, Error, Error, Error, Error, Error},
//3 - Nothin' //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},
skipping to change at line 1077 skipping to change at line 1086
//6 - AtTopLeftBorder //6 - AtTopLeftBorder
{ /*InFrontNorthWest,InFrontNorth, InFro ntNorthEast,*/ { /*InFrontNorthWest,InFrontNorth, InFro ntNorthEast,*/
/*InFrontWest,*/ InFront, InFro ntEast, /*InFrontWest,*/ InFront, InFro ntEast,
/*InFrontSouthWest,*/InFrontSouth, InFro ntSouthEast, /*InFrontSouthWest,*/InFrontSouth, InFro ntSouthEast,
/*NorthWest, North, North East,*/ /*NorthWest, North, North East,*/
/*West,*/ /*West,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error}, Error, Error, Error, Error, Error, Error, Error, Error, Error},
//7 - Nothin' //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 -----> should never be used //8 - AtBottomBorder
{ InFrontNorthWest, InFrontNorth, InFro ntNorthEast, { InFrontNorthWest, InFrontNorth, InFro ntNorthEast,
InFrontWest, InFront, InFro ntEast, InFrontWest, InFront, InFro ntEast,
InFrontSouthWest, InFrontSouth, InFro ntSouthEast, /* InFrontSouthWest, InFrontSouth, In FrontSouthEast, */
NorthWest, North, North East, NorthWest, North, North East,
West}, West,
//9 - AtBottomRightBorder -----> should never be used Error, Error, Error},
{ InFrontNorthWest, InFrontNorth, InFron //9 - AtBottomRightBorder
tNorthEast, { InFrontNorthWest, InFrontNorth, /* InF
InFrontWest, InFront, InFron rontNorthEast, */
tEast, InFrontWest, InFront, /* InF
InFrontSouthWest, InFrontSouth, InFron rontEast, */
tSouthEast, /* InFrontSouthWest, InFrontSouth, InF
rontSouthEast, */
NorthWest, North, NorthE NorthWest, North, /* Nor
ast, thEast, */
West}, West,
Error, Error, Error,Error, Error, Error},
//10 - AtBottomLeftBorder //10 - AtBottomLeftBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFron tNorthEast, { /*InFrontNorthWest,*/InFrontNorth, InFron tNorthEast,
/*InFrontWest,*/ InFront, InFron tEast, /*InFrontWest,*/ InFront, InFron tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast, /*InFrontSouthWest, InFrontSouth, InFront SouthEast, */
/*NorthWest,*/ North, NorthE ast, /*NorthWest,*/ North, NorthE ast,
/*West*/ /*West*/
Error, Error, Error, Error, Error}, Error, Error, Error, Error, Error, Error, Error},
//11 - Nothin' //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' //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' //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' //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' //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},
skipping to change at line 1177 skipping to change at line 1188
NorthWest, North, /*Nort hEast,*/ NorthWest, North, /*Nort hEast,*/
West, West,
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error}, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error},
//26 - AtBottomLeftFrontBorder //26 - AtBottomLeftFrontBorder
{ /*InFrontNorthWest, InFrontNorth, InFron tNorthEast, { /*InFrontNorthWest, InFrontNorth, InFron tNorthEast,
InFrontWest, InFront, InFron tEast, InFrontWest, InFront, InFron tEast,
InFrontSouthWest, InFrontSouth, InFron tSouthEast,*/ InFrontSouthWest, InFrontSouth, InFron tSouthEast,*/
/*NorthWest,*/ North, NorthE ast, /*NorthWest,*/ North, NorthE ast,
West, /* West, */
Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error,
Error, Error, Error, Error}, Error, Error, Error, Error, Error},
//27 - Nothin //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 //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 //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 //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 //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 -----> should never be used //32 - AtRearBorder
{ InFrontNorthWest, InFrontNorth, InFron tNorthEast, { InFrontNorthWest, InFrontNorth, InFron tNorthEast,
InFrontWest, InFront, InFron tEast, InFrontWest, InFront, InFron tEast,
InFrontSouthWest, InFrontSouth, InFron tSouthEast, InFrontSouthWest, InFrontSouth, InFron tSouthEast,
NorthWest, North, NorthE ast, NorthWest, North, NorthE ast,
West}, West},
//33 - AtRearRightBorder -----> should never be used //33 - AtRearRightBorder
{ InFrontNorthWest, InFrontNorth, InFron tNorthEast, { InFrontNorthWest, InFrontNorth, InFron tNorthEast,
InFrontWest, InFront, InFron tEast, InFrontWest, InFront, InFron tEast,
InFrontSouthWest, InFrontSouth, InFron tSouthEast, InFrontSouthWest, InFrontSouth, InFron tSouthEast,
NorthWest, North, NorthE ast, NorthWest, North, NorthE ast,
West}, West},
//34 - AtRearLeftBorder //34 - AtRearLeftBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFron tNorthEast, { /*InFrontNorthWest,*/InFrontNorth, InFron tNorthEast,
/*InFrontWest,*/ InFront, InFron tEast, /*InFrontWest,*/ InFront, InFron tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast, /*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast,
skipping to change at line 1239 skipping to change at line 1250
//38 - AtTopLeftRearBorder //38 - AtTopLeftRearBorder
{ /*InFrontNorthWest, InFrontNorth, InFron tNorthEast,*/ { /*InFrontNorthWest, InFrontNorth, InFron tNorthEast,*/
/*InFrontWest,*/ InFront, InFron tEast, /*InFrontWest,*/ InFront, InFron tEast,
/*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast, /*InFrontSouthWest,*/InFrontSouth, InFron tSouthEast,
/*NorthWest, North, NorthEast,*/ /*NorthWest, North, NorthEast,*/
/*West,*/ /*West,*/
Error, Error, Error, Error, Error, Error, Error, Error, Error}, Error, Error, Error, Error, Error, Error, Error, Error, Error},
//39 - Nothin //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 -----> should never be used //40 - AtBottomRearBorder
{ InFrontNorthWest, InFrontNorth, InFron tNorthEast, { InFrontNorthWest, InFrontNorth, InFron tNorthEast,
InFrontWest, InFront, InFron tEast, InFrontWest, InFront, InFron tEast,
InFrontSouthWest, InFrontSouth, InFron tSouthEast, InFrontSouthWest, InFrontSouth, InFron tSouthEast,
NorthWest, North, NorthE ast, NorthWest, North, NorthE ast,
West}, West},
//41 - AtBottomRightRearBorder -----> should never be used //41 - AtBottomRightRearBorder
{ InFrontNorthWest, InFrontNorth, InFron tNorthEast, { InFrontNorthWest, InFrontNorth, InFron tNorthEast,
InFrontWest, InFront, InFron tEast, InFrontWest, InFront, InFron tEast,
InFrontSouthWest, InFrontSouth, InFron tSouthEast, InFrontSouthWest, InFrontSouth, InFron tSouthEast,
NorthWest, North, NorthE ast, NorthWest, North, NorthE ast,
West}, West},
//42 - AtBottomLeftRearBorder //42 - AtBottomLeftRearBorder
{ /*InFrontNorthWest,*/InFrontNorth, InFron tNorthEast, { /*InFrontNorthWest,*/InFrontNorth, InFron tNorthEast,
/*InFrontWest,*/ InFront, InFron tEast, /*InFrontWest,*/ InFront, InFron tEast,
/*InFrontSouthWest,InFrontSouth, InFron tSouthEast,*/ /*InFrontSouthWest,InFrontSouth, InFron tSouthEast,*/
 End of changes. 23 change blocks. 
59 lines changed or deleted 68 lines changed or added


 watersheds.hxx   watersheds.hxx 
skipping to change at line 43 skipping to change at line 43
/* */ /* */
/************************************************************************/ /************************************************************************/
#ifndef VIGRA_WATERSHEDS_HXX #ifndef VIGRA_WATERSHEDS_HXX
#define VIGRA_WATERSHEDS_HXX #define VIGRA_WATERSHEDS_HXX
#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 "labelimage.hxx"
#include "seededregiongrowing.hxx"
#include "functorexpression.hxx"
#include "union_find.hxx" #include "union_find.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,
skipping to change at line 151 skipping to change at line 155
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[da(xd)], xd);
} }
} }
return count; return count;
} }
template <class SrcIterator, class SrcAccessor, template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood>
unsigned int watershedLabeling(triple<SrcIterator, SrcIterator, SrcAccessor
> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood)
{
return watershedLabeling(src.first, src.second, src.third,
dest.first, dest.second, neighborhood);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor> class DestIterator, class DestAccessor>
void prepareWatersheds(SrcIterator upperlefts, SrcIterator lowerrights, Src Accessor sa, void prepareWatersheds(SrcIterator upperlefts, SrcIterator lowerrights, Src Accessor sa,
DestIterator upperleftd, DestAccessor da, DestIterator upperleftd, DestAccessor da,
FourNeighborCode) FourNeighborCode)
{ {
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);
skipping to change at line 297 skipping to change at line 312
da.set(o, xd); da.set(o, xd);
} }
} }
} }
/** \addtogroup SeededRegionGrowing Region Segmentation Algorithms /** \addtogroup SeededRegionGrowing Region Segmentation Algorithms
Region growing, watersheds, and voronoi tesselation Region growing, watersheds, and voronoi tesselation
*/ */
//@{ //@{
/**\brief Options object for generateWatershedSeeds().
*
<b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br>
Namespace: vigra
\code
IImage seeds(boundary_indicator.size());
// detect all minima in 'boundary_indicator' that are below gray le
vel 22
generateWatershedSeeds(srcImageRange(boundary_indicator),
destImage(seeds),
SeedOptions().minima().threshold(22.0));
\endcode
*/
class SeedOptions
{
public:
enum DetectMinima { LevelSets, Minima, ExtendedMinima, Unspecified };
double thresh;
DetectMinima mini;
/**\brief Construct default options object.
*
Defaults are: detect minima without thresholding (i.e. all mini
ma).
*/
SeedOptions()
: thresh(NumericTraits<double>::max()),
mini(Minima)
{}
/** Generate seeds at minima.
Default: true
*/
SeedOptions & minima()
{
mini = Minima;
return *this;
}
/** Generate seeds at minima and minimal plateaus.
Default: false
*/
SeedOptions & extendedMinima()
{
mini = ExtendedMinima;
return *this;
}
/** Generate seeds as level sets.
Note that you must also set a threshold to define which level s
et is to be used.<br>
Default: false
*/
SeedOptions & levelSets()
{
mini = LevelSets;
return *this;
}
/** Generate seeds as level sets at given threshold.
Equivalent to <tt>SeedOptions().levelSet().threshold(threshold)
</tt><br>
Default: false
*/
SeedOptions & levelSets(double threshold)
{
mini = LevelSets;
thresh = threshold;
return *this;
}
/** Set threshold.
The threshold will be used by both the minima and level set var
iants
of seed generation.<br>
Default: no thresholding
*/
SeedOptions & threshold(double threshold)
{
thresh = threshold;
return *this;
}
// check whether the threshold has been set for the target type T
template <class T>
bool thresholdIsValid() const
{
return thresh < double(NumericTraits<T>::max());
}
// indicate that this option object is invalid (for internal use in
watersheds)
SeedOptions & unspecified()
{
mini = Unspecified;
return *this;
}
};
/** \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
eds)
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood>
unsigned int
generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrights, Src
Accessor sa,
DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood,
SeedOptions const & options = SeedOptions())
{
using namespace functor;
typedef typename SrcAccessor::value_type SrcType;
vigra_precondition(options.mini != SeedOptions::LevelSets ||
options.thresholdIsValid<SrcType>(),
"generateWatershedSeeds(): SeedOptions.levelSets() must be specifie
d with threshold.");
Diff2D shape = lowerrights - upperlefts;
BImage seeds(shape);
if(options.mini == SeedOptions::LevelSets)
{
transformImage(srcIterRange(upperlefts, lowerrights, sa),
destImage(seeds),
ifThenElse(Arg1() <= Param(options.thresh), Param(1)
, Param(0)));
}
else
{
localMinima(srcIterRange(upperlefts, lowerrights, sa), destImage(se
eds),
LocalMinmaxOptions().neighborhood(Neighborhood::DirectionCount)
.markWith(1.0)
.threshold(options.thresh)
.allowAtBorder()
.allowPlateaus(options.mini == SeedOptions:
:ExtendedMinima));
}
return labelImageWithBackground(srcImageRange(seeds), destIter(upperlef
td, da),
Neighborhood::DirectionCount == 8, 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);
}
/********************************************************/ /********************************************************/
/* */ /* */
/* watersheds */ /* watersheds */
/* */ /* */
/********************************************************/ /********************************************************/
/** \brief Region Segmentation by means of the watershed algorithm. /** \brief Region segmentation by means of the union-find watershed algorit hm.
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 gorithms, J. Roerdink, R. Meijster: "<em>The watershed transform: definitions, al gorithms,
and parallelization stretegies</em>", Fundamenta Informaticae, 41:187-2 28, 2000 and parallelization strategies</em>", Fundamenta Informaticae, 41:187-2 28, 2000
The source image is a boundary indicator such as the gradient magnitude The source image is a boundary indicator such as the gaussianGradientMa
of the trace of the \ref boundaryTensor(). Local minima of the boundary gnitude()
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 implementaion of the watershed Note that VIGRA provides an alternative implementation of the watershed
transform via transform via
\ref seededRegionGrowing(). It is slower, but handles plateaus better \ref watershedsRegionGrowing(). It is slower, but offers many more conf
and allows to keep a one pixel wide boundary between regions. iguration options.
<b> Declarations:</b> <b> Declarations:</b>
pass arguments explicitly: pass arguments explicitly:
\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
watersheds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAcce watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights
ssor sa, , 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
watersheds(triple<SrcIterator, SrcIterator, SrcAccessor> src, watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> s
pair<DestIterator, DestAccessor> dest, rc,
Neighborhood neighborhood = EightNeighborCode()) pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood = EightNeighborCode()
)
} }
\endcode \endcode
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="watersheds_8hxx-source.html">vigra/watershe ds.hxx</a>\><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
vigra::BImage in(w,h); vigra::BImage in(w,h);
... // read input data ... // read input data
vigra::FImage gradx(x,y), grady(x,y), gradMag(x,y); // compute gradient magnitude as boundary indicator
gaussianGradient(srcImageRange(src), destImage(gradx), destImage(grady) vigra::FImage gradMag(w, h);
, 3.0); gaussianGradientMagnitude(srcImageRange(src), destImage(gradMag), 3.0);
combineTwoImages(srcImageRange(gradx), srcImage(grady), destImage(gradM
ag),
vigra::MagnitudeFunctor<float>());
// 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(x,y); vigra::IImage labeling(w,h);
int max_region_label = watersheds(srcImageRange(gradMag), destImage(lab int max_region_label = watershedsUnionFind(srcImageRange(gradMag), dest
eling)); Image(labeling));
\endcode \endcode
<b> Required Interface:</b> <b> Required Interface:</b>
\code \code
SrcImageIterator src_upperleft, src_lowerright; SrcIterator src_upperleft, src_lowerright;
DestImageIterator 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
*/ */
doxygen_overloaded_function(template <...> unsigned int watersheds) 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
watersheds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAccessor sa, watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights, SrcAcc
DestIterator upperleftd, DestAccessor da, Neighborhood neighborh essor sa,
ood) DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood)
{ {
SImage orientationImage(lowerrights - upperlefts); SImage orientationImage(lowerrights - upperlefts);
SImage::traverser yo = orientationImage.upperLeft(); SImage::traverser yo = orientationImage.upperLeft();
prepareWatersheds(upperlefts, lowerrights, sa, prepareWatersheds(upperlefts, lowerrights, sa,
orientationImage.upperLeft(), orientationImage.accesso r(), neighborhood); orientationImage.upperLeft(), orientationImage.accesso r(), neighborhood);
return watershedLabeling(orientationImage.upperLeft(), orientationImage .lowerRight(), orientationImage.accessor(), return watershedLabeling(orientationImage.upperLeft(), orientationImage .lowerRight(), orientationImage.accessor(),
upperleftd, da, neighborhood); upperleftd, da, 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
watersheds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAccessor sa, watershedsUnionFind(SrcIterator upperlefts, SrcIterator lowerrights, SrcAcc essor sa,
DestIterator upperleftd, DestAccessor da) DestIterator upperleftd, DestAccessor da)
{ {
return watersheds(upperlefts, lowerrights, sa, upperleftd, da, EightNei ghborCode()); 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
watersheds(triple<SrcIterator, SrcIterator, SrcAccessor> src, watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest, Neighborhood neighborhood ) pair<DestIterator, DestAccessor> dest, Neighborhood neighborhood )
{ {
return watersheds(src.first, src.second, src.third, dest.first, dest.se return watershedsUnionFind(src.first, src.second, src.third,
cond, 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
watersheds(triple<SrcIterator, SrcIterator, SrcAccessor> src, watershedsUnionFind(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest) pair<DestIterator, DestAccessor> dest)
{ {
return watersheds(src.first, src.second, src.third, dest.first, dest.se return watershedsUnionFind(src.first, src.second, src.third,
cond); dest.first, dest.second);
}
/** \brief Options object for watershedsRegionGrowing().
<b> Usage:</b>
see watershedsRegionGrowing() for detailed examples.
*/
class WatershedOptions
{
public:
double max_cost, bias;
SRGType terminate;
unsigned int biased_label, bucket_count;
SeedOptions seed_options;
/** \brief Create options object with default settings.
Defaults are: perform complete grow (all pixels are assigned to
regions),
use standard algorithm, assume that the destination image alrea
dy contains
region seeds.
*/
WatershedOptions()
: max_cost(0.0),
bias(1.0),
terminate(CompleteGrow),
biased_label(0),
bucket_count(0),
seed_options(SeedOptions().unspecified())
{}
/** \brief Perform complete grow.
That is, all pixels are assigned to regions, without explicit c
ontours
in between.
Default: true
*/
WatershedOptions & completeGrow()
{
terminate = SRGType(CompleteGrow | (terminate & StopAtThreshold));
return *this;
}
/** \brief Keep one-pixel wide contour between regions.
Note that this option is unsupported by the turbo algorithm.
Default: false
*/
WatershedOptions & keepContours()
{
terminate = SRGType(KeepContours | (terminate & StopAtThreshold));
return *this;
}
/** \brief Set \ref SRGType explicitly.
Default: CompleteGrow
*/
WatershedOptions & srgType(SRGType type)
{
terminate = type;
return *this;
}
/** \brief Stop region growing when the boundaryness exceeds the th
reshold.
This option may be combined with completeGrow() and keepContour
s().
Default: no early stopping
*/
WatershedOptions & stopAtThreshold(double threshold)
{
terminate = SRGType(terminate | StopAtThreshold);
max_cost = threshold;
return *this;
}
/** \brief Use a simpler, but faster region growing algorithm.
The algorithm internally uses a \ref BucketQueue to determine
the processing order of the pixels. This is only useful,
when the input boundary indicator image contains integers
in the range <tt>[0, ..., bucket_count-1]</tt>. Since
these boundary indicators are typically represented as
UInt8 images, the default <tt>bucket_count</tt> is 256.
Default: don't use the turbo algorithm
*/
WatershedOptions & turboAlgorithm(unsigned int bucket_count = 256)
{
this->bucket_count = bucket_count;
return *this;
}
/** \brief Specify seed options.
In this case, watershedsRegionGrowing() assumes that the destin
ation
image does not yet contain seeds. It will therefore call
generateWatershedSeeds() and pass on the seed options.
Default: don't compute seeds (i.e. assume that destination imag
e already
contains seeds).
*/
WatershedOptions & seedOptions(SeedOptions const & s)
{
seed_options = s;
return *this;
}
/** \brief Bias the cost of the specified region by the given facto
r.
In certain applications, one region (typically the background)
should
be preferred in region growing. This is most easily achieved
by adjusting the assignment cost for that region as <tt>factor*
cost</tt>,
with a factor slightly below 1.
Default: don't bias any region.
*/
WatershedOptions & biasLabel(unsigned int label, double factor)
{
biased_label = label;
bias = factor;
return *this;
}
};
namespace detail {
template <class CostType, class LabelType>
class WatershedStatistics
{
public:
typedef SeedRgDirectValueFunctor<CostType> value_type;
typedef value_type & reference;
typedef value_type const & const_reference;
typedef CostType first_argument_type;
typedef LabelType second_argument_type;
typedef LabelType argument_type;
WatershedStatistics()
{}
void resize(unsigned int)
{}
void reset()
{}
/** update regions statistics (do nothing in the watershed algorith
m)
*/
template <class T1, class T2>
void operator()(first_argument_type const &, second_argument_type const
&)
{}
/** ask for maximal index (label) allowed
*/
LabelType maxRegionLabel() const
{ return size() - 1; }
/** ask for array size (i.e. maxRegionLabel() + 1)
*/
LabelType size() const
{ return NumericTraits<LabelType>::max(); }
/** read the statistics functor for a region via its label
*/
const_reference operator[](argument_type label) const
{ return stats; }
/** access the statistics functor for a region via its label
*/
reference operator[](argument_type label)
{ return stats; }
value_type stats;
};
template <class Value>
class SeedRgBiasedValueFunctor
{
public:
double bias;
/* the functor's argument type
*/
typedef Value argument_type;
/* the functor's result type (unused, only necessary for
use of SeedRgDirectValueFunctor in \ref vigra::ArrayOfRegionSta
tistics
*/
typedef Value result_type;
/* the return type of the cost() function
*/
typedef Value cost_type;
SeedRgBiasedValueFunctor(double b = 1.0)
: bias(b)
{}
/* Do nothing (since we need not update region statistics).
*/
void operator()(argument_type const &) const {}
/* Return scaled argument
*/
cost_type cost(argument_type const & v) const
{
return cost_type(bias*v);
}
};
template <class CostType, class LabelType>
class BiasedWatershedStatistics
{
public:
typedef SeedRgBiasedValueFunctor<CostType> value_type;
typedef value_type & reference;
typedef value_type const & const_reference;
typedef CostType first_argument_type;
typedef LabelType second_argument_type;
typedef LabelType argument_type;
BiasedWatershedStatistics(LabelType biasedLabel, double bias)
: biased_label(biasedLabel),
biased_stats(bias)
{}
void resize(unsigned int)
{}
void reset()
{}
/** update regions statistics (do nothing in the watershed algorith
m)
*/
template <class T1, class T2>
void operator()(first_argument_type const &, second_argument_type const
&)
{}
/** ask for maximal index (label) allowed
*/
LabelType maxRegionLabel() const
{ return size() - 1; }
/** ask for array size (i.e. maxRegionLabel() + 1)
*/
LabelType size() const
{ return NumericTraits<LabelType>::max(); }
/** read the statistics functor for a region via its label
*/
const_reference operator[](argument_type label) const
{
return (label == biased_label)
? biased_stats
: stats;
}
/** access the statistics functor for a region via its label
*/
reference operator[](argument_type label)
{
return (label == biased_label)
? biased_stats
: stats;
}
LabelType biased_label;
value_type stats, biased_stats;
};
} // namespace detail
/** \brief Region segmentation by means of a flooding-based watershed algor
ithm.
This function implements variants of the watershed algorithm
described in
L. Vincent and P. Soille: "<em>Watersheds in digital spaces: An efficie
nt algorithm
based on immersion simulations</em>", IEEE Trans. Patt. Analysis Mach.
Intell. 13(6):583-598, 1991
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
designating membership of each pixel in one of the regions. Plateaus in
the boundary
indicator (i.e. regions of constant gray value) are handled via a Eucli
dean distance
transform by default.
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().
Note that the seeds will be overridden with the final watershed segment
ation.
Alternatively, you may provide \ref SeedOptions in order to instruct
watershedsRegionGrowing() to generate its own seeds (it will call gener
ateWatershedSeeds()
internally). In that case, the destination image should be zero-initial
ized.
You can specify the neighborhood system to be used by passing \ref Four
NeighborCode
or \ref EightNeighborCode (default).
Further options to be specified via \ref WatershedOptions are:
<ul>
<li> Whether to keep a 1-pixel-wide contour (with label 0) between regi
ons or
perform complete grow (i.e. all pixels are assigned to a region).
<li> Whether to stop growing when the boundaryness exceeds a threshold
(remaining
pixels keep label 0).
<li> Whether to use a faster, but less powerful algorithm ("turbo algor
ithm"). It
is faster because it orders pixels by means of a \ref BucketQueue
(therefore,
the boundary indicator must contain integers in the range
<tt>[0, ..., bucket_count-1]</tt>, where <tt>bucket_count</tt> is
specified in
the options object), it only supports complete growing (no contour
between regions
is possible), and it handles plateaus in a simplistic way. It also
saves some
memory because it allocates less temporary storage.
<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).
</ul>
Note that VIGRA provides an alternative implementation of the watershed
transform via
\ref watershedsUnionFind().
<b> Declarations:</b>
pass arguments explicitly:
\code
namespace vigra {
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood = EightNeighborCode>
unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerri
ghts, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood = EightNeighborCo
de(),
WatershedOptions const & options = Watershe
dOptions());
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerri
ghts, SrcAccessor sa,
DestIterator upperleftd, DestAccessor da,
WatershedOptions const & options = Watershe
dOptions());
}
\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
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccesso
r> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood = EightNeighborCo
de(),
WatershedOptions const & options = Watershe
dOptions());
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
unsigned int
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccesso
r> src,
pair<DestIterator, DestAccessor> dest,
WatershedOptions const & options = Watershe
dOptions());
}
\endcode
<b> Usage:</b>
<b>\#include</b> \<vigra/watersheds.hxx\><br>
Namespace: vigra
Example: watersheds of the gradient magnitude.
\code
vigra::BImage src(w, h);
... // read input data
// compute gradient magnitude at scale 1.0 as a boundary indicator
vigra::FImage gradMag(w, h);
gaussianGradientMagnitude(srcImageRange(src), destImage(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
vigra::IImage 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(srcImageRange(gradMag), destImage(lab
eling),
FourNeighborCode(),
WatershedOptions().keepContours()
.seedOptions(SeedOptions().minim
a().threshold(2.0)));
}
// example 2
{
vigra::IImage 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(srcImageRange(gradMag), destImage(labe
ling),
SeedOptions().levelSets(4.0));
// quantize the gradient image to 256 gray levels
vigra::BImage gradMag256(w, h);
vigra::FindMinMax<float> minmax;
inspectImage(srcImageRange(gradMag), minmax); // find original rang
e
transformImage(srcImageRange(gradMag), destImage(gradMag256),
linearRangeMapping(minmax, 0, 255));
// call the turbo algorithm with 256 bins, using 8-neighborhood
watershedsRegionGrowing(srcImageRange(gradMag256), destImage(labeli
ng),
WatershedOptions().turboAlgorithm(256));
}
// example 3
{
vigra::IImage 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(srcImageRange(gradMag), destImage(labeling)
,
WatershedOptions().biasLabel(1, 0.9));
}
\endcode
<b> Required Interface:</b>
\code
SrcIterator src_upperleft, src_lowerright;
DestIterator dest_upperleft;
SrcAccessor src_accessor;
DestAccessor dest_accessor;
// compare src values
src_accessor(src_upperleft) <= src_accessor(src_upperleft)
// set result
int label;
dest_accessor.set(label, dest_upperleft);
\endcode
*/
doxygen_overloaded_function(template <...> unsigned int watershedsRegionGro
wing)
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood>
unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerrights, Sr
cAccessor sa,
DestIterator upperleftd, DestAccessor da,
Neighborhood neighborhood,
WatershedOptions const & options = WatershedOptions
())
{
typedef typename SrcAccessor::value_type ValueType;
typedef typename DestAccessor::value_type LabelType;
unsigned int max_region_label = 0;
if(options.seed_options.mini != SeedOptions::Unspecified)
{
// we are supposed to compute seeds
max_region_label =
generateWatershedSeeds(srcIterRange(upperlefts, lowerrights, sa
),
destIter(upperleftd, da),
neighborhood, options.seed_options);
}
if(options.biased_label != 0)
{
// create a statistics functor for biased region growing
detail::BiasedWatershedStatistics<ValueType, LabelType>
regionstats(options.biased_label, options.
bias);
// perform region growing, starting from the seeds computed above
if(options.bucket_count == 0)
{
max_region_label =
seededRegionGrowing(srcIterRange(upperlefts, lowerrights, sa),
srcIter(upperleftd, da),
destIter(upperleftd, da),
regionstats, options.terminate, neighborhoo
d, options.max_cost);
}
else
{
max_region_label =
fastSeededRegionGrowing(srcIterRange(upperlefts, lowerrights, s
a),
destIter(upperleftd, da),
regionstats, options.terminate,
neighborhood, options.max_cost, options
.bucket_count);
}
}
else
{
// create a statistics functor for region growing
detail::WatershedStatistics<ValueType, LabelType> regionstats;
// perform region growing, starting from the seeds computed above
if(options.bucket_count == 0)
{
max_region_label =
seededRegionGrowing(srcIterRange(upperlefts, lowerrights, sa),
srcIter(upperleftd, da),
destIter(upperleftd, da),
regionstats, options.terminate, neighborhoo
d, options.max_cost);
}
else
{
max_region_label =
fastSeededRegionGrowing(srcIterRange(upperlefts, lowerrights, s
a),
destIter(upperleftd, da),
regionstats, options.terminate,
neighborhood, options.max_cost, options
.bucket_count);
}
}
return max_region_label;
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline unsigned int
watershedsRegionGrowing(SrcIterator upperlefts, SrcIterator lowerrights, Sr
cAccessor sa,
DestIterator upperleftd, DestAccessor da,
WatershedOptions const & options = WatershedOptions
())
{
return watershedsRegionGrowing(upperlefts, lowerrights, sa, upperleftd,
da,
EightNeighborCode(), options);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor,
class Neighborhood>
inline unsigned int
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
Neighborhood neighborhood,
WatershedOptions const & options = WatershedOptions
())
{
return watershedsRegionGrowing(src.first, src.second, src.third,
dest.first, dest.second,
neighborhood, options);
}
template <class SrcIterator, class SrcAccessor,
class DestIterator, class DestAccessor>
inline unsigned int
watershedsRegionGrowing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
pair<DestIterator, DestAccessor> dest,
WatershedOptions const & options = WatershedOptions
())
{
return watershedsRegionGrowing(src.first, src.second, src.third,
dest.first, dest.second,
EightNeighborCode(), options);
} }
//@} //@}
} // namespace vigra } // namespace vigra
#endif // VIGRA_WATERSHEDS_HXX #endif // VIGRA_WATERSHEDS_HXX
 End of changes. 21 change blocks. 
40 lines changed or deleted 967 lines changed or added


 watersheds3d.hxx   watersheds3d.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_watersheds3D_HXX #ifndef VIGRA_watersheds3D_HXX
#define VIGRA_watersheds3D_HXX #define VIGRA_watersheds3D_HXX
#include "voxelneighborhood.hxx" #include "voxelneighborhood.hxx"
#include "multi_array.hxx" #include "multi_array.hxx"
#include "union_find.hxx" #include "multi_localminmax.hxx"
#include "labelvolume.hxx"
#include "seededregiongrowing3d.hxx"
#include "watersheds.hxx"
namespace vigra namespace vigra
{ {
template <class SrcIterator, class SrcAccessor, class SrcShape, template <class SrcIterator, class SrcAccessor, class SrcShape,
class DestIterator, class DestAccessor, class Neighborhood3D> class DestIterator, class DestAccessor, class Neighborhood3D>
int preparewatersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa, int preparewatersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
DestIterator d_Iter, DestAccessor da, Neighborhood 3D) DestIterator d_Iter, DestAccessor da, Neighborhood 3D)
{ {
//basically needed for iteration and border-checks //basically needed for iteration and border-checks
skipping to change at line 174 skipping to change at line 177
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 currentLabel = labels.nextFreeLabel(); // default : new region
//queck whether there is a special borde threatment to be u //check whether there is a special border treatment to be u
sed or not sed or not
AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); 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
skipping to change at line 237 skipping to change at line 240
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[da(xd)], xd);
} }
} }
} }
return count; return count;
} }
/** \addtogroup SeededRegionGrowing Region Segmentation Algorithms /** \addtogroup SeededRegionGrowing
Region growing, watersheds, and voronoi tesselation
*/ */
//@{ //@{
/** \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.
<b> Declarations:</b> <b> Declarations:</b>
skipping to change at line 304 skipping to change at line 444
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
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 gorithms, J. Roerdink, R. Meijster: "<em>The watershed transform: definitions, al gorithms,
and parallelization stretegies</em>", Fundamenta Informaticae, 41:187-2 28, 2000 and parallelization strategies</em>", Fundamenta Informaticae, 41:187-2 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. The function uses accessors.
...probably soon in VIGRA: ...probably soon in VIGRA:
Note that VIGRA provides an alternative implementaion of the watershed transform via Note that VIGRA provides an alternative implementation of the watershed transform via
\ref seededRegionGrowing3D(). It is slower, but handles plateaus better \ref seededRegionGrowing3D(). It is slower, but handles plateaus better
and allows to keep a one pixel wide boundary between regions. and allows to keep a one pixel wide boundary between regions.
<b> Usage:</b> <b> Usage:</b>
<b>\#include</b> \<<a href="watersheds3D_8hxx-source.html">vigra/waters heds3D.hxx</a>\><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
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));
 End of changes. 7 change blocks. 
10 lines changed or deleted 175 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/