| array_vector.hxx | | array_vector.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2002-2004 by Ullrich Koethe */ | | /* Copyright 2002-2004 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 41 | | 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_ARRAY_VECTOR_HXX | | #ifndef VIGRA_ARRAY_VECTOR_HXX | |
| #define VIGRA_ARRAY_VECTOR_HXX | | #define VIGRA_ARRAY_VECTOR_HXX | |
| | | | |
|
| | | #include "error.hxx" | |
| #include "memory.hxx" | | #include "memory.hxx" | |
|
| | | #include "numerictraits.hxx" | |
| #include <memory> | | #include <memory> | |
| #include <algorithm> | | #include <algorithm> | |
| #include <iosfwd> | | #include <iosfwd> | |
| | | | |
|
| | | #ifdef VIGRA_CHECK_BOUNDS | |
| | | #define VIGRA_ASSERT_INSIDE(diff) \ | |
| | | vigra_precondition(diff >= 0, "Index out of bounds");\ | |
| | | vigra_precondition((unsigned int)diff < size_, "Index out of bounds"); | |
| | | #else | |
| | | #define VIGRA_ASSERT_INSIDE(diff) | |
| | | #endif | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
| template <class T, class Alloc = std::allocator<T> > | | template <class T, class Alloc = std::allocator<T> > | |
| class ArrayVector; | | class ArrayVector; | |
| | | | |
| /** Provide STL conforming interface for C-arrays. | | /** Provide STL conforming interface for C-arrays. | |
| | | | |
|
| This template implements much of the functionality of <tt>std::vector</
tt> | | This template implements much of the functionality of <tt><a href="http
://www.sgi.com/tech/stl/Vector.html">std::vector</a></tt> | |
| on top of a C-array. <tt>ArrayVectorView</tt> does not manage the memor
y | | on top of a C-array. <tt>ArrayVectorView</tt> does not manage the memor
y | |
| it refers to (i.e. it does not allocate or deallocate any memory). | | it refers to (i.e. it does not allocate or deallocate any memory). | |
| Thus, if the underlying memory changes, all dependent <tt>ArrayVectorVi
ew</tt> | | Thus, if the underlying memory changes, all dependent <tt>ArrayVectorVi
ew</tt> | |
| objects are invalidated. This is especially important when <tt>ArrayVec
torView</tt> | | objects are invalidated. This is especially important when <tt>ArrayVec
torView</tt> | |
| is used as a base class for <tt>ArrayVector</tt>, where several functio
ns | | is used as a base class for <tt>ArrayVector</tt>, where several functio
ns | |
| (e.g. resize(), insert()) can allocate new memory and thus invalidate t
he | | (e.g. resize(), insert()) can allocate new memory and thus invalidate t
he | |
| dependent views. The rules what operations invalidate view objects are
the | | dependent views. The rules what operations invalidate view objects are
the | |
| same as the rules concerning standard iterators. | | same as the rules concerning standard iterators. | |
| | | | |
| <b>\#include</b> \<<a href="array__vector_8hxx-source.html">vigra/array
_vector.hxx</a>\><br> | | <b>\#include</b> \<<a href="array__vector_8hxx-source.html">vigra/array
_vector.hxx</a>\><br> | |
| | | | |
| skipping to change at line 82 | | skipping to change at line 90 | |
| public: | | public: | |
| /** default constructor | | /** default constructor | |
| */ | | */ | |
| typedef T value_type; | | typedef T value_type; | |
| typedef value_type & reference; | | typedef value_type & reference; | |
| typedef value_type const & const_reference; | | typedef value_type const & const_reference; | |
| typedef value_type * pointer; | | typedef value_type * pointer; | |
| typedef value_type const * const_pointer; | | typedef value_type const * const_pointer; | |
| typedef value_type * iterator; | | typedef value_type * iterator; | |
| typedef value_type const * const_iterator; | | typedef value_type const * const_iterator; | |
|
| typedef unsigned int size_type; | | typedef std::size_t size_type; | |
| typedef int difference_type; | | typedef std::ptrdiff_t difference_type; | |
| typedef std::reverse_iterator<iterator> reverse_iterator; | | typedef std::reverse_iterator<iterator> reverse_iterator; | |
| typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | |
| | | | |
| public: | | public: | |
| /** default constructor. | | /** default constructor. | |
| View contains NULL pointer. | | View contains NULL pointer. | |
| */ | | */ | |
| ArrayVectorView() | | ArrayVectorView() | |
| : size_(0), | | : size_(0), | |
| data_(0) | | data_(0) | |
| | | | |
| skipping to change at line 194 | | skipping to change at line 202 | |
| swapDataImpl(rhs); | | swapDataImpl(rhs); | |
| } | | } | |
| | | | |
| /** Construct <tt>ArrayVectorView</tt> refering to a subarray. | | /** Construct <tt>ArrayVectorView</tt> refering to a subarray. | |
| \a begin and \a end must be a valid sub-range of the current ar
ray. | | \a begin and \a end must be a valid sub-range of the current ar
ray. | |
| Otherwise, a <tt>PreconditionViolation</tt> | | Otherwise, a <tt>PreconditionViolation</tt> | |
| exception is thrown. | | exception is thrown. | |
| */ | | */ | |
| this_type subarray (size_type begin, size_type end) const | | this_type subarray (size_type begin, size_type end) const | |
| { | | { | |
|
| vigra_precondition(begin >= 0 && begin <= end && end <= size_, | | vigra_precondition(begin <= end && end <= size_, | |
| "ArrayVectorView::subarray(): Limits out of range."); | | "ArrayVectorView::subarray(): Limits out of range."); | |
| return this_type(end-begin, data_ + begin); | | return this_type(end-begin, data_ + begin); | |
| } | | } | |
| | | | |
| /** Get contained const pointer to the data. | | /** Get contained const pointer to the data. | |
| */ | | */ | |
| inline const_pointer data() const | | inline const_pointer data() const | |
| { | | { | |
| return data_; | | return data_; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 301 | | skipping to change at line 309 | |
| */ | | */ | |
| const_reference back() const | | const_reference back() const | |
| { | | { | |
| return data_[size_-1]; | | return data_[size_-1]; | |
| } | | } | |
| | | | |
| /** Access array element \a i. | | /** Access array element \a i. | |
| */ | | */ | |
| reference operator[]( difference_type i ) | | reference operator[]( difference_type i ) | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(i); | |
| return data()[i]; | | return data()[i]; | |
| } | | } | |
| | | | |
| /** Read array element \a i. | | /** Read array element \a i. | |
| */ | | */ | |
| const_reference operator[]( difference_type i ) const | | const_reference operator[]( difference_type i ) const | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(i); | |
| return data()[i]; | | return data()[i]; | |
| } | | } | |
| | | | |
| /** Equivalent to <tt>size() == 0</tt>. | | /** Equivalent to <tt>size() == 0</tt>. | |
| */ | | */ | |
| bool empty() const | | bool empty() const | |
| { | | { | |
| return size_ == 0; | | return size_ == 0; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 437 | | skipping to change at line 447 | |
| else | | else | |
| { | | { | |
| ArrayVector<T> t(*this); | | ArrayVector<T> t(*this); | |
| copyImpl(rhs); | | copyImpl(rhs); | |
| rhs.copyImpl(*this); | | rhs.copyImpl(*this); | |
| } | | } | |
| } | | } | |
| | | | |
| /** Replacement for <tt>std::vector</tt>. | | /** Replacement for <tt>std::vector</tt>. | |
| | | | |
|
| This template implements the same functionality as <tt>std::vector</tt>
. | | This template implements the same functionality as <tt>a href="http://w
ww.sgi.com/tech/stl/Vector.html">std::vector</a></tt> (see there for detail
ed documentation). | |
| However, it gives two useful guarantees, that <tt>std::vector</tt> fail
s | | However, it gives two useful guarantees, that <tt>std::vector</tt> fail
s | |
| to provide: | | to provide: | |
| | | | |
| <ul> | | <ul> | |
| <li>The memory is always allocated as one contiguous piece.</li> | | <li>The memory is always allocated as one contiguous piece.</li> | |
| <li>The iterator is always a <TT>T *</TT> </li> | | <li>The iterator is always a <TT>T *</TT> </li> | |
| </ul> | | </ul> | |
| | | | |
| This means that memory managed by <tt>ArrayVector</tt> can be passed | | This means that memory managed by <tt>ArrayVector</tt> can be passed | |
| to algorithms that expect raw memory. This is especially important | | to algorithms that expect raw memory. This is especially important | |
| | | | |
| skipping to change at line 475 | | skipping to change at line 485 | |
| description of <tt>ArrayVector</tt> functionality. | | description of <tt>ArrayVector</tt> functionality. | |
| | | | |
| <b>\#include</b> \<<a href="array__vector_8hxx-source.html">vigra/array
_vector.hxx</a>\><br> | | <b>\#include</b> \<<a href="array__vector_8hxx-source.html">vigra/array
_vector.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| */ | | */ | |
| template <class T, class Alloc /* = std::allocator<T> */ > | | template <class T, class Alloc /* = std::allocator<T> */ > | |
| class ArrayVector | | class ArrayVector | |
| : public ArrayVectorView<T> | | : public ArrayVectorView<T> | |
| { | | { | |
| typedef ArrayVector<T, Alloc> this_type; | | typedef ArrayVector<T, Alloc> this_type; | |
|
| enum { minimumCapacity = 2 }; | | enum { minimumCapacity = 2, resizeFactor = 2 }; | |
| | | | |
| public: | | public: | |
| typedef ArrayVectorView<T> view_type; | | typedef ArrayVectorView<T> view_type; | |
| typedef typename view_type::value_type value_type; | | typedef typename view_type::value_type value_type; | |
| typedef typename view_type::reference reference; | | typedef typename view_type::reference reference; | |
| typedef typename view_type::const_reference const_reference; | | typedef typename view_type::const_reference const_reference; | |
| typedef typename view_type::pointer pointer; | | typedef typename view_type::pointer pointer; | |
| typedef typename view_type::const_pointer const_pointer; | | typedef typename view_type::const_pointer const_pointer; | |
| typedef typename view_type::iterator iterator; | | typedef typename view_type::iterator iterator; | |
| typedef typename view_type::const_iterator const_iterator; | | typedef typename view_type::const_iterator const_iterator; | |
| | | | |
| skipping to change at line 510 | | skipping to change at line 520 | |
| | | | |
| explicit ArrayVector(Alloc const & alloc) | | explicit ArrayVector(Alloc const & alloc) | |
| : view_type(), | | : view_type(), | |
| capacity_(minimumCapacity), | | capacity_(minimumCapacity), | |
| alloc_(alloc) | | alloc_(alloc) | |
| { | | { | |
| this->data_ = reserve_raw(capacity_); | | this->data_ = reserve_raw(capacity_); | |
| } | | } | |
| | | | |
| explicit ArrayVector( size_type size, Alloc const & alloc = Alloc()) | | explicit ArrayVector( size_type size, Alloc const & alloc = Alloc()) | |
|
| : view_type(size, 0), | | : view_type(), | |
| capacity_(size), | | | |
| alloc_(alloc) | | alloc_(alloc) | |
| { | | { | |
|
| this->data_ = reserve_raw(capacity_); | | initImpl(size, value_type(), VigraTrueType()); | |
| if(this->size_ > 0) | | | |
| std::uninitialized_fill(this->data_, this->data_+this->size_, va | | | |
| lue_type()); | | | |
| } | | } | |
| | | | |
| ArrayVector( size_type size, value_type const & initial, Alloc const &
alloc = Alloc()) | | ArrayVector( size_type size, value_type const & initial, Alloc const &
alloc = Alloc()) | |
|
| : view_type(size, 0), | | : view_type(), | |
| capacity_(size), | | | |
| alloc_(alloc) | | alloc_(alloc) | |
| { | | { | |
|
| this->data_ = reserve_raw(capacity_); | | initImpl(size, initial, VigraTrueType()); | |
| if(this->size_ > 0) | | | |
| std::uninitialized_fill(this->data_, this->data_+this->size_, i | | | |
| nitial); | | | |
| } | | } | |
| | | | |
| ArrayVector( this_type const & rhs ) | | ArrayVector( this_type const & rhs ) | |
|
| : view_type(rhs.size(), 0), | | : view_type(), | |
| capacity_(rhs.capacity_), | | | |
| alloc_(rhs.alloc_) | | alloc_(rhs.alloc_) | |
| { | | { | |
|
| this->data_ = reserve_raw(capacity_); | | initImpl(rhs.begin(), rhs.end(), VigraFalseType()); | |
| if(this->size_ > 0) | | | |
| std::uninitialized_copy(rhs.data_, rhs.data_+rhs.size_, this->d | | | |
| ata_); | | | |
| } | | } | |
| | | | |
| template <class U> | | template <class U> | |
|
| explicit ArrayVector( ArrayVectorView<U> const & rhs, Alloc const & all | | explicit ArrayVector( ArrayVectorView<U> const & rhs, Alloc const & all | |
| oc = Alloc() ); | | oc = Alloc() ) | |
| | | : view_type(), | |
| | | alloc_(alloc) | |
| | | { | |
| | | initImpl(rhs.begin(), rhs.end(), VigraFalseType()); | |
| | | } | |
| | | | |
| template <class InputIterator> | | template <class InputIterator> | |
|
| ArrayVector(InputIterator i, InputIterator end); | | ArrayVector(InputIterator i, InputIterator end) | |
| | | { | |
| | | initImpl(i, end, typename NumericTraits<InputIterator>::isIntegral( | |
| | | )); | |
| | | } | |
| | | | |
| template <class InputIterator> | | template <class InputIterator> | |
|
| ArrayVector(InputIterator i, InputIterator end, Alloc const & alloc); | | ArrayVector(InputIterator i, InputIterator end, Alloc const & alloc) | |
| | | : alloc_(alloc) | |
| | | { | |
| | | initImpl(i, end, typename NumericTraits<InputIterator>::isIntegral( | |
| | | )); | |
| | | } | |
| | | | |
| this_type & operator=( this_type const & rhs ) | | this_type & operator=( this_type const & rhs ) | |
| { | | { | |
| if(this == &rhs) | | if(this == &rhs) | |
| return *this; | | return *this; | |
| if(this->size_ == rhs.size_) | | if(this->size_ == rhs.size_) | |
| this->copyImpl(rhs); | | this->copyImpl(rhs); | |
| else | | else | |
| { | | { | |
| ArrayVector t(rhs); | | ArrayVector t(rhs); | |
| | | | |
| skipping to change at line 611 | | skipping to change at line 624 | |
| } | | } | |
| | | | |
| void swap(this_type & rhs); | | void swap(this_type & rhs); | |
| | | | |
| private: | | private: | |
| | | | |
| void deallocate(pointer data, size_type size); | | void deallocate(pointer data, size_type size); | |
| | | | |
| pointer reserve_raw(size_type capacity); | | pointer reserve_raw(size_type capacity); | |
| | | | |
|
| size_type capacity_; | | void initImpl( size_type size, value_type const & initial, VigraTrueTyp | |
| Alloc alloc_; | | e /*isIntegral*/); | |
| }; | | | |
| | | | |
|
| template <class T, class Alloc> | | template <class Iter> | |
| template <class U> | | void initImpl( Iter i, Iter end, VigraFalseType /*isIntegral*/); | |
| ArrayVector<T, Alloc>::ArrayVector( ArrayVectorView<U> const & rhs, Alloc c | | | |
| onst & alloc ) | | | |
| : view_type(rhs.size(), 0), | | | |
| capacity_(rhs.size()), | | | |
| alloc_(alloc) | | | |
| { | | | |
| this->data_ = reserve_raw(capacity_); | | | |
| if(this->size_ > 0) | | | |
| std::uninitialized_copy(rhs.data(), rhs.data()+rhs.size(), this->da | | | |
| ta_); | | | |
| } | | | |
| | | | |
|
| template <class T, class Alloc> | | template <class Iter> | |
| template <class InputIterator> | | void initImpl( Iter i, Iter end, Error_NumericTraits_not_specialized_fo | |
| ArrayVector<T, Alloc>::ArrayVector(InputIterator i, InputIterator end) | | r_this_case) | |
| : view_type(std::distance(i, end), 0), | | { | |
| capacity_(view_type::size_), | | initImpl(i, end, VigraFalseType()); | |
| alloc_() | | } | |
| { | | | |
| this->data_ = reserve_raw(capacity_); | | | |
| std::uninitialized_copy(i, end, this->data_); | | | |
| } | | | |
| | | | |
|
| template <class T, class Alloc> | | size_type capacity_; | |
| template <class InputIterator> | | Alloc alloc_; | |
| ArrayVector<T, Alloc>::ArrayVector(InputIterator i, InputIterator end, Allo | | }; | |
| c const & alloc) | | | |
| : view_type(std::distance(i, end), 0), | | | |
| capacity_(view_type::size_), | | | |
| alloc_(alloc) | | | |
| { | | | |
| this->data_ = reserve_raw(capacity_); | | | |
| std::uninitialized_copy(i, end, this->data_); | | | |
| } | | | |
| | | | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| template <class U> | | template <class U> | |
| ArrayVector<T, Alloc> & ArrayVector<T, Alloc>::operator=( ArrayVectorView<U
> const & rhs ) | | ArrayVector<T, Alloc> & ArrayVector<T, Alloc>::operator=( ArrayVectorView<U
> const & rhs ) | |
| { | | { | |
| if(this->size_ == rhs.size()) | | if(this->size_ == rhs.size()) | |
| this->copyImpl(rhs); | | this->copyImpl(rhs); | |
| else | | else | |
| { | | { | |
| ArrayVector t(rhs); | | ArrayVector t(rhs); | |
| | | | |
| skipping to change at line 713 | | skipping to change at line 703 | |
| } | | } | |
| | | | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| typename ArrayVector<T, Alloc>::iterator | | typename ArrayVector<T, Alloc>::iterator | |
| ArrayVector<T, Alloc>::insert(iterator p, size_type n, value_type const & v
) | | ArrayVector<T, Alloc>::insert(iterator p, size_type n, value_type const & v
) | |
| { | | { | |
| difference_type pos = p - this->begin(); | | difference_type pos = p - this->begin(); | |
| size_type new_size = this->size() + n; | | size_type new_size = this->size() + n; | |
| if(new_size >= capacity_) | | if(new_size >= capacity_) | |
| { | | { | |
|
| pointer new_data = reserve_raw(new_size); | | size_type new_capacity = std::max(new_size, resizeFactor*capacity_) | |
| | | ; | |
| | | pointer new_data = reserve_raw(new_capacity); | |
| std::uninitialized_copy(this->begin(), p, new_data); | | std::uninitialized_copy(this->begin(), p, new_data); | |
| std::uninitialized_fill(new_data + pos, new_data + pos + n, v); | | std::uninitialized_fill(new_data + pos, new_data + pos + n, v); | |
| std::uninitialized_copy(p, this->end(), new_data + pos + n); | | std::uninitialized_copy(p, this->end(), new_data + pos + n); | |
| deallocate(this->data_, this->size_); | | deallocate(this->data_, this->size_); | |
|
| capacity_ = new_size; | | capacity_ = new_capacity; | |
| this->data_ = new_data; | | this->data_ = new_data; | |
| } | | } | |
| else if(pos + n >= this->size_) | | else if(pos + n >= this->size_) | |
| { | | { | |
| size_type diff = pos + n - this->size_; | | size_type diff = pos + n - this->size_; | |
| std::uninitialized_copy(p, this->end(), this->end() + diff); | | std::uninitialized_copy(p, this->end(), this->end() + diff); | |
| std::uninitialized_fill(this->end(), this->end() + diff, v); | | std::uninitialized_fill(this->end(), this->end() + diff, v); | |
| std::fill(p, this->end(), v); | | std::fill(p, this->end(), v); | |
| } | | } | |
| else | | else | |
| | | | |
| skipping to change at line 749 | | skipping to change at line 740 | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| template <class InputIterator> | | template <class InputIterator> | |
| typename ArrayVector<T, Alloc>::iterator | | typename ArrayVector<T, Alloc>::iterator | |
| ArrayVector<T, Alloc>::insert(iterator p, InputIterator i, InputIterator ie
nd) | | ArrayVector<T, Alloc>::insert(iterator p, InputIterator i, InputIterator ie
nd) | |
| { | | { | |
| size_type n = iend - i; | | size_type n = iend - i; | |
| size_type pos = p - this->begin(); | | size_type pos = p - this->begin(); | |
| size_type new_size = this->size() + n; | | size_type new_size = this->size() + n; | |
| if(new_size >= capacity_) | | if(new_size >= capacity_) | |
| { | | { | |
|
| pointer new_data = reserve_raw(new_size); | | size_type new_capacity = std::max(new_size, resizeFactor*capacity_) | |
| | | ; | |
| | | pointer new_data = reserve_raw(new_capacity); | |
| std::uninitialized_copy(this->begin(), p, new_data); | | std::uninitialized_copy(this->begin(), p, new_data); | |
| std::uninitialized_copy(i, iend, new_data + pos); | | std::uninitialized_copy(i, iend, new_data + pos); | |
| std::uninitialized_copy(p, this->end(), new_data + pos + n); | | std::uninitialized_copy(p, this->end(), new_data + pos + n); | |
| deallocate(this->data_, this->size_); | | deallocate(this->data_, this->size_); | |
|
| capacity_ = new_size; | | capacity_ = new_capacity; | |
| this->data_ = new_data; | | this->data_ = new_data; | |
| } | | } | |
| else if(pos + n >= this->size_) | | else if(pos + n >= this->size_) | |
| { | | { | |
| size_type diff = pos + n - this->size_; | | size_type diff = pos + n - this->size_; | |
| std::uninitialized_copy(p, this->end(), this->end() + diff); | | std::uninitialized_copy(p, this->end(), this->end() + diff); | |
| std::uninitialized_copy(iend - diff, iend, this->end()); | | std::uninitialized_copy(iend - diff, iend, this->end()); | |
| std::copy(i, iend - diff, p); | | std::copy(i, iend - diff, p); | |
| } | | } | |
| else | | else | |
| | | | |
| skipping to change at line 816 | | skipping to change at line 808 | |
| capacity_ = new_capacity; | | capacity_ = new_capacity; | |
| } | | } | |
| | | | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| inline void | | inline void | |
| ArrayVector<T, Alloc>::reserve() | | ArrayVector<T, Alloc>::reserve() | |
| { | | { | |
| if(capacity_ == 0) | | if(capacity_ == 0) | |
| reserve(minimumCapacity); | | reserve(minimumCapacity); | |
| else if(this->size_ == capacity_) | | else if(this->size_ == capacity_) | |
|
| reserve(2*capacity_); | | reserve(resizeFactor*capacity_); | |
| } | | } | |
| | | | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| inline void | | inline void | |
| ArrayVector<T, Alloc>::resize( size_type new_size, value_type const & initi
al) | | ArrayVector<T, Alloc>::resize( size_type new_size, value_type const & initi
al) | |
| { | | { | |
| if(new_size < this->size_) | | if(new_size < this->size_) | |
| erase(this->begin() + new_size, this->end()); | | erase(this->begin() + new_size, this->end()); | |
| else if(this->size_ < new_size) | | else if(this->size_ < new_size) | |
| { | | { | |
| insert(this->end(), new_size - this->size(), initial); | | insert(this->end(), new_size - this->size(), initial); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| inline void | | inline void | |
|
| | | ArrayVector<T, Alloc>::initImpl( size_type size, value_type const & initial | |
| | | , VigraTrueType /*isIntegral*/) | |
| | | { | |
| | | this->size_ = size; | |
| | | capacity_ = size; | |
| | | this->data_ = reserve_raw(capacity_); | |
| | | if(this->size_ > 0) | |
| | | std::uninitialized_fill(this->data_, this->data_+this->size_, initi | |
| | | al); | |
| | | } | |
| | | | |
| | | template <class T, class Alloc> | |
| | | template <class Iter> | |
| | | inline void | |
| | | ArrayVector<T, Alloc>::initImpl( Iter i, Iter end, VigraFalseType /*isInteg | |
| | | ral*/) | |
| | | { | |
| | | this->size_ = std::distance(i, end); | |
| | | capacity_ = this->size_; | |
| | | this->data_ = reserve_raw(capacity_); | |
| | | if(this->size_ > 0) | |
| | | std::uninitialized_copy(i, end, this->data_); | |
| | | } | |
| | | | |
| | | template <class T, class Alloc> | |
| | | inline void | |
| ArrayVector<T, Alloc>::swap(this_type & rhs) | | ArrayVector<T, Alloc>::swap(this_type & rhs) | |
| { | | { | |
| std::swap(this->size_, rhs.size_); | | std::swap(this->size_, rhs.size_); | |
| std::swap(capacity_, rhs.capacity_); | | std::swap(capacity_, rhs.capacity_); | |
| std::swap(this->data_, rhs.data_); | | std::swap(this->data_, rhs.data_); | |
| } | | } | |
| | | | |
| template <class T, class Alloc> | | template <class T, class Alloc> | |
| inline void | | inline void | |
| ArrayVector<T, Alloc>::deallocate(pointer data, size_type size) | | ArrayVector<T, Alloc>::deallocate(pointer data, size_type size) | |
| | | | |
| skipping to change at line 870 | | skipping to change at line 885 | |
| return data; | | return data; | |
| } | | } | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
| namespace std { | | namespace std { | |
| | | | |
| template <class T> | | template <class T> | |
| ostream & operator<<(ostream & s, vigra::ArrayVectorView<T> const & a) | | ostream & operator<<(ostream & s, vigra::ArrayVectorView<T> const & a) | |
| { | | { | |
|
| for(unsigned int k=0; k<a.size()-1; ++k) | | for(int k=0; k<(int)a.size()-1; ++k) | |
| s << a[k] << ", "; | | s << a[k] << ", "; | |
| if(a.size()) | | if(a.size()) | |
| s << a.back(); | | s << a.back(); | |
| return s; | | return s; | |
| } | | } | |
| | | | |
| } // namespace std | | } // namespace std | |
| | | | |
|
| | | #undef VIGRA_ASSERT_INSIDE | |
| #endif /* VIGRA_ARRAY_VECTOR_HXX */ | | #endif /* VIGRA_ARRAY_VECTOR_HXX */ | |
| | | | |
End of changes. 34 change blocks. |
| 75 lines changed or deleted | | 94 lines changed or added | |
|
| basicimage.hxx | | basicimage.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 46 | | skipping to change at line 44 | |
| /************************************************************************/ | | /************************************************************************/ | |
| | | | |
| #ifndef VIGRA_BASICIMAGE_HXX | | #ifndef VIGRA_BASICIMAGE_HXX | |
| #define VIGRA_BASICIMAGE_HXX | | #define VIGRA_BASICIMAGE_HXX | |
| | | | |
| #include <memory> | | #include <memory> | |
| #include <algorithm> | | #include <algorithm> | |
| #include "utilities.hxx" | | #include "utilities.hxx" | |
| #include "iteratortraits.hxx" | | #include "iteratortraits.hxx" | |
| #include "accessor.hxx" | | #include "accessor.hxx" | |
|
| | | #include "memory.hxx" | |
| | | | |
| | | // Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined. | |
| | | #ifdef VIGRA_CHECK_BOUNDS | |
| | | #define VIGRA_ASSERT_INSIDE(diff) \ | |
| | | vigra_precondition(this->isInside(diff), "Index out of bounds") | |
| | | #else | |
| | | #define VIGRA_ASSERT_INSIDE(diff) | |
| | | #endif | |
| | | | |
| namespace vigra { | | namespace vigra { | |
| | | | |
| template <class IMAGEITERATOR> | | template <class IMAGEITERATOR> | |
| class LineBasedColumnIteratorPolicy | | class LineBasedColumnIteratorPolicy | |
| { | | { | |
| public: | | public: | |
| typedef IMAGEITERATOR ImageIterator; | | typedef IMAGEITERATOR ImageIterator; | |
| typedef typename IMAGEITERATOR::LineStartIterator LineStartIterator; | | typedef typename IMAGEITERATOR::LineStartIterator LineStartIterator; | |
| typedef typename IMAGEITERATOR::value_type value_type; | | typedef typename IMAGEITERATOR::value_type value_type; | |
| | | | |
| skipping to change at line 175 | | skipping to change at line 182 | |
| { | | { | |
| IMAGEITERATOR ret(static_cast<IMAGEITERATOR const &>(*this)); | | IMAGEITERATOR ret(static_cast<IMAGEITERATOR const &>(*this)); | |
| | | | |
| ret -= s; | | ret -= s; | |
| | | | |
| return ret; | | return ret; | |
| } | | } | |
| | | | |
| difference_type operator-(BasicImageIteratorBase const & rhs) const | | difference_type operator-(BasicImageIteratorBase const & rhs) const | |
| { | | { | |
|
| return difference_type(x - rhs.x, y - rhs.y); | | return difference_type(difference_type::MoveX(x - rhs.x), | |
| | | difference_type::MoveY(y - rhs.y)); | |
| } | | } | |
| | | | |
| bool operator==(BasicImageIteratorBase const & rhs) const | | bool operator==(BasicImageIteratorBase const & rhs) const | |
| { | | { | |
| return (x == rhs.x) && (y == rhs.y); | | return (x == rhs.x) && (y == rhs.y); | |
| } | | } | |
| | | | |
| bool operator!=(BasicImageIteratorBase const & rhs) const | | bool operator!=(BasicImageIteratorBase const & rhs) const | |
| { | | { | |
| return (x != rhs.x) || (y != rhs.y); | | return (x != rhs.x) || (y != rhs.y); | |
| | | | |
| skipping to change at line 642 | | skipping to change at line 650 | |
| allocator_(alloc), | | allocator_(alloc), | |
| pallocator_(alloc) | | pallocator_(alloc) | |
| { | | { | |
| vigra_precondition((width >= 0) && (height >= 0), | | vigra_precondition((width >= 0) && (height >= 0), | |
| "BasicImage::BasicImage(int width, int height, value_type cons
t & ): " | | "BasicImage::BasicImage(int width, int height, value_type cons
t & ): " | |
| "width and height must be >= 0.\n"); | | "width and height must be >= 0.\n"); | |
| | | | |
| resize(width, height, d); | | resize(width, height, d); | |
| } | | } | |
| | | | |
|
| | | /** construct image of size width*height and try to skip initializa | |
| | | tion | |
| | | of the memory (see BasicImage::resize for details). | |
| | | Use the specified allocator. | |
| | | */ | |
| | | BasicImage(int width, int height, SkipInitializationTag, Alloc const & | |
| | | alloc = Alloc()) | |
| | | : data_(0), | |
| | | width_(0), | |
| | | height_(0), | |
| | | allocator_(alloc), | |
| | | pallocator_(alloc) | |
| | | { | |
| | | vigra_precondition((width >= 0) && (height >= 0), | |
| | | "BasicImage::BasicImage(int width, int height, value_type cons | |
| | | t & ): " | |
| | | "width and height must be >= 0.\n"); | |
| | | | |
| | | resize(width, height, SkipInitialization); | |
| | | } | |
| | | | |
| /** construct image of size size.x x size.y and initialize | | /** construct image of size size.x x size.y and initialize | |
| every pixel with given data (use this constructor, if | | every pixel with given data (use this constructor, if | |
| value_type doesn't have a default constructor). Use the specified a
llocator. | | value_type doesn't have a default constructor). Use the specified a
llocator. | |
| */ | | */ | |
| explicit BasicImage(difference_type const & size, value_type const & d,
Alloc const & alloc = Alloc()) | | explicit BasicImage(difference_type const & size, value_type const & d,
Alloc const & alloc = Alloc()) | |
| : data_(0), | | : data_(0), | |
| width_(0), | | width_(0), | |
| height_(0), | | height_(0), | |
| allocator_(alloc), | | allocator_(alloc), | |
| pallocator_(alloc) | | pallocator_(alloc) | |
| { | | { | |
| vigra_precondition((size.x >= 0) && (size.y >= 0), | | vigra_precondition((size.x >= 0) && (size.y >= 0), | |
| "BasicImage::BasicImage(Diff2D const & size, value_type const
& v): " | | "BasicImage::BasicImage(Diff2D const & size, value_type const
& v): " | |
| "size.x and size.y must be >= 0.\n"); | | "size.x and size.y must be >= 0.\n"); | |
| | | | |
| resize(size.x, size.y, d); | | resize(size.x, size.y, d); | |
| } | | } | |
| | | | |
|
| | | /** construct image of size size.x x size.y and try to skip initial | |
| | | ization | |
| | | of the memory (see BasicImage::resize for details). Use the spe | |
| | | cified allocator. | |
| | | */ | |
| | | explicit BasicImage(difference_type const & size, SkipInitializationTag | |
| | | , Alloc const & alloc = Alloc()) | |
| | | : data_(0), | |
| | | width_(0), | |
| | | height_(0), | |
| | | allocator_(alloc), | |
| | | pallocator_(alloc) | |
| | | { | |
| | | vigra_precondition((size.x >= 0) && (size.y >= 0), | |
| | | "BasicImage::BasicImage(Diff2D const & size, value_type const | |
| | | & v): " | |
| | | "size.x and size.y must be >= 0.\n"); | |
| | | | |
| | | resize(size.x, size.y, SkipInitialization); | |
| | | } | |
| | | | |
| /** construct image of size width*height and copy the data from the | | /** construct image of size width*height and copy the data from the | |
| given C-style array \a d. Use the specified allocator. | | given C-style array \a d. Use the specified allocator. | |
| */ | | */ | |
| BasicImage(int width, int height, const_pointer d, Alloc const & alloc
= Alloc()) | | BasicImage(int width, int height, const_pointer d, Alloc const & alloc
= Alloc()) | |
| : data_(0), | | : data_(0), | |
| width_(0), | | width_(0), | |
| height_(0), | | height_(0), | |
| allocator_(alloc), | | allocator_(alloc), | |
| pallocator_(alloc) | | pallocator_(alloc) | |
| { | | { | |
| | | | |
| skipping to change at line 750 | | skipping to change at line 793 | |
| { | | { | |
| resize(size.x, size.y, value_type()); | | resize(size.x, size.y, value_type()); | |
| } | | } | |
| } | | } | |
| | | | |
| /** reset image to specified size and initialize it with | | /** reset image to specified size and initialize it with | |
| given data (use this if value_type doesn't have a default | | given data (use this if value_type doesn't have a default | |
| constructor, dimensions must not be negative, | | constructor, dimensions must not be negative, | |
| old data are kept if new size matches old size) | | old data are kept if new size matches old size) | |
| */ | | */ | |
|
| void resize(int width, int height, value_type const & d); | | void resize(int width, int height, value_type const & d) | |
| | | { | |
| | | resizeImpl(width, height, d, false); | |
| | | } | |
| | | | |
| | | /** reset image to specified size and skip initialization | |
| | | if possible (use this if <tt>value_type</tt> is a built-in type | |
| | | or <tt>TinyVector<builtin>&</tt> and the data is | |
| | | immediately overridden afterwards). If <tt>value_type</tt> requ | |
| | | ires | |
| | | initialization, <tt>SkipInitialization</tt> is ignored. | |
| | | | |
| | | Usage: | |
| | | \code | |
| | | image.resize(new_width, new_height, SkipInitialization); | |
| | | \endcode | |
| | | */ | |
| | | void resize(int width, int height, SkipInitializationTag) | |
| | | { | |
| | | resizeImpl(width, height, NumericTraits<value_type>::zero(), | |
| | | CanSkipInitialization<value_type>::value); | |
| | | } | |
| | | | |
| /** resize image to given size and initialize by copying data | | /** resize image to given size and initialize by copying data | |
| from the C-style arra \a data. | | from the C-style arra \a data. | |
| */ | | */ | |
| void resizeCopy(int width, int height, const_pointer data); | | void resizeCopy(int width, int height, const_pointer data); | |
| | | | |
| /** resize image to size of other image and copy it's data | | /** resize image to size of other image and copy it's data | |
| */ | | */ | |
| void resizeCopy(const BasicImage & rhs) | | void resizeCopy(const BasicImage & rhs) | |
| { | | { | |
| | | | |
| skipping to change at line 802 | | skipping to change at line 865 | |
| { | | { | |
| return d.x >= 0 && d.y >= 0 && | | return d.x >= 0 && d.y >= 0 && | |
| d.x < width() && d.y < height(); | | d.x < width() && d.y < height(); | |
| } | | } | |
| | | | |
| /** access pixel at given location. <br> | | /** access pixel at given location. <br> | |
| usage: <TT> value_type value = image[Diff2D(1,2)] </TT> | | usage: <TT> value_type value = image[Diff2D(1,2)] </TT> | |
| */ | | */ | |
| reference operator[](difference_type const & d) | | reference operator[](difference_type const & d) | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(d); | |
| return lines_[d.y][d.x]; | | return lines_[d.y][d.x]; | |
| } | | } | |
| | | | |
| /** read pixel at given location. <br> | | /** read pixel at given location. <br> | |
| usage: <TT> value_type value = image[Diff2D(1,2)] </TT> | | usage: <TT> value_type value = image[Diff2D(1,2)] </TT> | |
| */ | | */ | |
| const_reference operator[](difference_type const & d) const | | const_reference operator[](difference_type const & d) const | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(d); | |
| return lines_[d.y][d.x]; | | return lines_[d.y][d.x]; | |
| } | | } | |
| | | | |
| /** access pixel at given location. <br> | | /** access pixel at given location. <br> | |
| usage: <TT> value_type value = image(1,2) </TT> | | usage: <TT> value_type value = image(1,2) </TT> | |
| */ | | */ | |
| reference operator()(int dx, int dy) | | reference operator()(int dx, int dy) | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(difference_type(dx,dy)); | |
| return lines_[dy][dx]; | | return lines_[dy][dx]; | |
| } | | } | |
| | | | |
| /** read pixel at given location. <br> | | /** read pixel at given location. <br> | |
| usage: <TT> value_type value = image(1,2) </TT> | | usage: <TT> value_type value = image(1,2) </TT> | |
| */ | | */ | |
| const_reference operator()(int dx, int dy) const | | const_reference operator()(int dx, int dy) const | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(difference_type(dx,dy)); | |
| return lines_[dy][dx]; | | return lines_[dy][dx]; | |
| } | | } | |
| | | | |
| /** access pixel at given location. | | /** access pixel at given location. | |
| Note that the 'x' index is the trailing index. <br> | | Note that the 'x' index is the trailing index. <br> | |
| usage: <TT> value_type value = image[2][1] </TT> | | usage: <TT> value_type value = image[2][1] </TT> | |
| */ | | */ | |
| pointer operator[](int dy) | | pointer operator[](int dy) | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(difference_type(0,dy)); | |
| return lines_[dy]; | | return lines_[dy]; | |
| } | | } | |
| | | | |
| /** read pixel at given location. | | /** read pixel at given location. | |
| Note that the 'x' index is the trailing index. <br> | | Note that the 'x' index is the trailing index. <br> | |
| usage: <TT> value_type value = image[2][1] </TT> | | usage: <TT> value_type value = image[2][1] </TT> | |
| */ | | */ | |
| const_pointer operator[](int dy) const | | const_pointer operator[](int dy) const | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(difference_type(0,dy)); | |
| return lines_[dy]; | | return lines_[dy]; | |
| } | | } | |
| | | | |
| /** init 2D random access iterator poining to upper left pixel | | /** init 2D random access iterator poining to upper left pixel | |
| */ | | */ | |
| traverser upperLeft() | | traverser upperLeft() | |
| { | | { | |
| vigra_precondition(data_ != 0, | | vigra_precondition(data_ != 0, | |
| "BasicImage::upperLeft(): image must have non-zero size."); | | "BasicImage::upperLeft(): image must have non-zero size."); | |
| return traverser(lines_); | | return traverser(lines_); | |
| | | | |
| skipping to change at line 1005 | | skipping to change at line 1074 | |
| /** return default const accessor | | /** return default const accessor | |
| */ | | */ | |
| ConstAccessor accessor() const | | ConstAccessor accessor() const | |
| { | | { | |
| return ConstAccessor(); | | return ConstAccessor(); | |
| } | | } | |
| | | | |
| private: | | private: | |
| | | | |
| void deallocate(); | | void deallocate(); | |
|
| | | void resizeImpl(int width, int height, value_type const & d, bool skipI
nit); | |
| | | | |
| value_type ** initLineStartArray(value_type * data, int width, int heig
ht); | | value_type ** initLineStartArray(value_type * data, int width, int heig
ht); | |
| | | | |
| PIXELTYPE * data_; | | PIXELTYPE * data_; | |
| PIXELTYPE ** lines_; | | PIXELTYPE ** lines_; | |
| int width_, height_; | | int width_, height_; | |
| Alloc allocator_; | | Alloc allocator_; | |
| LineAllocator pallocator_; | | LineAllocator pallocator_; | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 1064 | | skipping to change at line 1134 | |
| ScanOrderIterator i = begin(); | | ScanOrderIterator i = begin(); | |
| ScanOrderIterator iend = end(); | | ScanOrderIterator iend = end(); | |
| | | | |
| for(; i != iend; ++i) *i = pixel; | | for(; i != iend; ++i) *i = pixel; | |
| | | | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| template <class PIXELTYPE, class Alloc> | | template <class PIXELTYPE, class Alloc> | |
| void | | void | |
|
| BasicImage<PIXELTYPE, Alloc>::resize(int width, int height, value_type cons
t & d) | | BasicImage<PIXELTYPE, Alloc>::resizeImpl(int width, int height, value_type
const & d, bool skipInit) | |
| { | | { | |
| vigra_precondition((width >= 0) && (height >= 0), | | vigra_precondition((width >= 0) && (height >= 0), | |
| "BasicImage::resize(int width, int height, value_type const &): " | | "BasicImage::resize(int width, int height, value_type const &): " | |
| "width and height must be >= 0.\n"); | | "width and height must be >= 0.\n"); | |
|
| | | vigra_precondition(width * height >= 0, | |
| | | "BasicImage::resize(int width, int height, value_type const &): " | |
| | | "width * height too large (integer overflow -> negative).\n"); | |
| | | | |
| if (width_ != width || height_ != height) // change size? | | if (width_ != width || height_ != height) // change size? | |
| { | | { | |
| value_type * newdata = 0; | | value_type * newdata = 0; | |
| value_type ** newlines = 0; | | value_type ** newlines = 0; | |
| if(width*height > 0) | | if(width*height > 0) | |
| { | | { | |
| if (width*height != width_*height_) // different sizes, must re
allocate | | if (width*height != width_*height_) // different sizes, must re
allocate | |
| { | | { | |
| newdata = allocator_.allocate(typename Alloc::size_type(wid
th*height)); | | newdata = allocator_.allocate(typename Alloc::size_type(wid
th*height)); | |
|
| std::uninitialized_fill_n(newdata, width*height, d); | | if(!skipInit) | |
| | | std::uninitialized_fill_n(newdata, width*height, d); | |
| newlines = initLineStartArray(newdata, width, height); | | newlines = initLineStartArray(newdata, width, height); | |
| deallocate(); | | deallocate(); | |
| } | | } | |
| else // need only to reshape | | else // need only to reshape | |
| { | | { | |
| newdata = data_; | | newdata = data_; | |
|
| std::fill_n(newdata, width*height, d); | | if(!skipInit) | |
| | | std::fill_n(newdata, width*height, d); | |
| newlines = initLineStartArray(newdata, width, height); | | newlines = initLineStartArray(newdata, width, height); | |
| pallocator_.deallocate(lines_, typename Alloc::size_type(he
ight_)); | | pallocator_.deallocate(lines_, typename Alloc::size_type(he
ight_)); | |
| } | | } | |
| } | | } | |
| else | | else | |
| { | | { | |
| deallocate(); | | deallocate(); | |
| } | | } | |
| | | | |
| data_ = newdata; | | data_ = newdata; | |
| lines_ = newlines; | | lines_ = newlines; | |
| width_ = width; | | width_ = width; | |
| height_ = height; | | height_ = height; | |
| } | | } | |
|
| else if(width*height > 0) // keep size, re-init data | | else if(width*height > 0 && !skipInit) // keep size, re-init data | |
| { | | { | |
| std::fill_n(data_, width*height, d); | | std::fill_n(data_, width*height, d); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class PIXELTYPE, class Alloc> | | template <class PIXELTYPE, class Alloc> | |
| void | | void | |
| BasicImage<PIXELTYPE, Alloc>::resizeCopy(int width, int height, const_point
er data) | | BasicImage<PIXELTYPE, Alloc>::resizeCopy(int width, int height, const_point
er data) | |
| { | | { | |
| int newsize = width*height; | | int newsize = width*height; | |
| | | | |
| skipping to change at line 1429 | | skipping to change at line 1504 | |
| maskImage(BasicImage<PixelType, Alloc> const & img, Point2D const & ul) | | maskImage(BasicImage<PixelType, Alloc> const & img, Point2D const & ul) | |
| { | | { | |
| vigra_precondition(img.isInside(ul), | | vigra_precondition(img.isInside(ul), | |
| "maskImage(): ROI rectangle outside image."); | | "maskImage(): ROI rectangle outside image."); | |
| return pair<typename BasicImage<PixelType, Alloc>::const_traverser, | | return pair<typename BasicImage<PixelType, Alloc>::const_traverser, | |
| typename BasicImage<PixelType, Alloc>::ConstAccessor>(img.u
pperLeft() + ul, | | typename BasicImage<PixelType, Alloc>::ConstAccessor>(img.u
pperLeft() + ul, | |
| img.a
ccessor()); | | img.a
ccessor()); | |
| } | | } | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
|
| | | #undef VIGRA_ASSERT_INSIDE | |
| #endif // VIGRA_BASICIMAGE_HXX | | #endif // VIGRA_BASICIMAGE_HXX | |
| | | | |
End of changes. 21 change blocks. |
| 10 lines changed or deleted | | 93 lines changed or added | |
|
| colorconversions.hxx | | colorconversions.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 51 | | skipping to change at line 49 | |
| #include <cmath> | | #include <cmath> | |
| #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 | |
| { | | { | |
| | | | |
|
| inline double gammaCorrection(double value, double gamma) | | template<class ValueType> | |
| | | inline ValueType gammaCorrection(double value, double gamma) | |
| { | | { | |
|
| return (value < 0.0) ? | | typedef typename NumericTraits<ValueType>::RealPromote Promote; | |
| -VIGRA_CSTD::pow(-value, gamma) : | | return NumericTraits<ValueType>::fromRealPromote( | |
| VIGRA_CSTD::pow(value, gamma); | | RequiresExplicitCast<Promote>::cast( | |
| | | (value < 0.0) | |
| | | ? -std::pow(-value, gamma) | |
| | | : std::pow(value, gamma))); | |
| } | | } | |
| | | | |
|
| inline double gammaCorrection(double value, double gamma, double norm) | | template<class ValueType> | |
| | | inline ValueType gammaCorrection(double value, double gamma, double norm) | |
| { | | { | |
|
| return (value < 0.0) ? | | typedef typename NumericTraits<ValueType>::RealPromote Promote; | |
| -norm*VIGRA_CSTD::pow(-value/norm, gamma) : | | return NumericTraits<ValueType>::fromRealPromote( | |
| norm*VIGRA_CSTD::pow(value/norm, gamma); | | RequiresExplicitCast<Promote>::cast( | |
| | | (value < 0.0) | |
| | | ? -norm*std::pow(-value/norm, gamma) | |
| | | : norm*std::pow(value/norm, gamma))); | |
| } | | } | |
| | | | |
|
| inline double sRGBCorrection(double value, double norm) | | template<class ValueType> | |
| | | inline ValueType sRGBCorrection(double value, double norm) | |
| { | | { | |
| value /= norm; | | value /= norm; | |
|
| return (value <= 0.00304) | | typedef typename NumericTraits<ValueType>::RealPromote Promote; | |
| ? norm*12.92*value | | return NumericTraits<ValueType>::fromRealPromote( | |
| : norm*(1.055*VIGRA_CSTD::pow(value, 0.41666666666666667) - | | RequiresExplicitCast<ValueType>::cast( | |
| 0.055); | | (value <= 0.0031308) | |
| | | ? norm*12.92*value | |
| | | : norm*(1.055*std::pow(value, 0.41666666666666667) - 0. | |
| | | 055))); | |
| } | | } | |
| | | | |
|
| inline double inverse_sRGBCorrection(double value, double norm) | | template<class ValueType> | |
| | | inline ValueType inverse_sRGBCorrection(double value, double norm) | |
| { | | { | |
| value /= norm; | | value /= norm; | |
|
| return (value <= 0.03928) | | typedef typename NumericTraits<ValueType>::RealPromote Promote; | |
| ? norm*value / 12.92 | | return NumericTraits<ValueType>::fromRealPromote( | |
| : norm*VIGRA_CSTD::pow((value + 0.055)/1.055, 2.4); | | RequiresExplicitCast<ValueType>::cast( | |
| | | (value <= 0.04045) | |
| | | ? norm*value / 12.92 | |
| | | : 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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| skipping to change at line 269 | | skipping to change at line 283 | |
| class RGB2RGBPrimeFunctor | | class RGB2RGBPrimeFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| /** the functor's argument type | | /** the functor's argument type | |
| */ | | */ | |
| typedef TinyVector<From, 3> argument_type; | | typedef TinyVector<From, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<To> result_type; | | typedef TinyVector<To, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<To> value_type; | | typedef TinyVector<To, 3> value_type; | |
| | | | |
| /** the result component's promote type | | /** the result component's promote type | |
| */ | | */ | |
| typedef typename NumericTraits<To>::RealPromote component_type; | | typedef typename NumericTraits<To>::RealPromote component_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 | |
| */ | | */ | |
| RGB2RGBPrimeFunctor() | | RGB2RGBPrimeFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| | | | |
| skipping to change at line 298 | | skipping to change at line 312 | |
| */ | | */ | |
| RGB2RGBPrimeFunctor(component_type max) | | RGB2RGBPrimeFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** 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 RGBValue<To>( | | return TinyVector<To, 3>( | |
| NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[ | | detail::gammaCorrection<To>(rgb[0], 0.45, max_), | |
| 0], 0.45, max_)), | | detail::gammaCorrection<To>(rgb[1], 0.45, max_), | |
| NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[ | | detail::gammaCorrection<To>(rgb[2], 0.45, max_)); | |
| 1], 0.45, max_)), | | | |
| NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[ | | | |
| 2], 0.45, max_))); | | | |
| } | | } | |
| | | | |
| 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 RGBValue<unsigned char> 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] = NumericTraits<unsigned char>::fromRealPromote(detail:
:gammaCorrection(i, 0.45, 255.0)); | | lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, 255.0
); | |
| } | | } | |
| } | | } | |
| | | | |
| RGB2RGBPrimeFunctor(double max) | | RGB2RGBPrimeFunctor(double max) | |
| { | | { | |
| for(int i=0; i<256; ++i) | | for(int i=0; i<256; ++i) | |
| { | | { | |
|
| lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail:
:gammaCorrection(i, 0.45, max)); | | lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, max); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
|
| RGBValue<unsigned char> operator()(V const & rgb) const | | TinyVector<unsigned char, 3> operator()(V const & rgb) const | |
| { | | { | |
|
| return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb
[2]]); | | return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut
_[rgb[2]]); | |
| } | | } | |
| }; | | }; | |
| | | | |
| 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; | |
| }; | | }; | |
| | | | |
| skipping to change at line 359 | | skipping to change at line 373 | |
| | | | |
| <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | | <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><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.00304 \
\ | | 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} | |
| \end{array} \right. | | \end{array} \right. | |
| \f] | | \f] | |
| | | | |
| where C is any of the primaries R, G, and B. By default, \f$ C_{max} =
255 \f$ (this default can be | | where C is any of the primaries R, G, and B. By default, \f$ C_{max} =
255 \f$ (this default can be | |
| overridden in the constructor). If both source and target color compone
nts are stored | | overridden in the constructor). If both source and target color compone
nts are stored | |
| as <tt>unsigned char</tt>, a look-up-table will be used to speed up the
transformation. | | as <tt>unsigned char</tt>, a look-up-table will be used to speed up the
transformation. | |
| | | | |
| <b> Traits defined:</b> | | <b> Traits defined:</b> | |
| | | | |
| | | | |
| skipping to change at line 383 | | skipping to change at line 397 | |
| class RGB2sRGBFunctor | | class RGB2sRGBFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| /** the functor's argument type | | /** the functor's argument type | |
| */ | | */ | |
| typedef TinyVector<From, 3> argument_type; | | typedef TinyVector<From, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<To> result_type; | | typedef TinyVector<To, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<To> value_type; | | typedef TinyVector<To, 3> value_type; | |
| | | | |
| /** the result component's promote type | | /** the result component's promote type | |
| */ | | */ | |
| typedef typename NumericTraits<To>::RealPromote component_type; | | typedef typename NumericTraits<To>::RealPromote component_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 | |
| */ | | */ | |
| RGB2sRGBFunctor() | | RGB2sRGBFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| | | | |
| skipping to change at line 412 | | skipping to change at line 426 | |
| */ | | */ | |
| RGB2sRGBFunctor(component_type max) | | RGB2sRGBFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** 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 RGBValue<To>( | | return TinyVector<To, 3>( | |
| NumericTraits<To>::fromRealPromote(detail::sRGBCorrection(rgb[0 | | detail::sRGBCorrection<To>(rgb[0], max_), | |
| ], max_)), | | detail::sRGBCorrection<To>(rgb[1], max_), | |
| NumericTraits<To>::fromRealPromote(detail::sRGBCorrection(rgb[1 | | detail::sRGBCorrection<To>(rgb[2], max_)); | |
| ], max_)), | | | |
| NumericTraits<To>::fromRealPromote(detail::sRGBCorrection(rgb[2 | | | |
| ], max_))); | | | |
| } | | } | |
| | | | |
| 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 RGBValue<unsigned char> 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] = NumericTraits<unsigned char>::fromRealPromote(detail:
:sRGBCorrection(i, 255.0)); | | lut_[i] = detail::sRGBCorrection<unsigned char>(i, 255.0); | |
| } | | } | |
| } | | } | |
| | | | |
| RGB2sRGBFunctor(double max) | | RGB2sRGBFunctor(double max) | |
| { | | { | |
| for(int i=0; i<256; ++i) | | for(int i=0; i<256; ++i) | |
| { | | { | |
|
| lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail:
:sRGBCorrection(i, max)); | | lut_[i] = detail::sRGBCorrection<unsigned char>(i, max); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
|
| RGBValue<unsigned char> operator()(V const & rgb) const | | TinyVector<unsigned char, 3> operator()(V const & rgb) const | |
| { | | { | |
|
| return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb
[2]]); | | return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut
_[rgb[2]]); | |
| } | | } | |
| }; | | }; | |
| | | | |
| 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; | |
| }; | | }; | |
| | | | |
| skipping to change at line 494 | | skipping to change at line 508 | |
| class RGBPrime2RGBFunctor | | class RGBPrime2RGBFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| /** the functor's argument type | | /** the functor's argument type | |
| */ | | */ | |
| typedef TinyVector<From, 3> argument_type; | | typedef TinyVector<From, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<To> result_type; | | typedef TinyVector<To, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<To> value_type; | | typedef TinyVector<To, 3> value_type; | |
| | | | |
| /** the result component's promote type | | /** the result component's promote type | |
| */ | | */ | |
| typedef typename NumericTraits<To>::RealPromote component_type; | | typedef typename NumericTraits<To>::RealPromote component_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. | |
| */ | | */ | |
| RGBPrime2RGBFunctor() | | RGBPrime2RGBFunctor() | |
| : max_(255.0), gamma_(1.0/0.45) | | : max_(255.0), gamma_(1.0/0.45) | |
| | | | |
| skipping to change at line 522 | | skipping to change at line 536 | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| RGBPrime2RGBFunctor(component_type max) | | RGBPrime2RGBFunctor(component_type max) | |
| : max_(max), gamma_(1.0/0.45) | | : max_(max), gamma_(1.0/0.45) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| result_type operator()(argument_type const & rgb) const | | result_type operator()(argument_type const & rgb) const | |
| { | | { | |
|
| return RGBValue<To>( | | return TinyVector<To, 3>( | |
| NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[ | | detail::gammaCorrection<To>(rgb[0], gamma_, max_), | |
| 0], gamma_, max_)), | | detail::gammaCorrection<To>(rgb[1], gamma_, max_), | |
| NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[ | | detail::gammaCorrection<To>(rgb[2], gamma_, max_)); | |
| 1], gamma_, max_)), | | | |
| NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[ | | | |
| 2], gamma_, max_))); | | | |
| } | | } | |
| | | | |
| 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 RGBValue<unsigned char> 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] = NumericTraits<unsigned char>::fromRealPromote(detail:
:gammaCorrection(i, 1.0/0.45, 255.0)); | | lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, 2
55.0); | |
| } | | } | |
| } | | } | |
| | | | |
| RGBPrime2RGBFunctor(double max) | | RGBPrime2RGBFunctor(double max) | |
| { | | { | |
| for(int i=0; i<256; ++i) | | for(int i=0; i<256; ++i) | |
| { | | { | |
|
| lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail:
:gammaCorrection(i, 1.0/0.45, max)); | | lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, m
ax); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
|
| RGBValue<unsigned char> operator()(V const & rgb) const | | TinyVector<unsigned char, 3> operator()(V const & rgb) const | |
| { | | { | |
|
| return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb
[2]]); | | return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut
_[rgb[2]]); | |
| } | | } | |
| }; | | }; | |
| | | | |
| 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; | |
| }; | | }; | |
| | | | |
| skipping to change at line 584 | | skipping to change at line 598 | |
| | | | |
| <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | | <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><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.03928
\\ | | 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} | |
| \end{array}\right. | | \end{array}\right. | |
| \f] | | \f] | |
| | | | |
| where C is one of the color channels R, G, or B, and \f$ C_{max}\f$ equ
als 255 by default (This default | | where C is one of the color channels R, G, or B, and \f$ C_{max}\f$ equ
als 255 by default (This default | |
| can be overridden in the constructor). If both source and target color
components are stored | | can be overridden in the constructor). If both source and target color
components are stored | |
| as <tt>unsigned char</tt>, a look-up-table will be used to speed up the
transformation. | | as <tt>unsigned char</tt>, a look-up-table will be used to speed up the
transformation. | |
| | | | |
| <b> Traits defined:</b> | | <b> Traits defined:</b> | |
| | | | |
| | | | |
| skipping to change at line 608 | | skipping to change at line 622 | |
| class sRGB2RGBFunctor | | class sRGB2RGBFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| /** the functor's argument type | | /** the functor's argument type | |
| */ | | */ | |
| typedef TinyVector<From, 3> argument_type; | | typedef TinyVector<From, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<To> result_type; | | typedef TinyVector<To, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<To> value_type; | | typedef TinyVector<To, 3> value_type; | |
| | | | |
| /** the result component's promote type | | /** the result component's promote type | |
| */ | | */ | |
| typedef typename NumericTraits<To>::RealPromote component_type; | | typedef typename NumericTraits<To>::RealPromote component_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. | |
| */ | | */ | |
| sRGB2RGBFunctor() | | sRGB2RGBFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| | | | |
| skipping to change at line 636 | | skipping to change at line 650 | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| sRGB2RGBFunctor(component_type max) | | sRGB2RGBFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| result_type operator()(argument_type const & rgb) const | | result_type operator()(argument_type const & rgb) const | |
| { | | { | |
|
| return RGBValue<To>( | | return TinyVector<To, 3>( | |
| NumericTraits<To>::fromRealPromote(detail::inverse_sRGBCorrecti | | detail::inverse_sRGBCorrection<To>(rgb[0], max_), | |
| on(rgb[0], max_)), | | detail::inverse_sRGBCorrection<To>(rgb[1], max_), | |
| NumericTraits<To>::fromRealPromote(detail::inverse_sRGBCorrecti | | detail::inverse_sRGBCorrection<To>(rgb[2], max_)); | |
| on(rgb[1], max_)), | | | |
| NumericTraits<To>::fromRealPromote(detail::inverse_sRGBCorrecti | | | |
| on(rgb[2], max_))); | | | |
| } | | } | |
| | | | |
| 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 RGBValue<unsigned char> 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] = NumericTraits<unsigned char>::fromRealPromote(detail:
:inverse_sRGBCorrection(i, 255.0)); | | lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, 255.
0); | |
| } | | } | |
| } | | } | |
| | | | |
| sRGB2RGBFunctor(double max) | | sRGB2RGBFunctor(double max) | |
| { | | { | |
| for(int i=0; i<256; ++i) | | for(int i=0; i<256; ++i) | |
| { | | { | |
|
| lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail:
:inverse_sRGBCorrection(i, max)); | | lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, max)
; | |
| } | | } | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
|
| RGBValue<unsigned char> operator()(V const & rgb) const | | TinyVector<unsigned char, 3> operator()(V const & rgb) const | |
| { | | { | |
|
| return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb
[2]]); | | return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut
_[rgb[2]]); | |
| } | | } | |
| }; | | }; | |
| | | | |
| 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; | |
| }; | | }; | |
| | | | |
| skipping to change at line 704 | | skipping to change at line 718 | |
| \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} | |
| \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 | |
| in the constructor. X, Y, and Z are always positive and reach their max
imum for white. | | in the constructor. X, Y, and Z are always positive and reach their max
imum for white. | |
| The white point is obtained by transforming RGB(255, 255, 255). It corr
esponds to the | | The white point is obtained by transforming RGB(255, 255, 255). It corr
esponds to the | |
|
| D65 illuminant. Y represents the <em>luminance</em> ("brightness") of t | | D65 illuminant. Y represents the <em>luminance</em> ("brightness") of t | |
| he color. | | he color. The above | |
| | | transformation is officially defined in connection with the sRGB color | |
| | | space (i.e. when the RGB values | |
| | | are obtained by inverse gamma correction of sRGB), other color spaces u | |
| | | se slightly different numbers | |
| | | or another standard illuminant (which gives raise to significantly diff | |
| | | erent numbers). | |
| | | | |
| <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 RGB2XYZFunctor | | class RGB2XYZFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| | | | |
| skipping to change at line 749 | | skipping to change at line 766 | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| RGB2XYZFunctor(component_type max) | | RGB2XYZFunctor(component_type max) | |
| : max_(max) | | : 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; | |
| 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] = 0.412453*red + 0.357580*green + 0.180423*blue; | | result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423* | |
| result[1] = 0.212671*red + 0.715160*green + 0.072169*blue; | | blue); | |
| result[2] = 0.019334*red + 0.119193*green + 0.950227*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); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| 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> > | |
| | | | |
| skipping to change at line 814 | | skipping to change at line 832 | |
| 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_(255.0), gamma_(1.0/ 0.45) | | : max_(component_type(255.0)), gamma_(1.0/ 0.45) | |
| {} | | {} | |
| | | | |
| /** 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) | | : max_(max), gamma_(1.0/ 0.45) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| result_type operator()(argument_type const & rgb) const | | result_type operator()(argument_type const & rgb) const | |
| { | | { | |
|
| component_type red = detail::gammaCorrection(rgb[0]/max_, gamma_); | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| component_type green = detail::gammaCorrection(rgb[1]/max_, gamma_) | | component_type red = detail::gammaCorrection<component_type>(rgb[0] | |
| ; | | /max_, gamma_); | |
| component_type blue = detail::gammaCorrection(rgb[2]/max_, gamma_); | | component_type green = detail::gammaCorrection<component_type>(rgb[ | |
| | | 1]/max_, gamma_); | |
| | | component_type blue = detail::gammaCorrection<component_type>(rgb[2 | |
| | | ]/max_, gamma_); | |
| result_type result; | | result_type result; | |
|
| result[0] = 0.412453*red + 0.357580*green + 0.180423*blue; | | result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423* | |
| result[1] = 0.212671*red + 0.715160*green + 0.072169*blue; | | blue); | |
| result[2] = 0.019334*red + 0.119193*green + 0.950227*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); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| private: | | private: | |
|
| component_type max_, gamma_; | | double gamma_; | |
| | | 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; | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 888 | | skipping to change at line 908 | |
| | | | |
| public: | | public: | |
| /** the functor's argument type. (Actually, the argument type | | /** the functor's argument type. (Actually, the argument type | |
| is more general: <TT>V</TT> with arbitrary | | is more general: <TT>V</TT> with arbitrary | |
| <TT>V</TT>. But this cannot be expressed in a typedef.) | | <TT>V</TT>. But this cannot be expressed in a typedef.) | |
| */ | | */ | |
| typedef TinyVector<T, 3> argument_type; | | typedef TinyVector<T, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<T> result_type; | | typedef TinyVector<T, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<T> 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. | |
| */ | | */ | |
| XYZ2RGBFunctor() | | XYZ2RGBFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| {} | | {} | |
| | | | |
| /** constructor | | /** constructor | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| XYZ2RGBFunctor(component_type max) | | XYZ2RGBFunctor(component_type max) | |
| : max_(max) | | : 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 | |
| { | | { | |
|
| component_type red = 3.2404813432*xyz[0] - 1.5371515163*xyz[1] - | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 0.4985363262*xyz[2]; | | component_type red = Convert::cast( 3.2404813432*xyz[0] - 1.53715 | |
| component_type green = -0.9692549500*xyz[0] + 1.8759900015*xyz[1] + | | 15163*xyz[1] - 0.4985363262*xyz[2]); | |
| 0.0415559266*xyz[2]; | | component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.87599 | |
| component_type blue = 0.0556466391*xyz[0] - 0.2040413384*xyz[1] + | | 00015*xyz[1] + 0.0415559266*xyz[2]); | |
| 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_)); | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <class T> | | template <class T> | |
| class FunctorTraits<XYZ2RGBFunctor<T> > | | class FunctorTraits<XYZ2RGBFunctor<T> > | |
| : public FunctorTraitsBase<XYZ2RGBFunctor<T> > | | : public FunctorTraitsBase<XYZ2RGBFunctor<T> > | |
| { | | { | |
| | | | |
| skipping to change at line 953 | | skipping to change at line 974 | |
| | | | |
| <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 XYZ2RGBPrimeFunctor | | class XYZ2RGBPrimeFunctor | |
| { | | { | |
| typedef typename NumericTraits<T>::RealPromote component_type; | | typedef typename NumericTraits<T>::RealPromote component_type; | |
| | | | |
|
| component_type max_, gamma_; | | double gamma_; | |
| | | component_type max_; | |
| | | | |
| public: | | public: | |
| | | | |
| public: | | public: | |
| /** the functor's argument type. (actually, the argument type | | /** the functor's argument type. (actually, the argument type | |
| can be any vector type with the same interface. | | can be any vector type with the same interface. | |
| But this cannot be expressed in a typedef.) | | But this cannot be expressed in a typedef.) | |
| */ | | */ | |
| typedef TinyVector<T, 3> argument_type; | | typedef TinyVector<T, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<T> result_type; | | typedef TinyVector<T, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<T> 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_(255.0), gamma_(0.45) | | : max_(component_type(255.0)), gamma_(0.45) | |
| {} | | {} | |
| | | | |
| /** 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) | | : max_(max), gamma_(0.45) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| component_type red = 3.2404813432*xyz[0] - 1.5371515163*xyz[1] - | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 0.4985363262*xyz[2]; | | component_type red = Convert::cast( 3.2404813432*xyz[0] - 1.53715 | |
| component_type green = -0.9692549500*xyz[0] + 1.8759900015*xyz[1] + | | 15163*xyz[1] - 0.4985363262*xyz[2]); | |
| 0.0415559266*xyz[2]; | | component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.87599 | |
| component_type blue = 0.0556466391*xyz[0] - 0.2040413384*xyz[1] + | | 00015*xyz[1] + 0.0415559266*xyz[2]); | |
| 1.0573110696*xyz[2]; | | component_type blue = Convert::cast( 0.0556466391*xyz[0] - 0.20404 | |
| return value_type(NumericTraits<T>::fromRealPromote(detail::gammaCo | | 13384*xyz[1] + 1.0573110696*xyz[2]); | |
| rrection(red, gamma_) * max_), | | return value_type(NumericTraits<T>::fromRealPromote(detail::gammaCo | |
| NumericTraits<T>::fromRealPromote(detail::gammaCo | | rrection<component_type>(red, gamma_) * max_), | |
| rrection(green, gamma_) * max_), | | NumericTraits<T>::fromRealPromote(detail::gammaCo | |
| NumericTraits<T>::fromRealPromote(detail::gammaCo | | rrection<component_type>(green, gamma_) * max_), | |
| rrection(blue, gamma_) * max_)); | | NumericTraits<T>::fromRealPromote(detail::gammaCo | |
| | | rrection<component_type>(blue, gamma_) * max_)); | |
| } | | } | |
| }; | | }; | |
| | | | |
| 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; | |
| }; | | }; | |
| | | | |
| skipping to change at line 1029 | | skipping to change at line 1052 | |
| L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\ | | L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\ | |
| & & \\ | | & & \\ | |
| | | | |
| u' & = & \frac{4 X}{X+15 Y + 3 Z}, \quad | | u' & = & \frac{4 X}{X+15 Y + 3 Z}, \quad | |
| v' = \frac{9 Y}{X+15 Y + 3 Z}\\ | | v' = \frac{9 Y}{X+15 Y + 3 Z}\\ | |
| & & \\ | | & & \\ | |
| u^{*} & = & 13 L^{*} (u' - u_n'), \quad v^{*} = 13 L^{*} (v' - v_n'
) | | u^{*} & = & 13 L^{*} (u' - u_n'), \quad v^{*} = 13 L^{*} (v' - v_n'
) | |
| \end{array} | | \end{array} | |
| \f] | | \f] | |
| | | | |
|
| where \f$(X_n, Y_n, Z_n)\f$ is the reference white point, and | | where \f$(X_n, Y_n, Z_n) = (0.950456, 1.0, 1.088754)\f$ is the referenc | |
| \f$u_n' = 0.197839, v_n'=0.468342\f$ are the quantities \f$u', v'\f$ ca | | e white point of standard illuminant D65, | |
| lculated for this | | and \f$u_n' = 0.197839, v_n'=0.468342\f$ are the quantities \f$u', v'\f | |
| point. \f$L^{*}\f$ represents the | | $ calculated for this point. | |
| <em>lighness</em> ("brightness") of the color, and \f$u^{*}, v^{*}\f$ c | | \f$L^{*}\f$ represents the <em>lightness</em> ("brightness") of the col | |
| ode the | | or, and \f$u^{*}, v^{*}\f$ code the | |
| chromaticity. | | chromaticity. (Instead of the rationals \f$\frac{216}{24389}\f$ and \f$ | |
| | | \frac{24389}{27}\f$, the original standard gives the | |
| | | rounded values 0.008856 and 903.3. As <a href="http://www.brucelindbloo | |
| | | m.com/index.html?LContinuity.html">Bruce Lindbloom</a> | |
| | | points out, the rounded values give raise to a discontinuity which is r | |
| | | emoved by the accurate rationals. This bug will be fixed | |
| | | in future versions of the CIE Luv standard.) | |
| | | | |
| <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 XYZ2LuvFunctor | | class XYZ2LuvFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| | | | |
| skipping to change at line 1061 | | skipping to change at line 1086 | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
| 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; | |
| | | | |
| XYZ2LuvFunctor() | | XYZ2LuvFunctor() | |
|
| : gamma_(1.0/3.0) | | : gamma_(1.0/3.0), | |
| | | kappa_(24389.0/27.0), | |
| | | epsilon_(216.0/24389.0) | |
| {} | | {} | |
| | | | |
| template <class V> | | template <class V> | |
| result_type operator()(V const & xyz) const | | result_type operator()(V const & xyz) const | |
| { | | { | |
| result_type result; | | result_type result; | |
| if(xyz[1] == NumericTraits<T>::zero()) | | if(xyz[1] == NumericTraits<T>::zero()) | |
| { | | { | |
| result[0] = NumericTraits<component_type>::zero(); | | result[0] = NumericTraits<component_type>::zero(); | |
| result[1] = NumericTraits<component_type>::zero(); | | result[1] = NumericTraits<component_type>::zero(); | |
| result[2] = NumericTraits<component_type>::zero(); | | result[2] = NumericTraits<component_type>::zero(); | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| component_type L = xyz[1] < 0.008856 ? | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 903.3 * xyz[1] : | | component_type L = Convert::cast( | |
| 116.0 * VIGRA_CSTD::pow((double)xyz[1], g | | xyz[1] < epsilon_ | |
| amma_) - 16.0; | | ? kappa_ * xyz[1] | |
| component_type denom = xyz[0] + 15.0*xyz[1] + 3.0*xyz[2]; | | : 116.0 * VIGRA_CSTD::pow((double)xyz | |
| component_type uprime = 4.0 * xyz[0] / denom; | | [1], gamma_) - 16.0); | |
| component_type vprime = 9.0 * xyz[1] / denom; | | 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 vprime = Convert::cast(9.0 * xyz[1] / denom); | |
| result[0] = L; | | result[0] = L; | |
|
| result[1] = 13.0*L*(uprime - 0.197839); | | result[1] = Convert::cast(13.0*L*(uprime - 0.197839)); | |
| result[2] = 13.0*L*(vprime - 0.468342); | | result[2] = Convert::cast(13.0*L*(vprime - 0.468342)); | |
| } | | } | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| private: | | private: | |
|
| double gamma_; | | 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; | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 1134 | | skipping to change at line 1163 | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
| 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; | |
| | | | |
| Luv2XYZFunctor() | | Luv2XYZFunctor() | |
|
| : gamma_(3.0) | | : gamma_(3.0), | |
| | | ikappa_(27.0/24389.0) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
| result_type result; | | result_type result; | |
| if(luv[0] == NumericTraits<T>::zero()) | | if(luv[0] == NumericTraits<T>::zero()) | |
| { | | { | |
| result[0] = NumericTraits<component_type>::zero(); | | result[0] = NumericTraits<component_type>::zero(); | |
| result[1] = NumericTraits<component_type>::zero(); | | result[1] = NumericTraits<component_type>::zero(); | |
| result[2] = NumericTraits<component_type>::zero(); | | result[2] = NumericTraits<component_type>::zero(); | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| component_type uprime = luv[1] / 13.0 / luv[0] + 0.197839; | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| component_type vprime = luv[2] / 13.0 / luv[0] + 0.468342; | | component_type uprime = Convert::cast(luv[1] / 13.0 / luv[0] + | |
| | | 0.197839); | |
| | | component_type vprime = Convert::cast(luv[2] / 13.0 / luv[0] + | |
| | | 0.468342); | |
| | | | |
|
| result[1] = luv[0] < 8.0 ? | | result[1] = Convert::cast( | |
| luv[0] / 903.3 : | | luv[0] < 8.0 | |
| VIGRA_CSTD::pow((luv[0] + 16.0) / 116.0, | | ? luv[0] * ikappa_ | |
| gamma_); | | : VIGRA_CSTD::pow((luv[0] + 16.0) / 116.0, | |
| result[0] = 9.0*uprime*result[1] / 4.0 / vprime; | | gamma_)); | |
| result[2] = ((9.0 / vprime - 15.0)*result[1] - result[0])/ 3.0; | | 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); | |
| } | | } | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| private: | | private: | |
|
| double gamma_; | | 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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><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 \frac{216}{24389} < \frac{Y}{Y_n}\\ | |
| & & \\ | | & & \\ | |
|
| L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\ | | L^{*} & = & \frac{24389}{27} \enspace \frac{Y}{Y_n} \quad \mbox{oth
erwise} \\ | |
| & & \\ | | & & \\ | |
| a^{*} & = & 500 \left[ \left( \frac{X}{X_n} \right)^\frac{1}{3} - \
left( \frac{Y}{Y_n} \right)^\frac{1}{3} \right] \\ | | a^{*} & = & 500 \left[ \left( \frac{X}{X_n} \right)^\frac{1}{3} - \
left( \frac{Y}{Y_n} \right)^\frac{1}{3} \right] \\ | |
| & & \\ | | & & \\ | |
| b^{*} & = & 200 \left[ \left( \frac{Y}{Y_n} \right)^\frac{1}{3} - \
left( \frac{Z}{Z_n} \right)^\frac{1}{3} \right] \\ | | b^{*} & = & 200 \left[ \left( \frac{Y}{Y_n} \right)^\frac{1}{3} - \
left( \frac{Z}{Z_n} \right)^\frac{1}{3} \right] \\ | |
| \end{array} | | \end{array} | |
| \f] | | \f] | |
| | | | |
|
| where \f$(X_n, Y_n, Z_n)\f$ is the reference white point. \f$L^{*}\f$ r | | where \f$(X_n, Y_n, Z_n) = (0.950456, 1.0, 1.088754)\f$ is the referenc | |
| epresents the | | e white point of standard illuminant D65. | |
| <em>lighness</em> ("brightness") of the color, and \f$a^{*}, b^{*}\f$ c | | \f$L^{*}\f$ represents the <em>lightness</em> ("brightness") of the col | |
| ode the | | or, and \f$a^{*}, b^{*}\f$ code the | |
| chromaticity. | | chromaticity. (Instead of the rationals \f$\frac{216}{24389}\f$ and \f$ | |
| | | \frac{24389}{27}\f$, the original standard gives the | |
| | | rounded values 0.008856 and 903.3. As <a href="http://www.brucelindbloo | |
| | | m.com/index.html?LContinuity.html">Bruce Lindbloom</a> | |
| | | points out, the rounded values give raise to a discontinuity which is r | |
| | | emoved by the accurate rationals. This bug will be fixed | |
| | | in future versions of the CIE Lab standard.) | |
| | | | |
| <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 XYZ2LabFunctor | | class XYZ2LabFunctor | |
| { | | { | |
| public: | | public: | |
| | | | |
| | | | |
| skipping to change at line 1224 | | skipping to change at line 1259 | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
| 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; | |
| | | | |
| XYZ2LabFunctor() | | XYZ2LabFunctor() | |
|
| : gamma_(1.0/3.0) | | : gamma_(1.0/3.0), | |
| | | kappa_(24389.0/27.0), | |
| | | epsilon_(216.0/24389.0) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| component_type xgamma = VIGRA_CSTD::pow(xyz[0] / 0.950456, gamma_); | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| component_type ygamma = VIGRA_CSTD::pow((double)xyz[1], gamma_); | | component_type xgamma = Convert::cast(std::pow(xyz[0] / 0.950456, g | |
| component_type zgamma = VIGRA_CSTD::pow(xyz[2] / 1.088754, gamma_); | | amma_)); | |
| component_type L = xyz[1] < 0.008856 ? | | component_type ygamma = Convert::cast(std::pow((double)xyz[1], gamm | |
| 903.3 * xyz[1] : | | a_)); | |
| 116.0 * ygamma - 16.0; | | component_type zgamma = Convert::cast(std::pow(xyz[2] / 1.088754, g | |
| | | amma_)); | |
| | | component_type L = Convert::cast( | |
| | | xyz[1] < epsilon_ | |
| | | ? kappa_ * xyz[1] | |
| | | : 116.0 * ygamma - 16.0); | |
| result_type result; | | result_type result; | |
| result[0] = L; | | result[0] = L; | |
|
| result[1] = 500.0*(xgamma - ygamma); | | result[1] = Convert::cast(500.0*(xgamma - ygamma)); | |
| result[2] = 200.0*(ygamma - zgamma); | | result[2] = Convert::cast(200.0*(ygamma - zgamma)); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| private: | | private: | |
|
| double gamma_; | | 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; | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 1292 | | skipping to change at line 1331 | |
| */ | | */ | |
| 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; | |
| | | | |
| /** the functor's value type | | /** the functor's value type | |
| */ | | */ | |
| Lab2XYZFunctor() | | Lab2XYZFunctor() | |
|
| : gamma_(3.0) | | : gamma_(3.0), | |
| | | ikappa_(27.0/24389.0) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| component_type Y = lab[0] < 8.0 ? | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| lab[0] / 903.3 : | | component_type Y = Convert::cast( | |
| VIGRA_CSTD::pow((lab[0] + 16.0) / 116.0, gamm | | lab[0] < 8.0 | |
| a_); | | ? lab[0] * ikappa_ | |
| component_type ygamma = VIGRA_CSTD::pow((double)Y, 1.0 / gamma_); | | : std::pow((lab[0] + 16.0) / 116.0, gamma | |
| component_type X = VIGRA_CSTD::pow(lab[1] / 500.0 + ygamma, gamma_) | | _)); | |
| * 0.950456; | | component_type ygamma = Convert::cast(std::pow((double)Y, 1.0 / gam | |
| component_type Z = VIGRA_CSTD::pow(-lab[2] / 200.0 + ygamma, gamma_ | | ma_)); | |
| ) * 1.088754; | | 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); | |
| 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; | |
| } | | } | |
| | | | |
| private: | | private: | |
|
| double gamma_; | | 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; | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 2003 | | skipping to change at line 2045 | |
| */ | | */ | |
| RGBPrime2YPrimePbPrFunctor(component_type max) | | RGBPrime2YPrimePbPrFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 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] = 0.299*red + 0.587*green + 0.114*blue; | | result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue); | |
| result[1] = -0.1687358916*red - 0.3312641084*green + 0.5*blue; | | result[1] = Convert::cast(-0.1687358916*red - 0.3312641084*green + | |
| result[2] = 0.5*red - 0.4186875892*green - 0.0813124108*blue; | | 0.5*blue); | |
| | | result[2] = Convert::cast(0.5*red - 0.4186875892*green - 0.08131241 | |
| | | 08*blue); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| 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> > | |
| | | | |
| skipping to change at line 2054 | | skipping to change at line 2097 | |
| public: | | public: | |
| | | | |
| /** the functor's argument type. (Actually, the argument type | | /** the functor's argument type. (Actually, the argument type | |
| can be any vector type with the same interface. | | can be any vector type with the same interface. | |
| But this cannot be expressed in a typedef.) | | But this cannot be expressed in a typedef.) | |
| */ | | */ | |
| typedef TinyVector<T, 3> argument_type; | | typedef TinyVector<T, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<T> result_type; | | typedef TinyVector<T, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<T> 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. | |
| */ | | */ | |
| YPrimePbPr2RGBPrimeFunctor() | | YPrimePbPr2RGBPrimeFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| {} | | {} | |
| | | | |
| /** constructor | | /** constructor | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| YPrimePbPr2RGBPrimeFunctor(component_type max) | | YPrimePbPr2RGBPrimeFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| template <class V> | | template <class V> | |
| result_type operator()(V const & ypbpr) const | | result_type operator()(V const & ypbpr) const | |
| { | | { | |
|
| component_type nred = ypbpr[0] + 1.402*ypbpr[2]; | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| component_type ngreen = ypbpr[0] - 0.3441362862*ypbpr[1] - 0.714136 | | component_type nred = Convert::cast(ypbpr[0] + 1.402*ypbpr[2]); | |
| 2862*ypbpr[2]; | | component_type ngreen = Convert::cast(ypbpr[0] - 0.3441362862*ypbpr | |
| component_type nblue = ypbpr[0] + 1.772*ypbpr[1]; | | [1] - 0.7141362862*ypbpr[2]); | |
| | | 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_))
; | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <class T> | | template <class T> | |
| class FunctorTraits<YPrimePbPr2RGBPrimeFunctor<T> > | | class FunctorTraits<YPrimePbPr2RGBPrimeFunctor<T> > | |
| : public FunctorTraitsBase<YPrimePbPr2RGBPrimeFunctor<T> > | | : public FunctorTraitsBase<YPrimePbPr2RGBPrimeFunctor<T> > | |
| { | | { | |
| | | | |
| skipping to change at line 2174 | | skipping to change at line 2218 | |
| */ | | */ | |
| RGBPrime2YPrimeIQFunctor(component_type max) | | RGBPrime2YPrimeIQFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 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] = 0.299*red + 0.587*green + 0.114*blue; | | result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue); | |
| result[1] = 0.596*red - 0.274*green - 0.322*blue; | | result[1] = Convert::cast(0.596*red - 0.274*green - 0.322*blue); | |
| result[2] = 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; | |
| } | | } | |
| | | | |
| 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> > | |
| | | | |
| skipping to change at line 2225 | | skipping to change at line 2270 | |
| public: | | public: | |
| | | | |
| /** the functor's argument type. (Actually, the argument type | | /** the functor's argument type. (Actually, the argument type | |
| can be any vector type with the same interface. | | can be any vector type with the same interface. | |
| But this cannot be expressed in a typedef.) | | But this cannot be expressed in a typedef.) | |
| */ | | */ | |
| typedef TinyVector<T, 3> argument_type; | | typedef TinyVector<T, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<T> result_type; | | typedef TinyVector<T, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<T> 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. | |
| */ | | */ | |
| YPrimeIQ2RGBPrimeFunctor() | | YPrimeIQ2RGBPrimeFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| {} | | {} | |
| | | | |
| /** constructor | | /** constructor | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| YPrimeIQ2RGBPrimeFunctor(component_type max) | | YPrimeIQ2RGBPrimeFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| template <class V> | | template <class V> | |
| result_type operator()(V const & yiq) const | | result_type operator()(V const & yiq) const | |
| { | | { | |
|
| component_type nred = yiq[0] + 0.9548892043*yiq[1] + 0.6221039350 | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| *yiq[2]; | | component_type nred = Convert::cast(yiq[0] + 0.9548892043*yiq[1] | |
| component_type ngreen = yiq[0] - 0.2713547827*yiq[1] - 0.6475120259 | | + 0.6221039350*yiq[2]); | |
| *yiq[2]; | | component_type ngreen = Convert::cast(yiq[0] - 0.2713547827*yiq[1] | |
| component_type nblue = yiq[0] - 1.1072510054*yiq[1] + 1.7024603738 | | - 0.6475120259*yiq[2]); | |
| *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_), | |
|
| | | <span class="insert">1.7024603738*yiq[2]);</span> | |
| NumericTraits<T>::fromRealPromote(ngreen * max_)
, | | NumericTraits<T>::fromRealPromote(ngreen * max_)
, | |
| NumericTraits<T>::fromRealPromote(nblue * max_))
; | | NumericTraits<T>::fromRealPromote(nblue * max_))
; | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <class T> | | template <class T> | |
| class FunctorTraits<YPrimeIQ2RGBPrimeFunctor<T> > | | class FunctorTraits<YPrimeIQ2RGBPrimeFunctor<T> > | |
| : public FunctorTraitsBase<YPrimeIQ2RGBPrimeFunctor<T> > | | : public FunctorTraitsBase<YPrimeIQ2RGBPrimeFunctor<T> > | |
| { | | { | |
| | | | |
| skipping to change at line 2345 | | skipping to change at line 2391 | |
| */ | | */ | |
| RGBPrime2YPrimeUVFunctor(component_type max) | | RGBPrime2YPrimeUVFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 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] = 0.299*red + 0.587*green + 0.114*blue; | | result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue); | |
| result[1] = -0.1471376975*red - 0.2888623025*green + 0.436*blue; | | result[1] = Convert::cast(-0.1471376975*red - 0.2888623025*green + | |
| result[2] = 0.6149122807*red - 0.5149122807*green - 0.100*blue; | | 0.436*blue); | |
| | | result[2] = Convert::cast(0.6149122807*red - 0.5149122807*green - 0 | |
| | | .100*blue); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| 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> > | |
| | | | |
| skipping to change at line 2396 | | skipping to change at line 2443 | |
| public: | | public: | |
| | | | |
| /** the functor's argument type. (Actually, the argument type | | /** the functor's argument type. (Actually, the argument type | |
| can be any vector type with the same interface. | | can be any vector type with the same interface. | |
| But this cannot be expressed in a typedef.) | | But this cannot be expressed in a typedef.) | |
| */ | | */ | |
| typedef TinyVector<T, 3> argument_type; | | typedef TinyVector<T, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<T> result_type; | | typedef TinyVector<T, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<T> 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. | |
| */ | | */ | |
| YPrimeUV2RGBPrimeFunctor() | | YPrimeUV2RGBPrimeFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| {} | | {} | |
| | | | |
| /** constructor | | /** constructor | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| YPrimeUV2RGBPrimeFunctor(component_type max) | | YPrimeUV2RGBPrimeFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| template <class V> | | template <class V> | |
| result_type operator()(V const & yuv) const | | result_type operator()(V const & yuv) const | |
| { | | { | |
|
| component_type nred = yuv[0] + 1.140*yuv[2]; | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| component_type ngreen = yuv[0] - 0.3946517044*yuv[1] - 0.580681431* | | component_type nred = Convert::cast(yuv[0] + 1.140*yuv[2]); | |
| yuv[2]; | | component_type ngreen = Convert::cast(yuv[0] - 0.3946517044*yuv[1] | |
| component_type nblue = yuv[0] + 2.0321100920*yuv[1]; | | - 0.580681431*yuv[2]); | |
| | | 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_))
; | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <class T> | | template <class T> | |
| class FunctorTraits<YPrimeUV2RGBPrimeFunctor<T> > | | class FunctorTraits<YPrimeUV2RGBPrimeFunctor<T> > | |
| : public FunctorTraitsBase<YPrimeUV2RGBPrimeFunctor<T> > | | : public FunctorTraitsBase<YPrimeUV2RGBPrimeFunctor<T> > | |
| { | | { | |
| | | | |
| skipping to change at line 2506 | | skipping to change at line 2554 | |
| */ | | */ | |
| RGBPrime2YPrimeCbCrFunctor(component_type max) | | RGBPrime2YPrimeCbCrFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** 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 | |
| { | | { | |
|
| | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| 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] = 16.0 + 65.481*red + 128.553*green + 24.966*blue; | | result[0] = Convert::cast(16.0 + 65.481*red + 128.553*green + 24.96 | |
| result[1] = 128.0 - 37.79683972*red - 74.20316028*green + 112.0*blu | | 6*blue); | |
| e; | | result[1] = Convert::cast(128.0 - 37.79683972*red - 74.20316028*gre | |
| result[2] = 128.0 + 112.0*red - 93.78601998*green - 18.21398002*blu | | en + 112.0*blue); | |
| e; | | result[2] = Convert::cast(128.0 + 112.0*red - 93.78601998*green - 1 | |
| | | 8.21398002*blue); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| 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> > | |
| | | | |
| skipping to change at line 2557 | | skipping to change at line 2606 | |
| public: | | public: | |
| | | | |
| /** the functor's argument type. (Actually, the argument type | | /** the functor's argument type. (Actually, the argument type | |
| can be any vector type with the same interface. | | can be any vector type with the same interface. | |
| But this cannot be expressed in a typedef.) | | But this cannot be expressed in a typedef.) | |
| */ | | */ | |
| typedef TinyVector<T, 3> argument_type; | | typedef TinyVector<T, 3> argument_type; | |
| | | | |
| /** the functor's result type | | /** the functor's result type | |
| */ | | */ | |
|
| typedef RGBValue<T> result_type; | | typedef TinyVector<T, 3> result_type; | |
| | | | |
| /** \deprecated use argument_type and result_type | | /** \deprecated use argument_type and result_type | |
| */ | | */ | |
|
| typedef RGBValue<T> 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. | |
| */ | | */ | |
| YPrimeCbCr2RGBPrimeFunctor() | | YPrimeCbCr2RGBPrimeFunctor() | |
| : max_(255.0) | | : max_(255.0) | |
| {} | | {} | |
| | | | |
| /** constructor | | /** constructor | |
| \arg max - the maximum value for each RGB component | | \arg max - the maximum value for each RGB component | |
| */ | | */ | |
| YPrimeCbCr2RGBPrimeFunctor(component_type max) | | YPrimeCbCr2RGBPrimeFunctor(component_type max) | |
| : max_(max) | | : max_(max) | |
| {} | | {} | |
| | | | |
| /** apply the transformation | | /** apply the transformation | |
| */ | | */ | |
| template <class V> | | template <class V> | |
| result_type operator()(V const & ycbcr) const | | result_type operator()(V const & ycbcr) const | |
| { | | { | |
|
| component_type y = ycbcr[0] - 16.0; | | typedef detail::RequiresExplicitCast<component_type> Convert; | |
| component_type cb = ycbcr[1] - 128.0; | | component_type y = Convert::cast(ycbcr[0] - 16.0); | |
| component_type cr = ycbcr[2] - 128.0; | | component_type cb = Convert::cast(ycbcr[1] - 128.0); | |
| | | component_type cr = Convert::cast(ycbcr[2] - 128.0); | |
| | | | |
|
| component_type nred = 0.00456621*y + 0.006258928571*cr; | | component_type nred = Convert::cast(0.00456621*y + 0.006258928571 | |
| component_type ngreen = 0.00456621*y - 0.001536322706*cb - 0.003188 | | *cr); | |
| 108420*cr; | | component_type ngreen = Convert::cast(0.00456621*y - 0.001536322706 | |
| component_type nblue = 0.00456621*y + 0.007910714286*cb; | | *cb - 0.003188108420*cr); | |
| | | 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_))
; | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <class T> | | template <class T> | |
| class FunctorTraits<YPrimeCbCr2RGBPrimeFunctor<T> > | | class FunctorTraits<YPrimeCbCr2RGBPrimeFunctor<T> > | |
| : public FunctorTraitsBase<YPrimeCbCr2RGBPrimeFunctor<T> > | | : public FunctorTraitsBase<YPrimeCbCr2RGBPrimeFunctor<T> > | |
| { | | { | |
| | | | |
| skipping to change at line 2713 | | skipping to change at line 2763 | |
| magenta = [288.237, 0.603235, 0.863482] | | magenta = [288.237, 0.603235, 0.863482] | |
| \endcode | | \endcode | |
| */ | | */ | |
| inline TinyVector<float, 3> | | inline TinyVector<float, 3> | |
| polar2Lab(double color, double brightness, double saturation) | | polar2Lab(double color, double brightness, double saturation) | |
| { | | { | |
| double angle = (color+39.9977)/180.0*M_PI; | | double angle = (color+39.9977)/180.0*M_PI; | |
| double normsat = saturation*133.809; | | double normsat = saturation*133.809; | |
| | | | |
| TinyVector<float, 3> result; | | TinyVector<float, 3> result; | |
|
| result[0] = 100.0*brightness; | | result[0] = float(100.0*brightness); | |
| result[1] = normsat*VIGRA_CSTD::cos(angle); | | result[1] = float(normsat*VIGRA_CSTD::cos(angle)); | |
| result[2] = normsat*VIGRA_CSTD::sin(angle); | | result[2] = float(normsat*VIGRA_CSTD::sin(angle)); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
| TinyVector<float, 3> | | TinyVector<float, 3> | |
| polar2Lab(V const & polar) | | polar2Lab(V const & polar) | |
| { | | { | |
| return polar2Lab(polar[0], polar[1], polar[2]); | | return polar2Lab(polar[0], polar[1], polar[2]); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 2747 | | skipping to change at line 2797 | |
| 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; | |
|
| result[1] = lab[0]/100.0; | | result[1] = float(lab[0]/100.0); | |
| double angle = (lab[1] == 0.0 && lab[2] == 0.0) | | double angle = (lab[1] == 0.0 && lab[2] == 0.0) | |
| ? 0.0 | | ? 0.0 | |
| : 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 ? | |
|
| angle + 360.0 : | | float(angle + 360.0) : | |
| angle; | | float(angle); | |
| result[2] = VIGRA_CSTD::sqrt(lab[1]*lab[1] + lab[2]*lab[2])/133.809; | | 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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| | | | |
| skipping to change at line 2798 | | skipping to change at line 2848 | |
| magenta = [295.553, 0.603235, 0.767457] | | magenta = [295.553, 0.603235, 0.767457] | |
| \endcode | | \endcode | |
| */ | | */ | |
| inline TinyVector<float, 3> | | inline TinyVector<float, 3> | |
| polar2Luv(double color, double brightness, double saturation) | | polar2Luv(double color, double brightness, double saturation) | |
| { | | { | |
| double angle = (color+12.1727)/180.0*M_PI; | | double angle = (color+12.1727)/180.0*M_PI; | |
| double normsat = saturation*179.04; | | double normsat = saturation*179.04; | |
| | | | |
| TinyVector<float, 3> result; | | TinyVector<float, 3> result; | |
|
| result[0] = 100.0*brightness; | | result[0] = float(100.0*brightness); | |
| result[1] = normsat*VIGRA_CSTD::cos(angle); | | result[1] = float(normsat*VIGRA_CSTD::cos(angle)); | |
| result[2] = normsat*VIGRA_CSTD::sin(angle); | | result[2] = float(normsat*VIGRA_CSTD::sin(angle)); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
| TinyVector<float, 3> | | TinyVector<float, 3> | |
| polar2Luv(V const & polar) | | polar2Luv(V const & polar) | |
| { | | { | |
| return polar2Luv(polar[0], polar[1], polar[2]); | | return polar2Luv(polar[0], polar[1], polar[2]); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 2832 | | skipping to change at line 2882 | |
| 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; | |
|
| result[1] = luv[0]/100.0; | | result[1] = float(luv[0]/100.0); | |
| double angle = (luv[1] == 0.0 && luv[2] == 0.0) | | double angle = (luv[1] == 0.0 && luv[2] == 0.0) | |
| ? 0.0 | | ? 0.0 | |
| : 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 ? | |
|
| angle + 360.0 : | | float(angle + 360.0) : | |
| angle; | | float(angle); | |
| result[2] = VIGRA_CSTD::sqrt(luv[1]*luv[1] + luv[2]*luv[2])/179.04; | | 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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| | | | |
| skipping to change at line 2883 | | skipping to change at line 2933 | |
| magenta = [303.001, 0.413, 1] | | magenta = [303.001, 0.413, 1] | |
| \endcode | | \endcode | |
| */ | | */ | |
| inline TinyVector<float, 3> | | inline TinyVector<float, 3> | |
| polar2YPrimePbPr(double color, double brightness, double saturation) | | polar2YPrimePbPr(double color, double brightness, double saturation) | |
| { | | { | |
| double angle = (color+18.6481)/180.0*M_PI; | | double angle = (color+18.6481)/180.0*M_PI; | |
| double normsat = saturation*0.533887; | | double normsat = saturation*0.533887; | |
| | | | |
| TinyVector<float, 3> result; | | TinyVector<float, 3> result; | |
|
| result[0] = brightness; | | result[0] = float(brightness); | |
| result[1] = -normsat*VIGRA_CSTD::sin(angle); | | result[1] = float(-normsat*VIGRA_CSTD::sin(angle)); | |
| result[2] = normsat*VIGRA_CSTD::cos(angle); | | result[2] = float(normsat*VIGRA_CSTD::cos(angle)); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
| TinyVector<float, 3> | | TinyVector<float, 3> | |
| polar2YPrimePbPr(V const & polar) | | polar2YPrimePbPr(V const & polar) | |
| { | | { | |
| return polar2YPrimePbPr(polar[0], polar[1], polar[2]); | | return polar2YPrimePbPr(polar[0], polar[1], polar[2]); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 2917 | | skipping to change at line 2967 | |
| 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; | |
|
| result[1] = ypbpr[0]; | | result[1] = float(ypbpr[0]); | |
| double angle = (ypbpr[1] == 0.0 && ypbpr[2] == 0.0) | | double angle = (ypbpr[1] == 0.0 && ypbpr[2] == 0.0) | |
| ? 0.0 | | ? 0.0 | |
| : 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 ? | |
|
| angle + 360.0 : | | float(angle + 360.0) : | |
| angle; | | float(angle); | |
| result[2] = VIGRA_CSTD::sqrt(ypbpr[1]*ypbpr[1] + ypbpr[2]*ypbpr[2])/0.5 | | result[2] = float(VIGRA_CSTD::sqrt(ypbpr[1]*ypbpr[1] + ypbpr[2]*ypbpr[2 | |
| 33887; | | ])/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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| | | | |
| skipping to change at line 2968 | | skipping to change at line 3018 | |
| magenta = [303.001, 0.413, 1] | | magenta = [303.001, 0.413, 1] | |
| \endcode | | \endcode | |
| */ | | */ | |
| inline TinyVector<float, 3> | | inline TinyVector<float, 3> | |
| polar2YPrimeCbCr(double color, double brightness, double saturation) | | polar2YPrimeCbCr(double color, double brightness, double saturation) | |
| { | | { | |
| double angle = (color+18.6482)/180.0*M_PI; | | double angle = (color+18.6482)/180.0*M_PI; | |
| double normsat = saturation*119.591; | | double normsat = saturation*119.591; | |
| | | | |
| TinyVector<float, 3> result; | | TinyVector<float, 3> result; | |
|
| result[0] = brightness*219.0 + 16.0; | | result[0] = float(brightness*219.0 + 16.0); | |
| result[1] = -normsat*VIGRA_CSTD::sin(angle)+128.0; | | result[1] = float(-normsat*VIGRA_CSTD::sin(angle)+128.0); | |
| result[2] = normsat*VIGRA_CSTD::cos(angle)+128.0; | | result[2] = float(normsat*VIGRA_CSTD::cos(angle)+128.0); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
| TinyVector<float, 3> | | TinyVector<float, 3> | |
| polar2YPrimeCbCr(V const & polar) | | polar2YPrimeCbCr(V const & polar) | |
| { | | { | |
| return polar2YPrimeCbCr(polar[0], polar[1], polar[2]); | | return polar2YPrimeCbCr(polar[0], polar[1], polar[2]); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 3002 | | skipping to change at line 3052 | |
| 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; | |
|
| result[1] = (ycbcr[0]-16.0)/219.0; | | result[1] = float((ycbcr[0]-16.0)/219.0); | |
| double cb = ycbcr[1]-128.0; | | double cb = ycbcr[1]-128.0; | |
| double cr = ycbcr[2]-128.0; | | double cr = ycbcr[2]-128.0; | |
| double angle = (cb == 0.0 && cr == 0.0) | | double angle = (cb == 0.0 && cr == 0.0) | |
| ? 0.0 | | ? 0.0 | |
| : 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 ? | |
|
| angle + 360.0 : | | float(angle + 360.0) : | |
| angle; | | float(angle); | |
| result[2] = 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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| | | | |
| skipping to change at line 3055 | | skipping to change at line 3105 | |
| magenta = [317.231, 0.413, 0.933362] | | magenta = [317.231, 0.413, 0.933362] | |
| \endcode | | \endcode | |
| */ | | */ | |
| inline TinyVector<float, 3> | | inline TinyVector<float, 3> | |
| polar2YPrimeIQ(double color, double brightness, double saturation) | | polar2YPrimeIQ(double color, double brightness, double saturation) | |
| { | | { | |
| double angle = (color-19.5807)/180.0*M_PI; | | double angle = (color-19.5807)/180.0*M_PI; | |
| double normsat = saturation*0.632582; | | double normsat = saturation*0.632582; | |
| | | | |
| TinyVector<float, 3> result; | | TinyVector<float, 3> result; | |
|
| result[0] = brightness; | | result[0] = float(brightness); | |
| result[1] = normsat*VIGRA_CSTD::cos(angle); | | result[1] = float(normsat*VIGRA_CSTD::cos(angle)); | |
| result[2] = -normsat*VIGRA_CSTD::sin(angle); | | result[2] = float(-normsat*VIGRA_CSTD::sin(angle)); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
| TinyVector<float, 3> | | TinyVector<float, 3> | |
| polar2YPrimeIQ(V const & polar) | | polar2YPrimeIQ(V const & polar) | |
| { | | { | |
| return polar2YPrimeIQ(polar[0], polar[1], polar[2]); | | return polar2YPrimeIQ(polar[0], polar[1], polar[2]); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 3089 | | skipping to change at line 3139 | |
| 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; | |
|
| result[1] = yiq[0]; | | result[1] = float(yiq[0]); | |
| double angle = (yiq[1] == 0.0 && yiq[2] == 0.0) | | double angle = (yiq[1] == 0.0 && yiq[2] == 0.0) | |
| ? 0.0 | | ? 0.0 | |
| : 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 ? | |
|
| angle + 360.0 : | | float(angle + 360.0) : | |
| angle; | | float(angle); | |
| result[2] = VIGRA_CSTD::sqrt(yiq[1]*yiq[1] + yiq[2]*yiq[2])/0.632582; | | 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> \<<a href="colorconversions_8hxx-source.html">vigra/co
lorconversions.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| | | | |
| skipping to change at line 3140 | | skipping to change at line 3190 | |
| magenta = [317.231, 0.413, 0.933362] | | magenta = [317.231, 0.413, 0.933362] | |
| \endcode | | \endcode | |
| */ | | */ | |
| inline TinyVector<float, 3> | | inline TinyVector<float, 3> | |
| polar2YPrimeUV(double color, double brightness, double saturation) | | polar2YPrimeUV(double color, double brightness, double saturation) | |
| { | | { | |
| double angle = (color+13.4569)/180.0*M_PI; | | double angle = (color+13.4569)/180.0*M_PI; | |
| double normsat = saturation*0.632324; | | double normsat = saturation*0.632324; | |
| | | | |
| TinyVector<float, 3> result; | | TinyVector<float, 3> result; | |
|
| result[0] = brightness; | | result[0] = float(brightness); | |
| result[1] = -normsat*VIGRA_CSTD::sin(angle); | | result[1] = float(-normsat*VIGRA_CSTD::sin(angle)); | |
| result[2] = normsat*VIGRA_CSTD::cos(angle); | | result[2] = float(normsat*VIGRA_CSTD::cos(angle)); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| template <class V> | | template <class V> | |
| TinyVector<float, 3> | | TinyVector<float, 3> | |
| polar2YPrimeUV(V const & polar) | | polar2YPrimeUV(V const & polar) | |
| { | | { | |
| return polar2YPrimeUV(polar[0], polar[1], polar[2]); | | return polar2YPrimeUV(polar[0], polar[1], polar[2]); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 3174 | | skipping to change at line 3224 | |
| 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; | |
|
| result[1] = yuv[0]; | | result[1] = float(yuv[0]); | |
| double angle = (yuv[1] == 0.0 && yuv[2] == 0.0) | | double angle = (yuv[1] == 0.0 && yuv[2] == 0.0) | |
| ? 0.0 | | ? 0.0 | |
| : VIGRA_CSTD::atan2(-yuv[1], yuv[2])/M_PI*180.0-13.4569; | | : VIGRA_CSTD::atan2(-yuv[1], yuv[2])/M_PI*180.0-13.4569; | |
| result[0] = angle < 0.0 ? | | result[0] = angle < 0.0 ? | |
|
| angle + 360.0 : | | float(angle + 360.0) : | |
| angle; | | float(angle); | |
| result[2] = VIGRA_CSTD::sqrt(yuv[1]*yuv[1] + yuv[2]*yuv[2])/0.632324; | | result[2] = float(VIGRA_CSTD::sqrt(yuv[1]*yuv[1] + yuv[2]*yuv[2])/0.632 | |
| | | 324); | |
| return result; | | return result; | |
| } | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
| #endif /* VIGRA_COLORCONVERSIONS_HXX */ | | #endif /* VIGRA_COLORCONVERSIONS_HXX */ | |
| | | | |
End of changes. 119 change blocks. |
| 258 lines changed or deleted | | 335 lines changed or added | |
|
| convolution.hxx | | convolution.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 262 | | skipping to change at line 260 | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class T> | | class T> | |
| void convolveImage(SrcIterator supperleft, | | void convolveImage(SrcIterator supperleft, | |
| SrcIterator slowerright, SrcAccessor sa, | | SrcIterator slowerright, SrcAccessor sa, | |
| DestIterator dupperleft, DestAccessor da, | | DestIterator dupperleft, DestAccessor da, | |
| Kernel1D<T> const & kx, Kernel1D<T> const & ky) | | Kernel1D<T> const & kx, Kernel1D<T> const & ky) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | NumericTraits<typename SrcAccessor::value_type>::RealPromote | |
| TmpType; | | TmpType; | |
|
| BasicImage<TmpType> tmp(slowerright - supperleft); | | BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization); | |
| | | | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| destImage(tmp), kernel1d(kx)); | | destImage(tmp), kernel1d(kx)); | |
| separableConvolveY(srcImageRange(tmp), | | separableConvolveY(srcImageRange(tmp), | |
| destIter(dupperleft, da), kernel1d(ky)); | | destIter(dupperleft, da), kernel1d(ky)); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class T> | | class T> | |
| | | | |
| skipping to change at line 290 | | skipping to change at line 288 | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* simpleSharpening */ | | /* simpleSharpening */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Perform simple sharpening function. | | /** \brief Perform simple sharpening function. | |
| | | | |
|
| This function use \ref convolveImage() with following filter: | | This function uses \ref convolveImage() with the following filter: | |
| | | | |
| \code | | \code | |
| -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact
or/16.0, | | -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact
or/16.0, | |
| -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_fact
or/8.0, | | -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_fact
or/8.0, | |
| -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact
or/16.0; | | -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_fact
or/16.0; | |
| \endcode | | \endcode | |
| | | | |
|
| and use <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode. | | and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode. | |
| | | | |
| <b> Preconditions:</b> | | <b> Preconditions:</b> | |
| \code | | \code | |
| 1. sharpening_factor >= 0 | | 1. sharpening_factor >= 0 | |
| 2. scale >= 0 | | 2. scale >= 0 | |
| \endcode | | \endcode | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| skipping to change at line 391 | | skipping to change at line 389 | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* gaussianSharpening */ | | /* gaussianSharpening */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Perform sharpening function with gaussian filter. | | /** \brief Perform sharpening function with gaussian filter. | |
| | | | |
|
| This function use the \ref gaussianSmoothing() | | This function uses \ref gaussianSmoothing() at the given scale to creat | |
| at first and scale the source image | | e a | |
| (\code src \endcode) with the \code scale \endcode | | temporary image 'smooth' and than blends the original and smoothed imag | |
| factor in an temporary image (\code tmp \endcode). At second the new | | e | |
| pixel in the destination image will be with following | | according to the formula | |
| formel calculate: | | | |
| \code | | \code | |
|
| dest = (1 + sharpening_factor)*src - sharpening_factor*tmp | | dest = (1 + sharpening_factor)*src - sharpening_factor*smooth | |
| \endcode | | \endcode | |
| | | | |
| <b> Preconditions:</b> | | <b> Preconditions:</b> | |
| \code | | \code | |
| 1. sharpening_factor >= 0 | | 1. sharpening_factor >= 0 | |
| 2. scale >= 0 | | 2. scale >= 0 | |
| \endcode | | \endcode | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass arguments explicitly: | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAc
cessor src_acc, | | void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAc
cessor src_acc, | |
|
| DestIterator dest_ul, DestAccessor dest_acc | | DestIterator dest_ul, DestAccessor dest_acc, | |
| , double sharpening_factor, | | double sharpening_factor, double scale) | |
| double scale) | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor>
src, | | void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor>
src, | |
|
| pair<DestIterator, DestAccessor> dest, doubl | | pair<DestIterator, DestAccessor> dest, | |
| e sharpening_factor, | | double sharpening_factor, double scale) | |
| double scale) | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu
tion.hxx</a>\> | | <b>\#include</b> \<<a href="convolution_8hxx-source.html">vigra/convolu
tion.hxx</a>\> | |
| | | | |
| \code | | \code | |
| vigra::FImage src(w,h), dest(w,h); | | vigra::FImage src(w,h), dest(w,h); | |
| ... | | ... | |
| | | | |
| skipping to change at line 461 | | skipping to change at line 457 | |
| DestIterator dest_ul, DestAccessor dest_acc, double
sharpening_factor, | | DestIterator dest_ul, DestAccessor dest_acc, double
sharpening_factor, | |
| double scale) | | double scale) | |
| { | | { | |
| vigra_precondition(sharpening_factor >= 0.0, | | vigra_precondition(sharpening_factor >= 0.0, | |
| "gaussianSharpening(): amount of sharpening must be
>= 0"); | | "gaussianSharpening(): amount of sharpening must be
>= 0"); | |
| vigra_precondition(scale >= 0.0, | | vigra_precondition(scale >= 0.0, | |
| "gaussianSharpening(): scale parameter should be >=
0."); | | "gaussianSharpening(): scale parameter should be >=
0."); | |
| | | | |
| typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote ValueType; | | typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote ValueType; | |
| | | | |
|
| BasicImage<ValueType> tmp(src_lr - src_ul); | | BasicImage<ValueType> tmp(src_lr - src_ul, SkipInitialization); | |
| | | | |
| gaussianSmoothing(src_ul, src_lr, src_acc, tmp.upperLeft(), tmp.accesso
r(), scale); | | gaussianSmoothing(src_ul, src_lr, src_acc, tmp.upperLeft(), tmp.accesso
r(), scale); | |
| | | | |
| SrcIterator i_src = src_ul; | | SrcIterator i_src = src_ul; | |
| DestIterator i_dest = dest_ul; | | DestIterator i_dest = dest_ul; | |
| typename BasicImage<ValueType>::traverser tmp_ul = tmp.upperLeft(); | | typename BasicImage<ValueType>::traverser tmp_ul = tmp.upperLeft(); | |
| typename BasicImage<ValueType>::traverser i_tmp = tmp_ul; | | typename BasicImage<ValueType>::traverser i_tmp = tmp_ul; | |
| typename BasicImage<ValueType>::Accessor tmp_acc = tmp.accessor(); | | typename BasicImage<ValueType>::Accessor tmp_acc = tmp.accessor(); | |
| | | | |
| for(; i_src.y != src_lr.y ; i_src.y++, i_dest.y++, i_tmp.y++ ) | | for(; i_src.y != src_lr.y ; i_src.y++, i_dest.y++, i_tmp.y++ ) | |
| | | | |
| skipping to change at line 559 | | skipping to change at line 555 | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void gaussianSmoothing(SrcIterator supperleft, | | void gaussianSmoothing(SrcIterator supperleft, | |
| SrcIterator slowerright, SrcAccessor sa, | | SrcIterator slowerright, SrcAccessor sa, | |
| DestIterator dupperleft, DestAccessor da, | | DestIterator dupperleft, DestAccessor da, | |
| double scale) | | double scale) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | NumericTraits<typename SrcAccessor::value_type>::RealPromote | |
| TmpType; | | TmpType; | |
|
| BasicImage<TmpType> tmp(slowerright - supperleft); | | BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization); | |
| | | | |
| Kernel1D<double> smooth; | | Kernel1D<double> smooth; | |
| smooth.initGaussian(scale); | | smooth.initGaussian(scale); | |
| smooth.setBorderTreatment(BORDER_TREATMENT_REFLECT); | | smooth.setBorderTreatment(BORDER_TREATMENT_REFLECT); | |
| | | | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| destImage(tmp), kernel1d(smooth)); | | destImage(tmp), kernel1d(smooth)); | |
| separableConvolveY(srcImageRange(tmp), | | separableConvolveY(srcImageRange(tmp), | |
| destIter(dupperleft, da), kernel1d(smooth)); | | destIter(dupperleft, da), kernel1d(smooth)); | |
| } | | } | |
| | | | |
| skipping to change at line 674 | | skipping to change at line 670 | |
| class DestIteratorY, class DestAccessorY> | | class DestIteratorY, class DestAccessorY> | |
| void gaussianGradient(SrcIterator supperleft, | | void gaussianGradient(SrcIterator supperleft, | |
| SrcIterator slowerright, SrcAccessor sa, | | SrcIterator slowerright, SrcAccessor sa, | |
| DestIteratorX dupperleftx, DestAccessorX dax, | | DestIteratorX dupperleftx, DestAccessorX dax, | |
| DestIteratorY dupperlefty, DestAccessorY day, | | DestIteratorY dupperlefty, DestAccessorY day, | |
| double scale) | | double scale) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | NumericTraits<typename SrcAccessor::value_type>::RealPromote | |
| TmpType; | | TmpType; | |
|
| BasicImage<TmpType> tmp(slowerright - supperleft); | | BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization); | |
| | | | |
| Kernel1D<double> smooth, grad; | | Kernel1D<double> smooth, grad; | |
| smooth.initGaussian(scale); | | smooth.initGaussian(scale); | |
| grad.initGaussianDerivative(scale, 1); | | grad.initGaussianDerivative(scale, 1); | |
| | | | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| destImage(tmp), kernel1d(grad)); | | destImage(tmp), kernel1d(grad)); | |
| separableConvolveY(srcImageRange(tmp), | | separableConvolveY(srcImageRange(tmp), | |
| destIter(dupperleftx, dax), kernel1d(smooth)); | | destIter(dupperleftx, dax), kernel1d(smooth)); | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| | | | |
| skipping to change at line 784 | | skipping to change at line 780 | |
| doxygen_overloaded_function(template <...> void gaussianGradientMagnitude) | | doxygen_overloaded_function(template <...> void gaussianGradientMagnitude) | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void gaussianGradientMagnitude(SrcIterator sul, | | void gaussianGradientMagnitude(SrcIterator sul, | |
| SrcIterator slr, SrcAccessor src, | | SrcIterator slr, SrcAccessor src, | |
| DestIterator dupperleft, DestAccessor dest, | | DestIterator dupperleft, DestAccessor dest, | |
| double scale) | | double scale) | |
| { | | { | |
| typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType; | | typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType; | |
|
| BasicImage<TmpType> gradx(slr-sul), grady(slr-sul); | | BasicImage<TmpType> gradx(slr-sul, SkipInitialization), grady(slr-sul,
SkipInitialization); | |
| | | | |
| gaussianGradient(srcIterRange(sul, slr, src), | | gaussianGradient(srcIterRange(sul, slr, src), | |
| destImage(gradx), destImage(grady), scale); | | destImage(gradx), destImage(grady), scale); | |
| combineTwoImages(srcImageRange(gradx), srcImage(grady), destIter(dupper
left, dest), | | combineTwoImages(srcImageRange(gradx), srcImage(grady), destIter(dupper
left, dest), | |
| MagnitudeFunctor<TmpType>()); | | MagnitudeFunctor<TmpType>()); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline void | | inline void | |
| | | | |
| skipping to change at line 868 | | skipping to change at line 864 | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void laplacianOfGaussian(SrcIterator supperleft, | | void laplacianOfGaussian(SrcIterator supperleft, | |
| SrcIterator slowerright, SrcAccessor sa, | | SrcIterator slowerright, SrcAccessor sa, | |
| DestIterator dupperleft, DestAccessor da, | | DestIterator dupperleft, DestAccessor da, | |
| double scale) | | double scale) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | NumericTraits<typename SrcAccessor::value_type>::RealPromote | |
| TmpType; | | TmpType; | |
|
| BasicImage<TmpType> tmp(slowerright - supperleft), | | BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization), | |
| tmpx(slowerright - supperleft), | | tmpx(slowerright - supperleft, SkipInitialization), | |
| tmpy(slowerright - supperleft); | | tmpy(slowerright - supperleft, SkipInitialization); | |
| | | | |
| Kernel1D<double> smooth, deriv; | | Kernel1D<double> smooth, deriv; | |
| smooth.initGaussian(scale); | | smooth.initGaussian(scale); | |
| deriv.initGaussianDerivative(scale, 2); | | deriv.initGaussianDerivative(scale, 2); | |
| | | | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| destImage(tmp), kernel1d(deriv)); | | destImage(tmp), kernel1d(deriv)); | |
| separableConvolveY(srcImageRange(tmp), | | separableConvolveY(srcImageRange(tmp), | |
| destImage(tmpx), kernel1d(smooth)); | | destImage(tmpx), kernel1d(smooth)); | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| | | | |
| skipping to change at line 993 | | skipping to change at line 989 | |
| void hessianMatrixOfGaussian(SrcIterator supperleft, | | void hessianMatrixOfGaussian(SrcIterator supperleft, | |
| SrcIterator slowerright, SrcAccessor sa, | | SrcIterator slowerright, SrcAccessor sa, | |
| DestIteratorX dupperleftx, DestAccessorX dax, | | DestIteratorX dupperleftx, DestAccessorX dax, | |
| DestIteratorXY dupperleftxy, DestAccessorXY daxy, | | DestIteratorXY dupperleftxy, DestAccessorXY daxy, | |
| DestIteratorY dupperlefty, DestAccessorY day, | | DestIteratorY dupperlefty, DestAccessorY day, | |
| double scale) | | double scale) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | NumericTraits<typename SrcAccessor::value_type>::RealPromote | |
| TmpType; | | TmpType; | |
|
| BasicImage<TmpType> tmp(slowerright - supperleft); | | BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization); | |
| | | | |
| Kernel1D<double> smooth, deriv1, deriv2; | | Kernel1D<double> smooth, deriv1, deriv2; | |
| smooth.initGaussian(scale); | | smooth.initGaussian(scale); | |
| deriv1.initGaussianDerivative(scale, 1); | | deriv1.initGaussianDerivative(scale, 1); | |
| deriv2.initGaussianDerivative(scale, 2); | | deriv2.initGaussianDerivative(scale, 2); | |
| | | | |
| separableConvolveX(srcIterRange(supperleft, slowerright, sa), | | separableConvolveX(srcIterRange(supperleft, slowerright, sa), | |
| destImage(tmp), kernel1d(deriv2)); | | destImage(tmp), kernel1d(deriv2)); | |
| separableConvolveY(srcImageRange(tmp), | | separableConvolveY(srcImageRange(tmp), | |
| destIter(dupperleftx, dax), kernel1d(smooth)); | | destIter(dupperleftx, dax), kernel1d(smooth)); | |
| | | | |
| skipping to change at line 1156 | | skipping to change at line 1152 | |
| void structureTensor(SrcIterator supperleft, | | void structureTensor(SrcIterator supperleft, | |
| SrcIterator slowerright, SrcAccessor sa, | | SrcIterator slowerright, SrcAccessor sa, | |
| DestIteratorX dupperleftx, DestAccessorX dax, | | DestIteratorX dupperleftx, DestAccessorX dax, | |
| DestIteratorXY dupperleftxy, DestAccessorXY daxy, | | DestIteratorXY dupperleftxy, DestAccessorXY daxy, | |
| DestIteratorY dupperlefty, DestAccessorY day, | | DestIteratorY dupperlefty, DestAccessorY day, | |
| double inner_scale, double outer_scale) | | double inner_scale, double outer_scale) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | NumericTraits<typename SrcAccessor::value_type>::RealPromote | |
| TmpType; | | TmpType; | |
|
| BasicImage<TmpType> tmp(slowerright - supperleft), | | BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization), | |
| tmpx(slowerright - supperleft), | | tmpx(slowerright - supperleft, SkipInitialization), | |
| tmpy(slowerright - supperleft); | | tmpy(slowerright - supperleft, SkipInitialization); | |
| | | | |
| gaussianGradient(srcIterRange(supperleft, slowerright, sa), | | gaussianGradient(srcIterRange(supperleft, slowerright, sa), | |
| destImage(tmpx), destImage(tmpy), inner_scale); | | destImage(tmpx), destImage(tmpy), inner_scale); | |
| combineTwoImages(srcImageRange(tmpx), srcImage(tmpx), | | combineTwoImages(srcImageRange(tmpx), srcImage(tmpx), | |
| destImage(tmp), std::multiplies<TmpType>()); | | destImage(tmp), std::multiplies<TmpType>()); | |
| gaussianSmoothing(srcImageRange(tmp), | | gaussianSmoothing(srcImageRange(tmp), | |
| destIter(dupperleftx, dax), outer_scale); | | destIter(dupperleftx, dax), outer_scale); | |
| combineTwoImages(srcImageRange(tmpy), srcImage(tmpy), | | combineTwoImages(srcImageRange(tmpy), srcImage(tmpy), | |
| destImage(tmp), std::multiplies<TmpType>()); | | destImage(tmp), std::multiplies<TmpType>()); | |
| gaussianSmoothing(srcImageRange(tmp), | | gaussianSmoothing(srcImageRange(tmp), | |
| | | | |
| skipping to change at line 1228 | | skipping to change at line 1224 | |
| VigraFalseType /* isScalar */) | | VigraFalseType /* isScalar */) | |
| { | | { | |
| int bands = src.size(supperleft); | | int bands = src.size(supperleft); | |
| typedef VectorElementAccessor<SrcAccessor> SA; | | typedef VectorElementAccessor<SrcAccessor> SA; | |
| | | | |
| structureTensor(supperleft, slowerright, SA(0, src), | | structureTensor(supperleft, slowerright, SA(0, src), | |
| dupperleft, dest, | | dupperleft, dest, | |
| inner_scale, outer_scale, | | inner_scale, outer_scale, | |
| VigraTrueType() /* isScalar */); | | VigraTrueType() /* isScalar */); | |
| | | | |
|
| BasicImage<typename DestAccessor::value_type> st(slowerright - supperle
ft); | | BasicImage<typename DestAccessor::value_type> st(slowerright - supperle
ft, SkipInitialization); | |
| for(int k=1; k < bands; ++k) | | for(int k=1; k < bands; ++k) | |
| { | | { | |
| structureTensor(supperleft, slowerright, SA(k, src), | | structureTensor(supperleft, slowerright, SA(k, src), | |
| st.upperLeft(), st.accessor(), | | st.upperLeft(), st.accessor(), | |
| inner_scale, outer_scale, | | inner_scale, outer_scale, | |
| VigraTrueType() /* isScalar */); | | VigraTrueType() /* isScalar */); | |
| combineTwoImages(srcImageRange(st), srcIter(dupperleft, dest), dest
Iter(dupperleft, dest), | | combineTwoImages(srcImageRange(st), srcIter(dupperleft, dest), dest
Iter(dupperleft, dest), | |
| std::plus<typename DestAccessor::value_type>()); | | std::plus<typename DestAccessor::value_type>()); | |
| } | | } | |
| } | | } | |
| | | | |
End of changes. 18 change blocks. |
| 31 lines changed or deleted | | 27 lines changed or added | |
|
| edgedetection.hxx | | edgedetection.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 50 | | skipping to change at line 48 | |
| | | | |
| #include <vector> | | #include <vector> | |
| #include <queue> | | #include <queue> | |
| #include <cmath> // sqrt(), abs() | | #include <cmath> // sqrt(), abs() | |
| #include "utilities.hxx" | | #include "utilities.hxx" | |
| #include "numerictraits.hxx" | | #include "numerictraits.hxx" | |
| #include "stdimage.hxx" | | #include "stdimage.hxx" | |
| #include "stdimagefunctions.hxx" | | #include "stdimagefunctions.hxx" | |
| #include "recursiveconvolution.hxx" | | #include "recursiveconvolution.hxx" | |
| #include "separableconvolution.hxx" | | #include "separableconvolution.hxx" | |
|
| | | #include "convolution.hxx" | |
| #include "labelimage.hxx" | | #include "labelimage.hxx" | |
| #include "mathutil.hxx" | | #include "mathutil.hxx" | |
| #include "pixelneighborhood.hxx" | | #include "pixelneighborhood.hxx" | |
| #include "linear_solve.hxx" | | #include "linear_solve.hxx" | |
|
| | | #include "functorexpression.hxx" | |
| | | | |
| namespace vigra { | | namespace vigra { | |
| | | | |
| /** \addtogroup EdgeDetection Edge Detection | | /** \addtogroup EdgeDetection Edge Detection | |
| Edge detectors based on first and second derivatives, | | Edge detectors based on first and second derivatives, | |
| and related post-processing. | | and related post-processing. | |
| */ | | */ | |
| //@{ | | //@{ | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| skipping to change at line 220 | | skipping to change at line 220 | |
| recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale); | | recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale); | |
| recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale); | | recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale); | |
| | | | |
| typename TMPIMG::Iterator iy = smooth.upperLeft(); | | typename TMPIMG::Iterator iy = smooth.upperLeft(); | |
| typename TMPIMG::Iterator ty = tmp.upperLeft(); | | typename TMPIMG::Iterator ty = tmp.upperLeft(); | |
| DestIterator dy = dul; | | DestIterator dy = dul; | |
| | | | |
| static const Diff2D right(1, 0); | | static const Diff2D right(1, 0); | |
| static const Diff2D bottom(0, 1); | | static const Diff2D bottom(0, 1); | |
| | | | |
|
| TMPTYPE thresh = (gradient_threshold * gradient_threshold) * | | TMPTYPE thresh = detail::RequiresExplicitCast<TMPTYPE>::cast((gradient_ | |
| NumericTraits<TMPTYPE>::one(); | | threshold * gradient_threshold) * | |
| | | NumericTraits<TMPTYPE>::one()); | |
| TMPTYPE zero = NumericTraits<TMPTYPE>::zero(); | | TMPTYPE zero = NumericTraits<TMPTYPE>::zero(); | |
| | | | |
| for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, ++dy.y) | | for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, ++dy.y) | |
| { | | { | |
| typename TMPIMG::Iterator ix = iy; | | typename TMPIMG::Iterator ix = iy; | |
| typename TMPIMG::Iterator tx = ty; | | typename TMPIMG::Iterator tx = ty; | |
| DestIterator dx = dy; | | DestIterator dx = dy; | |
| | | | |
| for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, ++dx.x) | | for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, ++dx.x) | |
| { | | { | |
| | | | |
| skipping to change at line 509 | | skipping to change at line 509 | |
| recursiveSmoothX(srcIterRange(sul, slr, sa), destImage(tmp), scale / 2.
0); | | recursiveSmoothX(srcIterRange(sul, slr, sa), destImage(tmp), scale / 2.
0); | |
| recursiveSmoothY(srcImageRange(tmp), destImage(tmp), scale / 2.0); | | recursiveSmoothY(srcImageRange(tmp), destImage(tmp), scale / 2.0); | |
| | | | |
| recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale); | | recursiveSmoothX(srcImageRange(tmp), destImage(smooth), scale); | |
| recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale); | | recursiveSmoothY(srcImageRange(smooth), destImage(smooth), scale); | |
| | | | |
| typename TMPIMG::Iterator iy = smooth.upperLeft(); | | typename TMPIMG::Iterator iy = smooth.upperLeft(); | |
| typename TMPIMG::Iterator ty = tmp.upperLeft(); | | typename TMPIMG::Iterator ty = tmp.upperLeft(); | |
| DestIterator dy = dul; | | DestIterator dy = dul; | |
| | | | |
|
| TMPTYPE thresh = (gradient_threshold * gradient_threshold) * | | TMPTYPE thresh = detail::RequiresExplicitCast<TMPTYPE>::cast((gradient_ | |
| NumericTraits<TMPTYPE>::one(); | | threshold * gradient_threshold) * | |
| | | NumericTraits<TMPTYPE>::one()); | |
| | | | |
| // find zero crossings above threshold | | // find zero crossings above threshold | |
| for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, dy.y+=2) | | for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, dy.y+=2) | |
| { | | { | |
| typename TMPIMG::Iterator ix = iy; | | typename TMPIMG::Iterator ix = iy; | |
| typename TMPIMG::Iterator tx = ty; | | typename TMPIMG::Iterator tx = ty; | |
| DestIterator dx = dy; | | DestIterator dx = dy; | |
| | | | |
| for(int x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2) | | for(int x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2) | |
| { | | { | |
| | | | |
| skipping to change at line 1146 | | skipping to change at line 1146 | |
| { | | { | |
| beautifyCrackEdgeImage(src.first, src.second, src.third, | | beautifyCrackEdgeImage(src.first, src.second, src.third, | |
| edge_marker, background_marker); | | edge_marker, background_marker); | |
| } | | } | |
| | | | |
| /** Helper class that stores edgel attributes. | | /** Helper class that stores edgel attributes. | |
| */ | | */ | |
| class Edgel | | class Edgel | |
| { | | { | |
| public: | | public: | |
|
| | | | |
| | | /** The type of an Edgel's members. | |
| | | */ | |
| | | typedef float value_type; | |
| | | | |
| /** The edgel's sub-pixel x coordinate. | | /** The edgel's sub-pixel x coordinate. | |
| */ | | */ | |
|
| float x; | | value_type x; | |
| | | | |
| /** The edgel's sub-pixel y coordinate. | | /** The edgel's sub-pixel y coordinate. | |
| */ | | */ | |
|
| float y; | | value_type y; | |
| | | | |
| /** The edgel's strength (magnitude of the gradient vector). | | /** The edgel's strength (magnitude of the gradient vector). | |
| */ | | */ | |
|
| float strength; | | value_type strength; | |
| | | | |
| /** | | /** | |
|
| The edgel's orientation. This is the angle | | The edgel's orientation. This is the clockwise angle in radians | |
| between the x-axis and the edge, so that the bright side of the | | between the x-axis and the edge, so that the bright side of the | |
|
| edge is on the right. The angle is measured | | edge is on the left when one looks along the orientation vector. | |
| counter-clockwise in radians like this: | | The angle is measured clockwise because the y-axis increases | |
| | | downwards (left-handed coordinate system): | |
| | | | |
| \code | | \code | |
| | | | |
| edgel axis | | edgel axis | |
|
| \ (bright side) | | \ | |
| (dark \ | | (dark \ (bright side) | |
| side) \ /__ | | side) \ | |
| \\ \ orientation angle | | \ | |
| \ | | | | |
| +------------> x-axis | | +------------> x-axis | |
|
| | | | |\ | | |
| | | | | \ /_/ orientation angle | |
| | | | | \\ | |
| | | | \ | |
| | | | | | |
| y-axis V | | y-axis V | |
| \endcode | | \endcode | |
| | | | |
| So, for example a vertical edge with its dark side on the left | | So, for example a vertical edge with its dark side on the left | |
| has orientation PI/2, and a horizontal edge with dark side on top | | has orientation PI/2, and a horizontal edge with dark side on top | |
|
| has orientation 0. Obviously, the edge's orientation changes | | has orientation PI. Obviously, the edge's orientation changes | |
| by PI if the contrast is reversed. | | by PI if the contrast is reversed. | |
| | | | |
|
| | | Note that this convention changed as of VIGRA version 1.7.0. | |
| | | | |
| */ | | */ | |
|
| float orientation; | | value_type orientation; | |
| | | | |
| Edgel() | | Edgel() | |
|
| : x(0.0f), y(0.0f), strength(0.0f), orientation(0.0f) | | : x(0.0), y(0.0), strength(0.0), orientation(0.0) | |
| {} | | {} | |
| | | | |
|
| Edgel(float ix, float iy, float is, float 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 Image1, class Image2, class BackInsertable> | | template <class SrcIterator, class SrcAccessor, | |
| void internalCannyFindEdgels(Image1 const & gx, | | class MagnitudeImage, class BackInsertable> | |
| Image1 const & gy, | | void internalCannyFindEdgels(SrcIterator ul, SrcAccessor grad, | |
| Image2 const & magnitude, | | MagnitudeImage const & magnitude, | |
| BackInsertable & edgels) | | BackInsertable & edgels) | |
| { | | { | |
|
| typedef typename Image1::value_type PixelType; | | typedef typename SrcAccessor::value_type PixelType; | |
| | | typedef typename PixelType::value_type ValueType; | |
| | | | |
| double t = 0.5 / VIGRA_CSTD::sin(M_PI/8.0); | | double t = 0.5 / VIGRA_CSTD::sin(M_PI/8.0); | |
| | | | |
|
| for(int y=1; y<gx.height()-1; ++y) | | ul += Diff2D(1,1); | |
| | | for(int y=1; y<magnitude.height()-1; ++y, ++ul.y) | |
| { | | { | |
|
| for(int x=1; x<gx.width()-1; ++x) | | SrcIterator ix = ul; | |
| | | for(int x=1; x<magnitude.width()-1; ++x, ++ix.x) | |
| { | | { | |
|
| PixelType gradx = gx(x,y); | | | |
| PixelType grady = gy(x,y); | | | |
| double mag = magnitude(x, y); | | double mag = magnitude(x, y); | |
| if(mag == 0.0) | | if(mag == 0.0) | |
| continue; | | continue; | |
|
| | | ValueType gradx = grad.getComponent(ix, 0); | |
| | | 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, | |
| y2 = y + dy; | | y2 = y + dy; | |
| | | | |
|
| PixelType m1 = magnitude(x1, y1); | | double m1 = magnitude(x1, y1); | |
| PixelType m3 = magnitude(x2, y2); | | double m3 = magnitude(x2, y2); | |
| | | | |
| if(m1 < mag && m3 <= mag) | | if(m1 < mag && m3 <= mag) | |
| { | | { | |
| Edgel edgel; | | Edgel edgel; | |
| | | | |
| // local maximum => quadratic interpolation of sub-pixel lo
cation | | // local maximum => quadratic interpolation of sub-pixel lo
cation | |
|
| PixelType del = (m1 - m3) / 2.0 / (m1 + m3 - 2.0*mag); | | double del = 0.5 * (m1 - m3) / (m1 + m3 - 2.0*mag); | |
| edgel.x = x + dx*del; | | edgel.x = Edgel::value_type(x + dx*del); | |
| edgel.y = y + dy*del; | | edgel.y = Edgel::value_type(y + dy*del); | |
| edgel.strength = mag; | | edgel.strength = Edgel::value_type(mag); | |
| double orientation = VIGRA_CSTD::atan2(-grady, gradx) - M_P | | double orientation = VIGRA_CSTD::atan2(grady, gradx) + 0.5* | |
| I * 1.5; | | M_PI; | |
| if(orientation < 0.0) | | if(orientation < 0.0) | |
| orientation += 2.0*M_PI; | | orientation += 2.0*M_PI; | |
|
| edgel.orientation = orientation; | | edgel.orientation = Edgel::value_type(orientation); | |
| edgels.push_back(edgel); | | edgels.push_back(edgel); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* cannyEdgelList */ | | /* cannyEdgelList */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Simple implementation of Canny's edge detector. | | /** \brief Simple implementation of Canny's edge detector. | |
| | | | |
|
| This operator first calculates the gradient vector for each | | The function can be called in two modes: If you pass a 'scale', it is a | |
| pixel of the image using first derivatives of a Gaussian at the | | ssumed that the | |
| given scale. Then a very simple non-maxima supression is performed: | | 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 | |
| | | the given image already contains the gradient (i.e. its value_type must | |
| | | be | |
| | | a vector of length 2). | |
| | | | |
| | | On the basis of the gradient image, a simple non-maxima supression is p | |
| | | erformed: | |
| 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 octands). 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 | | edgel position is determined by fitting a parabola to the three gradien | |
| to the three gradient magnitude values | | t | |
| mentioned above. The sub-pixel location of the parabola'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 | |
| template <class SrcIterator, class SrcAccessor, class BackInsertabl
e> | | template <class SrcIterator, class SrcAccessor, class BackInsertabl
e> | |
|
| void cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src | | void | |
| , | | cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, | |
| BackInsertable & edgels, double scale); | | BackInsertable & edgels); | |
| | | | |
| | | // compute edgels from a scaler image (determine gradient internall | |
| | | y at 'scale') | |
| | | template <class SrcIterator, class SrcAccessor, class BackInsertabl | |
| | | e> | |
| | | void | |
| | | cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, | |
| | | 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 | |
| | | template <class SrcIterator, class SrcAccessor, class BackInsertabl | |
| | | e> | |
| | | void | |
| | | cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, | |
| | | BackInsertable & edgels); | |
| | | | |
| | | // compute edgels from a scaler 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> \<<a href="edgedetection_8hxx-source.html">vigra/edged
etection.hxx</a>\><br> | |
| | | | |
| skipping to change at line 1327 | | skipping to change at line 1357 | |
| | | | |
| <b> Preconditions:</b> | | <b> Preconditions:</b> | |
| | | | |
| \code | | \code | |
| scale > 0 | | scale > 0 | |
| \endcode | | \endcode | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void cannyEdgelList) | | doxygen_overloaded_function(template <...> void cannyEdgelList) | |
| | | | |
| template <class SrcIterator, class SrcAccessor, class BackInsertable> | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
|
| void cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, | | void | |
| BackInsertable & edgels, double scale) | | cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, | |
| | | BackInsertable & edgels, double scale) | |
| { | | { | |
|
| int w = lr.x - ul.x; | | typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP | |
| int h = lr.y - ul.y; | | romote TmpType; | |
| | | BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); | |
| // calculate image gradients | | gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); | |
| typedef typename | | | |
| NumericTraits<typename SrcAccessor::value_type>::RealPromote | | | |
| TmpType; | | | |
| | | | |
| BasicImage<TmpType> tmp(w,h), dx(w,h), dy(w,h); | | | |
| | | | |
| Kernel1D<double> smooth, grad; | | | |
| | | | |
|
| smooth.initGaussian(scale); | | cannyEdgelList(srcImageRange(grad), edgels); | |
| grad.initGaussianDerivative(scale, 1); | | } | |
| | | | |
|
| separableConvolveX(srcIterRange(ul, lr, src), destImage(tmp), kernel1d( | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
| grad)); | | inline void | |
| separableConvolveY(srcImageRange(tmp), destImage(dx), kernel1d(smooth)) | | cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, | |
| ; | | BackInsertable & edgels, double scale) | |
| | | { | |
| | | cannyEdgelList(src.first, src.second, src.third, edgels, scale); | |
| | | } | |
| | | | |
|
| separableConvolveY(srcIterRange(ul, lr, src), destImage(tmp), kernel1d( | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
| grad)); | | void | |
| separableConvolveX(srcImageRange(tmp), destImage(dy), kernel1d(smooth)) | | cannyEdgelList(SrcIterator ul, SrcIterator lr, SrcAccessor src, | |
| ; | | BackInsertable & edgels) | |
| | | { | |
| | | using namespace functor; | |
| | | | |
|
| combineTwoImages(srcImageRange(dx), srcImage(dy), destImage(tmp), | | typedef typename SrcAccessor::value_type SrcType; | |
| MagnitudeFunctor<TmpType>()); | | 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 | | // find edgels | |
|
| internalCannyFindEdgels(dx, dy, tmp, edgels); | | internalCannyFindEdgels(ul, src, magnitude, edgels); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, class BackInsertable> | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
| inline void | | inline void | |
| cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, | | cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src, | |
|
| BackInsertable & edgels, double scale) | | BackInsertable & edgels) | |
| { | | { | |
|
| cannyEdgelList(src.first, src.second, src.third, edgels, scale); | | cannyEdgelList(src.first, src.second, src.third, edgels); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* 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. | |
| | | | |
| | | | |
| skipping to change at line 1458 | | skipping to change at line 1492 | |
| 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); | | cannyEdgelList(sul, slr, sa, edgels, scale); | |
| | | | |
|
| | | int w = slr.x - sul.x; | |
| | | 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) | | 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) | |
| | | 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, | |
| | | | |
| skipping to change at line 1966 | | skipping to change at line 2006 | |
| 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) | |
| { | | { | |
| 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 Image1, class Image2, class BackInsertable> | | template <class SrcIterator, class SrcAccessor, | |
| void internalCannyFindEdgels3x3(Image1 const & grad, | | class MaskImage, class BackInsertable> | |
| Image2 const & mask, | | void internalCannyFindEdgels3x3(SrcIterator ul, SrcAccessor grad, | |
| | | MaskImage const & mask, | |
| BackInsertable & edgels) | | BackInsertable & edgels) | |
| { | | { | |
|
| typedef typename Image1::value_type PixelType; | | typedef typename SrcAccessor::value_type PixelType; | |
| typedef typename PixelType::value_type ValueType; | | typedef typename PixelType::value_type ValueType; | |
| | | | |
|
| for(int y=1; y<grad.height()-1; ++y) | | ul += Diff2D(1,1); | |
| | | for(int y=1; y<mask.height()-1; ++y, ++ul.y) | |
| { | | { | |
|
| for(int x=1; x<grad.width()-1; ++x) | | SrcIterator ix = ul; | |
| | | for(int x=1; x<mask.width()-1; ++x, ++ix.x) | |
| { | | { | |
| if(!mask(x,y)) | | if(!mask(x,y)) | |
| continue; | | continue; | |
| | | | |
|
| ValueType gradx = grad(x,y)[0]; | | ValueType gradx = grad.getComponent(ix, 0); | |
| ValueType grady = grad(x,y)[1]; | | ValueType grady = grad.getComponent(ix, 1); | |
| double mag = hypot(gradx, grady); | | double mag = hypot(gradx, grady); | |
| if(mag == 0.0) | | if(mag == 0.0) | |
| 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) | |
| { | | { | |
| double u = c*xx + s*yy; | | double u = c*xx + s*yy; | |
|
| double v = norm(grad(x+xx, y+yy)); | | double v = norm(grad(ix, Diff2D(xx, yy))); | |
| l(1,0) = u; | | l(1,0) = u; | |
| l(2,0) = u*u; | | l(2,0) = u*u; | |
| ml += outer(l); | | ml += outer(l); | |
| mr += v*l; | | mr += v*l; | |
| } | | } | |
| } | | } | |
| | | | |
| linearSolve(ml, mr, r); | | linearSolve(ml, mr, r); | |
| | | | |
| Edgel edgel; | | Edgel edgel; | |
| | | | |
| // local maximum => quadratic interpolation of sub-pixel locati
on | | // local maximum => quadratic interpolation of sub-pixel locati
on | |
| double del = -r(1,0) / 2.0 / r(2,0); | | double del = -r(1,0) / 2.0 / r(2,0); | |
| if(std::fabs(del) > 1.5) // don't move by more than about a pi
xel diameter | | if(std::fabs(del) > 1.5) // don't move by more than about a pi
xel diameter | |
| del = 0.0; | | del = 0.0; | |
|
| edgel.x = x + c*del; | | edgel.x = Edgel::value_type(x + c*del); | |
| edgel.y = y + s*del; | | edgel.y = Edgel::value_type(y + s*del); | |
| edgel.strength = mag; | | edgel.strength = Edgel::value_type(mag); | |
| double orientation = VIGRA_CSTD::atan2(-grady, gradx) - M_PI * | | double orientation = VIGRA_CSTD::atan2(grady, gradx) + 0.5*M_PI | |
| 1.5; | | ; | |
| if(orientation < 0.0) | | if(orientation < 0.0) | |
| orientation += 2.0*M_PI; | | orientation += 2.0*M_PI; | |
|
| edgel.orientation = orientation; | | edgel.orientation = Edgel::value_type(orientation); | |
| edgels.push_back(edgel); | | edgels.push_back(edgel); | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* cannyEdgelList3x3 */ | | /* cannyEdgelList3x3 */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Improved implementation of Canny's edge detector. | | /** \brief Improved implementation of Canny's edge detector. | |
| | | | |
| This operator first computes pixels which are crossed by the edge using | | This operator first computes pixels which are crossed by the edge using | |
|
| cannyEdgeImageWithThinning(). The gradient magnitude in the 3x3 neighbo
rhood of these | | cannyEdgeImageWithThinning(). The gradient magnitudes in the 3x3 neighb
orhood of these | |
| pixels are then projected onto the normal of the edge (as determined | | pixels are then projected onto the normal of the edge (as determined | |
| by the gradient direction). The edgel's subpixel location is found by f
itting a | | by the gradient direction). The edgel's subpixel location is found by f
itting a | |
| parabola through the 9 gradient values and determining the parabola's t
ip. | | parabola through the 9 gradient values and determining the parabola's t
ip. | |
| A new \ref Edgel is appended to the given vector of <TT>edgels</TT>. Si
nce the parabola | | A new \ref Edgel is appended to the given vector of <TT>edgels</TT>. Si
nce the parabola | |
| is fitted to 9 points rather than 3 points as in cannyEdgelList(), the
accuracy is higher. | | is fitted to 9 points rather than 3 points as in cannyEdgelList(), the
accuracy is higher. | |
| | | | |
|
| | | The function can be called in two modes: If you pass a 'scale', it is a | |
| | | ssumed that the | |
| | | 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 | |
| | | the given image already contains the gradient (i.e. its value_type must | |
| | | be | |
| | | a vector of length 2). | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass arguments explicitly: | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
|
| | | // compute edgels from a gradient image | |
| | | template <class SrcIterator, class SrcAccessor, class BackInsertabl | |
| | | e> | |
| | | void cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor | |
| | | src, | |
| | | BackInsertable & edgels); | |
| | | | |
| | | // compute edgels from a scaler 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 | |
| | | template <class SrcIterator, class SrcAccessor, class BackInsertabl | |
| | | e> | |
| | | void | |
| | | cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src | |
| | | , | |
| | | BackInsertable & edgels); | |
| | | | |
| | | // compute edgels from a scaler 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> \<<a href="edgedetection_8hxx-source.html">vigra/edged
etection.hxx</a>\><br> | |
| | | | |
| skipping to change at line 2101 | | skipping to change at line 2163 | |
| | | | |
| <b> Preconditions:</b> | | <b> Preconditions:</b> | |
| | | | |
| \code | | \code | |
| scale > 0 | | scale > 0 | |
| \endcode | | \endcode | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void cannyEdgelList3x3) | | doxygen_overloaded_function(template <...> void cannyEdgelList3x3) | |
| | | | |
| template <class SrcIterator, class SrcAccessor, class BackInsertable> | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
|
| void cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src, | | void | |
| BackInsertable & edgels, double scale) | | cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src, | |
| | | BackInsertable & edgels, double scale) | |
| { | | { | |
|
| int w = lr.x - ul.x; | | | |
| int h = lr.y - ul.y; | | | |
| | | | |
| typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType; | | typedef typename NumericTraits<typename SrcAccessor::value_type>::RealP
romote TmpType; | |
| BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); | | BasicImage<TinyVector<TmpType, 2> > grad(lr-ul); | |
| gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); | | gaussianGradient(srcIterRange(ul, lr, src), destImage(grad), scale); | |
| | | | |
|
| | | cannyEdgelList3x3(srcImageRange(grad), edgels); | |
| | | } | |
| | | | |
| | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
| | | inline void | |
| | | cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src, | |
| | | BackInsertable & edgels, double scale) | |
| | | { | |
| | | cannyEdgelList3x3(src.first, src.second, src.third, edgels, scale); | |
| | | } | |
| | | | |
| | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
| | | void | |
| | | cannyEdgelList3x3(SrcIterator ul, SrcIterator lr, SrcAccessor src, | |
| | | BackInsertable & edgels) | |
| | | { | |
| UInt8Image edges(lr-ul); | | UInt8Image edges(lr-ul); | |
|
| cannyEdgeImageFromGradWithThinning(srcImageRange(grad), destImage(edges
), | | cannyEdgeImageFromGradWithThinning(srcIterRange(ul, lr, src), destImage
(edges), | |
| 0.0, 1, false); | | 0.0, 1, false); | |
| | | | |
| // find edgels | | // find edgels | |
|
| internalCannyFindEdgels3x3(grad, edges, edgels); | | internalCannyFindEdgels3x3(ul, src, edges, edgels); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, class BackInsertable> | | template <class SrcIterator, class SrcAccessor, class BackInsertable> | |
| inline void | | inline void | |
| cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src, | | cannyEdgelList3x3(triple<SrcIterator, SrcIterator, SrcAccessor> src, | |
|
| BackInsertable & edgels, double scale) | | BackInsertable & edgels) | |
| { | | { | |
|
| cannyEdgelList3x3(src.first, src.second, src.third, edgels, scale); | | cannyEdgelList3x3(src.first, src.second, src.third, edgels); | |
| } | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| /** \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 accomodate 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 | |
| | | | |
End of changes. 64 change blocks. |
| 105 lines changed or deleted | | 202 lines changed or added | |
|
| fftw3.hxx | | fftw3.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2004 by Ullrich Koethe */ | | /* Copyright 1998-2004 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 458 | | skipping to change at line 456 | |
| { | | { | |
| typedef FFTWComplex Promote; | | typedef FFTWComplex Promote; | |
| }; | | }; | |
| | | | |
| template <> | | template <> | |
| struct PromoteTraits<double, FFTWComplex> | | struct PromoteTraits<double, FFTWComplex> | |
| { | | { | |
| typedef FFTWComplex Promote; | | typedef FFTWComplex Promote; | |
| }; | | }; | |
| | | | |
|
| | | template<class T> | |
| | | struct CanSkipInitialization<std::complex<T> > | |
| | | { | |
| | | typedef typename CanSkipInitialization<T>::type type; | |
| | | static const bool value = type::asBool; | |
| | | }; | |
| | | | |
| | | template<> | |
| | | struct CanSkipInitialization<FFTWComplex> | |
| | | { | |
| | | typedef CanSkipInitialization<fftw_real>::type type; | |
| | | static const bool value = type::asBool; | |
| | | }; | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* 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>
\> (for FFTW 3) or<br> | | <b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a>
\> (for FFTW 3) or<br> | |
| <b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br> | | <b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(for deprecated FFTW 2)<br> | |
| | | | |
| skipping to change at line 724 | | skipping to change at line 736 | |
| 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 { | |
| return i[d].re(); | | return i[d].re(); | |
| } | | } | |
| | | | |
|
| /// Write real part at iterator position. | | /// Write real part at iterator position from a scalar. | |
| 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; | |
| } | | } | |
| | | | |
|
| /// Write real part at offset from iterator position. | | /// 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. | |
| | | template <class ITERATOR> | |
| | | void set(FFTWComplex const & v, ITERATOR const & i) const { | |
| | | *i = v.re(); | |
| | | } | |
| | | | |
| | | /// Write real part at offset from iterator position into a scalar. | |
| | | template <class ITERATOR, class DIFFERENCE> | |
| | | void set(FFTWComplex const & v, ITERATOR const & i, DIFFERENCE d) const | |
| | | { | |
| | | 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>
\> (for FFTW 3) or<br> | | <b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a>
\> (for FFTW 3) or<br> | |
| <b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(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 FFTWImaginaryAccessor | | class FFTWImaginaryAccessor | |
| { | | { | |
| | | | |
| skipping to change at line 761 | | skipping to change at line 785 | |
| 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 { | |
| return i[d].im(); | | return i[d].im(); | |
| } | | } | |
| | | | |
|
| /// Write imaginary part at iterator position. | | /// Write imaginary part at iterator position from a scalar. | |
| 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).im()= v; | | (*i).im()= v; | |
| } | | } | |
| | | | |
|
| /// Write imaginary part at offset from iterator position. | | /// 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. | |
| | | template <class ITERATOR> | |
| | | void set(FFTWComplex const & v, ITERATOR const & i) const { | |
| | | *i = v.im(); | |
| | | } | |
| | | | |
| | | /// Write imaginary part at offset from iterator position into a sc | |
| | | alar. | |
| | | template <class ITERATOR, class DIFFERENCE> | |
| | | void set(FFTWComplex const & v, ITERATOR const & i, DIFFERENCE d) const | |
| | | { | |
| | | 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>
\> (for FFTW 3) or<br> | | <b>\#include</b> \<<a href="fftw3_8hxx-source.html">vigra/fftw3.hxx</a>
\> (for FFTW 3) or<br> | |
| <b>\#include</b> \<<a href="fftw_8hxx-source.html">vigra/fftw.hxx</a>\>
(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 | | class FFTWWriteRealAccessor: public FFTWRealAccessor | |
| | | | |
| skipping to change at line 1016 | | skipping to change at line 1052 | |
| \endcode | | \endcode | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void moveDCToCenter) | | doxygen_overloaded_function(template <...> void moveDCToCenter) | |
| | | | |
| 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) | |
| { | | { | |
|
| int w= src_lowerright.x - src_upperleft.x; | | int w = int(src_lowerright.x - src_upperleft.x); | |
| int h= src_lowerright.y - src_upperleft.y; | | int h = int(src_lowerright.y - src_upperleft.y); | |
| int w1 = w/2; | | int w1 = w/2; | |
| int h1 = h/2; | | int h1 = h/2; | |
| int w2 = (w+1)/2; | | int w2 = (w+1)/2; | |
| int h2 = (h+1)/2; | | int h2 = (h+1)/2; | |
| | | | |
| // 2. Quadrant zum 4. | | // 2. Quadrant zum 4. | |
| copyImage(srcIterRange(src_upperleft, | | copyImage(srcIterRange(src_upperleft, | |
| src_upperleft + Diff2D(w2, h2), sa), | | src_upperleft + Diff2D(w2, h2), sa), | |
| destIter (dest_upperleft + Diff2D(w1, h1), da)); | | destIter (dest_upperleft + Diff2D(w1, h1), da)); | |
| | | | |
| | | | |
| skipping to change at line 1098 | | skipping to change at line 1134 | |
| \endcode | | \endcode | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void moveDCToUpperLeft) | | doxygen_overloaded_function(template <...> void moveDCToUpperLeft) | |
| | | | |
| 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, SrcAccessor
sa, | | SrcImageIterator src_lowerright, SrcAccessor
sa, | |
| DestImageIterator dest_upperleft, DestAccess
or da) | | DestImageIterator dest_upperleft, DestAccess
or da) | |
| { | | { | |
|
| int w= src_lowerright.x - src_upperleft.x; | | int w = int(src_lowerright.x - src_upperleft.x); | |
| int h= src_lowerright.y - src_upperleft.y; | | int h = int(src_lowerright.y - src_upperleft.y); | |
| int w2 = w/2; | | int w2 = w/2; | |
| int h2 = h/2; | | int h2 = h/2; | |
| int w1 = (w+1)/2; | | int w1 = (w+1)/2; | |
| int h1 = (h+1)/2; | | int h1 = (h+1)/2; | |
| | | | |
| // 2. Quadrant zum 4. | | // 2. Quadrant zum 4. | |
| copyImage(srcIterRange(src_upperleft, | | copyImage(srcIterRange(src_upperleft, | |
| src_upperleft + Diff2D(w2, h2), sa), | | src_upperleft + Diff2D(w2, h2), sa), | |
| destIter (dest_upperleft + Diff2D(w1, h1), da)); | | destIter (dest_upperleft + Diff2D(w1, h1), da)); | |
| | | | |
| | | | |
| skipping to change at line 1136 | | skipping to change at line 1172 | |
| 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 = slr.x - sul.x; | | int w = int(slr.x - sul.x); | |
| int h = slr.y - sul.y; | | int h = int(slr.y - sul.y); | |
| | | | |
| FFTWComplexImage sworkImage, dworkImage; | | FFTWComplexImage sworkImage, dworkImage; | |
| | | | |
| fftw_complex * srcPtr = (fftw_complex *)(&*sul); | | fftw_complex * srcPtr = (fftw_complex *)(&*sul); | |
| fftw_complex * destPtr = (fftw_complex *)(&*dul); | | fftw_complex * destPtr = (fftw_complex *)(&*dul); | |
| | | | |
| // test for right memory layout (fftw expects a 2*width*height floats a
rray) | | // test for right memory layout (fftw expects a 2*width*height floats a
rray) | |
|
| if (&(*(sul + Diff2D(w, 0))) != &(*(sul + Diff2D(0, 1)))) | | if (h > 1 && &(*(sul + Diff2D(w, 0))) != &(*(sul + Diff2D(0, 1)))) | |
| { | | { | |
| sworkImage.resize(w, h); | | sworkImage.resize(w, h); | |
| copyImage(srcIterRange(sul, slr, src), destImage(sworkImage)); | | copyImage(srcIterRange(sul, slr, src), destImage(sworkImage)); | |
| srcPtr = (fftw_complex *)(&(*sworkImage.upperLeft())); | | srcPtr = (fftw_complex *)(&(*sworkImage.upperLeft())); | |
| } | | } | |
|
| if (&(*(dul + Diff2D(w, 0))) != &(*(dul + Diff2D(0, 1)))) | | if (h > 1 && &(*(dul + Diff2D(w, 0))) != &(*(dul + Diff2D(0, 1)))) | |
| { | | { | |
| dworkImage.resize(w, h); | | dworkImage.resize(w, h); | |
| destPtr = (fftw_complex *)(&(*dworkImage.upperLeft())); | | destPtr = (fftw_complex *)(&(*dworkImage.upperLeft())); | |
| } | | } | |
| | | | |
| fftw_plan plan = fftw_plan_dft_2d(h, w, srcPtr, destPtr, sign, FFTW_EST
IMATE ); | | fftw_plan plan = fftw_plan_dft_2d(h, w, srcPtr, destPtr, sign, FFTW_EST
IMATE ); | |
| fftw_execute(plan); | | fftw_execute(plan); | |
| fftw_destroy_plan(plan); | | fftw_destroy_plan(plan); | |
| | | | |
|
| if (&(*(dul + Diff2D(w, 0))) != &(*(dul + Diff2D(0, 1)))) | | if (h > 1 && &(*(dul + Diff2D(w, 0))) != &(*(dul + Diff2D(0, 1)))) | |
| { | | { | |
| copyImage(srcImageRange(dworkImage), destIter(dul, dest)); | | copyImage(srcImageRange(dworkImage), destIter(dul, dest)); | |
| } | | } | |
| } | | } | |
| | | | |
| } // namespace detail | | } // namespace detail | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* fourierTransform */ | | /* fourierTransform */ | |
| | | | |
| skipping to change at line 1287 | | skipping to change at line 1352 | |
| See \ref fourierTransform() for details. | | See \ref fourierTransform() for details. | |
| */ | | */ | |
| 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> | |
| | | void fourierTransformInverse(FFTWComplexImage::const_traverser sul, | |
| | | FFTWComplexImage::const_traverser slr, FFTWCom | |
| | | plexImage::ConstAccessor src, | |
| | | DestImageIterator dul, DestAccessor dest) | |
| | | { | |
| | | int w = slr.x - sul.x; | |
| | | int h = slr.y - sul.y; | |
| | | | |
| | | FFTWComplexImage workImage(w, h); | |
| | | fourierTransformInverse(sul, slr, src, workImage.upperLeft(), workImage | |
| | | .accessor()); | |
| | | copyImage(srcImageRange(workImage), destIter(dul, dest)); | |
| | | } | |
| | | | |
| | | template <class DestImageIterator, class DestAccessor> | |
| inline void | | inline void | |
| fourierTransformInverse(triple<FFTWComplexImage::const_traverser, | | fourierTransformInverse(triple<FFTWComplexImage::const_traverser, | |
| FFTWComplexImage::const_traverser, FFTWCompl
exImage::ConstAccessor> src, | | FFTWComplexImage::const_traverser, FFTWCompl
exImage::ConstAccessor> src, | |
|
| pair<FFTWComplexImage::traverser, FFTWComplexImage:
:Accessor> dest) | | pair<DestImageIterator, DestAccessor> dest) | |
| { | | { | |
| fourierTransformInverse(src.first, src.second, src.third, dest.first, d
est.second); | | fourierTransformInverse(src.first, src.second, src.third, dest.first, d
est.second); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* applyFourierFilter */ | | /* applyFourierFilter */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| | | | |
| skipping to change at line 1384 | | skipping to change at line 1463 | |
| | | | |
| template <class SrcImageIterator, class SrcAccessor, | | template <class SrcImageIterator, class SrcAccessor, | |
| class FilterImageIterator, class FilterAccessor, | | class FilterImageIterator, class FilterAccessor, | |
| class DestImageIterator, class DestAccessor> | | class DestImageIterator, class DestAccessor> | |
| void applyFourierFilter(SrcImageIterator srcUpperLeft, | | void applyFourierFilter(SrcImageIterator srcUpperLeft, | |
| SrcImageIterator srcLowerRight, SrcAccessor sa, | | SrcImageIterator srcLowerRight, SrcAccessor sa, | |
| FilterImageIterator filterUpperLeft, 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= srcLowerRight.x - srcUpperLeft.x; | | int w = int(srcLowerRight.x - srcUpperLeft.x); | |
| int h= 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); | |
| | | | |
| skipping to change at line 1447 | | skipping to change at line 1526 | |
| applyFourierFilter(src.first, src.second, src.third, | | applyFourierFilter(src.first, src.second, src.third, | |
| filter.first, filter.second, | | filter.first, filter.second, | |
| dest.first, dest.second); | | dest.first, dest.second); | |
| } | | } | |
| | | | |
| template <class FilterImageIterator, class FilterAccessor, | | template <class FilterImageIterator, class FilterAccessor, | |
| class DestImageIterator, class DestAccessor> | | class DestImageIterator, class DestAccessor> | |
| void applyFourierFilterImpl( | | void applyFourierFilterImpl( | |
| FFTWComplexImage::const_traverser srcUpperLeft, | | FFTWComplexImage::const_traverser srcUpperLeft, | |
| FFTWComplexImage::const_traverser srcLowerRight, | | FFTWComplexImage::const_traverser srcLowerRight, | |
|
| FFTWComplexImage::ConstAccessor sa, | | FFTWComplexImage::ConstAccessor, | |
| FilterImageIterator filterUpperLeft, FilterAccessor fa, | | FilterImageIterator filterUpperLeft, FilterAccessor fa, | |
| DestImageIterator destUpperLeft, DestAccessor da) | | DestImageIterator destUpperLeft, DestAccessor da) | |
| { | | { | |
|
| int w = srcLowerRight.x - srcUpperLeft.x; | | int w = int(srcLowerRight.x - srcUpperLeft.x); | |
| int h = srcLowerRight.y - srcUpperLeft.y; | | int h = int(srcLowerRight.y - srcUpperLeft.y); | |
| | | | |
| FFTWComplexImage complexResultImg(srcLowerRight - srcUpperLeft); | | FFTWComplexImage complexResultImg(srcLowerRight - srcUpperLeft); | |
| | | | |
| // 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); | |
| | | | |
| skipping to change at line 1609 | | skipping to change at line 1688 | |
| filters, results); | | filters, results); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class SrcAccessor, | | template <class SrcImageIterator, class SrcAccessor, | |
| class FilterType, class DestImage> | | class FilterType, class DestImage> | |
| 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= srcLowerRight.x - srcUpperLeft.x; | | int w = int(srcLowerRight.x - srcUpperLeft.x); | |
| int h= 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); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1669 | | skipping to change at line 1748 | |
| | | | |
| // make sure the filter images have the right dimensions | | // make sure the filter images have the right dimensions | |
| vigra_precondition((srcLowerRight - srcUpperLeft) == filters.imageSize(
), | | vigra_precondition((srcLowerRight - srcUpperLeft) == filters.imageSize(
), | |
| "applyFourierFilterFamily called with src image size
!= filters.imageSize()!"); | | "applyFourierFilterFamily called with src image size
!= filters.imageSize()!"); | |
| | | | |
| // make sure the result image array has the right dimensions | | // make sure the result image array has the right dimensions | |
| results.resize(filters.size()); | | results.resize(filters.size()); | |
| results.resizeImages(filters.imageSize()); | | results.resizeImages(filters.imageSize()); | |
| | | | |
| // FFT from srcImage to freqImage | | // FFT from srcImage to freqImage | |
|
| int w= srcLowerRight.x - srcUpperLeft.x; | | int w = int(srcLowerRight.x - srcUpperLeft.x); | |
| int h= srcLowerRight.y - srcUpperLeft.y; | | int h = int(srcLowerRight.y - srcUpperLeft.y); | |
| | | | |
| FFTWComplexImage freqImage(w, h); | | FFTWComplexImage freqImage(w, h); | |
| FFTWComplexImage result(w, h); | | FFTWComplexImage result(w, h); | |
| | | | |
| 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 *)freqImage.begin(), | | (fftw_complex *)freqImage.begin(), | |
| FFTW_FORWARD, FFTW_ESTIMATE ); | | FFTW_FORWARD, FFTW_ESTIMATE ); | |
| fftw_execute(forwardPlan); | | fftw_execute(forwardPlan); | |
| fftw_destroy_plan(forwardPlan); | | fftw_destroy_plan(forwardPlan); | |
| | | | |
End of changes. 24 change blocks. |
| 26 lines changed or deleted | | 110 lines changed or added | |
|
| fixedpoint.hxx | | fixedpoint.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2004-2005 by Ullrich Koethe */ | | /* Copyright 2004-2005 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 805 | | skipping to change at line 803 | |
| | | | |
| template <unsigned IntBits1, unsigned FracBits1, unsigned IntBits2, unsigne
d FracBits2> | | template <unsigned IntBits1, unsigned FracBits1, unsigned IntBits2, unsigne
d FracBits2> | |
| struct PromoteTraits<FixedPoint<IntBits1, FracBits1>, | | struct PromoteTraits<FixedPoint<IntBits1, FracBits1>, | |
| FixedPoint<IntBits2, FracBits2> > | | FixedPoint<IntBits2, FracBits2> > | |
| { | | { | |
| typedef typename | | typedef typename | |
| FixedPointTraits<FixedPoint<IntBits1, FracBits1>, FixedPoint<IntBit
s2, FracBits2> >::PlusType | | FixedPointTraits<FixedPoint<IntBits1, FracBits1>, FixedPoint<IntBit
s2, FracBits2> >::PlusType | |
| Promote; | | Promote; | |
| }; | | }; | |
| | | | |
|
| | | /************************************************************************** | |
| | | *********/ | |
| | | | |
| | | enum FPOverflowHandling { FPOverflowIgnore, FPOverflowSaturate, FPOverflowE | |
| | | rror }; | |
| | | | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling = FPOverflowIgno | |
| | | re> | |
| | | class FixedPoint16; | |
| | | | |
| | | /********************************************************/ | |
| | | /* */ | |
| | | /* FixedPoint16-Traits */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | /** \page FixedPoint16Traits Numeric and Promote Traits of FixedPoint16 | |
| | | | |
| | | The numeric and promote traits for FixedPoint16 follow | |
| | | the general specifications for \ref NumericPromotionTraits and | |
| | | \ref AlgebraicRing. They are implemented in terms of the traits of the | |
| | | basic types by | |
| | | partial template specialization: | |
| | | | |
| | | \code | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct NumericTraits<FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Type; | |
| | | typedef Type Promote; | |
| | | // RealPromote undefined -- multiplication with double is not s | |
| | | upported. | |
| | | // ComplexPromote undefined -- multiplication with double is no | |
| | | t supported. | |
| | | typedef Type ValueType; | |
| | | | |
| | | typedef VigraFalseType isIntegral; | |
| | | typedef VigraTrueType isScalar; | |
| | | typedef VigraTrueType isSigned; | |
| | | typedef VigraTrueType isOrdered; | |
| | | typedef VigraFalseType isComplex; | |
| | | | |
| | | ... // etc. | |
| | | }; | |
| | | | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBit | |
| | | s2> | |
| | | struct PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, | |
| | | FixedPoint16<IntBits2, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<MetaMax<IntBits1, IntBits2>::value, OverflowHa | |
| | | ndling> Promote; | |
| | | ... // etc. | |
| | | }; | |
| | | | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct NormTraits<FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Type; | |
| | | typedef typename PromoteTraits<Type, Type>::Promote SquaredNormType | |
| | | ; | |
| | | typedef Type NormType; | |
| | | }; | |
| | | | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct SquareRootTraits<FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Type; | |
| | | typedef FixedPoint16<(IntBits + 1) / 2, OverflowHandling> SquareRo | |
| | | otResult; | |
| | | typedef Type SquareRo | |
| | | otArgument; | |
| | | }; | |
| | | \endcode | |
| | | | |
| | | <b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vigra/fixedpoi | |
| | | nt.hxx</a>\><br> | |
| | | Namespace: vigra | |
| | | | |
| | | */ | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct NumericTraits<FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Type; | |
| | | typedef Type Promote; | |
| | | // RealPromote undefined -- multiplication with double is not suppo | |
| | | rted. | |
| | | // ComplexPromote undefined -- multiplication with double is not su | |
| | | pported. | |
| | | typedef Type ValueType; | |
| | | | |
| | | typedef VigraFalseType isIntegral; | |
| | | typedef VigraTrueType isScalar; | |
| | | typedef VigraTrueType isSigned; | |
| | | typedef VigraTrueType isOrdered; | |
| | | typedef VigraFalseType isComplex; | |
| | | | |
| | | static Type zero() { return Type(0, FPNoShift); } | |
| | | static Type one() { return Type(Type::ONE, FPNoShift); } | |
| | | static Type nonZero() { return one(); } | |
| | | static Type epsilon() { return Type(1, FPNoShift); } | |
| | | static Type smallestPositive() { return Type(1, FPNoShift); } | |
| | | static Type max() { return Type( Type::MAX, FPNoShift); } | |
| | | static Type min() { return Type( Type::MIN, FPNoShift); } | |
| | | | |
| | | static Promote toPromote(Type v) { return v; } | |
| | | static Type fromPromote(Promote v) { return v; }; | |
| | | }; | |
| | | | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | struct PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, | |
| | | FixedPoint16<IntBits2, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<MetaMax<IntBits1, IntBits2>::value, OverflowHandli | |
| | | ng> Promote; | |
| | | static Promote toPromote(FixedPoint16<IntBits1, OverflowHandling> v) { | |
| | | return Promote(v); } | |
| | | static Promote toPromote(FixedPoint16<IntBits2, OverflowHandling> v) { | |
| | | return Promote(v); } | |
| | | }; | |
| | | | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct PromoteTraits<FixedPoint16<IntBits, OverflowHandling>, | |
| | | FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Promote; | |
| | | static Promote toPromote(FixedPoint16<IntBits, OverflowHandling> v) { r | |
| | | eturn v; } | |
| | | }; | |
| | | | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct NormTraits<FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Type; | |
| | | typedef typename PromoteTraits<Type, Type>::Promote SquaredNormType; | |
| | | typedef Type NormType; | |
| | | }; | |
| | | | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | struct SquareRootTraits<FixedPoint16<IntBits, OverflowHandling> > | |
| | | { | |
| | | typedef FixedPoint16<IntBits, OverflowHandling> Type; | |
| | | typedef FixedPoint16<(IntBits + 1) / 2, OverflowHandling> SquareRootRe | |
| | | sult; | |
| | | typedef Type SquareRootAr | |
| | | gument; | |
| | | }; | |
| | | | |
| | | #ifndef DOXYGEN | |
| | | | |
| | | template <bool Compatible> | |
| | | struct FixedPoint_error__Right_shift_operator_has_unsupported_semantics | |
| | | : staticAssert::AssertBool<Compatible> | |
| | | {}; | |
| | | | |
| | | #endif /* DOXYGEN */ | |
| | | | |
| | | template <bool Predicate> | |
| | | struct FixedPoint16_assignment_error__Target_object_has_too_few_integer_bit | |
| | | s | |
| | | : staticAssert::AssertBool<Predicate> | |
| | | {}; | |
| | | | |
| | | namespace detail { | |
| | | | |
| | | template<int BeforeIntBits, int AfterIntBits, | |
| | | bool Round = false, | |
| | | bool RightShift = (AfterIntBits >= BeforeIntBits)> | |
| | | struct FP16Align; | |
| | | | |
| | | template<int BeforeIntBits> | |
| | | struct FP16Align<BeforeIntBits, BeforeIntBits, true, true> | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | return v; | |
| | | } | |
| | | }; | |
| | | | |
| | | template<int BeforeIntBits> | |
| | | struct FP16Align<BeforeIntBits, BeforeIntBits, false, true> | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | return v; | |
| | | } | |
| | | }; | |
| | | | |
| | | template<int BeforeIntBits, int AfterIntBits> | |
| | | struct FP16Align<BeforeIntBits, AfterIntBits, false, true> | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | return v >> (AfterIntBits - BeforeIntBits); | |
| | | } | |
| | | }; | |
| | | | |
| | | template<int BeforeIntBits, int AfterIntBits> | |
| | | struct FP16Align<BeforeIntBits, AfterIntBits, true, true> | |
| | | { | |
| | | enum { ONE_HALF = 1 << (AfterIntBits - BeforeIntBits - 1) }; | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | return (v + ONE_HALF) >> (AfterIntBits - BeforeIntBits); | |
| | | } | |
| | | }; | |
| | | | |
| | | template<int BeforeIntBits, int AfterIntBits, bool Round> | |
| | | struct FP16Align<BeforeIntBits, AfterIntBits, Round, false> | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | return v << (BeforeIntBits - AfterIntBits); | |
| | | } | |
| | | }; | |
| | | | |
| | | template <FPOverflowHandling OverflowHandling = FPOverflowIgnore> | |
| | | struct FP16OverflowHandling | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | return v; | |
| | | } | |
| | | | |
| | | static inline Int32 exec(UInt32 v) | |
| | | { | |
| | | return v; | |
| | | } | |
| | | }; | |
| | | | |
| | | template <> | |
| | | struct FP16OverflowHandling<FPOverflowSaturate> | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | if(v >= 1 << 15) | |
| | | return (1 << 15) - 1; | |
| | | if(v < -(1 << 15)) | |
| | | return -(1 << 15); | |
| | | return v; | |
| | | } | |
| | | static inline Int32 exec(UInt32 v) | |
| | | { | |
| | | if(v >= 1 << 15) | |
| | | return (1 << 15) - 1; | |
| | | return v; | |
| | | } | |
| | | }; | |
| | | | |
| | | template <> | |
| | | struct FP16OverflowHandling<FPOverflowError> | |
| | | { | |
| | | static inline Int32 exec(Int32 v) | |
| | | { | |
| | | vigra_precondition(v < (1 << 15) && v >= -(1 << 15), | |
| | | "FixedPoint16: Operation overflows."); | |
| | | return v; | |
| | | } | |
| | | static inline Int32 exec(UInt32 v) | |
| | | { | |
| | | vigra_precondition(v < (1 << 15), | |
| | | "FixedPoint16: Operation overflows."); | |
| | | return v; | |
| | | } | |
| | | }; | |
| | | | |
| | | template <int IntBits1, int IntBits2, int IntBitsOut, | |
| | | FPOverflowHandling OverflowHandling > | |
| | | struct FP16AddImpl | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | static inline Int32 exec(Int32 t1, Int32 t2) | |
| | | { | |
| | | return FP16OverflowHandling<OverflowHandling>::exec( | |
| | | FP16Align<MinIntBits, IntBitsOut, /*Round*/ true>::exec( | |
| | | FP16Align<IntBits1, MinIntBits, /*Round*/ false>::exe | |
| | | c(t1) + | |
| | | FP16Align<IntBits2, MinIntBits, /*Round*/ false>::exe | |
| | | c(t2))); | |
| | | } | |
| | | }; | |
| | | | |
| | | template <int IntBits1, int IntBits2, int IntBitsOut, | |
| | | FPOverflowHandling OverflowHandling > | |
| | | struct FP16SubImpl | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | static inline Int32 exec(Int32 t1, Int32 t2) | |
| | | { | |
| | | return FP16OverflowHandling<OverflowHandling>::exec( | |
| | | FP16Align<MinIntBits, IntBitsOut, /*Round*/ true>::exec( | |
| | | FP16Align<IntBits1, MinIntBits, /*Round*/ false>::exe | |
| | | c(t1) - | |
| | | FP16Align<IntBits2, MinIntBits, /*Round*/ false>::exe | |
| | | c(t2))); | |
| | | } | |
| | | }; | |
| | | | |
| | | template <int IntBits1, int IntBits2, int IntBitsOut, | |
| | | FPOverflowHandling OverflowHandling > | |
| | | struct FP16MulImpl | |
| | | { | |
| | | static inline Int32 exec(Int32 t1, Int32 t2) | |
| | | { | |
| | | return FP16OverflowHandling<OverflowHandling>::exec( | |
| | | FP16Align<IntBits1+IntBits2, IntBitsOut+15, /*Round*/ tr | |
| | | ue>::exec(t1*t2)); | |
| | | } | |
| | | }; | |
| | | | |
| | | template <int IntBits1, int IntBits2, int IntBitsOut, | |
| | | FPOverflowHandling OverflowHandling > | |
| | | struct FP16DivImpl | |
| | | { | |
| | | static inline Int32 exec(Int32 t1, Int32 t2) | |
| | | { | |
| | | if(t2 == 0) | |
| | | return (t1 >= 0) | |
| | | ? (1 << 15) - 1 | |
| | | : -(1 << 15); | |
| | | return FP16OverflowHandling<OverflowHandling>::exec( | |
| | | FP16Align<IntBits1-IntBits2, IntBitsOut+1, /*Round*/ tru | |
| | | e>::exec((t1<<16)/t2)); | |
| | | } | |
| | | }; | |
| | | | |
| | | } // namespace detail | |
| | | | |
| | | /********************************************************/ | |
| | | /* */ | |
| | | /* FixedPoint16 */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | template <class TARGET, int IntBits, FPOverflowHandling OverflowHandling> | |
| | | TARGET fixed_point_cast(FixedPoint16<IntBits, OverflowHandling> v); | |
| | | | |
| | | /** Template for 16-bit signed fixed point arithmetic. | |
| | | | |
| | | Fixed point arithmetic is used when computations with fractional accura | |
| | | cy | |
| | | must be made at the highest speed possible (e.g. in the inner loop | |
| | | of a volume rendering routine). The speed-up relative to floating | |
| | | point arithmetic can be dramatic, especially when one can avoid | |
| | | conversions between integer and floating point numbers (these are | |
| | | very expensive because integer and floating point arithmetic | |
| | | resides in different pipelines). | |
| | | | |
| | | The template wraps an <tt>Int16</tt> and uses <tt>IntBits</tt> to | |
| | | represent the integral part of a number, and <tt>15 - IntBits</tt> | |
| | | for the fractional part. The 16th bit is reserved because FixedPoint16 | |
| | | is a signed type. Results of expressions with mixed types will preserve | |
| | | larger number of <tt>IntBits</tt> of the results, in order to minimize | |
| | | the possibility for overflow. Nonetheless, overflow can occur, and the | |
| | | template parameter <tt>OverflowHandling</tt> determines how this will b | |
| | | e | |
| | | handled: | |
| | | | |
| | | <DL> | |
| | | <DT>FPOverflowIgnore<DD> (default) Ignore overflow, i.e. use the usual | |
| | | modulo behavior of the | |
| | | built-in integer types. | |
| | | | |
| | | <DT>FPOverflowSaturate<DD> Use the largest or smallest representable nu | |
| | | mber (depending on sign) | |
| | | in case of overflow. | |
| | | | |
| | | <DT>FPOverflowError<DD> Throw <tt>PreconditionViolation</tt> upon overf | |
| | | low. This is useful for | |
| | | debugging. | |
| | | </DL> | |
| | | | |
| | | The implementation relies on Int32-arithmetic and requires that the rig | |
| | | ht-shift operator | |
| | | preserves signedness. Although not enforced by the C++ standard, this i | |
| | | s implemented | |
| | | by most of today's processors. This property is checked by a | |
| | | VIGRA_STATIC_ASSERT(FixedPoint_error__Right_shift_operator_has_unsuppor | |
| | | ted_semantics). | |
| | | | |
| | | <tt>FixedPoint16</tt> implements the required interface of an | |
| | | \ref AlgebraicRing and the required numeric and | |
| | | promotion traits. In addition, it supports functions <tt>add</tt>, | |
| | | <tt>sub</tt>, <tt>mul</tt>, and <tt>div</tt>, where a particular layout | |
| | | of the result can be enforced. | |
| | | | |
| | | Built-in numeric types can be converted into <tt>FixedPoint16</tt> by t | |
| | | he | |
| | | appropriate constructors, and from <tt>FixedPoint16</tt> by means of | |
| | | <tt>fixed_point_cast<TargetType>(fixedPoint)</tt>. | |
| | | | |
| | | <b>See also:</b> | |
| | | <ul> | |
| | | <li> \ref FixedPoint16Operations | |
| | | <li> \ref FixedPoint16Traits | |
| | | </ul> | |
| | | | |
| | | <b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vigra/fixedpoi | |
| | | nt.hxx</a>\><br> | |
| | | Namespace: vigra | |
| | | */ | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | class FixedPoint16 | |
| | | { | |
| | | public: | |
| | | static const Int32 TOTAL_BITS = 15; // bit 16 is sign | |
| | | static const Int32 INT_BITS = IntBits; | |
| | | static const Int32 FRACTIONAL_BITS = TOTAL_BITS - INT_BITS; | |
| | | static const Int32 MAX = (Int32)((1u << TOTAL_BITS) - 1); | |
| | | static const Int32 MIN = -(Int32)(1u << TOTAL_BITS); | |
| | | static const Int32 ONE = 1 << FRACTIONAL_BITS; | |
| | | static const Int32 ONE_HALF = ONE >> 1; | |
| | | static const Int32 FRACTIONAL_MASK = (1u << FRACTIONAL_BITS) - 1; | |
| | | static const Int32 INT_MASK = 0xffffffffu ^ FRACTIONAL_MASK; | |
| | | | |
| | | Int16 value; | |
| | | | |
| | | FixedPoint16() | |
| | | : value(0) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | } | |
| | | | |
| | | /** Construct from an int (fractional part will become zero). | |
| | | Possible overflow is handled according to the taget type's <tt> | |
| | | OverflowHandling</tt>. | |
| | | */ | |
| | | explicit FixedPoint16(Int32 v) | |
| | | : value(detail::FP16OverflowHandling<OverflowHandling>::exec(v << FRACT | |
| | | IONAL_BITS)) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | } | |
| | | | |
| | | /** Construct from an int by a bitwise copy. This is normally only | |
| | | used internally. | |
| | | */ | |
| | | FixedPoint16(Int32 v, FixedPointNoShift) | |
| | | : value(detail::FP16OverflowHandling<OverflowHandling>::exec(v)) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | } | |
| | | | |
| | | /** Construct from a double and round the fractional part to | |
| | | <tt>FRACTIONAL_BITS</tt> accuracy. Possible overflow is handled | |
| | | according | |
| | | to the taget type's <tt>OverflowHandling</tt>. | |
| | | */ | |
| | | explicit FixedPoint16(double rhs) | |
| | | : value(detail::FP16OverflowHandling<OverflowHandling>::exec(roundi(rhs | |
| | | * ONE))) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | } | |
| | | | |
| | | /** Copy constructor. | |
| | | */ | |
| | | FixedPoint16(const FixedPoint16 &other) | |
| | | : value(other.value) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | } | |
| | | | |
| | | /** Construct from a FixedPoint16 with different layout. It rounds | |
| | | as appropriate and | |
| | | handles possible overflow according to the taget type's <tt>Ove | |
| | | rflowHandling</tt>. | |
| | | */ | |
| | | template <int IntBits2, FPOverflowHandling OverflowHandling2> | |
| | | FixedPoint16(const FixedPoint16<IntBits2, OverflowHandling2> &other) | |
| | | : value(detail::FP16OverflowHandling<OverflowHandling>::exec( | |
| | | detail::FP16Align<IntBits2, IntBits, /*Round*/true>::exec(other | |
| | | .value))) | |
| | | { | |
| | | VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_uns | |
| | | upported_semantics<((-1 >> 8) == -1)>)); | |
| | | } | |
| | | | |
| | | /** Assignment from int. The fractional part will become zero. | |
| | | Possible overflow is handled according to the taget type's <tt> | |
| | | OverflowHandling</tt>. | |
| | | */ | |
| | | FixedPoint16 &operator=(Int32 rhs) | |
| | | { | |
| | | value = detail::FP16OverflowHandling<OverflowHandling>::exec(rhs << | |
| | | FRACTIONAL_BITS); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Assignment form double. The fractional part is rounded, and pos | |
| | | sible overflow is | |
| | | handled according to the taget type's <tt>OverflowHandling</tt> | |
| | | . | |
| | | */ | |
| | | FixedPoint16 &operator=(double rhs) | |
| | | { | |
| | | value = detail::FP16OverflowHandling<OverflowHandling>::exec(roundi | |
| | | (rhs * ONE)); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Copy assignment. | |
| | | */ | |
| | | FixedPoint16 & operator=(const FixedPoint16 &other) | |
| | | { | |
| | | value = other.value; | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Assignment from a FixedPoint16 with different layout. It rounds | |
| | | as appropriate, and possible overflow is | |
| | | handled according to the taget type's <tt>OverflowHandling</tt> | |
| | | . | |
| | | */ | |
| | | template <int IntBits2> | |
| | | FixedPoint16 & operator=(const FixedPoint16<IntBits2, OverflowHandling> | |
| | | &other) | |
| | | { | |
| | | value = detail::FP16OverflowHandling<OverflowHandling>::exec( | |
| | | detail::FP16Align<IntBits2, IntBits, /*Round*/true>::exec(o | |
| | | ther.value)); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Conversion to float | |
| | | */ | |
| | | operator float() const | |
| | | { | |
| | | return fixed_point_cast<float>(*this); | |
| | | } | |
| | | | |
| | | /** Conversion to double | |
| | | */ | |
| | | operator double() const | |
| | | { | |
| | | return fixed_point_cast<double>(*this); | |
| | | } | |
| | | | |
| | | /** Unary plus. | |
| | | */ | |
| | | FixedPoint16 operator+() const | |
| | | { | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Negation. | |
| | | */ | |
| | | FixedPoint16 operator-() const | |
| | | { | |
| | | return FixedPoint16(-value, FPNoShift); | |
| | | } | |
| | | | |
| | | /** Pre-increment. | |
| | | */ | |
| | | FixedPoint16 & operator++() | |
| | | { | |
| | | value = detail::FP16OverflowHandling<OverflowHandling>::exec(value+ | |
| | | ONE); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Post-increment. | |
| | | */ | |
| | | FixedPoint16 operator++(int) | |
| | | { | |
| | | FixedPoint16 old(*this); | |
| | | ++(*this); | |
| | | return old; | |
| | | } | |
| | | | |
| | | /** Pre-decrement. | |
| | | */ | |
| | | FixedPoint16 & operator--() | |
| | | { | |
| | | value = detail::FP16OverflowHandling<OverflowHandling>::exec(value- | |
| | | ONE); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Post-decrement. | |
| | | */ | |
| | | FixedPoint16 operator--(int) | |
| | | { | |
| | | FixedPoint16 old(*this); | |
| | | --(*this); | |
| | | return old; | |
| | | } | |
| | | | |
| | | /** Add-assignment from a FixedPoint16 with different layout. It ro | |
| | | unds as appropriate, and possible overflow is | |
| | | handled according to the taget type's <tt>OverflowHandling</tt> | |
| | | . | |
| | | */ | |
| | | template <int IntBits2> | |
| | | FixedPoint16 & operator+=(const FixedPoint16<IntBits2, OverflowHandling | |
| | | > &other) | |
| | | { | |
| | | value = detail::FP16AddImpl<IntBits, IntBits2, IntBits, OverflowHan | |
| | | dling>::exec(value, other.value); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Subtract-assignment from a FixedPoint16 with different layout. | |
| | | It rounds as appropriate, and possible overflow is | |
| | | handled according to the taget type's <tt>OverflowHandling</tt> | |
| | | . | |
| | | */ | |
| | | template <int IntBits2> | |
| | | FixedPoint16 & operator-=(const FixedPoint16<IntBits2, OverflowHandling | |
| | | > &other) | |
| | | { | |
| | | value = detail::FP16SubImpl<IntBits, IntBits2, IntBits, OverflowHan | |
| | | dling>::exec(value, other.value); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Multiply-assignment from a FixedPoint16 with different layout. | |
| | | It rounds as appropriate, and possible overflow is | |
| | | handled according to the taget type's <tt>OverflowHandling</tt> | |
| | | . | |
| | | */ | |
| | | template <int IntBits2> | |
| | | FixedPoint16 & operator*=(const FixedPoint16<IntBits2, OverflowHandling | |
| | | > &other) | |
| | | { | |
| | | value = detail::FP16MulImpl<IntBits, IntBits2, IntBits, OverflowHan | |
| | | dling>::exec(value, other.value); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Divide-assignment from a FixedPoint16 with different layout. It | |
| | | rounds as appropriate, and possible overflow is | |
| | | handled according to the taget type's <tt>OverflowHandling</tt> | |
| | | . | |
| | | */ | |
| | | template <int IntBits2> | |
| | | FixedPoint16 & operator/=(const FixedPoint16<IntBits2, OverflowHandling | |
| | | > &other) | |
| | | { | |
| | | value = detail::FP16DivImpl<IntBits, IntBits2, IntBits, OverflowHan | |
| | | dling>::exec(value, other.value); | |
| | | return *this; | |
| | | } | |
| | | }; | |
| | | | |
| | | namespace detail { | |
| | | | |
| | | template <class T> | |
| | | struct FixedPoint16Cast; | |
| | | | |
| | | #define VIGRA_FIXED_POINT_CAST(type) \ | |
| | | template <> \ | |
| | | struct FixedPoint16Cast<type> \ | |
| | | { \ | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> \ | |
| | | static type cast(FixedPoint16<IntBits, OverflowHandling> v) \ | |
| | | { \ | |
| | | return round(v); \ | |
| | | } \ | |
| | | }; | |
| | | | |
| | | VIGRA_FIXED_POINT_CAST(Int8) | |
| | | VIGRA_FIXED_POINT_CAST(UInt8) | |
| | | VIGRA_FIXED_POINT_CAST(Int16) | |
| | | VIGRA_FIXED_POINT_CAST(UInt16) | |
| | | VIGRA_FIXED_POINT_CAST(Int32) | |
| | | VIGRA_FIXED_POINT_CAST(UInt32) | |
| | | VIGRA_FIXED_POINT_CAST(Int64) | |
| | | VIGRA_FIXED_POINT_CAST(UInt64) | |
| | | | |
| | | #undef VIGRA_FIXED_POINT_CAST | |
| | | | |
| | | template <> | |
| | | struct FixedPoint16Cast<float> | |
| | | { | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | static float cast(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return (float)v.value / FixedPoint16<IntBits, OverflowHandling>::ON | |
| | | E; | |
| | | } | |
| | | }; | |
| | | | |
| | | template <> | |
| | | struct FixedPoint16Cast<double> | |
| | | { | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | static double cast(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return (double)v.value / FixedPoint16<IntBits, OverflowHandling>::O | |
| | | NE; | |
| | | } | |
| | | }; | |
| | | | |
| | | } // namespace detail | |
| | | | |
| | | /********************************************************/ | |
| | | /* */ | |
| | | /* FixedPoint16Operations */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | /** \addtogroup FixedPoint16Operations Functions for FixedPoint16 | |
| | | | |
| | | \brief <b>\#include</b> \<<a href="fixedpoint_8hxx-source.html">vig | |
| | | ra/fixedpoint.hxx</a>\><br> | |
| | | | |
| | | These functions fulfill the requirements of an \ref AlgebraicRing. | |
| | | | |
| | | Namespace: vigra | |
| | | <p> | |
| | | | |
| | | */ | |
| | | //@{ | |
| | | | |
| | | /** Convert a FixedPoint16 to a built-in type. | |
| | | If the target is integral, the value is rounded.<br> | |
| | | Usage: | |
| | | \code | |
| | | FixedPoint16<16,15> fp(...); | |
| | | | |
| | | double d = fixed_point_cast<double>(fp); | |
| | | \endcode | |
| | | */ | |
| | | template <class TARGET, int IntBits, FPOverflowHandling OverflowHandling> | |
| | | TARGET fixed_point_cast(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return detail::FixedPoint16Cast<TARGET>::cast(v); | |
| | | } | |
| | | | |
| | | /// equal | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | bool operator==(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<In | |
| | | tBits2, OverflowHandling> r) | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | return (l.value << (IntBits1 - MinIntBits)) == (r.value << (IntBits2 - | |
| | | MinIntBits)); | |
| | | } | |
| | | | |
| | | /// not equal | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | bool operator!=(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<In | |
| | | tBits2, OverflowHandling> r) | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | return (l.value << (IntBits1 - MinIntBits)) != (r.value << (IntBits2 - | |
| | | MinIntBits)); | |
| | | } | |
| | | | |
| | | /// less than | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | bool operator<(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<Int | |
| | | Bits2, OverflowHandling> r) | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | return (l.value << (IntBits1 - MinIntBits)) < (r.value << (IntBits2 - M | |
| | | inIntBits)); | |
| | | } | |
| | | | |
| | | /// less or equal | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | bool operator<=(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<In | |
| | | tBits2, OverflowHandling> r) | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | return (l.value << (IntBits1 - MinIntBits)) <= (r.value << (IntBits2 - | |
| | | MinIntBits)); | |
| | | } | |
| | | | |
| | | /// greater | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | bool operator>(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<Int | |
| | | Bits2, OverflowHandling> r) | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | return (l.value << (IntBits1 - MinIntBits)) > (r.value << (IntBits2 - M | |
| | | inIntBits)); | |
| | | } | |
| | | | |
| | | /// greater or equal | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | bool operator>=(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<In | |
| | | tBits2, OverflowHandling> r) | |
| | | { | |
| | | enum { MinIntBits = MetaMin<IntBits1, IntBits2>::value }; | |
| | | return (l.value << (IntBits1 - MinIntBits)) >= (r.value << (IntBits2 - | |
| | | MinIntBits)); | |
| | | } | |
| | | | |
| | | /// addition with automatic determination of the appropriate result typ | |
| | | e. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | typename PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint | |
| | | 16<IntBits2, OverflowHandling> >::Promote | |
| | | operator+(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2 | |
| | | , OverflowHandling> r) | |
| | | { | |
| | | typedef typename | |
| | | PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint1 | |
| | | 6<IntBits2, OverflowHandling> >::Promote | |
| | | Result; | |
| | | return Result(detail::FP16AddImpl<IntBits1, IntBits2, Result::INT_BITS, | |
| | | OverflowHandling>::exec(l.value, r.value), FPNoShift); | |
| | | } | |
| | | | |
| | | /// addition with enforced result type. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2, | |
| | | int IntBits3> | |
| | | inline | |
| | | FixedPoint16<IntBits3, OverflowHandling> & | |
| | | add(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2, Over | |
| | | flowHandling> r, | |
| | | FixedPoint16<IntBits3, OverflowHandling> & result) | |
| | | { | |
| | | result.value = detail::FP16AddImpl<IntBits1, IntBits2, IntBits3, Overfl | |
| | | owHandling>::exec(l.value, r.value); | |
| | | return result; | |
| | | } | |
| | | | |
| | | /// subtraction with automatic determination of the appropriate result | |
| | | type. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | typename PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint | |
| | | 16<IntBits2, OverflowHandling> >::Promote | |
| | | operator-(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2 | |
| | | , OverflowHandling> r) | |
| | | { | |
| | | typedef typename | |
| | | PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint1 | |
| | | 6<IntBits2, OverflowHandling> >::Promote | |
| | | Result; | |
| | | return Result(detail::FP16SubImpl<IntBits1, IntBits2, Result::INT_BITS, | |
| | | OverflowHandling>::exec(l.value, r.value), FPNoShift); | |
| | | } | |
| | | | |
| | | /// subtraction with enforced result type. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2, | |
| | | int IntBits3> | |
| | | inline FixedPoint16<IntBits3, OverflowHandling> & | |
| | | sub(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2, Over | |
| | | flowHandling> r, | |
| | | FixedPoint16<IntBits3, OverflowHandling> & result) | |
| | | { | |
| | | result.value = detail::FP16SubImpl<IntBits1, IntBits2, IntBits3, Overfl | |
| | | owHandling>::exec(l.value, r.value); | |
| | | return result; | |
| | | } | |
| | | | |
| | | /// multiplication with automatic determination of the appropriate resu | |
| | | lt type. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | typename PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint | |
| | | 16<IntBits2, OverflowHandling> >::Promote | |
| | | operator*(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2 | |
| | | , OverflowHandling> r) | |
| | | { | |
| | | typedef typename | |
| | | PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint1 | |
| | | 6<IntBits2, OverflowHandling> >::Promote | |
| | | Result; | |
| | | return Result(detail::FP16MulImpl<IntBits1, IntBits2, Result::INT_BITS, | |
| | | OverflowHandling>::exec(l.value, r.value), FPNoShift); | |
| | | } | |
| | | | |
| | | /// multiplication with enforced result type. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2, | |
| | | int IntBits3> | |
| | | inline | |
| | | FixedPoint16<IntBits3, OverflowHandling> & | |
| | | mul(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2, Over | |
| | | flowHandling> r, | |
| | | FixedPoint16<IntBits3, OverflowHandling> & result) | |
| | | { | |
| | | result.value = detail::FP16MulImpl<IntBits1, IntBits2, IntBits3, Overfl | |
| | | owHandling>::exec(l.value, r.value); | |
| | | return result; | |
| | | } | |
| | | | |
| | | /// division with automatic determination of the appropriate result typ | |
| | | e. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2> | |
| | | inline | |
| | | typename PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint | |
| | | 16<IntBits2, OverflowHandling> >::Promote | |
| | | operator/(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2 | |
| | | , OverflowHandling> r) | |
| | | { | |
| | | typedef typename | |
| | | PromoteTraits<FixedPoint16<IntBits1, OverflowHandling>, FixedPoint1 | |
| | | 6<IntBits2, OverflowHandling> >::Promote | |
| | | Result; | |
| | | return Result(detail::FP16DivImpl<IntBits1, IntBits2, Result::INT_BITS, | |
| | | OverflowHandling>::exec(l.value, r.value), FPNoShift); | |
| | | } | |
| | | | |
| | | /// division with enforced result type. | |
| | | template <int IntBits1, FPOverflowHandling OverflowHandling, int IntBits2, | |
| | | int IntBits3> | |
| | | inline | |
| | | FixedPoint16<IntBits3, OverflowHandling> & | |
| | | div(FixedPoint16<IntBits1, OverflowHandling> l, FixedPoint16<IntBits2, Over | |
| | | flowHandling> r, | |
| | | FixedPoint16<IntBits3, OverflowHandling> & result) | |
| | | { | |
| | | result.value = detail::FP16DivImpl<IntBits1, IntBits2, IntBits3, Overfl | |
| | | owHandling>::exec(l.value, r.value); | |
| | | return result; | |
| | | } | |
| | | | |
| | | /// square root. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline typename SquareRootTraits<FixedPoint16<IntBits, OverflowHandling> >: | |
| | | :SquareRootResult | |
| | | sqrt(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | typedef typename SquareRootTraits<FixedPoint16<IntBits, OverflowHandlin | |
| | | g> >::SquareRootResult Result; | |
| | | enum { Shift = 15 + IntBits - 2*Result::INT_BITS }; | |
| | | return Result(sqrti(v.value << Shift), FPNoShift); | |
| | | } | |
| | | | |
| | | #ifndef VIGRA_NO_HYPOT | |
| | | using ::hypot; | |
| | | #endif | |
| | | | |
| | | /// Length of hypothenuse. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline FixedPoint16<IntBits, OverflowHandling> | |
| | | hypot(FixedPoint16<IntBits, OverflowHandling> v1, FixedPoint16<IntBits, Ove | |
| | | rflowHandling> v2) | |
| | | { | |
| | | UInt32 l = abs(v1.value), r = abs(v2.value); | |
| | | // sq(l) + sq(r) <= 2**31, so overflow handling after sqrti is sufficie | |
| | | nt | |
| | | return FixedPoint16<IntBits, OverflowHandling>( | |
| | | detail::FP16OverflowHandling<OverflowHandling>::exec(sqr | |
| | | ti(sq(l) + sq(r))), | |
| | | FPNoShift); | |
| | | } | |
| | | | |
| | | using std::atan2; | |
| | | | |
| | | /// Arctangent. Accuracy better than 1/3 degree (9 significant bits). | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | FixedPoint16<2, OverflowHandling> | |
| | | atan2(FixedPoint16<IntBits, OverflowHandling> y, FixedPoint16<IntBits, Over | |
| | | flowHandling> x) | |
| | | { | |
| | | enum { ResIntBits = 2 }; | |
| | | typedef FixedPoint16<ResIntBits, OverflowHandling> FP; | |
| | | static const FP zero(0), pi(M_PI), pi_2(0.5 * M_PI), mpi_2(-0.5 * M_PI) | |
| | | ; | |
| | | static const Int32 Pi_4 = roundi(0.25 * M_PI * (1 << 15)), // 15 frac | |
| | | bits | |
| | | Pi3_4 = roundi(0.75 * M_PI * (1 << 15)), | |
| | | c1 = roundi(0.19826763260224867 * (1 << 15)), | |
| | | c2 = roundi(-0.9757748231899761 * (1 << 30)); | |
| | | // coefficients c1 and c2 minimize | |
| | | // | |
| | | // NIntegrate[(c1 r^3 + c2 r + Pi/4 - a)^4 /. r -> (Cos[a] - Sin[a])/(C | |
| | | os[a] + Sin[a]), {a, 0, Pi/2}] | |
| | | // | |
| | | // Thanks to Jim Shima, http://www.dspguru.com/comp.dsp/tricks/alg/fxda | |
| | | tan2.htm | |
| | | | |
| | | if(x.value == 0) | |
| | | return (y.value > 0) | |
| | | ? pi_2 | |
| | | : (y.value < 0) | |
| | | ? mpi_2 | |
| | | : zero; | |
| | | | |
| | | Int32 abs_y = abs(y.value); | |
| | | Int32 r, angle; | |
| | | if(x.value > 0) | |
| | | { | |
| | | if(y.value == 0) | |
| | | return zero; | |
| | | r = ((x.value - abs_y) << 15) / (x.value + abs_y); // 15 frac bits | |
| | | angle = Pi_4; | |
| | | } | |
| | | else | |
| | | { | |
| | | if(y.value == 0) | |
| | | return pi; | |
| | | r = ((x.value + abs_y) << 15) / (abs_y - x.value); // 15 frac bits | |
| | | angle = Pi3_4; | |
| | | } | |
| | | | |
| | | angle += r*((c2 + c1 * (sq(r) >> 15)) >> 15) >> 15; | |
| | | | |
| | | return (y.value > 0) | |
| | | ? FP(detail::FP16Align<0, ResIntBits, true>::exec( angle), F | |
| | | PNoShift) | |
| | | : FP(detail::FP16Align<0, ResIntBits, true>::exec(-angle), F | |
| | | PNoShift); | |
| | | } | |
| | | | |
| | | /// absolute value. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline FixedPoint16<IntBits, OverflowHandling> | |
| | | abs(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return FixedPoint16<IntBits, OverflowHandling>(abs(v.value), FPNoShift) | |
| | | ; | |
| | | } | |
| | | | |
| | | /// squared norm (same as v*v). | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline | |
| | | typename NormTraits<FixedPoint16<IntBits, OverflowHandling> >::SquaredNormT | |
| | | ype | |
| | | squaredNorm(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return v*v; | |
| | | } | |
| | | | |
| | | /// norm (same as abs). | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline | |
| | | typename NormTraits<FixedPoint16<IntBits, OverflowHandling> >::NormType | |
| | | norm(FixedPoint16<IntBits, OverflowHandling> const & v) | |
| | | { | |
| | | return abs(v); | |
| | | } | |
| | | | |
| | | /// fractional part. (difference between v and its floor) | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline FixedPoint16<IntBits, OverflowHandling> | |
| | | frac(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return FixedPoint16<IntBits, OverflowHandling>( | |
| | | v.value - (v.value & FixedPoint16<IntBits, OverflowHandling>::IN | |
| | | T_MASK), | |
| | | FPNoShift); | |
| | | } | |
| | | | |
| | | /// dual fractional part. (1 - frac(v)) | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline FixedPoint16<IntBits, OverflowHandling> | |
| | | dual_frac(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return FixedPoint16<IntBits, OverflowHandling>( | |
| | | FixedPoint16<IntBits, OverflowHandling>::ONE - v.value + (v.valu | |
| | | e & FixedPoint16<IntBits, OverflowHandling>::INT_MASK), | |
| | | FPNoShift); | |
| | | } | |
| | | | |
| | | /// rounding down. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline Int32 | |
| | | floor(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return(v.value >> FixedPoint16<IntBits, OverflowHandling>::FRACTIONAL_B | |
| | | ITS); | |
| | | } | |
| | | | |
| | | /// rounding up. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline Int32 | |
| | | ceil(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return((v.value + FixedPoint16<IntBits, OverflowHandling>::FRACTIONAL_M | |
| | | ASK) >> | |
| | | FixedPoint16<IntBits, OverflowHandling>::FRACTIONAL_B | |
| | | ITS); | |
| | | } | |
| | | | |
| | | /// rounding to the nearest integer. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline Int32 | |
| | | round(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return((v.value + FixedPoint16<IntBits, OverflowHandling>::ONE_HALF) >> | |
| | | FixedPoint16<IntBits, OverflowHandling>::FRACTIONAL_B | |
| | | ITS); | |
| | | } | |
| | | | |
| | | /// rounding to the nearest integer. | |
| | | template <int IntBits, FPOverflowHandling OverflowHandling> | |
| | | inline Int32 | |
| | | roundi(FixedPoint16<IntBits, OverflowHandling> v) | |
| | | { | |
| | | return round(v); | |
| | | } | |
| | | | |
| | | //@} | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
|
| | | namespace std { | |
| | | | |
| | | template <int IntBits, vigra::FPOverflowHandling OverflowHandling> | |
| | | ostream & operator<<(ostream & s, vigra::FixedPoint16<IntBits, OverflowHand | |
| | | ling> v) | |
| | | { | |
| | | s << vigra::fixed_point_cast<float>(v); | |
| | | return s; | |
| | | } | |
| | | | |
| | | } // namespace std | |
| | | | |
| #endif // VIGRA_FIXEDPOINT_HXX | | #endif // VIGRA_FIXEDPOINT_HXX | |
| | | | |
End of changes. 5 change blocks. |
| 3 lines changed or deleted | | 1120 lines changed or added | |
|
| functorexpression.hxx | | functorexpression.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 49 | | skipping to change at line 47 | |
| #define VIGRA_FUNCTOREXPRESSION_HXX | | #define VIGRA_FUNCTOREXPRESSION_HXX | |
| | | | |
| /** \page FunctorExpressions Functor Expressions | | /** \page FunctorExpressions Functor Expressions | |
| | | | |
| Simple automatic functor creation by means of expression templates | | Simple automatic functor creation by means of expression templates | |
| (also known as a "lambda library"). | | (also known as a "lambda library"). | |
| | | | |
| <b>\#include</b> \<<a href="functorexpression_8hxx-source.html">vigra/f
unctorexpression.hxx</a>\><br> | | <b>\#include</b> \<<a href="functorexpression_8hxx-source.html">vigra/f
unctorexpression.hxx</a>\><br> | |
| Namespace: vigra::functor | | Namespace: vigra::functor | |
| | | | |
|
| <b> Note:</b> This functionality is not available under Microsoft Visua | | | |
| l C++, | | | |
| because support for partial template specialization is required. | | | |
| | | | |
| <b> Motivation</b> | | <b> Motivation</b> | |
| | | | |
| Many generic algorithms are made more flexible by means of functors | | Many generic algorithms are made more flexible by means of functors | |
| which define part of the algorithms' behavior according to the | | which define part of the algorithms' behavior according to the | |
| needs of a specific situation. For example, we can apply an exponential | | needs of a specific situation. For example, we can apply an exponential | |
| to each pixel by passing a pointer to the <TT>exp</TT> function | | to each pixel by passing a pointer to the <TT>exp</TT> function | |
| to <TT>transformImage()</TT>: | | to <TT>transformImage()</TT>: | |
| | | | |
| \code | | \code | |
| vigra::FImage src(w,h), dest(w,h); | | vigra::FImage src(w,h), dest(w,h); | |
| | | | |
| skipping to change at line 143 | | skipping to change at line 138 | |
| | | | |
| <b> Automatic Functor Creation</b> | | <b> Automatic Functor Creation</b> | |
| | | | |
| Automatic functor creation in VIGRA is based on a technique called | | Automatic functor creation in VIGRA is based on a technique called | |
| <a href="http://extreme.indiana.edu/~tveldhui/papers/Expression-Templat
es/exprtmpl.html">Expression Templates</a>. | | <a href="http://extreme.indiana.edu/~tveldhui/papers/Expression-Templat
es/exprtmpl.html">Expression Templates</a>. | |
| This means that C++ operators are | | This means that C++ operators are | |
| overloaded so that they don't execute the specified operation directly, | | overloaded so that they don't execute the specified operation directly, | |
| but instead produce a functor which will later calculate the result. | | but instead produce a functor which will later calculate the result. | |
| This technique has the big advantage that the familiar operator notatio
n | | This technique has the big advantage that the familiar operator notatio
n | |
| can be used, while all the flexibility of generic programming is preser
ved. | | can be used, while all the flexibility of generic programming is preser
ved. | |
|
| Unfortunately, it requires partial template specialization, so these ca | | | |
| pabilities | | | |
| are not available on compilers that dont support this C++ feature | | | |
| (in particular, on Microsoft Visual C++). | | | |
| | | | |
| The above problem "apply <TT>exp(-beta*v)</TT> to every pixel" will be
solved | | The above problem "apply <TT>exp(-beta*v)</TT> to every pixel" will be
solved | |
| like this: | | like this: | |
| | | | |
| \code | | \code | |
| using namespace vigra::functor; | | using namespace vigra::functor; | |
| | | | |
| float beta = ...; | | float beta = ...; | |
| | | | |
| transformImage(srcImageRange(src), destImage(dest), | | transformImage(srcImageRange(src), destImage(dest), | |
| | | | |
| skipping to change at line 180 | | skipping to change at line 172 | |
| for algorithms that have multiple input images, such as | | for algorithms that have multiple input images, such as | |
| \ref combineTwoImages() and \ref combineThreeImages(). | | \ref combineTwoImages() and \ref combineThreeImages(). | |
| | | | |
| <DT><b>* (multiplication):</b><DD> creates a functor that returns the p
roduct of | | <DT><b>* (multiplication):</b><DD> creates a functor that returns the p
roduct of | |
| its arguments. Likewise, the other C++ operators (i.e. | | its arguments. Likewise, the other C++ operators (i.e. | |
| <TT>+, -, *, /, %, ==, !=, <, <=, >, >=, &&, ||, &, |, ^, !, ~</TT
>) | | <TT>+, -, *, /, %, ==, !=, <, <=, >, >=, &&, ||, &, |, ^, !, ~</TT
>) | |
| are overloaded. | | are overloaded. | |
| | | | |
| <DT><b><TT>exp():</TT></b><DD> creates a functor that takes the exponen
tial of its | | <DT><b><TT>exp():</TT></b><DD> creates a functor that takes the exponen
tial of its | |
| argument. Likewise, the other algebraic functions | | argument. Likewise, the other algebraic functions | |
|
| (i.e. <TT>sqrt, exp, log, log10, sin, asin, cos, acos, tan, | | (i.e. <TT>sq, sqrt, exp, log, log10, sin, asin, cos, acos, tan, | |
| atan, abs, floor, ceil, pow, atan2, fmod, min, max</TT>) | | atan, abs, floor, ceil, pow, atan2, fmod, min, max</TT>) | |
| are overloaded. | | are overloaded. | |
| | | | |
| </DL> | | </DL> | |
| | | | |
| We will explain additional capabilities of the functor creation mechani
sm | | We will explain additional capabilities of the functor creation mechani
sm | |
| by means of examples. | | by means of examples. | |
| | | | |
| The same argument can be used several times in the expression. | | The same argument can be used several times in the expression. | |
| For example, to calculate the gradient magnitude from the components | | For example, to calculate the gradient magnitude from the components | |
| | | | |
| skipping to change at line 1030 | | skipping to change at line 1022 | |
| template <class EXPR1, class EXPR2, class EXPR3> | | template <class EXPR1, class EXPR2, class EXPR3> | |
| struct IfThenElseFunctor | | struct IfThenElseFunctor | |
| { | | { | |
| IfThenElseFunctor(EXPR1 const & e1, EXPR2 const & e2, EXPR3 const & e3) | | IfThenElseFunctor(EXPR1 const & e1, EXPR2 const & e2, EXPR3 const & e3) | |
| : expr1_(e1), expr2_(e2), expr3_(e3) | | : expr1_(e1), expr2_(e2), expr3_(e3) | |
| {} | | {} | |
| | | | |
| typename ResultTraits0<IfThenElseFunctor>::Res | | typename ResultTraits0<IfThenElseFunctor>::Res | |
| operator()() const | | operator()() const | |
| { | | { | |
|
| typename | | if(expr1_()) | |
| ResultTraits0<IfThenElseFunctor>::Res | | { | |
| r2(expr2_()); | | return typename ResultTraits0<IfThenElseFunctor>::Res(expr2_()) | |
| typename | | ; | |
| ResultTraits0<IfThenElseFunctor>::Res | | } | |
| r3(expr3_()); | | else | |
| return expr1_() ? r2 : r3; | | { | |
| | | return typename ResultTraits0<IfThenElseFunctor>::Res(expr3_()) | |
| | | ; | |
| | | } | |
| } | | } | |
| | | | |
| template <class T> | | template <class T> | |
| typename ResultTraits1<IfThenElseFunctor, T>::Res | | typename ResultTraits1<IfThenElseFunctor, T>::Res | |
| operator()(T const & v1) const | | operator()(T const & v1) const | |
| { | | { | |
|
| typename | | if(expr1_(v1)) | |
| ResultTraits1<IfThenElseFunctor, T>::Res | | { | |
| r2(expr2_(v1)); | | return typename ResultTraits1<IfThenElseFunctor, T>::Res(expr2_ | |
| typename | | (v1)); | |
| ResultTraits1<IfThenElseFunctor, T>::Res | | } | |
| r3(expr3_(v1)); | | else | |
| return expr1_(v1) ? r2 : r3; | | { | |
| | | return typename ResultTraits1<IfThenElseFunctor, T>::Res(expr3_ | |
| | | (v1)); | |
| | | } | |
| } | | } | |
| | | | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| typename ResultTraits2<IfThenElseFunctor, T1, T2>::Res | | typename ResultTraits2<IfThenElseFunctor, T1, T2>::Res | |
| operator()(T1 const & v1, T2 const & v2) const | | operator()(T1 const & v1, T2 const & v2) const | |
| { | | { | |
|
| typename | | if(expr1_(v1, v2)) | |
| ResultTraits2<IfThenElseFunctor, T1, T2>::Res | | { | |
| r2(expr2_(v1, v2)); | | return typename ResultTraits2<IfThenElseFunctor, T1, T2>::Res(e | |
| typename | | xpr2_(v1, v2)); | |
| ResultTraits2<IfThenElseFunctor, T1, T2>::Res | | } | |
| r3(expr3_(v1, v2)); | | else | |
| return expr1_(v1, v2) ? r2 : r3; | | { | |
| | | return typename ResultTraits2<IfThenElseFunctor, T1, T2>::Res(e | |
| | | xpr3_(v1, v2)); | |
| | | } | |
| } | | } | |
| | | | |
| template <class T1, class T2, class T3> | | template <class T1, class T2, class T3> | |
| typename ResultTraits3<IfThenElseFunctor, T1, T2, T3>::Res | | typename ResultTraits3<IfThenElseFunctor, T1, T2, T3>::Res | |
| operator()(T1 const & v1, T2 const & v2, T3 const & v3) const | | operator()(T1 const & v1, T2 const & v2, T3 const & v3) const | |
| { | | { | |
|
| typename | | if(expr1_(v1, v2, v3)) | |
| ResultTraits3<IfThenElseFunctor, T1, T2, T3>::Res | | { | |
| r2(expr2_(v1, v2, v3)); | | return typename ResultTraits3<IfThenElseFunctor, T1, T2, T3>::R | |
| typename | | es(expr2_(v1, v2, v3)); | |
| ResultTraits3<IfThenElseFunctor, T1, T2, T3>::Res | | } | |
| r3(expr3_(v1, v2, v3)); | | else | |
| return expr1_(v1, v2, v3) ? r2 : r3; | | { | |
| | | return typename ResultTraits3<IfThenElseFunctor, T1, T2, T3>::R | |
| | | es(expr3_(v1, v2, v3)); | |
| | | } | |
| } | | } | |
| | | | |
| private: | | private: | |
| | | | |
| EXPR1 expr1_; | | EXPR1 expr1_; | |
| EXPR2 expr2_; | | EXPR2 expr2_; | |
| EXPR3 expr3_; | | EXPR3 expr3_; | |
| | | | |
| IfThenElseFunctor & operator=(IfThenElseFunctor const &); // not implem
ented | | IfThenElseFunctor & operator=(IfThenElseFunctor const &); // not implem
ented | |
| }; | | }; | |
| | | | |
| skipping to change at line 1109 | | skipping to change at line 1105 | |
| UnaryFunctor<EXPR2>, | | UnaryFunctor<EXPR2>, | |
| UnaryFunctor<EXPR3> > >(p); | | UnaryFunctor<EXPR3> > >(p); | |
| } | | } | |
| | | | |
| /************************************************************/ | | /************************************************************/ | |
| /* */ | | /* */ | |
| /* functors for unary functions */ | | /* functors for unary functions */ | |
| /* */ | | /* */ | |
| /************************************************************/ | | /************************************************************/ | |
| | | | |
|
| #define MAKE_FUNCTOR_UNARY_FUNCTION(function, namespc) \ | | #define MAKE_FUNCTOR_UNARY_FUNCTION(function, namespc, traitsClass, traitsV
alue) \ | |
| using ::namespc::function; \ | | using ::namespc::function; \ | |
| template <class EXPR> \ | | template <class EXPR> \ | |
| struct Functor_##function; \ | | struct Functor_##function; \ | |
| \ | | \ | |
| template <class EXPR> \ | | template <class EXPR> \ | |
| struct ResultTraits0<Functor_##function<EXPR> > \ | | struct ResultTraits0<Functor_##function<EXPR> > \ | |
| { \ | | { \ | |
| typedef typename ResultTraits0<EXPR>::Res R1; \ | | typedef typename ResultTraits0<EXPR>::Res R1; \ | |
|
| typedef typename NumericTraits<R1>::RealPromote Res; \ | | typedef typename traitsClass<R1>::traitsValue Res; \ | |
| }; \ | | }; \ | |
| \ | | \ | |
| template <class EXPR, class T1> \ | | template <class EXPR, class T1> \ | |
| struct ResultTraits1<Functor_##function<EXPR>, T1> \ | | struct ResultTraits1<Functor_##function<EXPR>, T1> \ | |
| { \ | | { \ | |
| typedef typename ResultTraits1<EXPR, T1>::Res R1; \ | | typedef typename ResultTraits1<EXPR, T1>::Res R1; \ | |
|
| typedef typename NumericTraits<R1>::RealPromote Res; \ | | typedef typename traitsClass<R1>::traitsValue Res; \ | |
| }; \ | | }; \ | |
| \ | | \ | |
| template <class EXPR, class T1, class T2> \ | | template <class EXPR, class T1, class T2> \ | |
| struct ResultTraits2<Functor_##function<EXPR>, T1, T2> \ | | struct ResultTraits2<Functor_##function<EXPR>, T1, T2> \ | |
| { \ | | { \ | |
| typedef typename ResultTraits2<EXPR, T1, T2>::Res R1; \ | | typedef typename ResultTraits2<EXPR, T1, T2>::Res R1; \ | |
|
| typedef typename NumericTraits<R1>::RealPromote Res; \ | | typedef typename traitsClass<R1>::traitsValue Res; \ | |
| }; \ | | }; \ | |
| \ | | \ | |
| template <class EXPR, class T1, class T2, class T3> \ | | template <class EXPR, class T1, class T2, class T3> \ | |
| struct ResultTraits3<Functor_##function<EXPR>, T1, T2, T3> \ | | struct ResultTraits3<Functor_##function<EXPR>, T1, T2, T3> \ | |
| { \ | | { \ | |
| typedef typename ResultTraits3<EXPR, T1, T2, T3>::Res R1; \ | | typedef typename ResultTraits3<EXPR, T1, T2, T3>::Res R1; \ | |
|
| typedef typename NumericTraits<R1>::RealPromote Res; \ | | typedef typename traitsClass<R1>::traitsValue Res; \ | |
| }; \ | | }; \ | |
| \ | | \ | |
| template <class EXPR> \ | | template <class EXPR> \ | |
| struct Functor_##function \ | | struct Functor_##function \ | |
| { \ | | { \ | |
| Functor_##function(EXPR const & e) \ | | Functor_##function(EXPR const & e) \ | |
| : expr_(e) \ | | : expr_(e) \ | |
| {} \ | | {} \ | |
| \ | | \ | |
| typename ResultTraits0<Functor_##function>::Res \ | | typename ResultTraits0<Functor_##function>::Res \ | |
| | | | |
| skipping to change at line 1194 | | skipping to change at line 1190 | |
| template <class EXPR> \ | | template <class EXPR> \ | |
| inline UnaryFunctor<Functor_##function<UnaryFunctor<EXPR> > > \ | | inline UnaryFunctor<Functor_##function<UnaryFunctor<EXPR> > > \ | |
| function(UnaryFunctor<EXPR> const & e) \ | | function(UnaryFunctor<EXPR> const & e) \ | |
| { \ | | { \ | |
| Functor_##function<UnaryFunctor<EXPR> > p(e); \ | | Functor_##function<UnaryFunctor<EXPR> > p(e); \ | |
| return UnaryFunctor<Functor_##function<UnaryFunctor<EXPR> > >(p); \ | | return UnaryFunctor<Functor_##function<UnaryFunctor<EXPR> > >(p); \ | |
| } | | } | |
| | | | |
| /************************************************************/ | | /************************************************************/ | |
| | | | |
|
| MAKE_FUNCTOR_UNARY_FUNCTION(sqrt, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(sq, vigra, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(exp, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(sqrt, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(log, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(exp, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(log10, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(log, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(sin, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(log10, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(asin, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(sin, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(cos, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(asin, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(acos, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(cos, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(tan, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(acos, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(atan, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(tan, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(floor, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(atan, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(ceil, std) | | MAKE_FUNCTOR_UNARY_FUNCTION(floor, std, NumericTraits, RealPromote) | |
| MAKE_FUNCTOR_UNARY_FUNCTION(abs, vigra) | | MAKE_FUNCTOR_UNARY_FUNCTION(ceil, std, NumericTraits, RealPromote) | |
| //MAKE_FUNCTOR_UNARY_FUNCTION(norm, vigra) | | MAKE_FUNCTOR_UNARY_FUNCTION(abs, vigra, NumericTraits, RealPromote) | |
| //MAKE_FUNCTOR_UNARY_FUNCTION(squaredNorm, vigra) | | MAKE_FUNCTOR_UNARY_FUNCTION(norm, vigra, NormTraits, NormType) | |
| | | MAKE_FUNCTOR_UNARY_FUNCTION(squaredNorm, vigra, NormTraits, SquaredNormType | |
| | | ) | |
| | | | |
| #undef MAKE_FUNCTOR_UNARY_FUNCTION | | #undef MAKE_FUNCTOR_UNARY_FUNCTION | |
| | | | |
| /************************************************************/ | | /************************************************************/ | |
| /* */ | | /* */ | |
| /* functors for unary operators */ | | /* functors for unary operators */ | |
| /* */ | | /* */ | |
| /************************************************************/ | | /************************************************************/ | |
| | | | |
| #define MAKE_FUNCTOR_UNARY_OPERATOR(name, op) \ | | #define MAKE_FUNCTOR_UNARY_OPERATOR(name, op) \ | |
| | | | |
End of changes. 16 change blocks. |
| 60 lines changed or deleted | | 64 lines changed or added | |
|
| impex.hxx | | impex.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2001-2002 by Gunnar Kedenburg */ | | /* Copyright 2001-2002 by Gunnar Kedenburg */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 61 | | skipping to change at line 59 | |
| \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() | |
| and exportImage(). the matching implementation for the given datatype is | | and exportImage(). the matching implementation for the given datatype is | |
| selected by template metacode. | | selected by template metacode. | |
| */ | | */ | |
| | | | |
| #ifndef VIGRA_IMPEX_HXX | | #ifndef VIGRA_IMPEX_HXX | |
| #define VIGRA_IMPEX_HXX | | #define VIGRA_IMPEX_HXX | |
| | | | |
|
| #if defined(_MSC_VER) | | | |
| #pragma warning (disable: 4267) | | | |
| #endif | | | |
| | | | |
| #include "sized_int.hxx" | | #include "sized_int.hxx" | |
| #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" | |
| | | | |
| skipping to change at line 117 | | skipping to change at line 111 | |
| { | | { | |
| 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 == 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 des
tination 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(); | |
| | | | |
| skipping to change at line 303 | | skipping to change at line 297 | |
| <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 476 | | skipping to change at line 474 | |
| enc->setNumBands(num_bands); | | enc->setNumBands(num_bands); | |
| 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(); | |
| | | | |
|
| if (num_bands == 4) { | | // Speedup for the common cases | |
| // Speedup for this particular case | | switch (num_bands) | |
| | | { | |
| | | case 2: | |
| | | { | |
| | | unsigned int offset = enc->getOffset(); | |
| | | DstValueType * scanline0; | |
| | | DstValueType * scanline1; | |
| | | for( size_type y = 0; y < height; ++y, ++ys.y ) { | |
| | | xs = ys.rowIterator(); | |
| | | scanline0 = static_cast< DstValueType * > | |
| | | (enc->currentScanlineOfBand(0)); | |
| | | scanline1 = static_cast< DstValueType * > | |
| | | (enc->currentScanlineOfBand(1)); | |
| | | for( size_type x = 0; x < width; ++x, ++xs) { | |
| | | *scanline0 = detail::RequiresExplicitCast<DstValueType> | |
| | | ::cast(a.getComponent( xs, 0)); | |
| | | *scanline1 = detail::RequiresExplicitCast<DstValueType> | |
| | | ::cast(a.getComponent( xs, 1)); | |
| | | scanline0 += offset; | |
| | | scanline1 += offset; | |
| | | } | |
| | | enc->nextScanline(); | |
| | | | |
| | | } | |
| | | break; | |
| | | } | |
| | | case 3: | |
| | | { | |
| | | unsigned int offset = enc->getOffset(); | |
| | | DstValueType * scanline0; | |
| | | DstValueType * scanline1; | |
| | | DstValueType * scanline2; | |
| | | for( size_type y = 0; y < height; ++y, ++ys.y ) { | |
| | | xs = ys.rowIterator(); | |
| | | scanline0 = static_cast< DstValueType * > | |
| | | (enc->currentScanlineOfBand(0)); | |
| | | scanline1 = static_cast< DstValueType * > | |
| | | (enc->currentScanlineOfBand(1)); | |
| | | scanline2 = static_cast< DstValueType * > | |
| | | (enc->currentScanlineOfBand(2)); | |
| | | for( size_type x = 0; x < width; ++x, ++xs) { | |
| | | *scanline0 = detail::RequiresExplicitCast<DstValueType> | |
| | | ::cast(a.getComponent( xs, 0)); | |
| | | *scanline1 = detail::RequiresExplicitCast<DstValueType> | |
| | | ::cast(a.getComponent( xs, 1)); | |
| | | *scanline2 = detail::RequiresExplicitCast<DstValueType> | |
| | | ::cast(a.getComponent( xs, 2)); | |
| | | scanline0 += offset; | |
| | | scanline1 += offset; | |
| | | scanline2 += offset; | |
| | | } | |
| | | enc->nextScanline(); | |
| | | } | |
| | | break; | |
| | | } | |
| | | case 4: | |
| | | { | |
| unsigned int offset = enc->getOffset(); | | unsigned int offset = enc->getOffset(); | |
| DstValueType * scanline0; | | DstValueType * scanline0; | |
| DstValueType * scanline1; | | DstValueType * scanline1; | |
| DstValueType * scanline2; | | DstValueType * scanline2; | |
| DstValueType * scanline3; | | DstValueType * scanline3; | |
| 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)); | |
| scanline2 = static_cast< DstValueType * > | | scanline2 = static_cast< DstValueType * > | |
| (enc->currentScanlineOfBand(2)); | | (enc->currentScanlineOfBand(2)); | |
| scanline3 = static_cast< DstValueType * > | | scanline3 = static_cast< DstValueType * > | |
| (enc->currentScanlineOfBand(3)); | | (enc->currentScanlineOfBand(3)); | |
| for( size_type x = 0; x < width; ++x, ++xs) { | | for( size_type x = 0; x < width; ++x, ++xs) { | |
|
| /* | | | |
| *scanline0 = a.template getComponent<SrcRowIterator, 0> | | | |
| ( xs ); | | | |
| *scanline1 = a.template getComponent<SrcRowIterator, 1> | | | |
| ( xs ); | | | |
| *scanline2 = a.template getComponent<SrcRowIterator, 2> | | | |
| ( xs ); | | | |
| *scanline3 = a.template getComponent<SrcRowIterator, 3> | | | |
| ( xs ); | | | |
| */ | | | |
| *scanline0 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 0)); | | *scanline0 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 0)); | |
| *scanline1 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 1)); | | *scanline1 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 1)); | |
| *scanline2 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 2)); | | *scanline2 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 2)); | |
| *scanline3 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 3)); | | *scanline3 = detail::RequiresExplicitCast<DstValueType>
::cast(a.getComponent( xs, 3)); | |
| scanline0 += offset; | | scanline0 += offset; | |
| scanline1 += offset; | | scanline1 += offset; | |
| scanline2 += offset; | | scanline2 += offset; | |
| scanline3 += offset; | | scanline3 += offset; | |
| } | | } | |
| enc->nextScanline(); | | enc->nextScanline(); | |
| } | | } | |
|
| } | | break; | |
| else { | | } | |
| | | 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<DstValueType>: | | *scanline = detail::RequiresExplicitCast<DstValueTy | |
| :cast(a.getComponent( xs, b )); | | 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); | |
| | | | |
| skipping to change at line 587 | | skipping to change at line 633 | |
| \param a image accessor for the source image | | \param a image accessor for the source image | |
| */ | | */ | |
| template< class ImageIterator, class Accessor, class DstValueType > | | template< class ImageIterator, class Accessor, class DstValueType > | |
| void write_band( Encoder * enc, ImageIterator ul, ImageIterator lr, Acc
essor a, DstValueType) | | void write_band( Encoder * enc, ImageIterator ul, ImageIterator lr, Acc
essor a, DstValueType) | |
| { | | { | |
| typedef unsigned int size_type; | | typedef unsigned int size_type; | |
| typedef typename ImageIterator::row_iterator SrcRowIterator; | | typedef typename ImageIterator::row_iterator SrcRowIterator; | |
| typedef typename Accessor::value_type SrcValueType; | | typedef typename Accessor::value_type SrcValueType; | |
| | | | |
| // complete decoder settings | | // complete decoder settings | |
|
| const size_type width = lr.x - ul.x; | | const size_type width = size_type(lr.x - ul.x); | |
| const size_type height = lr.y - ul.y; | | const size_type height = size_type(lr.y - ul.y); | |
| enc->setWidth(width); | | enc->setWidth(width); | |
| enc->setHeight(height); | | enc->setHeight(height); | |
| enc->setNumBands(1); | | enc->setNumBands(1); | |
| 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. | |
| | | | |
| skipping to change at line 628 | | skipping to change at line 674 | |
| } | | } | |
| | | | |
| // export scalar images with conversion | | // export scalar images with conversion | |
| template < class SrcIterator, class SrcAccessor, class T > | | template < class SrcIterator, class SrcAccessor, class T > | |
| void exportScalarImage(SrcIterator sul, SrcIterator slr, SrcAccessor sg
et, | | void exportScalarImage(SrcIterator sul, SrcIterator slr, SrcAccessor sg
et, | |
| Encoder * enc, | | Encoder * enc, | |
| const ImageExportInfo & info, | | const ImageExportInfo & info, | |
| T zero) | | T zero) | |
| { | | { | |
| double fromMin, fromMax, toMin, toMax; | | double fromMin, fromMax, toMin, toMax; | |
|
| if(info.hasForcedRangeMapping()) | | if(info.getFromMin() < info.getFromMax()) | |
| { | | { | |
| fromMin = info.getFromMin(); | | fromMin = info.getFromMin(); | |
| fromMax = info.getFromMax(); | | fromMax = info.getFromMax(); | |
|
| toMin = info.getToMin(); | | | |
| toMax = info.getToMax(); | | | |
| } | | } | |
| else | | else | |
| { | | { | |
| typedef typename SrcAccessor::value_type SrcValue; | | typedef typename SrcAccessor::value_type SrcValue; | |
| FindMinMax<SrcValue> minmax; | | FindMinMax<SrcValue> minmax; | |
| inspectImage( sul, slr, sget, minmax ); | | inspectImage( sul, slr, sget, minmax ); | |
| | | | |
| fromMin = (double)minmax.min; | | fromMin = (double)minmax.min; | |
| fromMax = (double)minmax.max; | | fromMax = (double)minmax.max; | |
|
| | | if(fromMax <= fromMin) | |
| | | fromMax = fromMin + 1.0; | |
| | | } | |
| | | | |
| | | if(info.getToMin() < info.getToMax()) | |
| | | { | |
| | | toMin = info.getToMin(); | |
| | | toMax = info.getToMax(); | |
| | | } | |
| | | else | |
| | | { | |
| toMin = (double)NumericTraits<T>::min(); | | toMin = (double)NumericTraits<T>::min(); | |
| toMax = (double)NumericTraits<T>::max(); | | toMax = (double)NumericTraits<T>::max(); | |
| } | | } | |
|
| | | | |
| double scale = (toMax - toMin) / (fromMax - fromMin); | | double scale = (toMax - toMin) / (fromMax - fromMin); | |
| double offset = (toMin / scale) - fromMin; | | double offset = (toMin / scale) - fromMin; | |
| BasicImage<T> image(slr-sul); | | BasicImage<T> image(slr-sul); | |
| transformImage( sul, slr, sget, image.upperLeft(), image.accessor()
, | | transformImage( sul, slr, sget, image.upperLeft(), image.accessor()
, | |
| linearIntensityTransform(scale, offset)); | | linearIntensityTransform(scale, offset)); | |
| write_band( enc, image.upperLeft(), | | write_band( enc, image.upperLeft(), | |
| image.lowerRight(), image.accessor(), zero ); | | image.lowerRight(), image.accessor(), zero ); | |
| } | | } | |
| | | | |
| // export vector images without conversion | | // export vector images without conversion | |
| | | | |
| skipping to change at line 677 | | skipping to change at line 733 | |
| template < class SrcIterator, class SrcAccessor, class T > | | template < class SrcIterator, class SrcAccessor, class T > | |
| void exportVectorImage(SrcIterator sul, SrcIterator slr, SrcAccessor sg
et, | | void exportVectorImage(SrcIterator sul, SrcIterator slr, SrcAccessor sg
et, | |
| Encoder * enc, | | Encoder * enc, | |
| const ImageExportInfo & info, | | const ImageExportInfo & info, | |
| T zero) | | T zero) | |
| { | | { | |
| unsigned int bands = sget.size(sul); | | unsigned int bands = sget.size(sul); | |
| vigra_precondition(isBandNumberSupported(enc->getFileType(), bands)
, | | vigra_precondition(isBandNumberSupported(enc->getFileType(), bands)
, | |
| "exportImage(): file format does not support requested number of
bands (color channels)"); | | "exportImage(): file format does not support requested number of
bands (color channels)"); | |
| | | | |
|
| typedef typename SrcAccessor::value_type SrcValue; | | typedef typename SrcAccessor::ElementAccessor SrcElementAccessor; | |
| | | typedef typename SrcElementAccessor::value_type SrcComponent; | |
| double fromMin, fromMax, toMin, toMax; | | double fromMin, fromMax, toMin, toMax; | |
|
| if(info.hasForcedRangeMapping()) | | if(info.getFromMin() < info.getFromMax()) | |
| { | | { | |
| fromMin = info.getFromMin(); | | fromMin = info.getFromMin(); | |
| fromMax = info.getFromMax(); | | fromMax = info.getFromMax(); | |
|
| toMin = info.getToMin(); | | | |
| toMax = info.getToMax(); | | | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| typedef typename SrcValue::value_type SrcComponent; | | | |
| | | | |
| FindMinMax<SrcComponent> minmax; | | FindMinMax<SrcComponent> minmax; | |
| for(unsigned int i=0; i<bands; ++i) | | for(unsigned int i=0; i<bands; ++i) | |
| { | | { | |
|
| VectorComponentValueAccessor<SrcValue> band(i); | | SrcElementAccessor band(i, sget); | |
| inspectImage( sul, slr, band, minmax ); | | inspectImage( sul, slr, band, minmax ); | |
| } | | } | |
| | | | |
| fromMin = (double)minmax.min; | | fromMin = (double)minmax.min; | |
| fromMax = (double)minmax.max; | | fromMax = (double)minmax.max; | |
|
| | | if(fromMax <= fromMin) | |
| | | fromMax = fromMin + 1.0; | |
| | | } | |
| | | | |
| | | if(info.getToMin() < info.getToMax()) | |
| | | { | |
| | | toMin = info.getToMin(); | |
| | | toMax = info.getToMax(); | |
| | | } | |
| | | else | |
| | | { | |
| toMin = (double)NumericTraits<T>::min(); | | toMin = (double)NumericTraits<T>::min(); | |
| toMax = (double)NumericTraits<T>::max(); | | toMax = (double)NumericTraits<T>::max(); | |
| } | | } | |
|
| | | | |
| double scale = (toMax - toMin) / (fromMax - fromMin); | | double scale = (toMax - toMin) / (fromMax - fromMin); | |
| double offset = (toMin / scale) - fromMin; | | double offset = (toMin / scale) - fromMin; | |
| int w = slr.x - sul.x; | | int w = slr.x - sul.x; | |
| int h = slr.y - sul.y; | | int h = slr.y - sul.y; | |
| | | | |
| typedef vigra::MultiArray<3, T> MArray; | | typedef vigra::MultiArray<3, T> MArray; | |
| MArray array(typename MArray::difference_type(w, h, bands)); | | MArray array(typename MArray::difference_type(w, h, bands)); | |
| | | | |
| for(unsigned int i=0; i<bands; ++i) | | for(unsigned int i=0; i<bands; ++i) | |
| { | | { | |
| | | | |
| skipping to change at line 713 | | skipping to change at line 778 | |
| double offset = (toMin / scale) - fromMin; | | double offset = (toMin / scale) - fromMin; | |
| int w = slr.x - sul.x; | | int w = slr.x - sul.x; | |
| int h = slr.y - sul.y; | | int h = slr.y - sul.y; | |
| | | | |
| typedef vigra::MultiArray<3, T> MArray; | | typedef vigra::MultiArray<3, T> MArray; | |
| MArray array(typename MArray::difference_type(w, h, bands)); | | MArray array(typename MArray::difference_type(w, h, bands)); | |
| | | | |
| for(unsigned int i=0; i<bands; ++i) | | for(unsigned int i=0; i<bands; ++i) | |
| { | | { | |
| BasicImageView<T> subImage = makeBasicImageView(array.bindOuter
(i)); | | BasicImageView<T> subImage = makeBasicImageView(array.bindOuter
(i)); | |
|
| VectorComponentValueAccessor<SrcValue> band(i); | | SrcElementAccessor band(i, sget); | |
| transformImage( sul, slr, band, subImage.upperLeft(), subImage.
accessor(), | | transformImage( sul, slr, band, subImage.upperLeft(), subImage.
accessor(), | |
| linearIntensityTransform( scale, offset ) ); | | linearIntensityTransform( scale, offset ) ); | |
| } | | } | |
| write_bands( enc, array, zero ); | | write_bands( enc, array, zero ); | |
| } | | } | |
| | | | |
| } // namespace detail | | } // namespace detail | |
| | | | |
| /*! | | /*! | |
| \brief Deprecated. | | \brief Deprecated. | |
| | | | |
| skipping to change at line 983 | | skipping to change at line 1048 | |
| } | | } | |
| 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. 28 change blocks. |
| 46 lines changed or deleted | | 116 lines changed or added | |
|
| labelvolume.hxx | | labelvolume.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2006-2007 by F. Heinrich, B. Seppke, Ullrich Koethe */ | | /* Copyright 2006-2007 by F. Heinrich, B. Seppke, Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 43 | | 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_LABELVOLUME_HXX | | #ifndef VIGRA_LABELVOLUME_HXX | |
| #define VIGRA_LABELVOLUME_HXX | | #define VIGRA_LABELVOLUME_HXX | |
| | | | |
| #include "voxelneighborhood.hxx" | | #include "voxelneighborhood.hxx" | |
| #include "multi_array.hxx" | | #include "multi_array.hxx" | |
|
| | | #include "union_find.hxx" | |
| | | | |
| namespace vigra{ | | namespace vigra{ | |
| | | | |
| /** \addtogroup Labeling Connected Components Labeling | | /** \addtogroup Labeling Connected Components Labeling | |
| The 3-dimensional connected components algorithms may use either 6 or
26 connectivity. | | The 3-dimensional connected components algorithms may use either 6 or
26 connectivity. | |
| By means of a functor the merge criterium can be defined arbitrarily. | | By means of a functor the merge criterium can be defined arbitrarily. | |
| */ | | */ | |
| //@{ | | //@{ | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| skipping to change at line 205 | | skipping to change at line 204 | |
| return labelVolume(src.first, src.second, src.third, dest.first, dest.s
econd, neighborhood3D, equal); | | return labelVolume(src.first, src.second, src.third, dest.first, dest.s
econd, neighborhood3D, equal); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor,class SrcShape, | | template <class SrcIterator, class SrcAccessor,class SrcShape, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class Neighborhood3D, class EqualityFunctor> | | class Neighborhood3D, class EqualityFunctor> | |
| unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor
sa, | | unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor
sa, | |
| DestIterator d_Iter, DestAccessor da, | | DestIterator d_Iter, DestAccessor da, | |
| Neighborhood3D, EqualityFunctor equal) | | Neighborhood3D, EqualityFunctor equal) | |
| { | | { | |
|
| | | typedef typename DestAccessor::value_type LabelType; | |
| | | | |
| //basically needed for iteration and border-checks | | //basically needed for iteration and border-checks | |
| int w = srcShape[0], h = srcShape[1], d = srcShape[2]; | | int w = srcShape[0], h = srcShape[1], d = srcShape[2]; | |
|
| int x,y,z, i; | | int x,y,z; | |
| | | | |
| //declare and define Iterators for all three dims at src | | | |
| SrcIterator zs = s_Iter; | | | |
| SrcIterator ys(zs); | | | |
| SrcIterator xs(ys); | | | |
| | | | |
| // temporary image to store region labels | | // temporary image to store region labels | |
|
| typedef vigra::MultiArray<3,int> LabelVolume; | | detail::UnionFindArray<LabelType> label; | |
| typedef LabelVolume::traverser LabelTraverser; | | | |
| | | | |
| LabelVolume labelvolume(srcShape); | | | |
| | | | |
| //Declare traversers for all three dims at target | | //Declare traversers for all three dims at target | |
|
| LabelTraverser zt = labelvolume.traverser_begin(); | | SrcIterator zs = s_Iter; | |
| LabelTraverser yt(zt); | | DestIterator zd = d_Iter; | |
| LabelTraverser xt(yt); | | | |
| | | | |
| // Kovalevsky's clever idea to use | | | |
| // image iterator and scan order iterator simultaneously | | | |
| // memory order indicates label | | | |
| LabelVolume::iterator label = labelvolume.begin(); | | | |
| | | | |
| // initialize the neighborhood traversers | | // initialize the neighborhood traversers | |
|
| | | | |
| #if 0 | | | |
| NeighborOffsetTraverser<Neighborhood3D> nc(Neighborhood3D::CausalFirst) | | | |
| ; | | | |
| NeighborOffsetTraverser<Neighborhood3D> nce(Neighborhood3D::CausalLast) | | | |
| ; | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst | | | |
| ); | | | |
| NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast
); | | NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast
); | |
| ++nce; | | ++nce; | |
| // pass 1: scan image from upper left front to lower right back | | // pass 1: scan image from upper left front to lower right back | |
| // to find connected components | | // to find connected components | |
| | | | |
| // Each component will be represented by a tree of pixels. Each | | // Each component will be represented by a tree of pixels. Each | |
| // pixel contains the scan order address of its parent in the | | // pixel contains the scan order address of its parent in the | |
| // tree. In order for pass 2 to work correctly, the parent must | | // tree. In order for pass 2 to work correctly, the parent must | |
| // always have a smaller scan order address than the child. | | // always have a smaller scan order address than the child. | |
| // Therefore, we can merge trees only at their roots, because the | | // Therefore, we can merge trees only at their roots, because the | |
| // root of the combined tree must have the smallest scan order | | // root of the combined tree must have the smallest scan order | |
| // address among all the tree's pixels/ nodes. The root of each | | // address among all the tree's pixels/ nodes. The root of each | |
| // tree is distinguished by pointing to itself (it contains its | | // tree is distinguished by pointing to itself (it contains its | |
| // own scan order address). This condition is enforced whenever a | | // own scan order address). This condition is enforced whenever a | |
| // new region is found or two regions are merged | | // new region is found or two regions are merged | |
|
| i=0; | | for(z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2()) | |
| for(z = 0; z != d; ++z, ++zs.dim2(), ++zt.dim2()) | | | |
| { | | { | |
|
| ys = zs; | | SrcIterator ys(zs); | |
| yt = zt; | | DestIterator yd(zd); | |
| | | | |
|
| for(y = 0; y != h; ++y, ++ys.dim1(), ++yt.dim1()) | | for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1()) | |
| { | | { | |
|
| xs = ys; | | SrcIterator xs(ys); | |
| xt = yt; | | DestIterator xd(yd); | |
| | | | |
|
| for(x = 0; x != w; ++x, ++xs.dim0(), ++xt.dim0(), ++i) | | for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0()) | |
| { | | { | |
|
| *xt = i; // default: new region | | LabelType currentLabel = label.nextFreeLabel(); | |
| | | | |
|
| //queck whether there is a special borde threatment to be u
sed or not | | //queck whether there is a special border treatment to be u
sed or not | |
| AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); | | AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); | |
| | | | |
| //We are not at the border! | | //We are not at the border! | |
| if(atBorder == NotAtBorder) | | if(atBorder == NotAtBorder) | |
| { | | { | |
|
| | | NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo | |
| #if 0 | | d3D::CausalFirst); | |
| nc = NeighborOffsetTraverser<Neighborhood3D>(Neighborho | | | |
| od3D::CausalFirst); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh | | | |
| ood3D::CausalFirst); | | | |
| | | | |
| do | | do | |
| { | | { | |
| // if colors are equal | | // if colors are equal | |
|
| if(equal(*xs, xs[*nc])) | | if(equal(sa(xs), sa(xs, *nc))) | |
| { | | { | |
|
| int neighborLabel = xt[*nc]; | | currentLabel = label.makeUnion(label[da(xd,*nc) | |
| | | ], currentLabel); | |
| // find the root label of a label tree | | | |
| while(neighborLabel != label[neighborLabel]) | | | |
| { | | | |
| neighborLabel = label[neighborLabel]; | | | |
| } | | | |
| | | | |
| if(neighborLabel < *xt) // always keep the smal | | | |
| lest among the possible neighbor labels | | | |
| { | | | |
| label[*xt] = neighborLabel; | | | |
| *xt = neighborLabel; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[neighborLabel] = *xt; | | | |
| } | | | |
| } | | } | |
| ++nc; | | ++nc; | |
|
| }while(nc!=nce); | | } | |
| | | while(nc!=nce); | |
| } | | } | |
|
| //we are at a border - handle this!! | | else //we are at a border - handle this!! | |
| else | | | |
| { | | { | |
|
| | | NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo | |
| #if 0 | | d3D::nearBorderDirectionsCausal(atBorder,0)); | |
| nc = NeighborOffsetTraverser<Neighborhood3D>(Neighborho | | | |
| od3D::nearBorderDirectionsCausal(atBorder,0)); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh | | | |
| ood3D::nearBorderDirectionsCausal(atBorder,0)); | | | |
| int j=0; | | int j=0; | |
| while(nc.direction() != Neighborhood3D::Error) | | while(nc.direction() != Neighborhood3D::Error) | |
| { | | { | |
| // colors equal??? | | // colors equal??? | |
|
| if(equal(*xs, xs[*nc])) | | if(equal(sa(xs), sa(xs, *nc))) | |
| { | | { | |
|
| int neighborLabel = xt[*nc]; | | currentLabel = label.makeUnion(label[da(xd,*nc) | |
| | | ], currentLabel); | |
| // find the root label of a label tree | | | |
| while(neighborLabel != label[neighborLabel]) | | | |
| { | | | |
| neighborLabel = label[neighborLabel]; | | | |
| } | | | |
| | | | |
| if(neighborLabel < *xt) // always keep the smal | | | |
| lest among the possible neighbor labels | | | |
| { | | | |
| label[*xt] = neighborLabel; | | | |
| *xt = neighborLabel; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[neighborLabel] = *xt; | | | |
| } | | | |
| } | | } | |
| nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa
l(atBorder,++j)); | | nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa
l(atBorder,++j)); | |
| } | | } | |
| } | | } | |
|
| | | da.set(label.finalizeLabel(currentLabel), xd); | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | LabelType count = label.makeContiguous(); | |
| | | | |
| // pass 2: assign one label to each region (tree) | | // pass 2: assign one label to each region (tree) | |
| // so that labels form a consecutive sequence 1, 2, ... | | // so that labels form a consecutive sequence 1, 2, ... | |
|
| DestIterator zd = d_Iter; | | zd = d_Iter; | |
| | | | |
| unsigned int count = 0; | | | |
| | | | |
| i= 0; | | | |
| | | | |
| for(z=0; z != d; ++z, ++zd.dim2()) | | for(z=0; z != d; ++z, ++zd.dim2()) | |
| { | | { | |
| DestIterator yd(zd); | | DestIterator yd(zd); | |
| | | | |
| for(y=0; y != h; ++y, ++yd.dim1()) | | for(y=0; y != h; ++y, ++yd.dim1()) | |
| { | | { | |
| DestIterator xd(yd); | | DestIterator xd(yd); | |
| | | | |
|
| for(x = 0; x != w; ++x, ++xd.dim0(), ++i) | | for(x = 0; x != w; ++x, ++xd.dim0()) | |
| { | | { | |
|
| if(label[i] == i) | | da.set(label[da(xd)], xd); | |
| { | | | |
| label[i] = count++; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[i] = label[label[i]]; // compress trees | | | |
| } | | | |
| da.set(label[i]+1, xd); | | | |
| } | | } | |
| } | | } | |
| } | | } | |
| return count; | | return count; | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* labelVolumeSix */ | | /* labelVolumeSix */ | |
| /* */ | | /* */ | |
| | | | |
| skipping to change at line 552 | | skipping to change at line 478 | |
| | | | |
| template <class SrcIterator, class SrcAccessor,class SrcShape, | | template <class SrcIterator, class SrcAccessor,class SrcShape, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class Neighborhood3D, | | class Neighborhood3D, | |
| class ValueType, class EqualityFunctor> | | class ValueType, class EqualityFunctor> | |
| unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShap
e, SrcAccessor sa, | | unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShap
e, SrcAccessor sa, | |
| DestIterator d_Iter, DestAccessor da
, | | DestIterator d_Iter, DestAccessor da
, | |
| Neighborhood3D, | | Neighborhood3D, | |
| ValueType backgroundValue, EqualityF
unctor equal) | | ValueType backgroundValue, EqualityF
unctor equal) | |
| { | | { | |
|
| | | typedef typename DestAccessor::value_type LabelType; | |
| | | | |
| //basically needed for iteration and border-checks | | //basically needed for iteration and border-checks | |
| int w = srcShape[0], h = srcShape[1], d = srcShape[2]; | | int w = srcShape[0], h = srcShape[1], d = srcShape[2]; | |
|
| int x,y,z, i; | | int x,y,z; | |
| | | | |
| //declare and define Iterators for all three dims at src | | | |
| SrcIterator zs = s_Iter; | | | |
| SrcIterator ys(zs); | | | |
| SrcIterator xs(ys); | | | |
| | | | |
| // temporary image to store region labels | | // temporary image to store region labels | |
|
| typedef vigra::MultiArray<3,int> LabelVolume; | | detail::UnionFindArray<LabelType> label; | |
| typedef LabelVolume::traverser LabelTraverser; | | | |
| | | | |
| LabelVolume labelvolume(srcShape); | | | |
| | | | |
| //Declare traversers for all three dims at target | | //Declare traversers for all three dims at target | |
|
| LabelTraverser zt = labelvolume.traverser_begin(); | | SrcIterator zs = s_Iter; | |
| LabelTraverser yt(zt); | | DestIterator zd = d_Iter; | |
| LabelTraverser xt(yt); | | | |
| | | | |
| // Kovalevsky's clever idea to use | | | |
| // image iterator and scan order iterator simultaneously | | | |
| // memory order indicates label | | | |
| LabelVolume::iterator label = labelvolume.begin(); | | | |
| | | | |
| // initialize the neighborhood traversers | | // initialize the neighborhood traversers | |
|
| | | | |
| #if 0 | | | |
| NeighborOffsetTraverser<Neighborhood3D> nc(Neighborhood3D::CausalFirst) | | | |
| ; | | | |
| NeighborOffsetTraverser<Neighborhood3D> nce(Neighborhood3D::CausalLast) | | | |
| ; | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst | | | |
| ); | | | |
| NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast
); | | NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast
); | |
| ++nce; | | ++nce; | |
| // pass 1: scan image from upper left front to lower right back | | // pass 1: scan image from upper left front to lower right back | |
| // to find connected components | | // to find connected components | |
| | | | |
| // Each component will be represented by a tree of pixels. Each | | // Each component will be represented by a tree of pixels. Each | |
| // pixel contains the scan order address of its parent in the | | // pixel contains the scan order address of its parent in the | |
| // tree. In order for pass 2 to work correctly, the parent must | | // tree. In order for pass 2 to work correctly, the parent must | |
| // always have a smaller scan order address than the child. | | // always have a smaller scan order address than the child. | |
| // Therefore, we can merge trees only at their roots, because the | | // Therefore, we can merge trees only at their roots, because the | |
| // root of the combined tree must have the smallest scan order | | // root of the combined tree must have the smallest scan order | |
| // address among all the tree's pixels/ nodes. The root of each | | // address among all the tree's pixels/ nodes. The root of each | |
| // tree is distinguished by pointing to itself (it contains its | | // tree is distinguished by pointing to itself (it contains its | |
| // own scan order address). This condition is enforced whenever a | | // own scan order address). This condition is enforced whenever a | |
| // new region is found or two regions are merged | | // new region is found or two regions are merged | |
|
| i=0; | | for(z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2()) | |
| int backgroundAddress=-1; | | | |
| for(z = 0; z != d; ++z, ++zs.dim2(), ++zt.dim2()) | | | |
| { | | { | |
|
| ys = zs; | | SrcIterator ys(zs); | |
| yt = zt; | | DestIterator yd(zd); | |
| | | | |
|
| for(y = 0; y != h; ++y, ++ys.dim1(), ++yt.dim1()) | | for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1()) | |
| { | | { | |
|
| xs = ys; | | SrcIterator xs(ys); | |
| xt = yt; | | DestIterator xd(yd); | |
| | | | |
|
| for(x = 0; x != w; ++x, ++xs.dim0(), ++xt.dim0(), ++i) | | for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0()) | |
| { | | { | |
|
| if(equal(*xs, backgroundValue)){ | | if(equal(sa(xs), backgroundValue)) | |
| if(backgroundAddress==-1) backgroundAddress = i; | | { | |
| label[i]=backgroundAddress; | | da.set(label[0], xd); | |
| | | continue; | |
| } | | } | |
|
| else{ | | | |
| *xt = i; // default: new region | | | |
| | | | |
| //queck whether there is a special borde threatment to | | | |
| be used or not | | | |
| AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z, | | | |
| w,h,z); | | | |
| | | | |
|
| //We are not at the border! | | LabelType currentLabel = label.nextFreeLabel(); | |
| if(atBorder == NotAtBorder) | | | |
| { | | | |
| | | | |
|
| #if 0 | | //queck whether there is a special border treatment to be u | |
| nc = NeighborOffsetTraverser<Neighborhood3D>(Neighb | | sed or not | |
| orhood3D::CausalFirst); | | AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h, | |
| #endif /* #if 0 */ | | z); | |
| | | | |
|
| nc = NeighborOffsetCirculator<Neighborhood3D>(Neigh | | //We are not at the border! | |
| borhood3D::CausalFirst); | | if(atBorder == NotAtBorder) | |
| | | { | |
| | | NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo | |
| | | d3D::CausalFirst); | |
| | | | |
|
| do | | do | |
| | | { | |
| | | // if colors are equal | |
| | | if(equal(sa(xs), sa(xs, *nc))) | |
| { | | { | |
|
| // if colors are equal | | currentLabel = label.makeUnion(label[da(xd,*nc) | |
| if(equal(*xs, xs[*nc])) | | ], currentLabel); | |
| { | | } | |
| int neighborLabel = xt[*nc]; | | ++nc; | |
| | | | |
| // find the root label of a label tree | | | |
| while(neighborLabel != label[neighborLabel] | | | |
| ) | | | |
| { | | | |
| neighborLabel = label[neighborLabel]; | | | |
| } | | | |
| | | | |
| if(neighborLabel < *xt) // always keep the | | | |
| smallest among the possible neighbor labels | | | |
| { | | | |
| label[*xt] = neighborLabel; | | | |
| *xt = neighborLabel; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[neighborLabel] = *xt; | | | |
| } | | | |
| } | | | |
| ++nc; | | | |
| }while(nc!=nce); | | | |
| } | | } | |
|
| //we are at a border - handle this!! | | while(nc!=nce); | |
| else | | } | |
| | | else //we are at a border - handle this!! | |
| | | { | |
| | | NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhoo | |
| | | d3D::nearBorderDirectionsCausal(atBorder,0)); | |
| | | int j=0; | |
| | | while(nc.direction() != Neighborhood3D::Error) | |
| { | | { | |
|
| | | // colors equal??? | |
| #if 0 | | if(equal(sa(xs), sa(xs, *nc))) | |
| nc = NeighborOffsetTraverser<Neighborhood3D>(Neighb | | | |
| orhood3D::nearBorderDirectionsCausal(atBorder,0)); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| nc = NeighborOffsetCirculator<Neighborhood3D>(Neigh | | | |
| borhood3D::nearBorderDirectionsCausal(atBorder,0)); | | | |
| int j=0; | | | |
| while(nc.direction() != Neighborhood3D::Error) | | | |
| { | | { | |
|
| // colors equal??? | | currentLabel = label.makeUnion(label[da(xd,*nc) | |
| if(equal(*xs, xs[*nc])) | | ], currentLabel); | |
| { | | | |
| int neighborLabel = xt[*nc]; | | | |
| | | | |
| // find the root label of a label tree | | | |
| while(neighborLabel != label[neighborLabel] | | | |
| ) | | | |
| { | | | |
| neighborLabel = label[neighborLabel]; | | | |
| } | | | |
| | | | |
| if(neighborLabel < *xt) // always keep the | | | |
| smallest among the possible neighbor labels | | | |
| { | | | |
| label[*xt] = neighborLabel; | | | |
| *xt = neighborLabel; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[neighborLabel] = *xt; | | | |
| } | | | |
| } | | | |
| nc.turnTo(Neighborhood3D::nearBorderDirectionsC | | | |
| ausal(atBorder,++j)); | | | |
| } | | } | |
|
| | | nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa
l(atBorder,++j)); | |
| } | | } | |
| } | | } | |
|
| | | da.set(label.finalizeLabel(currentLabel), xd); | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | LabelType count = label.makeContiguous(); | |
| | | | |
| // pass 2: assign one label to each region (tree) | | // pass 2: assign one label to each region (tree) | |
| // so that labels form a consecutive sequence 1, 2, ... | | // so that labels form a consecutive sequence 1, 2, ... | |
|
| DestIterator zd = d_Iter; | | zd = d_Iter; | |
| | | | |
| unsigned int count = 0; | | | |
| | | | |
| i= 0; | | | |
| | | | |
| for(z=0; z != d; ++z, ++zd.dim2()) | | for(z=0; z != d; ++z, ++zd.dim2()) | |
| { | | { | |
| DestIterator yd(zd); | | DestIterator yd(zd); | |
| | | | |
| for(y=0; y != h; ++y, ++yd.dim1()) | | for(y=0; y != h; ++y, ++yd.dim1()) | |
| { | | { | |
| DestIterator xd(yd); | | DestIterator xd(yd); | |
| | | | |
|
| for(x = 0; x != w; ++x, ++xd.dim0(), ++i) | | for(x = 0; x != w; ++x, ++xd.dim0()) | |
| { | | { | |
|
| if(label[i] == backgroundAddress){ | | da.set(label[da(xd)], xd); | |
| label[i]=0; | | | |
| continue; | | | |
| } | | | |
| | | | |
| if(label[i] == i) | | | |
| { | | | |
| label[i] = count++; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[i] = label[label[i]]; // compress trees | | | |
| } | | | |
| da.set(label[i]+1, xd); | | | |
| } | | } | |
| } | | } | |
| } | | } | |
| return count; | | return count; | |
| } | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } //end of namespace vigra | | } //end of namespace vigra | |
| | | | |
| | | | |
End of changes. 55 change blocks. |
| 254 lines changed or deleted | | 88 lines changed or added | |
|
| linear_solve.hxx | | linear_solve.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */ | | /* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 154 | | skipping to change at line 152 | |
| return false; // no reflection needed | | return false; // no reflection needed | |
| givensCoefficients(a, b, g(0,0), g(0,1)); | | givensCoefficients(a, b, g(0,0), g(0,1)); | |
| g(1,1) = -g(0,0); | | g(1,1) = -g(0,0); | |
| g(1,0) = g(0,1); | | g(1,0) = g(0,1); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| // see Golub, van Loan: Algorithm 5.2.2 (p. 227) and Section 12.5.2 (p. 608
) | | // see Golub, van Loan: Algorithm 5.2.2 (p. 227) and Section 12.5.2 (p. 608
) | |
| template <class T, class C1, class C2> | | template <class T, class C1, class C2> | |
| bool | | bool | |
|
| qrGivensStepImpl(MultiArrayIndex i, MultiArrayView<2, T, C1> &r, MultiArray
View<2, T, C2> &rhs) | | qrGivensStepImpl(MultiArrayIndex i, MultiArrayView<2, T, C1> r, MultiArrayV
iew<2, T, C2> rhs) | |
| { | | { | |
| typedef typename Matrix<T>::difference_type Shape; | | typedef typename Matrix<T>::difference_type Shape; | |
| | | | |
| const MultiArrayIndex m = rowCount(r); | | const MultiArrayIndex m = rowCount(r); | |
| const MultiArrayIndex n = columnCount(r); | | const MultiArrayIndex n = columnCount(r); | |
| const MultiArrayIndex rhsCount = columnCount(rhs); | | const MultiArrayIndex rhsCount = columnCount(rhs); | |
| vigra_precondition(m == rowCount(rhs), | | vigra_precondition(m == rowCount(rhs), | |
| "qrGivensStepImpl(): Matrix shape mismatch."); | | "qrGivensStepImpl(): Matrix shape mismatch."); | |
| | | | |
| Matrix<T> givens(2,2); | | Matrix<T> givens(2,2); | |
| | | | |
| skipping to change at line 362 | | skipping to change at line 360 | |
| void | | void | |
| incrementalMaxSingularValueApproximation(MultiArrayView<2, T, C1> const & n
ewColumn, | | incrementalMaxSingularValueApproximation(MultiArrayView<2, T, C1> const & n
ewColumn, | |
| MultiArrayView<2, T, C2> & z, SNTy
pe & v) | | MultiArrayView<2, T, C2> & z, SNTy
pe & v) | |
| { | | { | |
| typedef typename Matrix<T>::difference_type Shape; | | typedef typename Matrix<T>::difference_type Shape; | |
| MultiArrayIndex n = rowCount(newColumn) - 1; | | MultiArrayIndex n = rowCount(newColumn) - 1; | |
| | | | |
| SNType vneu = squaredNorm(newColumn); | | SNType vneu = squaredNorm(newColumn); | |
| T yv = dot(columnVector(newColumn, Shape(0,0),n), columnVector(z, Shape
(0,0),n)); | | T yv = dot(columnVector(newColumn, Shape(0,0),n), columnVector(z, Shape
(0,0),n)); | |
| // use atan2 as it is robust against overflow/underflow | | // use atan2 as it is robust against overflow/underflow | |
|
| double t = 0.5*std::atan2(2.0*yv, sq(v)-vneu), | | T t = 0.5*std::atan2(T(2.0*yv), T(sq(v)-vneu)), | |
| s = std::sin(t), | | s = std::sin(t), | |
| c = std::cos(t); | | c = std::cos(t); | |
| v = std::sqrt(sq(c*v) + sq(s)*vneu + 2.0*s*c*yv); | | v = std::sqrt(sq(c*v) + sq(s)*vneu + 2.0*s*c*yv); | |
| columnVector(z, Shape(0,0),n) = c*columnVector(z, Shape(0,0),n) + s*col
umnVector(newColumn, Shape(0,0),n); | | columnVector(z, Shape(0,0),n) = c*columnVector(z, Shape(0,0),n) + s*col
umnVector(newColumn, Shape(0,0),n); | |
| z(n,0) = s*newColumn(n,0); | | z(n,0) = s*newColumn(n,0); | |
| } | | } | |
| | | | |
| // O(n) algorithm due to Bischof: Incremental Condition Estimation, 1990 | | // O(n) algorithm due to Bischof: Incremental Condition Estimation, 1990 | |
| template <class T, class C1, class C2, class SNType> | | template <class T, class C1, class C2, class SNType> | |
| void | | void | |
| incrementalMinSingularValueApproximation(MultiArrayView<2, T, C1> const & n
ewColumn, | | incrementalMinSingularValueApproximation(MultiArrayView<2, T, C1> const & n
ewColumn, | |
| MultiArrayView<2, T, C2> & z, SNTy
pe & v, double tolerance) | | MultiArrayView<2, T, C2> & z, SNTy
pe & v, double tolerance) | |
| | | | |
| skipping to change at line 395 | | skipping to change at line 393 | |
| | | | |
| T gamma = newColumn(n,0); | | T gamma = newColumn(n,0); | |
| if(gamma == 0.0) | | if(gamma == 0.0) | |
| { | | { | |
| v = 0.0; | | v = 0.0; | |
| return; | | return; | |
| } | | } | |
| | | | |
| T yv = dot(columnVector(newColumn, Shape(0,0),n), columnVector(z, Shape
(0,0),n)); | | T yv = dot(columnVector(newColumn, Shape(0,0),n), columnVector(z, Shape
(0,0),n)); | |
| // use atan2 as it is robust against overflow/underflow | | // use atan2 as it is robust against overflow/underflow | |
|
| double t = 0.5*std::atan2(-2.0*yv, squaredNorm(gamma / v) + squaredNorm | | T t = 0.5*std::atan2(T(-2.0*yv), T(squaredNorm(gamma / v) + squaredNorm | |
| (yv) - 1.0), | | (yv) - 1.0)), | |
| s = std::sin(t), | | s = std::sin(t), | |
| c = std::cos(t); | | c = std::cos(t); | |
| columnVector(z, Shape(0,0),n) *= c; | | columnVector(z, Shape(0,0),n) *= c; | |
| z(n,0) = (s - c*yv) / gamma; | | z(n,0) = (s - c*yv) / gamma; | |
| v *= norm(gamma) / hypot(c*gamma, v*(s - c*yv)); | | v *= norm(gamma) / hypot(c*gamma, v*(s - c*yv)); | |
| } | | } | |
| | | | |
| // QR algorithm with optional column pivoting | | // QR algorithm with optional column pivoting | |
| template <class T, class C1, class C2, class C3> | | template <class T, class C1, class C2, class C3> | |
| unsigned int | | unsigned int | |
| qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2,
T, C2> & rhs, MultiArrayView<2, T, C3> & householder, | | qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2,
T, C2> & rhs, MultiArrayView<2, T, C3> & householder, | |
| ArrayVector<MultiArrayIndex> & permutation, dou
ble epsilon) | | ArrayVector<MultiArrayIndex> & permutation, dou
ble epsilon) | |
| | | | |
| skipping to change at line 618 | | skipping to change at line 616 | |
| linearSolveQRReplace(MultiArrayView<2, T, C1> &A, MultiArrayView<2, T, C2>
&b, | | linearSolveQRReplace(MultiArrayView<2, T, C1> &A, MultiArrayView<2, T, C2>
&b, | |
| MultiArrayView<2, T, C3> & res, | | MultiArrayView<2, T, C3> & res, | |
| double epsilon = 0.0) | | double epsilon = 0.0) | |
| { | | { | |
| typedef typename Matrix<T>::difference_type Shape; | | typedef typename Matrix<T>::difference_type Shape; | |
| | | | |
| MultiArrayIndex n = columnCount(A); | | MultiArrayIndex n = columnCount(A); | |
| MultiArrayIndex m = rowCount(A); | | MultiArrayIndex m = rowCount(A); | |
| MultiArrayIndex rhsCount = columnCount(res); | | MultiArrayIndex rhsCount = columnCount(res); | |
| MultiArrayIndex rank = std::min(m,n); | | MultiArrayIndex rank = std::min(m,n); | |
|
| | | Shape ul(MultiArrayIndex(0), MultiArrayIndex(0)); | |
| | | | |
| vigra_precondition(rhsCount == columnCount(b), | | vigra_precondition(rhsCount == columnCount(b), | |
| "linearSolveQR(): RHS and solution must have the same number of
columns."); | | "linearSolveQR(): RHS and solution must have the same number of
columns."); | |
| vigra_precondition(m == rowCount(b), | | vigra_precondition(m == rowCount(b), | |
| "linearSolveQR(): Coefficient matrix and RHS must have the same
number of rows."); | | "linearSolveQR(): Coefficient matrix and RHS must have the same
number of rows."); | |
| vigra_precondition(n == rowCount(res), | | vigra_precondition(n == rowCount(res), | |
| "linearSolveQR(): Mismatch between column count of coefficient m
atrix and row count of solution."); | | "linearSolveQR(): Mismatch between column count of coefficient m
atrix and row count of solution."); | |
| vigra_precondition(epsilon >= 0.0, | | vigra_precondition(epsilon >= 0.0, | |
| "linearSolveQR(): 'epsilon' must be non-negative."); | | "linearSolveQR(): 'epsilon' must be non-negative."); | |
| | | | |
| | | | |
| skipping to change at line 635 | | skipping to change at line 634 | |
| vigra_precondition(epsilon >= 0.0, | | vigra_precondition(epsilon >= 0.0, | |
| "linearSolveQR(): 'epsilon' must be non-negative."); | | "linearSolveQR(): 'epsilon' must be non-negative."); | |
| | | | |
| if(m < n) | | if(m < n) | |
| { | | { | |
| // minimum norm solution of underdetermined system | | // minimum norm solution of underdetermined system | |
| Matrix<T> householderMatrix(n, m); | | Matrix<T> householderMatrix(n, m); | |
| MultiArrayView<2, T, StridedArrayTag> ht = transpose(householderMat
rix); | | MultiArrayView<2, T, StridedArrayTag> ht = transpose(householderMat
rix); | |
| rank = (MultiArrayIndex)detail::qrTransformToLowerTriangular(A, b,
ht, epsilon); | | rank = (MultiArrayIndex)detail::qrTransformToLowerTriangular(A, b,
ht, epsilon); | |
| res.subarray(Shape(rank,0), Shape(n, rhsCount)).init(NumericTraits<
T>::zero()); | | res.subarray(Shape(rank,0), Shape(n, rhsCount)).init(NumericTraits<
T>::zero()); | |
|
| | | | |
| if(rank < m) | | if(rank < m) | |
| { | | { | |
| // system is also rank-deficient => compute minimum norm least
squares solution | | // system is also rank-deficient => compute minimum norm least
squares solution | |
|
| MultiArrayView<2, T, C1> Asub = A.subarray(Shape(0,0), Shape(m,
rank)); | | MultiArrayView<2, T, C1> Asub = A.subarray(ul, Shape(m,rank)); | |
| detail::qrTransformToUpperTriangular(Asub, b, epsilon); | | detail::qrTransformToUpperTriangular(Asub, b, epsilon); | |
|
| linearSolveUpperTriangular(A.subarray(Shape(0,0), Shape(rank,ra | | linearSolveUpperTriangular(A.subarray(ul, Shape(rank,rank)), | |
| nk)), | | b.subarray(ul, Shape(rank,rhsCount)) | |
| b.subarray(Shape(0,0), Shape(rank,rh | | , | |
| sCount)), | | res.subarray(ul, Shape(rank, rhsCoun | |
| res.subarray(Shape(0,0), Shape(rank, | | t))); | |
| rhsCount))); | | | |
| } | | } | |
| else | | else | |
| { | | { | |
| // system has full rank => compute minimum norm solution | | // system has full rank => compute minimum norm solution | |
|
| linearSolveLowerTriangular(A.subarray(Shape(0,0), Shape(rank,ra | | linearSolveLowerTriangular(A.subarray(ul, Shape(rank,rank)), | |
| nk)), | | b.subarray(ul, Shape(rank, rhsCount) | |
| b.subarray(Shape(0,0), Shape(rank, r | | ), | |
| hsCount)), | | res.subarray(ul, Shape(rank, rhsCoun | |
| res.subarray(Shape(0,0), Shape(rank, | | t))); | |
| rhsCount))); | | | |
| } | | } | |
|
| detail::applyHouseholderColumnReflections(householderMatrix.subarra
y(Shape(0,0), Shape(n, rank)), res); | | detail::applyHouseholderColumnReflections(householderMatrix.subarra
y(ul, Shape(n, rank)), res); | |
| } | | } | |
| else | | else | |
| { | | { | |
| // solution of well-determined or overdetermined system | | // solution of well-determined or overdetermined system | |
| ArrayVector<MultiArrayIndex> permutation((unsigned int)n); | | ArrayVector<MultiArrayIndex> permutation((unsigned int)n); | |
| for(MultiArrayIndex k=0; k<n; ++k) | | for(MultiArrayIndex k=0; k<n; ++k) | |
| permutation[k] = k; | | permutation[k] = k; | |
| | | | |
| rank = (MultiArrayIndex)detail::qrTransformToUpperTriangular(A, b,
permutation, epsilon); | | rank = (MultiArrayIndex)detail::qrTransformToUpperTriangular(A, b,
permutation, epsilon); | |
| | | | |
| Matrix<T> permutedSolution(n, rhsCount); | | Matrix<T> permutedSolution(n, rhsCount); | |
| if(rank < n) | | if(rank < n) | |
| { | | { | |
| // system is rank-deficient => compute minimum norm solution | | // system is rank-deficient => compute minimum norm solution | |
| Matrix<T> householderMatrix(n, rank); | | Matrix<T> householderMatrix(n, rank); | |
| MultiArrayView<2, T, StridedArrayTag> ht = transpose(householde
rMatrix); | | MultiArrayView<2, T, StridedArrayTag> ht = transpose(householde
rMatrix); | |
|
| MultiArrayView<2, T, C1> Asub = A.subarray(Shape(0,0), Shape(ra
nk,n)); | | MultiArrayView<2, T, C1> Asub = A.subarray(ul, Shape(rank,n)); | |
| detail::qrTransformToLowerTriangular(Asub, ht, epsilon); | | detail::qrTransformToLowerTriangular(Asub, ht, epsilon); | |
|
| linearSolveLowerTriangular(A.subarray(Shape(0,0), Shape(rank,ra | | linearSolveLowerTriangular(A.subarray(ul, Shape(rank,rank)), | |
| nk)), | | b.subarray(ul, Shape(rank, rhsCount) | |
| b.subarray(Shape(0,0), Shape(rank, r | | ), | |
| hsCount)), | | permutedSolution.subarray(ul, Shape( | |
| permutedSolution.subarray(Shape(0,0) | | rank, rhsCount))); | |
| , Shape(rank, rhsCount))); | | | |
| detail::applyHouseholderColumnReflections(householderMatrix, pe
rmutedSolution); | | detail::applyHouseholderColumnReflections(householderMatrix, pe
rmutedSolution); | |
| } | | } | |
| else | | else | |
| { | | { | |
| // system has full rank => compute exact or least squares solut
ion | | // system has full rank => compute exact or least squares solut
ion | |
|
| linearSolveUpperTriangular(A.subarray(Shape(0,0), Shape(rank,ra | | linearSolveUpperTriangular(A.subarray(ul, Shape(rank,rank)), | |
| nk)), | | b.subarray(ul, Shape(rank,rhsCount)) | |
| b.subarray(Shape(0,0), Shape(rank,rh | | , | |
| sCount)), | | | |
| permutedSolution); | | permutedSolution); | |
| } | | } | |
| detail::inverseRowPermutation(permutedSolution, res, permutation); | | detail::inverseRowPermutation(permutedSolution, res, permutation); | |
| } | | } | |
| return (unsigned int)rank; | | return (unsigned int)rank; | |
| } | | } | |
| | | | |
| template <class T, class C1, class C2, class C3> | | template <class T, class C1, class C2, class C3> | |
| unsigned int linearSolveQR(MultiArrayView<2, T, C1> const & A, MultiArrayVi
ew<2, T, C2> const & b, | | unsigned int linearSolveQR(MultiArrayView<2, T, C1> const & A, MultiArrayVi
ew<2, T, C2> const & b, | |
| MultiArrayView<2, T, C3> & res) | | MultiArrayView<2, T, C3> & res) | |
| | | | |
| skipping to change at line 726 | | skipping to change at line 724 | |
| */ | | */ | |
| 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) | |
| { | | { | |
| const MultiArrayIndex n = columnCount(v); | | const MultiArrayIndex n = columnCount(v); | |
| vigra_precondition(n <= rowCount(v), | | vigra_precondition(n <= rowCount(v), | |
| "inverse(): input matrix must have at least as many rows as columns.
"); | | "inverse(): input matrix must have at least as many rows as columns.
"); | |
| vigra_precondition(n == rowCount(res) && rowCount(v) == 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> q(v.shape()), r(n, n); | | Matrix<T> r(v.shape()), q(n, n); | |
| if(!qrDecomposition(v, q, r)) | | if(!qrDecomposition(v, q, r)) | |
| return false; // a didn't have full rank | | return false; // a didn't have full rank | |
| linearSolveUpperTriangular(r, transpose(q), res); | | linearSolveUpperTriangular(r, transpose(q), 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. | |
| | | | |
| skipping to change at line 894 | | skipping to change at line 892 | |
| 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
r_solve.hxx</a>\> or<br> | | <b>\#include</b> \<<a href="linear__solve_8hxx-source.html">vigra/linea
r_solve.hxx</a>\> or<br> | |
| <b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin
ear_algebra.hxx</a>\><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) | |
| { | | { | |
|
| typedef T Real; | | | |
| | | | |
| 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), | |
| | | "choleskyDecomposition(): Input matrix must be symme | |
| | | tric."); | |
| | | | |
| for (MultiArrayIndex j = 0; j < n; ++j) | | for (MultiArrayIndex j = 0; j < n; ++j) | |
| { | | { | |
|
| Real d(0.0); | | T d(0.0); | |
| for (MultiArrayIndex k = 0; k < j; ++k) | | for (MultiArrayIndex k = 0; k < j; ++k) | |
| { | | { | |
|
| Real 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; | |
|
| vigra_precondition(A(k, j) == A(j, k), | | | |
| "choleskyDecomposition(): Input matrix must be symme | | | |
| tric."); | | | |
| } | | } | |
| 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; | |
| } | | } | |
| } | | } | |
| | | | |
| skipping to change at line 963 | | skipping to change at line 958 | |
| const MultiArrayIndex m = rowCount(a); | | const MultiArrayIndex m = rowCount(a); | |
| const MultiArrayIndex n = columnCount(a); | | const MultiArrayIndex n = columnCount(a); | |
| vigra_precondition(n == columnCount(r) && m == rowCount(r) && | | vigra_precondition(n == columnCount(r) && m == rowCount(r) && | |
| m == columnCount(q) && m == rowCount(q), | | m == columnCount(q) && m == rowCount(q), | |
| "qrDecomposition(): Matrix shape mismatch."); | | "qrDecomposition(): Matrix shape mismatch."); | |
| | | | |
| q = identityMatrix<T>(m); | | q = identityMatrix<T>(m); | |
| MultiArrayView<2,T, StridedArrayTag> tq = transpose(q); | | MultiArrayView<2,T, StridedArrayTag> tq = transpose(q); | |
| r = a; | | r = a; | |
| ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty | | ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty | |
|
| return (detail::qrTransformToUpperTriangular(r, tq, noPivoting, epsilon
) == std::min(m,n)); | | return ((MultiArrayIndex)detail::qrTransformToUpperTriangular(r, tq, no
Pivoting, epsilon) == std::min(m,n)); | |
| } | | } | |
| | | | |
| /** Deprecated, use \ref linearSolveUpperTriangular(). | | /** Deprecated, use \ref linearSolveUpperTriangular(). | |
| */ | | */ | |
| template <class T, class C1, class C2, class C3> | | template <class T, class C1, class C2, class C3> | |
| inline | | inline | |
| bool reverseElimination(const MultiArrayView<2, T, C1> &r, const MultiArray
View<2, T, C2> &b, | | bool reverseElimination(const MultiArrayView<2, T, C1> &r, const MultiArray
View<2, T, C2> &b, | |
| MultiArrayView<2, T, C3> x) | | MultiArrayView<2, T, C3> x) | |
| { | | { | |
| return linearSolveUpperTriangular(r, b, x); | | return linearSolveUpperTriangular(r, b, x); | |
| | | | |
| skipping to change at line 1077 | | skipping to change at line 1072 | |
| return false; // l doesn't have full rank | | return false; // l doesn't have full rank | |
| T sum = b(i, k); | | T sum = b(i, k); | |
| for(MultiArrayIndex j=0; j<i; ++j) | | for(MultiArrayIndex j=0; j<i; ++j) | |
| sum -= l(i, j) * x(j, k); | | sum -= l(i, j) * x(j, k); | |
| x(i, k) = sum / l(i, i); | | x(i, k) = sum / l(i, i); | |
| } | | } | |
| } | | } | |
| return true; | | return true; | |
| } | | } | |
| | | | |
|
| | | /** 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 | |
| | | 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 | |
| | | 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 | |
| | | columns of \a b. This implementation can be applied in-place, i.e. | |
| | | <tt>&b == &x</tt> is allowed. | |
| | | The following size requirements apply: | |
| | | | |
| | | \code | |
| | | rowCount(L) == columnCount(L); | |
| | | rowCount(L) == rowCount(b); | |
| | | columnCount(L) == rowCount(x); | |
| | | columnCount(b) == columnCount(x); | |
| | | \endcode | |
| | | | |
| | | <b>\#include</b> \<<a href="linear__solve_8hxx-source.html">vigra/linea | |
| | | r_solve.hxx</a>\> or<br> | |
| | | <b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin | |
| | | ear_algebra.hxx</a>\><br> | |
| | | Namespaces: vigra and vigra::linalg | |
| | | */ | |
| | | template <class T, class C1, class C2, class C3> | |
| | | inline | |
| | | void choleskySolve(MultiArrayView<2, T, C1> & L, MultiArrayView<2, T, C2> c | |
| | | onst & b, MultiArrayView<2, T, C3> & x) | |
| | | { | |
| | | /* Solve L * y = b */ | |
| | | linearSolveLowerTriangular(L, b, x); | |
| | | /* Solve L^T * x = y */ | |
| | | linearSolveUpperTriangular(transpose(L), x, x); | |
| | | } | |
| | | | |
| /** Solve a linear system. | | /** Solve a linear system. | |
| | | | |
| \a A is the coefficient matrix, and the column vectors | | \a A is the coefficient matrix, and the column vectors | |
| in \a b are the right-hand sides of the equation (so, several equat
ions | | in \a b are the right-hand sides of the equation (so, several equat
ions | |
| with the same coefficients can be solved in one go). The result is
returned | | with the same coefficients can be solved in one go). The result is
returned | |
| in \a res, whose columns contain the solutions for the correspondin
g | | in \a res, whose columns contain the solutions for the correspondin
g | |
| columns of \a b. The number of columns of \a A must equal the numbe
r of rows of | | columns of \a b. The number of columns of \a A must equal the numbe
r of rows of | |
| both \a b and \a res, and the number of columns of \a b and \a res
must match. | | both \a b and \a res, and the number of columns of \a b and \a res
must match. | |
| | | | |
| \a method must be one of the following: | | \a method must be one of the following: | |
| | | | |
| skipping to change at line 1152 | | skipping to change at line 1179 | |
| for(unsigned int k=0; k<method.size(); ++k) | | for(unsigned int k=0; k<method.size(); ++k) | |
| method[k] = (std::string::value_type)tolower(method[k]); | | method[k] = (std::string::value_type)tolower(method[k]); | |
| | | | |
| if(method == "cholesky") | | if(method == "cholesky") | |
| { | | { | |
| vigra_precondition(columnCount(A) == rowCount(A), | | vigra_precondition(columnCount(A) == rowCount(A), | |
| "linearSolve(): Cholesky method requires square coefficient mat
rix."); | | "linearSolve(): Cholesky method requires square coefficient mat
rix."); | |
| Matrix<T> L(A.shape()); | | Matrix<T> L(A.shape()); | |
| if(!choleskyDecomposition(A, L)) | | if(!choleskyDecomposition(A, L)) | |
| return false; // false if A wasn't symmetric positive definite | | return false; // false if A wasn't symmetric positive definite | |
|
| linearSolveLowerTriangular(L, b, res); | | choleskySolve(L, b, res); | |
| linearSolveUpperTriangular(transpose(L), res, res); | | | |
| } | | } | |
| else if(method == "qr") | | else if(method == "qr") | |
| { | | { | |
| 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") | |
| | | | |
| skipping to change at line 1197 | | skipping to change at line 1223 | |
| } | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } // namespace linalg | | } // namespace linalg | |
| | | | |
| using linalg::inverse; | | using linalg::inverse; | |
| using linalg::determinant; | | using linalg::determinant; | |
| using linalg::logDeterminant; | | using linalg::logDeterminant; | |
| using linalg::linearSolve; | | using linalg::linearSolve; | |
|
| | | using linalg::choleskySolve; | |
| using linalg::choleskyDecomposition; | | using linalg::choleskyDecomposition; | |
| using linalg::qrDecomposition; | | using linalg::qrDecomposition; | |
| using linalg::linearSolveUpperTriangular; | | using linalg::linearSolveUpperTriangular; | |
| using linalg::linearSolveLowerTriangular; | | using linalg::linearSolveLowerTriangular; | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
| #endif // VIGRA_LINEAR_SOLVE_HXX | | #endif // VIGRA_LINEAR_SOLVE_HXX | |
| | | | |
End of changes. 26 change blocks. |
| 49 lines changed or deleted | | 80 lines changed or added | |
|
| multi_array.hxx | | multi_array.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */ | | /* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */ | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 52 | | skipping to change at line 51 | |
| #include "accessor.hxx" | | #include "accessor.hxx" | |
| #include "tinyvector.hxx" | | #include "tinyvector.hxx" | |
| #include "rgbvalue.hxx" | | #include "rgbvalue.hxx" | |
| #include "basicimageview.hxx" | | #include "basicimageview.hxx" | |
| #include "imageiterator.hxx" | | #include "imageiterator.hxx" | |
| #include "numerictraits.hxx" | | #include "numerictraits.hxx" | |
| #include "multi_iterator.hxx" | | #include "multi_iterator.hxx" | |
| #include "metaprogramming.hxx" | | #include "metaprogramming.hxx" | |
| #include "mathutil.hxx" | | #include "mathutil.hxx" | |
| | | | |
|
| | | // Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined. | |
| | | #ifdef VIGRA_CHECK_BOUNDS | |
| | | #define VIGRA_ASSERT_INSIDE(diff) \ | |
| | | vigra_precondition(this->isInside(diff), "Index out of bounds") | |
| | | #else | |
| | | #define VIGRA_ASSERT_INSIDE(diff) | |
| | | #endif | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
| namespace detail | | namespace detail | |
| { | | { | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* defaultStride */ | | /* defaultStride */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| skipping to change at line 333 | | skipping to change at line 340 | |
| } | | } | |
| | | | |
| #define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \ | | #define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \ | |
| template <class SrcIterator, class Shape, class DestIterator> \ | | template <class SrcIterator, class Shape, class DestIterator> \ | |
| inline void \ | | inline void \ | |
| name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me
taInt<0>) \ | | name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me
taInt<0>) \ | |
| { \ | | { \ | |
| SrcIterator send = s + shape[0]; \ | | SrcIterator send = s + shape[0]; \ | |
| for(; s < send; ++s, ++d) \ | | for(; s < send; ++s, ++d) \ | |
| { \ | | { \ | |
|
| *d op *s; \ | | *d op detail::RequiresExplicitCast<typename DestIterator::value_typ
e>::cast(*s); \ | |
| } \ | | } \ | |
| } \ | | } \ | |
| \ | | \ | |
| template <class SrcIterator, class Shape, class DestIterator, int N> \ | | template <class SrcIterator, class Shape, class DestIterator, int N> \ | |
| void \ | | void \ | |
| name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me
taInt<N>) \ | | name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, Me
taInt<N>) \ | |
| { \ | | { \ | |
| SrcIterator send = s + shape[N]; \ | | SrcIterator send = s + shape[N]; \ | |
| for(; s < send; ++s, ++d) \ | | for(; s < send; ++s, ++d) \ | |
| { \ | | { \ | |
| | | | |
| skipping to change at line 355 | | skipping to change at line 362 | |
| } \ | | } \ | |
| } \ | | } \ | |
| \ | | \ | |
| template <class DestIterator, class Shape, class T> \ | | template <class DestIterator, class Shape, class T> \ | |
| inline void \ | | inline void \ | |
| name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i
nit, MetaInt<0>) \ | | name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i
nit, MetaInt<0>) \ | |
| { \ | | { \ | |
| DestIterator dend = d + shape[0]; \ | | DestIterator dend = d + shape[0]; \ | |
| for(; d < dend; ++d) \ | | for(; d < dend; ++d) \ | |
| { \ | | { \ | |
|
| *d op init; \ | | *d op detail::RequiresExplicitCast<typename DestIterator::value_typ
e>::cast(init); \ | |
| } \ | | } \ | |
| } \ | | } \ | |
| \ | | \ | |
| template <class DestIterator, class Shape, class T, int N> \ | | template <class DestIterator, class Shape, class T, int N> \ | |
| void \ | | void \ | |
| name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i
nit, MetaInt<N>) \ | | name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & i
nit, MetaInt<N>) \ | |
| { \ | | { \ | |
| DestIterator dend = d + shape[N]; \ | | DestIterator dend = d + shape[N]; \ | |
| for(; d < dend; ++d) \ | | for(; d < dend; ++d) \ | |
| { \ | | { \ | |
| | | | |
| skipping to change at line 676 | | skipping to change at line 683 | |
| /** pointer to the image. | | /** pointer to the image. | |
| */ | | */ | |
| pointer m_ptr; | | pointer m_ptr; | |
| | | | |
| template <class U, class CN> | | template <class U, class CN> | |
| void copyImpl(const MultiArrayView <N, U, CN>& rhs); | | void copyImpl(const MultiArrayView <N, U, CN>& rhs); | |
| | | | |
| template <class U, class CN> | | template <class U, class CN> | |
| void swapDataImpl(MultiArrayView <N, U, CN> rhs); | | void swapDataImpl(MultiArrayView <N, U, CN> rhs); | |
| | | | |
|
| | | template <class CN> | |
| | | 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>& rhs) const; | | bool arraysOverlap(const MultiArrayView <N, U, CN>&) const | |
| | | { | |
| | | return false; | |
| | | } | |
| | | | |
| public: | | public: | |
| | | | |
|
| /** default constructor: create an empty image of size 0. | | /** default constructor: create an invalid view, | |
| | | * 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 next) | | /** Construct from shape, strides (offset of a sample to the | |
| for every dimension) and pointer | | next) for every dimension, and pointer. (Note that | |
| | | strides are not given in bytes, but in offsets of the | |
| | | 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) | |
| {} | | {} | |
| | | | |
| /** Assignment. There are 3 cases: | | /** Assignment. There are 3 cases: | |
| | | | |
| skipping to change at line 789 | | skipping to change at line 805 | |
| 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; | |
| } | | } | |
| | | | |
| /** array access. | | /** array access. | |
| */ | | */ | |
| reference operator[] (const difference_type &d) | | reference operator[] (const difference_type &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); | |
| return m_ptr [dot (d, m_stride)]; | | return m_ptr [dot (d, m_stride)]; | |
| } | | } | |
| | | | |
|
| | | /** equvalent to bindInner(), when M < N. | |
| | | */ | |
| | | template <unsigned int M> | |
| | | MultiArrayView <N-M, T, StridedArrayTag> operator[] (const TinyVector<M | |
| | | ultiArrayIndex, M> &d) const | |
| | | { | |
| | | 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. | |
| */ | | */ | |
| reference operator[](difference_type_1 d) | | reference operator[](difference_type_1 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. | |
| */ | | */ | |
| const_reference operator[](difference_type_1 d) const | | const_reference operator[](difference_type_1 d) const | |
| { | | { | |
|
| | | 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 | |
| { | | { | |
| difference_type result; | | difference_type result; | |
| detail::ScanOrderToCoordinate<actual_dimension>::exec(d, m_shape, r
esult); | | detail::ScanOrderToCoordinate<actual_dimension>::exec(d, m_shape, r
esult); | |
| return result; | | return result; | |
| | | | |
| skipping to change at line 839 | | skipping to change at line 867 | |
| */ | | */ | |
| 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)); | |
| return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x)]; | | return m_ptr [detail::CoordinatesToOffest<C>::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)); | |
| return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x, y)]
; | | return m_ptr [detail::CoordinatesToOffest<C>::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)); | |
| 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]; | |
| } | | } | |
| | | | |
| /** 4D array access. Use only if N == 4. | | /** 4D array access. Use only if N == 4. | |
| */ | | */ | |
| reference operator() (difference_type_1 x, difference_type_1 y, | | reference operator() (difference_type_1 x, difference_type_1 y, | |
| difference_type_1 z, difference_type_1 u) | | difference_type_1 z, difference_type_1 u) | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(difference_type(x, y, z, u)); | |
| return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_str
ide[3]*u]; | | return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_str
ide[3]*u]; | |
| } | | } | |
| | | | |
| /** 5D array access. Use only if N == 5. | | /** 5D array access. Use only if N == 5. | |
| */ | | */ | |
| 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, | |
| difference_type_1 u, difference_type_1 v) | | difference_type_1 u, difference_type_1 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)); | |
| return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x)]; | | return m_ptr [detail::CoordinatesToOffest<C>::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)); | |
| return m_ptr [detail::CoordinatesToOffest<C>::exec(m_stride, x, y)]
; | | return m_ptr [detail::CoordinatesToOffest<C>::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)); | |
| 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]; | |
| } | | } | |
| | | | |
| /** 4D const array access. Use only if N == 4. | | /** 4D const array access. Use only if N == 4. | |
| */ | | */ | |
| const_reference operator() (difference_type_1 x, difference_type_1 y, | | const_reference operator() (difference_type_1 x, difference_type_1 y, | |
| difference_type_1 z, difference_type_1 u) c
onst | | difference_type_1 z, difference_type_1 u) c
onst | |
| { | | { | |
|
| | | VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u)); | |
| return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_str
ide[3]*u]; | | return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_str
ide[3]*u]; | |
| } | | } | |
| | | | |
| /** 5D const array access. Use only if N == 5. | | /** 5D const array access. Use only if N == 5. | |
| */ | | */ | |
| const_reference operator() (difference_type_1 x, difference_type_1 y, d
ifference_type_1 z, | | const_reference operator() (difference_type_1 x, difference_type_1 y, d
ifference_type_1 z, | |
| difference_type_1 u, difference_type_1 v) c
onst | | difference_type_1 u, difference_type_1 v) c
onst | |
| { | | { | |
|
| | | 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]; | |
| } | | } | |
| | | | |
| /** Init with a constant. | | /** Init with a constant. | |
| */ | | */ | |
| template <class U> | | template <class U> | |
| MultiArrayView & init(const U & init) | | MultiArrayView & init(const U & init) | |
| { | | { | |
| detail::copyScalarMultiArrayData(traverser_begin(), shape(), init,
MetaInt<actual_dimension-1>()); | | detail::copyScalarMultiArrayData(traverser_begin(), shape(), init,
MetaInt<actual_dimension-1>()); | |
| return *this; | | return *this; | |
| | | | |
| skipping to change at line 1060 | | skipping to change at line 1098 | |
| 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). | |
| | | | |
| | | 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 | |
| | | the 'reduce mode' of transformMultiArray() and combineTwoMultiA | |
| | | rrays(), | |
| | | because these functions require the source and destination arra | |
| | | ys to | |
| | | 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 i'th index, and the old indices from i upwards will shift o | |
| | | ne | |
| | | place to the right. | |
| | | | |
| | | <b>Usage:</b> | |
| | | | |
| | | Suppose we want have a 2D array and want to create a 1D array t | |
| | | hat contains | |
| | | the row average of the first array. | |
| | | \code | |
| | | typedef MultiArrayShape<2>::type Shape2; | |
| | | MultiArray<2, double> original(Shape2(40, 30)); | |
| | | | |
| | | typedef MultiArrayShape<1>::type Shape1; | |
| | | MultiArray<1, double> rowAverages(Shape1(30)); | |
| | | | |
| | | // temporarily add a singleton dimension to the destination arr | |
| | | ay | |
| | | transformMultiArray(srcMultiArrayRange(original), | |
| | | destMultiArrayRange(rowAverages.insertSingl | |
| | | etonDimension(0)), | |
| | | FindAverage<double>()); | |
| | | \endcode | |
| | | */ | |
| | | MultiArrayView <N+1, T, C> | |
| | | 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)); | |
| | | | |
| // get a subarray set is smaller by one element at all sides | | // get a subarray set is smaller by one element at all sides | |
| | | | |
| skipping to change at line 1092 | | skipping to change at line 1162 | |
| 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 layed 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> | | return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, | |
| (shape, m_stride * s, m_ptr); | | m_ptr); | |
| } | | } | |
| | | | |
|
| /** permute the dimensions of the array. | | /** Transpose an array. If N==2, this implements the usual matrix t | |
| The function exchanges the meaning of the dimensions without co | | ransposition. | |
| pying the data. | | For N > 2, it reverses the order of the indices. | |
| In case of a 2-dimensional array, this is simply array transpos | | | |
| ition. In higher dimensions, | | | |
| there are more possibilities. | | | |
| | | | |
| <b>Usage:</b><br> | | <b>Usage:</b><br> | |
| \code | | \code | |
| typedef MultiArray<2, double>::difference_type Shape; | | typedef MultiArray<2, double>::difference_type Shape; | |
| MultiArray<2, double> array(10, 20); | | MultiArray<2, double> array(10, 20); | |
| | | | |
|
| MultiArray<2, double, StridedArrayTag> transposed = array.permu
teDimensions(Shape(1,0)); | | MultiArray<2, double, StridedArrayTag> transposed = array.trans
pose(); | |
| | | | |
| for(int i=0; i<array.shape(0), ++i) | | for(int i=0; i<array.shape(0), ++i) | |
| for(int j=0; j<array.shape(1); ++j) | | for(int j=0; j<array.shape(1); ++j) | |
| assert(array(i, j) == transposed(j, i)); | | assert(array(i, j) == transposed(j, i)); | |
| \endcode | | \endcode | |
| */ | | */ | |
| MultiArrayView <N, T, StridedArrayTag> | | MultiArrayView <N, T, StridedArrayTag> | |
|
| permuteDimensions (const difference_type &s) const | | transpose () const | |
| { | | { | |
|
| difference_type shape, stride, check((typename difference_type::val | | difference_type shape(m_shape.begin(), difference_type::ReverseCopy | |
| ue_type)0); | | ), | |
| for (unsigned int i = 0; i < actual_dimension; ++i) | | stride(m_stride.begin(), difference_type::ReverseCo | |
| { | | py); | |
| shape[i] = m_shape[s[i]]; | | | |
| stride[i] = m_stride[s[i]]; | | | |
| ++check[s[i]]; | | | |
| } | | | |
| vigra_precondition(check == difference_type(1), | | | |
| "MultiArrayView::permuteDimensions(): every dimension must occur | | | |
| exactly once."); | | | |
| return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr)
; | | return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr)
; | |
| } | | } | |
| | | | |
|
| /** transpose a 2-dimensional array. Use only if N==2. | | /** permute the dimensions of the array. | |
| | | The function exchanges the meaning of the dimensions without co | |
| | | pying the data. | |
| | | In case of a 2-dimensional array, this is simply array transpos | |
| | | ition. In higher dimensions, | |
| | | there are more possibilities. | |
| | | | |
| <b>Usage:</b><br> | | <b>Usage:</b><br> | |
| \code | | \code | |
| typedef MultiArray<2, double>::difference_type Shape; | | typedef MultiArray<2, double>::difference_type Shape; | |
| MultiArray<2, double> array(10, 20); | | MultiArray<2, double> array(10, 20); | |
| | | | |
|
| MultiArray<2, double, StridedArrayTag> transposed = array.trans
pose(); | | MultiArray<2, double, StridedArrayTag> transposed = array.permu
teDimensions(Shape(1,0)); | |
| | | | |
| for(int i=0; i<array.shape(0), ++i) | | for(int i=0; i<array.shape(0), ++i) | |
| for(int j=0; j<array.shape(1); ++j) | | for(int j=0; j<array.shape(1); ++j) | |
| assert(array(i, j) == transposed(j, i)); | | assert(array(i, j) == transposed(j, i)); | |
| \endcode | | \endcode | |
| */ | | */ | |
|
| MultiArrayView <2, T, StridedArrayTag> | | MultiArrayView <N, T, StridedArrayTag> | |
| transpose () const | | permuteDimensions (const difference_type &s) const; | |
| | | | |
| | | /** Permute the dimensions of the array so that the strides are in | |
| | | ascending order. | |
| | | Determines the appropriate permutation and then calls permuteDi | |
| | | mensions(). | |
| | | */ | |
| | | MultiArrayView <N, T, StridedArrayTag> | |
| | | permuteStridesAscending() const; | |
| | | | |
| | | /** Permute the dimensions of the array so that the strides are in | |
| | | descending order. | |
| | | Determines the appropriate permutation and then calls permuteDi | |
| | | mensions(). | |
| | | */ | |
| | | MultiArrayView <N, T, StridedArrayTag> | |
| | | permuteStridesDescending() const; | |
| | | | |
| | | /** Compute the ordering of the strides in this array. | |
| | | The result is describes the current permutation of the axes rel | |
| | | ative | |
| | | to the standard ascending stride order. | |
| | | */ | |
| | | difference_type strideOrdering() const | |
| { | | { | |
|
| difference_type shape(m_shape[1], m_shape[0]), | | return strideOrdering(m_stride); | |
| stride(m_stride[1], m_stride[0]); | | | |
| return MultiArrayView <2, T, StridedArrayTag>(shape, stride, m_ptr) | | | |
| ; | | | |
| } | | } | |
| | | | |
|
| | | /** Compute the ordering of the given strides. | |
| | | The result is describes the current permutation of the axes rel | |
| | | ative | |
| | | to the standard ascending stride order. | |
| | | */ | |
| | | static difference_type strideOrdering(difference_type strides); | |
| | | | |
| /** number of the elements in the array. | | /** number of the elements in the array. | |
| */ | | */ | |
| difference_type_1 elementCount () const | | difference_type_1 elementCount () const | |
| { | | { | |
| difference_type_1 ret = m_shape[0]; | | difference_type_1 ret = m_shape[0]; | |
| for(int i = 1; i < actual_dimension; ++i) | | for(int i = 1; i < actual_dimension; ++i) | |
| ret *= m_shape[i]; | | ret *= m_shape[i]; | |
| return ret; | | return ret; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1266 | | skipping to change at line 1351 | |
| */ | | */ | |
| typename NormTraits<MultiArrayView>::NormType norm(int type = 2, bool u
seSquaredNorm = true) const; | | typename NormTraits<MultiArrayView>::NormType norm(int type = 2, bool u
seSquaredNorm = 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, | |
| | | * i.e. data() is not a NULL pointer. (this is false after | |
| | | * default construction.) | |
| | | */ | |
| | | bool hasData () const | |
| | | { | |
| | | return m_ptr != 0; | |
| | | } | |
| | | | |
| /** 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 1332 | | skipping to change at line 1427 | |
| 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 C> | |
|
| template <class U, class CN> | | template <class CN> | |
| bool | | bool | |
|
| MultiArrayView <N, T, C>::arraysOverlap(const MultiArrayView <N, U, CN>& rh
s) const | | MultiArrayView <N, T, C>::arraysOverlap(const MultiArrayView <N, T, CN>& rh
s) 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, U, 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 C> | |
| 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, C>::copyImpl(const MultiArrayView <N, U, CN>& rhs) | |
| { | | { | |
| | | | |
| skipping to change at line 1421 | | skipping to change at line 1516 | |
| { | | { | |
| // 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 C> | |
|
| | | MultiArrayView <N, T, StridedArrayTag> | |
| | | MultiArrayView <N, T, C>::permuteDimensions (const difference_type &s) cons | |
| | | t | |
| | | { | |
| | | difference_type shape, stride, check((typename difference_type::value_t | |
| | | ype)0); | |
| | | for (unsigned int i = 0; i < actual_dimension; ++i) | |
| | | { | |
| | | shape[i] = m_shape[s[i]]; | |
| | | stride[i] = m_stride[s[i]]; | |
| | | ++check[s[i]]; | |
| | | } | |
| | | vigra_precondition(check == difference_type(1), | |
| | | "MultiArrayView::permuteDimensions(): every dimension must occur exa | |
| | | ctly once."); | |
| | | return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr); | |
| | | } | |
| | | | |
| | | template <unsigned int N, class T, class C> | |
| | | typename MultiArrayView <N, T, C>::difference_type | |
| | | MultiArrayView <N, T, C>::strideOrdering(difference_type stride) | |
| | | { | |
| | | difference_type permutation; | |
| | | for(unsigned int k=0; k<N; ++k) | |
| | | permutation[k] = k; | |
| | | for(unsigned int k=0; k<N-1; ++k) | |
| | | { | |
| | | unsigned int smallest = k; | |
| | | for(unsigned int j=k+1; j<N; ++j) | |
| | | { | |
| | | if(stride[j] < stride[smallest]) | |
| | | smallest = j; | |
| | | } | |
| | | if(smallest != k) | |
| | | { | |
| | | std::swap(stride[k], stride[smallest]); | |
| | | std::swap(permutation[k], permutation[smallest]); | |
| | | } | |
| | | } | |
| | | difference_type ordering; | |
| | | for(unsigned int k=0; k<N; ++k) | |
| | | ordering[permutation[k]] = k; | |
| | | return ordering; | |
| | | } | |
| | | | |
| | | template <unsigned int N, class T, class C> | |
| | | MultiArrayView <N, T, StridedArrayTag> | |
| | | MultiArrayView <N, T, C>::permuteStridesAscending() const | |
| | | { | |
| | | difference_type ordering(strideOrdering(m_stride)), permutation; | |
| | | for(MultiArrayIndex k=0; k<N; ++k) | |
| | | permutation[ordering[k]] = k; | |
| | | return permuteDimensions(permutation); | |
| | | } | |
| | | | |
| | | template <unsigned int N, class T, class C> | |
| | | MultiArrayView <N, T, StridedArrayTag> | |
| | | MultiArrayView <N, T, C>::permuteStridesDescending() const | |
| | | { | |
| | | difference_type ordering(strideOrdering(m_stride)), permutation; | |
| | | for(MultiArrayIndex k=0; k<N; ++k) | |
| | | permutation[ordering[N-1-k]] = k; | |
| | | return permuteDimensions(permutation); | |
| | | } | |
| | | | |
| | | template <unsigned int N, class T, class C> | |
| template <unsigned int M> | | template <unsigned int M> | |
| MultiArrayView <N-M, T, C> | | MultiArrayView <N-M, T, C> | |
| MultiArrayView <N, T, C>::bindOuter (const TinyVector <MultiArrayIndex, M>
&d) const | | MultiArrayView <N, T, C>::bindOuter (const TinyVector <MultiArrayIndex, 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) | |
| | | | |
| skipping to change at line 1562 | | skipping to change at line 1720 | |
| 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 C> | |
|
| | | MultiArrayView <N + 1, T, C> | |
| | | MultiArrayView <N, T, C>::insertSingletonDimension (difference_type_1 i) co | |
| | | nst | |
| | | { | |
| | | vigra_precondition ( | |
| | | 0 <= i && i <= static_cast <difference_type_1> (N), | |
| | | "MultiArrayView <N, T, C>::insertSingletonDimension(): index out of | |
| | | range."); | |
| | | TinyVector <MultiArrayIndex, N+1> shape, stride; | |
| | | 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_stride.begin (), m_stride.begin () + i, stride.begin ()); | |
| | | std::copy (m_stride.begin () + i, m_stride.end (), stride.begin () + i | |
| | | + 1); | |
| | | shape[i] = 1; | |
| | | stride[i] = 1; | |
| | | | |
| | | return MultiArrayView <N+1, T, C>(shape, stride, m_ptr); | |
| | | } | |
| | | | |
| | | template <unsigned int N, class T, class C> | |
| typename NormTraits<MultiArrayView <N, T, C> >::NormType | | typename NormTraits<MultiArrayView <N, T, C> >::NormType | |
| MultiArrayView <N, T, C>::norm(int type, bool useSquaredNorm) const | | MultiArrayView <N, T, C>::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(); | |
| | | | |
| skipping to change at line 1914 | | skipping to change at line 2090 | |
| | | | |
| /** init elements with a constant | | /** init elements with a constant | |
| */ | | */ | |
| template <class U> | | template <class U> | |
| MultiArray & init(const U & init) | | MultiArray & init(const U & init) | |
| { | | { | |
| view_type::init(init); | | view_type::init(init); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| /** change the shape and allocate new memory.<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, NumericTraits <T>::zero ()); | |
| } | | } | |
| | | | |
|
| /** change the shape, allocate new memory and initialize it | | /** Allocate new memory with the given shape and initialize it | |
| with the given value.<br> | | with the given value.<br> | |
| <em>Note:</em> this operation invalidates all dependent objects | | <em>Note:</em> this operation invalidates all dependent objects | |
| (array views and iterators) | | (array views and iterators) | |
| */ | | */ | |
| void reshape (const difference_type &shape, const_reference init); | | void reshape (const difference_type &shape, const_reference init); | |
| | | | |
| /** Swap the contents with another MultiArray. This is fast, | | /** Swap the contents with another MultiArray. This is fast, | |
| because no data are copied, but only pointers and shapes swappe
d. | | because no data are copied, but only pointers and shapes swappe
d. | |
| <em>Note:</em> this operation invalidates all dependent objects | | <em>Note:</em> this operation invalidates all dependent objects | |
| (array views and iterators) | | (array views and iterators) | |
| | | | |
| skipping to change at line 2255 | | skipping to change at line 2431 | |
| template <unsigned int N, class T, class C, class Accessor> | | template <unsigned int N, class T, class C, class Accessor> | |
| inline pair<typename MultiArrayView<N,T,C>::traverser, | | inline pair<typename MultiArrayView<N,T,C>::traverser, | |
| Accessor > | | Accessor > | |
| destMultiArray( MultiArrayView<N,T,C> & array, Accessor a ) | | destMultiArray( MultiArrayView<N,T,C> & array, Accessor a ) | |
| { | | { | |
| return pair<typename MultiArrayView<N,T,C>::traverser, | | return pair<typename MultiArrayView<N,T,C>::traverser, | |
| Accessor > | | Accessor > | |
| ( array.traverser_begin(), a ); | | ( array.traverser_begin(), a ); | |
| } | | } | |
| | | | |
|
| | | /********************************************************************/ | |
| | | | |
| | | template <class PixelType, class Accessor> | |
| | | inline triple<ConstStridedImageIterator<PixelType>, | |
| | | ConstStridedImageIterator<PixelType>, Accessor> | |
| | | srcImageRange(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Ac | |
| | | cessor a) | |
| | | { | |
| | | ConstStridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | return triple<ConstStridedImageIterator<PixelType>, | |
| | | ConstStridedImageIterator<PixelType>, | |
| | | Accessor>( | |
| | | ul, ul + Size2D(img.shape(0), img.shape(1)), a); | |
| | | } | |
| | | | |
| | | template <class PixelType, class Accessor> | |
| | | inline pair<ConstStridedImageIterator<PixelType>, Accessor> | |
| | | srcImage(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Accesso | |
| | | r a) | |
| | | { | |
| | | ConstStridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | return pair<ConstStridedImageIterator<PixelType>, Accessor> | |
| | | (ul, a); | |
| | | } | |
| | | | |
| | | template <class PixelType, class Accessor> | |
| | | inline triple<StridedImageIterator<PixelType>, | |
| | | StridedImageIterator<PixelType>, Accessor> | |
| | | destImageRange(MultiArrayView<2, PixelType, StridedArrayTag> & img, Accesso | |
| | | r a) | |
| | | { | |
| | | StridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | return triple<StridedImageIterator<PixelType>, | |
| | | StridedImageIterator<PixelType>, | |
| | | Accessor>( | |
| | | ul, ul + Size2D(img.shape(0), img.shape(1)), a); | |
| | | } | |
| | | | |
| | | template <class PixelType, class Accessor> | |
| | | inline pair<StridedImageIterator<PixelType>, Accessor> | |
| | | destImage(MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a) | |
| | | { | |
| | | StridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | return pair<StridedImageIterator<PixelType>, Accessor> | |
| | | (ul, a); | |
| | | } | |
| | | | |
| | | template <class PixelType, class Accessor> | |
| | | inline pair<StridedImageIterator<PixelType>, Accessor> | |
| | | maskImage(MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a) | |
| | | { | |
| | | StridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | return pair<StridedImageIterator<PixelType>, Accessor> | |
| | | (ul, a); | |
| | | } | |
| | | | |
| | | // ------------------------------------------------------------------- | |
| | | | |
| | | template <class PixelType> | |
| | | inline triple<ConstStridedImageIterator<PixelType>, | |
| | | ConstStridedImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_const_accessor> | |
| | | srcImageRange(MultiArrayView<2, PixelType, StridedArrayTag> const & img) | |
| | | { | |
| | | ConstStridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_const_accessor Acce | |
| | | ssor; | |
| | | return triple<ConstStridedImageIterator<PixelType>, | |
| | | ConstStridedImageIterator<PixelType>, | |
| | | Accessor> | |
| | | (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline triple<ConstImageIterator<PixelType>, | |
| | | ConstImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_const_accessor> | |
| | | srcImageRange(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img) | |
| | | { | |
| | | ConstImageIterator<PixelType> | |
| | | ul(img.data(), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_const_accessor Acce | |
| | | ssor; | |
| | | return triple<ConstImageIterator<PixelType>, | |
| | | ConstImageIterator<PixelType>, | |
| | | Accessor> | |
| | | (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline pair< ConstStridedImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_const_accessor> | |
| | | srcImage(MultiArrayView<2, PixelType, StridedArrayTag> const & img) | |
| | | { | |
| | | ConstStridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_const_accessor Acce | |
| | | ssor; | |
| | | return pair<ConstStridedImageIterator<PixelType>, | |
| | | Accessor> | |
| | | (ul, Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline pair< ConstImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_const_accessor> | |
| | | srcImage(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img) | |
| | | { | |
| | | ConstImageIterator<PixelType> | |
| | | ul(img.data(), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_const_accessor Acce | |
| | | ssor; | |
| | | return pair<ConstImageIterator<PixelType>, | |
| | | Accessor> | |
| | | (ul, Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline triple< StridedImageIterator<PixelType>, | |
| | | StridedImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_accessor> | |
| | | destImageRange(MultiArrayView<2, PixelType, StridedArrayTag> & img) | |
| | | { | |
| | | StridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_accessor Accessor; | |
| | | return triple<StridedImageIterator<PixelType>, | |
| | | StridedImageIterator<PixelType>, | |
| | | Accessor> | |
| | | (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline triple< ImageIterator<PixelType>, | |
| | | ImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_accessor> | |
| | | destImageRange(MultiArrayView<2, PixelType, UnstridedArrayTag> & img) | |
| | | { | |
| | | ImageIterator<PixelType> | |
| | | ul(img.data(), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_accessor Accessor; | |
| | | return triple<ImageIterator<PixelType>, | |
| | | ImageIterator<PixelType>, | |
| | | Accessor> | |
| | | (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline pair< StridedImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_accessor> | |
| | | destImage(MultiArrayView<2, PixelType, StridedArrayTag> & img) | |
| | | { | |
| | | StridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_accessor Accessor; | |
| | | return pair<StridedImageIterator<PixelType>, Accessor> | |
| | | (ul, Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline pair< ImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_accessor> | |
| | | destImage(MultiArrayView<2, PixelType, UnstridedArrayTag> & img) | |
| | | { | |
| | | ImageIterator<PixelType> ul(img.data(), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_accessor Accessor; | |
| | | return pair<ImageIterator<PixelType>, Accessor>(ul, Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline pair< ConstStridedImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_accessor> | |
| | | maskImage(MultiArrayView<2, PixelType, StridedArrayTag> const & img) | |
| | | { | |
| | | ConstStridedImageIterator<PixelType> | |
| | | ul(img.data(), 1, img.stride(0), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_accessor Accessor; | |
| | | return pair<ConstStridedImageIterator<PixelType>, Accessor> | |
| | | (ul, Accessor()); | |
| | | } | |
| | | | |
| | | template <class PixelType> | |
| | | inline pair< ConstImageIterator<PixelType>, | |
| | | typename AccessorTraits<PixelType>::default_accessor> | |
| | | maskImage(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img) | |
| | | { | |
| | | ConstImageIterator<PixelType> | |
| | | ul(img.data(), img.stride(1)); | |
| | | typedef typename AccessorTraits<PixelType>::default_accessor Accessor; | |
| | | return pair<ConstImageIterator<PixelType>, Accessor> | |
| | | (ul, Accessor()); | |
| | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* makeBasicImageView */ | | /* makeBasicImageView */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \addtogroup MultiArrayToImage Wrap a \ref vigra::MultiArrayView in | | /** \addtogroup MultiArrayToImage Wrap a \ref vigra::MultiArrayView in | |
| a \ref vigra::BasicImageView | | a \ref vigra::BasicImageView | |
| */ | | */ | |
| //@{ | | //@{ | |
| | | | |
| skipping to change at line 2317 | | skipping to change at line 2685 | |
| vigra_precondition ( | | vigra_precondition ( | |
| array.shape (0) == 3, "makeRGBImageView(): array.shape(0) must be 3
."); | | array.shape (0) == 3, "makeRGBImageView(): array.shape(0) must be 3
."); | |
| return BasicImageView <RGBValue<T> > ( | | return BasicImageView <RGBValue<T> > ( | |
| reinterpret_cast <RGBValue <T> *> (array.data ()), | | reinterpret_cast <RGBValue <T> *> (array.data ()), | |
| array.shape (1), array.shape (2)); | | array.shape (1), array.shape (2)); | |
| } | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
|
| | | #undef VIGRA_ASSERT_INSIDE | |
| #endif // VIGRA_MULTI_ARRAY_HXX | | #endif // VIGRA_MULTI_ARRAY_HXX | |
| | | | |
End of changes. 45 change blocks. |
| 43 lines changed or deleted | | 442 lines changed or added | |
|
| multi_convolution.hxx | | multi_convolution.hxx | |
| //-- -*- c++ -*- | | //-- -*- c++ -*- | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003 by Christian-Dennis Rahn */ | | /* Copyright 2003 by Christian-Dennis Rahn */ | |
| /* and Ullrich Koethe */ | | /* and Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 51 | | skipping to change at line 49 | |
| #define VIGRA_MULTI_CONVOLUTION_H | | #define VIGRA_MULTI_CONVOLUTION_H | |
| | | | |
| #include "separableconvolution.hxx" | | #include "separableconvolution.hxx" | |
| #include "array_vector.hxx" | | #include "array_vector.hxx" | |
| #include "multi_array.hxx" | | #include "multi_array.hxx" | |
| #include "accessor.hxx" | | #include "accessor.hxx" | |
| #include "numerictraits.hxx" | | #include "numerictraits.hxx" | |
| #include "navigator.hxx" | | #include "navigator.hxx" | |
| #include "metaprogramming.hxx" | | #include "metaprogramming.hxx" | |
| #include "multi_pointoperators.hxx" | | #include "multi_pointoperators.hxx" | |
|
| | | #include "functorexpression.hxx" | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
| namespace detail | | namespace detail | |
| { | | { | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* internalSeparableConvolveMultiArray */ | | /* internalSeparableConvolveMultiArray */ | |
| | | | |
| skipping to change at line 171 | | skipping to change at line 170 | |
| \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); | |
| | | | |
|
| // apply each kernel from the sequence `kernels | | // 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); | |
| } | | } | |
| \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); | |
| | | | |
|
| // apply each kernel from the sequence `kernels | | // 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); | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| skipping to change at line 371 | | skipping to change at line 370 | |
| 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 ); | | SNavigator snav( s, shape, dim ); | |
| DNavigator dnav( d, shape, dim ); | | DNavigator dnav( d, shape, 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_ac
cessor() ); | | tmp.begin(), typename AccessorTraits<TmpType>::default_accessor(
) ); | |
| | | | |
| convolveLine( srcIterRange( tmp.begin(), tmp.end(), typename Acces
sorTraits<TmpType>::default_const_accessor()), | | convolveLine( srcIterRange( tmp.begin(), tmp.end(), typename Acces
sorTraits<TmpType>::default_const_accessor()), | |
| destIter( dnav.begin(), dest ), | | destIter( dnav.begin(), dest ), | |
| kernel1d( kernel ) ); | | 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 | |
| | | | |
| skipping to change at line 444 | | skipping to change at line 443 | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/
multi_convolution.hxx</a>\> | | <b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/
multi_convolution.hxx</a>\> | |
| | | | |
| \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 | |
| | | | |
| \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, double sigma ) | |
| { | | { | |
|
| typedef typename NumericTraits<typename DestAccessor::value_type>::Real | | Kernel1D<double> gauss; | |
| Promote kernel_type; | | | |
| Kernel1D<kernel_type> gauss; | | | |
| gauss.initGaussian( sigma ); | | gauss.initGaussian( sigma ); | |
| | | | |
| separableConvolveMultiArray( s, shape, src, d, dest, gauss); | | separableConvolveMultiArray( s, shape, src, d, dest, gauss); | |
| } | | } | |
| | | | |
| 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, | |
| | | | |
| skipping to change at line 537 | | skipping to change at line 535 | |
| 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> Required Interface:</b> | | <b> Required Interface:</b> | |
| | | | |
|
| see \ref convolveImage(), 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, SrcAcce | | gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAcces | |
| ssor src, | | sor src, | |
| DestIterator di, DestAccessor dest, double sigma | | DestIterator di, DestAccessor dest, double sigma | |
| ) | | ) | |
| { | | { | |
| typedef typename DestAccessor::value_type DestType; | | typedef typename DestAccessor::value_type DestType; | |
|
| typedef typename NumericTraits<typename DestType::value_type>::RealProm | | typedef typename DestType::value_type DestValueType; | |
| ote kernel_type; | | typedef typename NumericTraits<DestValueType>::RealPromote KernelType; | |
| | | | |
|
| Kernel1D<kernel_type> gauss, derivative; | | static const int N = SrcShape::static_size; | |
| | | | |
| | | for(int k=0; k<N; ++k) | |
| | | if(shape[k] <=0) | |
| | | return; | |
| | | | |
| | | vigra_precondition(N == dest.size(di), | |
| | | "gaussianGradientMultiArray(): Wrong number of channels in output a | |
| | | rray."); | |
| | | | |
| | | vigra_precondition(sigma > 0.0, "gaussianGradientMultiArray(): Scale mu | |
| | | st be positive."); | |
| | | | |
| | | Kernel1D<KernelType> gauss, derivative; | |
| gauss.initGaussian(sigma); | | gauss.initGaussian(sigma); | |
|
| derivative.initGaussianDerivative(sigma, 1); | | | |
| | | | |
| typedef VectorElementAccessor<DestAccessor> ElementAccessor; | | typedef VectorElementAccessor<DestAccessor> ElementAccessor; | |
| | | | |
| // compute gradient components | | // compute gradient components | |
|
| for(unsigned int d = 0; d < shape.size(); ++d ) | | for(int d = 0; d < N; ++d ) | |
| { | | { | |
|
| ArrayVector<Kernel1D<kernel_type> > kernels(shape.size(), gauss); | | ArrayVector<Kernel1D<KernelType> > kernels(N, gauss); | |
| kernels[d] = derivative; | | kernels[d].initGaussianDerivative(sigma, 1); | |
| separableConvolveMultiArray( si, shape, src, di, ElementAccessor(d,
dest), kernels.begin()); | | separableConvolveMultiArray( si, shape, src, di, ElementAccessor(d,
dest), kernels.begin()); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline void | | inline void | |
| gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const
& source, | | gaussianGradientMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const
& source, | |
|
| pair<DestIterator, DestAccessor> const & dest, double sig
ma ) | | pair<DestIterator, DestAccessor> const & dest, d
ouble sigma ) | |
| { | | { | |
| gaussianGradientMultiArray( source.first, source.second, source.third, | | gaussianGradientMultiArray( source.first, source.second, source.third, | |
|
| dest.first, dest.second, sigma ); | | dest.first, dest.second, sigma ); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* symmetricGradientMultiArray */ | | /* symmetricGradientMultiArray */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Calculate gradient of a multi-dimensional arrays using symmetric
difference filters. | | /** \brief Calculate gradient of a multi-dimensional arrays using symmetric
difference filters. | |
| | | | |
| | | | |
| skipping to change at line 637 | | skipping to change at line 646 | |
| 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> Required Interface:</b> | | <b> Required Interface:</b> | |
| | | | |
|
| see \ref convolveImage(), 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) | |
| { | | { | |
| typedef typename DestAccessor::value_type DestType; | | typedef typename DestAccessor::value_type DestType; | |
|
| typedef typename NumericTraits<typename DestType::value_type>::RealProm | | typedef typename DestType::value_type DestValueType; | |
| ote kernel_type; | | typedef typename NumericTraits<DestValueType>::RealPromote KernelType; | |
| | | | |
|
| Kernel1D<kernel_type> filter; | | static const int N = SrcShape::static_size; | |
| | | | |
| | | for(int k=0; k<N; ++k) | |
| | | if(shape[k] <=0) | |
| | | return; | |
| | | | |
| | | vigra_precondition(N == dest.size(di), | |
| | | "symmetricGradientMultiArray(): Wrong number of channels in output | |
| | | array."); | |
| | | | |
| | | Kernel1D<KernelType> filter; | |
| filter.initSymmetricGradient(); | | filter.initSymmetricGradient(); | |
| | | | |
| typedef VectorElementAccessor<DestAccessor> ElementAccessor; | | typedef VectorElementAccessor<DestAccessor> ElementAccessor; | |
| | | | |
| // compute gradient components | | // compute gradient components | |
|
| for(unsigned int d = 0; d < shape.size(); ++d ) | | for(int d = 0; d < N; ++d ) | |
| { | | { | |
| convolveMultiArrayOneDimension(si, shape, src, | | convolveMultiArrayOneDimension(si, shape, src, | |
|
| di, ElementAccessor(d | | di, ElementAccessor(d, dest), | |
| , dest), | | d, filter); | |
| d, filter); | | | |
| } | | } | |
| } | | } | |
| | | | |
| 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 ) | |
| { | | { | |
| symmetricGradientMultiArray(source.first, source.second, source.third, | | symmetricGradientMultiArray(source.first, source.second, source.third, | |
| dest.first, dest.second); | | dest.first, dest.second); | |
| } | | } | |
| | | | |
|
| | | /********************************************************/ | |
| | | /* */ | |
| | | /* laplacianOfGaussianMultiArray */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | /** \brief Calculate Laplacian of a N-dimensional arrays using Gaussian der | |
| | | ivative filters. | |
| | | | |
| | | This function computes the Laplacian the given N-dimensional | |
| | | array with a sequence of second-derivative-of-Gaussian filters at the g | |
| | | iven | |
| | | standard deviation <tt>sigma</tt>. Both source and destination arrays | |
| | | 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 | |
| | | \ref separableConvolveMultiArray() with the appropriate kernels, follow | |
| | | ed by summation. | |
| | | | |
| | | <b> Declarations:</b> | |
| | | | |
| | | pass arguments explicitly: | |
| | | \code | |
| | | namespace vigra { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | laplacianOfGaussianMultiArray(SrcIterator siter, SrcShape const & s | |
| | | hape, SrcAccessor src, | |
| | | DestIterator diter, DestAccessor dest | |
| | | , | |
| | | double sigma); | |
| | | } | |
| | | \endcode | |
| | | | |
| | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| | | \code | |
| | | namespace vigra { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | laplacianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAcce | |
| | | ssor> const & source, | |
| | | pair<DestIterator, DestAccessor> cons | |
| | | t & dest, | |
| | | double sigma); | |
| | | } | |
| | | \endcode | |
| | | | |
| | | <b> Usage:</b> | |
| | | | |
| | | <b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ | |
| | | multi_convolution.hxx</a>\> | |
| | | | |
| | | \code | |
| | | MultiArray<3, float> source(shape); | |
| | | MultiArray<3, float> laplacian(shape); | |
| | | ... | |
| | | // compute Laplacian at scale sigma | |
| | | laplacianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArra | |
| | | y(laplacian), sigma); | |
| | | \endcode | |
| | | | |
| | | <b> Required Interface:</b> | |
| | | | |
| | | see \ref separableConvolveMultiArray(), in addition: | |
| | | | |
| | | \code | |
| | | int dimension = 0; | |
| | | VectorElementAccessor<DestAccessor> elementAccessor(0, dest); | |
| | | \endcode | |
| | | | |
| | | \see separableConvolveMultiArray() | |
| | | */ | |
| | | doxygen_overloaded_function(template <...> void laplacianOfGaussianMultiArr | |
| | | ay) | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAc | |
| | | cessor src, | |
| | | DestIterator di, DestAccessor dest, double si | |
| | | gma ) | |
| | | { | |
| | | using namespace functor; | |
| | | | |
| | | typedef typename DestAccessor::value_type DestType; | |
| | | typedef typename NumericTraits<DestType>::RealPromote KernelType; | |
| | | typedef typename AccessorTraits<KernelType>::default_accessor Derivativ | |
| | | eAccessor; | |
| | | | |
| | | static const int N = SrcShape::static_size; | |
| | | | |
| | | vigra_precondition(sigma > 0.0, "laplacianOfGaussianMultiArray(): Scale | |
| | | must be positive."); | |
| | | | |
| | | Kernel1D<KernelType> gauss; | |
| | | gauss.initGaussian(sigma); | |
| | | | |
| | | MultiArray<N, KernelType> derivative(shape); | |
| | | | |
| | | // compute 2nd derivatives and sum them up | |
| | | for(int d = 0; d < N; ++d ) | |
| | | { | |
| | | ArrayVector<Kernel1D<KernelType> > kernels(N, gauss); | |
| | | kernels[d].initGaussianDerivative(sigma, 2); | |
| | | if(d == 0) | |
| | | { | |
| | | separableConvolveMultiArray( si, shape, src, | |
| | | di, dest, kernels.begin()); | |
| | | } | |
| | | else | |
| | | { | |
| | | separableConvolveMultiArray( si, shape, src, | |
| | | derivative.traverser_begin(), Deri | |
| | | vativeAccessor(), | |
| | | kernels.begin()); | |
| | | combineTwoMultiArrays(di, shape, dest, derivative.traverser_beg | |
| | | in(), DerivativeAccessor(), | |
| | | di, dest, Arg1() + Arg2() ); | |
| | | } | |
| | | } | |
| | | } | |
| | | | |
| | | 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 ) | |
| | | { | |
| | | laplacianOfGaussianMultiArray( source.first, source.second, source.thir | |
| | | d, | |
| | | dest.first, dest.second, sigma ); | |
| | | } | |
| | | | |
| | | /********************************************************/ | |
| | | /* */ | |
| | | /* hessianOfGaussianMultiArray */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | /** \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 | |
| | | array with a sequence of second-derivative-of-Gaussian filters at the g | |
| | | iven | |
| | | standard deviation <tt>sigma</tt>. Both source and destination arrays | |
| | | 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 | |
| | | upper triangular part of the symmetric Hessian matrix). This function i | |
| | | s implemented by calls to | |
| | | \ref separableConvolveMultiArray() with the appropriate kernels. | |
| | | | |
| | | <b> Declarations:</b> | |
| | | | |
| | | pass arguments explicitly: | |
| | | \code | |
| | | namespace vigra { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | hessianOfGaussianMultiArray(SrcIterator siter, SrcShape const & sha | |
| | | pe, SrcAccessor src, | |
| | | DestIterator diter, DestAccessor dest, | |
| | | double sigma); | |
| | | } | |
| | | \endcode | |
| | | | |
| | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| | | \code | |
| | | namespace vigra { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | hessianOfGaussianMultiArray(triple<SrcIterator, SrcShape, SrcAccess | |
| | | or> const & source, | |
| | | pair<DestIterator, DestAccessor> const | |
| | | & dest, | |
| | | double sigma); | |
| | | } | |
| | | \endcode | |
| | | | |
| | | <b> Usage:</b> | |
| | | | |
| | | <b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ | |
| | | multi_convolution.hxx</a>\> | |
| | | | |
| | | \code | |
| | | MultiArray<3, float> source(shape); | |
| | | MultiArray<3, TinyVector<float, 6> > dest(shape); | |
| | | ... | |
| | | // compute Hessian at scale sigma | |
| | | hessianOfGaussianMultiArray(srcMultiArrayRange(source), destMultiArray( | |
| | | dest), sigma); | |
| | | \endcode | |
| | | | |
| | | <b> Required Interface:</b> | |
| | | | |
| | | see \ref separableConvolveMultiArray(), in addition: | |
| | | | |
| | | \code | |
| | | int dimension = 0; | |
| | | VectorElementAccessor<DestAccessor> elementAccessor(0, dest); | |
| | | \endcode | |
| | | | |
| | | \see separableConvolveMultiArray(), vectorToTensorMultiArray() | |
| | | */ | |
| | | doxygen_overloaded_function(template <...> void hessianOfGaussianMultiArray | |
| | | ) | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAcce | |
| | | ssor src, | |
| | | DestIterator di, DestAccessor dest, double sigm | |
| | | a ) | |
| | | { | |
| | | typedef typename DestAccessor::value_type DestType; | |
| | | typedef typename DestType::value_type DestValueType; | |
| | | typedef typename NumericTraits<DestValueType>::RealPromote KernelType; | |
| | | | |
| | | static const int N = SrcShape::static_size; | |
| | | static const int M = N*(N+1)/2; | |
| | | | |
| | | for(int k=0; k<N; ++k) | |
| | | if(shape[k] <=0) | |
| | | return; | |
| | | | |
| | | vigra_precondition(M == dest.size(di), | |
| | | "hessianOfGaussianMultiArray(): Wrong number of channels in output | |
| | | array."); | |
| | | | |
| | | vigra_precondition(sigma > 0.0, "hessianOfGaussianMultiArray(): Scale m | |
| | | ust be positive."); | |
| | | | |
| | | Kernel1D<KernelType> gauss; | |
| | | gauss.initGaussian(sigma); | |
| | | | |
| | | typedef VectorElementAccessor<DestAccessor> ElementAccessor; | |
| | | | |
| | | // compute elements of the Hessian matrix | |
| | | for(int b=0, i=0; i<N; ++i) | |
| | | { | |
| | | for(int j=i; j<N; ++j, ++b) | |
| | | { | |
| | | ArrayVector<Kernel1D<KernelType> > kernels(N, gauss); | |
| | | if(i == j) | |
| | | { | |
| | | kernels[i].initGaussianDerivative(sigma, 2); | |
| | | } | |
| | | else | |
| | | { | |
| | | kernels[i].initGaussianDerivative(sigma, 1); | |
| | | kernels[j].initGaussianDerivative(sigma, 1); | |
| | | } | |
| | | separableConvolveMultiArray(si, shape, src, di, ElementAccessor | |
| | | (b, dest), | |
| | | kernels.begin()); | |
| | | } | |
| | | } | |
| | | } | |
| | | | |
| | | 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 ) | |
| | | { | |
| | | hessianOfGaussianMultiArray( source.first, source.second, source.third, | |
| | | dest.first, dest.second, sigma ); | |
| | | } | |
| | | | |
| | | namespace detail { | |
| | | | |
| | | template<int N, class VectorType> | |
| | | struct StructurTensorFunctor | |
| | | { | |
| | | typedef VectorType result_type; | |
| | | typedef typename VectorType::value_type ValueType; | |
| | | | |
| | | template <class T> | |
| | | VectorType operator()(T const & in) const | |
| | | { | |
| | | VectorType res; | |
| | | for(int b=0, i=0; i<N; ++i) | |
| | | { | |
| | | for(int j=i; j<N; ++j, ++b) | |
| | | { | |
| | | res[b] = detail::RequiresExplicitCast<ValueType>::cast(in[i | |
| | | ]*in[j]); | |
| | | } | |
| | | } | |
| | | return res; | |
| | | } | |
| | | }; | |
| | | | |
| | | } // namespace detail | |
| | | | |
| | | /********************************************************/ | |
| | | /* */ | |
| | | /* structureTensorMultiArray */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | /** \brief Calculate th structure tensor of a multi-dimensional arrays. | |
| | | | |
| | | This function computes the gradient (outer product) tensor for each ele | |
| | | ment | |
| | | of the given N-dimensional array with first-derivative-of-Gaussian filt | |
| | | ers at | |
| | | 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 | |
| | | 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 | |
| | | 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. | |
| | | This function is implemented by calls to | |
| | | \ref separableConvolveMultiArray() with the appropriate kernels. | |
| | | | |
| | | <b> Declarations:</b> | |
| | | | |
| | | pass arguments explicitly: | |
| | | \code | |
| | | namespace vigra { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | structureTensorMultiArray(SrcIterator siter, SrcShape const & shape | |
| | | , SrcAccessor src, | |
| | | DestIterator diter, DestAccessor dest, | |
| | | double innerScale, double outerScale); | |
| | | } | |
| | | \endcode | |
| | | | |
| | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| | | \code | |
| | | namespace vigra { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor | |
| | | > const & source, | |
| | | pair<DestIterator, DestAccessor> const & | |
| | | dest, | |
| | | double innerScale, double outerScale); | |
| | | } | |
| | | \endcode | |
| | | | |
| | | <b> Usage:</b> | |
| | | | |
| | | <b>\#include</b> \<<a href="multi__convolution_8hxx-source.html">vigra/ | |
| | | multi_convolution.hxx</a>\> | |
| | | | |
| | | \code | |
| | | MultiArray<3, RGBValue<float> > source(shape); | |
| | | MultiArray<3, TinyVector<float, 6> > dest(shape); | |
| | | ... | |
| | | // compute structure tensor at scales innerScale and outerScale | |
| | | structureTensorMultiArray(srcMultiArrayRange(source), destMultiArray(de | |
| | | st), innerScale, outerScale); | |
| | | \endcode | |
| | | | |
| | | <b> Required Interface:</b> | |
| | | | |
| | | see \ref separableConvolveMultiArray(), in addition: | |
| | | | |
| | | \code | |
| | | int dimension = 0; | |
| | | VectorElementAccessor<DestAccessor> elementAccessor(0, dest); | |
| | | \endcode | |
| | | | |
| | | \see separableConvolveMultiArray(), vectorToTensorMultiArray() | |
| | | */ | |
| | | doxygen_overloaded_function(template <...> void structureTensorMultiArray) | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | void | |
| | | structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccess | |
| | | or src, | |
| | | DestIterator di, DestAccessor dest, | |
| | | double innerScale, double outerScale) | |
| | | { | |
| | | static const int N = SrcShape::static_size; | |
| | | static const int M = N*(N+1)/2; | |
| | | | |
| | | typedef typename DestAccessor::value_type DestType; | |
| | | typedef typename DestType::value_type DestValueType; | |
| | | typedef typename NumericTraits<DestValueType>::RealPromote KernelType; | |
| | | typedef TinyVector<KernelType, N> GradientVector; | |
| | | typedef typename AccessorTraits<GradientVector>::default_accessor Gradi | |
| | | entAccessor; | |
| | | | |
| | | for(int k=0; k<N; ++k) | |
| | | if(shape[k] <=0) | |
| | | return; | |
| | | | |
| | | vigra_precondition(M == dest.size(di), | |
| | | "structureTensorMultiArray(): Wrong number of channels in output ar | |
| | | ray."); | |
| | | | |
| | | vigra_precondition(innerScale > 0.0 && outerScale >= 0.0, | |
| | | "structureTensorMultiArray(): Scale must be positive."); | |
| | | | |
| | | MultiArray<N, GradientVector> gradient(shape); | |
| | | gaussianGradientMultiArray(si, shape, src, | |
| | | gradient.traverser_begin(), GradientAccessor | |
| | | (), | |
| | | innerScale); | |
| | | | |
| | | transformMultiArray(gradient.traverser_begin(), shape, GradientAccessor | |
| | | (), | |
| | | di, dest, | |
| | | detail::StructurTensorFunctor<N, DestType>()); | |
| | | | |
| | | gaussianSmoothMultiArray(di, shape, dest, di, dest, outerScale); | |
| | | } | |
| | | | |
| | | 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) | |
| | | { | |
| | | structureTensorMultiArray( source.first, source.second, source.third, | |
| | | dest.first, dest.second, innerScale, outerSc | |
| | | ale ); | |
| | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } //-- namespace vigra | | } //-- namespace vigra | |
| | | | |
| #endif //-- VIGRA_MULTI_CONVOLUTION_H | | #endif //-- VIGRA_MULTI_CONVOLUTION_H | |
| | | | |
End of changes. 25 change blocks. |
| 33 lines changed or deleted | | 499 lines changed or added | |
|
| multi_distance.hxx | | multi_distance.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ | | /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ | |
| /* and Ullrich Koethe */ | | /* and Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 59 | | skipping to change at line 57 | |
| #include "metaprogramming.hxx" | | #include "metaprogramming.hxx" | |
| #include "multi_pointoperators.hxx" | | #include "multi_pointoperators.hxx" | |
| #include "functorexpression.hxx" | | #include "functorexpression.hxx" | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
| namespace detail | | namespace detail | |
| { | | { | |
| | | | |
|
| | | template <class Value> | |
| | | struct DistParabolaStackEntry | |
| | | { | |
| | | double left, center, right; | |
| | | Value prevVal; | |
| | | | |
| | | DistParabolaStackEntry(Value const & p, double l, double c, double r) | |
| | | : left(l), center(c), right(r), prevVal(p) | |
| | | {} | |
| | | }; | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* distParabola */ | | /* distParabola */ | |
| /* */ | | /* */ | |
| /* Version with sigma (parabola spread) for morphology */ | | /* Version with sigma (parabola spread) for morphology */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor > | | class DestIterator, class DestAccessor > | |
| void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa, | | void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa, | |
|
| DestIterator id, DestAccessor da, float sigma
) | | DestIterator id, DestAccessor da, double sigma ) | |
| { | | { | |
| // We assume that the data in the input is distance squared and treat i
t as such | | // We assume that the data in the input is distance squared and treat i
t as such | |
|
| int w = iend - is; | | double w = iend - is; | |
| | | double sigma2 = sigma * sigma; | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Valu | | double sigma22 = 2.0 * sigma2; | |
| eType ValueType; | | | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Real | | | |
| Promote SumType; | | | |
| | | | |
| // Define the stack we use to determine the nearest background row | | | |
| // (from previous dimension), the items on the stack will separate this | | | |
| column into | | | |
| // separate regions of influence. Each region of influence is closest t | | | |
| o the same | | | |
| // background row from the previous dimension. | | | |
| typedef triple<int, ValueType, int> influence; | | | |
| std::vector<influence> _stack; | | | |
| | | | |
|
| SrcIterator ibegin = is; | | typedef typename SrcAccessor::value_type SrcType; | |
| _stack.push_back(influence(0, sa(is), w)); | | typedef DistParabolaStackEntry<SrcType> Influence; | |
| | | std::vector<Influence> _stack; | |
| | | _stack.push_back(Influence(sa(is), 0.0, 0.0, w)); | |
| | | | |
| ++is; | | ++is; | |
|
| int current = 1; | | double current = 1.0; | |
| | | while(current < w ) | |
| int y0, y1, y2, y_dash, delta_y; | | | |
| sigma = sigma * sigma; | | | |
| bool nosigma = closeAtTolerance( sigma, 1.0 ); | | | |
| | | | |
| y0 = 0; // The beginning of the influence of row y1 | | | |
| | | | |
| while( is != iend && current < w ) | | | |
| { | | { | |
|
| y1 = _stack.back().first; | | Influence & s = _stack.back(); | |
| y2 = current; | | double diff = current - s.center; | |
| delta_y = y2 - y1; | | double intersection = current + (sa(is) - s.prevVal - sigma2*sq(dif | |
| | | f)) / (sigma22 * diff); | |
| // If sigma is 1 (common case) avoid float multiplication here. | | | |
| if(nosigma) | | | |
| y_dash = (int)(sa(is) - _stack.back().second) - delta_y*delta_y | | | |
| ; | | | |
| else | | | |
| y_dash = (int)(sigma * (sa(is) - _stack.back().second)) - delta | | | |
| _y*delta_y; | | | |
| y_dash = y_dash / (delta_y + delta_y); | | | |
| y_dash += y2; | | | |
| | | | |
|
| if( y_dash > y0) | | if( intersection < s.left) // previous point has no influence | |
| { | | { | |
|
| if( y_dash <= w ) // CASE 2 -- A new region of influence | | _stack.pop_back(); | |
| | | if(_stack.empty()) | |
| { | | { | |
|
| y0 = y_dash; | | _stack.push_back(Influence(sa(is), 0.0, current, w)); | |
| | | | |
| _stack.back().third = y_dash; | | | |
| | | | |
| _stack.push_back(influence(current, sa(is), w)); | | | |
| } | | } | |
|
| | | | |
| // CASE 1 -- This parabola is never active | | | |
| ++is; | | | |
| ++current; | | | |
| continue; | | | |
| } | | | |
| else // CASE 3 -- Parabola shadows the previous one completely | | | |
| { | | | |
| _stack.pop_back(); | | | |
| | | | |
| if(_stack.size() < 2) | | | |
| y0=0; | | | |
| else | | else | |
|
| y0=_stack[_stack.size()-2].third; | | | |
| | | | |
| if(_stack.empty()) // This row influences all previous rows. | | | |
| { | | { | |
|
| _stack.push_back(influence(current, sa(is), w)); | | continue; // try new top of stack without advancing current | |
| | | | |
| ++is; | | | |
| ++current; | | | |
| continue; | | | |
| } | | } | |
| } | | } | |
|
| | | else if(intersection < s.right) | |
| | | { | |
| | | s.right = intersection; | |
| | | _stack.push_back(Influence(sa(is), intersection, current, w)); | |
| | | } | |
| | | ++is; | |
| | | ++current; | |
| } | | } | |
| | | | |
| // Now we have the stack indicating which rows are influenced by (and t
herefore | | // Now we have the stack indicating which rows are influenced by (and t
herefore | |
| // closest to) which row. We can go through the stack and calculate the | | // closest to) which row. We can go through the stack and calculate the | |
| // distance squared for each element of the column. | | // distance squared for each element of the column. | |
|
| | | typename std::vector<Influence>::iterator it = _stack.begin(); | |
| typename std::vector<influence>::iterator it = _stack.begin(); | | for(current = 0.0; current < w; ++current, ++id) | |
| | | | |
| ValueType distance = 0; // The distance squared | | | |
| current = 0; | | | |
| delta_y = 0; | | | |
| is = ibegin; | | | |
| | | | |
| for(; is != iend; ++current, ++id, ++is) | | | |
| { | | { | |
|
| // FIXME FIXME Bound checking incorrect here? vvv | | while( current >= it->right) | |
| if( current >= (*it).third && it != _stack.end()) ++it; | | ++it; | |
| | | da.set(sigma2 * sq(current - it->center) + it->prevVal, id); | |
| // FIXME FIXME The following check speeds things up for distance, b | | | |
| ut completely | | | |
| // messes up the grayscale morphology. Use an extra flag??? | | | |
| /* if( *is == 0 ) // Skip background pixels | | | |
| { | | | |
| *id = 0; | | | |
| continue; | | | |
| } | | | |
| */ | | | |
| delta_y = current - (*it).first; | | | |
| distance = delta_y * delta_y + (*it).second; | | | |
| *id = distance; | | | |
| } | | } | |
|
| | | | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline void distParabola(triple<SrcIterator, SrcIterator, SrcAccessor> src, | | inline void distParabola(triple<SrcIterator, SrcIterator, SrcAccessor> src, | |
|
| pair<DestIterator, DestAccessor> dest, float sigma
) | | pair<DestIterator, DestAccessor> dest, double sigm
a) | |
| { | | { | |
| distParabola(src.first, src.second, src.third, | | distParabola(src.first, src.second, src.third, | |
| dest.first, dest.second, sigma); | | dest.first, dest.second, sigma); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* internalSeparableMultiArrayDistTmp */ | | /* internalSeparableMultiArrayDistTmp */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
|
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor, class Array> | |
| void internalSeparableMultiArrayDistTmp( | | void internalSeparableMultiArrayDistTmp( | |
| SrcIterator si, SrcShape const & shape, SrcAccessor s
rc, | | SrcIterator si, SrcShape const & shape, SrcAccessor s
rc, | |
|
| DestIterator di, DestAccessor dest, float sigma, bool
invert) | | DestIterator di, DestAccessor dest, Array const & sig
mas, bool invert) | |
| { | | { | |
|
| // Sigma is the spread of the parabolas and is only used for ND morphol | | // Sigma is the spread of the parabolas. It determines the structuring | |
| ogy. When | | element size | |
| // calculating the distance transform, it is set to 1 | | // for ND morphology. When calculating the distance transforms, sigma i | |
| enum { N = 1 + SrcIterator::level }; | | s usually set to 1, | |
| | | // unless one wants to account for anisotropic pixel pitch | |
| | | enum { N = SrcShape::static_size}; | |
| | | | |
| // we need the Promote type here if we want to invert the image (dilati
on) | | // we need the Promote type here if we want to invert the image (dilati
on) | |
|
| typedef typename NumericTraits<typename DestAccessor::value_type>::Prom
ote TmpType; | | typedef typename NumericTraits<typename DestAccessor::value_type>::Real
Promote TmpType; | |
| | | | |
| // temporary array to hold the current line to enable in-place operatio
n | | // temporary array to hold the current line to enable in-place operatio
n | |
| ArrayVector<TmpType> tmp( shape[0] ); | | ArrayVector<TmpType> tmp( shape[0] ); | |
| | | | |
| typedef MultiArrayNavigator<SrcIterator, N> SNavigator; | | typedef MultiArrayNavigator<SrcIterator, N> SNavigator; | |
| typedef MultiArrayNavigator<DestIterator, N> DNavigator; | | typedef MultiArrayNavigator<DestIterator, N> DNavigator; | |
| | | | |
| // only operate on first dimension here | | // 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 ); | |
| | | | |
| skipping to change at line 232 | | skipping to change at line 187 | |
| if(invert) | | if(invert) | |
| transformLine( snav.begin(), snav.end(), src, tmp.begin(), | | transformLine( snav.begin(), snav.end(), src, tmp.begin(), | |
| typename AccessorTraits<TmpType>::default_ac
cessor(), | | typename AccessorTraits<TmpType>::default_ac
cessor(), | |
| Param(NumericTraits<TmpType>::zero())-Arg1()
); | | Param(NumericTraits<TmpType>::zero())-Arg1()
); | |
| else | | else | |
| copyLine( snav.begin(), snav.end(), src, tmp.begin(), | | copyLine( snav.begin(), snav.end(), src, tmp.begin(), | |
| typename AccessorTraits<TmpType>::default_accesso
r() ); | | typename AccessorTraits<TmpType>::default_accesso
r() ); | |
| | | | |
| detail::distParabola( srcIterRange(tmp.begin(), tmp.end(), | | detail::distParabola( srcIterRange(tmp.begin(), tmp.end(), | |
| typename AccessorTraits<TmpType>::default_const_a
ccessor()), | | typename AccessorTraits<TmpType>::default_const_a
ccessor()), | |
|
| destIter( dnav.begin(), dest ), sigma ); | | destIter( dnav.begin(), dest ), sigmas[0] ); | |
| } | | } | |
| | | | |
| // operate on further dimensions | | // operate on further dimensions | |
| for( int d = 1; d < N; ++d ) | | for( int d = 1; d < N; ++d ) | |
| { | | { | |
| 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 temp for maximum cache efficiency | |
| copyLine( dnav.begin(), dnav.end(), dest, | | copyLine( dnav.begin(), dnav.end(), dest, | |
| tmp.begin(), typename AccessorTraits<TmpType>::defau
lt_accessor() ); | | tmp.begin(), typename AccessorTraits<TmpType>::defau
lt_accessor() ); | |
| | | | |
| detail::distParabola( srcIterRange(tmp.begin(), tmp.end(), | | detail::distParabola( srcIterRange(tmp.begin(), tmp.end(), | |
| typename AccessorTraits<TmpType>::default_const_
accessor()), | | typename AccessorTraits<TmpType>::default_const_
accessor()), | |
|
| destIter( dnav.begin(), dest ), sigma ); | | destIter( dnav.begin(), dest ), sigmas[d] ); | |
| } | | } | |
| } | | } | |
| if(invert) transformMultiArray( di, shape, dest, di, dest, -Arg1()); | | if(invert) transformMultiArray( di, shape, dest, di, dest, -Arg1()); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
|
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor, class Array> | |
| inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape co
nst & shape, SrcAccessor src, | | inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape co
nst & shape, SrcAccessor src, | |
|
| DestIterator di, DestAccess
or dest, float sigma) | | DestIterator di, DestAccess
or dest, Array const & sigmas) | |
| { | | { | |
|
| internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigma, fa
lse ); | | internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigmas, f
alse ); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape co
nst & shape, SrcAccessor src, | | inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape co
nst & shape, SrcAccessor src, | |
| DestIterator di, DestAccess
or dest) | | DestIterator di, DestAccess
or dest) | |
| { | | { | |
|
| internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, 1, false | | ArrayVector<double> sigmas(shape.size(), 1.0); | |
| ); | | internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigmas, f | |
| | | alse ); | |
| } | | } | |
| | | | |
| } // namespace detail | | } // namespace detail | |
| | | | |
| /** \addtogroup MultiArrayDistanceTransform Euclidean distance transform fo
r multi-dimensional arrays. | | /** \addtogroup MultiArrayDistanceTransform Euclidean distance transform fo
r multi-dimensional arrays. | |
| | | | |
| These functions perform the Euclidean distance transform an arbitrary d
imensional | | These functions perform the Euclidean distance transform an arbitrary d
imensional | |
| 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 291 | | skipping to change at line 247 | |
| //@{ | | //@{ | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* separableMultiDistSquared */ | | /* separableMultiDistSquared */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Euclidean distance squared on multi-dimensional arrays. | | /** \brief Euclidean distance squared on multi-dimensional arrays. | |
| | | | |
|
| | | The algorithm is taken from Donald Bailey: "An Efficient Euclidean Dist | |
| | | ance Transform", | |
| | | Proc. IWCIA'04, Springer LNCS 3322, 2004. | |
| | | | |
| <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 | | // explicitly specify pixel pitch for each coordinate | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor, class Array> | |
| | | void | |
| | | separableMultiDistSquared( SrcIterator s, SrcShape const & shape, S | |
| | | rcAccessor src, | |
| | | DestIterator d, DestAccessor dest, | |
| | | bool background, | |
| | | Array const & pixelPitch); | |
| | | | |
| | | // use default pixel pitch = 1.0 for each coordinate | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| separableMultiDistSquared(SrcIterator siter, SrcShape const & shape
, SrcAccessor src, | | separableMultiDistSquared(SrcIterator siter, SrcShape const & shape
, SrcAccessor src, | |
|
| DestIterator diter, DestAccessor dest, | | DestIterator diter, DestAccessor dest, | |
| bool background); | | bool background); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
|
| | | // explicitly specify pixel pitch for each coordinate | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor, class Array> | |
| | | void | |
| | | separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAccesso | |
| | | r> const & source, | |
| | | pair<DestIterator, DestAccessor> const & | |
| | | dest, | |
| | | bool background, | |
| | | Array const & pixelPitch); | |
| | | | |
| | | // use default pixel pitch = 1.0 for each coordinate | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
|
| separableMultiDistance(triple<SrcIterator, SrcShape, SrcAccessor> c | | separableMultiDistSquared(triple<SrcIterator, SrcShape, SrcAccessor | |
| onst & source, | | > const & source, | |
| pair<DestIterator, DestAccessor> const | | pair<DestIterator, DestAccessor> const & | |
| & dest, | | dest, | |
| bool background); | | bool background); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
|
| This function performs a Euclidean distance squared transform on the gi
ven | | This function performs a squared Euclidean squared distance transform o
n the given | |
| multi-dimensional array. Both source and destination | | multi-dimensional array. Both source and destination | |
| arrays are represented by iterators, shape objects and accessors. | | arrays are represented by iterators, shape objects and accessors. | |
| The destination array is required to already have the correct size. | | The destination array is required to already have the correct size. | |
| | | | |
| This function expects a mask as its source, where background pixels are | | This function expects a mask as its source, where background pixels are | |
| marked as zero, and non-background pixels as non-zero. If the parameter | | marked as zero, and non-background pixels as non-zero. If the parameter | |
| <i>background</i> is true, then the squared distance of all background | | <i>background</i> is true, then the squared distance of all background | |
| pixels to the nearest object is calculated. Otherwise, the distance of
all | | pixels to the nearest object is calculated. Otherwise, the distance of
all | |
| object pixels to the nearest background pixel is calculated. | | object pixels to the nearest background pixel is calculated. | |
| | | | |
|
| | | Optionally, one can pass an array that specifies the pixel pitch in eac | |
| | | h direction. | |
| | | This is necessary when the data have non-uniform resolution (as is comm | |
| | | on in confocal | |
| | | microscopy, for example). | |
| | | | |
| This function may work in-place, which means that <tt>siter == diter</t
t> is allowed. | | This function may work in-place, which means that <tt>siter == diter</t
t> is allowed. | |
| A full-sized internal array is only allocated if working on the destina
tion | | A full-sized internal array is only allocated if working on the destina
tion | |
| array directly would cause overflow errors (i.e. if | | array directly would cause overflow errors (i.e. if | |
|
| <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M
is the | | <tt> NumericTraits<typename DestAccessor::value_type>::max() < N * M*M<
/tt>, where M is the | |
| size of the largest dimension of the array. | | size of the largest dimension of the array. | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="multi__distance_8hxx-source.html">vigra/mul
ti_distance.hxx</a>\> | | <b>\#include</b> \<<a href="multi__distance_8hxx-source.html">vigra/mul
ti_distance.hxx</a>\> | |
| | | | |
| \code | | \code | |
| MultiArray<3, unsigned char>::size_type shape(width, height, depth); | | MultiArray<3, unsigned char>::size_type shape(width, height, depth); | |
| MultiArray<3, unsigned char> source(shape); | | MultiArray<3, unsigned char> source(shape); | |
| MultiArray<3, unsigned int> dest(shape); | | MultiArray<3, unsigned int> dest(shape); | |
| ... | | ... | |
| | | | |
| // Calculate Euclidean distance squared for all background pixels | | // Calculate Euclidean distance squared for all background pixels | |
| separableMultiDistSquared(srcMultiArrayRange(source), destMultiArray(de
st), true); | | separableMultiDistSquared(srcMultiArrayRange(source), destMultiArray(de
st), true); | |
| \endcode | | \endcode | |
| | | | |
|
| \see vigra::distanceTransform() | | \see vigra::distanceTransform(), vigra::separableMultiDistance() | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void separableMultiDistSquared) | | doxygen_overloaded_function(template <...> void separableMultiDistSquared) | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
|
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor, class Array> | |
| void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA
ccessor src, | | void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA
ccessor src, | |
|
| DestIterator d, DestAccessor dest, bool bac | | DestIterator d, DestAccessor dest, bool bac | |
| kground) | | kground, | |
| | | Array const & pixelPitch) | |
| { | | { | |
|
| typedef typename NumericTraits<typename DestAccessor::value_type>::Valu | | int N = shape.size(); | |
| eType DestType; | | | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Prom | | | |
| ote TmpType; | | | |
| DestType MaxValue = NumericTraits<DestType>::max(); | | | |
| enum { N = 1 + SrcIterator::level }; | | | |
| | | | |
|
| int MaxDim = 0; | | typedef typename SrcAccessor::value_type SrcType; | |
| for( int i=0; i<N; i++) | | typedef typename DestAccessor::value_type DestType; | |
| if(MaxDim < shape[i]) MaxDim = shape[i]; | | typedef typename NumericTraits<DestType>::RealPromote Real; | |
| int MaxDist = MaxDim*MaxDim; | | | |
| | | SrcType zero = NumericTraits<SrcType>::zero(); | |
| | | | |
| | | double dmax = 0.0; | |
| | | bool pixelPitchIsReal = false; | |
| | | for( int k=0; k<N; ++k) | |
| | | { | |
| | | if(int(pixelPitch[k]) != pixelPitch[k]) | |
| | | pixelPitchIsReal = true; | |
| | | dmax += sq(pixelPitch[k]*shape[k]); | |
| | | } | |
| | | | |
| using namespace vigra::functor; | | using namespace vigra::functor; | |
| | | | |
|
| if(N*MaxDim*MaxDim > MaxValue) // need a temporary array to avoid overf | | if(dmax > NumericTraits<DestType>::toRealPromote(NumericTraits<DestType | |
| lows | | >::max()) | |
| | | || pixelPitchIsReal) // need a temporary array to avoid overflows | |
| { | | { | |
| // Threshold the values so all objects have infinity value in the b
eginning | | // Threshold the values so all objects have infinity value in the b
eginning | |
|
| MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | | Real maxDist = (Real)dmax, rzero = (Real)0.0; | |
| | | MultiArray<SrcShape::static_size, Real> tmpArray(shape); | |
| if(background == true) | | if(background == true) | |
|
| transformMultiArray( s, shape, src, tmpArray.traverser_begin(), | | transformMultiArray( s, shape, src, | |
| typename AccessorTraits<TmpType>::default_ | | tmpArray.traverser_begin(), typename Acces | |
| accessor(), | | sorTraits<Real>::default_accessor(), | |
| ifThenElse( Arg1() == Param(0), Param(MaxD | | ifThenElse( Arg1() == Param(zero), Param(m | |
| ist), Param(0) )); | | axDist), Param(rzero) )); | |
| else | | else | |
|
| transformMultiArray( s, shape, src, tmpArray.traverser_begin(), | | transformMultiArray( s, shape, src, | |
| typename AccessorTraits<TmpType>::default_ | | tmpArray.traverser_begin(), typename Acces | |
| accessor(), | | sorTraits<Real>::default_accessor(), | |
| ifThenElse( Arg1() != Param(0), Param(MaxD | | ifThenElse( Arg1() != Param(zero), Param(m | |
| ist), Param(0) )); | | axDist), Param(rzero) )); | |
| | | | |
| detail::internalSeparableMultiArrayDistTmp( tmpArray.traverser_begi
n(), | | detail::internalSeparableMultiArrayDistTmp( tmpArray.traverser_begi
n(), | |
|
| shape, typename AccessorTraits<TmpType>::default_accessor()
, | | shape, typename AccessorTraits<Real>::default_accessor(), | |
| tmpArray.traverser_begin(), | | tmpArray.traverser_begin(), | |
|
| typename AccessorTraits<TmpType>::default_accessor()); | | typename AccessorTraits<Real>::default_accessor(), pixelPit | |
| | | ch); | |
| //copyMultiArray(srcMultiArrayRange(tmpArray), destIter(d, dest)); | | | |
| transformMultiArray( tmpArray.traverser_begin(), shape, | | | |
| typename AccessorTraits<TmpType>::default_acce | | | |
| ssor(), d, dest, | | | |
| ifThenElse( Arg1() > Param(MaxValue), Param(Ma | | | |
| xValue), Arg1() ) ); | | | |
| | | | |
|
| | | copyMultiArray(srcMultiArrayRange(tmpArray), destIter(d, dest)); | |
| } | | } | |
| else // work directly on the destination array | | else // work directly on the destination array | |
| { | | { | |
| // Threshold the values so all objects have infinity value in the b
eginning | | // Threshold the values so all objects have infinity value in the b
eginning | |
|
| | | DestType maxDist = DestType(std::ceil(dmax)), rzero = (DestType)0; | |
| if(background == true) | | if(background == true) | |
| transformMultiArray( s, shape, src, d, dest, | | transformMultiArray( s, shape, src, d, dest, | |
|
| ifThenElse( Arg1() == Param(0), Param(MaxD
ist), Param(0) )); | | ifThenElse( Arg1() == Param(zero), Param(m
axDist), Param(rzero) )); | |
| else | | else | |
| transformMultiArray( s, shape, src, d, dest, | | transformMultiArray( s, shape, src, d, dest, | |
|
| ifThenElse( Arg1() != Param(0), Param(MaxD
ist), Param(0) )); | | ifThenElse( Arg1() != Param(zero), Param(m
axDist), Param(rzero) )); | |
| | | | |
|
| detail::internalSeparableMultiArrayDistTmp( d, shape, dest, d, dest
); | | detail::internalSeparableMultiArrayDistTmp( d, shape, dest, d, dest
, pixelPitch); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
|
| | | class DestIterator, class DestAccessor, class Array> | |
| | | inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc | |
| | | essor> const & source, | |
| | | pair<DestIterator, DestAccessor> con | |
| | | st & dest, bool background, | |
| | | Array const & pixelPitch) | |
| | | { | |
| | | separableMultiDistSquared( source.first, source.second, source.third, | |
| | | dest.first, dest.second, background, pixelPi | |
| | | tch ); | |
| | | } | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | inline | |
| | | void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcA | |
| | | ccessor src, | |
| | | DestIterator d, DestAccessor dest, bool bac | |
| | | kground) | |
| | | { | |
| | | ArrayVector<double> pixelPitch(shape.size(), 1.0); | |
| | | separableMultiDistSquared( s, shape, src, d, dest, background, pixelPit | |
| | | ch ); | |
| | | } | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc
essor> const & source, | | inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAcc
essor> const & source, | |
| pair<DestIterator, DestAccessor> con
st & dest, bool background) | | pair<DestIterator, DestAccessor> con
st & dest, bool background) | |
| { | | { | |
| separableMultiDistSquared( source.first, source.second, source.third, | | separableMultiDistSquared( source.first, source.second, source.third, | |
| dest.first, dest.second, background ); | | dest.first, dest.second, background ); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| | | | |
| skipping to change at line 431 | | skipping to change at line 441 | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Euclidean distance on multi-dimensional arrays. | | /** \brief Euclidean distance on multi-dimensional arrays. | |
| | | | |
| <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 | | // explicitly specify pixel pitch for each coordinate | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor, class Array> | |
| | | void | |
| | | separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcA | |
| | | ccessor src, | |
| | | DestIterator d, DestAccessor dest, | |
| | | bool background, | |
| | | Array const & pixelPitch); | |
| | | | |
| | | // use default pixel pitch = 1.0 for each coordinate | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| separableMultiDistance(SrcIterator siter, SrcShape const & shape, S
rcAccessor src, | | separableMultiDistance(SrcIterator siter, SrcShape const & shape, S
rcAccessor src, | |
|
| DestIterator diter, DestAccessor dest, | | DestIterator diter, DestAccessor dest, | |
| bool background); | | bool background); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
|
| | | // explicitly specify pixel pitch for each coordinate | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor, class Array> | |
| | | void | |
| | | separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccessor> | |
| | | const & source, | |
| | | pair<DestIterator, DestAccessor> const & de | |
| | | st, | |
| | | bool background, | |
| | | Array const & pixelPitch); | |
| | | | |
| | | // use default pixel pitch = 1.0 for each coordinate | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| separableMultiDistance(triple<SrcIterator, SrcShape, SrcAccessor> c
onst & source, | | separableMultiDistance(triple<SrcIterator, SrcShape, SrcAccessor> c
onst & source, | |
|
| pair<DestIterator, DestAccessor> const | | pair<DestIterator, DestAccessor> const & des | |
| & dest, | | t, | |
| bool background); | | bool background); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| This function performs a Euclidean distance transform on the given | | This function performs a Euclidean distance transform on the given | |
|
| multi-dimensional array. Both source and destination | | multi-dimensional array. It simply calls \ref separableMultiDistSquared | |
| arrays are represented by iterators, shape objects and accessors. | | () | |
| The destination array is required to already have the correct size. | | and takes the pixel-wise square root of the result. See \ref separableM | |
| | | ultiDistSquared() | |
| This function expects a mask as its source, where background pixels are | | for more documentation. | |
| marked as zero, and non-background pixels as non-zero. If the parameter | | | |
| <i>background</i> is true, then the squared distance of all background | | | |
| pixels to the nearest object is calculated. Otherwise, the distance of | | | |
| all | | | |
| object pixels to the nearest background pixel is calculated. | | | |
| | | | |
| 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 | | | |
| array directly would cause overflow errors (i.e. if | | | |
| <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M | | | |
| is the | | | |
| size of the largest dimension of the array. | | | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="multi__distance_8hxx-source.html">vigra/mul
ti_distance.hxx</a>\> | | <b>\#include</b> \<<a href="multi__distance_8hxx-source.html">vigra/mul
ti_distance.hxx</a>\> | |
| | | | |
| \code | | \code | |
| MultiArray<3, unsigned char>::size_type shape(width, height, depth); | | MultiArray<3, unsigned char>::size_type shape(width, height, depth); | |
| MultiArray<3, unsigned char> source(shape); | | MultiArray<3, unsigned char> source(shape); | |
|
| MultiArray<3, unsigned float> dest(shape); | | MultiArray<3, float> dest(shape); | |
| ... | | ... | |
| | | | |
| // Calculate Euclidean distance squared for all background pixels | | // Calculate Euclidean distance squared for all background pixels | |
| separableMultiDistance(srcMultiArrayRange(source), destMultiArray(dest)
, true); | | separableMultiDistance(srcMultiArrayRange(source), destMultiArray(dest)
, true); | |
| \endcode | | \endcode | |
| | | | |
|
| \see vigra::distanceTransform() | | \see vigra::distanceTransform(), vigra::separableMultiDistSquared() | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void separableMultiDistance) | | doxygen_overloaded_function(template <...> void separableMultiDistance) | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
|
| | | class DestIterator, class DestAccessor, class Array> | |
| | | void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAcce | |
| | | ssor src, | |
| | | DestIterator d, DestAccessor dest, bool backgr | |
| | | ound, | |
| | | Array const & pixelPitch) | |
| | | { | |
| | | separableMultiDistSquared( s, shape, src, d, dest, background, pixelPit | |
| | | ch); | |
| | | | |
| | | // Finally, calculate the square root of the distances | |
| | | using namespace vigra::functor; | |
| | | | |
| | | transformMultiArray( d, shape, dest, d, dest, sqrt(Arg1()) ); | |
| | | } | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAcce
ssor src, | | void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAcce
ssor src, | |
| DestIterator d, DestAccessor dest, bool backgr
ound) | | DestIterator d, DestAccessor dest, bool backgr
ound) | |
| { | | { | |
| separableMultiDistSquared( s, shape, src, d, dest, background); | | separableMultiDistSquared( s, shape, src, d, dest, background); | |
| | | | |
| // Finally, calculate the square root of the distances | | // Finally, calculate the square root of the distances | |
|
| transformMultiArray( d, shape, dest, d, dest, (double(*)(double))&std:: | | using namespace vigra::functor; | |
| sqrt ); | | | |
| | | transformMultiArray( d, shape, dest, d, dest, sqrt(Arg1()) ); | |
| | | } | |
| | | | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor, class Array> | |
| | | inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccess | |
| | | or> const & source, | |
| | | pair<DestIterator, DestAccessor> const | |
| | | & dest, bool background, | |
| | | Array const & pixelPitch) | |
| | | { | |
| | | separableMultiDistance( source.first, source.second, source.third, | |
| | | dest.first, dest.second, background, pixelPitch | |
| | | ); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccess
or> const & source, | | inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccess
or> const & source, | |
| pair<DestIterator, DestAccessor> const
& dest, bool background) | | pair<DestIterator, DestAccessor> const
& dest, bool background) | |
| { | | { | |
| separableMultiDistance( source.first, source.second, source.third, | | separableMultiDistance( source.first, source.second, source.third, | |
| dest.first, dest.second, background ); | | dest.first, dest.second, background ); | |
| } | | } | |
| | | | |
End of changes. 64 change blocks. |
| 188 lines changed or deleted | | 240 lines changed or added | |
|
| multi_impex.hxx | | multi_impex.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003 by Gunnar Kedenburg */ | | /* Copyright 2003 by Gunnar Kedenburg */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 62 | | skipping to change at line 60 | |
| #include "multi_pointoperators.hxx" | | #include "multi_pointoperators.hxx" | |
| | | | |
| #ifdef _MSC_VER | | #ifdef _MSC_VER | |
| # include <direct.h> | | # include <direct.h> | |
| #else | | #else | |
| # include <unistd.h> | | # include <unistd.h> | |
| #endif | | #endif | |
| | | | |
| namespace vigra { | | namespace vigra { | |
| | | | |
|
| | | /** \addtogroup VolumeImpex Import/export of volume data. | |
| | | */ | |
| | | | |
| | | //@{ | |
| | | | |
| | | /** \brief Argument object for the function importVolume(). | |
| | | | |
| | | See \ref importVolume() for usage example. This object can be used | |
| | | to define the properties of a volume data set to be read from disk. | |
| | | Sorry, no \ref detailedDocumentation() available yet. | |
| | | | |
| | | <b>\#include</b> \<<a href="imageinfo_8hxx-source.html">vigra/multi_imp | |
| | | ex.hxx</a>\><br> | |
| | | Namespace: vigra | |
| | | **/ | |
| class VolumeImportInfo | | class VolumeImportInfo | |
| { | | { | |
| public: | | public: | |
| typedef ImageImportInfo::PixelType PixelType; | | typedef ImageImportInfo::PixelType PixelType; | |
| | | | |
| /// type of volume size returned by shape() | | /// type of volume size returned by shape() | |
| typedef MultiArrayShape<3>::type ShapeType; | | typedef MultiArrayShape<3>::type ShapeType; | |
| | | | |
| /// provided for backwards-compatibility (deprecated) | | /// provided for backwards-compatibility (deprecated) | |
| typedef ShapeType size_type; | | typedef ShapeType size_type; | |
| | | | |
| /// 3D resolution type returned by resolution() | | /// 3D resolution type returned by resolution() | |
| typedef TinyVector<float, 3> Resolution; | | typedef TinyVector<float, 3> Resolution; | |
| | | | |
| VIGRA_EXPORT VolumeImportInfo(const std::string &filename); | | VIGRA_EXPORT VolumeImportInfo(const std::string &filename); | |
| VIGRA_EXPORT VolumeImportInfo(const std::string &baseName, const std::s
tring &extension); | | VIGRA_EXPORT VolumeImportInfo(const std::string &baseName, const std::s
tring &extension); | |
| | | | |
|
| VIGRA_EXPORT ShapeType shape() const { return shape_; } | | VIGRA_EXPORT ShapeType shape() const; | |
| | | | |
| | | /** Get width of the volume. | |
| | | **/ | |
| | | VIGRA_EXPORT MultiArrayIndex width() const; | |
| | | | |
| | | /** Get height of the volume. | |
| | | **/ | |
| | | VIGRA_EXPORT MultiArrayIndex height() const; | |
| | | | |
| | | /** Get depth of the volume. | |
| | | **/ | |
| | | VIGRA_EXPORT MultiArrayIndex depth() const; | |
| | | | |
| /** | | /** | |
| * resolution() contains the alignment and resolution of the | | * resolution() contains the alignment and resolution of the | |
| * volume. resolution()[0] is the x increment in a left-handed | | * volume. resolution()[0] is the x increment in a left-handed | |
| * world coordinate system of one unstrided step in the volume | | * world coordinate system of one unstrided step in the volume | |
| * memory. The [1] and [2] elements contain the y resp. z | | * memory. The [1] and [2] elements contain the y resp. z | |
| * increments of the strided row resp. slice steps in the | | * increments of the strided row resp. slice steps in the | |
| * volume. | | * volume. | |
| * | | * | |
| * EXAMPLES: (1.f, 1.f, 4.f) means that the slices are four | | * EXAMPLES: (1.f, 1.f, 4.f) means that the slices are four | |
| * times thicker than the x/y resolution. | | * times thicker than the x/y resolution. | |
| * (1.f, -1.f, 1.f) means that the volume coordinate system is | | * (1.f, -1.f, 1.f) means that the volume coordinate system is | |
| * right-handed. | | * right-handed. | |
| */ | | */ | |
|
| VIGRA_EXPORT Resolution resolution() const { return resolution_; } | | VIGRA_EXPORT Resolution resolution() const; | |
| | | | |
|
| VIGRA_EXPORT PixelType pixelType() const { return pixelType_; } | | /** Query the pixel type of the image. | |
| | | | |
|
| VIGRA_EXPORT int numBands() const { return numBands_; } | | Possible values are: | |
| VIGRA_EXPORT bool isGrayscale() const { return numBands_ == 1; } | | <DL> | |
| VIGRA_EXPORT bool isColor() const { return numBands_ > 1; } | | <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) | |
| | | <DT>"INT16"<DD> 16-bit signed integer (short) | |
| | | <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short) | |
| | | <DT>"INT32"<DD> 32-bit signed integer (long) | |
| | | <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long) | |
| | | <DT>"FLOAT"<DD> 32-bit floating point (float) | |
| | | <DT>"DOUBLE"<DD> 64-bit floating point (double) | |
| | | </DL> | |
| | | **/ | |
| | | VIGRA_EXPORT const char * getPixelType() const; | |
| | | | |
| | | /** Query the pixel type of the image. | |
| | | | |
| | | Same as getPixelType(), but the result is returned as a | |
| | | ImageImportInfo::PixelType enum. This is useful to implement | |
| | | a switch() on the pixel type. | |
| | | | |
| | | Possible values are: | |
| | | <DL> | |
| | | <DT>UINT8<DD> 8-bit unsigned integer (unsigned char) | |
| | | <DT>INT16<DD> 16-bit signed integer (short) | |
| | | <DT>UINT16<DD> 16-bit unsigned integer (unsigned short) | |
| | | <DT>INT32<DD> 32-bit signed integer (long) | |
| | | <DT>UINT32<DD> 32-bit unsigned integer (unsigned long) | |
| | | <DT>FLOAT<DD> 32-bit floating point (float) | |
| | | <DT>DOUBLE<DD> 64-bit floating point (double) | |
| | | </DL> | |
| | | **/ | |
| | | VIGRA_EXPORT PixelType pixelType() const; | |
| | | | |
| | | VIGRA_EXPORT MultiArrayIndex numBands() const; | |
| | | VIGRA_EXPORT bool isGrayscale() const; | |
| | | VIGRA_EXPORT bool isColor() const; | |
| | | | |
| // get base file name without path, image index, and extension | | // get base file name without path, image index, and extension | |
|
| VIGRA_EXPORT const std::string &name() const { return name_; } | | VIGRA_EXPORT const std::string &name() const; | |
| | | | |
|
| VIGRA_EXPORT const std::string &description() const { return descriptio
n_; } | | VIGRA_EXPORT const std::string &description() const; | |
| | | | |
|
| template <class T, class Allocator> | | template <class T, class Stride> | |
| void importImpl(MultiArray <3, T, Allocator> &volume) const; | | void importImpl(MultiArrayView <3, T, Stride> &volume) const; | |
| | | | |
| protected: | | protected: | |
| void getVolumeInfoFromFirstSlice(const std::string &filename); | | void getVolumeInfoFromFirstSlice(const std::string &filename); | |
| | | | |
| size_type shape_; | | size_type shape_; | |
| Resolution resolution_; | | Resolution resolution_; | |
|
| PixelType pixelType_; | | //PixelType pixelType_; | |
| int numBands_; | | int numBands_; | |
| | | | |
|
| std::string path_, name_, description_; | | std::string path_, name_, description_, pixelType_; | |
| | | | |
| std::string rawFilename_; | | std::string rawFilename_; | |
| std::string baseName_, extension_; | | std::string baseName_, extension_; | |
| std::vector<std::string> numbers_; | | std::vector<std::string> numbers_; | |
| }; | | }; | |
| | | | |
|
| template <class T, class Allocator> | | /********************************************************/ | |
| void VolumeImportInfo::importImpl(MultiArray <3, T, Allocator> &volume) con | | /* */ | |
| st | | /* VolumeExportInfo */ | |
| | | /* */ | |
| | | /********************************************************/ | |
| | | | |
| | | /** \brief Argument object for the function exportVolume(). | |
| | | | |
| | | See \ref exportVolume() for usage example. This object must be used | |
| | | to define the properties of a volume to be written to disk. | |
| | | | |
| | | <b>\#include</b> \<<a href="imageinfo_8hxx-source.html">vigra/imageinfo | |
| | | .hxx</a>\><br> | |
| | | Namespace: vigra | |
| | | **/ | |
| | | class VolumeExportInfo | |
| { | | { | |
|
| volume.reshape(this->shape()); | | public: | |
| | | /** Construct VolumeExportInfo object. | |
| | | | |
| | | The volume will be stored in a by-slice manner, where the numbe | |
| | | r of slices | |
| | | equals the depth of the volume. The file names will be enumerat | |
| | | ed like | |
| | | <tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext | |
| | | </tt> etc. | |
| | | (the actual number of zeros depends on the depth). If the targe | |
| | | t image type | |
| | | does not support the source voxel type, all slices will be mapp | |
| | | ed | |
| | | simultaneously to the appropriate target range. | |
| | | The file type will be guessed from the extension unless overrid | |
| | | den | |
| | | by \ref setFileType(). Recognized extensions: '.bmp', '.gif', | |
| | | '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', | |
| | | '.ras', | |
| | | '.tif', '.tiff', '.xv', '.hdr'. | |
| | | JPEG support requires libjpeg, PNG support requires libpng, and | |
| | | TIFF support requires libtiff. | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo( const char * name_base, const char * nam | |
| | | e_ext ); | |
| | | VIGRA_EXPORT ~VolumeExportInfo(); | |
| | | | |
| | | /** Set volume file name base. | |
| | | | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setFileNameBase(const char * name_base) | |
| | | ; | |
| | | /** Set volume file name extension. | |
| | | | |
| | | The file type will be guessed from the extension unless overrid | |
| | | den | |
| | | by \ref setFileType(). Recognized extensions: '.bmp', '.gif', | |
| | | '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', | |
| | | '.ras', | |
| | | '.tif', '.tiff', '.xv', '.hdr'. | |
| | | JPEG support requires libjpeg, PNG support requires libpng, and | |
| | | TIFF support requires libtiff. | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setFileNameExt(const char * name_ext); | |
| | | VIGRA_EXPORT const char * getFileNameBase() const; | |
| | | VIGRA_EXPORT const char * getFileNameExt() const; | |
| | | | |
| | | /** Store volume as given file type. | |
| | | | |
| | | This will override any type guessed | |
| | | from the file name's extension. Recognized file types: | |
| | | | |
| | | <DL> | |
| | | <DT>"BMP"<DD> Microsoft Windows bitmap image file. | |
| | | <DT>"GIF"<DD> CompuServe graphics interchange format; 8-bit col | |
| | | or. | |
| | | <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). | |
| | | <DT>"PBM"<DD> Portable bitmap format (black and white). | |
| | | <DT>"PGM"<DD> Portable graymap format (gray scale). | |
| | | <DT>"PNM"<DD> Portable anymap. | |
| | | <DT>"PPM"<DD> Portable pixmap format (color). | |
| | | <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> | |
| | | | |
| | | 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 | |
| | | pixel. | |
| | | | |
| | | PNG can store UInt8 and UInt16 values, and supports 1 and 3 cha | |
| | | nnel | |
| | | images. One additional alpha channel is also supported. | |
| | | | |
| | | PNM can store 1 and 3 channel images with UInt8, UInt16 and UIn | |
| | | t32 | |
| | | values in each channel. | |
| | | | |
| | | TIFF and VIFF are aditionally able to store short and long | |
| | | integers (2 or 4 bytes) and real values (32 bit float and | |
| | | 64 bit double) without conversion. So you will need to use | |
| | | TIFF or VIFF if you need to store images with high | |
| | | accuracy (the appropriate type to write is automatically | |
| | | derived from the image type to be exported). However, many | |
| | | other programs using TIFF (e.g. ImageMagick) have not | |
| | | implemented support for those pixel types. So don't be | |
| | | surprised if the generated TIFF is not readable in some | |
| | | cases. If this happens, export the image as 'unsigned | |
| | | char' or 'RGBValue\<unsigned char\>' by calling | |
| | | \ref ImageExportInfo::setPixelType(). | |
| | | | |
| | | Support to reading and writing ICC color profiles is | |
| | | provided for TIFF, JPEG, and PNG images. | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setFileType( const char * ); | |
| | | VIGRA_EXPORT const char * getFileType() const; | |
| | | | |
| | | /** Set compression type. | |
| | | | |
| | | Recognized strings: "" (no compression), "LZW", | |
| | | "RunLength", "1" ... "100". A number is interpreted as the | |
| | | compression quality for JPEG compression. JPEG compression is | |
| | | supported by the JPEG and TIFF formats. "LZW" is only available | |
| | | if libtiff was installed with LZW enabled. By default, libtiff | |
| | | came | |
| | | with LZW disabled due to Unisys patent enforcement. In this cas | |
| | | e, | |
| | | VIGRA stores the image uncompressed. | |
| | | | |
| | | Valid Compression for TIFF files: | |
| | | JPEG jpeg compression, call setQuality as well! | |
| | | RLE runlength compression | |
| | | LZW lzw compression | |
| | | DEFLATE deflate compression | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setCompression( const char * ); | |
| | | VIGRA_EXPORT const char * getCompression() const; | |
| | | | |
| | | /** Set the pixel type of the volume file(s). Possible values are: | |
| | | <DL> | |
| | | <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) | |
| | | <DT>"INT16"<DD> 16-bit signed integer (short) | |
| | | <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short) | |
| | | <DT>"INT32"<DD> 32-bit signed integer (long) | |
| | | <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long) | |
| | | <DT>"FLOAT"<DD> 32-bit floating point (float) | |
| | | <DT>"DOUBLE"<DD> 64-bit floating point (double) | |
| | | </DL> | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setPixelType( const char * ); | |
| | | | |
| | | /** Get the pixel type of the images in the volume. Possible values | |
| | | are: | |
| | | <DL> | |
| | | <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char) | |
| | | <DT>"INT16"<DD> 16-bit signed integer (short) | |
| | | <DT>"INT32"<DD> 32-bit signed integer (long) | |
| | | <DT>"FLOAT"<DD> 32-bit floating point (float) | |
| | | <DT>"DOUBLE"<DD> 64-bit floating point (double) | |
| | | </DL> | |
| | | **/ | |
| | | VIGRA_EXPORT const char * getPixelType() const; | |
| | | | |
| | | VIGRA_EXPORT VolumeExportInfo & setForcedRangeMapping(double fromMin, d | |
| | | ouble fromMax, | |
| | | double toMin, double t | |
| | | oMax); | |
| | | VIGRA_EXPORT bool hasForcedRangeMapping() const; | |
| | | VIGRA_EXPORT double getFromMin() const; | |
| | | VIGRA_EXPORT double getFromMax() const; | |
| | | VIGRA_EXPORT double getToMin() const; | |
| | | VIGRA_EXPORT double getToMax() const; | |
| | | | |
| | | /** Set the volume resolution in horizontal direction | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setXResolution( float ); | |
| | | VIGRA_EXPORT float getXResolution() const; | |
| | | | |
| | | /** Set the image resolution in vertical direction | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setYResolution( float ); | |
| | | VIGRA_EXPORT float getYResolution() const; | |
| | | | |
| | | /** Set the image resolution in depth direction | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setZResolution( float ); | |
| | | VIGRA_EXPORT float getZResolution() const; | |
| | | | |
| | | /** Set the position of the upper Left corner on a global | |
| | | canvas. | |
| | | | |
| | | Currently only supported by TIFF and PNG files. | |
| | | | |
| | | The offset is encoded in the XPosition and YPosition TIFF tags. | |
| | | | |
| | | @param pos position of the upper left corner in pixels | |
| | | (must be >= 0) | |
| | | **/ | |
| | | // FIXME: mhanselm: we might want to support 3D positions | |
| | | VIGRA_EXPORT VolumeExportInfo & setPosition(const Diff2D & pos); | |
| | | | |
| | | /** Get the position of the upper left corner on | |
| | | a global canvas. | |
| | | **/ | |
| | | // FIXME: mhanselm: we might want to support 3D positions | |
| | | VIGRA_EXPORT Diff2D getPosition() const; | |
| | | | |
| | | /** | |
| | | ICC profiles (handled as raw data so far). | |
| | | see getICCProfile()/setICCProfile() | |
| | | **/ | |
| | | typedef ArrayVector<unsigned char> ICCProfile; | |
| | | | |
| | | /** Returns a reference to the ICC profile. | |
| | | */ | |
| | | VIGRA_EXPORT const ICCProfile & getICCProfile() const; | |
| | | | |
| | | /** Sets the ICC profile. | |
| | | ICC profiles are currently supported by TIFF, PNG and JPEG imag | |
| | | es. | |
| | | (Otherwise, the profile data is silently ignored.) | |
| | | **/ | |
| | | VIGRA_EXPORT VolumeExportInfo & setICCProfile(const ICCProfile & profil | |
| | | e); | |
| | | | |
| | | private: | |
| | | float m_x_res, m_y_res, m_z_res; | |
| | | | |
| | | std::string m_filetype, m_filename_base, m_filename_ext, m_pixeltype, m | |
| | | _comp; | |
| | | Diff2D m_pos; | |
| | | ICCProfile m_icc_profile; | |
| | | double fromMin_, fromMax_, toMin_, toMax_; | |
| | | }; | |
| | | | |
| | | namespace detail { | |
| | | | |
| | | template <class DestIterator, class Shape, class T> | |
| | | inline void | |
| | | readVolumeImpl(DestIterator d, Shape const & shape, std::ifstream & s, Arra | |
| | | yVector<T> & buffer, MetaInt<0>) | |
| | | { | |
| | | s.read((char*)buffer.begin(), shape[0]*sizeof(T)); | |
| | | | |
| | | DestIterator dend = d + shape[0]; | |
| | | int k = 0; | |
| | | for(; d < dend; ++d, k++) | |
| | | { | |
| | | *d = buffer[k]; | |
| | | } | |
| | | } | |
| | | | |
| | | template <class DestIterator, class Shape, class T, int N> | |
| | | void | |
| | | readVolumeImpl(DestIterator d, Shape const & shape, std::ifstream & s, Arra | |
| | | yVector<T> & buffer, MetaInt<N>) | |
| | | { | |
| | | DestIterator dend = d + shape[N]; | |
| | | for(; d < dend; ++d) | |
| | | { | |
| | | readVolumeImpl(d.begin(), shape, s, buffer, MetaInt<N-1>()); | |
| | | } | |
| | | } | |
| | | | |
| | | } // namespace detail | |
| | | | |
| | | template <class T, class Stride> | |
| | | void VolumeImportInfo::importImpl(MultiArrayView <3, T, Stride> &volume) co | |
| | | nst | |
| | | { | |
| | | vigra_precondition(this->shape() == volume.shape(), "importVolume(): Vo | |
| | | lume must be shaped according to VolumeImportInfo."); | |
| | | | |
| if(rawFilename_.size()) | | if(rawFilename_.size()) | |
| { | | { | |
| std::string dirName, baseName; | | std::string dirName, baseName; | |
| char oldCWD[2048]; | | char oldCWD[2048]; | |
| | | | |
| #ifdef _MSC_VER | | #ifdef _MSC_VER | |
|
| _getcwd(oldCWD, 2048); | | if(_getcwd(oldCWD, 2048) == 0) | |
| | | { | |
| | | perror("getcwd"); | |
| | | vigra_fail("VolumeImportInfo: Unable to query current directory | |
| | | (getcwd)."); | |
| | | } | |
| if(_chdir(path_.c_str())) | | if(_chdir(path_.c_str())) | |
|
| | | { | |
| perror("chdir"); | | perror("chdir"); | |
|
| | | vigra_fail("VolumeImportInfo: Unable to change to new directory | |
| | | (chdir)."); | |
| | | } | |
| #else | | #else | |
|
| getcwd(oldCWD, 2048); | | if(getcwd(oldCWD, 2048) == 0) | |
| | | { | |
| | | perror("getcwd"); | |
| | | vigra_fail("VolumeImportInfo: Unable to query current directory | |
| | | (getcwd)."); | |
| | | } | |
| if(chdir(path_.c_str())) | | if(chdir(path_.c_str())) | |
|
| | | { | |
| perror("chdir"); | | perror("chdir"); | |
|
| | | vigra_fail("VolumeImportInfo: Unable to change to new directory | |
| | | (chdir)."); | |
| | | } | |
| #endif | | #endif | |
| | | | |
| std::ifstream s(rawFilename_.c_str(), std::ios::binary); | | std::ifstream s(rawFilename_.c_str(), std::ios::binary); | |
| vigra_precondition(s.good(), "RAW file could not be opened"); | | vigra_precondition(s.good(), "RAW file could not be opened"); | |
|
| s.read((char*)volume.begin(), shape_[0]*shape_[1]*shape_[2]*sizeof( | | | |
| T)); | | ArrayVector<T> buffer(shape_[0]); | |
| | | detail::readVolumeImpl(volume.traverser_begin(), shape_, s, buffer, | |
| | | vigra::MetaInt<2>()); | |
| | | | |
| | | //vigra_precondition(s.good(), "RAW file could not be opened"); | |
| | | //s.read((char*)volume.data(), shape_[0]*shape_[1]*shape_[2]*sizeof | |
| | | (T)); | |
| | | | |
| #ifdef _MSC_VER | | #ifdef _MSC_VER | |
|
| _chdir(oldCWD); | | if(_chdir(oldCWD)) | |
| | | perror("chdir"); | |
| #else | | #else | |
|
| chdir(oldCWD); | | if(chdir(oldCWD)) | |
| | | perror("chdir"); | |
| #endif | | #endif | |
| | | | |
| vigra_postcondition( | | vigra_postcondition( | |
| volume.shape() == shape(), "imported volume has wrong size"); | | volume.shape() == shape(), "imported volume has wrong size"); | |
| } | | } | |
| else | | else | |
| { | | { | |
| for (unsigned int i = 0; i < numbers_.size(); ++i) | | for (unsigned int i = 0; i < numbers_.size(); ++i) | |
| { | | { | |
| // build the filename | | // build the filename | |
| std::string name = baseName_ + numbers_[i] + extension_; | | std::string name = baseName_ + numbers_[i] + extension_; | |
| | | | |
| // import the image | | // import the image | |
| ImageImportInfo info (name.c_str ()); | | ImageImportInfo info (name.c_str ()); | |
| | | | |
| // generate a basic image view to the current layer | | // generate a basic image view to the current layer | |
|
| MultiArrayView <2, T> array_view (volume.bindOuter (i)); | | MultiArrayView <2, T, Stride> view (volume.bindOuter (i)); | |
| BasicImageView <T> view = makeBasicImageView (array_view); | | vigra_precondition(view.shape() == info.shape(), | |
| vigra_precondition(view.size() == info.size(), | | "importVolume(): the images have inconsistent sizes."); | |
| "importVolume(): image size mismatch."); | | | |
| | | | |
| importImage (info, destImage(view)); | | importImage (info, destImage(view)); | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| VIGRA_EXPORT void findImageSequence(const std::string &name_base, | | VIGRA_EXPORT void findImageSequence(const std::string &name_base, | |
| const std::string &name_ext, | | const std::string &name_ext, | |
| std::vector<std::string> & numbers); | | std::vector<std::string> & numbers); | |
| | | | |
|
| /** \addtogroup VolumeImpex Import/export of volume data. | | | |
| */ | | | |
| | | | |
| //@{ | | | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* importVolume */ | | /* importVolume */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Function for importing a 3D volume. | | /** \brief Function for importing a 3D volume. | |
| | | | |
| The data are expected to be stored in a by-slice manner, | | The data are expected to be stored in a by-slice manner, | |
| where the slices are enumerated from <tt>name_base+"[0-9]+"+name_ext</t
t>. | | where the slices are enumerated from <tt>name_base+"[0-9]+"+name_ext</t
t>. | |
| | | | |
| skipping to change at line 216 | | skipping to change at line 529 | |
| \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | | \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | |
| | | | |
| Namespace: vigra | | Namespace: vigra | |
| */ | | */ | |
| template <class T, class Allocator> | | template <class T, class Allocator> | |
| void importVolume (MultiArray <3, T, Allocator> & volume, | | void importVolume (MultiArray <3, T, Allocator> & volume, | |
| const std::string &name_base, | | const std::string &name_base, | |
| const std::string &name_ext) | | const std::string &name_ext) | |
| { | | { | |
| VolumeImportInfo info(name_base, name_ext); | | VolumeImportInfo info(name_base, name_ext); | |
|
| | | volume.reshape(info.shape()); | |
| | | | |
| info.importImpl(volume); | | info.importImpl(volume); | |
| } | | } | |
| | | | |
| /** \brief Function for importing a 3D volume. | | /** \brief Function for importing a 3D volume. | |
| | | | |
| The data can be given in two ways: | | The data can be given in two ways: | |
| | | | |
| <UL> | | <UL> | |
| <LI> If the volume is stored in a by-slice manner (e.g. one image per s
lice), | | <LI> If the volume is stored in a by-slice manner (e.g. one image per s
lice), | |
| | | | |
| skipping to change at line 262 | | skipping to change at line 576 | |
| <b>\#include</b> | | <b>\#include</b> | |
| \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | | \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | |
| | | | |
| Namespace: vigra | | Namespace: vigra | |
| */ | | */ | |
| template <class T, class Allocator> | | template <class T, class Allocator> | |
| void importVolume(MultiArray <3, T, Allocator> &volume, | | void importVolume(MultiArray <3, T, Allocator> &volume, | |
| const std::string &filename) | | const std::string &filename) | |
| { | | { | |
| VolumeImportInfo info(filename); | | VolumeImportInfo info(filename); | |
|
| | | volume.reshape(info.shape()); | |
| | | | |
| info.importImpl(volume); | | info.importImpl(volume); | |
| } | | } | |
| | | | |
| /** \brief Function for importing a 3D volume. | | /** \brief Function for importing a 3D volume. | |
| | | | |
| Read the volume data set <tt>info</tt> refers to. Explicit construction | | Read the volume data set <tt>info</tt> refers to. Explicit construction | |
| of the info object allows to allocate a <tt>volume</tt> object type who
se | | of the info object allows to allocate a <tt>volume</tt> object type who
se | |
| <tt>value_type</tt> matches the voxel type of the stored data. | | <tt>value_type</tt> matches the voxel type of the stored data. | |
| The <tt>volume</tt> will be reshaped to match the count and | | The <tt>volume</tt> will be reshaped to match the count and | |
| size of the slices found. | | size of the slices found. | |
| | | | |
| <b>\#include</b> | | <b>\#include</b> | |
| \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | | \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | |
| | | | |
| Namespace: vigra | | Namespace: vigra | |
| */ | | */ | |
|
| template <class T, class Allocator> | | template <class T, class Stride> | |
| void importVolume(VolumeImportInfo const & info, MultiArray <3, T, Allocato | | void importVolume(VolumeImportInfo const & info, MultiArrayView <3, T, Stri | |
| r> &volume) | | de> &volume) | |
| { | | { | |
| info.importImpl(volume); | | info.importImpl(volume); | |
| } | | } | |
| | | | |
| namespace detail { | | namespace detail { | |
| | | | |
| template <class T> | | template <class T> | |
| void setRangeMapping(std::string const & pixeltype, | | void setRangeMapping(std::string const & pixeltype, | |
| FindMinMax<T> const & minmax, ImageExportInfo & info) | | FindMinMax<T> const & minmax, ImageExportInfo & info) | |
| { | | { | |
| if(pixeltype == "UINT8") | | if(pixeltype == "UINT8") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max, | |
| (double)NumericTraits<Int8>::min(), | | (double)NumericTraits<UInt8>::min(), | |
| (double)NumericTraits<Int8>::max()); | | (double)NumericTraits<UInt8>::max()); | |
| else if(pixeltype == "INT16") | | else if(pixeltype == "INT16") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max, | |
| (double)NumericTraits<Int16>::min(), | | (double)NumericTraits<Int16>::min(), | |
| (double)NumericTraits<Int16>::max()); | | (double)NumericTraits<Int16>::max()); | |
| else if(pixeltype == "UINT16") | | else if(pixeltype == "UINT16") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max, | |
| (double)NumericTraits<UInt16>::min(), | | (double)NumericTraits<UInt16>::min(), | |
| (double)NumericTraits<UInt16>::max()); | | (double)NumericTraits<UInt16>::max()); | |
| else if(pixeltype == "INT32") | | else if(pixeltype == "INT32") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max, | |
| (double)NumericTraits<Int32>::min(), | | (double)NumericTraits<Int32>::min(), | |
| (double)NumericTraits<Int32>::max()); | | (double)NumericTraits<Int32>::max()); | |
| else if(pixeltype == "UINT32") | | else if(pixeltype == "UINT32") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max, | |
| (double)NumericTraits<UInt32>::min(), | | (double)NumericTraits<UInt32>::min(), | |
| (double)NumericTraits<UInt32>::max()); | | (double)NumericTraits<UInt32>::max()); | |
| else if(pixeltype == "FLOAT") | | else if(pixeltype == "FLOAT") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, 0.0, 1.0); | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max,
0.0, 1.0); | |
| else if(pixeltype == "DOUBLE") | | else if(pixeltype == "DOUBLE") | |
|
| info.setForcedRangeMapping(minmax.min, minmax.max, 0.0, 1.0); | | info.setForcedRangeMapping((double)minmax.min, (double)minmax.max,
0.0, 1.0); | |
| } | | } | |
| | | | |
| template <class T, class Tag> | | template <class T, class Tag> | |
| void setRangeMapping(MultiArrayView <3, T, Tag> const & volume, | | void setRangeMapping(MultiArrayView <3, T, Tag> const & volume, | |
| ImageExportInfo & info, VigraTrueType /* isScalar */) | | ImageExportInfo & info, VigraTrueType /* isScalar */) | |
| { | | { | |
| std::string pixeltype = info.getPixelType(); | | std::string pixeltype = info.getPixelType(); | |
| bool downcast = negotiatePixelType(getEncoderType(info.getFileName(), i
nfo.getFileType()), | | bool downcast = negotiatePixelType(getEncoderType(info.getFileName(), i
nfo.getFileType()), | |
| TypeAsString<T>::result(), pixeltype
); | | TypeAsString<T>::result(), pixeltype
); | |
| | | | |
| | | | |
| skipping to change at line 379 | | skipping to change at line 694 | |
| does not support the source voxel type, all slices will be mapped simul
taneously | | does not support the source voxel type, all slices will be mapped simul
taneously | |
| to the appropriate target range. | | to the appropriate target range. | |
| | | | |
| <b>\#include</b> | | <b>\#include</b> | |
| \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | | \<<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>\> | |
| | | | |
| Namespace: vigra | | Namespace: vigra | |
| */ | | */ | |
| template <class T, class Tag> | | template <class T, class Tag> | |
| void exportVolume (MultiArrayView <3, T, Tag> const & volume, | | void exportVolume (MultiArrayView <3, T, Tag> const & volume, | |
|
| const std::string &name_base, | | const VolumeExportInfo & volinfo) | |
| const std::string &name_ext) | | | |
| { | | { | |
|
| std::string name = name_base + name_ext; | | std::string name = std::string(volinfo.getFileNameBase()) + std::string
(volinfo.getFileNameExt()); | |
| ImageExportInfo info(name.c_str()); | | ImageExportInfo info(name.c_str()); | |
|
| | | info.setCompression(volinfo.getCompression()); | |
| | | info.setPixelType(volinfo.getPixelType()); | |
| detail::setRangeMapping(volume, info, typename NumericTraits<T>::isScal
ar()); | | detail::setRangeMapping(volume, info, typename NumericTraits<T>::isScal
ar()); | |
| | | | |
| const unsigned int depth = volume.shape (2); | | const unsigned int depth = volume.shape (2); | |
| int numlen = static_cast <int> (std::ceil (std::log10 ((double)depth)))
; | | int numlen = static_cast <int> (std::ceil (std::log10 ((double)depth)))
; | |
| for (unsigned int i = 0; i < depth; ++i) | | for (unsigned int i = 0; i < depth; ++i) | |
| { | | { | |
| | | | |
| // build the filename | | // build the filename | |
| std::stringstream stream; | | std::stringstream stream; | |
| stream << std::setfill ('0') << std::setw (numlen) << i; | | stream << std::setfill ('0') << std::setw (numlen) << i; | |
| std::string name_num; | | std::string name_num; | |
| stream >> name_num; | | stream >> name_num; | |
|
| std::string name = name_base + name_num + name_ext; | | std::string name = std::string(volinfo.getFileNameBase()) + name_nu | |
| | | m + std::string(volinfo.getFileNameExt()); | |
| if(i == 0) | | | |
| { | | | |
| } | | | |
| | | | |
|
| // generate a basic image view to the current layer | | MultiArrayView <2, T, Tag> view (volume.bindOuter (i)); | |
| MultiArrayView <2, T, Tag> array_view (volume.bindOuter (i)); | | | |
| BasicImageView <T> view = makeBasicImageView (array_view); | | | |
| | | | |
| // export the image | | // export the image | |
| info.setFileName(name.c_str ()); | | info.setFileName(name.c_str ()); | |
| exportImage(srcImageRange(view), info); | | exportImage(srcImageRange(view), info); | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | // for backward compatibility | |
| | | template <class T, class Tag> | |
| | | inline | |
| | | void exportVolume (MultiArrayView <3, T, Tag> const & volume, | |
| | | const std::string &name_base, | |
| | | const std::string &name_ext) | |
| | | { | |
| | | VolumeExportInfo volinfo(name_base.c_str(), name_ext.c_str()); | |
| | | exportVolume(volume, volinfo); | |
| | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
| #endif // VIGRA_MULTI_IMPEX_HXX | | #endif // VIGRA_MULTI_IMPEX_HXX | |
| | | | |
End of changes. 42 change blocks. |
| 57 lines changed or deleted | | 413 lines changed or added | |
|
| multi_morphology.hxx | | multi_morphology.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ | | /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ | |
| /* and Ullrich Koethe */ | | /* and Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 57 | | skipping to change at line 55 | |
| #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" | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
|
| | | namespace detail { | |
| | | | |
| | | // this class simplfies the design, but more importantly, it makes sure | |
| | | // that the in-place code doesn't get compiled for boolean arrays | |
| | | // (were it would never executed anyway -- see the specializations below) | |
| | | template <class DestType, class TmpType> | |
| | | struct MultiBinaryMorphologyImpl | |
| | | { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | static void | |
| | | exec( SrcIterator s, SrcShape const & shape, SrcAccessor src, | |
| | | DestIterator d, DestAccessor dest, | |
| | | double radius, bool dilation) | |
| | | { | |
| | | using namespace vigra::functor; | |
| | | | |
| | | // Allocate a new temporary array if the distances squared wouldn't | |
| | | fit | |
| | | MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | |
| | | | |
| | | separableMultiDistSquared(s, shape, src, | |
| | | tmpArray.traverser_begin(), typename Acce | |
| | | ssorTraits<TmpType>::default_accessor(), dilation ); | |
| | | | |
| | | // threshold everything less than radius away from the edge | |
| | | double radius2 = radius * radius; | |
| | | DestType foreground = dilation | |
| | | ? NumericTraits<DestType>::zero() | |
| | | : NumericTraits<DestType>::one(), | |
| | | background = dilation | |
| | | ? NumericTraits<DestType>::one() | |
| | | : NumericTraits<DestType>::zero(); | |
| | | transformMultiArray( tmpArray.traverser_begin(), shape, StandardVal | |
| | | ueAccessor<double>(), | |
| | | d, dest, | |
| | | ifThenElse( Arg1() >= Param(radius2), | |
| | | Param(foreground), Param(backgroun | |
| | | d) ) ); | |
| | | } | |
| | | }; | |
| | | | |
| | | template <class DestType> | |
| | | struct MultiBinaryMorphologyImpl<DestType, DestType> | |
| | | { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | static void | |
| | | exec( SrcIterator s, SrcShape const & shape, SrcAccessor src, | |
| | | DestIterator d, DestAccessor dest, | |
| | | double radius, bool dilation) | |
| | | { | |
| | | using namespace vigra::functor; | |
| | | | |
| | | separableMultiDistSquared( s, shape, src, d, dest, dilation ); | |
| | | | |
| | | // threshold everything less than radius away from the edge | |
| | | DestType radius2 = detail::RequiresExplicitCast<DestType>::cast(rad | |
| | | ius * radius); | |
| | | DestType foreground = dilation | |
| | | ? NumericTraits<DestType>::zero() | |
| | | : NumericTraits<DestType>::one(), | |
| | | background = dilation | |
| | | ? NumericTraits<DestType>::one() | |
| | | : NumericTraits<DestType>::zero(); | |
| | | transformMultiArray( d, shape, dest, d, dest, | |
| | | ifThenElse( Arg1() > Param(radius2), | |
| | | Param(foreground), Param(backgroun | |
| | | d) ) ); | |
| | | } | |
| | | }; | |
| | | | |
| | | template <> | |
| | | struct MultiBinaryMorphologyImpl<bool, bool> | |
| | | { | |
| | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| | | class DestIterator, class DestAccessor> | |
| | | static void | |
| | | exec( SrcIterator s, SrcShape const & shape, SrcAccessor src, | |
| | | DestIterator d, DestAccessor dest, double radius, bool dilation) | |
| | | { | |
| | | vigra_fail("multiBinaryMorphology(): Internal error (this function | |
| | | should never be called)."); | |
| | | } | |
| | | }; | |
| | | | |
| | | } // namespace detail | |
| | | | |
| /** \addtogroup MultiArrayMorphology Morphological operators for multi-dime
nsional arrays. | | /** \addtogroup MultiArrayMorphology Morphological operators for multi-dime
nsional arrays. | |
| | | | |
| These functions perform morphological operations on an arbitrary | | These functions perform morphological operations on an arbitrary | |
| dimensional array that is specified by iterators (compatible to \ref Mu
ltiIteratorPage) | | dimensional array that is specified by iterators (compatible to \ref Mu
ltiIteratorPage) | |
| 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.). | |
| */ | | */ | |
| //@{ | | //@{ | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* multiBinaryErosion */ | | /* multiBinaryErosion */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| /** \brief Binary erosion on multi-dimensional arrays. | | /** \brief Binary erosion on multi-dimensional arrays. | |
| | | | |
| This function applies a flat circular erosion operator with a given rad
ius. The | | This function applies a flat circular erosion operator with a given rad
ius. The | |
|
| operation is isotropic. | | operation is isotropic. The input is intepreted as a binary multi-dimen | |
| The input is a binary multi-dimensional array where non-zero pixels rep | | sional | |
| resent | | array where non-zero pixels represent foreground and zero pixels repres | |
| foreground and zero pixels represent background. | | ent | |
| | | background. In the output, foregound is always represented by ones | |
| | | (i.e. NumericTrais<typename DestAccessor::value_type>::one()). | |
| | | | |
| This function may work in-place, which means that <tt>siter == diter</t
t> is allowed. | | This function may work in-place, which means that <tt>siter == diter</t
t> is allowed. | |
|
| A full-sized internal array is only allocated if working on the destina | | A temporary internal array is only allocated if working on the destinat | |
| tion | | ion | |
| array directly would cause overflow errors (i.e. if | | array directly would cause overflow errors (that is if | |
| <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M | | <tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredN | |
| is the | | orm(shape)</tt>, | |
| size of the largest dimension of the array. | | i.e. the squared length of the image diagonal doesn't fit into the dest | |
| | | ination type). | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass 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 | |
| multiBinaryErosion(SrcIterator siter, SrcShape const & shape, SrcAc
cessor src, | | multiBinaryErosion(SrcIterator siter, SrcShape const & shape, SrcAc
cessor src, | |
| | | | |
| skipping to change at line 133 | | skipping to change at line 213 | |
| \endcode | | \endcode | |
| | | | |
| \see vigra::discErosion() | | \see vigra::discErosion() | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void multiBinaryErosion) | | doxygen_overloaded_function(template <...> void multiBinaryErosion) | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| multiBinaryErosion( SrcIterator s, SrcShape const & shape, SrcAccessor src, | | multiBinaryErosion( SrcIterator s, SrcShape const & shape, SrcAccessor src, | |
|
| DestIterator d, DestAccessor dest, float radiu
s) | | DestIterator d, DestAccessor dest, double radi
us) | |
| { | | { | |
|
| typedef typename NumericTraits<typename DestAccessor::value_type>::Valu | | typedef typename DestAccessor::value_type DestType; | |
| eType DestType; | | typedef Int32 TmpType; | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Prom | | | |
| ote TmpType; | | | |
| DestType MaxValue = NumericTraits<DestType>::max(); | | | |
| float radius2 = (float) radius * radius; | | | |
| enum { N = 1 + SrcIterator::level }; | | | |
| | | | |
| int MaxDim = 0; | | | |
| for( int i=0; i<N; i++) | | | |
| if(MaxDim < shape[i]) MaxDim = shape[i]; | | | |
| | | | |
|
| using namespace vigra::functor; | | double dmax = squaredNorm(shape); | |
| | | | |
| // Get the distance squared transform of the image | | // Get the distance squared transform of the image | |
|
| if(N*MaxDim*MaxDim > MaxValue) | | if(dmax > NumericTraits<DestType>::toRealPromote(NumericTraits<DestType
>::max())) | |
| { | | { | |
|
| // Allocate a new temporary array if the distances squared wouldn't | | detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape | |
| fit | | , src, d, dest, radius, false); | |
| MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | | | |
| //detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArr | | | |
| ay.traverser_begin(), | | | |
| // typename AccessorTraits<TmpType>::default_accessor()/*, false | | | |
| */ ); | | | |
| | | | |
| separableMultiDistSquared(s, shape, src, tmpArray.traverser_begin() | | | |
| , | | | |
| typename AccessorTraits<TmpType>::default_accessor(), false | | | |
| ); | | | |
| | | | |
| // threshold everything less than radius away from the edge | | | |
| // std::cerr << "Thresholding!!!!!" << std::endl; | | | |
| transformMultiArray( tmpArray.traverser_begin(), shape, | | | |
| typename AccessorTraits<TmpType>::default_accessor(), d, dest, | | | |
| ifThenElse( Arg1() > Param(radius2), | | | |
| Param(MaxValue), Param(0) ) ); | | | |
| } | | } | |
| else // work directly on the destination array | | else // work directly on the destination array | |
| { | | { | |
|
| //detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, des | | detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shap | |
| t/*, false*/ ); | | e, src, d, dest, radius, false); | |
| separableMultiDistSquared( s, shape, src, d, dest, false ); | | | |
| | | | |
| // threshold everything less than radius away from the edge | | | |
| transformMultiArray( d, shape, dest, d, dest, | | | |
| ifThenElse( Arg1() > Param(radius2), | | | |
| Param(MaxValue), Param(0) ) ); | | | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void multiBinaryErosion( | | void multiBinaryErosion( | |
| triple<SrcIterator, SrcShape, SrcAccessor> const & source, | | triple<SrcIterator, SrcShape, SrcAccessor> const & source, | |
|
| pair<DestIterator, DestAccessor> const & dest, int radius) | | pair<DestIterator, DestAccessor> const & dest, double radius) | |
| { | | { | |
| multiBinaryErosion( source.first, source.second, source.third, | | multiBinaryErosion( source.first, source.second, source.third, | |
| dest.first, dest.second, radius ); | | dest.first, dest.second, radius ); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* multiBinaryDilation */ | | /* multiBinaryDilation */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Binary dilation on multi-dimensional arrays. | | /** \brief Binary dilation on multi-dimensional arrays. | |
| | | | |
| This function applies a flat circular dilation operator with a given ra
dius. The | | This function applies a flat circular dilation operator with a given ra
dius. The | |
|
| operation is isotropic. | | operation is isotropic. The input is intepreted as a binary multi-dimen | |
| The input is a binary multi-dimensional array where non-zero pixels rep | | sional | |
| resent | | array where non-zero pixels represent foreground and zero pixels repres | |
| foreground and zero pixels represent background. | | ent | |
| | | background. In the output, foregound is always represented by ones | |
| | | (i.e. NumericTrais<typename DestAccessor::value_type>::one()). | |
| | | | |
| This function may work in-place, which means that <tt>siter == diter</t
t> is allowed. | | This function may work in-place, which means that <tt>siter == diter</t
t> is allowed. | |
|
| A full-sized internal array is only allocated if working on the destina | | A temporary internal array is only allocated if working on the destinat | |
| tion | | ion | |
| array directly would cause overflow errors (i.e. if | | array directly would cause overflow errors (that is if | |
| <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M | | <tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredN | |
| is the | | orm(shape)</tt>, | |
| size of the largest dimension of the array. | | i.e. the squared length of the image diagonal doesn't fit into the dest | |
| | | ination type). | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass 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 | |
| multiBinaryDilation(SrcIterator siter, SrcShape const & shape, SrcA
ccessor src, | | multiBinaryDilation(SrcIterator siter, SrcShape const & shape, SrcA
ccessor src, | |
| | | | |
| skipping to change at line 256 | | skipping to change at line 311 | |
| \endcode | | \endcode | |
| | | | |
| \see vigra::discDilation() | | \see vigra::discDilation() | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void multiBinaryDilation) | | doxygen_overloaded_function(template <...> void multiBinaryDilation) | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| multiBinaryDilation( SrcIterator s, SrcShape const & shape, SrcAccessor src
, | | multiBinaryDilation( SrcIterator s, SrcShape const & shape, SrcAccessor src
, | |
|
| DestIterator d, DestAccessor dest, float radiu
s) | | DestIterator d, DestAccessor dest, double radi
us) | |
| { | | { | |
|
| typedef typename NumericTraits<typename DestAccessor::value_type>::Valu | | typedef typename DestAccessor::value_type DestType; | |
| eType DestType; | | typedef Int32 TmpType; | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Prom | | | |
| ote TmpType; | | | |
| DestType MaxValue = NumericTraits<DestType>::max(); | | | |
| float radius2 = (float) radius * radius; | | | |
| enum { N = 1 + SrcIterator::level }; | | | |
| | | | |
| int MaxDim = 0; | | | |
| for( int i=0; i<N; i++) | | | |
| if(MaxDim < shape[i]) MaxDim = shape[i]; | | | |
| | | | |
|
| using namespace vigra::functor; | | double dmax = squaredNorm(shape); | |
| | | | |
| // Get the distance squared transform of the image | | // Get the distance squared transform of the image | |
|
| if(N*MaxDim*MaxDim > MaxValue) | | if(dmax > NumericTraits<DestType>::toRealPromote(NumericTraits<DestType
>::max())) | |
| { | | { | |
|
| // Allocate a new temporary array if the distances squared wouldn't | | detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape | |
| fit | | , src, d, dest, radius, true); | |
| MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | | | |
| //detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArr | | | |
| ay.traverser_begin(), | | | |
| // typename AccessorTraits<TmpType>::default_accessor(), true ); | | | |
| | | | |
| separableMultiDistSquared(s, shape, src, tmpArray.traverser_begin() | | | |
| , | | | |
| typename AccessorTraits<TmpType>::default_accessor(), true ); | | | |
| | | | |
| // threshold everything less than radius away from the edge | | | |
| transformMultiArray( tmpArray.traverser_begin(), shape, | | | |
| typename AccessorTraits<TmpType>::default_accessor(), d, dest, | | | |
| ifThenElse( Arg1() > Param(radius2), | | | |
| Param(0), Param(MaxValue) ) ); | | | |
| } | | } | |
| else // work directly on the destination array | | else // work directly on the destination array | |
| { | | { | |
|
| //detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, des | | detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shap | |
| t, true ); | | e, src, d, dest, radius, true); | |
| separableMultiDistSquared( s, shape, src, d, dest, true ); | | | |
| | | | |
| // threshold everything less than radius away from the edge | | | |
| transformMultiArray( d, shape, dest, d, dest, | | | |
| ifThenElse( Arg1() > Param(radius2), | | | |
| Param(0), Param(MaxValue) ) ); | | | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void multiBinaryDilation( | | void multiBinaryDilation( | |
| triple<SrcIterator, SrcShape, SrcAccessor> const & source, | | triple<SrcIterator, SrcShape, SrcAccessor> const & source, | |
|
| pair<DestIterator, DestAccessor> const & dest, int radius) | | pair<DestIterator, DestAccessor> const & dest, double radius) | |
| { | | { | |
| multiBinaryDilation( source.first, source.second, source.third, | | multiBinaryDilation( source.first, source.second, source.third, | |
| dest.first, dest.second, radius ); | | dest.first, dest.second, radius ); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* multiGrayscaleErosion */ | | /* multiGrayscaleErosion */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| skipping to change at line 336 | | skipping to change at line 366 | |
| | | | |
| <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 | |
| multiGrayscaleErosion(SrcIterator siter, SrcShape const & shape, Sr
cAccessor src, | | multiGrayscaleErosion(SrcIterator siter, SrcShape const & shape, Sr
cAccessor src, | |
|
| DestIterator diter, DestAccessor dest,
float sigma); | | DestIterator diter, DestAccessor dest,
double sigma); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| multiGrayscaleErosion(triple<SrcIterator, SrcShape, SrcAccessor> co
nst & source, | | multiGrayscaleErosion(triple<SrcIterator, SrcShape, SrcAccessor> co
nst & source, | |
| pair<DestIterator, DestAccessor> const
& dest, | | pair<DestIterator, DestAccessor> const
& dest, | |
|
| float sigma); | | double sigma); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m
ulti_morphology.hxx</a>\> | | <b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m
ulti_morphology.hxx</a>\> | |
| | | | |
| \code | | \code | |
| MultiArray<3, unsigned char>::size_type shape(width, height, depth); | | MultiArray<3, unsigned char>::size_type shape(width, height, depth); | |
| | | | |
| skipping to change at line 376 | | skipping to change at line 406 | |
| \endcode | | \endcode | |
| | | | |
| \see vigra::discErosion() | | \see vigra::discErosion() | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void multiGrayscaleErosion) | | doxygen_overloaded_function(template <...> void multiGrayscaleErosion) | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| multiGrayscaleErosion( SrcIterator s, SrcShape const & shape, SrcAccessor s
rc, | | multiGrayscaleErosion( SrcIterator s, SrcShape const & shape, SrcAccessor s
rc, | |
|
| DestIterator d, DestAccessor dest, float sigma) | | DestIterator d, DestAccessor dest, double sigma) | |
| { | | { | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Valu
eType DestType; | | typedef typename NumericTraits<typename DestAccessor::value_type>::Valu
eType DestType; | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Prom
ote TmpType; | | typedef typename NumericTraits<typename DestAccessor::value_type>::Prom
ote TmpType; | |
| DestType MaxValue = NumericTraits<DestType>::max(); | | DestType MaxValue = NumericTraits<DestType>::max(); | |
| enum { N = 1 + SrcIterator::level }; | | enum { N = 1 + SrcIterator::level }; | |
| | | | |
| // temporay array to hold the current line to enable in-place operation | | // temporay array to hold the current line to enable in-place operation | |
| ArrayVector<TmpType> tmp( shape[0] ); | | ArrayVector<TmpType> tmp( shape[0] ); | |
| | | | |
| typedef MultiArrayNavigator<SrcIterator, N> SNavigator; | | typedef MultiArrayNavigator<SrcIterator, N> SNavigator; | |
| typedef MultiArrayNavigator<DestIterator, N> DNavigator; | | typedef MultiArrayNavigator<DestIterator, N> DNavigator; | |
| | | | |
| int MaxDim = 0; | | int MaxDim = 0; | |
| for( int i=0; i<N; i++) | | for( int i=0; i<N; i++) | |
| if(MaxDim < shape[i]) MaxDim = shape[i]; | | if(MaxDim < shape[i]) MaxDim = shape[i]; | |
| | | | |
| using namespace vigra::functor; | | using namespace vigra::functor; | |
| | | | |
|
| | | ArrayVector<double> sigmas(shape.size(), sigma); | |
| | | | |
| // Allocate a new temporary array if the distances squared wouldn't fit | | // Allocate a new temporary array if the distances squared wouldn't fit | |
| if(N*MaxDim*MaxDim > MaxValue) | | if(N*MaxDim*MaxDim > MaxValue) | |
| { | | { | |
| MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | | MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | |
| | | | |
| detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArray
.traverser_begin(), | | detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArray
.traverser_begin(), | |
|
| typename AccessorTraits<TmpType>::default_accessor(), sigma ); | | typename AccessorTraits<TmpType>::default_accessor(), sigmas ); | |
| | | | |
| transformMultiArray( tmpArray.traverser_begin(), shape, | | transformMultiArray( tmpArray.traverser_begin(), shape, | |
| typename AccessorTraits<TmpType>::default_accessor(), d, de
st, | | typename AccessorTraits<TmpType>::default_accessor(), d, de
st, | |
| ifThenElse( Arg1() > Param(MaxValue), Param(MaxValue), Arg1
() ) ); | | ifThenElse( Arg1() > Param(MaxValue), Param(MaxValue), Arg1
() ) ); | |
| //copyMultiArray( tmpArray.traverser_begin(), shape, | | //copyMultiArray( tmpArray.traverser_begin(), shape, | |
| // typename AccessorTraits<TmpType>::default_accessor(), d,
dest ); | | // typename AccessorTraits<TmpType>::default_accessor(), d,
dest ); | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest,
sigma ); | | detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest,
sigmas ); | |
| } | | } | |
| | | | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void multiGrayscaleErosion( | | void multiGrayscaleErosion( | |
| triple<SrcIterator, SrcShape, SrcAccessor> const & source, | | triple<SrcIterator, SrcShape, SrcAccessor> const & source, | |
|
| pair<DestIterator, DestAccessor> const & dest, float sigma) | | pair<DestIterator, DestAccessor> const & dest, double sigma) | |
| { | | { | |
| multiGrayscaleErosion( source.first, source.second, source.third, | | multiGrayscaleErosion( source.first, source.second, source.third, | |
| dest.first, dest.second, sigma); | | dest.first, dest.second, sigma); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* multiGrayscaleDilation */ | | /* multiGrayscaleDilation */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| skipping to change at line 453 | | skipping to change at line 485 | |
| | | | |
| <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 | |
| multiGrayscaleDilation(SrcIterator siter, SrcShape const & shape, S
rcAccessor src, | | multiGrayscaleDilation(SrcIterator siter, SrcShape const & shape, S
rcAccessor src, | |
|
| DestIterator diter, DestAccessor dest,
float sigma); | | DestIterator diter, DestAccessor dest,
double sigma); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void | | void | |
| multiGrayscaleDilation(triple<SrcIterator, SrcShape, SrcAccessor> c
onst & source, | | multiGrayscaleDilation(triple<SrcIterator, SrcShape, SrcAccessor> c
onst & source, | |
| pair<DestIterator, DestAccessor> const
& dest, | | pair<DestIterator, DestAccessor> const
& dest, | |
|
| float sigma); | | double sigma); | |
| | | | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m
ulti_morphology.hxx</a>\> | | <b>\#include</b> \<<a href="multi__morphology_8hxx-source.html">vigra/m
ulti_morphology.hxx</a>\> | |
| | | | |
| \code | | \code | |
| MultiArray<3, unsigned char>::size_type shape(width, height, depth); | | MultiArray<3, unsigned char>::size_type shape(width, height, depth); | |
| | | | |
| skipping to change at line 492 | | skipping to change at line 524 | |
| multiGrayscaleDilation(srcMultiArrayRange(source), destMultiArray(dest)
, 3.0); | | multiGrayscaleDilation(srcMultiArrayRange(source), destMultiArray(dest)
, 3.0); | |
| \endcode | | \endcode | |
| | | | |
| \see vigra::discErosion() | | \see vigra::discErosion() | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void multiGrayscaleDilation) | | doxygen_overloaded_function(template <...> void multiGrayscaleDilation) | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void multiGrayscaleDilation( SrcIterator s, SrcShape const & shape, SrcAcce
ssor src, | | void multiGrayscaleDilation( SrcIterator s, SrcShape const & shape, SrcAcce
ssor src, | |
|
| DestIterator d, DestAccessor dest, float sigma
) | | DestIterator d, DestAccessor dest, double sigm
a) | |
| { | | { | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Valu
eType DestType; | | typedef typename NumericTraits<typename DestAccessor::value_type>::Valu
eType DestType; | |
| typedef typename NumericTraits<typename DestAccessor::value_type>::Prom
ote TmpType; | | typedef typename NumericTraits<typename DestAccessor::value_type>::Prom
ote TmpType; | |
| DestType MinValue = NumericTraits<DestType>::min(); | | DestType MinValue = NumericTraits<DestType>::min(); | |
| DestType MaxValue = NumericTraits<DestType>::max(); | | DestType MaxValue = NumericTraits<DestType>::max(); | |
| enum { N = 1 + SrcIterator::level }; | | enum { N = 1 + SrcIterator::level }; | |
| | | | |
| // temporay array to hold the current line to enable in-place operation | | // temporay array to hold the current line to enable in-place operation | |
| ArrayVector<TmpType> tmp( shape[0] ); | | ArrayVector<TmpType> tmp( shape[0] ); | |
| | | | |
| typedef MultiArrayNavigator<SrcIterator, N> SNavigator; | | typedef MultiArrayNavigator<SrcIterator, N> SNavigator; | |
| typedef MultiArrayNavigator<DestIterator, N> DNavigator; | | typedef MultiArrayNavigator<DestIterator, N> DNavigator; | |
| | | | |
| int MaxDim = 0; | | int MaxDim = 0; | |
| for( int i=0; i<N; i++) | | for( int i=0; i<N; i++) | |
| if(MaxDim < shape[i]) MaxDim = shape[i]; | | if(MaxDim < shape[i]) MaxDim = shape[i]; | |
| | | | |
| using namespace vigra::functor; | | using namespace vigra::functor; | |
| | | | |
|
| | | ArrayVector<double> sigmas(shape.size(), sigma); | |
| | | | |
| // Allocate a new temporary array if the distances squared wouldn't fit | | // Allocate a new temporary array if the distances squared wouldn't fit | |
| if(-N*MaxDim*MaxDim < MinValue || N*MaxDim*MaxDim > MaxValue) | | if(-N*MaxDim*MaxDim < MinValue || N*MaxDim*MaxDim > MaxValue) | |
| { | | { | |
| MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | | MultiArray<SrcShape::static_size, TmpType> tmpArray(shape); | |
| | | | |
| detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArray
.traverser_begin(), | | detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArray
.traverser_begin(), | |
|
| typename AccessorTraits<TmpType>::default_accessor(), sigma, tr
ue ); | | typename AccessorTraits<TmpType>::default_accessor(), sigmas, t
rue ); | |
| | | | |
| transformMultiArray( tmpArray.traverser_begin(), shape, | | transformMultiArray( tmpArray.traverser_begin(), shape, | |
| typename AccessorTraits<TmpType>::default_accessor(), d, de
st, | | typename AccessorTraits<TmpType>::default_accessor(), d, de
st, | |
| ifThenElse( Arg1() > Param(MaxValue), Param(MaxValue), | | ifThenElse( Arg1() > Param(MaxValue), Param(MaxValue), | |
| ifThenElse( Arg1() < Param(MinValue), Param(MinValue),
Arg1() ) ) ); | | ifThenElse( Arg1() < Param(MinValue), Param(MinValue),
Arg1() ) ) ); | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest,
sigma, true ); | | detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest,
sigmas, true ); | |
| } | | } | |
| | | | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void multiGrayscaleDilation( | | void multiGrayscaleDilation( | |
| triple<SrcIterator, SrcShape, SrcAccessor> const & source, | | triple<SrcIterator, SrcShape, SrcAccessor> const & source, | |
|
| pair<DestIterator, DestAccessor> const & dest, float sigma) | | pair<DestIterator, DestAccessor> const & dest, double sigma) | |
| { | | { | |
| multiGrayscaleDilation( source.first, source.second, source.third, | | multiGrayscaleDilation( source.first, source.second, source.third, | |
| dest.first, dest.second, sigma); | | dest.first, dest.second, sigma); | |
| } | | } | |
| | | | |
| //@} | | //@} | |
| | | | |
| } //-- namespace vigra | | } //-- namespace vigra | |
| | | | |
| #endif //-- VIGRA_MULTI_MORPHOLOGY_HXX | | #endif //-- VIGRA_MULTI_MORPHOLOGY_HXX | |
| | | | |
End of changes. 36 change blocks. |
| 116 lines changed or deleted | | 151 lines changed or added | |
|
| regression.hxx | | regression.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2008 by Ullrich Koethe */ | | /* Copyright 2008 by Ullrich Koethe */ | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 52 | | skipping to change at line 51 | |
| #include "singular_value_decomposition.hxx" | | #include "singular_value_decomposition.hxx" | |
| #include "numerictraits.hxx" | | #include "numerictraits.hxx" | |
| #include "functorexpression.hxx" | | #include "functorexpression.hxx" | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
| namespace linalg | | namespace linalg | |
| { | | { | |
| | | | |
|
| /** \addtogroup MatrixAlgebra | | /** \addtogroup Optimization Optimization and Regression | |
| */ | | */ | |
| //@{ | | //@{ | |
| /** Ordinary Least Squares Regression. | | /** Ordinary Least Squares Regression. | |
| | | | |
| Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | | Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | |
| and a column vector \a b of length <tt>m</tt> rows, this function co
mputes | | and a column vector \a b of length <tt>m</tt> rows, this function co
mputes | |
|
| a column vector \a x of length <tt>n</tt> rows such that the residua
l | | the column vector \a x of length <tt>n</tt> rows that solves the opt
imization problem | |
| | | | |
|
| \f[ \left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right|^2 | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| | | \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\righ | |
| | | t|\right|_2^2 | |
| \f] | | \f] | |
| | | | |
|
| is minimized. When \a b is a matrix with <tt>k</tt> columns, \a x mu
st 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 | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| on_8hxx.hxx</a>\> or<br> | | on.hxx</a>\> | |
| <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 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); | |
| } | | } | |
| | | | |
| /** Weighted Least Squares Regression. | | /** Weighted Least Squares Regression. | |
| | | | |
| Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | | Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | |
| a vector \a b of length <tt>m</tt>, and a weight vector \a weights o
f length <tt>m</tt> | | a vector \a b of length <tt>m</tt>, and a weight vector \a weights o
f length <tt>m</tt> | |
|
| with non-negative entries, this function computes a vector \a x of l | | with non-negative entries, this function computes the vector \a x of | |
| ength <tt>n</tt> | | length <tt>n</tt> | |
| such that the weighted residual | | that solves the optimization problem | |
| | | | |
|
| \f[ \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right)^T | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| | | \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right)^T | |
| \textrm{diag}(\textrm{\bf weights}) | | \textrm{diag}(\textrm{\bf weights}) | |
| \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right) | | \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right) | |
| \f] | | \f] | |
| | | | |
|
| is minimized, where <tt>diag(weights)</tt> creates a diagonal matrix
from \a weights. | | where <tt>diag(weights)</tt> creates a diagonal matrix from \a weigh
ts. | |
| The algorithm calls \ref leastSquares() on the equivalent problem | | The algorithm calls \ref leastSquares() on the equivalent problem | |
| | | | |
|
| \f[ \left|\textrm{diag}(\textrm{\bf weights})^{1/2}\textrm{\bf A} \ | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| textrm{\bf x} - | | \left|\left|\textrm{diag}(\textrm{\bf weights})^{1/2}\textrm{\ | |
| \textrm{diag}(\textrm{\bf weights})^{1/2} \textrm{\bf b}\ | | bf A} \textrm{\bf x} - | |
| right|^2 | | \textrm{diag}(\textrm{\bf weights})^{1/2} \textrm{\bf b}\ | |
| | | right|\right|_2^2 | |
| \f] | | \f] | |
| | | | |
| 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 | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| on.hxx</a>\> or<br> | | on.hxx</a>\> | |
| <b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin | | | |
| ear_algebra.hxx</a>\><br> | | | |
| Namespaces: vigra and vigra::linalg | | Namespaces: vigra and vigra::linalg | |
| */ | | */ | |
| template <class T, class C1, class C2, class C3, class C4> | | template <class T, class C1, class C2, class C3, class C4> | |
| 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 158 | | skipping to change at line 158 | |
| wb(k,l) = w * b(k,l); | | wb(k,l) = w * b(k,l); | |
| } | | } | |
| | | | |
| return leastSquares(wa, wb, x, method); | | return leastSquares(wa, wb, x, method); | |
| } | | } | |
| | | | |
| /** Ridge Regression. | | /** Ridge Regression. | |
| | | | |
| Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | | Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | |
| a vector \a b of length <tt>m</tt>, and a regularization parameter <
tt>lambda \>= 0.0</tt>, | | a vector \a b of length <tt>m</tt>, and a regularization parameter <
tt>lambda \>= 0.0</tt>, | |
|
| this function computes a vector \a x of length <tt>n</tt> such that | | this function computes the vector \a x of length <tt>n</tt> | |
| the residual | | that solves the optimization problem | |
| | | | |
|
| \f[ \left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right|^2 + | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| | | \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\righ | |
| | | t|\right|_2^2 + | |
| \lambda \textrm{\bf x}^T\textrm{\bf x} | | \lambda \textrm{\bf x}^T\textrm{\bf x} | |
| \f] | | \f] | |
| | | | |
|
| is minimized. This is implemented by means of \ref singularValueDeco
mposition(). | | 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 | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| on.hxx</a>\> or<br> | | on.hxx</a>\> | |
| <b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin | | | |
| ear_algebra.hxx</a>\><br> | | | |
| Namespaces: vigra and vigra::linalg | | Namespaces: vigra and vigra::linalg | |
| */ | | */ | |
| template <class T, class C1, class C2, class C3> | | template <class T, class C1, class C2, class C3> | |
| bool | | bool | |
| 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 218 | | skipping to change at line 219 | |
| 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; | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| /** Weighted ridge Regression. | | /** Weighted ridge Regression. | |
| | | | |
| Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | | Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit
h <tt>m \>= n</tt>), | |
| a vector \a b of length <tt>m</tt>, a weight vector \a weights of le
ngth <tt>m</tt> | | a vector \a b of length <tt>m</tt>, a weight vector \a weights of le
ngth <tt>m</tt> | |
| with non-negative entries, and a regularization parameter <tt>lambda
>= 0.0</tt> | | with non-negative entries, and a regularization parameter <tt>lambda
>= 0.0</tt> | |
|
| this function computes a vector \a x of length <tt>n</tt> such that | | this function computes the vector \a x of length <tt>n</tt> | |
| the weighted residual | | that solves the optimization problem | |
| | | | |
|
| \f[ \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right)^T | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| | | \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right)^T | |
| \textrm{diag}(\textrm{\bf weights}) | | \textrm{diag}(\textrm{\bf weights}) | |
| \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right) + | | \left(\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right) + | |
| \lambda \textrm{\bf x}^T\textrm{\bf x} | | \lambda \textrm{\bf x}^T\textrm{\bf x} | |
| \f] | | \f] | |
| | | | |
|
| is minimized, where <tt>diag(weights)</tt> creates a diagonal matrix
from \a weights. | | where <tt>diag(weights)</tt> creates a diagonal matrix from \a weigh
ts. | |
| The algorithm calls \ref ridgeRegression() on the equivalent problem | | The algorithm calls \ref ridgeRegression() on the equivalent problem | |
| | | | |
|
| \f[ \left|\textrm{diag}(\textrm{\bf weights})^{1/2}\textrm{\bf A} \ | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| textrm{\bf x} - | | \left|\left|\textrm{diag}(\textrm{\bf weights})^{1/2}\textrm{\b | |
| \textrm{diag}(\textrm{\bf weights})^{1/2} \textrm{\bf b}\ | | f A} \textrm{\bf x} - | |
| right|^2 + | | \textrm{diag}(\textrm{\bf weights})^{1/2} \textrm{\bf b}\ | |
| | | right|\right|_2^2 + | |
| \lambda \textrm{\bf x}^T\textrm{\bf x} | | \lambda \textrm{\bf x}^T\textrm{\bf x} | |
| \f] | | \f] | |
| | | | |
| 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 | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| on.hxx</a>\> or<br> | | on.hxx</a>\> | |
| <b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin | | | |
| ear_algebra.hxx</a>\><br> | | | |
| Namespaces: vigra and vigra::linalg | | Namespaces: vigra and vigra::linalg | |
| */ | | */ | |
| template <class T, class C1, class C2, class C3, class C4> | | template <class T, class C1, class C2, class C3, class C4> | |
| 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 299 | | 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 | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| on.hxx</a>\> or<br> | | on.hxx</a>\> | |
| <b>\#include</b> \<<a href="linear__algebra_8hxx-source.html">vigra/lin | | | |
| ear_algebra.hxx</a>\><br> | | | |
| Namespaces: vigra and vigra::linalg | | Namespaces: vigra and vigra::linalg | |
| */ | | */ | |
| template <class T, class C1, class C2, class C3, class 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 333 | | skipping to change at line 335 | |
| 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 == 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(). | |
| | | | |
| | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| | | on.hxx</a>\> | |
| | | Namespaces: vigra and vigra::linalg | |
| | | */ | |
| | | class LeastAngleRegressionOptions | |
| | | { | |
| | | public: | |
| | | enum Mode { LARS, LASSO, NNLASSO }; | |
| | | | |
| | | /** Initialize all options with default values. | |
| | | */ | |
| | | LeastAngleRegressionOptions() | |
| | | : max_solution_count(0), | |
| | | unconstrained_dimension_count(0), | |
| | | mode(LASSO), | |
| | | least_squares_solutions(true) | |
| | | {} | |
| | | | |
| | | /** Maximum number of solutions to be computed. | |
| | | | |
| | | If \a n is 0 (the default), the number of solutions is determin | |
| | | ed by the length | |
| | | of the solution array. Otherwise, the minimum of maxSolutionCou | |
| | | nt() and that | |
| | | length is taken.<br> | |
| | | Default: 0 (use length of solution array) | |
| | | */ | |
| | | LeastAngleRegressionOptions & maxSolutionCount(unsigned int n) | |
| | | { | |
| | | max_solution_count = (int)n; | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Set the mode of the algorithm. | |
| | | | |
| | | Mode must be one of "lars", "lasso", "nnlasso". The function ju | |
| | | st calls | |
| | | the member function of the corresponding name to set the mode. | |
| | | | |
| | | Default: "lasso" | |
| | | */ | |
| | | LeastAngleRegressionOptions & setMode(std::string mode) | |
| | | { | |
| | | for(unsigned int k=0; k<mode.size(); ++k) | |
| | | mode[k] = (std::string::value_type)tolower(mode[k]); | |
| | | if(mode == "lars") | |
| | | this->lars(); | |
| | | else if(mode == "lasso") | |
| | | this->lasso(); | |
| | | else if(mode == "nnlasso") | |
| | | this->nnlasso(); | |
| | | else | |
| | | vigra_fail("LeastAngleRegressionOptions.setMode(): Invalid mode | |
| | | ."); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Use the plain LARS algorithm. | |
| | | | |
| | | Default: inactive | |
| | | */ | |
| | | LeastAngleRegressionOptions & lars() | |
| | | { | |
| | | mode = LARS; | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Use the LASSO modification of the LARS algorithm. | |
| | | | |
| | | This allows features to be removed from the active set under ce | |
| | | rtain conditions.<br> | |
| | | Default: active | |
| | | */ | |
| | | LeastAngleRegressionOptions & lasso() | |
| | | { | |
| | | mode = LASSO; | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Use the non-negative LASSO modification of the LARS algorithm. | |
| | | | |
| | | This enforces all non-zero entries in the solution to be positi | |
| | | ve.<br> | |
| | | Default: inactive | |
| | | */ | |
| | | LeastAngleRegressionOptions & nnlasso() | |
| | | { | |
| | | mode = NNLASSO; | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Compute least squares solutions. | |
| | | | |
| | | Use least angle regression to determine active sets, but | |
| | | return least squares solutions for the features in each active | |
| | | set, | |
| | | instead of constrained solutions.<br> | |
| | | Default: <tt>true</tt> | |
| | | */ | |
| | | LeastAngleRegressionOptions & leastSquaresSolutions(bool select = true) | |
| | | { | |
| | | least_squares_solutions = select; | |
| | | return *this; | |
| | | } | |
| | | | |
| | | int max_solution_count, unconstrained_dimension_count; | |
| | | Mode mode; | |
| | | bool least_squares_solutions; | |
| | | }; | |
| | | | |
| | | namespace detail { | |
| | | | |
| | | template <class T, class C1, class C2> | |
| | | struct LarsData | |
| | | { | |
| | | typedef typename MultiArrayShape<2>::type Shape; | |
| | | | |
| | | int activeSetSize; | |
| | | MultiArrayView<2, T, C1> A; | |
| | | MultiArrayView<2, T, C2> b; | |
| | | Matrix<T> R, qtb, lars_solution, lars_prediction, next_lsq_solution, ne | |
| | | xt_lsq_prediction, searchVector; | |
| | | ArrayVector<MultiArrayIndex> columnPermutation; | |
| | | | |
| | | // init data for a new run | |
| | | LarsData(MultiArrayView<2, T, C1> const & Ai, MultiArrayView<2, T, C2> | |
| | | const & bi) | |
| | | : activeSetSize(1), | |
| | | A(Ai), b(bi), R(A), qtb(b), | |
| | | lars_solution(A.shape(1), 1), lars_prediction(A.shape(0), 1), | |
| | | next_lsq_solution(A.shape(1), 1), next_lsq_prediction(A.shape(0), 1), | |
| | | searchVector(A.shape(0), 1), | |
| | | columnPermutation(A.shape(1)) | |
| | | { | |
| | | for(unsigned int k=0; k<columnPermutation.size(); ++k) | |
| | | columnPermutation[k] = k; | |
| | | } | |
| | | | |
| | | // copy data for the recursive call in nnlassolsq | |
| | | LarsData(LarsData const & d, int asetSize) | |
| | | : activeSetSize(asetSize), | |
| | | A(d.R.subarray(Shape(0,0), Shape(d.A.shape(0), activeSetSize))), b(d. | |
| | | qtb), R(A), qtb(b), | |
| | | lars_solution(d.lars_solution.subarray(Shape(0,0), Shape(activeSetSiz | |
| | | e, 1))), lars_prediction(d.lars_prediction), | |
| | | next_lsq_solution(d.next_lsq_solution.subarray(Shape(0,0), Shape(acti | |
| | | veSetSize, 1))), | |
| | | next_lsq_prediction(d.next_lsq_prediction), searchVector(d.searchVect | |
| | | or), | |
| | | columnPermutation(A.shape(1)) | |
| | | { | |
| | | for(unsigned int k=0; k<columnPermutation.size(); ++k) | |
| | | columnPermutation[k] = k; | |
| | | } | |
| | | }; | |
| | | | |
| | | 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> 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 | |
| | | | |
| | | // In theory, all vectors in the active set should have the same co | |
| | | rrelation C, and | |
| | | // the correlation of all others should not exceed this. In practic | |
| | | e, we may find the | |
| | | // 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(cLARS) | |
| | | : argMax(abs(cLARS)); | |
| | | T C = abs(cLARS(cmaxIndex, 0)); | |
| | | | |
| | | Matrix<T> ac(cols - d.activeSetSize, 1); | |
| | | for(MultiArrayIndex k = 0; k<cols-d.activeSetSize; ++k) | |
| | | { | |
| | | T rho = cLSQ(inactiveSet[k], 0), | |
| | | cc = C - sign(rho)*cLARS(inactiveSet[k], 0); | |
| | | | |
| | | if(rho == 0.0) // make sure that 0/0 cannot happen in the othe | |
| | | r cases | |
| | | ac(k,0) = 1.0; // variable k is linearly dependent on the a | |
| | | ctive set | |
| | | else if(rho > 0.0) | |
| | | ac(k,0) = cc / (cc + rho); // variable k would enter the ac | |
| | | tive set with positive sign | |
| | | else if(enforce_positive) | |
| | | ac(k,0) = 1.0; // variable k cannot enter the active set be | |
| | | cause it would be negative | |
| | | else | |
| | | ac(k,0) = cc / (cc - rho); // variable k would enter the ac | |
| | | tive set with negative sign | |
| | | } | |
| | | | |
| | | // 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 = argMin(ac); | |
| | | | |
| | | // 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 = (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)); | |
| | | if(columnToBeRemoved >= 0) | |
| | | { | |
| | | needToRemoveColumn = true; // remove takes precedence over | |
| | | add | |
| | | gamma = s(columnToBeRemoved, 0); | |
| | | } | |
| | | } | |
| | | | |
| | | // compute the current solutions | |
| | | d.lars_prediction = gamma * d.next_lsq_prediction + (1.0 - gamma) | |
| | | * d.lars_prediction; | |
| | | 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 | |
| | | d.next_lsq_prediction.init(0.0); | |
| | | 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]); | |
| | | } | |
| | | | |
| | | 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> | |
| | | unsigned int | |
| | | leastAngleRegressionImpl(MultiArrayView<2, T, C1> const & A, MultiArrayView | |
| | | <2, T, C2> const &b, | |
| | | Array1 & activeSets, Array2 * lasso_solutions, Arr | |
| | | ay2 * lsq_solutions, | |
| | | LeastAngleRegressionOptions const & options) | |
| | | { | |
| | | using namespace vigra::functor; | |
| | | | |
| | | const MultiArrayIndex rows = rowCount(A); | |
| | | | |
| | | vigra_precondition(rowCount(b) == rows && columnCount(b) == 1, | |
| | | "leastAngleRegression(): Shape mismatch between matrices A and b."); | |
| | | | |
| | | bool enforce_positive = (options.mode == LeastAngleRegressionOptions::N | |
| | | NLASSO); | |
| | | | |
| | | detail::LarsData<T, C1, C2> d(A, b); | |
| | | | |
| | | // find dimension with largest correlation | |
| | | Matrix<T> c = transpose(A)*b; | |
| | | MultiArrayIndex initialColumn = enforce_positive | |
| | | ? argMaxIf(c, Arg1() > Param(0.0)) | |
| | | : argMax(abs(c)); | |
| | | if(initialColumn == -1) | |
| | | return 0; // no solution found | |
| | | | |
| | | // prepare initial active set and search direction etc. | |
| | | std::swap(d.columnPermutation[0], d.columnPermutation[initialColumn]); | |
| | | columnVector(d.R, 0).swapData(columnVector(d.R, initialColumn)); | |
| | | detail::qrColumnHouseholderStep(0, d.R, d.qtb); | |
| | | d.next_lsq_solution(0,0) = d.qtb(0,0) / d.R(0,0); | |
| | | d.next_lsq_prediction = d.next_lsq_solution(0,0) * columnVector(A, d.co | |
| | | lumnPermutation[0]); | |
| | | d.searchVector = d.next_lsq_solution(0,0) * columnVector(A, d.columnPer | |
| | | mutation[0]); | |
| | | | |
| | | return leastAngleRegressionMainLoop(d, activeSets, lasso_solutions, lsq | |
| | | _solutions, options); | |
| | | } | |
| | | | |
| | | } // namespace detail | |
| | | | |
| | | /** Least Angle Regression. | |
| | | | |
| | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| | | on.hxx</a>\> | |
| | | Namespaces: vigra and vigra::linalg | |
| | | | |
| | | <b> Declarations:</b> | |
| | | | |
| | | \code | |
| | | namespace vigra { | |
| | | namespace linalg { | |
| | | // compute either LASSO or least sqaures solutions | |
| | | template <class T, class C1, class C2, class Array1, class Array2> | |
| | | unsigned int | |
| | | leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray | |
| | | View<2, T, C2> const &b, | |
| | | Array1 & activeSets, Array2 & solutions, | |
| | | LeastAngleRegressionOptions const & options = | |
| | | LeastAngleRegressionOptions()); | |
| | | | |
| | | // compute LASSO and least sqaures solutions | |
| | | template <class T, class C1, class C2, class Array1, class Array2> | |
| | | unsigned int | |
| | | leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArray | |
| | | View<2, T, C2> const &b, | |
| | | Array1 & activeSets, Array2 & lasso_solutions, | |
| | | Array2 & lsq_solutions, | |
| | | LeastAngleRegressionOptions const & options = | |
| | | LeastAngleRegressionOptions()); | |
| | | } | |
| | | using linalg::leastAngleRegression; | |
| | | } | |
| | | \endcode | |
| | | | |
| | | This function implements Least Angle Regression (LARS) as described | |
| | | in | |
| | | | |
| | | | |
| | | B.Efron, T.Hastie, I.Johnstone, and R.Tibshirani: <em>"Least Angle R | |
| | | egression"</em>, | |
| | | Annals of Statistics 32(2):407-499, 2004. | |
| | | | |
| | | It is an efficient algorithm to solve the L1-regularized least squar | |
| | | es (LASSO) problem | |
| | | | |
| | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| | | \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\rig | |
| | | ht|\right|_2^2 | |
| | | \textrm{ subject to } \left|\left|\textrm{\bf x}\right|\right|_1 | |
| | | \le s | |
| | | \f] | |
| | | | |
| | | and the L1-regularized non-negative least squares (NN-LASSO) problem | |
| | | | |
| | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} \left|\left|\textrm{\bf | |
| | | A} \textrm{\bf x} - \textrm{\bf b}\right|\right|_2^2 | |
| | | \textrm{ subject to } \left|\left|\textrm{\bf x}\right|\right|_1 | |
| | | \le s \textrm{ and } \textrm{\bf x}\ge \textrm{\bf 0} | |
| | | \f] | |
| | | | |
| | | where \a A is a matrix with <tt>m</tt> rows and <tt>n</tt> columns ( | |
| | | often with <tt>m \< n</tt>), | |
| | | \a b a vector of length <tt>m</tt>, and a regularization parameter s | |
| | | \>= 0.0. | |
| | | L1-regularization has the desirable effect that it causes the soluti | |
| | | on \a x to be sparse, i.e. only | |
| | | the most important variables (called the <em>active set</em>) have n | |
| | | on-zero values. The | |
| | | key insight of the LARS algorithm is the following: When the solutio | |
| | | n vector is considered | |
| | | as a function of the regularization parameter s, then <b>x</b>(s) is | |
| | | a piecewise | |
| | | linear function, i.e. a polyline in n-dimensional space. The knots o | |
| | | f the polyline | |
| | | occur precisely at those values of s where one variable enters or le | |
| | | aves the active set, | |
| | | and can be efficiently computed. | |
| | | | |
| | | Therefore, leastAngleRegression() returns the entire solution path a | |
| | | s a sequence of knot points, starting | |
| | | at \f$\textrm{\bf x}(s=0)\f$ (where the only feasible solution is ob | |
| | | viously <b>x</b> = 0) and ending at | |
| | | \f$\textrm{\bf x}(s=\infty)\f$ (where the solution becomes the ordin | |
| | | ary least squares solution). Actually, | |
| | | the initial null solution is not explicitly returned, i.e. the seque | |
| | | nce starts at the first non-zero | |
| | | solution with one variable in the active set. The function leastAngl | |
| | | eRegression() returns the number | |
| | | of solutions( i.e. knot points) computed. | |
| | | | |
| | | The sequences of active sets and corresponding variable weights are | |
| | | returned in \a activeSets and | |
| | | \a solutions respectively. That is, <tt>activeSets[i]</tt> is an \re | |
| | | f vigra::ArrayVector "ArrayVector\<int\>" | |
| | | containing the indices of the variables that are active at the i-th | |
| | | knot, and <tt>solutions</tt> is a | |
| | | \ref vigra::linalg::Matrix "Matrix\<T\>" containing the weights of t | |
| | | hose variables, in the same order (see | |
| | | example below). Variables not contained in <tt>activeSets[i]</tt> ar | |
| | | e zero at this solution. | |
| | | | |
| | | The behavior of the algorithm can be adapted by \ref vigra::linalg:: | |
| | | LeastAngleRegressionOptions | |
| | | "LeastAngleRegressionOptions": | |
| | | <DL> | |
| | | <DT><b>options.lasso()</b> (active by default) | |
| | | <DD> Compute the LASSO solution as described abov | |
| | | e. | |
| | | <DT><b>options.nnlasso()</b> (inactive by default) | |
| | | <DD> Compute non-negative LASSO solutions, i.e. u | |
| | | se the additional constraint that | |
| | | <b>x</b> \>= 0 in all solutions. | |
| | | <DT><b>options.lars()</b> (inactive by default) | |
| | | <DD> Compute a solution path according to the pla | |
| | | in LARS rule, i.e. never remove | |
| | | a variable from the active set once it enter | |
| | | ed. | |
| | | <DT><b>options.leastSquaresSolutions(bool)</b> (default: true) | |
| | | <DD> Use the algorithm mode selected above | |
| | | to determine the sequence of active sets, bu | |
| | | t then compute and return an | |
| | | ordinary (unconstrained) least squares solut | |
| | | ion for every active set.<br> | |
| | | <b>Note:</b> The second form of leastAngleRe | |
| | | gression() ignores this option and | |
| | | does always compute both constrained and unc | |
| | | onstrained solutions (returned in | |
| | | \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) | |
| | | <DD> Compute at most <tt>n</tt> solutions. | |
| | | </DL> | |
| | | | |
| | | <b>Usage:</b> | |
| | | | |
| | | \code | |
| | | int m = ..., n = ...; | |
| | | Matrix<double> A(m, n), b(m, 1); | |
| | | ... // fill A and b | |
| | | | |
| | | // normalize the input | |
| | | Matrix<double> offset(1,n), scaling(1,n); | |
| | | prepareColumns(A, A, offset, scaling, DataPreparationGoals(ZeroM | |
| | | ean|UnitVariance)); | |
| | | prepareColumns(b, b, DataPreparationGoals(ZeroMean)); | |
| | | | |
| | | // arrays to hold the output | |
| | | ArrayVector<ArrayVector<int> > activeSets; | |
| | | ArrayVector<Matrix<double> > solutions; | |
| | | | |
| | | // run leastAngleRegression() in non-negative LASSO mode | |
| | | int numSolutions = leastAngleRegression(A, b, activeSets, soluti | |
| | | ons, | |
| | | LeastAngleRegressionOptions().nnlass | |
| | | o()); | |
| | | | |
| | | // print results | |
| | | Matrix<double> denseSolution(1, n); | |
| | | for (MultiArrayIndex k = 0; k < numSolutions; ++k) | |
| | | { | |
| | | // transform the sparse solution into a dense vector | |
| | | denseSolution.init(0.0); // ensure that inactive variabl | |
| | | es are zero | |
| | | for (unsigned int i = 0; i < activeSets[k].size(); ++i) | |
| | | { | |
| | | // set the values of the active variables; | |
| | | // activeSets[k][i] is the true index of the i-t | |
| | | h variable in the active set | |
| | | denseSolution(0, activeSets[k][i]) = solutions[k | |
| | | ](i,0); | |
| | | } | |
| | | | |
| | | // invert the input normalization | |
| | | denseSolution = denseSolution * pointWise(scaling); | |
| | | | |
| | | // output the solution | |
| | | std::cout << "solution " << k << ":\n" << denseSolution << std: | |
| | | :endl; | |
| | | } | |
| | | \endcode | |
| | | | |
| | | <b>Required Interface:</b> | |
| | | | |
| | | <ul> | |
| | | <li> <tt>T</tt> must be numeric type (compatible to double) | |
| | | <li> <tt>Array1 a1;</tt><br> | |
| | | <tt>a1.push_back(ArrayVector\<int\>());</tt> | |
| | | <li> <tt>Array2 a2;</tt><br> | |
| | | <tt>a2.push_back(Matrix\<T\>());</tt> | |
| | | </ul> | |
| | | */ | |
| | | doxygen_overloaded_function(template <...> unsigned int leastAngleRegressio | |
| | | n) | |
| | | | |
| | | template <class T, class C1, class C2, class Array1, class Array2> | |
| | | inline unsigned int | |
| | | leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, | |
| | | T, C2> const &b, | |
| | | Array1 & activeSets, Array2 & solutions, | |
| | | LeastAngleRegressionOptions const & options = LeastAng | |
| | | leRegressionOptions()) | |
| | | { | |
| | | if(options.least_squares_solutions) | |
| | | return detail::leastAngleRegressionImpl(A, b, activeSets, (Array2*) | |
| | | 0, &solutions, options); | |
| | | else | |
| | | return detail::leastAngleRegressionImpl(A, b, activeSets, &solution | |
| | | s, (Array2*)0, options); | |
| | | } | |
| | | | |
| | | template <class T, class C1, class C2, class Array1, class Array2> | |
| | | inline unsigned int | |
| | | leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, | |
| | | T, C2> const &b, | |
| | | Array1 & activeSets, Array2 & lasso_solutions, Array2 | |
| | | & lsq_solutions, | |
| | | LeastAngleRegressionOptions const & options = LeastAng | |
| | | leRegressionOptions()) | |
| | | { | |
| | | return detail::leastAngleRegressionImpl(A, b, activeSets, &lasso_soluti | |
| | | ons, &lsq_solutions, options); | |
| | | } | |
| | | | |
| | | /** Non-negative Least Squares Regression. | |
| | | | |
| | | Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (wit | |
| | | h <tt>m \>= n</tt>), | |
| | | and a column vector \a b of length <tt>m</tt> rows, this function co | |
| | | mputes | |
| | | a column vector \a x of length <tt>n</tt> with <b>non-negative entri | |
| | | es</b> that solves the optimization problem | |
| | | | |
| | | \f[ \tilde \textrm{\bf x} = \textrm{argmin} | |
| | | \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} | |
| | | \f] | |
| | | | |
| | | 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 | |
| | | of \ref leastAngleRegression() with non-negativity constraint. | |
| | | | |
| | | <b>\#include</b> \<<a href="regression_8hxx-source.html">vigra/regressi | |
| | | on.hxx</a>\> | |
| | | Namespaces: vigra and vigra::linalg | |
| | | */ | |
| | | template <class T, class C1, class C2, class C3> | |
| | | inline void | |
| | | nonnegativeLeastSquares(MultiArrayView<2, T, C1> const & A, | |
| | | MultiArrayView<2, T, C2> const &b, MultiArrayView<2 | |
| | | , T, C3> &x) | |
| | | { | |
| | | vigra_precondition(columnCount(A) == rowCount(x) && rowCount(A) == r | |
| | | owCount(b), | |
| | | "nonnegativeLeastSquares(): Matrix shape mismatch."); | |
| | | vigra_precondition(columnCount(b) == 1 && columnCount(x) == 1, | |
| | | "nonnegativeLeastSquares(): RHS and solution must be vectors (i. | |
| | | e. columnCount == 1)."); | |
| | | | |
| | | ArrayVector<ArrayVector<MultiArrayIndex> > activeSets; | |
| | | ArrayVector<Matrix<T> > results; | |
| | | | |
| | | leastAngleRegression(A, b, activeSets, results, | |
| | | LeastAngleRegressionOptions().leastSquaresSolution | |
| | | s(false).nnlasso()); | |
| | | x.init(NumericTraits<T>::zero()); | |
| | | if(activeSets.size() > 0) | |
| | | for(unsigned int k=0; k<activeSets.back().size(); ++k) | |
| | | x(activeSets.back()[k],0) = results.back()[k]; | |
| | | } | |
| | | | |
| | | //@} | |
| | | | |
| } // namespace linalg | | } // namespace linalg | |
| | | | |
| using linalg::leastSquares; | | using linalg::leastSquares; | |
| using linalg::weightedLeastSquares; | | using linalg::weightedLeastSquares; | |
| using linalg::ridgeRegression; | | using linalg::ridgeRegression; | |
| using linalg::weightedRidgeRegression; | | using linalg::weightedRidgeRegression; | |
| using linalg::ridgeRegressionSeries; | | using linalg::ridgeRegressionSeries; | |
|
| | | using linalg::nonnegativeLeastSquares; | |
| | | using linalg::leastAngleRegression; | |
| | | using linalg::LeastAngleRegressionOptions; | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
| #endif // VIGRA_REGRESSION_HXX | | #endif // VIGRA_REGRESSION_HXX | |
| | | | |
End of changes. 26 change blocks. |
| 49 lines changed or deleted | | 1023 lines changed or added | |
|
| rgbvalue.hxx | | rgbvalue.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 155 | | skipping to change at line 153 | |
| /** STL-compatible definition of const iterator | | /** STL-compatible definition of const iterator | |
| */ | | */ | |
| typedef typename Base::const_iterator const_iterator; | | typedef typename Base::const_iterator const_iterator; | |
| /** squared norm type (result of squaredManitude()) | | /** squared norm type (result of squaredManitude()) | |
| */ | | */ | |
| typedef typename Base::SquaredNormType SquaredNormType; | | typedef typename Base::SquaredNormType SquaredNormType; | |
| /** norm type (result of magnitude()) | | /** norm type (result of magnitude()) | |
| */ | | */ | |
| typedef typename Base::NormType NormType; | | typedef typename Base::NormType NormType; | |
| | | | |
|
| | | typedef typename Base::reference reference; | |
| | | typedef typename Base::const_reference const_reference; | |
| | | typedef typename Base::pointer pointer; | |
| | | typedef typename Base::const_pointer const_pointer; | |
| | | typedef typename Base::size_type size_type; | |
| | | typedef typename Base::difference_type difference_type; | |
| | | typedef typename Base::scalar_multiplier scalar_multiplier; | |
| | | typedef typename Base::ReverseCopyTag ReverseCopyTag; | |
| | | | |
| /** Color index positions | | /** Color index positions | |
| */ | | */ | |
| enum | | enum | |
| { | | { | |
| RedIdx = RED_IDX, | | RedIdx = RED_IDX, | |
| GreenIdx = GREEN_IDX, | | GreenIdx = GREEN_IDX, | |
| BlueIdx = BLUE_IDX | | BlueIdx = BLUE_IDX | |
| }; | | }; | |
| | | | |
| /** Construct from explicit color values. | | /** Construct from explicit color values. | |
| \a first, \a second, \a third are written in this order, | | \a first, \a second, \a third are written in this order, | |
| irrespective of how the color indices are specified. | | irrespective of how the color indices are specified. | |
| */ | | */ | |
| RGBValue(value_type first, value_type second, value_type third) | | RGBValue(value_type first, value_type second, value_type third) | |
| : Base(first, second, third) | | : Base(first, second, third) | |
| { | | { | |
| VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | | VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | |
| } | | } | |
| | | | |
|
| /** Construct gray value | | /** Construct gray value. | |
| */ | | */ | |
| RGBValue(value_type gray) | | RGBValue(value_type gray) | |
| : Base(gray, gray, gray) | | : Base(gray, gray, gray) | |
| { | | { | |
| VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | | VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | |
| } | | } | |
| | | | |
|
| /** Construct from another sequence (must have length 3!) | | /** Copy from raw memory. The order is preserved, | |
| | | irrespective of how the color indices are specified. | |
| */ | | */ | |
|
| template <class Iterator> | | explicit RGBValue(const_pointer i) | |
| RGBValue(Iterator i, Iterator end) | | : Base(i) | |
| : Base(i[0], i[1], i[2]) | | { | |
| | | VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, | |
| | | BLUE_IDX>)); | |
| | | } | |
| | | | |
| | | /** Construct by reverse copying from raw memory. | |
| | | */ | |
| | | RGBValue(const_pointer i, ReverseCopyTag reverse) | |
| | | : Base(i, reverse) | |
| { | | { | |
| VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | | VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | |
| } | | } | |
| | | | |
| /** Default constructor (sets all components to 0) | | /** Default constructor (sets all components to 0) | |
| */ | | */ | |
| RGBValue() | | RGBValue() | |
| : Base(0, 0, 0) | | : Base(0, 0, 0) | |
| { | | { | |
| VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | | VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | |
| } | | } | |
| | | | |
| #if !defined(TEMPLATE_COPY_CONSTRUCTOR_BUG) | | #if !defined(TEMPLATE_COPY_CONSTRUCTOR_BUG) | |
| | | | |
| RGBValue(RGBValue const & r) | | RGBValue(RGBValue const & r) | |
|
| : Base(r) | | : Base((Base const &)r) | |
| { | | { | |
| VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | | VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX,
BLUE_IDX>)); | |
| } | | } | |
| | | | |
| RGBValue & operator=(RGBValue const & r) | | RGBValue & operator=(RGBValue const & r) | |
| { | | { | |
| Base::operator=(r); | | Base::operator=(r); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 257 | | skipping to change at line 272 | |
| RGBValue & operator=(TinyVector<value_type, 3> const & r) | | RGBValue & operator=(TinyVector<value_type, 3> const & r) | |
| { | | { | |
| Base::operator=(r); | | Base::operator=(r); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| /** Unary negation (construct RGBValue with negative values) | | /** Unary negation (construct RGBValue with negative values) | |
| */ | | */ | |
| RGBValue operator-() const | | RGBValue operator-() const | |
| { | | { | |
|
| return RGBValue(-red(), -green(), -blue()); | | return RGBValue(-(*this)[0], -(*this)[1], -(*this)[2]); | |
| } | | } | |
| | | | |
| /** Access red component. | | /** Access red component. | |
| */ | | */ | |
| value_type & red() { return (*this)[RED_IDX]; } | | value_type & red() { return (*this)[RED_IDX]; } | |
| | | | |
| /** Access green component. | | /** Access green component. | |
| */ | | */ | |
| value_type & green() { return (*this)[GREEN_IDX]; } | | value_type & green() { return (*this)[GREEN_IDX]; } | |
| | | | |
| | | | |
| skipping to change at line 509 | | skipping to change at line 524 | |
| { | | { | |
| typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promo
te; | | typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promo
te; | |
| }; | | }; | |
| | | | |
| template <class T, unsigned int R, unsigned int G, unsigned int B> | | template <class T, unsigned int R, unsigned int G, unsigned int B> | |
| struct PromoteTraits<double, RGBValue<T, R, G, B> > | | struct PromoteTraits<double, RGBValue<T, R, G, B> > | |
| { | | { | |
| typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promo
te; | | typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promo
te; | |
| }; | | }; | |
| | | | |
|
| | | template<class T, unsigned int R, unsigned int G, unsigned int B> | |
| | | struct CanSkipInitialization<RGBValue<T, R, G, B> > | |
| | | { | |
| | | typedef typename CanSkipInitialization<T>::type type; | |
| | | static const bool value = type::asBool; | |
| | | }; | |
| | | | |
| #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION | | #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION | |
| | | | |
| #define RGBVALUE_NUMTRAITS(T) \ | | #define RGBVALUE_NUMTRAITS(T) \ | |
| template<>\ | | template<>\ | |
| struct NumericTraits<RGBValue<T, 0, 1, 2> >\ | | struct NumericTraits<RGBValue<T, 0, 1, 2> >\ | |
| {\ | | {\ | |
| typedef RGBValue<T> Type; \ | | typedef RGBValue<T> Type; \ | |
| typedef RGBValue<NumericTraits<T>::Promote> Promote; \ | | typedef RGBValue<NumericTraits<T>::Promote> Promote; \ | |
| typedef RGBValue<NumericTraits<T>::RealPromote> RealPromote; \ | | typedef RGBValue<NumericTraits<T>::RealPromote> RealPromote; \ | |
| typedef RGBValue<NumericTraits<T>::ComplexPromote> ComplexPromote; \ | | typedef RGBValue<NumericTraits<T>::ComplexPromote> ComplexPromote; \ | |
| | | | |
| skipping to change at line 670 | | skipping to change at line 692 | |
| } | | } | |
| | | | |
| /// componentwise multiply-assignment | | /// componentwise multiply-assignment | |
| template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BI
DX1, | | template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BI
DX1, | |
| class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BI
DX2> | | class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BI
DX2> | |
| inline | | inline | |
| RGBValue<V1, RIDX1, GIDX1, BIDX1> & | | RGBValue<V1, RIDX1, GIDX1, BIDX1> & | |
| operator*=(RGBValue<V1, RIDX1, GIDX1, BIDX1> & l, | | operator*=(RGBValue<V1, RIDX1, GIDX1, BIDX1> & l, | |
| RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r) | | RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r) | |
| { | | { | |
|
| l.red() *= r.red(); | | l.red() = V1(l.red() * r.red()); | |
| l.green() *= r.green(); | | l.green() = V1(l.green() * r.green()); | |
| l.blue() *= r.blue(); | | l.blue() = V1(l.blue() * r.blue()); | |
| return l; | | return l; | |
| } | | } | |
| | | | |
| /// componentwise scalar multiply-assignment | | /// componentwise scalar multiply-assignment | |
| template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX> | | template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX> | |
| inline | | inline | |
| RGBValue<V, RIDX, GIDX, BIDX> & | | RGBValue<V, RIDX, GIDX, BIDX> & | |
| operator*=(RGBValue<V, RIDX, GIDX, BIDX> & l, double r) | | operator*=(RGBValue<V, RIDX, GIDX, BIDX> & l, double r) | |
| { | | { | |
|
| l.red() *= r; | | l.red() = V(l.red() * r); | |
| l.green() *= r; | | l.green() = V(l.green() * r); | |
| l.blue() *= r; | | l.blue() = V(l.blue() * r); | |
| | | return l; | |
| | | } | |
| | | | |
| | | /// componentwise divide-assignment | |
| | | template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BI | |
| | | DX1, | |
| | | class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BI | |
| | | DX2> | |
| | | inline | |
| | | RGBValue<V1, RIDX1, GIDX1, BIDX1> & | |
| | | operator/=(RGBValue<V1, RIDX1, GIDX1, BIDX1> & l, | |
| | | RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r) | |
| | | { | |
| | | l.red() = V1(l.red() / r.red()); | |
| | | l.green() = V1(l.green() / r.green()); | |
| | | l.blue() = V1(l.blue() / r.blue()); | |
| return l; | | return l; | |
| } | | } | |
| | | | |
| /// componentwise scalar divide-assignment | | /// componentwise scalar divide-assignment | |
| template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX> | | template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX> | |
| inline | | inline | |
| RGBValue<V, RIDX, GIDX, BIDX> & | | RGBValue<V, RIDX, GIDX, BIDX> & | |
| operator/=(RGBValue<V, RIDX, GIDX, BIDX> & l, double r) | | operator/=(RGBValue<V, RIDX, GIDX, BIDX> & l, double r) | |
| { | | { | |
|
| l.red() /= r; | | l.red() = V(l.red() / r); | |
| l.green() /= r; | | l.green() = V(l.green() / r); | |
| l.blue() /= r; | | l.blue() = V(l.blue() / r); | |
| return l; | | return l; | |
| } | | } | |
| | | | |
| using VIGRA_CSTD::abs; | | using VIGRA_CSTD::abs; | |
| | | | |
| /// component-wise absolute value | | /// component-wise absolute value | |
| template <class T, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX> | | template <class T, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX> | |
| inline | | inline | |
| RGBValue<T, RIDX, GIDX, BIDX> | | RGBValue<T, RIDX, GIDX, BIDX> | |
| abs(RGBValue<T, RIDX, GIDX, BIDX> const & v) | | abs(RGBValue<T, RIDX, GIDX, BIDX> const & v) | |
| | | | |
| skipping to change at line 785 | | skipping to change at line 821 | |
| typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote | | typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote | |
| operator*(RGBValue<V, R, G, B> const & r, double v) | | operator*(RGBValue<V, R, G, B> const & r, double v) | |
| { | | { | |
| typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r); | | typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r); | |
| | | | |
| res *= v; | | res *= v; | |
| | | | |
| return res; | | return res; | |
| } | | } | |
| | | | |
|
| | | /// component-wise division | |
| | | template <class V1, unsigned int R, unsigned int G, unsigned int B, class V | |
| | | 2> | |
| | | inline | |
| | | typename PromoteTraits<RGBValue<V1, R, G, B>, | |
| | | RGBValue<V2, R, G, B> >::Promote | |
| | | operator/(RGBValue<V1, R, G, B> const & r1, | |
| | | RGBValue<V2, R, G, B> const & r2) | |
| | | { | |
| | | typename PromoteTraits<RGBValue<V1, R, G, B>, | |
| | | RGBValue<V2, R, G, B> >::Promote res(r1); | |
| | | | |
| | | res /= r2; | |
| | | | |
| | | return res; | |
| | | } | |
| | | | |
| /// component-wise scalar division | | /// component-wise scalar division | |
| template <class V, unsigned int R, unsigned int G, unsigned int B> | | template <class V, unsigned int R, unsigned int G, unsigned int B> | |
| inline | | inline | |
| typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote | | typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote | |
| operator/(RGBValue<V, R, G, B> const & r, double v) | | operator/(RGBValue<V, R, G, B> const & r, double v) | |
| { | | { | |
| typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r); | | typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r); | |
| | | | |
| res /= v; | | res /= v; | |
| | | | |
| | | | |
End of changes. 14 change blocks. |
| 19 lines changed or deleted | | 75 lines changed or added | |
|
| seededregiongrowing.hxx | | seededregiongrowing.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
|
| /* Copyright 1998-2003 by Ullrich Koethe, Hans Meine */ | | /* Copyright 1998-2010 by Ullrich Koethe, Hans Meine */ | |
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 47 | | skipping to change at line 45 | |
| | | | |
| #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" | |
| | | | |
| 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 164 | | skipping to change at line 163 | |
| 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 { KeepContours, CompleteGrow, SRGWatershedLabel = -1 }; | | 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 */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \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://kogs-www.informatik.uni-hamburg.de/~koethe/papers/#
primary">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). | |
| 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. This | | the existing regions so that a cost function is minimized. | |
| works as follows: | | 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> | |
| | | which can take the values <tt>FourNeighborCode()</tt> (the default) | |
| | | or <tt>EightNeighborCode()</tt>. The algorithm basically works as follo | |
| | | ws | |
| | | (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 adajacent re
gion | |
| and put the candidates into a priority queue. | | and put the candidates into a priority queue. | |
| | | | |
|
| <li> While( priority queue is not empty) | | <li> While( priority queue is not empty 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 | |
| into the priority queue. | | into the priority queue. | |
| | | | |
| </ol> | | </ol> | |
| | | | |
| </ol> | | </ol> | |
| | | | |
|
| If <tt>SRGType == CompleteGrow</tt> (the default), this algorithm | | <tt>SRGType</tt> can take the following values: | |
| will produce a complete 4-connected tesselation of the image. | | | |
| If <tt>SRGType == KeepContours</tt>, a one-pixel-wide border will be le | | <DL> | |
| ft | | <DT><tt>CompleteGrow</tt> <DD> produce a complete tesselation of the vo | |
| between the regions. The border pixels get label 0 (zero). | | lume (default). | |
| | | <DT><tt>KeepContours</tt> <DD> keep a 1-voxel wide unlabeled contour be | |
| | | tween all regions. | |
| | | <DT><tt>StopAtThreshold</tt> <DD> stop when the boundary indicator valu | |
| | | es exceed the | |
| | | threshold given by parameter <tt>max_cost</tt> | |
| | | . | |
| | | <DT><tt>KeepContours | StopAtThreshold</tt> <DD> keep 1-voxel wide cont | |
| | | our and stop at given <tt>max_cost</tt>. | |
| | | </DL> | |
| | | | |
| The cost is determined jointly by the source image and the | | The cost is determined jointly by the source image and the | |
| region statistics functor. The source image contains feature values for
each | | region statistics functor. The source image contains feature values for
each | |
| pixel which will be used by the region statistics functor to calculate
and | | pixel which will be used by the region statistics functor to calculate
and | |
| 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 | |
| | | | |
| skipping to change at line 244 | | skipping to change at line 252 | |
| 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>SrcImageIterator</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. | | 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 | |
| | | <tt>max_cost</tt> value (which defaults to <tt>NumericTraits<double>::m | |
| | | ax()</tt>), | |
| | | region growing is aborted, and all voxels not yet assigned to a region | |
| | | remain unlabeled. | |
| | | | |
| In some cases, the cost only depends on the feature value of the curren
t | | In some cases, the cost only depends on the feature value of the curren
t | |
| pixel. Then the update operation will simply be a no-op, and the <TT>co
st()</TT> | | pixel. Then the update operation will simply be a no-op, and the <TT>co
st()</TT> | |
| function returns its argument. This behavior is implemented by the | | function returns its argument. This behavior is implemented by the | |
| \ref SeedRgDirectValueFunctor. With <tt>SRGType == KeepContours</tt>, | | \ref SeedRgDirectValueFunctor. With <tt>SRGType == KeepContours</tt>, | |
| this is equivalent to the watershed algorithm. | | this is equivalent to the watershed algorithm. | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass arguments explicitly: | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcImageIterator, class SrcAccessor, | | template <class SrcImageIterator, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray> | | class RegionStatisticsArray, class Neighborhood> | |
| void seededRegionGrowing(SrcImageIterator srcul, | | void | |
| SrcImageIterator srclr, SrcAccessor as, | | seededRegionGrowing(SrcImageIterator srcul, SrcImageIterator srclr, | |
| SeedImageIterator seedsul, SeedAccessor as | | SrcAccessor as, | |
| eeds, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| DestImageIterator destul, DestAccessor ad, | | DestImageIterator destul, DestAccessor ad, | |
| RegionStatisticsArray & stats, | | RegionStatisticsArray & stats, | |
| SRGType srgType = CompleteGrow); | | SRGType srgType = CompleteGrow, | |
| | | Neighborhood neighborhood = FourNeighborCode(), | |
| | | 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 SrcImageIterator, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray> | | class RegionStatisticsArray, class Neighborhood> | |
| void | | void | |
|
| seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcA | | seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcA | |
| ccessor> img1, | | ccessor> src, | |
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> seeds, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> dest, | |
| RegionStatisticsArray & stats, | | RegionStatisticsArray & stats, | |
|
| SRGType srgType = CompleteGrow); | | SRGType srgType = CompleteGrow, | |
| | | Neighborhood neighborhood = FourNeighborCode(), | |
| | | 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> \<<a href="seededregiongrowing_8hxx-source.html">vigra
/seededregiongrowing.hxx</a>\><br> | |
| Namespace: vigra | | Namespace: vigra | |
| | | | |
| Example: implementation of the voronoi tesselation | | Example: implementation of the voronoi tesselation | |
| | | | |
| | | | |
| skipping to change at line 353 | | skipping to change at line 368 | |
| 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 SrcImageIterator, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray> | | class RegionStatisticsArray, class Neighborhood> | |
| void seededRegionGrowing(SrcImageIterator srcul, | | void seededRegionGrowing(SrcImageIterator srcul, | |
| SrcImageIterator srclr, SrcAccessor as, | | SrcImageIterator srclr, SrcAccessor as, | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| DestImageIterator destul, DestAccessor ad, | | DestImageIterator destul, DestAccessor ad, | |
| RegionStatisticsArray & stats, | | RegionStatisticsArray & stats, | |
|
| const SRGType srgType) | | SRGType srgType, | |
| | | 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 | | SrcImageIterator isy = srcul, isx = srcul; // iterators for the src im
age | |
| | | | |
| 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; | |
| | | | |
| skipping to change at line 389 | | skipping to change at line 406 | |
| 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; | |
| | | | |
|
| static const Diff2D dist[] = { Diff2D(-1,0), Diff2D(0,-1), | | typedef typename Neighborhood::Direction Direction; | |
| Diff2D(1,0), Diff2D(0,1) }; | | 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) | |
| { | | { | |
| if(*irx == 0) | | if(*irx == 0) | |
| { | | { | |
| // find candidate pixels for growing and fill heap | | // find candidate pixels for growing and fill heap | |
|
| for(int i=0; i<4; i++) | | for(int i=0; i<directionCount; i++) | |
| { | | { | |
|
| cneighbor = irx[dist[i]]; | | // cneighbor = irx[dist[i]]; | |
| | | cneighbor = irx[Neighborhood::diff((Direction)i)]; | |
| 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+dist[i], cost, count+
+, cneighbor); | | allocator.create(pos, pos+Neighborhood::diff((D
irection)i), cost, count++, cneighbor); | |
| pheap.push(pixel); | | pheap.push(pixel); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| // 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_; | |
| | | | |
| allocator.dismiss(pixel); | | allocator.dismiss(pixel); | |
| | | | |
| 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) | | if((srgType & KeepContours) != 0) | |
| { | | { | |
|
| for(int i=0; i<4; i++) | | for(int i=0; i<directionCount; i++) | |
| { | | { | |
|
| cneighbor = irx[dist[i]]; | | cneighbor = irx[Neighborhood::diff((Direction)i)]; | |
| if((cneighbor>0) && (cneighbor != lab)) | | if((cneighbor>0) && (cneighbor != lab)) | |
| { | | { | |
| lab = SRGWatershedLabel; | | lab = SRGWatershedLabel; | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| *irx = lab; | | *irx = lab; | |
| | | | |
|
| if((srgType != KeepContours) || (lab > 0)) | | if((srgType & KeepContours) == 0 || lab > 0) | |
| { | | { | |
| // update statistics | | // update statistics | |
| stats[*irx](as(isx)); | | stats[*irx](as(isx)); | |
| | | | |
| // search neighborhood | | // search neighborhood | |
| // second pass: find new candidate pixels | | // second pass: find new candidate pixels | |
|
| for(int i=0; i<4; i++) | | for(int i=0; i<directionCount; i++) | |
| { | | { | |
|
| if(irx[dist[i]] == 0) | | if(irx[Neighborhood::diff((Direction)i)] == 0) | |
| { | | { | |
|
| CostType cost = stats[lab].cost(as(isx, dist[i])); | | CostType cost = stats[lab].cost(as(isx, Neighborhood::d
iff((Direction)i))); | |
| | | | |
| Pixel * new_pixel = | | Pixel * new_pixel = | |
|
| allocator.create(pos+dist[i], nearest, cost, count+
+, lab); | | allocator.create(pos+Neighborhood::diff((Direction)
i), nearest, cost, count++, lab); | |
| pheap.push(new_pixel); | | pheap.push(new_pixel); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| // 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()); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class SrcAccessor, | | template <class SrcImageIterator, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| | | class RegionStatisticsArray, class Neighborhood> | |
| | | inline void | |
| | | seededRegionGrowing(SrcImageIterator srcul, | |
| | | SrcImageIterator srclr, SrcAccessor as, | |
| | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| | | DestImageIterator destul, DestAccessor ad, | |
| | | RegionStatisticsArray & stats, | |
| | | SRGType srgType, | |
| | | Neighborhood n) | |
| | | { | |
| | | seededRegionGrowing(srcul, srclr, as, | |
| | | seedsul, aseeds, | |
| | | destul, ad, | |
| | | stats, srgType, n, NumericTraits<double>::max()); | |
| | | } | |
| | | | |
| | | template <class SrcImageIterator, class SrcAccessor, | |
| | | class SeedImageIterator, class SeedAccessor, | |
| | | class DestImageIterator, class DestAccessor, | |
| | | class RegionStatisticsArray> | |
| | | inline void | |
| | | seededRegionGrowing(SrcImageIterator srcul, | |
| | | SrcImageIterator srclr, SrcAccessor as, | |
| | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| | | DestImageIterator destul, DestAccessor ad, | |
| | | RegionStatisticsArray & stats, | |
| | | SRGType srgType) | |
| | | { | |
| | | seededRegionGrowing(srcul, srclr, as, | |
| | | seedsul, aseeds, | |
| | | destul, ad, | |
| | | stats, srgType, FourNeighborCode()); | |
| | | } | |
| | | | |
| | | template <class SrcImageIterator, class SrcAccessor, | |
| | | class SeedImageIterator, class SeedAccessor, | |
| | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray> | | class RegionStatisticsArray> | |
| inline void | | inline void | |
| seededRegionGrowing(SrcImageIterator srcul, | | seededRegionGrowing(SrcImageIterator srcul, | |
| SrcImageIterator srclr, SrcAccessor as, | | SrcImageIterator srclr, SrcAccessor as, | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| DestImageIterator destul, DestAccessor ad, | | DestImageIterator destul, DestAccessor ad, | |
| RegionStatisticsArray & stats) | | RegionStatisticsArray & stats) | |
| { | | { | |
| seededRegionGrowing(srcul, srclr, as, | | seededRegionGrowing(srcul, srclr, as, | |
| seedsul, aseeds, | | seedsul, aseeds, | |
| destul, ad, | | destul, ad, | |
| stats, CompleteGrow); | | stats, CompleteGrow); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class SrcAccessor, | | template <class SrcImageIterator, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| | | class RegionStatisticsArray, class Neighborhood> | |
| | | inline void | |
| | | seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> | |
| | | img1, | |
| | | pair<SeedImageIterator, SeedAccessor> img3, | |
| | | pair<DestImageIterator, DestAccessor> img4, | |
| | | RegionStatisticsArray & stats, | |
| | | SRGType srgType, | |
| | | Neighborhood n, | |
| | | double max_cost) | |
| | | { | |
| | | seededRegionGrowing(img1.first, img1.second, img1.third, | |
| | | img3.first, img3.second, | |
| | | img4.first, img4.second, | |
| | | stats, srgType, n, max_cost); | |
| | | } | |
| | | | |
| | | template <class SrcImageIterator, class SrcAccessor, | |
| | | class SeedImageIterator, class SeedAccessor, | |
| | | class DestImageIterator, class DestAccessor, | |
| | | class RegionStatisticsArray, class Neighborhood> | |
| | | inline void | |
| | | seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> | |
| | | img1, | |
| | | pair<SeedImageIterator, SeedAccessor> img3, | |
| | | pair<DestImageIterator, DestAccessor> img4, | |
| | | RegionStatisticsArray & stats, | |
| | | SRGType srgType, | |
| | | Neighborhood n) | |
| | | { | |
| | | seededRegionGrowing(img1.first, img1.second, img1.third, | |
| | | img3.first, img3.second, | |
| | | img4.first, img4.second, | |
| | | stats, srgType, n, NumericTraits<double>::max()); | |
| | | } | |
| | | | |
| | | template <class SrcImageIterator, class SrcAccessor, | |
| | | class SeedImageIterator, class SeedAccessor, | |
| | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray> | | class RegionStatisticsArray> | |
| inline void | | inline void | |
| seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor>
img1, | | seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor>
img1, | |
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> img3, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> img4, | |
| RegionStatisticsArray & stats, | | RegionStatisticsArray & stats, | |
| SRGType srgType) | | SRGType srgType) | |
| { | | { | |
| seededRegionGrowing(img1.first, img1.second, img1.third, | | 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); | | stats, srgType, FourNeighborCode()); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class SrcAccessor, | | template <class SrcImageIterator, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray> | | class RegionStatisticsArray> | |
| inline void | | inline void | |
| seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor>
img1, | | seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor>
img1, | |
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> img3, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> img4, | |
| | | | |
End of changes. 32 change blocks. |
| 45 lines changed or deleted | | 156 lines changed or added | |
|
| seededregiongrowing3d.hxx | | seededregiongrowing3d.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ | | /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */ | |
| /* and Ullrich Koethe */ | | /* and Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 50 | | skipping to change at line 48 | |
| #define VIGRA_SEEDEDREGIONGROWING_3D_HXX | | #define VIGRA_SEEDEDREGIONGROWING_3D_HXX | |
| | | | |
| #include <vector> | | #include <vector> | |
| #include <stack> | | #include <stack> | |
| #include <queue> | | #include <queue> | |
| #include "utilities.hxx" | | #include "utilities.hxx" | |
| #include "stdimage.hxx" | | #include "stdimage.hxx" | |
| #include "stdimagefunctions.hxx" | | #include "stdimagefunctions.hxx" | |
| #include "seededregiongrowing.hxx" | | #include "seededregiongrowing.hxx" | |
| #include "multi_pointoperators.hxx" | | #include "multi_pointoperators.hxx" | |
|
| | | #include "voxelneighborhood.hxx" | |
| | | | |
| namespace vigra { | | namespace vigra { | |
| | | | |
| namespace detail { | | namespace detail { | |
| | | | |
| template <class COST, class Diff_type> | | template <class COST, class Diff_type> | |
| class SeedRgVoxel | | class SeedRgVoxel | |
| { | | { | |
| public: | | public: | |
| Diff_type location_, nearest_; | | Diff_type location_, nearest_; | |
| | | | |
| skipping to change at line 186 | | skipping to change at line 185 | |
| | | | |
| /** \brief Three-dimensional Region Segmentation by means of Seeded Region
Growing. | | /** \brief Three-dimensional 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 | |
| | | | |
| The seed image is a partly segmented multi-dimensional array which cont
ains uniquely | | The seed image is a partly segmented multi-dimensional array which cont
ains uniquely | |
| labeled regions (the seeds) and unlabeled voxels (the candidates, label
0). | | labeled regions (the seeds) and unlabeled voxels (the candidates, label
0). | |
| Seed regions can be as large as you wish and as small as one voxel. If | | Seed regions can be as large as you wish and as small as one voxel. If | |
| there are no candidates, the algorithm will simply copy the seed array | | there are no candidates, the algorithm will simply copy the seed array | |
| into the output array. Otherwise it will aggregate the candidates into | | into the output array. Otherwise it will aggregate the candidates into | |
|
| the existing regions so that a cost function is minimized. This | | the existing regions so that a cost function is minimized. | |
| works as follows: | | 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> | |
| | | which can take the values <tt>NeighborCode3DSix()</tt> (the default) | |
| | | or <tt>NeighborCode3DTwentySix()</tt>. The algorithm basically works as | |
| | | follows | |
| | | (illustrated for 6-neighborhood, but 26-neighborhood works in the same | |
| | | way): | |
| | | | |
| <ol> | | <ol> | |
| | | | |
| <li> Find all candidate pixels that are 6-adjacent to a seed region. | | <li> Find all candidate pixels that are 6-adjacent to a seed region. | |
| Calculate the cost for aggregating each candidate into its adajacent re
gion | | Calculate the cost for aggregating each candidate into its adajacent re
gion | |
| and put the candidates into a priority queue. | | and put the candidates into a priority queue. | |
| | | | |
| <li> While( priority queue is not empty) | | <li> While( priority queue is not empty) | |
| | | | |
| <ol> | | <ol> | |
| | | | |
| skipping to change at line 209 | | skipping to change at line 212 | |
| <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 | |
| into the priority queue. | | into the priority queue. | |
| | | | |
| </ol> | | </ol> | |
| | | | |
| </ol> | | </ol> | |
| | | | |
|
| If <tt>SRGType == CompleteGrow</tt> (the default), this algorithm will | | <tt>SRGType</tt> can take the following values: | |
| produce a complete 6-connected tesselation of the array. | | | |
| Other grow types (such as keeping contours for watersheds) are currentl | | <DL> | |
| y not | | <DT><tt>CompleteGrow</tt> <DD> produce a complete tesselation of the vo | |
| supported | | lume (default). | |
| | | <DT><tt>KeepContours</tt> <DD> keep a 1-voxel wide unlabeled contour be | |
| | | tween all regions. | |
| | | <DT><tt>StopAtThreshold</tt> <DD> stop when the boundary indicator valu | |
| | | es exceed the | |
| | | threshold given by parameter <tt>max_cost</tt> | |
| | | . | |
| | | <DT><tt>KeepContours | StopAtThreshold</tt> <DD> keep 1-voxel wide cont | |
| | | our and stop at given <tt>max_cost</tt>. | |
| | | </DL> | |
| | | | |
| The cost is determined jointly by the source array and the | | The cost is determined jointly by the source array and the | |
| region statistics functor. The source array contains feature values for
each | | region statistics functor. The source array contains feature values for
each | |
| pixel which will be used by the region statistics functor to calculate
and | | pixel which will be used by the region statistics functor to calculate
and | |
| 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>seededRegionGrowing3D()</TT> | | been calculated prior to calling <TT>seededRegionGrowing3D()</TT> | |
| | | | |
| skipping to change at line 234 | | skipping to change at line 242 | |
| 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>SrcImageIterator</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, at any point in | | cost, the algorithm will favour the nearest region. If <tt>StopAtThresh | |
| the algorithm, | | old</tt> is active, | |
| the cost of the current candidate exceeds the optional <tt>max_cost</tt | | and the cost of the current candidate at any point in the algorithm exc | |
| > value (which defaults to | | eeds the optional | |
| <tt>-1</tt>), region growing is aborted, and all voxels not yet assigne | | <tt>max_cost</tt> value (which defaults to <tt>NumericTraits<double>::m | |
| d to a region | | ax()</tt>), | |
| remain unlabeled. | | region growing is aborted, and all voxels not yet assigned to a region | |
| | | remain unlabeled. | |
| | | | |
| In some cases, the cost only depends on the feature value of the curren
t | | In some cases, the cost only depends on the feature value of the curren
t | |
| voxel. Then the update operation will simply be a no-op, and the <TT>co
st()</TT> | | voxel. Then the update operation will simply be a no-op, and the <TT>co
st()</TT> | |
| function returns its argument. This behavior is implemented by the | | function returns its argument. This behavior is implemented by the | |
| \ref SeedRgDirectValueFunctor. | | \ref SeedRgDirectValueFunctor. | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass arguments explicitly: | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
|
| template <class SrcImageIterator, class Diff_type, class SrcAccesso | | template <class SrcImageIterator, class Shape, class SrcAccessor, | |
| r, | | | |
| class SeedImageIterator, class SeedAccessor, | | | |
| class DestImageIterator, class DestAccessor, | | | |
| class RegionStatisticsArray, class CostThresholdType > | | | |
| void seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, | | | |
| SrcAccessor as, | | | |
| SeedImageIterator seedsul, SeedAccessor as | | | |
| eeds, | | | |
| DestImageIterator destul, DestAccessor ad, | | | |
| RegionStatisticsArray & stats, | | | |
| CostThresholdType max_cost = -1.0, | | | |
| const SRGType srgType == CompleteGrow); | | | |
| | | | |
| template <class SrcImageIterator, class Diff_type, class SrcAccesso | | | |
| r, | | | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray> | | class RegionStatisticsArray, class Neighborhood> | |
| void seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, | | void | |
| SrcAccessor as, | | seededRegionGrowing3D(SrcImageIterator srcul, Shape shape, SrcAcces | |
| SeedImageIterator seedsul, SeedAccessor as | | sor as, | |
| eeds, | | SeedImageIterator seedsul, SeedAccessor aseed | |
| DestImageIterator destul, DestAccessor ad, | | s, | |
| RegionStatisticsArray & stats, | | DestImageIterator destul, DestAccessor ad, | |
| const SRGType srgType == CompleteGrow); | | RegionStatisticsArray & stats, | |
| | | SRGType srgType = CompleteGrow, | |
| } | | Neighborhood neighborhood = NeighborCode3DSix | |
| | | (), | |
| | | double max_cost = NumericTraits<double>::max( | |
| | | )); | |
| | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
|
| template <class SrcImageIterator, class Shape, class SrcAccesso | | template <class SrcImageIterator, class Shape, class SrcAccessor, | |
| r, | | | |
| class SeedImageIterator, class SeedAccessor, | | | |
| class DestImageIterator, class DestAccessor, | | | |
| class RegionStatisticsArray, class CostThresholdType> | | | |
| void | | | |
| seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccess | | | |
| or> img1, | | | |
| pair<SeedImageIterator, SeedAccessor> img3, | | | |
| pair<DestImageIterator, DestAccessor> img4, | | | |
| RegionStatisticsArray & stats, | | | |
| CostThresholdType max_cost = -1.0, | | | |
| const SRGType srgType == CompleteGrow); | | | |
| | | | |
| template <class SrcImageIterator, class Shape, class SrcAccesso | | | |
| r, | | | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray> | | class RegionStatisticsArray, class Neighborhood> | |
| void | | void | |
| seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccess | | seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> | |
| or> img1, | | src, | |
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> seeds, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> dest, | |
| RegionStatisticsArray & stats, | | RegionStatisticsArray & stats, | |
| const SRGType srgType == CompleteGrow); | | SRGType srgType = CompleteGrow, | |
| | | Neighborhood neighborhood = NeighborCode3DSix | |
| | | (), | |
| | | double max_cost = NumericTraits<double>::max( | |
| | | )); | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| */ | | */ | |
| doxygen_overloaded_function(template <...> void seededRegionGrowing3D) | | doxygen_overloaded_function(template <...> void seededRegionGrowing3D) | |
| | | | |
| template <class SrcImageIterator, class Diff_type, class SrcAccessor, | | template <class SrcImageIterator, class Diff_type, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray, class CostThresholdType> | | class RegionStatisticsArray, class Neighborhood> | |
| void seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, | | void | |
| SrcAccessor as, | | seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | as, | |
| DestImageIterator destul, DestAccessor ad, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| RegionStatisticsArray & stats, CostThresholdType m | | DestImageIterator destul, DestAccessor ad, | |
| ax_cost, | | RegionStatisticsArray & stats, | |
| const SRGType srgType) | | SRGType srgType, | |
| | | Neighborhood, | |
| | | double max_cost) | |
| { | | { | |
| SrcImageIterator srclr = srcul + shape; | | SrcImageIterator srclr = srcul + shape; | |
| //int w = srclr.x - srcul.x; | | //int w = srclr.x - srcul.x; | |
| int w = shape[0]; | | int w = shape[0]; | |
| //int h = srclr.y - srcul.y; | | //int h = srclr.y - srcul.y; | |
| int h = shape[1]; | | int h = shape[1]; | |
| //int d = srclr.z - srcul.z; | | //int d = srclr.z - srcul.z; | |
| int d = shape[2]; | | int d = shape[2]; | |
| int count = 0; | | int count = 0; | |
| | | | |
| SrcImageIterator isy = srcul, isx = srcul, isz = srcul; // iterators f
or the src image | | SrcImageIterator isy = srcul, isx = srcul, isz = srcul; // iterators f
or the src image | |
| | | | |
| typedef typename RegionStatisticsArray::value_type RegionStatistics; | | typedef typename RegionStatisticsArray::value_type RegionStatistics; | |
|
| typedef typename PromoteTraits<typename RegionStatistics::cost_type, Co
stThresholdType>::Promote CostType; | | typedef typename PromoteTraits<typename RegionStatistics::cost_type, do
uble>::Promote CostType; | |
| typedef detail::SeedRgVoxel<CostType, Diff_type> Voxel; | | typedef detail::SeedRgVoxel<CostType, Diff_type> Voxel; | |
| | | | |
| typename Voxel::Allocator allocator; | | typename Voxel::Allocator allocator; | |
| | | | |
| typedef std::priority_queue< Voxel *, | | typedef std::priority_queue< Voxel *, | |
| std::vector<Voxel *>, | | std::vector<Voxel *>, | |
| typename Voxel::Compare > SeedRgVoxelHeap
; | | typename Voxel::Compare > SeedRgVoxelHeap
; | |
| typedef MultiArray<3, int> IVolume; | | typedef MultiArray<3, int> IVolume; | |
| | | | |
| // copy seed image in an image with border | | // copy seed image in an image with border | |
| | | | |
| skipping to change at line 351 | | skipping to change at line 340 | |
| IVolume regions(regionshape); | | IVolume regions(regionshape); | |
| MultiIterator<3,int> ir = regions.traverser_begin(); | | MultiIterator<3,int> ir = regions.traverser_begin(); | |
| ir = ir + Diff_type(1,1,1); | | ir = ir + Diff_type(1,1,1); | |
| | | | |
| //IVolume::Iterator iry, irx, irz; | | //IVolume::Iterator iry, irx, irz; | |
| MultiIterator<3,int> iry, irx, irz; | | MultiIterator<3,int> iry, irx, irz; | |
| | | | |
| //initImageBorder(destImageRange(regions), 1, SRGWatershedLabel); | | //initImageBorder(destImageRange(regions), 1, SRGWatershedLabel); | |
| initMultiArrayBorder(destMultiArrayRange(regions), 1, SRGWatershedLabel
); | | initMultiArrayBorder(destMultiArrayRange(regions), 1, SRGWatershedLabel
); | |
| | | | |
|
| copyMultiArray(seedsul, Diff_type(w,h,d), aseeds, ir, AccessorTraits<in
t>::default_accessor()/* vigra::StandardValueAccessor<int>*/); | | copyMultiArray(seedsul, Diff_type(w,h,d), aseeds, ir, AccessorTraits<in
t>::default_accessor()); | |
| | | | |
| // allocate and init memory for the results | | // allocate and init memory for the results | |
| | | | |
| SeedRgVoxelHeap pheap; | | SeedRgVoxelHeap pheap; | |
| int cneighbor; | | int cneighbor; | |
| | | | |
|
| | | #if 0 | |
| static const Diff_type dist[] = { Diff_type(-1, 0, 0), Diff_type( 0,-1,
0), | | static const Diff_type dist[] = { Diff_type(-1, 0, 0), Diff_type( 0,-1,
0), | |
| Diff_type( 1, 0, 0), Diff_type( 0, 1,
0), | | Diff_type( 1, 0, 0), Diff_type( 0, 1,
0), | |
| Diff_type( 0, 0,-1), Diff_type( 0, 0,
1) }; | | Diff_type( 0, 0,-1), Diff_type( 0, 0,
1) }; | |
|
| | | #endif | |
| | | | |
| | | typedef typename Neighborhood::Direction Direction; | |
| | | int directionCount = Neighborhood::DirectionCount; | |
| | | | |
| Diff_type pos(0,0,0); | | Diff_type pos(0,0,0); | |
| | | | |
| for(isz=srcul, irz=ir, pos[2]=0; pos[2]<d; | | for(isz=srcul, irz=ir, pos[2]=0; pos[2]<d; | |
| pos[2]++, isz.dim2()++, irz.dim2()++) | | pos[2]++, isz.dim2()++, irz.dim2()++) | |
| { | | { | |
| //std::cerr << "Z = " << pos[2] << std::endl; | | //std::cerr << "Z = " << pos[2] << std::endl; | |
| | | | |
| for(isy=isz, iry=irz, pos[1]=0; pos[1]<h; | | for(isy=isz, iry=irz, pos[1]=0; pos[1]<h; | |
| pos[1]++, isy.dim1()++, iry.dim1()++) | | pos[1]++, isy.dim1()++, iry.dim1()++) | |
| | | | |
| skipping to change at line 382 | | skipping to change at line 376 | |
| //std::cerr << "Y = " << pos[1] << std::endl; | | //std::cerr << "Y = " << pos[1] << std::endl; | |
| | | | |
| for(isx=isy, irx=iry, pos[0]=0; pos[0]<w; | | for(isx=isy, irx=iry, pos[0]=0; pos[0]<w; | |
| pos[0]++, isx.dim0()++, irx.dim0()++) | | pos[0]++, isx.dim0()++, irx.dim0()++) | |
| { | | { | |
| //std::cerr << "X = " << pos[0] << std::endl; | | //std::cerr << "X = " << pos[0] << std::endl; | |
| | | | |
| if(*irx == 0) | | if(*irx == 0) | |
| { | | { | |
| // find candidate pixels for growing and fill heap | | // find candidate pixels for growing and fill heap | |
|
| for(int i=0; i<6; i++) | | for(int i=0; i<directionCount; i++) | |
| { | | { | |
|
| cneighbor = *(irx + dist[i]); | | cneighbor = *(irx + Neighborhood::diff((Direction)i
)); | |
| if(cneighbor > 0) | | if(cneighbor > 0) | |
| { | | { | |
| CostType cost = stats[cneighbor].cost(as(isx)); | | CostType cost = stats[cneighbor].cost(as(isx)); | |
| | | | |
| Voxel * voxel = | | Voxel * voxel = | |
|
| allocator.create(pos, pos+dist[i], cost, co
unt++, cneighbor); | | allocator.create(pos, pos+Neighborhood::dif
f((Direction)i), cost, count++, cneighbor); | |
| pheap.push(voxel); | | pheap.push(voxel); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| // perform region growing | | // perform region growing | |
| while(pheap.size() != 0) | | while(pheap.size() != 0) | |
| { | | { | |
| Voxel * voxel = pheap.top(); | | Voxel * voxel = pheap.top(); | |
| pheap.pop(); | | pheap.pop(); | |
| | | | |
|
| if(max_cost > NumericTraits<CostThresholdType>::zero() && voxel->co | | if((srgType & StopAtThreshold) != 0 && voxel->cost_ > max_cost) | |
| st_ > max_cost) break; | | break; | |
| | | | |
| Diff_type pos = voxel->location_; | | Diff_type pos = voxel->location_; | |
| Diff_type nearest = voxel->nearest_; | | Diff_type nearest = voxel->nearest_; | |
| int lab = voxel->label_; | | int lab = voxel->label_; | |
| | | | |
| allocator.dismiss(voxel); | | allocator.dismiss(voxel); | |
| | | | |
| 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) | | if((srgType & KeepContours) != 0) | |
| { | | { | |
|
| for(int i=0; i<6; i++) | | for(int i=0; i<directionCount; i++) | |
| { | | { | |
|
| cneighbor = * (irx + dist[i]); | | cneighbor = * (irx + Neighborhood::diff((Direction)i)); | |
| if((cneighbor>0) && (cneighbor != lab)) | | if((cneighbor>0) && (cneighbor != lab)) | |
| { | | { | |
| lab = SRGWatershedLabel; | | lab = SRGWatershedLabel; | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| *irx = lab; | | *irx = lab; | |
| | | | |
|
| if((srgType != KeepContours) || (lab > 0)) | | if((srgType & KeepContours) == 0 || lab > 0) | |
| { | | { | |
| // update statistics | | // update statistics | |
| stats[*irx](as(isx)); | | stats[*irx](as(isx)); | |
| | | | |
| // search neighborhood | | // search neighborhood | |
| // second pass: find new candidate pixels | | // second pass: find new candidate pixels | |
|
| for(int i=0; i<6; i++) | | for(int i=0; i<directionCount; i++) | |
| { | | { | |
|
| if(*(irx + dist[i]) == 0) | | if(*(irx + Neighborhood::diff((Direction)i)) == 0) | |
| { | | { | |
|
| CostType cost = stats[lab].cost(as(isx, dist[i])); | | CostType cost = stats[lab].cost(as(isx, Neighborhood::d
iff((Direction)i))); | |
| | | | |
| Voxel * new_voxel = | | Voxel * new_voxel = | |
|
| allocator.create(pos+dist[i], nearest, cost, count+
+, lab); | | allocator.create(pos+Neighborhood::diff((Direction)
i), nearest, cost, count++, lab); | |
| pheap.push(new_voxel); | | pheap.push(new_voxel); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| // write result | | // write result | |
|
| transformMultiArray(ir, Diff_type(w,h,d), AccessorTraits<int>::default_ | | transformMultiArray(ir, Diff_type(w,h,d), AccessorTraits<int>::default_ | |
| accessor()/* regions.accessor()*/, destul, ad, | | accessor(), | |
| detail::UnlabelWatersheds()); | | destul, ad, detail::UnlabelWatersheds()); | |
| } | | | |
| /* | | | |
| template <class SrcImageIterator, class SrcAccessor, | | | |
| class SeedImageIterator, class SeedAccessor, | | | |
| class DestImageIterator, class DestAccessor, | | | |
| class RegionStatisticsArray> | | | |
| inline void | | | |
| seededRegionGrowing3D(SrcImageIterator srcul, | | | |
| SrcImageIterator srclr, SrcAccessor as, | | | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | | |
| DestImageIterator destul, DestAccessor ad, | | | |
| RegionStatisticsArray & stats) | | | |
| { | | | |
| seededRegionGrowing3D(srcul, srclr, as, | | | |
| seedsul, aseeds, | | | |
| destul, ad, | | | |
| stats, CompleteGrow); | | | |
| }*/ | | | |
| /* | | | |
| template <class SrcImageIterator, class SrcAccessor, | | | |
| class SeedImageIterator, class SeedAccessor, | | | |
| class DestImageIterator, class DestAccessor, | | | |
| class RegionStatisticsArray> | | | |
| inline void | | | |
| seededRegionGrowing3D(triple<SrcImageIterator, SrcImageIterator, SrcAccesso | | | |
| r> img1, | | | |
| pair<SeedImageIterator, SeedAccessor> img3, | | | |
| pair<DestImageIterator, DestAccessor> img4, | | | |
| RegionStatisticsArray & stats, | | | |
| SRGType srgType) | | | |
| { | | | |
| seededRegionGrowing3D(img1.first, img1.second, img1.third, | | | |
| img3.first, img3.second, | | | |
| img4.first, img4.second, | | | |
| stats, srgType); | | | |
| } | | | |
| | | | |
| template <class SrcImageIterator, class SrcAccessor, | | | |
| class SeedImageIterator, class SeedAccessor, | | | |
| class DestImageIterator, class DestAccessor, | | | |
| class RegionStatisticsArray> | | | |
| inline void | | | |
| seededRegionGrowing3D(triple<SrcImageIterator, SrcImageIterator, SrcAccesso | | | |
| r> img1, | | | |
| pair<SeedImageIterator, SeedAccessor> img3, | | | |
| pair<DestImageIterator, DestAccessor> img4, | | | |
| RegionStatisticsArray & stats) | | | |
| { | | | |
| seededRegionGrowing3D(img1.first, img1.second, img1.third, | | | |
| img3.first, img3.second, | | | |
| img4.first, img4.second, | | | |
| stats, CompleteGrow); | | | |
| } | | } | |
|
| */ | | | |
| | | | |
| template <class SrcImageIterator, class Diff_type, class SrcAccessor, | | template <class SrcImageIterator, class Diff_type, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray, class CostThresholdType> | | class RegionStatisticsArray, class Neighborhood > | |
| void seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, | | inline void | |
| SrcAccessor as, | | seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | as, | |
| DestImageIterator destul, DestAccessor ad, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| RegionStatisticsArray & stats, CostThresholdType m | | DestImageIterator destul, DestAccessor ad, | |
| ax_cost) | | RegionStatisticsArray & stats, SRGType srgType, Neigh | |
| | | borhood n) | |
| { | | { | |
|
| seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, destul, ad, s | | seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, | |
| tats, max_cost, CompleteGrow); | | destul, ad, stats, srgType, n, NumericTraits<dou | |
| | | ble>::max()); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class Diff_type, class SrcAccessor, | | template <class SrcImageIterator, class Diff_type, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray > | | class RegionStatisticsArray > | |
|
| void seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, | | inline void | |
| SrcAccessor as, | | seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | as, | |
| DestImageIterator destul, DestAccessor ad, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| RegionStatisticsArray & stats) | | DestImageIterator destul, DestAccessor ad, | |
| | | RegionStatisticsArray & stats, SRGType srgType) | |
| { | | { | |
|
| seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, destul, ad, s | | seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, | |
| tats, -1.0, CompleteGrow); | | destul, ad, stats, srgType, NeighborCode3DSix()) | |
| | | ; | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class Diff_type, class SrcAccessor, | | template <class SrcImageIterator, class Diff_type, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray > | | class RegionStatisticsArray > | |
|
| void seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, | | inline void | |
| SrcAccessor as, | | seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor | |
| SeedImageIterator seedsul, SeedAccessor aseeds, | | as, | |
| DestImageIterator destul, DestAccessor ad, | | SeedImageIterator seedsul, SeedAccessor aseeds, | |
| RegionStatisticsArray & stats, SRGType srgType) | | DestImageIterator destul, DestAccessor ad, | |
| | | RegionStatisticsArray & stats) | |
| { | | { | |
|
| seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, destul, ad, s | | seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, destul, ad, | |
| tats, -1.0, srgType); | | stats, CompleteGrow); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class Shape, class SrcAccessor, | | template <class SrcImageIterator, class Shape, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray> | | class RegionStatisticsArray, class Neighborhood> | |
| inline void | | inline void | |
| seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | | seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | |
|
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> img3, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> img4, | |
| RegionStatisticsArray & stats, int max_cost) | | RegionStatisticsArray & stats, | |
| | | SRGType srgType, Neighborhood n, double max_cost) | |
| { | | { | |
| seededRegionGrowing3D(img1.first, img1.second, img1.third, | | seededRegionGrowing3D(img1.first, img1.second, img1.third, | |
|
| img3.first, img3.second, | | img3.first, img3.second, | |
| img4.first, img4.second, | | img4.first, img4.second, | |
| stats, max_cost, CompleteGrow); | | stats, srgType, n, max_cost); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class Shape, class SrcAccessor, | | template <class SrcImageIterator, class Shape, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
|
| class RegionStatisticsArray, class CostThresholdType> | | class RegionStatisticsArray, class Neighborhood> | |
| inline void | | inline void | |
| seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | | seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | |
|
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> img3, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> img4, | |
| RegionStatisticsArray & stats, CostThresholdType max_co | | RegionStatisticsArray & stats, | |
| st, const SRGType srgType) | | SRGType srgType, Neighborhood n) | |
| { | | { | |
| seededRegionGrowing3D(img1.first, img1.second, img1.third, | | seededRegionGrowing3D(img1.first, img1.second, img1.third, | |
|
| img3.first, img3.second, | | img3.first, img3.second, | |
| img4.first, img4.second, | | img4.first, img4.second, | |
| stats, max_cost, srgType); | | stats, srgType, n, NumericTraits<double>::max()); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class Shape, class SrcAccessor, | | template <class SrcImageIterator, class Shape, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray> | | class RegionStatisticsArray> | |
| inline void | | inline void | |
| seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | | seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | |
|
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> img3, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> img4, | |
| RegionStatisticsArray & stats, const SRGType srgType) | | RegionStatisticsArray & stats, SRGType srgType) | |
| { | | { | |
| seededRegionGrowing3D(img1.first, img1.second, img1.third, | | seededRegionGrowing3D(img1.first, img1.second, img1.third, | |
|
| img3.first, img3.second, | | img3.first, img3.second, | |
| img4.first, img4.second, | | img4.first, img4.second, | |
| stats, -1.0, srgType); | | stats, srgType, NeighborCode3DSix()); | |
| } | | } | |
| | | | |
| template <class SrcImageIterator, class Shape, class SrcAccessor, | | template <class SrcImageIterator, class Shape, class SrcAccessor, | |
| class SeedImageIterator, class SeedAccessor, | | class SeedImageIterator, class SeedAccessor, | |
| class DestImageIterator, class DestAccessor, | | class DestImageIterator, class DestAccessor, | |
| class RegionStatisticsArray> | | class RegionStatisticsArray> | |
| inline void | | inline void | |
| seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | | seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1, | |
|
| pair<SeedImageIterator, SeedAccessor> img3, | | pair<SeedImageIterator, SeedAccessor> img3, | |
| pair<DestImageIterator, DestAccessor> img4, | | pair<DestImageIterator, DestAccessor> img4, | |
| RegionStatisticsArray & stats) | | RegionStatisticsArray & stats) | |
| { | | { | |
| seededRegionGrowing3D(img1.first, img1.second, img1.third, | | seededRegionGrowing3D(img1.first, img1.second, img1.third, | |
|
| img3.first, img3.second, | | img3.first, img3.second, | |
| img4.first, img4.second, | | img4.first, img4.second, | |
| stats, -1.0, CompleteGrow); | | stats); | |
| } | | } | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
| | | | |
| #endif // VIGRA_SEEDEDREGIONGROWING_HXX | | #endif // VIGRA_SEEDEDREGIONGROWING_HXX | |
| | | | |
End of changes. 46 change blocks. |
| 196 lines changed or deleted | | 151 lines changed or added | |
|
| separableconvolution.hxx | | separableconvolution.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 68 | | skipping to change at line 66 | |
| 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 w = iend - is; | | // int w = iend - is; | |
| int w = std::distance( is, iend ); | | int w = std::distance( is, iend ); | |
| | | | |
|
| typedef typename NumericTraits<typename | | typedef typename PromoteTraits< | |
| SrcAccessor::value_type>::RealPromote SumType; | | typename SrcAccessor::value_type, | |
| | | typename KernelAccessor::value_type>::Promote SumType; | |
| | | | |
| SrcIterator ibegin = is; | | SrcIterator ibegin = is; | |
| | | | |
| for(int x=0; x<w; ++x, ++is, ++id) | | for(int x=0; x<w; ++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) | |
| { | | { | |
| | | | |
| skipping to change at line 122 | | skipping to change at line 121 | |
| else | | else | |
| { | | { | |
| 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); | |
| } | | } | |
| } | | } | |
| | | | |
|
| da.set(NumericTraits<typename | | da.set(detail::RequiresExplicitCast<typename | |
| DestAccessor::value_type>::fromRealPromote(sum), id); | | DestAccessor::value_type>::cast(sum), id); | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* internalConvolveLineClip */ | | /* internalConvolveLineClip */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| | | | |
| skipping to change at line 145 | | skipping to change at line 144 | |
| 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 w = iend - is; | | // int w = iend - is; | |
| int w = std::distance( is, iend ); | | int w = std::distance( is, iend ); | |
| | | | |
|
| typedef typename NumericTraits<typename | | typedef typename PromoteTraits< | |
| SrcAccessor::value_type>::RealPromote SumType; | | typename SrcAccessor::value_type, | |
| | | typename KernelAccessor::value_type>::Promote SumType; | |
| | | | |
| SrcIterator ibegin = is; | | SrcIterator ibegin = is; | |
| | | | |
| for(int x=0; x<w; ++x, ++is, ++id) | | for(int x=0; x<w; ++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) | |
| { | | { | |
| | | | |
| skipping to change at line 204 | | skipping to change at line 204 | |
| else | | else | |
| { | | { | |
| 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); | |
| } | | } | |
| } | | } | |
| | | | |
|
| da.set(NumericTraits<typename | | da.set(detail::RequiresExplicitCast<typename | |
| DestAccessor::value_type>::fromRealPromote(sum), id); | | DestAccessor::value_type>::cast(sum), id); | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* 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 w = iend - is; | | // int w = iend - is; | |
| int w = std::distance( is, iend ); | | int w = std::distance( is, iend ); | |
| | | | |
|
| typedef typename NumericTraits<typename | | typedef typename PromoteTraits< | |
| SrcAccessor::value_type>::RealPromote SumType; | | typename SrcAccessor::value_type, | |
| | | typename KernelAccessor::value_type>::Promote SumType; | |
| | | | |
| SrcIterator ibegin = is; | | SrcIterator ibegin = is; | |
| | | | |
| for(int x=0; x<w; ++x, ++is, ++id) | | for(int x=0; x<w; ++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) | |
| { | | { | |
| | | | |
| skipping to change at line 279 | | skipping to change at line 280 | |
| else | | else | |
| { | | { | |
| 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); | |
| } | | } | |
| } | | } | |
| | | | |
|
| da.set(NumericTraits<typename | | da.set(detail::RequiresExplicitCast<typename | |
| DestAccessor::value_type>::fromRealPromote(sum), id); | | DestAccessor::value_type>::cast(sum), id); | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* 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 w = iend - is; | | // int w = iend - is; | |
| int w = std::distance( is, iend ); | | int w = std::distance( is, iend ); | |
| | | | |
|
| typedef typename NumericTraits<typename | | typedef typename PromoteTraits< | |
| SrcAccessor::value_type>::RealPromote SumType; | | typename SrcAccessor::value_type, | |
| | | typename KernelAccessor::value_type>::Promote SumType; | |
| | | | |
| SrcIterator ibegin = is; | | SrcIterator ibegin = is; | |
| | | | |
| for(int x=0; x<w; ++x, ++is, ++id) | | for(int x=0; x<w; ++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) | |
| { | | { | |
| | | | |
| skipping to change at line 354 | | skipping to change at line 356 | |
| else | | else | |
| { | | { | |
| 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); | |
| } | | } | |
| } | | } | |
| | | | |
|
| da.set(NumericTraits<typename | | da.set(detail::RequiresExplicitCast<typename | |
| DestAccessor::value_type>::fromRealPromote(sum), id); | | DestAccessor::value_type>::cast(sum), id); | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* 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 w = iend - is; | | // int w = iend - is; | |
| int w = std::distance( is, iend ); | | int w = std::distance( is, iend ); | |
| | | | |
|
| typedef typename NumericTraits<typename | | typedef typename PromoteTraits< | |
| SrcAccessor::value_type>::RealPromote SumType; | | typename SrcAccessor::value_type, | |
| | | typename KernelAccessor::value_type>::Promote SumType; | |
| | | | |
| is += kright; | | is += kright; | |
| id += kright; | | id += kright; | |
| | | | |
| for(int x=kright; x<w+kleft; ++x, ++is, ++id) | | for(int x=kright; x<w+kleft; ++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); | |
| } | | } | |
| | | | |
|
| da.set(NumericTraits<typename | | da.set(detail::RequiresExplicitCast<typename | |
| DestAccessor::value_type>::fromRealPromote(sum), id); | | DestAccessor::value_type>::cast(sum), id); | |
| } | | } | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* Separable convolution functions */ | | /* Separable convolution functions */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \addtogroup SeparableConvolution One-dimensional and separable convolut
ion functions | | /** \addtogroup SeparableConvolution One-dimensional and separable convolut
ion functions | |
| | | | |
| skipping to change at line 981 | | skipping to change at line 984 | |
| /** Copy constructor. | | /** Copy constructor. | |
| */ | | */ | |
| Kernel1D(Kernel1D const & k) | | Kernel1D(Kernel1D const & k) | |
| : kernel_(k.kernel_), | | : kernel_(k.kernel_), | |
| left_(k.left_), | | left_(k.left_), | |
| right_(k.right_), | | right_(k.right_), | |
| border_treatment_(k.border_treatment_), | | border_treatment_(k.border_treatment_), | |
| norm_(k.norm_) | | norm_(k.norm_) | |
| {} | | {} | |
| | | | |
|
| | | /** Construct from kernel with different element type, e.g. double | |
| | | => FixedPoint16. | |
| | | */ | |
| | | template <class U> | |
| | | Kernel1D(Kernel1D<U> const & k) | |
| | | : kernel_(k.center()+k.left(), k.center()+k.right()+1), | |
| | | left_(k.left()), | |
| | | right_(k.right()), | |
| | | border_treatment_(k.borderTreatment()), | |
| | | norm_(k.norm()) | |
| | | {} | |
| | | | |
| /** Copy assignment. | | /** Copy assignment. | |
| */ | | */ | |
| Kernel1D & operator=(Kernel1D const & k) | | Kernel1D & operator=(Kernel1D const & k) | |
| { | | { | |
| if(this != &k) | | if(this != &k) | |
| { | | { | |
| left_ = k.left_; | | left_ = k.left_; | |
| right_ = k.right_; | | right_ = k.right_; | |
| border_treatment_ = k.border_treatment_; | | border_treatment_ = k.border_treatment_; | |
| norm_ = k.norm_; | | norm_ = k.norm_; | |
| | | | |
| skipping to change at line 1678 | | skipping to change at line 1692 | |
| sum += *k; | | sum += *k; | |
| } | | } | |
| } | | } | |
| else | | else | |
| { | | { | |
| unsigned int faculty = 1; | | unsigned int faculty = 1; | |
| for(unsigned int i = 2; i <= derivativeOrder; ++i) | | for(unsigned int i = 2; i <= derivativeOrder; ++i) | |
| faculty *= i; | | faculty *= i; | |
| for(double x = left() + offset; k < kernel_.end(); ++x, ++k) | | for(double x = left() + offset; k < kernel_.end(); ++x, ++k) | |
| { | | { | |
|
| sum += *k * VIGRA_CSTD::pow(-x, int(derivativeOrder)) / faculty
; | | sum = TmpType(sum + *k * VIGRA_CSTD::pow(-x, int(derivativeOrde
r)) / faculty); | |
| } | | } | |
| } | | } | |
| | | | |
| vigra_precondition(sum != NumericTraits<value_type>::zero(), | | vigra_precondition(sum != NumericTraits<value_type>::zero(), | |
| "Kernel1D<ARITHTYPE>::normalize(): " | | "Kernel1D<ARITHTYPE>::normalize(): " | |
| "Cannot normalize a kernel with sum = 0"); | | "Cannot normalize a kernel with sum = 0"); | |
| // normalize | | // normalize | |
| sum = norm / sum; | | sum = norm / sum; | |
| k = kernel_.begin(); | | k = kernel_.begin(); | |
| for(; k != kernel_.end(); ++k) | | for(; k != kernel_.end(); ++k) | |
| | | | |
| skipping to change at line 1707 | | skipping to change at line 1721 | |
| | | | |
| 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) | |
| { | | { | |
| 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.")
; | |
| | | | |
| if(std_dev > 0.0) | | if(std_dev > 0.0) | |
| { | | { | |
|
| Gaussian<ARITHTYPE> gauss(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 = (int)(3.0 * 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 = -radius; x <= radius; ++x) | | for(ARITHTYPE x = -(ARITHTYPE)radius; x <= (ARITHTYPE)radius; ++x) | |
| { | | { | |
| kernel_.push_back(gauss(x)); | | kernel_.push_back(gauss(x)); | |
| } | | } | |
| left_ = -radius; | | left_ = -radius; | |
| right_ = radius; | | right_ = radius; | |
| } | | } | |
| else | | else | |
| { | | { | |
| kernel_.erase(kernel_.begin(), kernel_.end()); | | kernel_.erase(kernel_.begin(), kernel_.end()); | |
| kernel_.push_back(1.0); | | kernel_.push_back(1.0); | |
| | | | |
| skipping to change at line 1833 | | skipping to change at line 1847 | |
| if(order == 0) | | if(order == 0) | |
| { | | { | |
| initGaussian(std_dev, norm); | | initGaussian(std_dev, norm); | |
| 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."); | |
| | | | |
|
| Gaussian<ARITHTYPE> gauss(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 = (int)(3.0 * std_dev + 0.5 * order + 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; | |
|
| for(ARITHTYPE x = -radius; x <= radius; ++x) | | for(ARITHTYPE x = -(ARITHTYPE)radius; x <= (ARITHTYPE)radius; ++x) | |
| { | | { | |
| kernel_.push_back(gauss(x)); | | kernel_.push_back(gauss(x)); | |
| dc += kernel_[kernel_.size()-1]; | | dc += kernel_[kernel_.size()-1]; | |
| } | | } | |
|
| dc /= (2.0*radius + 1.0); | | dc = ARITHTYPE(dc / (2.0*radius + 1.0)); | |
| | | | |
| // remove DC, but only if kernel correction is permitted by a non-zero | | // remove DC, but only if kernel correction is permitted by a non-zero | |
| // value for norm | | // value for norm | |
| if(norm != 0.0) | | if(norm != 0.0) | |
| { | | { | |
| for(unsigned int i=0; i < kernel_.size(); ++i) | | for(unsigned int i=0; i < kernel_.size(); ++i) | |
| { | | { | |
| kernel_[i] -= dc; | | kernel_[i] -= dc; | |
| } | | } | |
| } | | } | |
| | | | |
| skipping to change at line 1888 | | skipping to change at line 1902 | |
| | | | |
| template <class ARITHTYPE> | | template <class ARITHTYPE> | |
| void | | void | |
| Kernel1D<ARITHTYPE>::initBinomial(int radius, | | Kernel1D<ARITHTYPE>::initBinomial(int radius, | |
| value_type norm) | | value_type norm) | |
| { | | { | |
| vigra_precondition(radius > 0, | | vigra_precondition(radius > 0, | |
| "Kernel1D::initBinomial(): Radius must be > 0."); | | "Kernel1D::initBinomial(): Radius must be > 0."); | |
| | | | |
| // allocate the kernel | | // allocate the kernel | |
|
| InternalVector kernel(radius*2+1); | | InternalVector(radius*2+1).swap(kernel_); | |
| | | typename InternalVector::iterator x = kernel_.begin() + radius; | |
| int i,j; | | | |
| for(i=0; i<radius*2+1; ++i) kernel[i] = 0; | | | |
| | | | |
| // fill kernel | | // fill kernel | |
|
| typename InternalVector::iterator x = kernel.begin() + radius; | | x[radius] = norm; | |
| x[radius] = 1.0; | | for(int j=radius-1; j>=-radius; --j) | |
| | | | |
| for(j=radius-1; j>=-radius; --j) | | | |
| { | | { | |
|
| for(i=j; i<radius; ++i) | | x[j] = 0.5 * x[j+1]; | |
| | | for(int i=j+1; i<radius; ++i) | |
| { | | { | |
|
| x[i] = (x[i] + x[i+1]) / 2.0; | | x[i] = 0.5 * (x[i] + x[i+1]); | |
| } | | } | |
|
| x[radius] /= 2.0; | | x[radius] *= 0.5; | |
| } | | | |
| | | | |
| // normalize | | | |
| kernel_.erase(kernel_.begin(), kernel_.end()); | | | |
| kernel_.reserve(radius*2+1); | | | |
| | | | |
| for(i=0; i<=radius*2+1; ++i) | | | |
| { | | | |
| kernel_.push_back(kernel[i] * norm); | | | |
| } | | } | |
| | | | |
| left_ = -radius; | | left_ = -radius; | |
| right_ = radius; | | right_ = radius; | |
| norm_ = norm; | | norm_ = norm; | |
| | | | |
| // best border treatment for Binomial is BORDER_TREATMENT_REFLECT | | // best border treatment for Binomial is BORDER_TREATMENT_REFLECT | |
| border_treatment_ = BORDER_TREATMENT_REFLECT; | | border_treatment_ = BORDER_TREATMENT_REFLECT; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1961 | | skipping to change at line 1963 | |
| | | | |
| /***********************************************************************/ | | /***********************************************************************/ | |
| | | | |
| template <class ARITHTYPE> | | template <class ARITHTYPE> | |
| void | | void | |
| Kernel1D<ARITHTYPE>::initSymmetricDifference(value_type norm) | | Kernel1D<ARITHTYPE>::initSymmetricDifference(value_type norm) | |
| { | | { | |
| kernel_.erase(kernel_.begin(), kernel_.end()); | | kernel_.erase(kernel_.begin(), kernel_.end()); | |
| kernel_.reserve(3); | | kernel_.reserve(3); | |
| | | | |
|
| kernel_.push_back(0.5 * norm); | | kernel_.push_back(ARITHTYPE(0.5 * norm)); | |
| kernel_.push_back(0.0 * norm); | | kernel_.push_back(ARITHTYPE(0.0 * norm)); | |
| kernel_.push_back(-0.5 * norm); | | kernel_.push_back(ARITHTYPE(-0.5 * norm)); | |
| | | | |
| left_ = -1; | | left_ = -1; | |
| right_ = 1; | | right_ = 1; | |
| norm_ = norm; | | norm_ = norm; | |
| | | | |
| // best border treatment for symmetric difference is | | // best border treatment for symmetric difference is | |
| // BORDER_TREATMENT_REFLECT | | // BORDER_TREATMENT_REFLECT | |
| border_treatment_ = BORDER_TREATMENT_REFLECT; | | border_treatment_ = BORDER_TREATMENT_REFLECT; | |
| } | | } | |
| | | | |
| | | | |
End of changes. 26 change blocks. |
| 52 lines changed or deleted | | 55 lines changed or added | |
|
| splineimageview.hxx | | splineimageview.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2004 by Ullrich Koethe */ | | /* Copyright 1998-2004 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 393 | | skipping to change at line 391 | |
| unsigned int height() const | | unsigned int height() const | |
| { return h_; } | | { return h_; } | |
| | | | |
| /** The size of the image. | | /** The size of the image. | |
| <tt>0 <= x <= size().x-1</tt> and <tt>0 <= y <= size().y-1</tt> | | <tt>0 <= x <= size().x-1</tt> and <tt>0 <= y <= size().y-1</tt> | |
| are required for all access functions. | | are required for all access functions. | |
| */ | | */ | |
| size_type size() const | | size_type size() const | |
| { return size_type(w_, h_); } | | { return size_type(w_, h_); } | |
| | | | |
|
| | | /** The shape of the image. | |
| | | Same as size(), except for the return type. | |
| | | */ | |
| | | TinyVector<unsigned int, 2> shape() const | |
| | | { return TinyVector<unsigned int, 2>(w_, h_); } | |
| | | | |
| /** The internal image holding the spline coefficients. | | /** The internal image holding the spline coefficients. | |
| */ | | */ | |
| InternalImage const & image() const | | InternalImage const & image() const | |
| { | | { | |
| return image_; | | return image_; | |
| } | | } | |
| | | | |
| /** Get the array of polynomial coefficients for the facet containi
ng | | /** Get the array of polynomial coefficients for the facet containi
ng | |
| the point <tt>(x, y)</tt>. The array <tt>res</tt> will be resiz
ed to | | the point <tt>(x, y)</tt>. The array <tt>res</tt> will be resiz
ed to | |
| dimension <tt>(ORDER+1)x(ORDER+1)</tt>. From these coefficients
, the | | dimension <tt>(ORDER+1)x(ORDER+1)</tt>. From these coefficients
, the | |
| | | | |
| skipping to change at line 549 | | skipping to change at line 553 | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <int i, class ValueType> | | template <int i, class ValueType> | |
| struct SplineImageViewUnrollLoop2 | | struct SplineImageViewUnrollLoop2 | |
| { | | { | |
| template <class Array1, class RowIterator, class Array2> | | template <class Array1, class RowIterator, class Array2> | |
| static ValueType | | static ValueType | |
| exec(Array1 k, RowIterator r, Array2 x) | | exec(Array1 k, RowIterator r, Array2 x) | |
| { | | { | |
|
| return k[i] * r[x[i]] + SplineImageViewUnrollLoop2<i-1, ValueType>:
:exec(k, r, x); | | return ValueType(k[i] * r[x[i]]) + SplineImageViewUnrollLoop2<i-1,
ValueType>::exec(k, r, x); | |
| } | | } | |
| }; | | }; | |
| | | | |
| template <class ValueType> | | template <class ValueType> | |
| struct SplineImageViewUnrollLoop2<0, ValueType> | | struct SplineImageViewUnrollLoop2<0, ValueType> | |
| { | | { | |
| template <class Array1, class RowIterator, class Array2> | | template <class Array1, class RowIterator, class Array2> | |
| static ValueType | | static ValueType | |
| exec(Array1 k, RowIterator r, Array2 x) | | exec(Array1 k, RowIterator r, Array2 x) | |
| { | | { | |
|
| return k[0] * r[x[0]]; | | return ValueType(k[0] * r[x[0]]); | |
| } | | } | |
| }; | | }; | |
| | | | |
| } // namespace detail | | } // namespace detail | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| void | | void | |
| SplineImageView<ORDER, VALUETYPE>::calculateIndices(double x, double y) con
st | | SplineImageView<ORDER, VALUETYPE>::calculateIndices(double x, double y) con
st | |
| { | | { | |
| if(x == x_ && y == y_) | | if(x == x_ && y == y_) | |
| | | | |
| skipping to change at line 642 | | skipping to change at line 646 | |
| unsigned int d, double * con
st & c) const | | unsigned int d, double * con
st & c) const | |
| { | | { | |
| t += kcenter_; | | t += kcenter_; | |
| for(int i = 0; i<ksize_; ++i) | | for(int i = 0; i<ksize_; ++i) | |
| c[i] = k_(t-i, d); | | c[i] = k_(t-i, d); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::convolve() const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::convolve() const | |
| { | | { | |
|
| InternalValue sum; | | typedef typename NumericTraits<VALUETYPE>::RealPromote RealPromote; | |
| sum = ky_[0]*detail::SplineImageViewUnrollLoop2<ORDER, InternalValue>:: | | RealPromote sum; | |
| exec(kx_, image_.rowBegin(iy_[0]), ix_); | | sum = RealPromote( | |
| | | ky_[0]*detail::SplineImageViewUnrollLoop2<ORDER, RealPromote>::exec(k | |
| | | x_, image_.rowBegin(iy_[0]), ix_)); | |
| | | | |
| for(int j=1; j<ksize_; ++j) | | for(int j=1; j<ksize_; ++j) | |
| { | | { | |
|
| sum += ky_[j]*detail::SplineImageViewUnrollLoop2<ORDER, InternalVal | | sum += RealPromote( | |
| ue>::exec(kx_, image_.rowBegin(iy_[j]), ix_); | | ky_[j]*detail::SplineImageViewUnrollLoop2<ORDER, RealPromote>::ex | |
| | | ec(kx_, image_.rowBegin(iy_[j]), ix_)); | |
| } | | } | |
|
| return NumericTraits<VALUETYPE>::fromRealPromote(sum); | | return detail::RequiresExplicitCast<VALUETYPE>::cast(sum); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| template <class Array> | | template <class Array> | |
| void | | void | |
| SplineImageView<ORDER, VALUETYPE>::coefficientArray(double x, double y, Arr
ay & res) const | | SplineImageView<ORDER, VALUETYPE>::coefficientArray(double x, double y, Arr
ay & res) const | |
| { | | { | |
| typename Spline::WeightMatrix & weights = Spline::weights(); | | typename Spline::WeightMatrix & weights = Spline::weights(); | |
|
| InternalValue tmp[ksize_][ksize_]; | | double tmp[ksize_][ksize_]; | |
| | | | |
| calculateIndices(x, y); | | calculateIndices(x, y); | |
| for(int j=0; j<ksize_; ++j) | | for(int j=0; j<ksize_; ++j) | |
| { | | { | |
| for(int i=0; i<ksize_; ++i) | | for(int i=0; i<ksize_; ++i) | |
| { | | { | |
| tmp[i][j] = 0.0; | | tmp[i][j] = 0.0; | |
| for(int k=0; k<ksize_; ++k) | | for(int k=0; k<ksize_; ++k) | |
| { | | { | |
| tmp[i][j] += weights[i][k]*image_(ix_[k], iy_[j]); | | tmp[i][j] += weights[i][k]*image_(ix_[k], iy_[j]); | |
| | | | |
| skipping to change at line 714 | | skipping to change at line 721 | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2(double x, double y) const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2(double x, double y) const | |
| { | | { | |
| return sq(dx(x,y)) + sq(dy(x,y)); | | return sq(dx(x,y)) + sq(dy(x,y)); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2x(double x, double y) const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2x(double x, double y) const | |
| { | | { | |
|
| return 2.0*(dx(x,y) * dxx(x,y) + dy(x,y) * dxy(x,y)); | | return VALUETYPE(2.0)*(dx(x,y) * dxx(x,y) + dy(x,y) * dxy(x,y)); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2y(double x, double y) const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2y(double x, double y) const | |
| { | | { | |
|
| return 2.0*(dx(x,y) * dxy(x,y) + dy(x,y) * dyy(x,y)); | | return VALUETYPE(2.0)*(dx(x,y) * dxy(x,y) + dy(x,y) * dyy(x,y)); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2xx(double x, double y) const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2xx(double x, double y) const | |
| { | | { | |
|
| return 2.0*(sq(dxx(x,y)) + dx(x,y) * dx3(x,y) + sq(dxy(x,y)) + dy(x,y)
* dxxy(x,y)); | | return VALUETYPE(2.0)*(sq(dxx(x,y)) + dx(x,y) * dx3(x,y) + sq(dxy(x,y))
+ dy(x,y) * dxxy(x,y)); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2yy(double x, double y) const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2yy(double x, double y) const | |
| { | | { | |
|
| return 2.0*(sq(dxy(x,y)) + dx(x,y) * dxyy(x,y) + sq(dyy(x,y)) + dy(x,y)
* dy3(x,y)); | | return VALUETYPE(2.0)*(sq(dxy(x,y)) + dx(x,y) * dxyy(x,y) + sq(dyy(x,y)
) + dy(x,y) * dy3(x,y)); | |
| } | | } | |
| | | | |
| template <int ORDER, class VALUETYPE> | | template <int ORDER, class VALUETYPE> | |
| VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2xy(double x, double y) const | | VALUETYPE SplineImageView<ORDER, VALUETYPE>::g2xy(double x, double y) const | |
| { | | { | |
|
| return 2.0*(dx(x,y) * dxxy(x,y) + dy(x,y) * dxyy(x,y) + dxy(x,y) * (dxx
(x,y) + dyy(x,y))); | | return VALUETYPE(2.0)*(dx(x,y) * dxxy(x,y) + dy(x,y) * dxyy(x,y) + dxy(
x,y) * (dxx(x,y) + dyy(x,y))); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* SplineImageView0 */ | | /* SplineImageView0 */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| template <class VALUETYPE, class INTERNAL_INDEXER> | | template <class VALUETYPE, class INTERNAL_INDEXER> | |
| class SplineImageView0Base | | class SplineImageView0Base | |
| { | | { | |
| | | | |
| skipping to change at line 947 | | skipping to change at line 954 | |
| | | | |
| unsigned int width() const | | unsigned int width() const | |
| { return w_; } | | { return w_; } | |
| | | | |
| unsigned int height() const | | unsigned int height() const | |
| { return h_; } | | { return h_; } | |
| | | | |
| size_type size() const | | size_type size() const | |
| { return size_type(w_, h_); } | | { return size_type(w_, h_); } | |
| | | | |
|
| | | TinyVector<unsigned int, 2> shape() const | |
| | | { return TinyVector<unsigned int, 2>(w_, h_); } | |
| | | | |
| template <class Array> | | template <class Array> | |
| void coefficientArray(double x, double y, Array & res) const | | void coefficientArray(double x, double y, Array & res) const | |
| { | | { | |
| res.resize(1, 1); | | res.resize(1, 1); | |
| res(0, 0) = operator()(x,y); | | res(0, 0) = operator()(x,y); | |
| } | | } | |
| | | | |
| bool isInsideX(double x) const | | bool isInsideX(double x) const | |
| { | | { | |
| return x >= 0.0 && x <= width() - 1.0; | | return x >= 0.0 && x <= width() - 1.0; | |
| | | | |
| skipping to change at line 971 | | skipping to change at line 981 | |
| return y >= 0.0 && y <= height() - 1.0; | | return y >= 0.0 && y <= height() - 1.0; | |
| } | | } | |
| | | | |
| bool isInside(double x, double y) const | | bool isInside(double x, double y) const | |
| { | | { | |
| return isInsideX(x) && isInsideY(y); | | return isInsideX(x) && isInsideY(y); | |
| } | | } | |
| | | | |
| bool isValid(double x, double y) const | | bool isValid(double x, double y) const | |
| { | | { | |
|
| return x < 2.0*w_-2.0 && x > -w_+1.0 && y < 2.0*h_-2.0 && y > -h_+1
.0; | | return x < 2.0*w_-2.0 && x > 1.0-w_ && y < 2.0*h_-2.0 && y > 1.0-h_
; | |
| } | | } | |
| | | | |
| bool sameFacet(double x0, double y0, double x1, double y1) const | | bool sameFacet(double x0, double y0, double x1, double y1) const | |
| { | | { | |
| x0 = VIGRA_CSTD::floor(x0 + 0.5); | | x0 = VIGRA_CSTD::floor(x0 + 0.5); | |
| y0 = VIGRA_CSTD::floor(y0 + 0.5); | | y0 = VIGRA_CSTD::floor(y0 + 0.5); | |
| x1 = VIGRA_CSTD::floor(x1 + 0.5); | | x1 = VIGRA_CSTD::floor(x1 + 0.5); | |
| y1 = VIGRA_CSTD::floor(y1 + 0.5); | | y1 = VIGRA_CSTD::floor(y1 + 0.5); | |
| return x0 == x1 && y0 == y1; | | return x0 == x1 && y0 == y1; | |
| } | | } | |
| | | | |
| skipping to change at line 1336 | | skipping to change at line 1346 | |
| int iy = (int)std::floor(y); | | int iy = (int)std::floor(y); | |
| if(iy == (int)h_ - 1) | | if(iy == (int)h_ - 1) | |
| --iy; | | --iy; | |
| double ty = y - iy; | | double ty = y - iy; | |
| switch(dx) | | switch(dx) | |
| { | | { | |
| case 0: | | case 0: | |
| switch(dy) | | switch(dy) | |
| { | | { | |
| case 0: | | case 0: | |
|
| return NumericTraits<value_type>::fromRealPromote( | | return detail::RequiresExplicitCast<value_type>::cast( | |
| (1.0-ty)*((1.0-tx)*internalIndexer_(ix,iy) +
tx*internalIndexer_(ix+1,iy)) + | | (1.0-ty)*((1.0-tx)*internalIndexer_(ix,iy) +
tx*internalIndexer_(ix+1,iy)) + | |
| ty *((1.0-tx)*internalIndexer_(ix,iy+1) + t
x*internalIndexer_(ix+1,iy+1))); | | ty *((1.0-tx)*internalIndexer_(ix,iy+1) + t
x*internalIndexer_(ix+1,iy+1))); | |
| case 1: | | case 1: | |
|
| return NumericTraits<value_type>::fromRealPromote( | | return detail::RequiresExplicitCast<value_type>::cast( | |
| ((1.0-tx)*internalIndexer_(ix,iy+1) + tx*int
ernalIndexer_(ix+1,iy+1)) - | | ((1.0-tx)*internalIndexer_(ix,iy+1) + tx*int
ernalIndexer_(ix+1,iy+1)) - | |
| ((1.0-tx)*internalIndexer_(ix,iy) + tx*inter
nalIndexer_(ix+1,iy))); | | ((1.0-tx)*internalIndexer_(ix,iy) + tx*inter
nalIndexer_(ix+1,iy))); | |
| default: | | default: | |
| return NumericTraits<VALUETYPE>::zero(); | | return NumericTraits<VALUETYPE>::zero(); | |
| } | | } | |
| case 1: | | case 1: | |
| switch(dy) | | switch(dy) | |
| { | | { | |
| case 0: | | case 0: | |
|
| return NumericTraits<value_type>::fromRealPromote( | | return detail::RequiresExplicitCast<value_type>::cast( | |
| (1.0-ty)*(internalIndexer_(ix+1,iy) - intern
alIndexer_(ix,iy)) + | | (1.0-ty)*(internalIndexer_(ix+1,iy) - intern
alIndexer_(ix,iy)) + | |
| ty *(internalIndexer_(ix+1,iy+1) - internal
Indexer_(ix,iy+1))); | | ty *(internalIndexer_(ix+1,iy+1) - internal
Indexer_(ix,iy+1))); | |
| case 1: | | case 1: | |
| return detail::RequiresExplicitCast<value_type>::cast( | | return detail::RequiresExplicitCast<value_type>::cast( | |
| (internalIndexer_(ix+1,iy+1) - internalIndexe
r_(ix,iy+1)) - | | (internalIndexer_(ix+1,iy+1) - internalIndexe
r_(ix,iy+1)) - | |
| (internalIndexer_(ix+1,iy) - internalIndexer_
(ix,iy))); | | (internalIndexer_(ix+1,iy) - internalIndexer_
(ix,iy))); | |
| default: | | default: | |
| return NumericTraits<VALUETYPE>::zero(); | | return NumericTraits<VALUETYPE>::zero(); | |
| } | | } | |
| default: | | default: | |
| | | | |
| skipping to change at line 1513 | | skipping to change at line 1523 | |
| | | | |
| unsigned int width() const | | unsigned int width() const | |
| { return w_; } | | { return w_; } | |
| | | | |
| unsigned int height() const | | unsigned int height() const | |
| { return h_; } | | { return h_; } | |
| | | | |
| size_type size() const | | size_type size() const | |
| { return size_type(w_, h_); } | | { return size_type(w_, h_); } | |
| | | | |
|
| | | TinyVector<unsigned int, 2> shape() const | |
| | | { return TinyVector<unsigned int, 2>(w_, h_); } | |
| | | | |
| template <class Array> | | template <class Array> | |
| void coefficientArray(double x, double y, Array & res) const; | | void coefficientArray(double x, double y, Array & res) const; | |
| | | | |
| void calculateIndices(double x, double y, int & ix, int & iy, int & ix1
, int & iy1) const; | | void calculateIndices(double x, double y, int & ix, int & iy, int & ix1
, int & iy1) const; | |
| | | | |
| bool isInsideX(double x) const | | bool isInsideX(double x) const | |
| { | | { | |
| return x >= 0.0 && x <= width() - 1.0; | | return x >= 0.0 && x <= width() - 1.0; | |
| } | | } | |
| | | | |
| | | | |
End of changes. 21 change blocks. |
| 21 lines changed or deleted | | 34 lines changed or added | |
|
| stdconvolution.hxx | | stdconvolution.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 58 | |
| 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 KSumType> | | class KSumType> | |
| void internalPixelEvaluationByClip(int x, int y, int w, int h, SrcIterator
xs, | | void internalPixelEvaluationByClip(int x, int y, int w, int h, SrcIterator
xs, | |
| SrcAccessor src_acc, DestIterator xd, De
stAccessor dest_acc, | | SrcAccessor src_acc, DestIterator xd, De
stAccessor dest_acc, | |
| KernelIterator ki, Diff2D kul, Diff2D kl
r, KernelAccessor ak, | | KernelIterator ki, Diff2D kul, Diff2D kl
r, KernelAccessor ak, | |
| KSumType norm) | | KSumType norm) | |
| { | | { | |
| typedef typename | | typedef typename | |
|
| NumericTraits<typename SrcAccessor::value_type>::RealPromote SumTyp | | PromoteTraits<typename SrcAccessor::value_type, | |
| e; | | typename KernelAccessor::value_type>::Promote SumType | |
| typedef | | ; | |
| NumericTraits<typename DestAccessor::value_type> DestTraits; | | typedef typename DestAccessor::value_type DestType; | |
| | | | |
| // 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; | |
| | | | |
| SumType sum = NumericTraits<SumType>::zero(); | | SumType sum = NumericTraits<SumType>::zero(); | |
| int xx, yy; | | int xx, yy; | |
| int x0, y0, x1, y1; | | int x0, y0, x1, y1; | |
| | | | |
| y0 = (y<klr.y) ? -y : -klr.y; | | y0 = (y<klr.y) ? -y : -klr.y; | |
| | | | |
| skipping to change at line 100 | | skipping to change at line 98 | |
| KernelIterator xk = yk; | | KernelIterator xk = yk; | |
| | | | |
| for(xx=0; xx<kernel_width; ++xx, ++xxs.x, --xk.x) | | for(xx=0; xx<kernel_width; ++xx, ++xxs.x, --xk.x) | |
| { | | { | |
| sum += ak(xk) * src_acc(xxs); | | sum += ak(xk) * src_acc(xxs); | |
| ksum += ak(xk); | | ksum += ak(xk); | |
| } | | } | |
| } | | } | |
| | | | |
| // store average in destination pixel | | // store average in destination pixel | |
|
| dest_acc.set(DestTraits::fromRealPromote((norm / ksum) * sum), xd); | | dest_acc.set(detail::RequiresExplicitCast<DestType>::cast((norm / ksum) | |
| | | * sum), xd); | |
| } | | } | |
| | | | |
| #if 0 | | #if 0 | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class KernelIterator, class KernelAccessor> | | class KernelIterator, class KernelAccessor> | |
| void internalPixelEvaluationByWrapReflectRepeat(int x, int y, int src_width
, int src_height, SrcIterator xs, | | void internalPixelEvaluationByWrapReflectRepeat(int x, int y, int src_width
, int src_height, SrcIterator xs, | |
| SrcAccessor src_acc, DestIt
erator xd, DestAccessor dest_acc, | | SrcAccessor src_acc, DestIt
erator xd, DestAccessor dest_acc, | |
| KernelIterator ki, Diff2D k
ul, Diff2D klr, KernelAccessor ak, | | KernelIterator ki, Diff2D k
ul, Diff2D klr, KernelAccessor ak, | |
| | | | |
| skipping to change at line 482 | | skipping to change at line 479 | |
| vigra_precondition(klr.x >= 0 && klr.y >= 0, | | vigra_precondition(klr.x >= 0 && klr.y >= 0, | |
| "convolveImage(): coordinates of " | | "convolveImage(): coordinates of " | |
| "kernel's lower right must be >= 0."); | | "kernel's lower right must be >= 0."); | |
| | | | |
| // use traits to determine SumType as to prevent possible overflow | | // use traits to determine SumType as to prevent possible overflow | |
| typedef typename | | typedef typename | |
| PromoteTraits<typename SrcAccessor::value_type, | | PromoteTraits<typename SrcAccessor::value_type, | |
| typename KernelAccessor::value_type>::Promote SumType
; | | typename KernelAccessor::value_type>::Promote SumType
; | |
| typedef typename | | typedef typename | |
| NumericTraits<typename KernelAccessor::value_type>::RealPromote Ker
nelSumType; | | NumericTraits<typename KernelAccessor::value_type>::RealPromote Ker
nelSumType; | |
|
| typedef | | typedef typename DestAccessor::value_type DestType; | |
| NumericTraits<typename DestAccessor::value_type> DestTraits; | | | |
| | | | |
| // 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 >= kernel_width && h >= kernel_height, | |
| | | | |
| skipping to change at line 549 | | skipping to change at line 545 | |
| typename SrcIterator::row_iterator xxe = xxs + kernel_width
; | | typename SrcIterator::row_iterator xxe = xxs + kernel_width
; | |
| typename KernelIterator::row_iterator xk = yk.rowIterator(
); | | typename KernelIterator::row_iterator xk = yk.rowIterator(
); | |
| | | | |
| for(; xxs < xxe; ++xxs, --xk) | | for(; xxs < xxe; ++xxs, --xk) | |
| { | | { | |
| sum += ak(xk) * src_acc(xxs); | | sum += ak(xk) * src_acc(xxs); | |
| } | | } | |
| } | | } | |
| | | | |
| // store convolution result in destination pixel | | // store convolution result in destination pixel | |
|
| dest_acc.set(DestTraits::fromRealPromote(sum), xd); | | dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(sum),
xd); | |
| } | | } | |
| } | | } | |
| | | | |
| if(border == BORDER_TREATMENT_AVOID) | | if(border == BORDER_TREATMENT_AVOID) | |
| return; // skip processing near the border | | return; // skip processing near the border | |
| | | | |
| int interiorskip = w + kul.x - klr.x - 1; | | int interiorskip = w + kul.x - klr.x - 1; | |
|
| int borderskipx; | | int borderskipx = 0; | |
| int borderskipy; | | int borderskipy = 0; | |
| int borderinc; | | int borderinc = 0; | |
| if(border == BORDER_TREATMENT_REPEAT) | | if(border == BORDER_TREATMENT_REPEAT) | |
| { | | { | |
| borderskipx = 0; | | borderskipx = 0; | |
| borderskipy = 0; | | borderskipy = 0; | |
| borderinc = 0; | | borderinc = 0; | |
| } | | } | |
| else if(border == BORDER_TREATMENT_REFLECT) | | else if(border == BORDER_TREATMENT_REFLECT) | |
| { | | { | |
| borderskipx = -1; | | borderskipx = -1; | |
| borderskipy = -1; | | borderskipy = -1; | |
| | | | |
| skipping to change at line 586 | | skipping to change at line 582 | |
| borderinc = 1; | | borderinc = 1; | |
| } | | } | |
| | | | |
| // create iterators for the entire image | | // create iterators for the entire image | |
| yd = dest_ul; | | yd = dest_ul; | |
| ys = src_ul; | | ys = src_ul; | |
| | | | |
| // work on entire image (but skip the already computed points in the lo
op) | | // 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) | | for(int y = 0; y < h; ++y, ++ys.y, ++yd.y) | |
| { | | { | |
|
| int top = std::max(static_cast<IntBiggest>(-klr.y), | | int top = int(std::max(static_cast<IntBiggest>(-klr.y), | |
| static_cast<IntBiggest>(src_ul.y - ys.y)); | | static_cast<IntBiggest>(src_ul.y - ys.y)) | |
| int bottom = std::min(static_cast<IntBiggest>(-kul.y), | | ); | |
| static_cast<IntBiggest>(src_lr.y - ys.y - 1)) | | int bottom = int(std::min(static_cast<IntBiggest>(-kul.y), | |
| ; | | static_cast<IntBiggest>(src_lr.y - ys.y - | |
| | | 1))); | |
| | | | |
| // create x iterators | | // create x iterators | |
| DestIterator xd(yd); | | DestIterator xd(yd); | |
| SrcIterator xs(ys); | | SrcIterator xs(ys); | |
| | | | |
| for(int x = 0; x < w; ++x, ++xs.x, ++xd.x) | | for(int x = 0; x < w; ++x, ++xs.x, ++xd.x) | |
| { | | { | |
| // check if we are away from the border | | // check if we are away from the border | |
| if(y >= klr.y && y < h+kul.y && x == klr.x) | | if(y >= klr.y && y < h+kul.y && x == klr.x) | |
| { | | { | |
| | | | |
| skipping to change at line 644 | | skipping to change at line 640 | |
| } | | } | |
| yys = xs + Size2D(0, bottom + borderskipy); | | yys = xs + Size2D(0, bottom + borderskipy); | |
| yk = ki - Size2D(0, bottom + 1); | | yk = ki - Size2D(0, bottom + 1); | |
| for(yy = bottom + 1; yy <= -kul.y; ++yy, yys.y += borderinc
, --yk.y) | | for(yy = bottom + 1; yy <= -kul.y; ++yy, yys.y += borderinc
, --yk.y) | |
| { | | { | |
| internalPixelEvaluationByWrapReflectRepeat(yys.rowItera
tor(), src_acc, yk.rowIterator(), ak, | | internalPixelEvaluationByWrapReflectRepeat(yys.rowItera
tor(), src_acc, yk.rowIterator(), ak, | |
| left, right, kul.x, klr.x, borderskipx, borderinc,
sum); | | left, right, kul.x, klr.x, borderskipx, borderinc,
sum); | |
| } | | } | |
| | | | |
| // store convolution result in destination pixel | | // store convolution result in destination pixel | |
|
| dest_acc.set(DestTraits::fromRealPromote(sum), xd); | | dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(s
um), xd); | |
| | | | |
| // internalPixelEvaluationByWrapReflectRepeat(x, y, w, h, xs
, src_acc, xd, dest_acc, ki, kul, klr, ak, border); | | // internalPixelEvaluationByWrapReflectRepeat(x, y, w, h, xs
, src_acc, xd, dest_acc, ki, kul, klr, ak, border); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class KernelIterator, class KernelAccessor> | | class KernelIterator, class KernelAccessor> | |
| | | | |
| skipping to change at line 909 | | skipping to change at line 905 | |
| typename SrcIterator::row_iterator xxend = xxs + kernel_wid
th; | | typename SrcIterator::row_iterator xxend = xxs + kernel_wid
th; | |
| typename MaskIterator::row_iterator xxm = yym.rowIterator()
; | | typename MaskIterator::row_iterator xxm = yym.rowIterator()
; | |
| typename KernelIterator::row_iterator xk = yk.rowIterator(
); | | typename KernelIterator::row_iterator xk = yk.rowIterator(
); | |
| | | | |
| for(xx=0; xxs < xxend; ++xxs, --xk, ++xxm) | | for(xx=0; xxs < xxend; ++xxs, --xk, ++xxm) | |
| { | | { | |
| if(!am(xxm)) continue; | | if(!am(xxm)) continue; | |
| | | | |
| if(first) | | if(first) | |
| { | | { | |
|
| sum = ak(xk) * src_acc(xxs); | | sum = detail::RequiresExplicitCast<SumType>::cast(a
k(xk) * src_acc(xxs)); | |
| ksum = ak(xk); | | ksum = ak(xk); | |
| first = false; | | first = false; | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| sum += 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(!first && | |
| ksum != NumericTraits<KSumType>::zero()) | | ksum != NumericTraits<KSumType>::zero()) | |
| { | | { | |
|
| dest_acc.set(DestTraits::fromRealPromote((norm / ksum) * su | | dest_acc.set(DestTraits::fromRealPromote( | |
| m), xd); | | detail::RequiresExplicitCast<SumType>::cast((n | |
| | | orm / ksum) * sum)), xd); | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class MaskIterator, class MaskAccessor, | | class MaskIterator, class MaskAccessor, | |
| class KernelIterator, class KernelAccessor> | | class KernelIterator, class KernelAccessor> | |
| inline | | inline | |
| | | | |
| skipping to change at line 1230 | | skipping to change at line 1227 | |
| | | | |
| <b> Required Interface:</b> | | <b> Required Interface:</b> | |
| | | | |
| The kernel's value_type must be a linear algebra. | | The kernel's value_type must be a linear algebra. | |
| | | | |
| \code | | \code | |
| vigra::Kernel2D<...>::value_type v; | | vigra::Kernel2D<...>::value_type v; | |
| v = v * v; | | v = v * v; | |
| \endcode | | \endcode | |
| */ | | */ | |
|
| void initSeparable(Kernel1D<value_type> & kx, | | void initSeparable(Kernel1D<value_type> const & kx, | |
| Kernel1D<value_type> & ky) | | Kernel1D<value_type> const & ky) | |
| { | | { | |
| left_ = Diff2D(kx.left(), ky.left()); | | left_ = Diff2D(kx.left(), ky.left()); | |
| right_ = Diff2D(kx.right(), ky.right()); | | right_ = Diff2D(kx.right(), ky.right()); | |
| int w = right_.x - left_.x + 1; | | int w = right_.x - left_.x + 1; | |
| int h = right_.y - left_.y + 1; | | int h = right_.y - left_.y + 1; | |
| kernel_.resize(w, h); | | kernel_.resize(w, h); | |
| | | | |
| norm_ = kx.norm() * ky.norm(); | | norm_ = kx.norm() * ky.norm(); | |
| | | | |
|
| typedef typename Kernel1D<value_type>::Iterator KIter; | | typedef typename Kernel1D<value_type>::const_iterator KIter; | |
| typename Kernel1D<value_type>::Accessor ka; | | typename Kernel1D<value_type>::Accessor ka; | |
| | | | |
| KIter kiy = ky.center() + left_.y; | | KIter kiy = ky.center() + left_.y; | |
| Iterator iy = center() + left_; | | Iterator iy = center() + left_; | |
| | | | |
| for(int y=left_.y; y<=right_.y; ++y, ++kiy, ++iy.y) | | for(int y=left_.y; y<=right_.y; ++y, ++kiy, ++iy.y) | |
| { | | { | |
| KIter kix = kx.center() + left_.x; | | KIter kix = kx.center() + left_.x; | |
| Iterator ix = iy; | | Iterator ix = iy; | |
| for(int x=left_.x; x<=right_.x; ++x, ++kix, ++ix.x) | | for(int x=left_.x; x<=right_.x; ++x, ++kix, ++ix.x) | |
| | | | |
| skipping to change at line 1321 | | skipping to change at line 1318 | |
| typename BasicImage<value_type>::iterator iend = kernel_.end(); | | typename BasicImage<value_type>::iterator iend = kernel_.end(); | |
| norm_ = *i; | | norm_ = *i; | |
| ++i; | | ++i; | |
| | | | |
| for(; i!= iend; ++i) | | for(; i!= iend; ++i) | |
| { | | { | |
| norm_ += *i; | | norm_ += *i; | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | /** Init as a 2D Gaussian function with given standard deviation an | |
| | | d norm. | |
| | | */ | |
| | | void initGaussian(double std_dev, value_type norm) | |
| | | { | |
| | | Kernel1D<value_type> gauss; | |
| | | gauss.initGaussian(std_dev, norm); | |
| | | initSeparable(gauss, gauss); | |
| | | } | |
| | | | |
| | | /** Init as a 2D Gaussian function with given standard deviation an | |
| | | d unit norm. | |
| | | */ | |
| | | void initGaussian(double std_dev) | |
| | | { | |
| | | initGaussian(std_dev, NumericTraits<value_type>::one()); | |
| | | } | |
| | | | |
| /** Init the 2D kernel as a circular averaging filter. The norm wil
l be | | /** Init the 2D kernel as a circular averaging filter. The norm wil
l be | |
| calculated as | | calculated as | |
| <TT>NumericTraits<value_type>::one() / (number of non-zero kern
el values)</TT>. | | <TT>NumericTraits<value_type>::one() / (number of non-zero kern
el values)</TT>. | |
| The kernel's value_type must be a linear space. | | The kernel's value_type must be a linear space. | |
| | | | |
| <b> Required Interface:</b> | | <b> Required Interface:</b> | |
| | | | |
| \code | | \code | |
| value_type v = vigra::NumericTraits<value_type>::one(); | | value_type v = vigra::NumericTraits<value_type>::one(); | |
| | | | |
| | | | |
End of changes. 16 change blocks. |
| 28 lines changed or deleted | | 45 lines changed or added | |
|
| tensorutilities.hxx | | tensorutilities.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2002-2004 by Ullrich Koethe */ | | /* Copyright 2002-2004 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 43 | | 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_TENSORUTILITIES_HXX | | #ifndef VIGRA_TENSORUTILITIES_HXX | |
| #define VIGRA_TENSORUTILITIES_HXX | | #define VIGRA_TENSORUTILITIES_HXX | |
| | | | |
| #include <cmath> | | #include <cmath> | |
| #include "utilities.hxx" | | #include "utilities.hxx" | |
|
| | | #include "mathutil.hxx" | |
| | | | |
| namespace vigra { | | namespace vigra { | |
| | | | |
| /** \addtogroup TensorImaging Tensor Image Processing | | /** \addtogroup TensorImaging Tensor Image Processing | |
| */ | | */ | |
| //@{ | | //@{ | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* vectorToTensor */ | | /* vectorToTensor */ | |
| | | | |
| skipping to change at line 64 | | skipping to change at line 63 | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Calculate the tensor (outer) product of a 2D vector with itself. | | /** \brief Calculate the tensor (outer) product of a 2D vector with itself. | |
| | | | |
| This function is useful to transform vector images into a tensor repres
entation | | This function is useful to transform vector images into a tensor repres
entation | |
| that can be used as input to tensor based processing and analysis funct
ions | | that can be used as input to tensor based processing and analysis funct
ions | |
| (e.g. tensor smoothing). The imput pixel type must be vectors of length
2, whereas | | (e.g. tensor smoothing). The imput pixel type must be vectors of length
2, whereas | |
| the output must contain vectors of length 3 which will represent the te
nsor components | | the output must contain vectors of length 3 which will represent the te
nsor components | |
| in the order t11, t12 (== t21 due to symmetry), t22. | | in the order t11, t12 (== t21 due to symmetry), t22. | |
| | | | |
|
| <b>Note:</b> By default, this function negates the second component of | | <b>Note:</b> In order to account for the left-handedness of the image c | |
| the vector | | oordinate system, | |
| in order to turn a left handed vector (the usual resul of convolution, | | the second tensor component (t12) can be negated by setting <tt>negateC | |
| e.g. a gradient filter, because <tt>y</tt> runs from top to bottom) | | omponent2 = false</tt>. | |
| into a right handed tensor (as is required by all tensor function in VI | | Angles will then be interpreted counter-clockwise rather than clockwise | |
| GRA). This | | . By default, | |
| behavior can be switched off by setting <tt>negateComponent2 = false</t | | this behavior is switched off. | |
| t>. | | | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass arguments explicitly: | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor s
rc, | | void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor s
rc, | |
| DestIterator dul, DestAccessor dest, | | DestIterator dul, DestAccessor dest, | |
|
| bool negateComponent2 = true); | | bool negateComponent2 = false); | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| use argument objects in conjunction with \ref ArgumentObjectFactories : | | use argument objects in conjunction with \ref ArgumentObjectFactories : | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s
, | | void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s
, | |
| pair<DestIterator, DestAccessor> d, | | pair<DestIterator, DestAccessor> d, | |
|
| bool negateComponent2 = true); | | bool negateComponent2 = false); | |
| } | | } | |
| \endcode | | \endcode | |
| | | | |
| <b> Usage:</b> | | <b> Usage:</b> | |
| | | | |
| <b>\#include</b> \<<a href="tensorutilities_8hxx-source.html">vigra/ten
sorutilities.hxx</a>\> | | <b>\#include</b> \<<a href="tensorutilities_8hxx-source.html">vigra/ten
sorutilities.hxx</a>\> | |
| | | | |
| \code | | \code | |
| FImage img(w,h); | | FImage img(w,h); | |
| FVector2Image gradient(w,h); | | FVector2Image gradient(w,h); | |
| | | | |
| skipping to change at line 157 | | skipping to change at line 155 | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, | | void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, | |
| DestIterator dul, DestAccessor dest) | | DestIterator dul, DestAccessor dest) | |
| { | | { | |
|
| vectorToTensor(sul, slr, src, dul, dest, true); | | vectorToTensor(sul, slr, src, dul, dest, false); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, | | void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, | |
| pair<DestIterator, DestAccessor> d, | | pair<DestIterator, DestAccessor> d, | |
| bool negateComponent2) | | bool negateComponent2) | |
| { | | { | |
| vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateCom
ponent2); | | vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateCom
ponent2); | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline | | inline | |
| void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, | | void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, | |
| pair<DestIterator, DestAccessor> d) | | pair<DestIterator, DestAccessor> d) | |
| { | | { | |
|
| vectorToTensor(s.first, s.second, s.third, d.first, d.second, true); | | vectorToTensor(s.first, s.second, s.third, d.first, d.second, false); | |
| } | | } | |
| | | | |
| /********************************************************/ | | /********************************************************/ | |
| /* */ | | /* */ | |
| /* tensorEigenRepresentation */ | | /* tensorEigenRepresentation */ | |
| /* */ | | /* */ | |
| /********************************************************/ | | /********************************************************/ | |
| | | | |
| /** \brief Calculate eigen representation of a symmetric 2x2 tensor. | | /** \brief Calculate eigen representation of a symmetric 2x2 tensor. | |
| | | | |
| This function turns a 3-band image representing the tensor components | | This function turns a 3-band image representing the tensor components | |
| t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding
the eigen | | t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding
the eigen | |
|
| representation e1, e2, and angle, where e1 \> e2. The original tensor m | | representation e1, e2, and angle, where e1 \> e2. When the tensor is | |
| ust be | | defined in a left-handed coordinate system (the default on images), the | |
| defined in a right-handed coordinate system, and the angle of the tenso | | angle will | |
| r will | | then be given in clockwise orientation, starting at the x-axis. Otherwi | |
| then be given in mathematical positive (counter-clockwise) orientation, | | se, it | |
| starting | | will be given in counter-clockwise orientation. | |
| at the x-axis. | | | |
| | | | |
| <b> Declarations:</b> | | <b> Declarations:</b> | |
| | | | |
| pass arguments explicitly: | | pass arguments explicitly: | |
| \code | | \code | |
| namespace vigra { | | namespace vigra { | |
| template <class SrcIterator, class SrcAccessor, | | template <class SrcIterator, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, Sr
cAccessor src, | | void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, Sr
cAccessor src, | |
| DestIterator dul, DestAccessor dest)
; | | DestIterator dul, DestAccessor dest)
; | |
| | | | |
| skipping to change at line 254 | | skipping to change at line 252 | |
| { | | { | |
| typename SrcIterator::row_iterator s = sul.rowIterator(); | | typename SrcIterator::row_iterator s = sul.rowIterator(); | |
| typename SrcIterator::row_iterator send = s + w; | | typename SrcIterator::row_iterator send = s + w; | |
| typename DestIterator::row_iterator d = dul.rowIterator(); | | typename DestIterator::row_iterator d = dul.rowIterator(); | |
| for(; s < send; ++s, ++d) | | for(; s < send; ++s, ++d) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::component_type>::RealPro
mote TmpType; | | NumericTraits<typename SrcAccessor::component_type>::RealPro
mote TmpType; | |
| TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); | | TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); | |
| TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); | | TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); | |
|
| TmpType d3 = 2.0 * src.getComponent(s,1); | | TmpType d3 = TmpType(2.0) * src.getComponent(s,1); | |
| TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3)); | | TmpType d4 = (TmpType)hypot(d2, d3); | |
| | | | |
| dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV | | dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV | |
| dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV | | dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV | |
| if(d2==0.0 && d3==0.0) | | if(d2==0.0 && d3==0.0) | |
| { | | { | |
| dest.setComponent(0, d, 2); // orientation | | dest.setComponent(0, d, 2); // orientation | |
| } | | } | |
| else | | else | |
| { | | { | |
| dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); /
/ orientation | | dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); /
/ orientation | |
| | | | |
| skipping to change at line 445 | | skipping to change at line 443 | |
| typename SrcIterator::row_iterator send = s + w; | | typename SrcIterator::row_iterator send = s + w; | |
| typename DestIterator1::row_iterator e = edgeul.rowIterator(); | | typename DestIterator1::row_iterator e = edgeul.rowIterator(); | |
| typename DestIterator2::row_iterator c = cornerul.rowIterator(); | | typename DestIterator2::row_iterator c = cornerul.rowIterator(); | |
| for(; s < send; ++s, ++e, ++c) | | for(; s < send; ++s, ++e, ++c) | |
| { | | { | |
| typedef typename | | typedef typename | |
| NumericTraits<typename SrcAccessor::component_type>::RealPro
mote TmpType; | | NumericTraits<typename SrcAccessor::component_type>::RealPro
mote TmpType; | |
| TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); | | TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); | |
| TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); | | TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); | |
| TmpType d3 = 2.0 * src.getComponent(s,1); | | TmpType d3 = 2.0 * src.getComponent(s,1); | |
|
| TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3)); | | TmpType d4 = (TmpType)hypot(d2, d3); | |
| | | | |
| edge.setComponent(d4, e, 0); // edgeness = difference of EVs | | edge.setComponent(d4, e, 0); // edgeness = difference of EVs | |
| if(d2 == 0.0 && d3 == 0.0) | | if(d2 == 0.0 && d3 == 0.0) | |
| { | | { | |
| edge.setComponent(0.0, e, 1); // orientation | | edge.setComponent(0.0, e, 1); // orientation | |
| } | | } | |
| else | | else | |
| { | | { | |
| edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); /
/ orientation | | edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); /
/ orientation | |
| } | | } | |
| | | | |
End of changes. 12 change blocks. |
| 25 lines changed or deleted | | 22 lines changed or added | |
|
| tinyvector.hxx | | tinyvector.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 1998-2002 by Ullrich Koethe */ | | /* Copyright 1998-2002 by Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 46 | | skipping to change at line 44 | |
| /************************************************************************/ | | /************************************************************************/ | |
| | | | |
| #ifndef VIGRA_TINYVECTOR_HXX | | #ifndef VIGRA_TINYVECTOR_HXX | |
| #define VIGRA_TINYVECTOR_HXX | | #define VIGRA_TINYVECTOR_HXX | |
| | | | |
| #include <cmath> // abs(double) | | #include <cmath> // abs(double) | |
| #include <cstdlib> // abs(int) | | #include <cstdlib> // abs(int) | |
| #include <iosfwd> // ostream | | #include <iosfwd> // ostream | |
| #include "config.hxx" | | #include "config.hxx" | |
| #include "error.hxx" | | #include "error.hxx" | |
|
| | | #include "metaprogramming.hxx" | |
| #include "numerictraits.hxx" | | #include "numerictraits.hxx" | |
|
| | | #include "memory.hxx" | |
| #include "mathutil.hxx" | | #include "mathutil.hxx" | |
|
| | | #include "diff2d.hxx" | |
| | | | |
| | | #ifdef VIGRA_CHECK_BOUNDS | |
| | | #define VIGRA_ASSERT_INSIDE(diff) \ | |
| | | vigra_precondition(diff >= 0, "Index out of bounds");\ | |
| | | vigra_precondition(diff < SIZE, "Index out of bounds"); | |
| | | #else | |
| | | #define VIGRA_ASSERT_INSIDE(diff) | |
| | | #endif | |
| | | | |
| namespace vigra { | | namespace vigra { | |
| | | | |
| using VIGRA_CSTD::abs; | | using VIGRA_CSTD::abs; | |
| using VIGRA_CSTD::ceil; | | using VIGRA_CSTD::ceil; | |
| using VIGRA_CSTD::floor; | | using VIGRA_CSTD::floor; | |
| | | | |
| template <class V1, int SIZE, class D1, class D2> | | template <class V1, int SIZE, class D1, class D2> | |
| class TinyVectorBase; | | class TinyVectorBase; | |
| | | | |
| | | | |
| skipping to change at line 78 | | skipping to change at line 87 | |
| { \ | | { \ | |
| for(int i=0; i<LEVEL; ++i) \ | | for(int i=0; i<LEVEL; ++i) \ | |
| (left[i]) OPER (right[i]); \ | | (left[i]) OPER (right[i]); \ | |
| } | | } | |
| | | | |
| #define VIGRA_EXEC_LOOP_SCALAR(NAME, OPER) \ | | #define VIGRA_EXEC_LOOP_SCALAR(NAME, OPER) \ | |
| template <class T1, class T2> \ | | template <class T1, class T2> \ | |
| static void NAME(T1 * left, T2 right) \ | | static void NAME(T1 * left, T2 right) \ | |
| { \ | | { \ | |
| for(int i=0; i<LEVEL; ++i) \ | | for(int i=0; i<LEVEL; ++i) \ | |
|
| (left[i]) OPER (right); \ | | (left[i]) = detail::RequiresExplicitCast<T1>::cast((left[i]) OP
ER (right)); \ | |
| } | | } | |
| | | | |
| template <int LEVEL> | | template <int LEVEL> | |
| struct ExecLoop | | struct ExecLoop | |
| { | | { | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void assignCast(T1 * left, T2 const * right) | | static void assignCast(T1 * left, T2 const * right) | |
| { | | { | |
| for(int i=0; i<LEVEL; ++i) | | for(int i=0; i<LEVEL; ++i) | |
| left[i] = detail::RequiresExplicitCast<T1>::cast(right[i]); | | left[i] = detail::RequiresExplicitCast<T1>::cast(right[i]); | |
| } | | } | |
| | | | |
|
| | | template <class T1, class T2> | |
| | | static void reverseAssign(T1 * left, T2 const * right) | |
| | | { | |
| | | for(int i=0; i<LEVEL; ++i) | |
| | | left[i] = right[-i]; | |
| | | } | |
| | | | |
| | | template <class T1, class T2> | |
| | | static void assignScalar(T1 * left, T2 right) | |
| | | { | |
| | | for(int i=0; i<LEVEL; ++i) | |
| | | left[i] = detail::RequiresExplicitCast<T1>::cast(right); | |
| | | } | |
| | | | |
| VIGRA_EXEC_LOOP(assign, =) | | VIGRA_EXEC_LOOP(assign, =) | |
| VIGRA_EXEC_LOOP(add, +=) | | VIGRA_EXEC_LOOP(add, +=) | |
| VIGRA_EXEC_LOOP(sub, -=) | | VIGRA_EXEC_LOOP(sub, -=) | |
| VIGRA_EXEC_LOOP(mul, *=) | | VIGRA_EXEC_LOOP(mul, *=) | |
|
| | | VIGRA_EXEC_LOOP(div, /=) | |
| VIGRA_EXEC_LOOP(neg, = -) | | VIGRA_EXEC_LOOP(neg, = -) | |
| VIGRA_EXEC_LOOP(abs, = vigra::abs) | | VIGRA_EXEC_LOOP(abs, = vigra::abs) | |
| VIGRA_EXEC_LOOP(floor, = vigra::floor) | | VIGRA_EXEC_LOOP(floor, = vigra::floor) | |
| VIGRA_EXEC_LOOP(ceil, = vigra::ceil) | | VIGRA_EXEC_LOOP(ceil, = vigra::ceil) | |
| VIGRA_EXEC_LOOP(fromPromote, = NumericTraits<T1>::fromPromote) | | VIGRA_EXEC_LOOP(fromPromote, = NumericTraits<T1>::fromPromote) | |
| VIGRA_EXEC_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote) | | VIGRA_EXEC_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote) | |
|
| VIGRA_EXEC_LOOP_SCALAR(assignScalar, =) | | VIGRA_EXEC_LOOP_SCALAR(mulScalar, *) | |
| VIGRA_EXEC_LOOP_SCALAR(mulScalar, *=) | | VIGRA_EXEC_LOOP_SCALAR(divScalar, /) | |
| VIGRA_EXEC_LOOP_SCALAR(divScalar, /=) | | | |
| | | | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static bool notEqual(T1 const * left, T2 const * right) | | static bool notEqual(T1 const * left, T2 const * right) | |
| { | | { | |
| for(int i=0; i<LEVEL; ++i) | | for(int i=0; i<LEVEL; ++i) | |
| if(left[i] != right[i]) | | if(left[i] != right[i]) | |
| return true; | | return true; | |
| return false; | | return false; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 218 | | skipping to change at line 241 | |
| static void NAME(T1 * left, T2 const * right) \ | | static void NAME(T1 * left, T2 const * right) \ | |
| { \ | | { \ | |
| (*left) OPER (*right); \ | | (*left) OPER (*right); \ | |
| UnrollLoop<LEVEL-1>::NAME(left+1, right+1); \ | | UnrollLoop<LEVEL-1>::NAME(left+1, right+1); \ | |
| } | | } | |
| | | | |
| #define VIGRA_UNROLL_LOOP_SCALAR(NAME, OPER) \ | | #define VIGRA_UNROLL_LOOP_SCALAR(NAME, OPER) \ | |
| template <class T1, class T2> \ | | template <class T1, class T2> \ | |
| static void NAME(T1 * left, T2 right) \ | | static void NAME(T1 * left, T2 right) \ | |
| { \ | | { \ | |
|
| (*left) OPER (right); \ | | (*left) = detail::RequiresExplicitCast<T1>::cast((*left) OPER (righ
t)); \ | |
| UnrollLoop<LEVEL-1>::NAME(left+1, right); \ | | UnrollLoop<LEVEL-1>::NAME(left+1, right); \ | |
| } | | } | |
| | | | |
| template <int LEVEL> | | template <int LEVEL> | |
| struct UnrollLoop | | struct UnrollLoop | |
| { | | { | |
| template <class T1, class T2> | | template <class T1, class T2> | |
|
| | | static void reverseAssign(T1 * left, T2 const * right) | |
| | | { | |
| | | *left = *right; | |
| | | UnrollLoop<LEVEL-1>::reverseAssign(left+1, right-1); | |
| | | } | |
| | | | |
| | | template <class T1, class T2> | |
| static void assignCast(T1 * left, T2 const * right) | | static void assignCast(T1 * left, T2 const * right) | |
| { | | { | |
| *left = detail::RequiresExplicitCast<T1>::cast(*right); | | *left = detail::RequiresExplicitCast<T1>::cast(*right); | |
| UnrollLoop<LEVEL-1>::assignCast(left+1, right+1); | | UnrollLoop<LEVEL-1>::assignCast(left+1, right+1); | |
| } | | } | |
| | | | |
|
| | | template <class T1, class T2> | |
| | | static void assignScalar(T1 * left, T2 right) | |
| | | { | |
| | | *left = detail::RequiresExplicitCast<T1>::cast(right); | |
| | | UnrollLoop<LEVEL-1>::assignScalar(left+1, right); | |
| | | } | |
| | | | |
| VIGRA_UNROLL_LOOP(assign, =) | | VIGRA_UNROLL_LOOP(assign, =) | |
| VIGRA_UNROLL_LOOP(add, +=) | | VIGRA_UNROLL_LOOP(add, +=) | |
| VIGRA_UNROLL_LOOP(sub, -=) | | VIGRA_UNROLL_LOOP(sub, -=) | |
| VIGRA_UNROLL_LOOP(mul, *=) | | VIGRA_UNROLL_LOOP(mul, *=) | |
|
| | | VIGRA_UNROLL_LOOP(div, /=) | |
| VIGRA_UNROLL_LOOP(neg, = -) | | VIGRA_UNROLL_LOOP(neg, = -) | |
| VIGRA_UNROLL_LOOP(abs, = vigra::abs) | | VIGRA_UNROLL_LOOP(abs, = vigra::abs) | |
| VIGRA_UNROLL_LOOP(floor, = vigra::floor) | | VIGRA_UNROLL_LOOP(floor, = vigra::floor) | |
| VIGRA_UNROLL_LOOP(ceil, = vigra::ceil) | | VIGRA_UNROLL_LOOP(ceil, = vigra::ceil) | |
| VIGRA_UNROLL_LOOP(fromPromote, = NumericTraits<T1>::fromPromote) | | VIGRA_UNROLL_LOOP(fromPromote, = NumericTraits<T1>::fromPromote) | |
| VIGRA_UNROLL_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote
) | | VIGRA_UNROLL_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote
) | |
|
| VIGRA_UNROLL_LOOP_SCALAR(assignScalar, =) | | VIGRA_UNROLL_LOOP_SCALAR(mulScalar, *) | |
| VIGRA_UNROLL_LOOP_SCALAR(mulScalar, *=) | | VIGRA_UNROLL_LOOP_SCALAR(divScalar, /) | |
| VIGRA_UNROLL_LOOP_SCALAR(divScalar, /=) | | | |
| | | | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static bool notEqual(T1 const * left, T2 const * right) | | static bool notEqual(T1 const * left, T2 const * right) | |
| { | | { | |
| return (*left != *right) || UnrollLoop<LEVEL - 1>::notEqual(left+1,
right+1); | | return (*left != *right) || UnrollLoop<LEVEL - 1>::notEqual(left+1,
right+1); | |
| } | | } | |
| | | | |
| template <class T> | | template <class T> | |
| static typename NumericTraits<T>::Promote | | static typename NumericTraits<T>::Promote | |
| dot(T const * d) | | dot(T const * d) | |
| | | | |
| skipping to change at line 281 | | skipping to change at line 318 | |
| } | | } | |
| }; | | }; | |
| | | | |
| #undef VIGRA_UNROLL_LOOP | | #undef VIGRA_UNROLL_LOOP | |
| #undef VIGRA_UNROLL_LOOP_SCALAR | | #undef VIGRA_UNROLL_LOOP_SCALAR | |
| | | | |
| template <> | | template <> | |
| struct UnrollLoop<0> | | struct UnrollLoop<0> | |
| { | | { | |
| template <class T1, class T2> | | template <class T1, class T2> | |
|
| | | static void reverseAssign(T1, T2) {} | |
| | | template <class T1, class T2> | |
| static void assignCast(T1, T2) {} | | static void assignCast(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void assign(T1, T2) {} | | static void assign(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void assignScalar(T1, T2) {} | | static void assignScalar(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void add(T1, T2) {} | | static void add(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void sub(T1, T2) {} | | static void sub(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| | | | |
| skipping to change at line 314 | | skipping to change at line 353 | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void abs(T1, T2) {} | | static void abs(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void floor(T1, T2) {} | | static void floor(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static void ceil(T1, T2) {} | | static void ceil(T1, T2) {} | |
| template <class T1, class T2> | | template <class T1, class T2> | |
| static bool notEqual(T1, T2) { return false; } | | static bool notEqual(T1, T2) { return false; } | |
| }; | | }; | |
| | | | |
|
| template <bool PREDICATE> | | | |
| struct TinyVectorIf | | | |
| { | | | |
| template <class T, class F> | | | |
| struct res | | | |
| { | | | |
| typedef T type; | | | |
| }; | | | |
| }; | | | |
| | | | |
| template <> | | | |
| struct TinyVectorIf<false> | | | |
| { | | | |
| template <class T, class F> | | | |
| struct res | | | |
| { | | | |
| typedef F type; | | | |
| }; | | | |
| }; | | | |
| | | | |
| template <int SIZE> | | template <int SIZE> | |
| struct LoopType | | struct LoopType | |
| { | | { | |
|
| typedef typename TinyVectorIf<SIZE < 5>:: | | typedef typename IfBool<(SIZE < 5), UnrollLoop<SIZE>, ExecLoop<SIZE> >: | |
| template res<UnrollLoop<SIZE>, ExecLoop<SIZE> >::type type; | | :type type; | |
| | | | |
| }; | | }; | |
| | | | |
| struct DontInit {}; | | struct DontInit {}; | |
| | | | |
| inline DontInit dontInit() {return DontInit(); } | | inline DontInit dontInit() {return DontInit(); } | |
| | | | |
| } // namespace detail | | } // namespace detail | |
| | | | |
| template <class T, int SIZE> | | template <class T, int SIZE> | |
| class TinyVector; | | class TinyVector; | |
| | | | |
| skipping to change at line 445 | | skipping to change at line 464 | |
| /** Initialize from another sequence (must have length SIZE!) | | /** Initialize from another sequence (must have length SIZE!) | |
| */ | | */ | |
| template <class Iterator> | | template <class Iterator> | |
| void init(Iterator i, Iterator end) | | void init(Iterator i, Iterator end) | |
| { | | { | |
| vigra_precondition(end-i == SIZE, | | vigra_precondition(end-i == SIZE, | |
| "TinyVector::init(): Sequence has wrong size."); | | "TinyVector::init(): Sequence has wrong size."); | |
| Loop::assignCast(data_, i); | | Loop::assignCast(data_, i); | |
| } | | } | |
| | | | |
|
| | | /** Initialize with constant value | |
| | | */ | |
| | | void init(value_type initial) | |
| | | { | |
| | | Loop::assignScalar(data_, initial); | |
| | | } | |
| | | | |
| /** Component-wise add-assignment | | /** Component-wise add-assignment | |
| */ | | */ | |
| template <class T1, class D1, class D2> | | template <class T1, class D1, class D2> | |
| DERIVED & operator+=(TinyVectorBase<T1, SIZE, D1, D2> const & r) | | DERIVED & operator+=(TinyVectorBase<T1, SIZE, D1, D2> const & r) | |
| { | | { | |
| Loop::add(data_, r.begin()); | | Loop::add(data_, r.begin()); | |
| return static_cast<DERIVED &>(*this); | | return static_cast<DERIVED &>(*this); | |
| } | | } | |
| | | | |
| /** Component-wise subtract-assignment | | /** Component-wise subtract-assignment | |
| | | | |
| skipping to change at line 472 | | skipping to change at line 498 | |
| | | | |
| /** Component-wise multiply-assignment | | /** Component-wise multiply-assignment | |
| */ | | */ | |
| template <class T1, class D1, class D2> | | template <class T1, class D1, class D2> | |
| DERIVED & operator*=(TinyVectorBase<T1, SIZE, D1, D2> const & r) | | DERIVED & operator*=(TinyVectorBase<T1, SIZE, D1, D2> const & r) | |
| { | | { | |
| Loop::mul(data_, r.begin()); | | Loop::mul(data_, r.begin()); | |
| return static_cast<DERIVED &>(*this); | | return static_cast<DERIVED &>(*this); | |
| } | | } | |
| | | | |
|
| | | /** Component-wise divide-assignment | |
| | | */ | |
| | | template <class T1, class D1, class D2> | |
| | | DERIVED & operator/=(TinyVectorBase<T1, SIZE, D1, D2> const & r) | |
| | | { | |
| | | Loop::div(data_, r.begin()); | |
| | | return static_cast<DERIVED &>(*this); | |
| | | } | |
| | | | |
| /** Component-wise scalar multiply-assignment | | /** Component-wise scalar multiply-assignment | |
| */ | | */ | |
| DERIVED & operator*=(double r) | | DERIVED & operator*=(double r) | |
| { | | { | |
| Loop::mulScalar(data_, r); | | Loop::mulScalar(data_, r); | |
| return static_cast<DERIVED &>(*this); | | return static_cast<DERIVED &>(*this); | |
| } | | } | |
| | | | |
| /** Component-wise scalar divide-assignment | | /** Component-wise scalar divide-assignment | |
| */ | | */ | |
| | | | |
| skipping to change at line 505 | | skipping to change at line 540 | |
| | | | |
| /** Calculate squared magnitude. | | /** Calculate squared magnitude. | |
| */ | | */ | |
| SquaredNormType squaredMagnitude() const | | SquaredNormType squaredMagnitude() const | |
| { | | { | |
| return Loop::squaredNorm(data_); | | return Loop::squaredNorm(data_); | |
| } | | } | |
| | | | |
| /** Access component by index. | | /** Access component by index. | |
| */ | | */ | |
|
| reference operator[](difference_type i) { return data_[i]; } | | reference operator[](difference_type i) | |
| | | { | |
| | | VIGRA_ASSERT_INSIDE(i); | |
| | | return data_[i]; | |
| | | } | |
| | | | |
| /** Get component by index. | | /** Get component by index. | |
| */ | | */ | |
|
| const_reference operator[](difference_type i) const { return data_[i]; | | const_reference operator[](difference_type i) const | |
| } | | { | |
| | | VIGRA_ASSERT_INSIDE(i); | |
| | | return data_[i]; | |
| | | } | |
| | | | |
| /** Get random access iterator to begin of vector. | | /** Get random access iterator to begin of vector. | |
| */ | | */ | |
| iterator begin() { return data_; } | | iterator begin() { return data_; } | |
| /** Get random access iterator past-the-end of vector. | | /** Get random access iterator past-the-end of vector. | |
| */ | | */ | |
| iterator end() { return data_ + SIZE; } | | iterator end() { return data_ + SIZE; } | |
| | | | |
| /** Get const random access iterator to begin of vector. | | /** Get const random access iterator to begin of vector. | |
| */ | | */ | |
| | | | |
| skipping to change at line 587 | | skipping to change at line 631 | |
| typedef typename BaseType::pointer pointer; | | typedef typename BaseType::pointer pointer; | |
| typedef typename BaseType::const_pointer const_pointer; | | typedef typename BaseType::const_pointer const_pointer; | |
| typedef typename BaseType::iterator iterator; | | typedef typename BaseType::iterator iterator; | |
| typedef typename BaseType::const_iterator const_iterator; | | typedef typename BaseType::const_iterator const_iterator; | |
| typedef typename BaseType::size_type size_type; | | typedef typename BaseType::size_type size_type; | |
| typedef typename BaseType::difference_type difference_type; | | typedef typename BaseType::difference_type difference_type; | |
| typedef typename BaseType::scalar_multiplier scalar_multiplier; | | typedef typename BaseType::scalar_multiplier scalar_multiplier; | |
| typedef typename BaseType::SquaredNormType SquaredNormType; | | typedef typename BaseType::SquaredNormType SquaredNormType; | |
| typedef typename BaseType::NormType NormType; | | typedef typename BaseType::NormType NormType; | |
| | | | |
|
| | | enum ReverseCopyTag { ReverseCopy }; | |
| | | | |
| /** Construction with constant value | | /** Construction with constant value | |
| */ | | */ | |
| explicit TinyVector(value_type const & initial) | | explicit TinyVector(value_type const & initial) | |
| : BaseType() | | : BaseType() | |
| { | | { | |
| Loop::assignScalar(BaseType::begin(), initial); | | Loop::assignScalar(BaseType::begin(), initial); | |
| } | | } | |
| | | | |
|
| | | /** Construction with Diff2D (only implemented for 2D TinyVector) | |
| | | */ | |
| | | explicit TinyVector(Diff2D const & initial) | |
| | | : BaseType() | |
| | | { | |
| | | BaseType::data_[0] = detail::RequiresExplicitCast<T>::cast(initial. | |
| | | x); | |
| | | BaseType::data_[1] = detail::RequiresExplicitCast<T>::cast(initial. | |
| | | y); | |
| | | } | |
| | | | |
| /** Construction with explicit values. | | /** Construction with explicit values. | |
| Call only if SIZE == 2 | | Call only if SIZE == 2 | |
| */ | | */ | |
| TinyVector(value_type const & i1, value_type const & i2) | | TinyVector(value_type const & i1, value_type const & i2) | |
| : BaseType() | | : BaseType() | |
| { | | { | |
| BaseType::data_[0] = i1; | | BaseType::data_[0] = i1; | |
| BaseType::data_[1] = i2; | | BaseType::data_[1] = i2; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 629 | | skipping to change at line 684 | |
| TinyVector(value_type const & i1, value_type const & i2, | | TinyVector(value_type const & i1, value_type const & i2, | |
| value_type const & i3, value_type const & i4) | | value_type const & i3, value_type const & i4) | |
| : BaseType() | | : BaseType() | |
| { | | { | |
| BaseType::data_[0] = i1; | | BaseType::data_[0] = i1; | |
| BaseType::data_[1] = i2; | | BaseType::data_[1] = i2; | |
| BaseType::data_[2] = i3; | | BaseType::data_[2] = i3; | |
| BaseType::data_[3] = i4; | | BaseType::data_[3] = i4; | |
| } | | } | |
| | | | |
|
| | | /** Construction with explicit values. | |
| | | Call only if SIZE == 5 | |
| | | */ | |
| | | TinyVector(value_type const & i1, value_type const & i2, | |
| | | value_type const & i3, value_type const & i4, | |
| | | value_type const & i5) | |
| | | : BaseType() | |
| | | { | |
| | | BaseType::data_[0] = i1; | |
| | | BaseType::data_[1] = i2; | |
| | | BaseType::data_[2] = i3; | |
| | | BaseType::data_[3] = i4; | |
| | | BaseType::data_[4] = i5; | |
| | | } | |
| /** Default constructor (initializes all components with zero) | | /** Default constructor (initializes all components with zero) | |
| */ | | */ | |
| TinyVector() | | TinyVector() | |
| : BaseType() | | : BaseType() | |
| { | | { | |
| Loop::assignScalar(BaseType::data_, NumericTraits<value_type>::zero
()); | | Loop::assignScalar(BaseType::data_, NumericTraits<value_type>::zero
()); | |
| } | | } | |
| | | | |
| /** Copy constructor. | | /** Copy constructor. | |
| */ | | */ | |
| | | | |
| skipping to change at line 653 | | skipping to change at line 722 | |
| } | | } | |
| | | | |
| /** Constructor from C array. | | /** Constructor from C array. | |
| */ | | */ | |
| explicit TinyVector(const_pointer data) | | explicit TinyVector(const_pointer data) | |
| : BaseType() | | : BaseType() | |
| { | | { | |
| Loop::assign(BaseType::data_, data); | | Loop::assign(BaseType::data_, data); | |
| } | | } | |
| | | | |
|
| | | /** Constructor by reverse copy from C array. | |
| | | | |
| | | Usage: | |
| | | \code | |
| | | TinyVector<int, 3> v(1,2,3); | |
| | | TinyVector<int, 3> reverse(v.begin(), TinyVector<int, 3>::Rever | |
| | | seCopy); | |
| | | \endcode | |
| | | */ | |
| | | explicit TinyVector(const_pointer data, ReverseCopyTag) | |
| | | : BaseType() | |
| | | { | |
| | | Loop::reverseAssign(BaseType::data_, data+SIZE-1); | |
| | | } | |
| | | | |
| /** Copy assignment. | | /** Copy assignment. | |
| */ | | */ | |
| TinyVector & operator=(TinyVector const & r) | | TinyVector & operator=(TinyVector const & r) | |
| { | | { | |
| Loop::assign(BaseType::data_, r.data_); | | Loop::assign(BaseType::data_, r.data_); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | /** Assignment from Diff2D. | |
| | | */ | |
| | | TinyVector & operator=(Diff2D const & r) | |
| | | { | |
| | | BaseType::data_[0] = detail::RequiresExplicitCast<T>::cast(r.x); | |
| | | BaseType::data_[1] = detail::RequiresExplicitCast<T>::cast(r.y); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | /** Copy with type conversion. | |
| | | */ | |
| | | template <class U> | |
| | | TinyVector(TinyVector<U, SIZE> const & r) | |
| | | : BaseType() | |
| | | { | |
| | | Loop::assignCast(BaseType::data_, r.begin()); | |
| | | } | |
| | | | |
| /** Copy with type conversion. | | /** Copy with type conversion. | |
| */ | | */ | |
| template <class U, class DATA, class DERIVED> | | template <class U, class DATA, class DERIVED> | |
| TinyVector(TinyVectorBase<U, SIZE, DATA, DERIVED> const & r) | | TinyVector(TinyVectorBase<U, SIZE, DATA, DERIVED> const & r) | |
| : BaseType() | | : BaseType() | |
| { | | { | |
| Loop::assignCast(BaseType::data_, r.begin()); | | Loop::assignCast(BaseType::data_, r.begin()); | |
| } | | } | |
| | | | |
| /** Copy assignment with type conversion. | | /** Copy assignment with type conversion. | |
| */ | | */ | |
| template <class U, class DATA, class DERIVED> | | template <class U, class DATA, class DERIVED> | |
| TinyVector & operator=(TinyVectorBase<U, SIZE, DATA, DERIVED> const & r
) | | TinyVector & operator=(TinyVectorBase<U, SIZE, DATA, DERIVED> const & r
) | |
| { | | { | |
| Loop::assignCast(BaseType::data_, r.begin()); | | Loop::assignCast(BaseType::data_, r.begin()); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | explicit TinyVector(SkipInitializationTag) | |
| | | : BaseType() | |
| | | {} | |
| | | | |
| explicit TinyVector(detail::DontInit) | | explicit TinyVector(detail::DontInit) | |
| : BaseType() | | : BaseType() | |
| {} | | {} | |
| }; | | }; | |
| | | | |
| /** \brief Wrapper for fixed size vectors. | | /** \brief Wrapper for fixed size vectors. | |
| | | | |
| This class wraps an array of size SIZE of the specified VALUETYPE. | | This class wraps an array of size SIZE of the specified VALUETYPE. | |
| Thus, the array can be accessed with an interface similar to | | Thus, the array can be accessed with an interface similar to | |
| that of std::vector (except that there are no functions | | that of std::vector (except that there are no functions | |
| | | | |
| skipping to change at line 1036 | | skipping to change at line 1141 | |
| { | | { | |
| typedef TinyVector<typename NumericTraits<T>::RealPromote, SIZE> Promot
e; | | typedef TinyVector<typename NumericTraits<T>::RealPromote, SIZE> Promot
e; | |
| }; | | }; | |
| | | | |
| template <class T, int SIZE> | | template <class T, int SIZE> | |
| struct PromoteTraits<double, TinyVectorView<T, SIZE> > | | struct PromoteTraits<double, TinyVectorView<T, SIZE> > | |
| { | | { | |
| typedef TinyVector<typename NumericTraits<T>::RealPromote, SIZE> Promot
e; | | typedef TinyVector<typename NumericTraits<T>::RealPromote, SIZE> Promot
e; | |
| }; | | }; | |
| | | | |
|
| | | template<class T, int SIZE> | |
| | | struct CanSkipInitialization<TinyVectorView<T, SIZE> > | |
| | | { | |
| | | typedef typename CanSkipInitialization<T>::type type; | |
| | | static const bool value = type::asBool; | |
| | | }; | |
| | | | |
| | | template<class T, int SIZE> | |
| | | struct CanSkipInitialization<TinyVector<T, SIZE> > | |
| | | { | |
| | | typedef typename CanSkipInitialization<T>::type type; | |
| | | static const bool value = type::asBool; | |
| | | }; | |
| | | | |
| #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION | | #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION | |
| | | | |
| #define TINYVECTOR_NUMTRAITS(T, SIZE) \ | | #define TINYVECTOR_NUMTRAITS(T, SIZE) \ | |
| template<>\ | | template<>\ | |
| struct NumericTraits<TinyVector<T, SIZE> >\ | | struct NumericTraits<TinyVector<T, SIZE> >\ | |
| {\ | | {\ | |
| typedef TinyVector<T, SIZE> Type;\ | | typedef TinyVector<T, SIZE> Type;\ | |
| typedef TinyVector<NumericTraits<T>::Promote, SIZE> Promote;\ | | typedef TinyVector<NumericTraits<T>::Promote, SIZE> Promote;\ | |
| typedef TinyVector<NumericTraits<T>::RealPromote, SIZE> RealPromote;\ | | typedef TinyVector<NumericTraits<T>::RealPromote, SIZE> RealPromote;\ | |
| typedef TinyVector<NumericTraits<T>::ComplexPromote, SIZE> ComplexPromo
te;\ | | typedef TinyVector<NumericTraits<T>::ComplexPromote, SIZE> ComplexPromo
te;\ | |
| | | | |
| skipping to change at line 1187 | | skipping to change at line 1306 | |
| /// component-wise multiplication | | /// component-wise multiplication | |
| template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4> | | template <class V1, int SIZE, class D1, class D2, class V2, class D3, class
D4> | |
| inline | | inline | |
| typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2, SIZE> >::Promot
e | | typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2, SIZE> >::Promot
e | |
| operator*(TinyVectorBase<V1, SIZE, D1, D2> const & l, | | operator*(TinyVectorBase<V1, SIZE, D1, D2> const & l, | |
| TinyVectorBase<V2, SIZE, D3, D4> const & r) | | TinyVectorBase<V2, SIZE, D3, D4> const & r) | |
| { | | { | |
| return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZ
E> >::Promote(l) *= r; | | return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZ
E> >::Promote(l) *= r; | |
| } | | } | |
| | | | |
|
| | | /// component-wise division | |
| | | template <class V1, int SIZE, class D1, class D2, class V2, class D3, class | |
| | | D4> | |
| | | inline | |
| | | typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2, SIZE> >::Promot | |
| | | e | |
| | | operator/(TinyVectorBase<V1, SIZE, D1, D2> const & l, | |
| | | TinyVectorBase<V2, SIZE, D3, D4> const & r) | |
| | | { | |
| | | return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZ | |
| | | E> >::Promote(l) /= r; | |
| | | } | |
| | | | |
| /// component-wise left scalar multiplication | | /// component-wise left scalar multiplication | |
| template <class V, int SIZE, class D1, class D2> | | template <class V, int SIZE, class D1, class D2> | |
| inline | | inline | |
| typename NumericTraits<TinyVector<V, SIZE> >::RealPromote | | typename NumericTraits<TinyVector<V, SIZE> >::RealPromote | |
| operator*(double v, TinyVectorBase<V, SIZE, D1, D2> const & r) | | operator*(double v, TinyVectorBase<V, SIZE, D1, D2> const & r) | |
| { | | { | |
| return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(r) *=
v; | | return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(r) *=
v; | |
| } | | } | |
| | | | |
| /// component-wise right scalar multiplication | | /// component-wise right scalar multiplication | |
| | | | |
| skipping to change at line 1310 | | skipping to change at line 1439 | |
| template <class V, int SIZE> | | template <class V, int SIZE> | |
| inline | | inline | |
| typename TinyVector<V, SIZE>::SquaredNormType | | typename TinyVector<V, SIZE>::SquaredNormType | |
| squaredNorm(TinyVector<V, SIZE> const & t) | | squaredNorm(TinyVector<V, SIZE> const & t) | |
| { | | { | |
| return t.squaredMagnitude(); | | return t.squaredMagnitude(); | |
| } | | } | |
| //@} | | //@} | |
| | | | |
| } // namespace vigra | | } // namespace vigra | |
|
| | | #undef VIGRA_ASSERT_INSIDE | |
| #endif // VIGRA_TINYVECTOR_HXX | | #endif // VIGRA_TINYVECTOR_HXX | |
| | | | |
End of changes. 31 change blocks. |
| 37 lines changed or deleted | | 171 lines changed or added | |
|
| watersheds3d.hxx | | watersheds3d.hxx | |
| /************************************************************************/ | | /************************************************************************/ | |
| /* */ | | /* */ | |
| /* Copyright 2006-2007 by F. Heinrich, B. Seppke, Ullrich Koethe */ | | /* Copyright 2006-2007 by F. Heinrich, B. Seppke, Ullrich Koethe */ | |
|
| /* Cognitive Systems Group, University of Hamburg, Germany */ | | | |
| /* */ | | /* */ | |
| /* This file is part of the VIGRA computer vision library. */ | | /* This file is part of the VIGRA computer vision library. */ | |
|
| /* ( Version 1.6.0, Aug 13 2008 ) */ | | | |
| /* The VIGRA Website is */ | | /* The VIGRA Website is */ | |
|
| /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ | | /* http://hci.iwr.uni-heidelberg.de/vigra/ */ | |
| /* Please direct questions, bug reports, and contributions to */ | | /* Please direct questions, bug reports, and contributions to */ | |
| /* ullrich.koethe@iwr.uni-heidelberg.de or */ | | /* ullrich.koethe@iwr.uni-heidelberg.de or */ | |
| /* vigra@informatik.uni-hamburg.de */ | | /* vigra@informatik.uni-hamburg.de */ | |
| /* */ | | /* */ | |
| /* Permission is hereby granted, free of charge, to any person */ | | /* Permission is hereby granted, free of charge, to any person */ | |
| /* obtaining a copy of this software and associated documentation */ | | /* obtaining a copy of this software and associated documentation */ | |
| /* files (the "Software"), to deal in the Software without */ | | /* files (the "Software"), to deal in the Software without */ | |
| /* restriction, including without limitation the rights to use, */ | | /* restriction, including without limitation the rights to use, */ | |
| /* copy, modify, merge, publish, distribute, sublicense, and/or */ | | /* copy, modify, merge, publish, distribute, sublicense, and/or */ | |
| /* sell copies of the Software, and to permit persons to whom the */ | | /* sell copies of the Software, and to permit persons to whom the */ | |
| | | | |
| skipping to change at line 43 | | skipping to change at line 41 | |
| /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ | | /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ | |
| /* OTHER DEALINGS IN THE SOFTWARE. */ | | /* OTHER DEALINGS IN THE SOFTWARE. */ | |
| /* */ | | /* */ | |
| /************************************************************************/ | | /************************************************************************/ | |
| | | | |
| #ifndef VIGRA_watersheds3D_HXX | | #ifndef VIGRA_watersheds3D_HXX | |
| #define VIGRA_watersheds3D_HXX | | #define VIGRA_watersheds3D_HXX | |
| | | | |
| #include "voxelneighborhood.hxx" | | #include "voxelneighborhood.hxx" | |
| #include "multi_array.hxx" | | #include "multi_array.hxx" | |
|
| | | #include "union_find.hxx" | |
| | | | |
| namespace vigra | | namespace vigra | |
| { | | { | |
| | | | |
| template <class SrcIterator, class SrcAccessor, class SrcShape, | | template <class SrcIterator, class SrcAccessor, class SrcShape, | |
| class DestIterator, class DestAccessor, class Neighborhood3D> | | class DestIterator, class DestAccessor, class Neighborhood3D> | |
| int preparewatersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccessor
sa, | | int preparewatersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccessor
sa, | |
| DestIterator d_Iter, DestAccessor da, Neighborhood
3D) | | DestIterator d_Iter, DestAccessor da, Neighborhood
3D) | |
| { | | { | |
| //basically needed for iteration and border-checks | | //basically needed for iteration and border-checks | |
| | | | |
| skipping to change at line 85 | | skipping to change at line 84 | |
| { | | { | |
| AtVolumeBorder atBorder = isAtVolumeBorder(x,y,z,w,h,d); | | AtVolumeBorder atBorder = isAtVolumeBorder(x,y,z,w,h,d); | |
| typename SrcAccessor::value_type v = sa(xs); | | typename SrcAccessor::value_type v = sa(xs); | |
| // the following choice causes minima to point | | // the following choice causes minima to point | |
| // to their lowest neighbor -- would this be better??? | | // to their lowest neighbor -- would this be better??? | |
| // typename SrcAccessor::value_type v = NumericTraits<typen
ame SrcAccessor::value_type>::max(); | | // typename SrcAccessor::value_type v = NumericTraits<typen
ame SrcAccessor::value_type>::max(); | |
| int o = 0; // means center is minimum | | int o = 0; // means center is minimum | |
| typename SrcAccessor::value_type my_v = v; | | typename SrcAccessor::value_type my_v = v; | |
| if(atBorder == NotAtBorder) | | if(atBorder == NotAtBorder) | |
| { | | { | |
|
| #if 0 | | | |
| NeighborhoodTraverser<SrcIterator, Neighborhood3D> c(x | | | |
| s), cend(c); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| NeighborhoodCirculator<SrcIterator, Neighborhood3D> c(
xs), cend(c); | | NeighborhoodCirculator<SrcIterator, Neighborhood3D> c(
xs), cend(c); | |
| | | | |
| do { | | do { | |
| if(sa(c) < v) | | if(sa(c) < v) | |
| { | | { | |
| v = sa(c); | | v = sa(c); | |
| o = c.directionBit(); | | o = c.directionBit(); | |
| } | | } | |
| else if(sa(c) == my_v && my_v == v) | | else if(sa(c) == my_v && my_v == v) | |
| { | | { | |
| o = o | c.directionBit(); | | o = o | c.directionBit(); | |
| } | | } | |
| } | | } | |
| while(++c != cend); | | while(++c != cend); | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| #if 0 | | | |
| RestrictedNeighborhoodTraverser<SrcIterator, Neighborho | | | |
| od3D> c(xs, atBorder), cend(c); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| RestrictedNeighborhoodCirculator<SrcIterator, Neighborh
ood3D> c(xs, atBorder), cend(c); | | RestrictedNeighborhoodCirculator<SrcIterator, Neighborh
ood3D> c(xs, atBorder), cend(c); | |
| do { | | do { | |
| if(sa(c) < v) | | if(sa(c) < v) | |
| { | | { | |
| v = sa(c); | | v = sa(c); | |
| o = c.directionBit(); | | o = c.directionBit(); | |
| } | | } | |
| else if(sa(c) == my_v && my_v == v) | | else if(sa(c) == my_v && my_v == v) | |
| { | | { | |
| o = o | c.directionBit(); | | o = o | c.directionBit(); | |
| | | | |
| skipping to change at line 139 | | skipping to change at line 130 | |
| return local_min_count; | | return local_min_count; | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcAccessor,class SrcShape, | | template <class SrcIterator, class SrcAccessor,class SrcShape, | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class Neighborhood3D> | | class Neighborhood3D> | |
| unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, Sr
cAccessor sa, | | unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, Sr
cAccessor sa, | |
| DestIterator d_Iter, DestAccessor da, | | DestIterator d_Iter, DestAccessor da, | |
| Neighborhood3D) | | Neighborhood3D) | |
| { | | { | |
|
| | | typedef typename DestAccessor::value_type LabelType; | |
| | | | |
| //basically needed for iteration and border-checks | | //basically needed for iteration and border-checks | |
| int w = srcShape[0], h = srcShape[1], d = srcShape[2]; | | int w = srcShape[0], h = srcShape[1], d = srcShape[2]; | |
|
| int x,y,z, i; | | int x,y,z; | |
| | | | |
| //declare and define Iterators for all three dims at src | | //declare and define Iterators for all three dims at src | |
| SrcIterator zs = s_Iter; | | SrcIterator zs = s_Iter; | |
|
| SrcIterator ys(zs); | | DestIterator zd = d_Iter; | |
| SrcIterator xs(ys); | | | |
| | | | |
| // temporary image to store region labels | | // temporary image to store region labels | |
|
| typedef vigra::MultiArray<3,int> LabelVolume; | | detail::UnionFindArray<LabelType> labels; | |
| typedef LabelVolume::traverser LabelTraverser; | | | |
| | | | |
| LabelVolume labelvolume(srcShape); | | | |
| | | | |
| //Declare traversers for all three dims at target | | | |
| LabelTraverser zt = labelvolume.traverser_begin(); | | | |
| LabelTraverser yt(zt); | | | |
| LabelTraverser xt(yt); | | | |
| | | | |
| // Kovalevsky's clever idea to use | | | |
| // image iterator and scan order iterator simultaneously | | | |
| // memory order indicates label | | | |
| LabelVolume::iterator label = labelvolume.begin(); | | | |
| | | | |
| // initialize the neighborhood traversers | | // initialize the neighborhood traversers | |
|
| | | | |
| #if 0 | | | |
| NeighborOffsetTraverser<Neighborhood3D> nc(Neighborhood3D::CausalFirst) | | | |
| ; | | | |
| NeighborOffsetTraverser<Neighborhood3D> nce(Neighborhood3D::CausalLast) | | | |
| ; | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst
); | | NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst
); | |
| NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast
); | | NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast
); | |
| ++nce; | | ++nce; | |
| // pass 1: scan image from upper left front to lower right back | | // pass 1: scan image from upper left front to lower right back | |
| // to find connected components | | // to find connected components | |
| | | | |
| // Each component will be represented by a tree of pixels. Each | | // Each component will be represented by a tree of pixels. Each | |
| // pixel contains the scan order address of its parent in the | | // pixel contains the scan order address of its parent in the | |
| // tree. In order for pass 2 to work correctly, the parent must | | // tree. In order for pass 2 to work correctly, the parent must | |
| // always have a smaller scan order address than the child. | | // always have a smaller scan order address than the child. | |
| // Therefore, we can merge trees only at their roots, because the | | // Therefore, we can merge trees only at their roots, because the | |
| // root of the combined tree must have the smallest scan order | | // root of the combined tree must have the smallest scan order | |
| // address among all the tree's pixels/ nodes. The root of each | | // address among all the tree's pixels/ nodes. The root of each | |
| // tree is distinguished by pointing to itself (it contains its | | // tree is distinguished by pointing to itself (it contains its | |
| // own scan order address). This condition is enforced whenever a | | // own scan order address). This condition is enforced whenever a | |
| // new region is found or two regions are merged | | // new region is found or two regions are merged | |
|
| i=0; | | for(z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2()) | |
| for(z = 0; z != d; ++z, ++zs.dim2(), ++zt.dim2()) | | | |
| { | | { | |
|
| ys = zs; | | SrcIterator ys = zs; | |
| yt = zt; | | DestIterator yd = zd; | |
| | | | |
|
| for(y = 0; y != h; ++y, ++ys.dim1(), ++yt.dim1()) | | for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1()) | |
| { | | { | |
|
| xs = ys; | | SrcIterator xs = ys; | |
| xt = yt; | | DestIterator xd = yd; | |
| | | | |
|
| for(x = 0; x != w; ++x, ++xs.dim0(), ++xt.dim0(), ++i) | | for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0()) | |
| { | | { | |
|
| *xt = i; // default: new region | | LabelType currentLabel = labels.nextFreeLabel(); // default
: new region | |
| | | | |
| //queck whether there is a special borde threatment to be u
sed or not | | //queck whether there is a special borde threatment to be u
sed or not | |
| AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); | | AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,
z); | |
| | | | |
| //We are not at the border! | | //We are not at the border! | |
| if(atBorder == NotAtBorder) | | if(atBorder == NotAtBorder) | |
| { | | { | |
| | | | |
|
| #if 0 | | | |
| nc = NeighborOffsetTraverser<Neighborhood3D>(Neighborho | | | |
| od3D::CausalFirst); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh
ood3D::CausalFirst); | | nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh
ood3D::CausalFirst); | |
| | | | |
| do | | do | |
| { | | { | |
| // Direction of NTraversr Neighbor's direct
ion bit is pointing | | // Direction of NTraversr Neighbor's direct
ion bit is pointing | |
| // = Direction of voxel towards us? | | // = Direction of voxel towards us? | |
|
| if((*xs & nc.directionBit()) || (xs[*nc] & nc.oppos
iteDirectionBit())) | | if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc
.oppositeDirectionBit())) | |
| { | | { | |
|
| int neighborLabel = xt[*nc]; | | currentLabel = labels.makeUnion(da(xd,*nc), cur | |
| | | rentLabel); | |
| // find the root label of a label tree | | | |
| while(neighborLabel != label[neighborLabel]) | | | |
| { | | | |
| neighborLabel = label[neighborLabel]; | | | |
| } | | | |
| | | | |
| if(neighborLabel < *xt) // always keep the smal | | | |
| lest among the possible neighbor labels | | | |
| { | | | |
| label[*xt] = neighborLabel; | | | |
| *xt = neighborLabel; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[neighborLabel] = *xt; | | | |
| } | | | |
| } | | } | |
| ++nc; | | ++nc; | |
| }while(nc!=nce); | | }while(nc!=nce); | |
| } | | } | |
| //we are at a border - handle this!! | | //we are at a border - handle this!! | |
| else | | else | |
| { | | { | |
|
| | | | |
| #if 0 | | | |
| nc = NeighborOffsetTraverser<Neighborhood3D>(Neighborho | | | |
| od3D::nearBorderDirectionsCausal(atBorder,0)); | | | |
| #endif /* #if 0 */ | | | |
| | | | |
| nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh
ood3D::nearBorderDirectionsCausal(atBorder,0)); | | nc = NeighborOffsetCirculator<Neighborhood3D>(Neighborh
ood3D::nearBorderDirectionsCausal(atBorder,0)); | |
| int j=0; | | int j=0; | |
| while(nc.direction() != Neighborhood3D::Error) | | while(nc.direction() != Neighborhood3D::Error) | |
| { | | { | |
| // Direction of NTraversr Neighbor's direct
ion bit is pointing | | // Direction of NTraversr Neighbor's direct
ion bit is pointing | |
| // = Direction of voxel towards us? | | // = Direction of voxel towards us? | |
|
| if((*xs & nc.directionBit()) || (xs[*nc] & nc.oppos
iteDirectionBit())) | | if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc
.oppositeDirectionBit())) | |
| { | | { | |
|
| int neighborLabel = xt[*nc]; | | currentLabel = labels.makeUnion(da(xd,*nc), cur | |
| | | rentLabel); | |
| // find the root label of a label tree | | | |
| while(neighborLabel != label[neighborLabel]) | | | |
| { | | | |
| neighborLabel = label[neighborLabel]; | | | |
| } | | | |
| | | | |
| if(neighborLabel < *xt) // always keep the smal | | | |
| lest among the possible neighbor labels | | | |
| { | | | |
| label[*xt] = neighborLabel; | | | |
| *xt = neighborLabel; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[neighborLabel] = *xt; | | | |
| } | | | |
| } | | } | |
| nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa
l(atBorder,++j)); | | nc.turnTo(Neighborhood3D::nearBorderDirectionsCausa
l(atBorder,++j)); | |
| } | | } | |
| } | | } | |
|
| | | da.set(labels.finalizeLabel(currentLabel), xd); | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | unsigned int count = labels.makeContiguous(); | |
| | | | |
| // pass 2: assign one label to each region (tree) | | // pass 2: assign one label to each region (tree) | |
| // so that labels form a consecutive sequence 1, 2, ... | | // so that labels form a consecutive sequence 1, 2, ... | |
|
| DestIterator zd = d_Iter; | | zd = d_Iter; | |
| | | | |
| unsigned int count = 0; | | | |
| | | | |
| i= 0; | | | |
| | | | |
| for(z=0; z != d; ++z, ++zd.dim2()) | | for(z=0; z != d; ++z, ++zd.dim2()) | |
| { | | { | |
| DestIterator yd(zd); | | DestIterator yd(zd); | |
| | | | |
| for(y=0; y != h; ++y, ++yd.dim1()) | | for(y=0; y != h; ++y, ++yd.dim1()) | |
| { | | { | |
| DestIterator xd(yd); | | DestIterator xd(yd); | |
| | | | |
|
| for(x = 0; x != w; ++x, ++xd.dim0(), ++i) | | for(x = 0; x != w; ++x, ++xd.dim0()) | |
| { | | { | |
|
| if(label[i] == i) | | da.set(labels[da(xd)], xd); | |
| { | | | |
| label[i] = count++; | | | |
| } | | | |
| else | | | |
| { | | | |
| label[i] = label[label[i]]; // compress trees | | | |
| } | | | |
| da.set(label[i]+1, xd); | | | |
| } | | } | |
| } | | } | |
| } | | } | |
| return count; | | return count; | |
| } | | } | |
| | | | |
| /** \addtogroup SeededRegionGrowing Region Segmentation Algorithms | | /** \addtogroup SeededRegionGrowing Region Segmentation Algorithms | |
| Region growing, watersheds, and voronoi tesselation | | Region growing, watersheds, and voronoi tesselation | |
| */ | | */ | |
| //@{ | | //@{ | |
| | | | |
| skipping to change at line 459 | | skipping to change at line 380 | |
| class DestIterator, class DestAccessor, | | class DestIterator, class DestAccessor, | |
| class Neighborhood3D> | | class Neighborhood3D> | |
| unsigned int watersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccess
or sa, | | unsigned int watersheds3D( SrcIterator s_Iter, SrcShape srcShape, SrcAccess
or sa, | |
| DestIterator d_Iter, DestAccessor da, Neighborho
od3D neighborhood3D) | | DestIterator d_Iter, DestAccessor da, Neighborho
od3D neighborhood3D) | |
| { | | { | |
| //create temporary volume to store the DAG of directions to minima | | //create temporary volume to store the DAG of directions to minima | |
| if ((int)Neighborhood3D::DirectionCount>7){ //If we have 3D-TwentySix
Neighborhood | | if ((int)Neighborhood3D::DirectionCount>7){ //If we have 3D-TwentySix
Neighborhood | |
| | | | |
| vigra::MultiArray<3,int> orientationVolume(srcShape); | | vigra::MultiArray<3,int> orientationVolume(srcShape); | |
| | | | |
|
| int local_min_count= preparewatersheds3D( s_Iter, srcShape, sa, | | preparewatersheds3D( s_Iter, srcShape, sa, | |
| destMultiArray(orientatio | | destMultiArray(orientationVolume).first, destM | |
| nVolume).first, destMultiArray(orientationVolume).second, | | ultiArray(orientationVolume).second, | |
| neighborhood3D); | | neighborhood3D); | |
| | | | |
| return watershedLabeling3D( srcMultiArray(orientationVolume).first,
srcShape, srcMultiArray(orientationVolume).second, | | return watershedLabeling3D( srcMultiArray(orientationVolume).first,
srcShape, srcMultiArray(orientationVolume).second, | |
| d_Iter, da, | | d_Iter, da, | |
| neighborhood3D); | | neighborhood3D); | |
| } | | } | |
| else{ | | else{ | |
| | | | |
| vigra::MultiArray<3,unsigned char> orientationVolume(srcShape); | | vigra::MultiArray<3,unsigned char> orientationVolume(srcShape); | |
| | | | |
|
| int local_min_count= preparewatersheds3D( s_Iter, srcShape, sa, | | preparewatersheds3D( s_Iter, srcShape, sa, | |
| destMultiArray(orientatio | | destMultiArray(orientationVolume).first, dest | |
| nVolume).first, destMultiArray(orientationVolume).second, | | MultiArray(orientationVolume).second, | |
| neighborhood3D); | | neighborhood3D); | |
| | | | |
| return watershedLabeling3D( srcMultiArray(orientationVolume).first,
srcShape, srcMultiArray(orientationVolume).second, | | return watershedLabeling3D( srcMultiArray(orientationVolume).first,
srcShape, srcMultiArray(orientationVolume).second, | |
| d_Iter, da, | | d_Iter, da, | |
| neighborhood3D); | | neighborhood3D); | |
| } | | } | |
| } | | } | |
| | | | |
| template <class SrcIterator, class SrcShape, class SrcAccessor, | | template <class SrcIterator, class SrcShape, class SrcAccessor, | |
| class DestIterator, class DestAccessor> | | class DestIterator, class DestAccessor> | |
| inline unsigned int watersheds3DSix( vigra::triple<SrcIterator, SrcShape, S
rcAccessor> src, | | inline unsigned int watersheds3DSix( vigra::triple<SrcIterator, SrcShape, S
rcAccessor> src, | |
| | | | |
End of changes. 30 change blocks. |
| 120 lines changed or deleted | | 35 lines changed or added | |
|