https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)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