1004: Add border to milena 2D image.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Add border to milena 2D image. * tests/main.cc: Update. * tests/image2d_b.cc: New. * mln/core/concept/image.hh (npoints): New. * mln/core/concept/doc/image.hh: Update. * mln/core/internal/image_base.hh: Update. * mln/core/concept/genpoint.hh (operator-): New. * mln/core/image2d.hh: Rename as... * mln/core/image2d_b.hh: ...this. (vb_, bdr_): New. (image2d_b): Update. * mln/border/thickness.hh: New. mln/border/thickness.hh | 50 ++++++++++ mln/core/concept/doc/image.hh | 4 mln/core/concept/genpoint.hh | 32 +++++++ mln/core/concept/image.hh | 1 mln/core/image2d_b.hh | 182 +++++++++++++++++++++++++++++----------- mln/core/internal/image_base.hh | 18 +-- tests/image2d_b.cc | 48 ++++++++++ tests/main.cc | 10 +- 8 files changed, 283 insertions(+), 62 deletions(-) Index: tests/main.cc --- tests/main.cc (revision 1003) +++ tests/main.cc (working copy) @@ -27,7 +27,7 @@ #include <cmath> -#include <mln/core/image2d.hh> +#include <mln/core/image2d_b.hh> #include <mln/level/fill.hh> #include <mln/debug/println.hh> @@ -54,7 +54,7 @@ using namespace mln; const unsigned size = 1000; - image2d<int_u8> f(size, size); + image2d_b<int_u8> f(size, size); morpho::Rd(f, f, c8()); } @@ -73,7 +73,7 @@ // std::cout << c8() << std::endl; // { -// image2d<int> ima(b); +// image2d_b<int> ima(b); // level::fill(ima, 51); // debug::println(ima); @@ -87,12 +87,12 @@ // { -// image2d<int> ima(b); +// image2d_b<int> ima(b); // level::fill(ima, cos_sin); // debug::println(ima); // std::cout << std::endl; -// image2d<int> ima2 = morpho::erosion(ima, win); +// image2d_b<int> ima2 = morpho::erosion(ima, win); // debug::println(ima2); // } Index: tests/image2d_b.cc --- tests/image2d_b.cc (revision 0) +++ tests/image2d_b.cc (revision 0) @@ -0,0 +1,48 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +/*! \file tests/image2d_b.cc + * + * \brief Tests on mln::image2d_b. + */ + +#include <mln/core/image2d_b.hh> + + +int main() +{ + using namespace mln; + + const unsigned nrows = 1; + const unsigned ncols = 66; + const unsigned border = 4; + + image2d_b<int> f(nrows, ncols, border); + + mln_assertion(f.npoints() = f.nrows() * f.ncols()); + mln_assertion(f.ncells() = (nrows + 2 * border) * (ncols + 2 * border)); +} Index: mln/core/concept/image.hh --- mln/core/concept/image.hh (revision 1003) +++ mln/core/concept/image.hh (working copy) @@ -80,6 +80,7 @@ bool has(const psite& p) const; const box_<point>& bbox() const; + std::size_t npoints() const; */ protected: Index: mln/core/concept/genpoint.hh --- mln/core/concept/genpoint.hh (revision 1003) +++ mln/core/concept/genpoint.hh (working copy) @@ -176,6 +176,27 @@ operator+(const GenPoint<P>& lhs, const mln_dpoint(P)& rhs); + /*! \brief Substract a delta-point \p rhs to a generalized point \p lhs. + * + * \param[in] lhs A generalized point. + * \param[in] rhs A delta-point. + * + * The type of \p rhs has to be exactly the delta-point type + * associated with the type of \p lhs. + * + * \return A point (temporary object). + * + * \see mln::Dpoint + * \relates mln::GenPoint + * + * \todo Introduce the notion of "generalized dpoint" and + * add the more general extra operator-(GenPoint, GenDpoint). + */ + template <typename P> + mln_point(P) + operator-(const GenPoint<P>& lhs, const mln_dpoint(P)& rhs); + + /*! \brief Print a generalized point \p p into the output stream \p * ostr. * @@ -263,6 +284,17 @@ } template <typename P> + mln_point(P) + operator-(const GenPoint<P>& lhs, const mln_dpoint(P)& rhs) + { + const P& lhs_ = lhs.force_exact_(); + mln_point(P) tmp; + for (unsigned i = 0; i < P::dim; ++i) + tmp[i] = lhs_[i] - rhs[i]; + return tmp; + } + + template <typename P> std::ostream& operator<<(std::ostream& ostr, const GenPoint<P>& p) { const P& p_ = p.force_exact_(); Index: mln/core/concept/doc/image.hh --- mln/core/concept/doc/image.hh (revision 1003) +++ mln/core/concept/doc/image.hh (working copy) @@ -156,6 +156,10 @@ * \return A bounding box of the image domain. */ const box_<point>& bbox() const; + + /*! \brief Give the number of points of the image domain. + */ + std::size_t npoints() const; }; } // end of namespace mln::doc Index: mln/core/image2d_b.hh --- mln/core/image2d_b.hh (revision 1003) +++ mln/core/image2d_b.hh (working copy) @@ -25,17 +25,20 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_CORE_IMAGE2D_HH -# define MLN_CORE_IMAGE2D_HH +#ifndef MLN_CORE_IMAGE2D_B_HH +# define MLN_CORE_IMAGE2D_B_HH -/*! \file mln/core/image2d.hh +/*! \file mln/core/image2d_b.hh * - * \brief Definition of the basic mln::image2d class. + * \brief Definition of the basic mln::image2d_b class. */ # include <mln/core/internal/image_base.hh> # include <mln/core/box2d.hh> +# include <mln/border/thickness.hh> +# include <mln/fun/all.hh> + namespace mln { @@ -43,10 +46,11 @@ /*! \brief Basic 2D image class. * * The parameter \c T is the type of pixel values. This image class - * stores data in memory and has no virtual border. + * stores data in memory and has a virtual border with constant + * thickness around data. */ template <typename T> - struct image2d : public internal::image_base_< box2d, image2d<T> > + struct image2d_b : public internal::image_base_< box2d, image2d_b<T> > { // warning: just to make effective types appear in Doxygen @@ -72,23 +76,28 @@ template <typename U> struct change_value { - typedef image2d<U> ret; + typedef image2d_b<U> ret; }; /// Constructor without argument. - image2d(); - - /// Constructor with the numbers of rows and columns. - image2d(int nrows, int ncols); + image2d_b(); - /// Constructor with a box. - image2d(const box2d& b); + /// Constructor with the numbers of rows and columns and the + /// border thickness. + image2d_b(int nrows, int ncols, unsigned bdr = border::thickness); + + /// Constructor with a box and the border thickness (default is + /// 3). + image2d_b(const box2d& b, unsigned bdr = border::thickness); /// Copy constructor. - image2d(const image2d<T>& rhs); + image2d_b(const image2d_b<T>& rhs); /// Assignment operator. - image2d& operator=(const image2d<T>& rhs); + image2d_b& operator=(const image2d_b<T>& rhs); + + /// Test if \p p is valid. + bool owns_(const point2d& p) const; /// Test if this image has been initialized. bool has_data() const; @@ -96,6 +105,18 @@ /// Give the definition domain. const box2d& domain() const; + /// Give the border thickness. + unsigned border() const; + + /// Give the number of rows (not including the border). + unsigned nrows() const; + + /// Give the number of cols (not including the border). + unsigned ncols() const; + + /// Give the number of cells (points including border ones). + std::size_t ncells() const; + /// Read-only access to the image value located at \p p. const T& operator()(const point2d& p) const; @@ -103,18 +124,21 @@ T& operator()(const point2d& p); /// Destructor. - ~image2d(); + ~image2d_b(); private: - box2d b_; + box2d b_; // theoretical box T* buffer_; T** array_; + unsigned bdr_; + box2d vb_; // virtual box, i.e., box including the virtual border + void update_vb_(); void allocate_(); void deallocate_(); - typedef internal::image_base_< box2d, image2d<T> > super; + typedef internal::image_base_< box2d, image2d_b<T> > super; }; @@ -123,42 +147,47 @@ // ctors template <typename T> - image2d<T>::image2d() + image2d_b<T>::image2d_b() { buffer_ = 0; array_ = 0; + bdr_ = border::thickness; // default value in ctors. } template <typename T> - image2d<T>::image2d(int nrows, int ncols) + image2d_b<T>::image2d_b(int nrows, int ncols, unsigned bdr) { b_ = mk_box2d(nrows, ncols); + bdr_ = bdr; allocate_(); } template <typename T> - image2d<T>::image2d(const box2d& b) - : b_(b) + image2d_b<T>::image2d_b(const box2d& b, unsigned bdr) + : b_(b), + bdr_(bdr) { + bdr_ = bdr; allocate_(); } template <typename T> - image2d<T>::image2d(const image2d<T>& rhs) + image2d_b<T>::image2d_b(const image2d_b<T>& rhs) : super(rhs), - b_(rhs.domain()) + b_(rhs.domain()), + bdr_(rhs.border()) { allocate_(); std::memcpy(this->buffer_, rhs.buffer_, - b_.npoints() * sizeof(value)); + ncells() * sizeof(value)); } // assignment template <typename T> - image2d<T>& - image2d<T>::operator=(const image2d<T>& rhs) + image2d_b<T>& + image2d_b<T>::operator=(const image2d_b<T>& rhs) { assert(rhs.has_data()); if (& rhs = this) @@ -166,9 +195,11 @@ if (this->has_data()) this->deallocate_(); this->b_ = rhs.domain(); + this->bdr_ = rhs.border(); + allocate_(); std::memcpy(this->buffer_, rhs.buffer_, - b_.npoints() * sizeof(value)); + ncells() * sizeof(value)); return *this; } @@ -176,36 +207,83 @@ template <typename T> bool - image2d<T>::has_data() const + image2d_b<T>::has_data() const { return buffer_ != 0 && array_ != 0; } template <typename T> const box2d& - image2d<T>::domain() const + image2d_b<T>::domain() const { + mln_precondition(this->has_data()); return b_; } template <typename T> + unsigned + image2d_b<T>::border() const + { + mln_precondition(this->has_data()); + return bdr_; + } + + template <typename T> + unsigned + image2d_b<T>::nrows() const + { + mln_precondition(this->has_data()); + return 1 + b_.pmax().row() - b_.pmin().row(); + } + + template <typename T> + unsigned + image2d_b<T>::ncols() const + { + mln_precondition(this->has_data()); + return 1 + b_.pmax().col() - b_.pmin().col(); + } + + template <typename T> + std::size_t + image2d_b<T>::ncells() const + { + mln_precondition(this->has_data()); + std::size_t s = 1; + s *= nrows() + 2 * bdr_; + s *= ncols() + 2 * bdr_; + return s; + } + + template <typename T> + bool + image2d_b<T>::owns_(const point2d& p) const + { + mln_precondition(this->has_data()); + return p.row() >= vb_.pmin().row() + && p.row() <= vb_.pmax().row() + && p.col() >= vb_.pmin().col() + && p.col() <= vb_.pmax().col(); + } + + template <typename T> const T& - image2d<T>::operator()(const point2d& p) const + image2d_b<T>::operator()(const point2d& p) const { - assert(this->has_data() && this->owns_(p)); + mln_precondition(this->owns_(p)); return array_[p.row()][p.col()]; } template <typename T> T& - image2d<T>::operator()(const point2d& p) + image2d_b<T>::operator()(const point2d& p) { - assert(this->has_data() && this->owns_(p)); + mln_precondition(this->owns_(p)); return array_[p.row()][p.col()]; } template <typename T> - image2d<T>::~image2d() + image2d_b<T>::~image2d_b() { deallocate_(); } @@ -214,26 +292,34 @@ template <typename T> void - image2d<T>::allocate_() + image2d_b<T>::update_vb_() + { + vb_.pmin() = b_.pmin() - dpoint2d(all(bdr_)); + vb_.pmax() = b_.pmax() + dpoint2d(all(bdr_)); + } + + template <typename T> + void + image2d_b<T>::allocate_() { + update_vb_(); unsigned - nrows = 1 + b_.pmax().row() - b_.pmin().row(), - ncols = 1 + b_.pmax().col() - b_.pmin().col(), - len = nrows * ncols; - buffer_ = new T[len]; - array_ = new T*[nrows]; - T* buf = buffer_ - b_.pmin().col(); - for (unsigned i = 0; i < nrows; ++i) + nr = nrows() + 2 * bdr_, + nc = ncols() + 2 * bdr_; + buffer_ = new T[ncells()]; + array_ = new T*[nr]; + T* buf = buffer_ - (b_.pmin().col() - bdr_); + for (unsigned i = 0; i < nr; ++i) { array_[i] = buf; - buf += ncols; + buf += nc; } - array_ -= b_.pmin().row(); + array_ -= b_.pmin().row() - bdr_; } template <typename T> void - image2d<T>::deallocate_() + image2d_b<T>::deallocate_() { if (buffer_) { @@ -242,7 +328,7 @@ } if (array_) { - array_ += b_.pmin().row(); + array_ += b_.pmin().row() - bdr_; delete[] array_; array_ = 0; } @@ -253,4 +339,4 @@ } // end of namespace mln -#endif // ! MLN_CORE_IMAGE2D_HH +#endif // ! MLN_CORE_IMAGE2D_B_HH Index: mln/core/internal/image_base.hh --- mln/core/internal/image_base.hh (revision 1003) +++ mln/core/internal/image_base.hh (working copy) @@ -70,12 +70,12 @@ /// Test if \p p belongs to the image domain. bool has(const psite& p) const; - /// Test if a pixel value is accessible at \p p. - bool owns_(const psite& p) const; - /// Give a bounding box of the image domain. const box_<point>& bbox() const; + /// Give the number of points of the image domain. + std::size_t npoints() const; + protected: image_base_(); }; @@ -91,17 +91,17 @@ } template <typename S, typename E> - bool - image_base_<S,E>::owns_(const psite& p) const // default + const box_<mln_point(S)>& + image_base_<S,E>::bbox() const { - return this->has(p); + return exact(this)->domain().bbox(); } template <typename S, typename E> - const box_<mln_point(S)>& - image_base_<S,E>::bbox() const + std::size_t + image_base_<S,E>::npoints() const { - return exact(this)->domain().bbox(); + return exact(this)->domain().npoints(); } template <typename S, typename E> Index: mln/border/thickness.hh --- mln/border/thickness.hh (revision 0) +++ mln/border/thickness.hh (revision 0) @@ -0,0 +1,50 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_BORDER_THICKNESS_HH +# define MLN_BORDER_THICKNESS_HH + +/*! \file mln/border/thickness.hh + * + * \brief FIXME. + */ + + +namespace mln +{ + + namespace border + { + + const unsigned thickness = 3; + + } // end of namespace mln::border + +} // end of namespace mln + + +#endif // ! MLN_BORDER_THICKNESS_HH
participants (1)
-
Thierry Geraud