1005: Better milena median.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Better milena median. * tests/median.cc: Update. * mln/convert/to_dpoint.hh: New. * mln/debug/println.hh (println): Add endl. * mln/level/median.hh: New. * mln/io/save_pgm.hh: New. * mln/io/load_pgm.hh: New. * mln/core/box.hh (len): New. * mln/core/concept/box.hh: Likewise. * mln/core/point.hh (zero): New. * mln/core/dpoint.hh: Likewise. * mln/core/concept/window.hh (dpoint, point): New. * mln/core/window.hh, * mln/core/rectangle2d.hh: Update. * mln/core/concept/genpoint.hh: Remove dead line. * mln/core/concept/dpoint.hh (operator+): New. * mln/core/image2d_b.hh: . * mln/core/internal/force_exact.hh: Avoid obj creation. * mln/accu: New. * mln/value/histo.hh: Rename as... * mln/value/median.hh: ...this. * mln/accu/histo.hh: Rename as... * mln/accu/median.hh: ...this. * mln/accu/median_alt.hh: New. mln/accu/histo.hh | 20 +- mln/accu/median.hh | 147 +++++++++----------- mln/accu/median_alt.hh | 279 +++++++++++++++++++++++++++++++++++++++ mln/convert/to_dpoint.hh | 66 +++++++++ mln/core/box.hh | 13 + mln/core/concept/box.hh | 6 mln/core/concept/dpoint.hh | 22 +++ mln/core/concept/genpoint.hh | 1 mln/core/concept/window.hh | 6 mln/core/dpoint.hh | 13 + mln/core/image2d_b.hh | 32 +--- mln/core/internal/force_exact.hh | 6 mln/core/point.hh | 11 + mln/core/rectangle2d.hh | 6 mln/core/window.hh | 61 ++++++++ mln/debug/println.hh | 1 mln/io/load_pgm.hh | 177 ++++++++++++++++++++++++ mln/io/save_pgm.hh | 74 ++++++++++ mln/level/median.hh | 136 +++++++++++++++++++ tests/median.cc | 230 ++++++++++++++++++-------------- 20 files changed, 1092 insertions(+), 215 deletions(-) Index: tests/median.cc --- tests/median.cc (revision 1004) +++ tests/median.cc (working copy) @@ -30,155 +30,185 @@ * \brief Tests on mln::value::median<S>. */ +#include <cmath> + +#include <mln/core/image2d_b.hh> #include <mln/value/int_u.hh> -#include <mln/value/median.hh> +#include <mln/level/fill.hh> +#include <mln/level/median.hh> +#include <mln/debug/println.hh> + +#include <mln/core/rectangle2d.hh> + +#include <mln/io/load_pgm.hh> +#include <mln/io/save_pgm.hh> -int main() -{ using namespace mln; using namespace mln::value; - typedef set_<int_u8> S; - median<S> m(S::the()); +int_u8 f(const point2d& p) +{ + return unsigned((2 + + std::cos(float(p.row())) + + std::sin(float(p.col()))) * 63.9); +} +int main() { - unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42 }; - unsigned n = sizeof(vals)/sizeof(unsigned); - for (unsigned i = 0; i < n; ++i) - { - std::cout << "taking " << vals[i] << ':' << std::endl; - m.take(vals[i]); - std::cout << m << std::endl; - } +// typedef set_<int_u8> S; - for (int i = int(n) - 1; i >= 0; --i) - { - std::cout << "untaking " << vals[i] << ':' << std::endl; - m.untake(vals[i]); - std::cout << m << std::endl; - } +// median<S> m(S::the()); - } +// { +// unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42 }; +// unsigned n = sizeof(vals)/sizeof(unsigned); - { +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "taking " << vals[i] << ':' << std::endl; +// m.take(vals[i]); +// std::cout << m << std::endl; +// } - unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42 }; - unsigned n = sizeof(vals)/sizeof(unsigned); +// for (int i = int(n) - 1; i >= 0; --i) +// { +// std::cout << "untaking " << vals[i] << ':' << std::endl; +// m.untake(vals[i]); +// std::cout << m << std::endl; +// } - for (unsigned i = 0; i < n; ++i) - { - std::cout << "taking " << vals[i] << ':' << std::endl; - m.take(vals[i]); - std::cout << m << std::endl; - } +// } - for (unsigned i = 0; i < n; ++i) - { - std::cout << "untaking " << vals[i] << ':' << std::endl; - m.untake(vals[i]); - std::cout << m << std::endl; - } + image2d_b<int_u8> + lena = io::load_pgm("lena.pgm"), + out(lena.domain()); + + rectangle2d rec(64, 64); + level::median(lena, rec, out); + io::save_pgm(out, "out.pgm"); } - { - unsigned vals[] = { 42, 42, 69, 69, 51, 51, 12, 12, 51, 51, 12, 12, 42, 42 }; - unsigned n = sizeof(vals)/sizeof(unsigned); +// { - for (unsigned i = 0; i < n; ++i) - { - std::cout << "taking " << vals[i] << ':' << std::endl; - m.take(vals[i]); - std::cout << m << std::endl; - } +// unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42 }; +// unsigned n = sizeof(vals)/sizeof(unsigned); - for (int i = int(n) - 1; i >= 0; --i) - { - std::cout << "untaking " << vals[i] << ':' << std::endl; - m.untake(vals[i]); - std::cout << m << std::endl; - } +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "taking " << vals[i] << ':' << std::endl; +// m.take(vals[i]); +// std::cout << m << std::endl; +// } - } +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "untaking " << vals[i] << ':' << std::endl; +// m.untake(vals[i]); +// std::cout << m << std::endl; +// } +// } - { - unsigned vals[] = { 42, 42, 69, 69, 51, 51, 12, 12, 51, 51, 12, 12, 42, 42 }; - unsigned n = sizeof(vals)/sizeof(unsigned); - for (unsigned i = 0; i < n; ++i) - { - std::cout << "taking " << vals[i] << ':' << std::endl; - m.take(vals[i]); - std::cout << m << std::endl; - } +// { - for (unsigned i = 0; i < n; ++i) - { - std::cout << "untaking " << vals[i] << ':' << std::endl; - m.untake(vals[i]); - std::cout << m << std::endl; - } +// unsigned vals[] = { 42, 42, 69, 69, 51, 51, 12, 12, 51, 51, 12, 12, 42, 42 }; +// unsigned n = sizeof(vals)/sizeof(unsigned); - } +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "taking " << vals[i] << ':' << std::endl; +// m.take(vals[i]); +// std::cout << m << std::endl; +// } +// for (int i = int(n) - 1; i >= 0; --i) +// { +// std::cout << "untaking " << vals[i] << ':' << std::endl; +// m.untake(vals[i]); +// std::cout << m << std::endl; +// } +// } - { +// { - unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42, 69, 51, 12, 51, 12, 42 }; - unsigned n = sizeof(vals)/sizeof(unsigned); +// unsigned vals[] = { 42, 42, 69, 69, 51, 51, 12, 12, 51, 51, 12, 12, 42, 42 }; +// unsigned n = sizeof(vals)/sizeof(unsigned); - for (unsigned i = 0; i < n; ++i) - { - std::cout << "taking " << vals[i] << ':' << std::endl; - m.take(vals[i]); - std::cout << m << std::endl; - } +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "taking " << vals[i] << ':' << std::endl; +// m.take(vals[i]); +// std::cout << m << std::endl; +// } - for (int i = int(n) - 1; i >= 0; --i) - { - std::cout << "untaking " << vals[i] << ':' << std::endl; - m.untake(vals[i]); - std::cout << m << std::endl; - } +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "untaking " << vals[i] << ':' << std::endl; +// m.untake(vals[i]); +// std::cout << m << std::endl; +// } - } +// } - { - unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42, 69, 51, 12, 51, 12, 42 }; - unsigned n = sizeof(vals)/sizeof(unsigned); - for (unsigned i = 0; i < n; ++i) - { - std::cout << "taking " << vals[i] << ':' << std::endl; - m.take(vals[i]); - std::cout << m << std::endl; - } +// { - for (unsigned i = 0; i < n; ++i) - { - std::cout << "untaking " << vals[i] << ':' << std::endl; - m.untake(vals[i]); - std::cout << m << std::endl; - } +// unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42, 69, 51, 12, 51, 12, 42 }; +// unsigned n = sizeof(vals)/sizeof(unsigned); - } +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "taking " << vals[i] << ':' << std::endl; +// m.take(vals[i]); +// std::cout << m << std::endl; +// } +// for (int i = int(n) - 1; i >= 0; --i) +// { +// std::cout << "untaking " << vals[i] << ':' << std::endl; +// m.untake(vals[i]); +// std::cout << m << std::endl; +// } + +// } + + +// { + +// unsigned vals[] = { 42, 69, 51, 12, 51, 12, 42, 69, 51, 12, 51, 12, 42 }; +// unsigned n = sizeof(vals)/sizeof(unsigned); + +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "taking " << vals[i] << ':' << std::endl; +// m.take(vals[i]); +// std::cout << m << std::endl; +// } + +// for (unsigned i = 0; i < n; ++i) +// { +// std::cout << "untaking " << vals[i] << ':' << std::endl; +// m.untake(vals[i]); +// std::cout << m << std::endl; +// } + +// } -} Index: mln/convert/to_dpoint.hh --- mln/convert/to_dpoint.hh (revision 0) +++ mln/convert/to_dpoint.hh (revision 0) @@ -0,0 +1,66 @@ +// 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_CONVERT_TO_DPOINT_HH +# define MLN_CONVERT_TO_DPOINT_HH + +/*! \file mln/convert/to_dpoint.hh + * + * \brief Convertions to mln::Dpoint. + */ + + +namespace mln +{ + + namespace convert + { + + template <typename P> + mln_dpoint(P) to_dpoint(const GenPoint<P>& p); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename P> + mln_dpoint(P) to_dpoint(const GenPoint<P>& p_) + { + const P& p = p_.force_exact_(); + mln_dpoint(P) tmp; + for (unsigned i = 0; i < P::dim; ++i) + tmp[i] = p[i]; + return tmp; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::convert + +} // end of namespace mln + + +#endif // ! MLN_CONVERT_TO_DPOINT_HH Index: mln/debug/println.hh --- mln/debug/println.hh (revision 1004) +++ mln/debug/println.hh (working copy) @@ -74,6 +74,7 @@ std::cout << input(mk_point2d(row, col)) << ' '; std::cout << std::endl; } + std::cout << std::endl; } } // end of namespace mln::debug::impl Index: mln/level/median.hh --- mln/level/median.hh (revision 0) +++ mln/level/median.hh (revision 0) @@ -0,0 +1,136 @@ +// 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_LEVEL_MEDIAN_HH +# define MLN_LEVEL_MEDIAN_HH + +/*! \file mln/level/median.hh + * + * \brief Median filter on an image. + */ + +# include <mln/core/concept/image.hh> +# include <mln/core/window2d.hh> +# include <mln/accu/median.hh> + + +namespace mln +{ + + namespace level + { + + /*! FIXME: Median the image \p ima with the values of the image \p data. + * + * \param[in] input The image to be filtered. + * \param[in] win The window. + * \param[in,out] output The output image. + * + * \warning The definition domain of \p ima has to be included in + * the one of \p data. + * + * \pre \p ima has to be initialized. + * + * \todo Test domain inclusion. + */ + template <typename I, typename W, typename O> + void median(const Image<I>& input, const Window<W>& win, + Image<O>& output); + + +# ifndef MLN_INCLUDE_ONLY + + + namespace impl + { + + template <typename I, typename W, typename O> + void median(const I& input, + const W& win, + O& output) + { + dpoint2d dp = mk_dpoint2d(0, 1); + + window2d + w_plus = win - (win - dp), + w_minus = (win - dp) - win; + + accu::median_on<mln_value(I)> med; + + point2d p; + mln_qiter(W) q(win, p); + mln_qiter(W) q_plus(w_plus, p); + mln_qiter(W) q_minus(w_minus, p); + + for (p.row() = input.domain().pmin().row(); + p.row() <= input.domain().pmax().row(); + ++p.row()) + { + // init + med.init(); + p.col() = input.domain().pmin().col(); + for_all(q) + if (input.has(q)) + med.take(input(q)); + output(p) = med; + + // other col + for (++p.col(); + p.col() <= input.domain().pmax().col(); + ++p.col()) + { + for_all(q_plus) + if (input.has(q_plus)) + med.take(input(q_plus)); + for_all(q_minus) + if (input.has(q_minus)) + med.untake(input(q_minus)); + output(p) = med; + } + } + } + + } // end of namespace mln::level::impl + + + // facade + + template <typename I, typename W, typename O> + void median(const Image<I>& input, const Window<W>& win, + Image<O>& output) + { + impl::median(exact(input), exact(win), exact(output)); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::level + +} // end of namespace mln + + +#endif // ! MLN_LEVEL_MEDIAN_HH Index: mln/io/save_pgm.hh --- mln/io/save_pgm.hh (revision 0) +++ mln/io/save_pgm.hh (revision 0) @@ -0,0 +1,74 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 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_IO_SAVE_PGM_HH +# define MLN_IO_SAVE_PGM_HH + +# include <iostream> +# include <fstream> + +# include <mln/core/image2d_b.hh> +# include <mln/value/int_u.hh> + + +namespace mln +{ + + namespace io + { + + void save_pgm(const image2d_b<value::int_u8>& ima, const std::string& filename) + { + std::ofstream file(filename.c_str()); + if (not file) + { + std::cerr << "error: cannot open file '" << filename + << "'!"; + abort(); + } + file << "P5" << std::endl; + file << "# olena" << std::endl; + file << ima.ncols() << ' ' << ima.nrows() << std::endl; + file << "255" << std::endl; + point2d p = mk_point2d(ima.domain().pmin().row(), + ima.domain().pmin().col()); + size_t len = ima.ncols() * sizeof(unsigned char); + for (; + p.row() <= ima.domain().pmax().row(); + ++p.row()) + { + file.write((char*)(& ima(p)), len); + } + } + + } // end of namespace mln::io + +} // end of namespace mln + + +#endif // ! MLN_IO_SAVE_PGM_HH Index: mln/io/load_pgm.hh --- mln/io/load_pgm.hh (revision 0) +++ mln/io/load_pgm.hh (revision 0) @@ -0,0 +1,177 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 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_IO_LOAD_PGM_HH +# define MLN_IO_LOAD_PGM_HH + +# include <iostream> +# include <fstream> +# include <string> + +# include <mln/core/image2d_b.hh> +# include <mln/value/int_u.hh> + + +namespace mln +{ + + namespace io + { + + namespace internal + { + + void abort() + { + std::cerr << " aborting." << std::endl; + exit(0); + } + + bool read_pnm_header(std::istream& istr, + char& type, + int& nrows, int& ncols, + bool test = false) + { + // check magic + if (istr.get() != 'P' ) + goto err; + type = istr.get(); + if (type < '1' or type > '6') + goto err; + if (istr.get() != '\n') + goto err; + + // skip comments + while (istr.peek() = '#') + { + std::string line; + std::getline(istr, line); + } + + // get size + istr >> ncols >> nrows; + if (nrows <= 0 or ncols <= 0) + goto err; + + // skip maxvalue + if (istr.get() != '\n') + goto err; + if (type != '1' and type != '4') + { + std::string line; + std::getline(istr, line); + } + return true; + + err: + if (not test) + { + std::cerr << "error: badly formed header!"; + abort(); + } + return false; + } + + void read_pnm_header(char ascii, char raw, + std::istream& istr, + char& type, + int& nrows, int& ncols) + { + read_pnm_header(istr, type, nrows, ncols); + if (not (type = ascii or type = raw)) + { + std::cerr << "error: bad pnm type; " + << "expected P" << ascii + << " or P" << raw + << ", get P" << type << "!"; + abort(); + } + } + + + /// load_ascii. + template <typename I> + void load_pgm_ascii(std::ifstream& file, I& ima) + { + mln_fwd_piter(I) p(ima.domain()); + for_all(p) + { + unsigned value; + file >> value; + ima(p) = value; + // FIXME: Test alt code below. + // file >> ima(p); + } + } + + + /// load_raw_2d. + template <typename I> + void load_pgm_raw_2d(std::ifstream& file, I& ima) + { + point2d p = mk_point2d(0, ima.domain().pmin().col()); + size_t len = ima.ncols() * sizeof(mln_value(I)); + for (p.row() = ima.domain().pmin().row(); + p.row() <= ima.domain().pmax().row(); + ++p.row()) + { + file.read((char*)(& ima(p)), len); + } + } + + + } // end of namespace mln::io::internal + + + image2d_b<value::int_u8> load_pgm(const std::string& filename) + { + std::ifstream file(filename.c_str()); + if (not file) + { + std::cerr << "error: file '" << filename + << "' not found!"; + abort(); + } + char type; + int nrows, ncols; + internal::read_pnm_header('2', '5', file, type, nrows, ncols); + image2d_b<value::int_u8> ima(nrows, ncols); + if (type = '5') + internal::load_pgm_raw_2d(file, ima); + else + if (type = '2') + internal::load_pgm_ascii(file, ima); + return ima; + } + + } // end of namespace mln::io + +} // end of namespace mln + + +#endif // ! MLN_IO_LOAD_PGM_HH Index: mln/core/dpoints_piter.hh Index: mln/core/box.hh --- mln/core/box.hh (revision 1004) +++ mln/core/box.hh (working copy) @@ -88,6 +88,11 @@ */ P& pmax(); + /*! \brief Give the length of the \p i-th side. + * \pre i < dim + */ + unsigned len(unsigned i) const; + /*! \brief Constructor without argument. */ box_(); @@ -151,6 +156,14 @@ } template <typename P> + unsigned + box_<P>::len(unsigned i) const + { + mln_precondition(i < P::dim); + return 1 + pmax_[i] - pmin_[i]; + } + + template <typename P> box_<P>::box_() { } Index: mln/core/point.hh --- mln/core/point.hh (revision 1004) +++ mln/core/point.hh (working copy) @@ -35,6 +35,7 @@ # include <mln/core/concept/point.hh> # include <mln/core/internal/coord_impl.hh> +# include <mln/fun/all.hh> namespace mln @@ -92,6 +93,9 @@ */ void set_all(C c); + /// Give the origin (all coordinates are 0). + static const point_<n,C>& zero(); + protected: C coord_[n]; }; @@ -133,6 +137,13 @@ coord_[i] = c; } + template <unsigned n, typename C> + const point_<n,C>& point_<n,C>::zero() + { + static const point_<n,C> zero_(all(0)); + return zero_; + } + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln Index: mln/core/rectangle2d.hh --- mln/core/rectangle2d.hh (revision 1004) +++ mln/core/rectangle2d.hh (working copy) @@ -56,6 +56,12 @@ struct rectangle2d : public Window< rectangle2d >, public internal::set_of_<dpoint2d> { + /// Point associated type. + typedef point2d point; + + /// Dpoint associated type. + typedef dpoint2d dpoint; + /*! \brief Piter type to browse a rectangle such as: "for each row * (increasing), for each column (increasing)." */ Index: mln/core/concept/genpoint.hh --- mln/core/concept/genpoint.hh (revision 1004) +++ mln/core/concept/genpoint.hh (working copy) @@ -60,7 +60,6 @@ */ template <typename E> struct GenPoint - // : virtual internal::object_<E> { /* Index: mln/core/concept/box.hh --- mln/core/concept/box.hh (revision 1004) +++ mln/core/concept/box.hh (working copy) @@ -52,6 +52,7 @@ /* const point& pmin() const; const point& pmax() const; + unsigned len(unsigned i) const; // FIXME: Doc! */ /*! \brief Return the bounding box of this point set. @@ -102,10 +103,7 @@ std::size_t count = 1; typedef typename E::point P; // helps g++-3.3.5 for (unsigned i = 0; i < P::dim; ++i) - count *- exact(this)->pmax()[i] - + 1 - - exact(this)->pmin()[i]; + count *= exact(this)->len(i); return count; } Index: mln/core/concept/dpoint.hh --- mln/core/concept/dpoint.hh (revision 1004) +++ mln/core/concept/dpoint.hh (working copy) @@ -78,6 +78,19 @@ D operator-(const Dpoint<D>& rhs); + /*! \brief Add the couple of delta-points \p lhs and \p rhs. + * + * \param[in] lhs A delta-point. + * \param[in] rhs Another delta-point. + * + * \return A delta-point (temporary object). + * + * \relates mln::Dpoint + */ + template <typename D> + D operator+(const Dpoint<D>& lhs, const Dpoint<D>& rhs); + + /*! \brief Equality comparison between a couple of delta-point \p lhs * and \p rhs. * @@ -149,6 +162,15 @@ return tmp; } + template <typename D> + D operator+(const Dpoint<D>& lhs, const Dpoint<D>& rhs) + { + D tmp; + for (unsigned i = 0; i < D::dim; ++i) + tmp[i] = exact(lhs)[i] + exact(rhs)[i]; + return tmp; + } + template <typename Dl, typename Dr> bool operator=(const Dpoint<Dl>& lhs, const Dpoint<Dr>& rhs) { Index: mln/core/concept/window.hh --- mln/core/concept/window.hh (revision 1004) +++ mln/core/concept/window.hh (working copy) @@ -47,6 +47,9 @@ struct Window : public Object<E> { /* + typedef point; + typedef dpoint; + typedef qiter; typedef fwd_qiter; typedef bkd_qiter; @@ -66,6 +69,9 @@ template <typename E> Window<E>::Window() { + typedef mln_point(E) point; + typedef mln_dpoint(E) dpoint; + typedef mln_qiter(E) qiter; typedef mln_fwd_qiter(E) fwd_qiter; typedef mln_bkd_qiter(E) bkd_qiter; Index: mln/core/dpoint.hh --- mln/core/dpoint.hh (revision 1004) +++ mln/core/dpoint.hh (working copy) @@ -35,6 +35,7 @@ # include <mln/core/concept/dpoint.hh> # include <mln/core/internal/coord_impl.hh> +# include <mln/fun/all.hh> namespace mln @@ -86,12 +87,15 @@ /*! \brief Constructor; coordinates are set by function \p f. */ template <typename F> - dpoint_(F f); + dpoint_(F f); // FIXME: Bound parameter! /*! \brief Set all coordinates to the value \p c. */ void set_all(C c); + /// Give the null delta-point (all coordinates are 0). + static const dpoint_<n,C>& zero(); + protected: C coord_[n]; }; @@ -133,6 +137,13 @@ coord_[i] = c; } + template <unsigned n, typename C> + const dpoint_<n,C>& dpoint_<n,C>::zero() + { + static const dpoint_<n,C> zero_(all(0)); + return zero_; + } + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln Index: mln/core/window.hh --- mln/core/window.hh (revision 1004) +++ mln/core/window.hh (working copy) @@ -34,8 +34,11 @@ */ # include <mln/core/concept/window.hh> +# include <mln/core/concept/genpoint.hh> # include <mln/core/internal/set_of.hh> # include <mln/core/dpoint.hh> + +# include <mln/convert/to_dpoint.hh> # include <mln/fun/all.hh> @@ -56,6 +59,12 @@ struct window_ : public Window< window_<D> >, public internal::set_of_<D> { + /// Point associated type. + typedef mln_point(D) point; + + /// Dpoint associated type. + typedef D dpoint; + /*! \brief Piter type to browse the points of a generic window * w.r.t. the ordering of delta-points. */ @@ -90,6 +99,25 @@ }; + // FIXME: Move both ops below to mln/core/concept/window.hh + + /// Shift a window \p win with a delta-point \p dp. + template <typename W> + window_<mln_dpoint(W)> operator+(const Window<W>& win, + const mln_dpoint(W)& dp); + + /// Shift a window \p win with the delta-point (-\p dp). + template <typename W> + window_<mln_dpoint(W)> operator-(const Window<W>& win, + const mln_dpoint(W)& dp); + + /// Substract \p rhs from \p lhs. + // FIXME: Give details! + template <typename Wl, typename Wr> + window_<mln_dpoint(Wl)> operator-(const Window<Wl>& lhs, + const Window<Wr>& rhs); + + # ifndef MLN_INCLUDE_ONLY @@ -112,6 +140,39 @@ return false; } + template <typename W> + window_<mln_dpoint(W)> operator+(const Window<W>& win, + const mln_dpoint(W)& dp) + { + window_<mln_dpoint(W)> tmp; + mln_qiter(W) q(win, W::point::zero()); + for_all(q) + tmp.insert(convert::to_dpoint(q) + dp); + return tmp; + } + + template <typename W> + window_<mln_dpoint(W)> operator-(const Window<W>& win, + const mln_dpoint(W)& dp) + { + return win + (-dp); + } + + template <typename W, typename Wr> + window_<mln_dpoint(W)> operator-(const Window<W>& lhs, + const Window<Wr>& rhs) + { + window_<mln_dpoint(W)> tmp; + mln_qiter(W) q(lhs, W::point::zero()); + for_all(q) + { + mln_dpoint(W) dp = convert::to_dpoint(q); + if (not exact(rhs).has(dp)) + tmp.insert(dp); + } + return tmp; + } + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln Index: mln/core/image2d_b.hh --- mln/core/image2d_b.hh (revision 1004) +++ mln/core/image2d_b.hh (working copy) @@ -180,7 +180,7 @@ allocate_(); std::memcpy(this->buffer_, rhs.buffer_, - ncells() * sizeof(value)); + ncells() * sizeof(T)); } // assignment @@ -199,7 +199,7 @@ allocate_(); std::memcpy(this->buffer_, rhs.buffer_, - ncells() * sizeof(value)); + ncells() * sizeof(T)); return *this; } @@ -233,7 +233,7 @@ image2d_b<T>::nrows() const { mln_precondition(this->has_data()); - return 1 + b_.pmax().row() - b_.pmin().row(); + return b_.len(0); } template <typename T> @@ -241,7 +241,7 @@ image2d_b<T>::ncols() const { mln_precondition(this->has_data()); - return 1 + b_.pmax().col() - b_.pmin().col(); + return b_.len(1); } template <typename T> @@ -249,10 +249,7 @@ 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; + return vb_.npoints(); } template <typename T> @@ -260,10 +257,7 @@ 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(); + return vb_.has(p); } template <typename T> @@ -304,17 +298,19 @@ { update_vb_(); unsigned - nr = nrows() + 2 * bdr_, - nc = ncols() + 2 * bdr_; - buffer_ = new T[ncells()]; + nr = vb_.len(0), + nc = vb_.len(1); + buffer_ = new T[nr * nc]; array_ = new T*[nr]; - T* buf = buffer_ - (b_.pmin().col() - bdr_); + T* buf = buffer_ - vb_.pmin().col(); for (unsigned i = 0; i < nr; ++i) { array_[i] = buf; buf += nc; } - array_ -= b_.pmin().row() - bdr_; + array_ -= vb_.pmin().row(); + mln_postcondition(vb_.len(0) = b_.nrows() + 2 * bdr_); + mln_postcondition(vb_.len(1) = b_.ncols() + 2 * bdr_); } template <typename T> @@ -328,7 +324,7 @@ } if (array_) { - array_ += b_.pmin().row() - bdr_; + array_ += vb_.pmin().row(); delete[] array_; array_ = 0; } Index: mln/core/internal/force_exact.hh --- mln/core/internal/force_exact.hh (revision 1004) +++ mln/core/internal/force_exact.hh (working copy) @@ -50,11 +50,11 @@ \ E& force_exact_() const \ { \ - static const E exact_obj; \ - static const Type& exact_obj_ref = exact_obj; \ + static const E* exact_obj; \ + static const Type& exact_obj_ref = *exact_obj; \ static const int exact_offset = \ (const char*)(void*)(&exact_obj_ref) \ - - (const char*)(void*)(&exact_obj); \ + - (const char*)(void*)( exact_obj); \ return *(E*)((char*)(this) - exact_offset); \ } Index: mln/accu/histo.hh --- mln/accu/histo.hh (revision 0) +++ mln/accu/histo.hh (working copy) @@ -25,8 +25,8 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_VALUE_HISTO_HH -# define MLN_VALUE_HISTO_HH +#ifndef MLN_ACCU_HISTO_HH +# define MLN_ACCU_HISTO_HH /*! \file mln/value/histo.hh * @@ -43,7 +43,7 @@ namespace mln { - namespace value + namespace accu { @@ -58,7 +58,7 @@ void take(const value& v); void untake(const value& v); - void clear(); + void init(); std::size_t operator()(const value& v) const; std::size_t operator[](std::size_t i) const; @@ -86,7 +86,7 @@ /*! Generic histogram class over the set of values of type \c T. */ template <typename T> - struct histo_on_type : public histo_on_set< set_<T> > + struct histo_on_type : public histo_on_set< value::set_<T> > { histo_on_type(); }; @@ -127,9 +127,10 @@ template <typename S> void - histo_on_set<S>::clear() + histo_on_set<S>::init() { std::fill(h_.begin(), h_.end(), 0); + sum_ = 0; } template <typename S> @@ -180,6 +181,7 @@ { mln_viter(S) v(h.vset()); for_all(v) + if (h(v) != 0) ostr << v << ':' << h(v) << ' '; ostr << std::endl; return ostr; @@ -190,7 +192,7 @@ template <typename T> histo_on_type<T>::histo_on_type() - : histo_on_set< set_<T> >(set_<T>::the()) + : histo_on_set< value::set_<T> >(value::set_<T>::the()) { } @@ -198,9 +200,9 @@ # endif // ! MLN_INCLUDE_ONLY - } // end of namespace mln::value + } // end of namespace mln::accu } // end of namespace mln -#endif // ! MLN_VALUE_HISTO_HH +#endif // ! MLN_ACCU_HISTO_HH Index: mln/accu/median.hh --- mln/accu/median.hh (revision 0) +++ mln/accu/median.hh (working copy) @@ -25,21 +25,21 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_VALUE_MEDIAN_HH -# define MLN_VALUE_MEDIAN_HH +#ifndef MLN_ACCU_MEDIAN_HH +# define MLN_ACCU_MEDIAN_HH -/*! \file mln/value/median.hh +/*! \file mln/accu/median.hh * * \brief Define FIXME */ -# include <mln/value/histo.hh> +# include <mln/accu/histo.hh> namespace mln { - namespace value + namespace accu { @@ -55,11 +55,15 @@ void take(const value& v); void untake(const value& v); - void clear(); + void init(); + + unsigned card() const { return h_.sum(); } operator value() const; value to_value() const; + const histo_on_set<S>& histo() const; + // FIXME: remove void debug__() const { @@ -71,20 +75,31 @@ protected: - histo_on_set<S> h_; + mutable histo_on_set<S> h_; const S& s_; // derived from h_ - std::size_t sum_minus_, sum_plus_; + mutable std::size_t sum_minus_, sum_plus_; - std::size_t i_; // the median index - value v_; // the median value + mutable bool valid_; + mutable std::size_t i_; // the median index + mutable value v_; // the median value // Auxiliary methods - void go_minus_(); - void go_plus_(); + void update_() const; + void go_minus_() const; + void go_plus_() const; }; + template <typename T> + struct median_on : public median< value::set_<T> > + { + median_on() + : median< value::set_<T> >(value::set_<T>::the()) + { + } + }; + # ifndef MLN_INCLUDE_ONLY @@ -94,7 +109,7 @@ : h_(s), s_(h_.vset()) { - clear(); + init(); } @@ -102,42 +117,15 @@ void median<S>::take(const value& v) { - // update h_ h_.take(v); - // particular case: - // current state was initialization - if (h_[i_] = 0) - { - // std::cout << "init!" << std::endl; - i_ = s_.index_of(v); - v_ = v; - return; - } - - // particular case: - // the median does not change - if (v = v_) - { - // std::cout << "no change!" << std::endl; - return; - } - - // general case: - if (v < v_) - { ++sum_minus_; - if (2 * sum_minus_ > h_.sum()) - go_minus_(); - } - else - // v > v_ - { + else if (v > v_) ++sum_plus_; - if (2 * sum_plus_ > h_.sum()) - go_plus_(); - } + + if (valid_) + valid_ = false; } @@ -146,34 +134,33 @@ median<S>::untake(const value& v) { mln_precondition(h_(v) != 0); - - // update h_ h_.untake(v); - // particular case: - // the only value has been removed - if (h_.sum() = 0) - { - clear(); - return; - } - - // general case: if (v < v_) - { --sum_minus_; - if (2 * sum_plus_ > h_.sum()) - go_plus_(); - } else if (v > v_) - { --sum_plus_; + + if (valid_) + valid_ = false; + } + + + template <typename S> + void + median<S>::update_() const + { + valid_ = true; + + if (h_.sum() = 0) + return; + if (2 * sum_minus_ > h_.sum()) go_minus_(); - } else - // v = v_ - { + if (2 * sum_plus_ > h_.sum()) + go_plus_(); + else if (h_[i_] = 0) { // go to the heaviest side @@ -182,21 +169,12 @@ else go_minus_(); // default when both sides are balanced } - else - { - if (2 * sum_plus_ > h_.sum()) - go_plus_(); - else if (2 * sum_minus_ > h_.sum()) - go_minus_(); - // else no change - } - } } template <typename S> void - median<S>::go_minus_() + median<S>::go_minus_() const { do { @@ -213,7 +191,7 @@ template <typename S> void - median<S>::go_plus_() + median<S>::go_plus_() const { do { @@ -230,29 +208,40 @@ template <typename S> void - median<S>::clear() + median<S>::init() { - h_.clear(); + h_.init(); sum_minus_ = 0; sum_plus_ = 0; i_ = (mln_max(value) - mln_min(value)) / 2; v_ = s_[i_]; + valid_ = true; } + template <typename S> median<S>::operator typename median<S>::value () const { - return v_; + return to_value(); } template <typename S> typename median<S>::value median<S>::to_value() const { + if (not valid_) + update_(); return v_; } template <typename S> + const histo_on_set<S>& + median<S>::histo() const + { + return h_; + } + + template <typename S> std::ostream& operator<<(std::ostream& ostr, const median<S>& m) { m.debug__(); @@ -262,9 +251,9 @@ # endif // ! MLN_INCLUDE_ONLY - } // end of namespace mln::value + } // end of namespace mln::accu } // end of namespace mln -#endif // ! MLN_VALUE_MEDIAN_HH +#endif // ! MLN_ACCU_MEDIAN_HH Index: mln/accu/median_alt.hh --- mln/accu/median_alt.hh (revision 0) +++ mln/accu/median_alt.hh (revision 0) @@ -0,0 +1,279 @@ +// 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_ACCU_MEDIAN_ALT_HH +# define MLN_ACCU_MEDIAN_ALT_HH + +/*! \file mln/accu/median_alt.hh + * + * \brief Define FIXME + */ + +# include <mln/accu/histo.hh> + + +namespace mln +{ + + namespace accu + { + + + /*! Generic median_alt function based on histogram over a value set + * with type \c S. + */ + template <typename S> + struct median_alt + { + typedef mln_value(S) value; + + median_alt(const Value_Set<S>& s); + + void take(const value& v); + void untake(const value& v); + void init(); + + operator value() const; + value to_value() const; + + // FIXME: remove + void debug__() const + { + std::cout << " i = " << i_ + << " v = " << v_ + << " s = " << sum_minus_ << " ; " << h_[i_] << " ; " << sum_plus_ << " = " << h_.sum() + << std::endl; + } + + protected: + + histo_on_set<S> h_; + const S& s_; // derived from h_ + + std::size_t sum_minus_, sum_plus_; + + std::size_t i_; // the median index + value v_; // the median value + + // Auxiliary methods + void go_minus_(); + void go_plus_(); + }; + + + template <typename T> + struct median_alt_on : public median_alt< value::set_<T> > + { + median_alt_on() + : median_alt< value::set_<T> >(value::set_<T>::the()) + { + } + }; + + +# ifndef MLN_INCLUDE_ONLY + + + template <typename S> + median_alt<S>::median_alt(const Value_Set<S>& s) + : h_(s), + s_(h_.vset()) + { + init(); + } + + + template <typename S> + void + median_alt<S>::take(const value& v) + { + // update h_ + h_.take(v); + + // particular case: + // current state was initialization + if (h_[i_] = 0) + { + // std::cout << "init!" << std::endl; + i_ = s_.index_of(v); + v_ = v; + return; + } + + // particular case: + // the median does not change + if (v = v_) + { + // std::cout << "no change!" << std::endl; + return; + } + + // general case: + + if (v < v_) + { + ++sum_minus_; + if (2 * sum_minus_ > h_.sum()) + go_minus_(); + } + else + // v > v_ + { + ++sum_plus_; + if (2 * sum_plus_ > h_.sum()) + go_plus_(); + } + } + + + template <typename S> + void + median_alt<S>::untake(const value& v) + { + mln_precondition(h_(v) != 0); + + // update h_ + h_.untake(v); + + // particular case: + // the only value has been removed + if (h_.sum() = 0) + { + init(); + return; + } + + // general case: + if (v < v_) + { + --sum_minus_; + if (2 * sum_plus_ > h_.sum()) + go_plus_(); + } + else if (v > v_) + { + --sum_plus_; + if (2 * sum_minus_ > h_.sum()) + go_minus_(); + } + else + // v = v_ + { + if (h_[i_] = 0) + { + // go to the heaviest side + if (sum_plus_ > sum_minus_) + go_plus_(); + else + go_minus_(); // default when both sides are balanced + } + else + { + if (2 * sum_plus_ > h_.sum()) + go_plus_(); + else if (2 * sum_minus_ > h_.sum()) + go_minus_(); + // else no change + } + } + } + + + template <typename S> + void + median_alt<S>::go_minus_() + { + do + { + sum_plus_ += h_[i_]; + do + --i_; + while (h_[i_] = 0); + sum_minus_ -= h_[i_]; + } + while (2 * sum_minus_ > h_.sum()); + v_ = s_[i_]; + } + + + template <typename S> + void + median_alt<S>::go_plus_() + { + do + { + sum_minus_ += h_[i_]; + do + ++i_; + while (h_[i_] = 0); + sum_plus_ -= h_[i_]; + } + while (2 * sum_plus_ > h_.sum()); + v_ = s_[i_]; + } + + + template <typename S> + void + median_alt<S>::init() + { + h_.init(); + sum_minus_ = 0; + sum_plus_ = 0; + i_ = (mln_max(value) - mln_min(value)) / 2; + v_ = s_[i_]; + } + + template <typename S> + median_alt<S>::operator typename median_alt<S>::value () const + { + return v_; + } + + template <typename S> + typename median_alt<S>::value + median_alt<S>::to_value() const + { + return v_; + } + + template <typename S> + std::ostream& operator<<(std::ostream& ostr, const median_alt<S>& m) + { + m.debug__(); + return ostr << m.to_value(); + } + + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::accu + +} // end of namespace mln + + +#endif // ! MLN_ACCU_MEDIAN_ALT_HH
participants (1)
-
Thierry Geraud