URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2008-04-25 Matthieu Garrigues <garrigues(a)lrde.epita.fr>
Add delta points array and use it in fllt.
* mln/core/dp_array.hh: New. Array for delta points
* sandbox/garrigues/fllt/fllt_simple.cc: Use dp_array for c6
neighborhood. Start a test with interpixel browsing.
---
mln/core/dp_array.hh | 256 ++++++++++++++++++++++++++++++++++
sandbox/garrigues/fllt/fllt_simple.cc | 222 ++++++++++++++++++++++-------
2 files changed, 426 insertions(+), 52 deletions(-)
Index: trunk/milena/mln/core/dp_array.hh
===================================================================
--- trunk/milena/mln/core/dp_array.hh (revision 0)
+++ trunk/milena/mln/core/dp_array.hh (revision 1894)
@@ -0,0 +1,256 @@
+// 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_CORE_DP_ARRAY_HH
+# define MLN_CORE_DP_ARRAY_HH
+
+/*! \file mln/core/dp_array.hh
+ *
+ * \brief Definition of a point set class based on std::vector.
+ */
+
+# include <vector>
+
+# include <mln/core/internal/point_set_base.hh>
+# include <mln/accu/bbox.hh>
+
+
+namespace mln
+{
+
+ // Fwd decls.
+ template <typename D> struct dp_array_fwd_piter_;
+ template <typename D> struct dp_array_bkd_piter_;
+
+
+ /*! \brief Point set class based on std::vector.
+ *
+ * This is a multi-set of points.
+ *
+ * \warning We have some troubles with point set comparison based on
+ * a call to npoints(). FIXME: Explain!
+ *
+ * \todo Make it work with P being a Point_Site.
+ */
+ template <typename D>
+ class dp_array : public internal::dpoints_base_< D, dp_array<D> >
+ {
+ public:
+
+ /// Dpoint associated type.
+ typedef D dpoint;
+
+ /// Point associated type.
+ typedef mln_point(D) point;
+
+ /*! \brief Point_Iterator type to browse the points of a generic
+ * neighborhood w.r.t. the ordering of delta-points.
+ */
+ typedef dpoints_fwd_piter<D> fwd_niter;
+
+ /*! \brief Point_Iterator type to browse the points of a generic
+ * neighborhood w.r.t. the reverse ordering of delta-points.
+ */
+ typedef dpoints_bkd_piter<D> bkd_niter;
+
+ /// Constructor.
+ dp_array();
+
+ /// Constructor from a vector \p vect.
+ dp_array(const std::vector<D>& vect);
+
+ /// Reserve \p n cells.
+ void reserve(std::size_t n);
+
+ /// Test is \p p belongs to this point set.
+ bool has(const D& dp) const;
+
+ /// Give the number of dpoints.
+ std::size_t ndpoints() const;
+
+ /// Give the exact bounding box.
+ const box_<point>& bbox() const;
+
+ /// Append a point \p p.
+ dp_array<D>& append(const D& dp);
+
+ /// Append an array \p other of points.
+ dp_array<D>& append(const dp_array<D>& other);
+
+ /// Clear this set.
+ void clear();
+
+ /// Return the corresponding std::vector of points.
+ const std::vector<D>& vect() const;
+
+ /// Return the \p i-th point.
+ const D& operator[](unsigned i) const;
+
+ /// Hook to data.
+ std::vector<D>& hook_();
+
+ protected:
+
+ std::vector<D> vect_;
+ mutable accu::bbox<dpoint> bb_;
+ mutable bool bb_needs_update_;
+
+ void update_bb_() const;
+ // FIXME: Add invariant bb_.is_valid() <=> npoints() != 0
+ };
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename D>
+ inline
+ dp_array<D>::dp_array()
+ {
+ bb_needs_update_ = false;
+ }
+
+ template <typename D>
+ inline
+ dp_array<D>::dp_array(const std::vector<D>& vect)
+ : vect_(vect)
+ {
+ bb_needs_update_ = true;
+ }
+
+ template <typename D>
+ inline
+ void
+ dp_array<D>::reserve(std::size_t n)
+ {
+ vect_.reserve(n);
+ }
+
+ template <typename D>
+ inline
+ std::vector<D>&
+ dp_array<D>::hook_()
+ {
+ return vect_;
+ }
+
+ template <typename D>
+ inline
+ void
+ dp_array<D>::update_bb_() const
+ {
+ bb_.init();
+ for (unsigned i = 0; i < vect_.size(); ++i)
+ bb_.take(vect_[i]);
+ bb_needs_update_ = false;
+ }
+
+ template <typename D>
+ inline
+ bool
+ dp_array<D>::has(const D& dp) const
+ {
+ for (unsigned i = 0; i < vect_.size(); ++i)
+ if (vect_[i] == dp)
+ return true;
+ return false;
+ }
+
+ template <typename D>
+ inline
+ std::size_t
+ dp_array<D>::ndpoints() const
+ {
+ return vect_.size();
+ }
+
+ template <typename D>
+ inline
+ const box_<mln_point(D)>&
+ dp_array<D>::bbox() const
+ {
+ mln_precondition(ndpoints() != 0);
+ if (bb_needs_update_)
+ update_bb_();
+ return bb_.to_result();
+ }
+
+ template <typename D>
+ inline
+ dp_array<D>&
+ dp_array<D>::append(const D& dp)
+ {
+ vect_.push_back(dp);
+ if (! bb_needs_update_)
+ bb_needs_update_ = true;
+ return *this;
+ }
+
+ template <typename D>
+ inline
+ dp_array<D>&
+ dp_array<D>::append(const dp_array<D>& other)
+ {
+ vect_.insert(vect_.end(),
+ other.vect().begin(), other.vect().end());
+ if (! bb_needs_update_)
+ bb_needs_update_ = true;
+ return *this;
+ }
+
+ template <typename D>
+ inline
+ void
+ dp_array<D>::clear()
+ {
+ bb_.init();
+ vect_.clear();
+ bb_needs_update_ = false;
+ }
+
+ template <typename D>
+ inline
+ const std::vector<D>&
+ dp_array<D>::vect() const
+ {
+ return vect_;
+ }
+
+ template <typename D>
+ inline
+ const D&
+ dp_array<D>::operator[](unsigned i) const
+ {
+ mln_precondition(i < ndpoints());
+ return vect_[i];
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+#endif // ! MLN_CORE_DP_ARRAY_HH
Index: trunk/milena/sandbox/garrigues/fllt/fllt_simple.cc
===================================================================
--- trunk/milena/sandbox/garrigues/fllt/fllt_simple.cc (revision 1893)
+++ trunk/milena/sandbox/garrigues/fllt/fllt_simple.cc (revision 1894)
@@ -35,6 +35,11 @@
#include <mln/core/p_array.hh>
#include <mln/core/clone.hh>
+#include <mln/core/cast_image.hh>
+#include <mln/core/p_queue_fast.hh>
+
+#include <mln/core/dp_array.hh>
+
#include <mln/value/int_u8.hh>
#include <mln/io/pgm/load.hh>
@@ -51,8 +56,6 @@
#include <mln/util/tree_to_image.hh>
#include <mln/util/branch_iter_ind.hh>
-#include <mln/core/cast_image.hh>
-#include <mln/core/p_queue_fast.hh>
namespace mln
{
@@ -142,6 +145,146 @@
};
+ struct c6_neighb
+ {
+ // C6 neigboohood.
+ //static std::vector<dpoint2d> nbhs[2];
+ static dp_array<dpoint2d> nbhs[2];
+
+ static inline const dp_array<dpoint2d>& get(point2d p)
+ {
+ static bool toto = false;
+
+ if (!toto)
+ {
+ toto = true;
+ c6_neighb::nbhs[0].append(make::dpoint2d(-1,-1));
+ c6_neighb::nbhs[0].append(make::dpoint2d(-1,0));
+ c6_neighb::nbhs[0].append(make::dpoint2d(-1,1));
+ c6_neighb::nbhs[0].append(make::dpoint2d(0,1));
+ c6_neighb::nbhs[0].append(make::dpoint2d(1,0));
+ c6_neighb::nbhs[0].append(make::dpoint2d(0,-1));
+
+ c6_neighb::nbhs[1].append(make::dpoint2d(-1,0));
+ c6_neighb::nbhs[1].append(make::dpoint2d(0,1));
+ c6_neighb::nbhs[1].append(make::dpoint2d(1,1));
+ c6_neighb::nbhs[1].append(make::dpoint2d(1,0));
+ c6_neighb::nbhs[1].append(make::dpoint2d(1,-1));
+ c6_neighb::nbhs[1].append(make::dpoint2d(0,-1));
+ }
+
+ return nbhs[abs(p[1] % 2)];
+ }
+ };
+ dp_array<dpoint2d> c6_neighb::nbhs[2];
+
+
+ struct c6_interpixel
+ {
+ c6_interpixel() {}
+
+ c6_interpixel(point2d pt1, point2d pt2,
+ unsigned i1, unsigned i2)
+ : pt1(pt1), pt2(pt2),
+ i1(i1), i2(i2)
+ {
+ mln_assertion(pt1 + c6_neighb::get(pt1)[i1] == pt2);
+ mln_assertion(pt2 + c6_neighb::get(pt2)[i2] == pt1);
+ }
+
+ bool is_valid()
+ {
+ return (pt1 + c6_neighb::get(pt1)[i1] == pt2) &&
+ (pt2 + c6_neighb::get(pt2)[i2] == pt1);
+ }
+
+ point2d pt1, pt2;
+ unsigned i1, i2;
+ };
+
+ template <typename I>
+ inline bool is_level_line_in_ip(const Image<I>& ima,
+ const c6_interpixel& ip,
+ const mln_value(I)& v)
+ {
+ mln_value(I) v1, v2;
+ v1 = ima(ip.pt1);
+ v2 = ima(ip.pt2);
+
+ return v1 != v2 && ((v1 >= v && v2 <= v) || (v1 <= v
&& v2 >= v));
+ }
+
+ class c6_interpixel_niter
+ {
+ public:
+ c6_interpixel_niter(const c6_interpixel& ip)
+ : ip_ref_(ip)
+ {
+ }
+
+ bool is_valid() const
+ {
+ i_ >= 4;
+ }
+
+ void invalidate()
+ {
+ i_ = 4;
+ }
+
+ void start()
+ {
+ i_ = 0;
+ ip_.pt1 = ip_ref_.pt1 + c6_neighb::get(ip_ref_.pt1)[ip_ref_.i1 + 1];
+ ip_.pt2 = ip_ref_.pt2;
+ ip_.i1 = ip_ref_.i1 + 1;
+ ip_.i2 = ip_ref_.i2 - 1;
+ mln_assertion(ip_.is_valid());
+ }
+
+ void next_()
+ {
+ mln_assertion(is_valid() && i_ > 0);
+ i_++;
+ switch (i_)
+ {
+ case 1:
+ ip_.pt1 = ip_ref_.pt1 + c6_neighb::get(ip_ref_.pt1)[ip_ref_.i1 - 1];
+ mln_assertion(ip_.pt2 == ip_ref_.pt2);
+ ip_.i1 = ip_ref_.i1 - 1;
+ ip_.i2 = ip_ref_.i2 + 1;
+ break;
+ case 2:
+ ip_.pt1 = ip_ref_.pt1;
+ ip_.pt2 = ip_ref_.pt2 + c6_neighb::get(ip_ref_.pt2)[ip_.i2 + 1];
+ ip_.i1 = ip_ref_.i1 - 1;
+ ip_.i2 = ip_ref_.i2 + 1;
+ break;
+ case 3:
+ mln_assertion(ip_.pt1 == ip_ref_.pt1);
+ ip_.pt1 = ip_ref_.pt2 + c6_neighb::get(ip_ref_.pt2)[ip_.i2 - 1];
+ ip_.i1 = ip_ref_.i1 + 1;
+ ip_.i2 = ip_ref_.i2 - 1;
+ break;
+ }
+ mln_assertion(ip_.is_valid());
+ }
+
+ private:
+ unsigned i_;
+ c6_interpixel ip_;
+ const c6_interpixel& ip_ref_;
+ };
+
+ struct c6_niter : public dpoints_fwd_piter<dpoint2d>
+ {
+ typedef dpoints_fwd_piter<dpoint2d> super;
+
+ c6_niter(const point2d& p)
+ : super(c6_neighb::get(p), p)
+ {}
+ };
+
template <typename P, typename V>
void add_npoints_to(fllt_node(P, V)* node, unsigned npoints)
{
@@ -152,7 +295,6 @@
add_npoints_to(node->parent(), npoints);
}
-
template <typename R>
struct map_cell
{
@@ -172,8 +314,6 @@
}
};
-
-
template <typename P, typename V>
void
draw_tree(const image2d<V>& ima,
@@ -196,7 +336,6 @@
}
}
-
template <typename P, typename V>
void
visualize_bounds(image2d<value::int_u8>& output,
@@ -246,7 +385,6 @@
N = tmp;
}
-
template <typename N_t>
void clear_N(N_t& N)
{
@@ -255,7 +393,7 @@
}
template <typename I, typename CC>
- void erase_exterior_border(I& map, const box2d& bbox, const CC&
current_cc, const std::vector<dpoint2d> nbh[])
+ void erase_exterior_border(I& map, const box2d& bbox, const CC&
current_cc)
{
typedef const std::vector<dpoint2d> arr_dp_t;
typedef std::vector<dpoint2d>::const_iterator arr_dp_t_it;
@@ -276,21 +414,17 @@
{
mln_point(I) a = qu.pop_front();
//map(a).border_of_hole_of = 0;
- arr_dp_t* n_dp = &nbh[abs(a[1] % 2 > 0)];
-// unsigned i = 0;
- for(arr_dp_t_it x = n_dp->begin(); x != n_dp->end(); x++)
- {
- mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x);
+
+ c6_niter n(a);
+ for_all(n)
+ {
if(!map.has(n))
continue;
if (map(n).border_of_hole_of == current_cc &&
map(n).belongs_to != current_cc)
{
-// i++;
-// std::cout << i << std::endl;
-// mln_assertion(i <= 2);
map(n).restore_border();
qu.push(n);
break;
@@ -310,22 +444,6 @@
typedef fllt_node(mln_point(I), mln_value(I)) node_type;
typedef fllt_tree(mln_point(I), mln_value(I)) tree_type;
- // C6 neigboohood.
- arr_dp_t neighb_c6[2];
- neighb_c6[0].push_back(make::dpoint2d(-1,-1));
- neighb_c6[0].push_back(make::dpoint2d(-1,0));
- neighb_c6[0].push_back(make::dpoint2d(-1,1));
- neighb_c6[0].push_back(make::dpoint2d(0,1));
- neighb_c6[0].push_back(make::dpoint2d(1,0));
- neighb_c6[0].push_back(make::dpoint2d(0,-1));
-
- neighb_c6[1].push_back(make::dpoint2d(-1,0));
- neighb_c6[1].push_back(make::dpoint2d(0,1));
- neighb_c6[1].push_back(make::dpoint2d(1,1));
- neighb_c6[1].push_back(make::dpoint2d(1,0));
- neighb_c6[1].push_back(make::dpoint2d(1,-1));
- neighb_c6[1].push_back(make::dpoint2d(0,-1));
-
// Variables.
image2d<map_cell<node_type> > map(input.domain().to_larger(1));
I u = mln::clone(input);
@@ -454,10 +572,10 @@
#endif
for_all(a)
{
- arr_dp_t* nbh = &neighb_c6[a[1] % 2];
- for(arr_dp_t_it x = nbh->begin(); x != nbh->end(); x++)
+
+ c6_niter n(a);
+ for_all(n)
{
- mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x);
if (is(n) == in_O)
{
if (!current_parent)
@@ -500,7 +618,7 @@
add_npoints_to(current_parent, current_cc->elt().npoints);
// Was : current_parent->elt().npoints += current_cc->elt().npoints;
current_cc->set_parent(current_parent);
- erase_exterior_border(map, N_box, current_cc, neighb_c6);
+ erase_exterior_border(map, N_box, current_cc);
goto step_1;
}
else
@@ -537,9 +655,9 @@
typedef fllt_node(mln_point_(I), mln_value_(I)) node_type;
typedef fllt_tree(mln_point_(I), mln_value_(I)) tree_type;
-// image2d<int_u8> ima;
-// //io::pgm::load(ima, "../../../img/lena.pgm");
-// io::pgm::load(ima, "../tapis.pgm");
+ image2d<int_u8> ima;
+ //io::pgm::load(ima, "../../../img/lena.pgm");
+ io::pgm::load(ima, "../tapis.pgm");
// int_u8 vs[9][9] = {
@@ -568,15 +686,15 @@
// {100, 200, 255, 200, 100},
// {100, 100, 100, 100, 100} };
- int vs[9][9] = { {2,2,2,2,2,2,2,2,2},
- {2,2,2,2,2,2,2,2,2},
- {2,1,1,1,1,1,1,1,2},
- {2,1,2,2,1,0,0,1,2},
- {2,1,2,2,1,0,0,1,2},
- {2,1,2,2,1,0,0,1,2},
- {2,1,1,1,1,1,1,1,2},
- {2,1,1,1,1,1,1,1,2},
- {2,2,2,2,2,2,2,2,2} };
+// int vs[9][9] = { {2,2,2,2,2,2,2,2,2},
+// {2,2,2,2,2,2,2,2,2},
+// {2,1,1,1,1,1,1,1,2},
+// {2,1,2,2,1,0,0,1,2},
+// {2,1,2,2,1,0,0,1,2},
+// {2,1,2,2,1,0,0,1,2},
+// {2,1,1,1,1,1,1,1,2},
+// {2,1,1,1,1,1,1,1,2},
+// {2,2,2,2,2,2,2,2,2} };
// int vs[7[7] = { {101, 101, 101, 191, 204, 255, 191},
// {101, 101, 191, 204, 204, 204, 204},
@@ -589,14 +707,14 @@
// int vs[2][1] = { {121}, {101} };
- image2d<int> ima_(make::image2d(vs));
- image2d<int_u8> ima(ima_.domain());
- level::fill(ima, ima_);
+// image2d<int> ima_(make::image2d(vs));
+// image2d<int_u8> ima(ima_.domain());
+// level::fill(ima, ima_);
tree_type tree = my::fllt(ima);
- draw_tree(ima, tree);
+// draw_tree(ima, tree);