| 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 | |
|
| 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 | |
|
| 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 | |
|
| 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<> > 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<> >()); | |
| | | | |
| // 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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | |
|
| 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> & 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_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> <em>Iterator for unstrided \ref vigra::MultiArra
yView</em> | | <BR> <em>Difference type for \ref vigra::MultiArrayVi
ew or \ref vigra::MultiIterator</em> | |
| <LI> \ref vigra::MultiIterator | | <LI> \ref vigra::MultiIterator | |
| <BR> <em>Iterator for unstrided \ref vigra::MultiArra
yView</em> | | <BR> <em>Iterator for unstrided \ref vigra::MultiArra
yView</em> | |
| <LI> \ref vigra::StridedMultiIterator | | <LI> \ref vigra::StridedMultiIterator | |
| <BR> <em>Iterator for strided \ref vigra::MultiArrayV
iew</em> | | <BR> <em>Iterator for strided \ref vigra::MultiArrayV
iew</em> | |
|
| | | <LI> \ref vigra::StridedScanOrderIterator | |
| | | <BR> <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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | |
|
| 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öthe: | | Ullrich Kö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 | |
|
| 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 | |
|
| 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 | |
|
| 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 | |
|