Commit 3c42c279 authored by Thierry Geraud's avatar Thierry Geraud
Browse files

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.


git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@1004 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 35293fda
2007-07-11 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.
2007-07-09 Thierry Geraud <thierry.geraud@lrde.epita.fr>
Add progressive histogram and median in milena.
......
// 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
......@@ -156,6 +156,10 @@ namespace mln
* \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
......
......@@ -176,6 +176,27 @@ namespace mln
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.
*
......@@ -262,6 +283,17 @@ namespace mln
return tmp;
}
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)
{
......
......@@ -80,6 +80,7 @@ namespace mln
bool has(const psite& p) const;
const box_<point>& bbox() const;
std::size_t npoints() const;
*/
protected:
......
......@@ -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 @@ namespace mln
/*! \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 @@ namespace mln
template <typename U>
struct change_value
{
typedef image2d<U> ret;
typedef image2d_b<U> ret;
};
/// Constructor without argument.
image2d();
image2d_b();
/// Constructor with the numbers of rows and columns.
image2d(int nrows, int ncols);
/// 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.
image2d(const box2d& b);
/// 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 @@ namespace mln
/// 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 @@ namespace mln
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 @@ namespace mln
// ctors
template <typename T>
image2d<T>::image2d()
image2d_b<T>::image2d_b()
{
buffer_ = 0;
array_ = 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 @@ namespace mln
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 @@ namespace mln
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 @@ namespace mln
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 @@ namespace mln
}
if (array_)
{
array_ += b_.pmin().row();
array_ += b_.pmin().row() - bdr_;
delete[] array_;
array_ = 0;
}
......@@ -253,4 +339,4 @@ namespace mln
} // end of namespace mln
#endif // ! MLN_CORE_IMAGE2D_HH
#endif // ! MLN_CORE_IMAGE2D_B_HH
......@@ -70,12 +70,12 @@ namespace mln
/// 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 @@ namespace mln
}
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>
......
// 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));
}
......@@ -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 @@ int main()
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 @@ int main()
// 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 @@ int main()
// {
// 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);
// }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment