Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
October 2008
- 14 participants
- 373 discussions
From: Maxime van Noppen <yabo(a)lrde.epita.fr>
To: olena-patches(a)lrde.epita.fr
Subject: r2674: Enhance the build-system
URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-24 Maxime van Noppen <yabo(a)lrde.epita.fr>
Enhance the build-system.
* Makefile: Make a nice and usefull Makefile.
---
Makefile | 48 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 5 deletions(-)
Index: branches/cleanup-2008/milena/sandbox/classif/Makefile
===================================================================
--- branches/cleanup-2008/milena/sandbox/classif/Makefile (revision 2673)
+++ branches/cleanup-2008/milena/sandbox/classif/Makefile (revision 2674)
@@ -1,7 +1,45 @@
-CCFLAGS=-I../.. -O1 -DNDEBUG
+INCLUDES=-I../..
-all:
- g++ iccvg04.cc $(CCFLAGS)
+SRC=iccvg04.cc
+TARGET=iccvg
-debug:
- g++ iccvg04.cc -I../../ -O0 -g3 -ggdb3
+TARGET_DBG=iccvg_dbg
+
+IMG?=../../img/lena.ppm
+DIV?=8
+LAMBDA?=10
+
+LOG=> stdout.log 2> stderr.log
+
+all: $(TARGET)
+
+$(TARGET): $(SRC)
+ g++ $(INCLUDES) -O1 -DNDEBUG $(SRC) -o $(TARGET)
+
+debug: $(TARGET_DBG)
+
+iccvg_dbg: $(SRC)
+ g++ $(INCLUDES) -O0 -g3 -ggdb3 $(SRC) -o $(TARGET_DBG)
+
+.PHONY:clean check check-debug valgrind
+
+clean:
+ rm -f $(TARGET)
+ rm -f $(TARGET_DBG)
+
+check-debug: $(TARGET_DBG)
+ ./iccvg_dbg $(IMG) $(DIV) $(LAMBDA) $(LOG)
+ cat stdout.log
+ display out.ppm &
+
+check: $(TARGET)
+ ./iccvg $(IMG) $(DIV) $(LAMBDA) $(LOG)
+ cat stdout.log
+ display out.ppm &
+
+valgrind:
+ valgrind --log-file=valgrind.log ./iccvg_dbg ../../img/lena.ppm $(DIV) $(LAMBDA) $(LOG)
+
+gdb: $(TARGET_DBG)
+ echo "run ../../img/lena.ppm $(DIV) $(LAMBDA)" > gdb.cmd
+ gdb $(TARGET_DBG) -x gdb.cmd
1
0
cleanup-2008 2673: Add bijective functors, 2-way functors and meta-fun.
by Alexandre Abraham 24 Oct '08
by Alexandre Abraham 24 Oct '08
24 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
Index: ChangeLog
from Alexandre Abraham <abraham(a)lrde.epita.fr>
Add bijective functors, 2-way functors and meta-fun.
* abraham/tests/morpho/test_component_tree.cc: Remove
This test was outdated.
* abraham/tests/morpho/test_watershed.cc:
Clean.
* abraham/tests/morpho/test_watershed_topo.cc:
Clean.
* abraham/tests/fun/meta: New.
* abraham/tests/fun/meta/red.cc: New
(mln::meta::red) : meta function to access red in rgb.
* abraham/tests/core/image/thru_norm.cc: New
test for norm functor.
* abraham/tests/core/image/thru_v2v.cc: New
test for abs functor.
* abraham/tests/core/image/thru.cc: Remove.
* abraham/tests/core/image/thru_const.cc: New
test of writing in a const image.
* abraham/tests/core/image/thru_v2w2v.cc: New
test for cosinus functor.
* abraham/tests/core/concept: New.
* abraham/tests/core/concept/test.cc: New.
* abraham/mln/morpho/najman_wst.hh: New
M-W watershed.
* abraham/mln/morpho/basic_najman.hh:
Obsolete, will eventually be removed.
* abraham/mln/morpho/topo_wst.hh: New
1 pass topological watershed.
* abraham/mln/core/image/thru.hh:
(mln::thru): see an image throught a function.
* abraham/mln/core/image/shell.hh: New
(mln::shell): value shell.
* abraham/mln/core/concept/function.hh:
Add bijective and 2-way function.
* abraham/mln/core/concept/meta_fun.hh: New
Add concept for meta function.
* abraham/mln/fun/meta: New.
* abraham/mln/fun/meta/red.hh: New
red fun object.
* abraham/mln/fun/v2w_w2v/norm.hh:
2-way functor.
* vigouroux/tests.cc: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_cmy.hh: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_xyz.hh: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_hsi.hh: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_yuv.hh: Rename image_if_value > image_if.
abraham/mln/core/concept/function.hh | 2
abraham/mln/core/concept/meta_fun.hh | 83 ++
abraham/mln/core/image/shell.hh | 118 ++++
abraham/mln/core/image/thru.hh | 40 -
abraham/mln/fun/meta/red.hh | 45 +
abraham/mln/fun/v2w_w2v/norm.hh | 4
abraham/mln/morpho/basic_najman.hh | 196 +++---
abraham/mln/morpho/najman_wst.hh | 791 ++++++++++++++++++++++++++++
abraham/mln/morpho/topo_wst.hh | 744 ++++++++++++++++++++++++++
abraham/tests/core/concept/test.cc | 75 ++
abraham/tests/core/image/thru.cc | 56 -
abraham/tests/core/image/thru_const.cc | 64 ++
abraham/tests/core/image/thru_norm.cc | 58 ++
abraham/tests/core/image/thru_v2v.cc | 56 +
abraham/tests/core/image/thru_v2w2v.cc | 64 ++
abraham/tests/fun/meta/red.cc | 60 ++
abraham/tests/morpho/test_component_tree.cc | 230 --------
abraham/tests/morpho/test_watershed.cc | 60 --
abraham/tests/morpho/test_watershed_topo.cc | 8
vigouroux/color/rgb_to_cmy.hh | 8
vigouroux/color/rgb_to_hsi.hh | 2
vigouroux/color/rgb_to_xyz.hh | 14
vigouroux/color/rgb_to_yuv.hh | 8
vigouroux/tests.cc | 6
24 files changed, 2311 insertions(+), 481 deletions(-)
Index: abraham/tests/morpho/test_watershed.cc
--- abraham/tests/morpho/test_watershed.cc (revision 2672)
+++ abraham/tests/morpho/test_watershed.cc (working copy)
@@ -7,7 +7,7 @@
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
-#include <mln/morpho/basic_najman.hh>
+#include <mln/morpho/najman_wst.hh>
#include <string>
#include <iostream>
@@ -22,15 +22,15 @@
// #define TEST
- io::pgm::load(input, "./images/test_watershed.pgm");
+ // io::pgm::load(input, "./images/test_watershed.pgm");
// io::pgm::load(input, "./images/little_test.pgm");
- // io::pgm::load(input, "./images/test_2.pgm");
+ io::pgm::load(input, "./images/test.pgm");
// io::pgm::load(input, "./images/lena_light.pgm");
// io::pgm::load(mverif, "./images/result_m_watershed.pgm");
// io::pgm::load(wverif, "./images/result_topo_watershed.pgm");
- morpho::basic_najman< image2d<int_u8>, neighb2d> n(input, c4());
+ morpho::najman_wst< image2d<int_u8>, neighb2d> n(input, c4());
/*
image2dint::fwd_piter it(input.domain());
@@ -43,60 +43,8 @@
// io::tikz::save(input, "start.tex");
- std::cout << "Building Component tree..." << std::endl;
-
n.go();
- std::cout << "M-Watershed" << std::endl;
-
- n.m_watershed();
-
- io::pgm::save(n.pima, "int.pgm");
-
- // io::tikz::save(n.pima, "step.tex");
-
-#ifdef TEST
-
- bool equal = true;
-
- equal = n.pima == mverif;
-
- if (!equal)
- {
- std::cout << "M-Watershed broken" << std::endl;
- return 1;
- }
- else
- std::cout << "M-Watershed good as chocolate ice cream" << std::endl;
-
-#endif
-
- std::cout << "W-watershed" << std::endl;
-
- n.w_watershed();
- // io::pgm::save(n.pima, "int.pgm");
- // std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
- // n.w_watershed();
-
- // for_all(it)
- // n.pima(it) = n.pima(it) * 17;
-
-#ifdef TEST
- equal = n.pima == wverif;
-
- if (!equal)
- {
- std::cout << "W-Watershed broken" << std::endl;
- return 1;
- }
- else
- std::cout << "W-Watershed good as chocolate ice cream" << std::endl;
-#endif
-
- // io::tikz::save(n.pima, "end.tex");
-
- // n.image_output(n.pima);
-
io::pgm::save(n.pima, "out.pgm");
return 0;
Index: abraham/tests/morpho/test_watershed_topo.cc
--- abraham/tests/morpho/test_watershed_topo.cc (revision 2672)
+++ abraham/tests/morpho/test_watershed_topo.cc (working copy)
@@ -9,7 +9,7 @@
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
-#include <mln/morpho/basic_najman.hh>
+#include <mln/morpho/topo_wst.hh>
#include <string>
#include <iostream>
@@ -32,7 +32,7 @@
// io::pgm::load(input, "./images/test_watershed.pgm");
// io::pgm::load(input, "./images/little_test.pgm");
- io::pgm::load(input, "./images/test_4.pgm");
+ io::pgm::load(input, "./images/test.pgm");
// io::pgm::load(input, "../../img/dots.pgm");
//io::pgm::load(input, "./images/+irm6.pgm");
@@ -40,7 +40,7 @@
// io::pgm::load(mverif, "./images/result_m_watershed.pgm");
// io::pgm::load(wverif, "./images/result_topo_watershed.pgm");
- morpho::basic_najman< image2d<int_u8>, neighb2d> n(input, c4());
+ morpho::topo_wst< image2d<int_u8>, neighb2d> n(input, c4());
/*
image2dint::fwd_piter it(input.domain());
@@ -53,7 +53,7 @@
// io::tikz::save(input, "start.tex");
- n.gotopo();
+ n.go();
io::pgm::save(n.pima, "out.pgm");
Index: abraham/tests/fun/meta/red.cc
--- abraham/tests/fun/meta/red.cc (revision 0)
+++ abraham/tests/fun/meta/red.cc (revision 0)
@@ -0,0 +1,60 @@
+#include <mln/fun/meta/red.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/thru.hh>
+
+namespace mln
+{
+
+ template <class T>
+ struct rgb
+ {
+ T red() const { return r; }
+ T& red() { return r; }
+ T r;
+ };
+
+ template <class T>
+ struct function< meta::red, rgb<T> > : public Function_v2w_w2v<function< meta::red, rgb<T> > >
+ {
+ typedef T result;
+ T read(const rgb<T>& c)
+ {
+ std::cout << "read red rgb<T>" << std::endl;
+ return c.red();
+ }
+
+ typedef T& lresult;
+ T& write(rgb<T>& c)
+ {
+ std::cout << "write red rgb<T>" << std::endl;
+ return c.red();
+ }
+ };
+}
+
+int main ()
+{
+ typedef mln::rgb<int> C;
+ mln::image2d<C> i(3, 2, 0);
+ C c;
+ c.r = 51;
+ i(mln::point2d(0,0)) = c;
+ c.r = 23;
+ i(mln::point2d(0,1)) = c;
+ c.r = 43;
+ i(mln::point2d(1,0)) = c;
+ c.r = 0;
+ i(mln::point2d(1,1)) = c;
+ c.r = 65;
+ i(mln::point2d(2,0)) = c;
+ c.r = 1;
+ i(mln::point2d(2,1)) = c;
+
+ mln::thru<mln::meta::red, mln::image2d<C> > out(i);
+
+ for_all (p)
+ std::cout << out(p) << std::endl;
+
+
+}
+
Index: abraham/tests/core/image/thru_norm.cc
--- abraham/tests/core/image/thru_norm.cc (revision 0)
+++ abraham/tests/core/image/thru_norm.cc (revision 0)
@@ -0,0 +1,58 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2w_w2v/norm.hh>
+# include <mln/algebra/vec.hh>
+# include <mln/level/fill.hh>
+# include <mln/core/image/violent_cast_image.hh>
+
+
+int main ()
+{
+
+ using namespace mln;
+ typedef image2d<algebra::vec<2, double> > I;
+
+ I ima(3, 2, 0);
+
+ ima(point2d(0,0)).set (1, 1);
+ ima(point2d(0,1)).set (1, 3);
+ ima(point2d(1,0)).set (4, 4);
+ ima(point2d(1,1)).set (-1, 3);
+ ima(point2d(2,0)).set (23, 23);
+ ima(point2d(2,1)).set (3, 1);
+
+ thru<mln::fun::v2w_w2v::l1_norm<algebra::vec<2, double>, double>, I > out(ima);
+ level::fill(out, 1);
+
+ box_fwd_piter_<point2d> p(ima.domain());
+
+ for_all (p)
+ std::cout << ima(p) << std::endl;
+}
Index: abraham/tests/core/image/thru_v2v.cc
--- abraham/tests/core/image/thru_v2v.cc (revision 0)
+++ abraham/tests/core/image/thru_v2v.cc (revision 0)
@@ -0,0 +1,56 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2v/abs.hh>
+
+int main ()
+{
+
+ using namespace mln;
+
+ typedef image2d<int> I;
+
+ int vs[6][5] = {
+
+ { -3, -3, -4, -4, -4 },
+ { -2, -1, -1, -1, -1 },
+ { -1, -4, -4, -4, -1 },
+ { -1, -4, -3, -4, -1 },
+ { -1, -4, -5, -3, -1 },
+ { -1, -1, -1, -1, -1 }
+
+ };
+
+ image2d<int> ima(make::image2d(vs));
+ thru<mln::fun::v2v::abs<int>, image2d<int> > out(ima);
+
+ box_fwd_piter_<point2d> p(ima.domain());
+ for_all (p)
+ mln_assertion (out(p) >= 0);
+}
Index: abraham/tests/core/image/thru_const.cc
--- abraham/tests/core/image/thru_const.cc (revision 0)
+++ abraham/tests/core/image/thru_const.cc (revision 0)
@@ -0,0 +1,64 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2w2v/cos.hh>
+
+int main ()
+{
+
+ using namespace mln;
+
+ typedef const image2d<double> I;
+
+ double vs[6][5] = {
+
+ { 12, -3, 8, -4, 6 },
+ { -2, 22, -1, 45, -1 },
+ { -1, -4, -4, -4, -1 },
+ { -1, -4, -3, -4, -1 },
+ { -1, -4, -5, -3, -1 },
+ { -1, -1, -1, -1, -1 }
+
+ };
+
+ I ima(make::image2d(vs));
+ thru<mln::fun::v2w2v::cos<double>, I > out(ima);
+
+ double i = 0;
+
+ box_fwd_piter_<point2d> p(ima.domain());
+ for_all (p)
+ {
+ out(p) = i;
+ i += 1./40.;
+ }
+
+ for_all (p)
+ std::cout << out(p) << std::endl;
+}
Index: abraham/tests/core/image/thru_v2w2v.cc
--- abraham/tests/core/image/thru_v2w2v.cc (revision 0)
+++ abraham/tests/core/image/thru_v2w2v.cc (revision 0)
@@ -0,0 +1,64 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2w2v/cos.hh>
+
+int main ()
+{
+
+ using namespace mln;
+
+ typedef image2d<double> I;
+
+ double vs[6][5] = {
+
+ { 12, -3, 8, -4, 6 },
+ { -2, 22, -1, 45, -1 },
+ { -1, -4, -4, -4, -1 },
+ { -1, -4, -3, -4, -1 },
+ { -1, -4, -5, -3, -1 },
+ { -1, -1, -1, -1, -1 }
+
+ };
+
+ image2d<double> ima(make::image2d(vs));
+ thru<mln::fun::v2w2v::cos<double>, image2d<double> > out(ima);
+
+ double i = 0;
+
+ box_fwd_piter_<point2d> p(ima.domain());
+ for_all (p)
+ {
+ out(p) = i;
+ i += 1./40.;
+ }
+
+ for_all (p)
+ std::cout << out(p) << std::endl;
+}
Index: abraham/tests/core/concept/test.cc
--- abraham/tests/core/concept/test.cc (revision 0)
+++ abraham/tests/core/concept/test.cc (revision 0)
@@ -0,0 +1,75 @@
+#include <iostream>
+#include <mln/core/concept/meta_fun.hh>
+
+using namespace mln;
+
+meta::red red; // fun-obj
+
+
+
+template <class T>
+struct rgb
+{
+ T red() const { return r; }
+ T& red() { return r; }
+ T r;
+};
+
+
+
+template <class T>
+struct fun< meta::red, rgb<T> > : Function_v2v< fun< meta::red, rgb<T> > >
+{
+ typedef T result;
+ T read(const rgb<T>& c)
+ {
+ std::cout << "read red rgb<T>" << std::endl;
+ return c.red();
+ }
+
+ typedef T& lresult;
+ T& write(rgb<T>& c)
+ {
+ std::cout << "write red rgb<T>" << std::endl;
+ return c.red();
+ }
+};
+
+
+/*
+
+ morpher apply(M m, I ima)
+ {
+ M et value(I) -> F -> nature
+ }
+
+ */
+
+
+
+int main()
+{
+ typedef rgb<int> C;
+ C c;
+ c.r = 51;
+
+ int r = red(c);
+ std::cout << r << std::endl;
+
+
+ // norm(v) = 1;
+
+
+ // norm( ima(p) ) = n;
+
+ // norm( v& ) = n;
+ // v = n * v / norm(v);
+
+ // norm( v& ) = 1;
+
+
+
+ // ima' = apply(norm, ima)
+ // ima'(p) = 1;
+
+}
Index: abraham/mln/morpho/najman_wst.hh
--- abraham/mln/morpho/najman_wst.hh (revision 0)
+++ abraham/mln/morpho/najman_wst.hh (revision 0)
@@ -0,0 +1,791 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// 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_MORPHO_NAJMAN_WST_HH
+# define MLN_MORPHO_NAJMAN_WST_HH
+
+
+
+#include <mln/level/sort_psites.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/site_set/p_set.hh>
+#include <mln/estim/min_max.hh>
+#include <mln/math/sqr.hh>
+#include <mln/util/greater_psite.hh>
+#include <mln/util/ord.hh>
+
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
+
+#include <queue>
+#include <vector>
+#include <map>
+
+namespace mln
+{
+ namespace morpho
+ {
+
+ template <class I, class N>
+ struct najman_wst
+ {
+
+ // Typedefs
+ // --------
+ typedef mln_site(I) site;
+
+ // Component tree management
+ // -------------------------
+ private:
+ struct node {
+ mln_value(I) level;
+ int area;
+ int highest;
+ typedef mln_site(I) site;
+ // Can't modify the sites in a p_array
+ // p_array<mln_site(I)> children;
+ std::vector<site> children;
+
+ void addChildren(const node& n)
+ {
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for (it.start();
+ // it.is_valid();
+ // it.next())
+ // children.append(it.to_site());
+ for (unsigned i=0; i < n.children.size(); ++i)
+ children.push_back(n.children[i]);
+ }
+
+ void addChild(const site p)
+ {
+ // children.append(n);
+ children.push_back(p);
+ }
+ }; // struct node
+
+ const mln_exact(N)& nbh;
+ mln_ch_value(I, site) Par_node;
+ mln_ch_value(I, site) Par_tree;
+
+ mln_ch_value(I, int) Rnk_tree;
+ mln_ch_value(I, int) Rnk_node;
+ mln_ch_value(I, site) subtreeRoot;
+ mln_ch_value(I, node) nodes;
+ site Root;
+
+ void MakeSet_tree(site x);
+ void MakeSet_node(site x);
+ site Find_tree(site x);
+ void swap(site& x, site& y);
+ site Find_node(site x);
+ void BuildComponentTree();
+ site MergeNode(site& node1, site& node2);
+ site Link_tree(site x, site y);
+ site Link_node(site x, site y);
+ node MakeNode(int level);
+
+
+ // Watershed algorithm
+ // -------------------
+
+ private:
+ mln_ch_value(I, bool) isproc;
+
+ // Ctor
+ public:
+ najman_wst(const Image<I>& i,
+ const Neighborhood<N>& n);
+
+
+ // Result
+ public:
+ mln_exact(I) pima;
+
+ public:
+ void go();
+
+ private:
+ site min (p_set<site>& components);
+ site max (p_set<site>& components);
+ bool highest_fork (p_set<site>& components);
+ bool highest_fork (p_set<site>& components, site &r);
+ bool m_destructible(site p);
+ bool w_destructible(site p);
+ bool m_destructible(site p, site &r);
+ bool w_destructible(site p, site &r);
+ void m_watershed ();
+ void w_watershed ();
+
+ // Optimized LCA Algorithm
+ private:
+ int *euler;
+ int *depth;
+ int ctree_size;
+ std::map<site, int, mln::util::ord<site> > pos;
+ site *repr;
+
+ int *minim;
+ int **Minim;
+
+ void compute_ctree_size (site p);
+ void build_euler_tour_rec(site p, int &position, int d);
+ void build_euler_tour();
+ void build_minim ();
+ site lca (site a, site b);
+ void removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node);
+ void compressTree();
+ }; // struct najman_wst
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // Ctor
+ template <class I, class N>
+ najman_wst<I, N>::najman_wst(const Image<I>& i,
+ const Neighborhood<N>& n)
+ : pima(exact(i)),
+ nbh(exact(n)),
+ Par_node(exact(i).domain(), exact(i).border()),
+ Par_tree(exact(i).domain(), exact(i).border()),
+ Rnk_tree(exact(i).domain(), exact(i).border()),
+ Rnk_node(exact(i).domain(), exact(i).border()),
+ subtreeRoot(exact(i).domain(), exact(i).border()),
+ nodes(exact(i).domain(), exact(i).border()),
+ isproc(exact(i).domain(), exact(i).border())
+ {
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::MakeSet_tree(site x)
+ {
+ Par_tree(x) = x;
+ Rnk_tree(x) = 0;
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::MakeSet_node(site x)
+ {
+ Par_node(x) = x;
+ Rnk_node(x) = 0;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Find_tree(site x)
+ {
+ if (Par_tree(x) != x)
+ Par_tree(x) = Find_tree(Par_tree(x));
+ return Par_tree(x);
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::swap(site& x, site& y)
+ {
+ site memo = x;
+ x = y;
+ y = memo;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Find_node(site x)
+ {
+ if (Par_node(x) != x)
+ Par_node(x) = Find_node(Par_node(x));
+ return Par_node(x);
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::go()
+ {
+ BuildComponentTree();
+ compressTree();
+ build_euler_tour();
+ build_minim();
+ m_watershed();
+ w_watershed();
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::BuildComponentTree()
+ {
+ // Init:
+
+ // Sort the sites in increasing order
+ p_array<mln_site(I)> S;
+ S = level::sort_psites_increasing(pima);
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ for (int ip = 0; ip < int(S.nsites()); ++ip)
+ {
+ site p = S[ip];
+ MakeSet_node(p);
+ MakeSet_tree(p);
+ // if (subtreeRoot.hold(p))
+ subtreeRoot(p) = p;
+ // if (nodes.hold(p))
+ nodes(p) = MakeNode(pima(p));
+ }
+
+
+
+ typename p_array<mln_site(I)>::fwd_piter ip(S);
+ for_all(ip)
+ {
+ site p = ip.to_site();
+
+ site curCanonicalElt = Find_tree(p);
+ site curNode = Find_node(subtreeRoot(curCanonicalElt));
+
+ mln_niter(N) q(nbh, ip);
+ for_all(q)
+ if (pima.has(q) and isproc(q) and pima(q) <= pima(p))
+ {
+ site adjCanonicalElt = Find_tree(q);
+ site adjNode = Find_node(subtreeRoot(adjCanonicalElt));
+ if (curNode != adjNode)
+ {
+ if (nodes(curNode).level == nodes(adjNode).level)
+ curNode = MergeNode(adjNode, curNode);
+ else
+ {
+ nodes(curNode).addChild(adjNode);
+ nodes(curNode).area += nodes(adjNode).area;
+ nodes(curNode).highest += nodes(adjNode).highest;
+ }
+ }
+
+ curCanonicalElt = Link_tree(adjCanonicalElt, curCanonicalElt);
+ subtreeRoot(curCanonicalElt) = curNode;
+ }
+ isproc(p) = true;
+ }
+ // Pour garder une map de correspondance site <-> local_root
+ // for (int ip = 0; ip < int(S.size()); ++ip)
+ // {
+ // site p = S[ip];
+ // M(p) = Find_node(p);
+ // }
+
+ mln_piter(I) r(Par_node.domain());
+ for_all(r)
+ Par_node(r) = Find_node(r);
+
+ Root = subtreeRoot(Find_tree(Find_node(site(0, 0))));
+ }
+
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::MergeNode(site& node1, site& node2)
+ {
+ site tmpNode = Link_node(node1, node2);
+ site tmpNode2;
+ if (tmpNode == node2)
+ {
+ nodes(node2).addChildren(nodes(node1));
+ tmpNode2 = node1;
+ }
+ else
+ {
+ nodes(node1).addChildren(nodes(node2));
+ tmpNode2 = node2;
+ }
+ nodes(tmpNode).area += nodes(tmpNode2).area;
+ nodes(tmpNode).highest += nodes(tmpNode2).highest;
+ return tmpNode;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Link_tree(site x, site y)
+ {
+ if (Rnk_tree(x) > Rnk_tree(y))
+ swap(x, y);
+ else
+ if (Rnk_tree(x) == Rnk_tree(y))
+ Rnk_tree(y) += 1;
+ Par_tree(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Link_node(site x, site y)
+ {
+ if (Rnk_node(x) > Rnk_node(y))
+ swap(x, y);
+ else
+ if (Rnk_node(x) == Rnk_node(y))
+ Rnk_node(y) += 1;
+ Par_node(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::node najman_wst<I, N>::MakeNode(int level)
+ {
+ node n;
+ n.level = level;
+ n.area = 1;
+ n.highest = level;
+ return n;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::min (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site min = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) < pima(min))
+ min = it.to_site();
+
+ return min;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::max (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site max = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) > pima(max))
+ max = it.to_site();
+
+ return max;
+ }
+
+
+ template <class I, class N>
+ bool najman_wst<I, N>::highest_fork (p_set<site>& components, site &r)
+ {
+ if (components.nsites() == 0)
+ {
+ std::cerr << "highest fork : empty set" << std::endl;
+ return false;
+ }
+
+ site
+ m = min(components),
+ hfork = m;
+
+ typename p_set<site>::fwd_piter it(components);
+ for_all(it)
+ {
+ // Can't remove the site from the set
+ if (it.to_site() == m)
+ continue;
+
+ site c = lca(hfork, it.to_site());
+ if (c != it.to_site())
+ hfork = c;
+ }
+
+ if (nodes(m).level == nodes(hfork).level)
+ return false;
+
+ r = hfork;
+ return true;
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::w_destructible(site p, site &r)
+ {
+ mln_niter(N) q(nbh, p);
+ p_set<site> v;
+
+ for_all(q)
+ if (pima.has(q) && pima(q) < pima(p))
+ v.insert(Par_node(q));
+
+ if (v.nsites() == 0)
+ return false;
+
+ site hf;
+ bool is_hf = highest_fork(v, hf);
+
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
+
+ if (nodes(hf).level <= pima(p)) {
+ r = hf;
+ return true;
+ }
+ return false;
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::highest_fork (p_set<site>& components) {
+ site i;
+ return highest_fork(components, i);
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::m_destructible(site p) {
+ site i;
+ return m_destructible(p, i);
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::w_destructible(site p) {
+ site i;
+ return w_destructible(p, i);
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::m_destructible(site p, site &r)
+ {
+ mln_niter(N) q(nbh, p);
+ p_set<site> v = p_set<site>();
+
+ for_all(q)
+ if (pima.has(q) && pima(q) < pima(p))
+ v.insert(Par_node(q));
+
+ if (v.nsites() == 0)
+ return false;
+
+ // if (nodes(min(v)).children.nsites() != 0)
+ if (nodes(min(v)).children.size() != 0)
+ return false;
+
+ bool is_hf = highest_fork(v);
+
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
+
+ return false;
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::m_watershed ()
+ {
+ typedef
+ // p_priority_queue<site, mln_value(I) >
+ std::priority_queue<site, std::vector<site>, util::greater_psite<I> >
+ ordered_queue_type;
+
+
+ ordered_queue_type l(util::make_greater_psite(pima));
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ mln_piter(I) it(pima.domain());
+
+ for_all(it)
+ if (m_destructible(it.to_site()))
+ {
+ l.push(it.to_site());
+ isproc(it.to_site()) = true;
+ }
+
+ site p, i;
+ while (!l.empty())
+ {
+ // Extract priority queue
+ p = l.top();
+ l.pop();
+
+ // unmark p
+ isproc(p) = false;
+
+ bool is_m = m_destructible(p, i);
+
+ if (is_m)
+ {
+ pima(p) = nodes(i).level;
+ Par_node(p) = i;
+
+ mln_niter(N) q(nbh, p);
+ for_all(q)
+ if (pima.has(q) && !isproc(q))
+ if (m_destructible(q))
+ {
+ // Add priority queue
+ l.push(q);
+
+ // mark q
+ isproc(q) = true;
+ }
+ }
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::w_watershed ()
+ {
+ mln::p_priority< mln_value(I), p_queue_fast<site> > L;
+
+ mln_value(I) max = level::compute(accu::meta::max(), pima);
+
+ // I K(pima.domain(), pima.border());
+ mln_ch_value(I, unsigned) K(pima.domain(), pima.border());
+ mln_ch_value(I, site) H(pima.domain(), pima.border());
+
+ // For All p of E do
+ mln_piter(I) it(pima.domain());
+ for_all(it)
+ {
+ site p = it.to_site();
+ site i;
+
+ // i <- W-Destructible(p)
+ bool is_w = w_destructible(p, i);
+
+ // If i != infinity then
+ if (is_w)
+ {
+ L.push(max - nodes(i).level, p);
+ K(p) = nodes(i).level;
+ H(p) = i;
+ }
+ }
+
+ while (!L.is_empty())
+ {
+ mln_value(I) k = max - L.highest_priority();
+
+ site p = L.front();
+ L.pop();
+
+ if (K(p) == k)
+ {
+ pima(p) = k;
+ Par_node(p) = H(p);
+
+ mln_niter(N) q(nbh, p);
+ for_all(q)
+ if (pima.has(q) && k < pima(q))
+ {
+ site i;
+ bool is_w = w_destructible(q, i);
+ if (!is_w)
+ K(q) = 10000; // FIXME : supposed to be infinity...
+ else
+ if (K(q) != nodes(i).level)
+ {
+ L.push(max - nodes(i).level, q);
+ K(q) = nodes(i).level;
+ H(q) = i;
+ }
+ }
+ }
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::compute_ctree_size (site p)
+ {
+ ctree_size += 1;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // compute_ctree_size(it.to_site());
+
+ for (unsigned i=0; i < n.children.size(); ++i)
+ compute_ctree_size(n.children[i]);
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::build_euler_tour_rec(site p, int &position, int d)
+ {
+ if (pos.find(p) == pos.end())
+ pos[p] = position;
+
+ repr[position] = p;
+ depth[position] = d;
+ euler[position] = pos[p];
+ ++position;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // {
+ // build_euler_tour_rec(it.to_site(), position, d+1);
+ // depth[position] = d; // Not optimized
+ // euler[position] = pos[p];
+ // repr[position] = p; // Pas necessaire?
+ // ++position;
+ // }
+
+ for(unsigned i=0; i < n.children.size(); ++i)
+ {
+ build_euler_tour_rec(n.children[i], position, d+1);
+ depth[position] = d; // Not optimized
+ euler[position] = pos[p];
+ repr[position] = p; // Pas necessaire?
+ ++position;
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::build_euler_tour ()
+ {
+ ctree_size = 0;
+ compute_ctree_size(Root);
+
+ int size = 2 * ctree_size - 1;
+
+ // FIXME : free this
+ euler = new int[size];
+ depth = new int[size];
+ repr = new site[size];
+
+ int position = 0;
+ build_euler_tour_rec(Root, position, 0);
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::build_minim ()
+ {
+ // compute_tree_size(); // Already done in build_euler_tour
+ int size = 2 * ctree_size - 1;
+ int logn = (int)(ceil(log((double)(size))/log(2.0)));
+ // minim.reserve(size);
+ minim = new int [logn * size]; // FIXME : Think about freeing this
+ Minim = new int* [logn];
+
+ Minim[0] = minim;
+
+ // Init
+ for (int i = 0; i < size - 1; ++i)
+ if (depth[euler[i]] < depth[euler[i+1]]) {
+ Minim[0][i] = i;
+ } else {
+ Minim[0][i] = i+1;
+ }
+
+ // Minim[0][size - 1] = size - 1;
+
+ int k;
+ for (int j = 1; j < logn; j++) {
+ k = 1 << (j - 1);
+ Minim[j] = &minim[j * size];
+ for (int i = 0; i < size; i++) {
+ if ((i + (k << 1)) >= size) {
+ //Minim[j][i] = size - 1;
+ }
+ else {
+ if (depth[euler[Minim[j - 1][i]]] <= depth[euler[Minim[j - 1][i + k]]])
+ Minim[j][i] = Minim[j - 1][i];
+ else
+ Minim[j][i] = Minim[j - 1][i + k];
+ }
+ }
+ }
+
+ } // void build_minim ()
+
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::lca (site a, site b)
+ {
+ int
+ m = pos[a],
+ n = pos[b],
+ k;
+
+ if (m == n)
+ return repr[m];
+
+ if (m > n)
+ {
+ k = n;
+ n = m;
+ m = k;
+ }
+
+ k = (int)(log((double)(n - m))/log(2.));
+
+ if (depth[euler[Minim[k][m]]] < depth[euler[Minim[k][n - (1 << k)]]]) {
+ return repr[euler[Minim[k][m]]];
+ } else {
+ return repr[euler[Minim[k][n - (1 << k)]]];
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node)
+ {
+ node &n = nodes(*p);
+
+ if (n.children.size() == 1) // this node has 1 son, delete it
+ {
+ n.area = -1;
+ newPar_node(*p) = n.children[0];
+ *p = n.children[0];
+ removeOneSonNodes(p, newPar_node);
+ }
+ else // there is more than one son, recursive call
+ {
+ for (unsigned i = 0; i < n.children.size(); ++i)
+ removeOneSonNodes(&(n.children[i]), newPar_node);
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::compressTree()
+ {
+ mln_ch_value(I, site) newPar_node(Par_node.domain(), Par_node.border());
+
+ // Remove the nodes with one son
+ removeOneSonNodes(&Root, newPar_node);
+
+ // Update the references on deleted nodes
+ mln_piter(I) p(Par_node.domain());
+ for_all(p)
+ while (nodes(Par_node(p)).area == -1)
+ Par_node(p) = newPar_node(Par_node(p));
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+
+ }; // namespace morpho
+
+}; // namespace mln
+
+#endif // MLN_MORPHO_NAJMAN_WST_HH
Index: abraham/mln/morpho/basic_najman.hh
--- abraham/mln/morpho/basic_najman.hh (revision 2672)
+++ abraham/mln/morpho/basic_najman.hh (working copy)
@@ -33,8 +33,10 @@
#include <mln/estim/min_max.hh>
#include <mln/math/sqr.hh>
#include <mln/util/greater_psite.hh>
+#include <mln/util/ord.hh>
-#include <mln/core/site_set/p_priority_queue.hh>
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
#include <queue>
#include <vector>
@@ -78,8 +80,8 @@
}
}; // struct node
- I pima;
- const Neighborhood<N>& nbh;
+ mln_exact(I) pima;
+ const mln_exact(N)& nbh;
mln_ch_value(I, site) Par_node;
mln_ch_value(I, site) Par_tree;
@@ -148,6 +150,8 @@
compressTree();
build_euler_tour();
build_minim();
+ m_watershed();
+ w_watershed();
}
@@ -269,22 +273,6 @@
return n;
}
- template <typename C>
- void image_output(image2d<C>& img)
- {
- for(unsigned int i = 0; i < img.domain().len(0); ++i)
- {
- for(unsigned int j = 0; j < img.domain().len(1); ++j)
- {
- C l = (img(site(i, j)));//.row() * img.domain().len(1) + (img(site(i, j))).col();
- std::cout << " " << l << " ";
- }
- std::cout << std::endl;
- }
- }
-
-
-
void print_tree(site p)
{
node& n = nodes(p);
@@ -335,12 +323,12 @@
}
- site highest_fork (p_set<site>& components)
+ bool highest_fork (p_set<site>& components, site &r)
{
if (components.nsites() == 0)
{
std::cerr << "highest fork : empty set" << std::endl;
- return site(-1, -1);
+ return false;
}
site
@@ -360,12 +348,13 @@
}
if (nodes(m).level == nodes(hfork).level)
- return site(-1, -1);
+ return false;
- return hfork;
+ r = hfork;
+ return true;
}
- site w_destructible(site p)
+ bool w_destructible(site p, site &r)
{
mln_niter(N) q(nbh, p);
p_set<site> v;
@@ -375,20 +364,45 @@
v.insert(Par_node(q));
if (v.nsites() == 0)
- return site(-1, -1);
+ return false;
- site hf = highest_fork(v);
+ site hf;
+ bool is_hf = highest_fork(v, hf);
- if (hf == site(-1, -1))
- return min(v);
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
- if (nodes(hf).level <= pima(p))
- return hf;
+ if (nodes(hf).level <= pima(p)) {
+ r = hf;
+ return true;
+ }
+ return false;
+ }
- return site(-1, -1);
+ bool highest_fork (p_set<site>& components) {
+ site i;
+ return highest_fork(components, i);
}
- site m_destructible(site p)
+ bool m_destructible(site p) {
+ site i;
+ return m_destructible(p, i);
+ }
+
+ bool w_destructible(site p) {
+ site i;
+ return w_destructible(p, i);
+ }
+
+ bool w_constructible(site p) {
+ site i;
+ return w_constructible(p, i);
+ }
+
+
+ bool m_destructible(site p, site &r)
{
mln_niter(N) q(nbh, p);
p_set<site> v = p_set<site>();
@@ -398,21 +412,23 @@
v.insert(Par_node(q));
if (v.nsites() == 0)
- return site(-1, -1);
+ return false;
// if (nodes(min(v)).children.nsites() != 0)
if (nodes(min(v)).children.size() != 0)
- return (site(-1, -1));
+ return false;
- site hf = highest_fork(v);
+ bool is_hf = highest_fork(v);
- if (hf == site(-1, -1))
- return min(v);
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
- return site(-1, -1);
+ return false;
}
- site w_constructible(site p)
+ bool w_constructible(site p, site &r)
{
mln_niter(N) q(nbh, p);
p_set<site> v;
@@ -422,10 +438,12 @@
v.insert(Par_node(q));
if (v.nsites() == 0)
- return site(-1, -1);
+ return false;
- if (v.nsites() == 1)
- return v[0];
+ if (v.nsites() == 1) {
+ r = v[0];
+ return true;
+ }
site
c = max(v),
@@ -445,9 +463,10 @@
}
if (nodes(c).level <= pima(p))
- return site(-1, -1);
+ return false;
- return c;
+ r = c;
+ return true;
}
void m_watershed ()
@@ -465,7 +484,7 @@
mln_piter(I) it(pima.domain());
for_all(it)
- if (m_destructible(it.to_site()) != site(-1, -1))
+ if (m_destructible(it.to_site()))
{
l.push(it.to_site());
isproc(it.to_site()) = true;
@@ -481,9 +500,9 @@
// unmark p
isproc(p) = false;
- i = m_destructible(p);
+ bool is_m = m_destructible(p, i);
- if (i != site(-1, -1))
+ if (is_m)
{
pima(p) = nodes(i).level;
Par_node(p) = i;
@@ -491,7 +510,7 @@
mln_niter(N) q(nbh, p);
for_all(q)
if (pima.has(q) && !isproc(q))
- if (m_destructible(q) != site(-1, -1))
+ if (m_destructible(q))
{
// Add priority queue
l.push(q);
@@ -505,15 +524,9 @@
void w_watershed()
{
- std::map< mln_value(I), std::set<site> > L;
+ mln::p_priority< mln_value(I), p_queue_fast<site> > L;
- // Setting the min and the max of the image
- mln_value(I) k, kmin, kmax;
- mln::estim::min_max(pima, kmin, kmax);
-
- // For k From kmin to kmax - 1 Do Lk <- <empty set>
- for (k = kmin; k < kmax; k++)
- L[k] = std::set<site>();
+ mln_value(I) max = level::compute(accu::meta::max(), pima);
// I K(pima.domain(), pima.border());
mln_ch_value(I, unsigned) K(pima.domain(), pima.border());
@@ -524,27 +537,26 @@
for_all(it)
{
site p = it.to_site();
+ site i;
// i <- W-Destructible(p)
- site i = w_destructible(p);
+ bool is_w = w_destructible(p, i);
// If i != infinity then
- if (i != site(-1, -1))
+ if (is_w)
{
- L[nodes(i).level].insert(p);
+ L.push(max - nodes(i).level, p);
K(p) = nodes(i).level;
H(p) = i;
}
}
- for (k = kmin; k < kmax; k++)
+ while (!L.is_empty())
{
- std::set<site>& Lk = L[k];
+ mln_value(I) k = max - L.highest_priority();
- while (!Lk.empty())
- {
- site p = *(Lk.begin());
- Lk.erase(p);
+ site p = L.front();
+ L.pop();
if (K(p) == k)
{
@@ -555,13 +567,14 @@
for_all(q)
if (pima.has(q) && k < pima(q))
{
- site i = w_destructible(q);
- if (i == site(-1, -1))
+ site i;
+ bool is_w = w_destructible(q, i);
+ if (!is_w)
K(q) = 10000; // FIXME : supposed to be infinity...
else
if (K(q) != nodes(i).level)
{
- L[nodes(i).level].insert(q);
+ L.push(max - nodes(i).level, q);
K(q) = nodes(i).level;
H(q) = i;
}
@@ -569,8 +582,6 @@
}
}
}
- }
-
void revert_tree (site p)
{
@@ -628,7 +639,7 @@
// Mark enqueued sites
mln_ch_value(I, bool) enqueued(pima.domain(), pima.border());
- p_priority_queue < site, mln_value(I) > l;
+ p_priority< mln_value(I), p_queue_fast<site> > l;
// p_queue < site > m;
std::queue<site> m;
mln_value(I) max = mln_max(mln_value(I));
@@ -655,7 +666,7 @@
if (cmax.has(q) && !cmax(q) && !enqueued(q))
{
enqueued(q) = true;
- l.push(q, pima(q));
+ l.push(pima(q), q);
}
m.pop();
}
@@ -670,9 +681,10 @@
l.pop();
enqueued(x) = false;
- site c = w_constructible(x);
+ site c;
+ bool is_w = w_constructible(x, c);
- if (c != site(-1, -1))
+ if (is_w)
{
pima(x) = nodes(c).level;
Par_node(x) = c;
@@ -692,7 +704,7 @@
{
enqueued(q) = true;
- l.push(q, pima(q));
+ l.push(pima(q), q);
}
} // if (c != site(-1, -1))
} // while(!l.empty())
@@ -707,7 +719,7 @@
int *euler;
int *depth;
int ctree_size;
- std::map<site, int> pos;
+ std::map<site, int, mln::util::ord<site> > pos;
site *repr;
int *minim;
Index: abraham/mln/morpho/topo_wst.hh
--- abraham/mln/morpho/topo_wst.hh (revision 0)
+++ abraham/mln/morpho/topo_wst.hh (revision 0)
@@ -0,0 +1,744 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// 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_MORPHO_TOPO_WST_HH
+# define MLN_MORPHO_TOPO_WST_HH
+
+
+
+#include <mln/level/sort_psites.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/site_set/p_set.hh>
+#include <mln/estim/min_max.hh>
+#include <mln/math/sqr.hh>
+#include <mln/util/greater_psite.hh>
+#include <mln/util/ord.hh>
+#include <mln/arith/revert.hh>
+
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
+
+#include <queue>
+#include <vector>
+#include <map>
+
+namespace mln
+{
+ namespace morpho
+ {
+
+ template <class I, class N>
+ struct topo_wst
+ {
+
+ // Typedefs
+ // --------
+ typedef mln_site(I) site;
+
+ // Component tree management
+ // -------------------------
+ private:
+ struct node {
+ mln_value(I) level;
+ int area;
+ int highest;
+ typedef mln_site(I) site;
+ // Can't modify the sites in a p_array
+ // p_array<mln_site(I)> children;
+ std::vector<site> children;
+
+ void addChildren(const node& n)
+ {
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for (it.start();
+ // it.is_valid();
+ // it.next())
+ // children.append(it.to_site());
+ for (unsigned i=0; i < n.children.size(); ++i)
+ children.push_back(n.children[i]);
+ }
+
+ void addChild(const site p)
+ {
+ // children.append(n);
+ children.push_back(p);
+ }
+
+ mln_value(I) min() { return mln_min(mln_value(I)); }
+ mln_value(I) max() { return mln_max(mln_value(I)); }
+
+ }; // struct node
+
+ const mln_exact(N)& nbh;
+ mln_ch_value(I, site) Par_node;
+ mln_ch_value(I, site) Par_tree;
+
+ mln_ch_value(I, int) Rnk_tree;
+ mln_ch_value(I, int) Rnk_node;
+ mln_ch_value(I, site) subtreeRoot;
+ mln_ch_value(I, node) nodes;
+ site Root;
+
+ void MakeSet_tree(site x);
+ void MakeSet_node(site x);
+ site Find_tree(site x);
+ void swap(site& x, site& y);
+ site Find_node(site x);
+ void BuildComponentTree();
+ site MergeNode(site& node1, site& node2);
+ site Link_tree(site x, site y);
+ site Link_node(site x, site y);
+ node MakeNode(int level);
+
+
+ // Watershed algorithm
+ // -------------------
+
+ private:
+ mln_ch_value(I, bool) isproc;
+
+ // Ctor
+ public:
+ topo_wst(const Image<I>& i,
+ const Neighborhood<N>& n);
+
+
+ // Result
+ public:
+ mln_exact(I) pima;
+
+ public:
+ void go();
+
+ private:
+ site min (p_set<site>& components);
+ site max (p_set<site>& components);
+ bool highest_fork (p_set<site>& components);
+ bool highest_fork (p_set<site>& components, site &r);
+ bool w_constructible(site p, site &r);
+ bool w_constructible(site p);
+ void topo_watershed();
+
+
+ // Optimized LCA Algorithm
+ private:
+ int *euler;
+ int *depth;
+ int ctree_size;
+ std::map<site, int, mln::util::ord<site> > pos;
+ site *repr;
+
+ int *minim;
+ int **Minim;
+
+ void compute_ctree_size (site p);
+ void build_euler_tour_rec(site p, int &position, int d);
+ void build_euler_tour();
+ void build_minim ();
+ site lca (site a, site b);
+ void removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node);
+ void compressTree();
+ }; // struct topo_wst
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // Ctor
+ template <class I, class N>
+ topo_wst<I, N>::topo_wst(const Image<I>& i,
+ const Neighborhood<N>& n)
+ : pima(exact(i)),
+ nbh(exact(n)),
+ Par_node(exact(i).domain(), exact(i).border()),
+ Par_tree(exact(i).domain(), exact(i).border()),
+ Rnk_tree(exact(i).domain(), exact(i).border()),
+ Rnk_node(exact(i).domain(), exact(i).border()),
+ subtreeRoot(exact(i).domain(), exact(i).border()),
+ nodes(exact(i).domain(), exact(i).border()),
+ isproc(exact(i).domain(), exact(i).border())
+ {
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::MakeSet_tree(site x)
+ {
+ Par_tree(x) = x;
+ Rnk_tree(x) = 0;
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::MakeSet_node(site x)
+ {
+ Par_node(x) = x;
+ Rnk_node(x) = 0;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Find_tree(site x)
+ {
+ if (Par_tree(x) != x)
+ Par_tree(x) = Find_tree(Par_tree(x));
+ return Par_tree(x);
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::swap(site& x, site& y)
+ {
+ site memo = x;
+ x = y;
+ y = memo;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Find_node(site x)
+ {
+ if (Par_node(x) != x)
+ Par_node(x) = Find_node(Par_node(x));
+ return Par_node(x);
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::go()
+ {
+ BuildComponentTree();
+ compressTree();
+ arith::revert_inplace(pima);
+ arith::revert_inplace(nodes);
+ build_euler_tour();
+ build_minim();
+ topo_watershed();
+ arith::revert_inplace(pima);
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::BuildComponentTree()
+ {
+ // Init:
+
+ // Sort the sites in increasing order
+ p_array<mln_site(I)> S;
+ S = level::sort_psites_increasing(pima);
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ for (int ip = 0; ip < int(S.nsites()); ++ip)
+ {
+ site p = S[ip];
+ MakeSet_node(p);
+ MakeSet_tree(p);
+ // if (subtreeRoot.hold(p))
+ subtreeRoot(p) = p;
+ // if (nodes.hold(p))
+ nodes(p) = MakeNode(pima(p));
+ }
+
+
+
+ typename p_array<mln_site(I)>::fwd_piter ip(S);
+ for_all(ip)
+ {
+ site p = ip.to_site();
+
+ site curCanonicalElt = Find_tree(p);
+ site curNode = Find_node(subtreeRoot(curCanonicalElt));
+
+ mln_niter(N) q(nbh, ip);
+ for_all(q)
+ if (pima.has(q) and isproc(q) and pima(q) <= pima(p))
+ {
+ site adjCanonicalElt = Find_tree(q);
+ site adjNode = Find_node(subtreeRoot(adjCanonicalElt));
+ if (curNode != adjNode)
+ {
+ if (nodes(curNode).level == nodes(adjNode).level)
+ curNode = MergeNode(adjNode, curNode);
+ else
+ {
+ nodes(curNode).addChild(adjNode);
+ nodes(curNode).area += nodes(adjNode).area;
+ nodes(curNode).highest += nodes(adjNode).highest;
+ }
+ }
+
+ curCanonicalElt = Link_tree(adjCanonicalElt, curCanonicalElt);
+ subtreeRoot(curCanonicalElt) = curNode;
+ }
+ isproc(p) = true;
+ }
+ // Pour garder une map de correspondance site <-> local_root
+ // for (int ip = 0; ip < int(S.size()); ++ip)
+ // {
+ // site p = S[ip];
+ // M(p) = Find_node(p);
+ // }
+
+ mln_piter(I) r(Par_node.domain());
+ for_all(r)
+ Par_node(r) = Find_node(r);
+
+ Root = subtreeRoot(Find_tree(Find_node(site(0, 0))));
+ }
+
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::MergeNode(site& node1, site& node2)
+ {
+ site tmpNode = Link_node(node1, node2);
+ site tmpNode2;
+ if (tmpNode == node2)
+ {
+ nodes(node2).addChildren(nodes(node1));
+ tmpNode2 = node1;
+ }
+ else
+ {
+ nodes(node1).addChildren(nodes(node2));
+ tmpNode2 = node2;
+ }
+ nodes(tmpNode).area += nodes(tmpNode2).area;
+ nodes(tmpNode).highest += nodes(tmpNode2).highest;
+ return tmpNode;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Link_tree(site x, site y)
+ {
+ if (Rnk_tree(x) > Rnk_tree(y))
+ swap(x, y);
+ else
+ if (Rnk_tree(x) == Rnk_tree(y))
+ Rnk_tree(y) += 1;
+ Par_tree(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Link_node(site x, site y)
+ {
+ if (Rnk_node(x) > Rnk_node(y))
+ swap(x, y);
+ else
+ if (Rnk_node(x) == Rnk_node(y))
+ Rnk_node(y) += 1;
+ Par_node(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::node topo_wst<I, N>::MakeNode(int level)
+ {
+ node n;
+ n.level = level;
+ n.area = 1;
+ n.highest = level;
+ return n;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::min (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site min = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) < pima(min))
+ min = it.to_site();
+
+ return min;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::max (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site max = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) > pima(max))
+ max = it.to_site();
+
+ return max;
+ }
+
+
+ template <class I, class N>
+ bool topo_wst<I, N>::highest_fork (p_set<site>& components, site &r)
+ {
+ if (components.nsites() == 0)
+ {
+ std::cerr << "highest fork : empty set" << std::endl;
+ return false;
+ }
+
+ site
+ m = min(components),
+ hfork = m;
+
+ typename p_set<site>::fwd_piter it(components);
+ for_all(it)
+ {
+ // Can't remove the site from the set
+ if (it.to_site() == m)
+ continue;
+
+ site c = lca(hfork, it.to_site());
+ if (c != it.to_site())
+ hfork = c;
+ }
+
+ if (nodes(m).level == nodes(hfork).level)
+ return false;
+
+ r = hfork;
+ return true;
+ }
+
+ template <class I, class N>
+ bool topo_wst<I, N>::highest_fork (p_set<site>& components) {
+ site i;
+ return highest_fork(components, i);
+ }
+
+ template <class I, class N>
+ bool topo_wst<I, N>::w_constructible(site p) {
+ site i;
+ return w_constructible(p, i);
+ }
+
+ template <class I, class N>
+ bool topo_wst<I, N>::w_constructible(site p, site &r)
+ {
+ mln_niter(N) q(nbh, p);
+ p_set<site> v;
+
+ for_all(q)
+ if (pima.has(q) && pima(q) > pima(p))
+ v.insert(Par_node(q));
+
+ if (v.nsites() == 0)
+ return false;
+
+ if (v.nsites() == 1) {
+ r = v[0];
+ return true;
+ }
+
+ site
+ c = max(v),
+ cmax = c;
+
+ typename p_set<site>::fwd_piter it(v);
+ for_all(it)
+ {
+ // Can't remove the site from the set
+ if (it.to_site() == cmax)
+ continue;
+
+ site c1 = lca(c, it.to_site());
+
+ if (c1 != it.to_site())
+ c = c1;
+ }
+
+ if (nodes(c).level <= pima(p))
+ return false;
+
+ r = c;
+ return true;
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::topo_watershed()
+ {
+ // Maxima components
+ mln_ch_value(I, bool) cmax(pima.domain(), pima.border());
+
+ // Mark enqueued sites
+ mln_ch_value(I, bool) enqueued(pima.domain(), pima.border());
+
+ p_priority< mln_value(I), p_queue_fast<site> > l;
+ // p_queue < site > m;
+ std::queue<site> m;
+ mln_value(I) max = mln_max(mln_value(I));
+
+ std::cout << "Init" << std::endl;
+
+ // Flag C-maxima
+ level::fill(cmax, false);
+ level::fill(enqueued, false);
+
+ mln_piter(I) it(Par_node.domain());
+ for_all(it)
+ // if (nodes(Par_node(it.to_site())).children.nsites() == 0)
+ if (nodes(Par_node(it.to_site())).children.size() == 0)
+ {
+ cmax(it.to_site()) = true;
+ m.push(it.to_site());
+ }
+
+ while (!m.empty())
+ {
+ mln_niter(N) q(nbh, m.front());
+ for_all(q)
+ if (cmax.has(q) && !cmax(q) && !enqueued(q))
+ {
+ enqueued(q) = true;
+ l.push(pima(q), q);
+ }
+ m.pop();
+ }
+
+
+ std::cout << "end" << std::endl;
+
+ // Main loop
+ while(!l.is_empty())
+ {
+ site x = l.front();
+ l.pop();
+ enqueued(x) = false;
+
+ site c;
+ bool is_w = w_constructible(x, c);
+
+ if (is_w)
+ {
+ pima(x) = nodes(c).level;
+ Par_node(x) = c;
+
+ // if (nodes(c).children.nsites() == 0)
+ if (nodes(c).children.size() == 0)
+ cmax(x) = true;
+ else
+ // if (nodes(c).children.nsites() > 1)
+ if (nodes(c).children.size() == 1)
+ std::cerr << "ERREUR COMPOSANTE BRANCHE " << nodes(c).children.size() << std::endl;
+
+
+ mln_niter(N) q(nbh, x);
+ for_all(q)
+ if (pima.has(q) && !cmax(q) && !enqueued(q))
+ {
+ enqueued(q) = true;
+
+ l.push(pima(q), q);
+ }
+ } // if (c != site(-1, -1))
+ } // while(!l.empty())
+
+ for_all(it)
+ pima(it.to_site()) = nodes(Par_node(it.to_site())).level;
+ }
+
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::compute_ctree_size (site p)
+ {
+ ctree_size += 1;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // compute_ctree_size(it.to_site());
+
+ for (unsigned i=0; i < n.children.size(); ++i)
+ compute_ctree_size(n.children[i]);
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::build_euler_tour_rec(site p, int &position, int d)
+ {
+ if (pos.find(p) == pos.end())
+ pos[p] = position;
+
+ repr[position] = p;
+ depth[position] = d;
+ euler[position] = pos[p];
+ ++position;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // {
+ // build_euler_tour_rec(it.to_site(), position, d+1);
+ // depth[position] = d; // Not optimized
+ // euler[position] = pos[p];
+ // repr[position] = p; // Pas necessaire?
+ // ++position;
+ // }
+
+ for(unsigned i=0; i < n.children.size(); ++i)
+ {
+ build_euler_tour_rec(n.children[i], position, d+1);
+ depth[position] = d; // Not optimized
+ euler[position] = pos[p];
+ repr[position] = p; // Pas necessaire?
+ ++position;
+ }
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::build_euler_tour ()
+ {
+ ctree_size = 0;
+ compute_ctree_size(Root);
+
+ int size = 2 * ctree_size - 1;
+
+ // FIXME : free this
+ euler = new int[size];
+ depth = new int[size];
+ repr = new site[size];
+
+ int position = 0;
+ build_euler_tour_rec(Root, position, 0);
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::build_minim ()
+ {
+ // compute_tree_size(); // Already done in build_euler_tour
+ int size = 2 * ctree_size - 1;
+ int logn = (int)(ceil(log((double)(size))/log(2.0)));
+ // minim.reserve(size);
+ minim = new int [logn * size]; // FIXME : Think about freeing this
+ Minim = new int* [logn];
+
+ Minim[0] = minim;
+
+ // Init
+ for (int i = 0; i < size - 1; ++i)
+ if (depth[euler[i]] < depth[euler[i+1]]) {
+ Minim[0][i] = i;
+ } else {
+ Minim[0][i] = i+1;
+ }
+
+ // Minim[0][size - 1] = size - 1;
+
+ int k;
+ for (int j = 1; j < logn; j++) {
+ k = 1 << (j - 1);
+ Minim[j] = &minim[j * size];
+ for (int i = 0; i < size; i++) {
+ if ((i + (k << 1)) >= size) {
+ //Minim[j][i] = size - 1;
+ }
+ else {
+ if (depth[euler[Minim[j - 1][i]]] <= depth[euler[Minim[j - 1][i + k]]])
+ Minim[j][i] = Minim[j - 1][i];
+ else
+ Minim[j][i] = Minim[j - 1][i + k];
+ }
+ }
+ }
+
+ } // void build_minim ()
+
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::lca (site a, site b)
+ {
+ int
+ m = pos[a],
+ n = pos[b],
+ k;
+
+ if (m == n)
+ return repr[m];
+
+ if (m > n)
+ {
+ k = n;
+ n = m;
+ m = k;
+ }
+
+ k = (int)(log((double)(n - m))/log(2.));
+
+ if (depth[euler[Minim[k][m]]] < depth[euler[Minim[k][n - (1 << k)]]]) {
+ return repr[euler[Minim[k][m]]];
+ } else {
+ return repr[euler[Minim[k][n - (1 << k)]]];
+ }
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node)
+ {
+ node &n = nodes(*p);
+
+ if (n.children.size() == 1) // this node has 1 son, delete it
+ {
+ n.area = -1;
+ newPar_node(*p) = n.children[0];
+ *p = n.children[0];
+ removeOneSonNodes(p, newPar_node);
+ }
+ else // there is more than one son, recursive call
+ {
+ for (unsigned i = 0; i < n.children.size(); ++i)
+ removeOneSonNodes(&(n.children[i]), newPar_node);
+ }
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::compressTree()
+ {
+ mln_ch_value(I, site) newPar_node(Par_node.domain(), Par_node.border());
+
+ // Remove the nodes with one son
+ removeOneSonNodes(&Root, newPar_node);
+
+ // Update the references on deleted nodes
+ mln_piter(I) p(Par_node.domain());
+ for_all(p)
+ while (nodes(Par_node(p)).area == -1)
+ Par_node(p) = newPar_node(Par_node(p));
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+
+ }; // namespace morpho
+
+}; // namespace mln
+
+#endif // MLN_MORPHO_TOPO_WST_HH
Index: abraham/mln/core/image/thru.hh
--- abraham/mln/core/image/thru.hh (revision 2672)
+++ abraham/mln/core/image/thru.hh (working copy)
@@ -36,7 +36,9 @@
*/
# include <mln/core/internal/image_value_morpher.hh>
+# include <mln/trait/images.hh>
# include <mln/value/set.hh>
+# include <mln/core/image/shell.hh>
namespace mln
{
@@ -50,8 +52,8 @@
template <typename F, typename I>
struct data< thru<F,I> >
{
- data(const I& ima);
- const I& ima_;
+ data( I& ima);
+ I& ima_;
};
} // end of namespace mln::internal
@@ -64,7 +66,9 @@
template <typename F, typename I>
struct image_< thru<F,I> > : default_image_morpher< I, mln_result(F), thru<F,I> >
{
- typedef trait::image::value_io::read_only value_io;
+ typedef trait::image::value_io::read_write value_io;
+ typedef trait::image::value_access::computed value_access;
+ typedef trait::image::value_storage::disrupted value_storage;
};
} // end of namespace mln::trait
@@ -85,28 +89,22 @@
typedef mln_result(F) rvalue;
/// Return type of read-write access.
- typedef mln_result(F) lvalue;
+ typedef shell<F,I> lvalue;
/// Skeleton.
typedef thru< tag::value_<mln_result(F)>, tag::image_<I> > skeleton;
/// Constructor.
- thru(const Image<I>& ima);
+ thru(Image<I>& ima);
/// Initialize an empty image.
- void init_(const Image<I>& ima);
+ void init_(Image<I>& ima);
/// Read-only access of pixel value at point site \p p.
mln_result(F) operator()(const mln_psite(I)& p) const;
- /// Mutable access is only OK for reading (not writing).
- // T operator()(const mln_psite(I)& p);
- };
-
- template <typename F, typename I>
- struct thru <F, const I>
- {
- mln_result(F) operator()(const mln_psite(I)& p);
+ /// Mutable access is for reading and writing.
+ lvalue operator()(const mln_psite(I)& p);
};
# ifndef MLN_INCLUDE_ONLY
@@ -119,7 +117,7 @@
template <typename F, typename I>
inline
- data< thru<F,I> >::data(const I& ima)
+ data< thru<F,I> >::data(I& ima)
: ima_(ima)
{
}
@@ -130,22 +128,22 @@
template <typename F, typename I>
inline
- thru<F,I>::thru(const Image<I>& ima)
+ thru<F,I>::thru(Image<I>& ima)
{
mln_precondition(exact(ima).has_data());
this->data_ = new internal::data< thru<F,I> >(exact(ima));
}
- /*
+
template <typename F, typename I>
inline
void
- thru<F,I>::init_(const Image<I>& ima)
+ thru<F,I>::init_(Image<I>& ima)
{
mln_precondition(exact(ima).has_data());
this->data_ = new internal::data<thru<F,I> >(exact(ima));
}
- */
+
template <typename F, typename I>
inline
@@ -158,10 +156,10 @@
template <typename F, typename I>
inline
- mln_result(F)
+ shell<F, I>
thru<F,I>::operator()(const mln_psite(I)& p)
{
- return *(F*)(void*)&( this->data_->ima_(p) );
+ return shell<F, I>( this->data_->ima_, p );
}
# endif // ! MLN_INCLUDE_ONLY
Index: abraham/mln/core/image/shell.hh
--- abraham/mln/core/image/shell.hh (revision 0)
+++ abraham/mln/core/image/shell.hh (revision 0)
@@ -0,0 +1,118 @@
+// 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_VALUE_SHELL_HH
+# define MLN_CORE_VALUE_SHELL_HH
+
+# include <mln/core/concept/image.hh>
+
+namespace mln
+{
+
+ // FIXME : traits
+
+ template <typename F, typename I, class C>
+ struct shell_write;
+
+ template <typename F, typename I>
+ struct shell_write<F, I, Function_v2w2v<void> >
+ {
+ mln_value(I) set_ (I &ima, const mln_site(I) &s, const typename F::result &v);
+ };
+
+ template <typename F, typename I>
+ struct shell_write<F, I, Function_v2w_w2v<void> >
+ {
+ mln_value(I) set_ (I &ima, const mln_site(I) &s, const typename F::result &v);
+ };
+
+
+ template <typename F, typename I>
+ struct shell;
+
+ template <typename F, typename I>
+ struct shell : shell_write<F, I, typename F::category> // FIXME : inherit of value_base or sth?
+ {
+ typedef mln_value(I) value;
+
+ // Ctor
+ shell(Image<I> &ima, const mln_site(I) &s);
+
+ // Read
+ operator value ();
+
+ // Write
+ mln_value(I) operator= (typename F::result);
+
+ protected :
+ I &ima;
+ mln_site(I) s;
+ };
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // Ctor
+
+ template <typename F, typename I>
+ shell<F, I>::shell(Image<I> &ima, const mln_site(I) &s)
+ : ima(exact(ima)), s(s)
+ { }
+
+
+ // Read for everyone
+ template <typename F, typename I>
+ shell<F, I>::operator value ()
+ {
+ return F()(ima(s));
+ }
+
+ // Write for everyone
+ template <typename F, typename I>
+ mln_value(I) shell<F, I>::operator= (typename F::result v)
+ {
+ set_(ima, s, v);
+ }
+
+ template <typename F, typename I>
+ mln_value(I) shell_write<F, I, Function_v2w2v<void> >::set_ (I &ima, const mln_site(I) &s, const typename F::result &v)
+ {
+ ima(s) = F().f_1(v);
+ return ima(s);
+ }
+
+ template <typename F, typename I>
+ mln_value(I) shell_write<F, I, Function_v2w_w2v<void> >::set_ (I &ima, const mln_site(I) &s, const typename F::result &v)
+ {
+ ima(s) = F().f_1(ima(s), v);
+ return ima(s);
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+}; // end of namespace mln
+
+#endif // MLN_CORE_VALUE_SHELL_HH
Index: abraham/mln/core/concept/function.hh
--- abraham/mln/core/concept/function.hh (revision 2672)
+++ abraham/mln/core/concept/function.hh (working copy)
@@ -160,7 +160,7 @@
template <typename E>
struct Function_v2w_w2v : public Function<E>
{
- typedef Function_v2w2v<void> category;
+ typedef Function_v2w_w2v<void> category;
/*
result operator() (value);
Index: abraham/mln/core/concept/meta_fun.hh
--- abraham/mln/core/concept/meta_fun.hh (revision 0)
+++ abraham/mln/core/concept/meta_fun.hh (revision 0)
@@ -0,0 +1,83 @@
+// 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_CONCEPT_META_FUN_HH
+# define MLN_CORE_CONCEPT_META_FUN_HH
+
+/*! \file mln/core/concept/meta_fun.hh
+ *
+ * \brief Definition of concept of meta function.
+ */
+
+# include <mln/core/concept/object.hh>
+# include <mln/core/concept/function.hh>
+
+namespace mln
+{
+
+ template <class M, class T>
+ struct function;
+
+ namespace meta
+ {
+
+ template <class M>
+ struct impl
+ {
+
+ template <class T>
+ struct info
+ {
+ typedef function<M, T> F;
+ typedef typename F::result result;
+ typedef typename F::lresult lresult;
+ };
+
+ template <class T>
+ typename info<T>::result
+ operator()(const T& t) const
+ {
+ function<M,T> f;
+ return f.read(t);
+ }
+
+ template <class T>
+ T&
+ f_1(typename info<T>::result v, T& t)
+ {
+ function<M,T> f;
+ f.write(t) = v;
+ return t;
+ }
+
+ };
+
+ } // end of namespace meta
+
+} // end of namespace mln
+
+#endif // MLN_CORE_CONCEPT_META_FUN_HH
Index: abraham/mln/fun/meta/red.hh
--- abraham/mln/fun/meta/red.hh (revision 0)
+++ abraham/mln/fun/meta/red.hh (revision 0)
@@ -0,0 +1,45 @@
+// 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_FUN_META_RED_HH
+# define MLN_FUN_META_RED_HH
+
+# include <mln/core/concept/meta_fun.hh>
+
+namespace mln {
+
+ namespace meta {
+
+ struct red : impl<red> { };
+
+ };
+
+ meta::red red; // fun obj
+
+};
+
+#endif // MLN_FUN_META_RED_HH
Index: abraham/mln/fun/v2w_w2v/norm.hh
--- abraham/mln/fun/v2w_w2v/norm.hh (revision 2672)
+++ abraham/mln/fun/v2w_w2v/norm.hh (working copy)
@@ -71,7 +71,7 @@
* \see mln::norm::l2.
*/
template <typename V, typename R>
- struct l2_norm : public Function_v2v< l2_norm<V, R> >
+ struct l2_norm : public Function_v2w_w2v< l2_norm<V, R> >
{
typedef R result;
R operator()(const V& v) const;
@@ -85,7 +85,7 @@
* \see mln::norm::linfty.
*/
template <typename V, typename R>
- struct linfty_norm : public Function_v2v< linfty_norm<V, R> >
+ struct linfty_norm : public Function_v2w_w2v< linfty_norm<V, R> >
{
typedef R result;
R operator()(const V& v) const;
Index: vigouroux/tests.cc
--- vigouroux/tests.cc (revision 2672)
+++ vigouroux/tests.cc (working copy)
@@ -1,4 +1,4 @@
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_cmy.hh
--- vigouroux/color/rgb_to_cmy.hh (revision 2672)
+++ vigouroux/color/rgb_to_cmy.hh (working copy)
@@ -1,4 +1,4 @@
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_xyz.hh
--- vigouroux/color/rgb_to_xyz.hh (revision 2672)
+++ vigouroux/color/rgb_to_xyz.hh (working copy)
@@ -1,7 +1,7 @@
#ifndef OLENA_CONVERT_RGBXYZ_HH
# define OLENA_CONVERT_RGBXYZ_HH
-# include <mln/core/image_if_value.hh>
+# include <mln/core/image/image_if.hh>
# include <mln/core/alias/w_window2d_int.hh>
# include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_hsi.hh
--- vigouroux/color/rgb_to_hsi.hh (revision 2672)
+++ vigouroux/color/rgb_to_hsi.hh (working copy)
@@ -1,7 +1,7 @@
#include <cmath>
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_yuv.hh
--- vigouroux/color/rgb_to_yuv.hh (revision 2672)
+++ vigouroux/color/rgb_to_yuv.hh (working copy)
@@ -1,4 +1,4 @@
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
1
0
24 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
De-activate not compiling tests in level transform.
* doc/examples/tuto_bis.cc: Layout.
(label): Set no border.
(lab): Change extension from pw fun to image.
That fixes some weird behavior.
* mln/level/transform.hh (todo): New.
De-activate tests since Nicolas has not fixed it yet.
* mln/level/stretch.hh (FIXME): Fix.
Avoid escaping allows for properly tracing.
* mln/estim/nsites.hh: Rename as...
* mln/geom/nsites.hh: ...this.
Update.
* mln/level/sort_psites.hh: Use geom::nsites.
Remember that only some images have the nsites method.
* mln/trace/exiting.hh: Print the scope when exiting.
It eases debugging (reading traces).
* mln/morpho/closing_volume.hh,.
* mln/morpho/meyer_wst.hh: Add trace equipment
doc/examples/tuto_bis.cc | 11 +++++++----
mln/geom/nsites.hh | 34 +++++++++++++++++-----------------
mln/level/sort_psites.hh | 8 +++++---
mln/level/stretch.hh | 6 +++---
mln/level/transform.hh | 18 +++++++++++-------
mln/morpho/closing_volume.hh | 2 ++
mln/morpho/meyer_wst.hh | 2 ++
mln/trace/exiting.hh | 6 +++---
8 files changed, 50 insertions(+), 37 deletions(-)
Index: doc/examples/tuto_bis.cc
--- doc/examples/tuto_bis.cc (revision 2671)
+++ doc/examples/tuto_bis.cc (working copy)
@@ -20,6 +20,7 @@
# include <mln/level/paste.hh>
# include <mln/level/fill.hh>
# include <mln/level/transform.hh>
+# include <mln/extension/fill.hh>
# include <mln/morpho/meyer_wst.hh>
@@ -113,7 +114,7 @@
dilation(const I& input, const N& nbh)
{
typedef mln_value(I) V;
- // extension::fill(input, mln_min(V));
+ // FIXME: extension::fill(input, mln_min(V));
mln_concrete(I) output;
initialize(output, input);
@@ -133,10 +134,12 @@
} // mln::morpho
+
} // mln
+
// Functions
inline
@@ -239,8 +242,7 @@
// 1 1
- image2d<unsigned> label(ima.bbox(), 1);
- border::fill(label, 0);
+ image2d<unsigned> label(ima.bbox(), 0);
level::fill(label, 9);
debug::println(label);
// 9 9 9 9 9
@@ -309,7 +311,8 @@
//
// 9 9 9
- level::paste(morpho::dilation(extend(lab, pw::value(label)),
+
+ level::paste(morpho::dilation(extend(lab, label),
c4()),
label);
Index: mln/level/transform.hh
--- mln/level/transform.hh (revision 2671)
+++ mln/level/transform.hh (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007 EPITA Research and Development Laboratory
+// Copyright (C) 2007, 2008 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
@@ -33,6 +33,8 @@
* \brief Transform the contents of an image into another one.
*
* \todo Clean this file + overload with pixel iterators.
+ *
+ * \todo Re-activate tests and make them static.
*/
# include <mln/core/concept/image.hh>
@@ -91,10 +93,11 @@
(void) output;
// Properties check
- mln_precondition((mlc_is(mln_trait_image_pw_io(O),
- trait::image::pw_io::read_write)::value ||
- mlc_is(mln_trait_image_vw_io(O),
- trait::image::vw_io::read_write)::value));
+ // FIXME: Re-activate!
+// mln_precondition((mlc_is(mln_trait_image_pw_io(O),
+// trait::image::pw_io::read_write)::value ||
+// mlc_is(mln_trait_image_vw_io(O),
+// trait::image::vw_io::read_write)::value));
// FIXME Convert test
mlc_converts_to(mln_result(F), mln_value(O))::check();
@@ -129,8 +132,9 @@
level::internal::transform_tests(input, f, output);
- mlc_is(mln_trait_image_pw_io(O),
- trait::image::pw_io::read_write)::check();
+ // FIXME: Re-activate!
+// mlc_is(mln_trait_image_pw_io(O),
+// trait::image::pw_io::read_write)::check();
mln_piter(I) p(input.domain());
for_all(p)
Index: mln/level/stretch.hh
--- mln/level/stretch.hh (revision 2671)
+++ mln/level/stretch.hh (working copy)
@@ -72,8 +72,8 @@
mln_value(I) min_, max_;
estim::min_max(input, min_, max_);
- if (max_ == min_)
- return; // FIXME
+ if (max_ != min_)
+ {
float min = float(min_), max = float(max_);
const float epsilon = mln_epsilon(float);
float m = 0.0f - 0.5f + epsilon;
@@ -82,7 +82,7 @@
float b = (m * max - M * min) / (max - min);
fun::v2v::linear<float, float, int> f(a, b);
level::transform(input, f, output);
-
+ }
trace::exiting("level::impl::stretch");
}
Index: mln/level/sort_psites.hh
--- mln/level/sort_psites.hh (revision 2671)
+++ mln/level/sort_psites.hh (working copy)
@@ -1,4 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -39,6 +40,7 @@
# include <mln/convert/to_p_array.hh>
# include <mln/histo/compute.hh>
# include <mln/util/ord.hh>
+# include <mln/geom/nsites.hh>
namespace mln
@@ -154,7 +156,7 @@
loc[i] = loc[i-1] + h[i-1];
// computing output data
- std::vector<mln_psite(I)> vec(input.nsites());
+ std::vector<mln_psite(I)> vec(geom::nsites(input));
mln_fwd_piter(I) p(input.domain());
for_all(p)
vec[loc[vset.index_of(input(p))]++] = p;
@@ -198,7 +200,7 @@
loc[i] = loc[i+1] + h[i+1];
// computing output data
- std::vector<mln_psite(I)> vec(input.nsites());
+ std::vector<mln_psite(I)> vec(geom::nsites(input));
mln_fwd_piter(I) p(input.domain());
for_all(p)
vec[loc[vset.index_of(input(p))]++] = p;
Index: mln/geom/nsites.hh
--- mln/geom/nsites.hh (revision 2670)
+++ mln/geom/nsites.hh (working copy)
@@ -25,10 +25,10 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_ESTIM_NSITES_HH
-# define MLN_ESTIM_NSITES_HH
+#ifndef MLN_GEOM_NSITES_HH
+# define MLN_GEOM_NSITES_HH
-/*! \file mln/estim/nsites.hh
+/*! \file mln/geom/nsites.hh
*
* \brief Compute the number of sites of an image or a site set.
*/
@@ -40,7 +40,7 @@
namespace mln
{
- namespace estim
+ namespace geom
{
/// Compute the number of sites of the site set \p input.
@@ -69,7 +69,7 @@
template <typename S>
unsigned nsites(const Site_Set<S>& s_)
{
- trace::entering("estim::impl::generic::nsites");
+ trace::entering("geom::impl::generic::nsites");
const S& s = exact(s_);
mln_precondition(s.is_valid());
@@ -78,11 +78,11 @@
for_all(p)
++n;
- trace::exiting("estim::impl::generic::nsites");
+ trace::exiting("geom::impl::generic::nsites");
return n;
}
- } // end of namespace mln::estim::impl::generic
+ } // end of namespace mln::geom::impl::generic
// A single specialization.
@@ -91,13 +91,13 @@
inline
unsigned nsites_method(const Site_Set<S>& s)
{
- trace::entering("estim::impl::nsites_method");
+ trace::entering("geom::impl::nsites_method");
unsigned n = exact(s).nsites();
- trace::exiting("estim::impl::nsites_method");
+ trace::exiting("geom::impl::nsites_method");
return n;
}
- } // end of namespace mln::estim::impl
+ } // end of namespace mln::geom::impl
@@ -132,7 +132,7 @@
s);
}
- } // end of namespace mln::estim::internal
+ } // end of namespace mln::geom::internal
@@ -142,12 +142,12 @@
inline
unsigned nsites(const Site_Set<S>& s)
{
- trace::entering("estim::nsites");
+ trace::entering("geom::nsites");
mln_precondition(exact(s).is_valid());
unsigned n = internal::nsites_dispatch(s);
- trace::exiting("estim::nsites");
+ trace::exiting("geom::nsites");
return n;
}
@@ -155,7 +155,7 @@
inline
unsigned nsites(const Image<I>& input_)
{
- trace::entering("estim::nsites");
+ trace::entering("geom::nsites");
const I& input = exact(input_);
mln_precondition(input.has_data());
@@ -164,15 +164,15 @@
// Relies on the nsites routines on a site set.
unsigned n = internal::nsites_dispatch(input.domain());
- trace::exiting("estim::nsites");
+ trace::exiting("geom::nsites");
return n;
}
# endif // ! MLN_INCLUDE_ONLY
- } // end of namespace mln::estim
+ } // end of namespace mln::geom
} // end of namespace mln
-#endif // ! MLN_ESTIM_NSITES_HH
+#endif // ! MLN_GEOM_NSITES_HH
Index: mln/trace/exiting.hh
--- mln/trace/exiting.hh (revision 2671)
+++ mln/trace/exiting.hh (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007 EPITA Research and Development Laboratory
+// Copyright (C) 2007, 2008 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
@@ -50,14 +50,14 @@
# ifndef MLN_INCLUDE_ONLY
inline
- void exiting(const std::string&)
+ void exiting(const std::string& str)
{
if (quiet)
return;
--tab;
for (unsigned i = 0; i < tab; ++i)
std::cout << " ";
- std::cout << "}" << std::endl;
+ std::cout << "} " << str << std::endl;
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/morpho/closing_volume.hh
--- mln/morpho/closing_volume.hh (revision 2671)
+++ mln/morpho/closing_volume.hh (working copy)
@@ -54,9 +54,11 @@
void closing_volume(const Image<I>& input, const Neighborhood<N>& nbh,
std::size_t lambda, Image<O>& output)
{
+ trace::entering("morpho::closing_volume");
mln_precondition(exact(output).domain() == exact(input).domain());
// FIXME: Change sig of closing_attribute!
closing_attribute< accu::volume<I> >(input, nbh, lambda, output);
+ trace::exiting("morpho::closing_volume");
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/morpho/meyer_wst.hh
--- mln/morpho/meyer_wst.hh (revision 2671)
+++ mln/morpho/meyer_wst.hh (working copy)
@@ -108,6 +108,7 @@
meyer_wst(const Image<I>& input_, const Neighborhood<N>& nbh_,
L& nbasins)
{
+ trace::entering("morpho::meyer_wst");
/* FIXME: Ensure the input image has scalar values. */
const I input = exact(input_);
@@ -192,6 +193,7 @@
}
}
}
+ trace::exiting("morpho::meyer_wst");
return output;
}
1
0
24 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add a processing chain about segmentation on edges.
* geraud/wst_edge.cc: New.
wst_edge.cc | 406 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 406 insertions(+)
Index: geraud/wst_edge.cc
--- geraud/wst_edge.cc (revision 0)
+++ geraud/wst_edge.cc (revision 0)
@@ -0,0 +1,406 @@
+# include <mln/core/var.hh>
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/image_if.hh>
+# include <mln/core/image/extended.hh>
+# include <mln/core/routine/extend.hh>
+
+# include <mln/core/alias/window2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/make/double_neighb2d.hh>
+# include <mln/core/site_set/p_centered.hh>
+
+# include <mln/literal/origin.hh>
+# include <mln/literal/black.hh>
+# include <mln/literal/white.hh>
+
+# include <mln/value/int_u8.hh>
+# include <mln/io/pgm/load.hh>
+# include <mln/io/pgm/save.hh>
+
+# include <mln/value/rgb8.hh>
+# include <mln/io/ppm/save.hh>
+
+# include <mln/accu/min_max.hh>
+# include <mln/accu/mean.hh>
+
+# include <mln/fun/i2v/array.hh>
+# include <mln/fun/p2v/iota.hh>
+
+# include <mln/level/paste.hh>
+# include <mln/level/fill.hh>
+# include <mln/level/transform.hh>
+# include <mln/extension/fill.hh>
+
+# include <mln/morpho/meyer_wst.hh>
+# include <mln/morpho/closing_area.hh>
+
+# include <mln/debug/println.hh>
+
+
+
+// Functions
+
+inline
+bool is_row_odd(const mln::point2d& p)
+{
+ return p.row() % 2;
+}
+
+inline
+bool is_cell(const mln::point2d& p)
+{
+ return p.row() % 2 == 0 && p.col() % 2 == 0;
+}
+
+inline
+bool is_edge(const mln::point2d& p)
+{
+ return p.row() % 2 + p.col() % 2 == 1;
+}
+
+inline
+bool is_point(const mln::point2d& p)
+{
+ return p.row() % 2 && p.col() % 2;
+}
+
+
+inline
+bool is_not_edge(const mln::point2d& p)
+{
+ return ! is_edge(p);
+}
+
+
+
+namespace mln
+{
+
+ namespace border
+ {
+
+ template <typename I>
+ void
+ fill(I& ima, const mln_value(I)& v)
+ {
+ const int nrows = ima.nrows();
+ const int ncols = ima.ncols();
+ for (int r = -1; r <= nrows; ++r)
+ {
+ ima.at(r, -1) = v;
+ ima.at(r, ncols) = v;
+ }
+ for (int c = -1; c <= ncols; ++c)
+ {
+ ima.at(-1, c) = v;
+ ima.at(nrows, c) = v;
+ }
+ }
+
+ } // mln::border
+
+ namespace accu
+ {
+
+ template <typename I, typename L, typename A, typename V>
+ inline
+ void
+ compute(const Image<I>& input_,
+ const Image<L>& label_,
+ const Accumulator<A>&,
+ V& v)
+ {
+ trace::entering("accu::compute");
+
+ const I& input = exact(input_);
+ const L& label = exact(label_);
+
+ const unsigned n = v.size();
+ std::vector<A> a(n);
+
+ mln_piter(I) p(input.domain());
+ for_all(p)
+ a[label(p)].take(input(p));
+
+ for (unsigned l = 1; l < n; ++l)
+ v(l) = a[l].to_result();
+
+ trace::exiting("accu::compute");
+ }
+
+ } // mln::accu
+
+ namespace morpho
+ {
+
+ template <typename I, typename N>
+ mln_concrete(I)
+ gradient(const I& input, const N& nbh)
+ {
+ mln_concrete(I) output;
+ initialize(output, input);
+ accu::min_max<mln_value(I)> mm;
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ mm.init();
+ for_all(n) if (input.has(n))
+ mm.take(input(n));
+ output(p) = mm.second() - mm.first();
+ }
+ return output;
+ }
+
+ template <typename I, typename N>
+ mln_concrete(I)
+ dilation(const I& input, const N& nbh)
+ {
+ typedef mln_value(I) V;
+ // FIXME: extension::fill(input, mln_min(V));
+
+ mln_concrete(I) output;
+ initialize(output, input);
+ accu::max<V> m;
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ m.init();
+ for_all(n) if (input.has(n))
+ m.take(input(n));
+ output(p) = m;
+ }
+ return output;
+ }
+
+ } // mln::morpho
+
+
+ struct colorize : Function_v2v< colorize >
+ {
+ typedef value::rgb8 result;
+ colorize(unsigned max)
+ : lut(max + 1)
+ {
+ lut[0] = literal::black;
+ for (unsigned i = 1; i <= max; ++i)
+ lut[i] = result(100 + std::rand() % 150,
+ 100 + std::rand() % 150,
+ 100 + std::rand() % 150);
+ }
+ result operator()(unsigned i) const
+ {
+ return lut[i];
+ }
+ std::vector<result> lut;
+ };
+
+
+ template <typename I>
+ I display_edge(const I& ima, mln_value(I) bg, unsigned zoom)
+ {
+ unsigned nrows = ima.nrows() / 2 + 1;
+ unsigned ncols = ima.ncols() / 2 + 1;
+ I output(nrows * (zoom + 1) - 1,
+ ncols * (zoom + 1) - 1);
+ level::fill(output, bg);
+ mln_VAR( edge, ima | is_edge );
+ mln_piter(edge_t) p(edge.domain());
+ for_all(p)
+ if (p.row() % 2) // horizontal edge
+ {
+ unsigned row = (p.row() / 2 + 1) * (zoom + 1) - 1;
+ unsigned col = (p.col() / 2) * (zoom + 1);
+ for (unsigned i = 0; i < zoom; ++i)
+ output.at(row, col + i) = ima(p);
+ }
+ else // vertical edge
+ {
+ unsigned row = (p.row() / 2) * (zoom + 1);
+ unsigned col = (p.col() / 2 + 1) * (zoom + 1) - 1;
+ for (unsigned i = 0; i < zoom; ++i)
+ output.at(row + i, col) = ima(p);
+ }
+ return output;
+ }
+
+} // mln
+
+
+
+template <typename T>
+mln::image2d<T>
+image2cells(const mln::image2d<T>& input)
+{
+ mln::image2d<T> output(2 * input.nrows() - 1,
+ 2 * input.ncols() - 1);
+ for (int row = 0; row < input.nrows(); ++row)
+ for (int col = 0; col < input.ncols(); ++col)
+ output.at(2 * row, 2 * col) = input.at(row, col);
+ return output;
+}
+
+
+template <typename T>
+mln::image2d<T>
+cells2image(const mln::image2d<T>& input)
+{
+ mln::image2d<T> output((input.nrows() + 1) / 2,
+ (input.ncols() + 1) / 2);
+ for (int row = 0; row < input.nrows(); row += 2)
+ for (int col = 0; col < input.ncols(); col += 2)
+ output.at(row / 2, col / 2) = input.at(row, col);
+ return output;
+}
+
+
+
+
+template <typename I>
+void
+do_it(I& ima, int lambda, const std::string& filename, unsigned& nbasins)
+{
+ using namespace mln;
+
+ // e2c
+
+ bool e2c_h[] = { 0, 1, 0,
+ 0, 0, 0,
+ 0, 1, 0 };
+
+ bool e2c_v[] = { 0, 0, 0,
+ 1, 0, 1,
+ 0, 0, 0 };
+
+ mln_VAR( e2c, make::double_neighb2d(is_row_odd, e2c_h, e2c_v) );
+
+ bool e2e_h[] = { 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0 };
+
+ bool e2e_v[] = { 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0 };
+
+ mln_VAR( e2e, make::double_neighb2d(is_row_odd, e2e_h, e2e_v) );
+
+ // cell
+ mln_VAR(cell, ima | is_cell);
+
+ // edge
+ mln_VAR(edge, extend((ima | is_edge).rw(),
+ pw::value(ima)));
+
+ level::paste(morpho::gradient(edge, e2c), edge);
+ // ^^^
+ // edge -> neighboring cells
+
+ // 'edge' looks like:
+ //
+ // 1 1
+ // 3 3 3
+ // 1 1
+
+ {
+ io::pgm::save(display_edge(ima, 0, 3),
+ "temp_edge.pgm");
+ }
+
+
+ level::paste( morpho::closing_area(edge, e2e, lambda), edge );
+
+
+ image2d<unsigned> label(ima.bbox(), 0);
+ // mln_ch_value(I, unsigned) label;
+ // initialize(label, ima);
+
+
+ mln_VAR(wst, label | is_edge);
+
+ level::fill(wst, morpho::meyer_wst(edge, e2e, nbasins));
+ // ^^^
+ // edge -> neighboring edges
+
+ // 'wst' looks like:
+ //
+ // 2 2
+ // 0 0 0
+ // 1 1
+
+ colorize colors(nbasins);
+
+ {
+ image2d<value::rgb8> temp(label.domain());
+ level::fill(temp, literal::white);
+
+ level::paste( level::transform(label | is_edge,
+ colors),
+ temp );
+
+ io::ppm::save(display_edge(temp, literal::white, 3),
+ "temp_label.ppm");
+ }
+
+ // YET THOSE VALUES ARE ON EDGES, NOT ON CELLS...
+
+
+ mln_VAR(lab, label | is_cell);
+
+ level::paste(morpho::dilation(extend(lab, label),
+ c4()),
+ label);
+
+ // 'lab' looks like:
+ //
+ // 2 2 2
+ //
+ // 1 1 1
+
+ io::ppm::save(level::transform(cells2image(label),
+ colors),
+ filename);
+}
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm lambda output.ppm" << std::endl;
+ std::cerr << " lambda >= 0" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 4)
+ usage(argv);
+
+ image2d<int_u8> temp;
+ io::pgm::load(temp, argv[1]);
+
+ image2d<int_u8> ima = image2cells(temp);
+
+
+ int lambda = atoi(argv[2]);
+ if (lambda < 0)
+ usage(argv);
+
+ std::string filename(argv[3]);
+
+ unsigned nbasins;
+ do_it(ima, lambda, filename, nbasins);
+ std::cout << "nbasins = " << nbasins << std::endl;
+}
1
0
URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-24 Jimmy Ma <jimmy.ma(a)lrde.epita.fr>
Fix the skeleton algorithm introduced by aroumougame.
* garrigues/ocr/skeleton.cc,
garrigues/ocr/skeleton.hh: New.
The code has been updated to work with the current version of
milena. However, the code itself has to be cleaned and improved.
---
skeleton.cc | 30 ++
skeleton.hh | 611 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 641 insertions(+)
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh (revision 2670)
@@ -0,0 +1,611 @@
+// Copyright (C) 2007, 2008 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 SKELETON_HH
+# define SKELETON_HH
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <sandbox/aroumougame/skeleton/sedt.hh>
+
+#include <mln/core/site_set/p_set.hh>
+#include <mln/math/sqrt.hh>
+
+namespace mln
+{
+
+
+template <typename P>
+ std::vector< std::pair< double, P > > remove(std::vector< std::pair< double, P > > Q, P p)
+{
+ typename std::vector<std::pair< double, P > >::iterator it;
+
+ for(it = Q.begin(); it!=Q.end(); it++)
+ {
+ if((*it).second==p)
+ {
+ it = Q.erase(it);
+ break;
+ }
+ }
+ return Q;
+}
+template <typename N>
+ double distance(N a, N b, N c, N d)
+{
+ double dist = sqrt((a-c)*(a-c)+(b-d)*(b-d));
+ return dist;
+}
+template <typename P>
+ std::vector< std::pair< double, P > > insertDicho(std::vector< std::pair< double, P > > Q, std::pair< double, P> p)
+{
+ int indMin, indMax, indMid;
+
+ indMin = 0;
+ indMax = Q.size();
+
+ if(indMax==0 || Q[indMax-1].first <= p.first)
+ Q.push_back(p);
+ else
+ {
+ while(indMax > indMin)
+ {
+ indMid = int(indMin + (indMax-indMin)/2);
+ if(Q[indMid].first < p.first)
+ {
+ indMin = indMid+1;
+ if(Q[indMin].first > p.first)
+ {
+ indMax = indMid;
+ }
+ }
+ else
+ {
+ indMax = indMid-1;
+ if(Q[indMax].first < p.first)
+ {
+ indMin = indMid;
+ }
+ }
+ }
+
+ typename std::vector< std::pair< double, P > >::iterator it=Q.begin();
+ it = Q.insert ( it+indMin, p);
+ }
+
+ return Q;
+}
+
+
+const neighb2d& complement_neighborhood(const Neighborhood<neighb2d>& nbh)
+{
+ if(&nbh == &c4())
+ return c8();
+ return c4();
+}
+
+template <typename N>
+ int nb_composant_connexe(p_set< mln_psite(N) > X_full,const Neighborhood<N>& nbh_,const mln_psite(N)& p_ref, bool local)
+{
+ N nbh = exact(nbh_);
+ p_set< mln_psite(N) > X;
+ if(local)
+ {
+ mln_niter(N) n(max_neighborhood(nbh), p_ref);
+
+ for_all(n)
+ {
+ if (X_full.has(n))
+ X.insert(n);
+ }
+ }
+ else
+ {
+ X = X_full;
+ }
+
+ int T;
+ p_set< mln_psite(N) > done;
+ p_set< mln_psite(N) > neighbors;
+ p_set< mln_psite(N) > composant;
+
+ done.insert(p_ref);
+ mln_niter(N) q(nbh, p_ref);
+ for_all(q)
+ {
+ if (X.has(q)&&!done.has(q))
+ {
+ neighbors.insert(q);
+ }
+ }
+// std::cout << "nb_composant_connexe: neighbors " << neighbors.nsites() <<std::endl;
+ if(neighbors.nsites()<=1)
+ {
+ return neighbors.nsites();
+ }
+ else
+ T=0;
+
+ while(neighbors.nsites()!=0)
+ {
+ T++;
+ done.insert(neighbors[0]);
+ mln_niter(N) t(nbh, neighbors[0]);
+ neighbors.remove(neighbors[0]);
+ for_all(t)
+ {
+ if (X.has(t)&&!done.has(t))
+ {
+ composant.insert(t);
+ }
+ }
+
+ while(composant.nsites()!=0)
+ {
+ done.insert(composant[0]);
+ if(neighbors.has(composant[0]))
+ {
+ neighbors.remove(composant[0]);
+ if(neighbors.nsites()==0)
+ return T;
+ }
+
+ mln_niter(N) r(nbh, composant[0]);
+ composant.remove(composant[0]);
+ for_all(r)
+ {
+ if (X.has(r) && !done.has(r))
+ {
+ composant.insert(r);
+ }
+ }
+ }
+ }
+ return T;
+}
+
+template <typename N>
+ bool simple_point(p_set< mln_psite(N) > X,const Neighborhood<N>& nbh, p_set< mln_psite(N) > X_complement, const mln_psite(N)& p_ref, bool local)
+{
+ int nX = nb_composant_connexe(X,exact(nbh),p_ref,local);
+ int nX_complement = nb_composant_connexe(X_complement,complement_neighborhood(exact(nbh)),p_ref,local);
+
+ if((nX_complement == 1)&&(nX == 1))
+ return true;
+ return false;
+}
+
+
+ template <typename N>
+ p_set<mln_psite(N)> euclideanSkeleton(p_set<mln_psite(N)> X, p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt, p_set<mln_psite(N)>& Y, const Neighborhood<N>& nbh_, bool local)
+ {
+ std::vector< std::pair< double, mln::point2d> > Q;
+ std::vector< std::pair< double, mln::point2d> > R;
+ N nbh = exact(nbh_);
+
+ // fill Q
+ for (uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ std::pair<double, mln_psite(N)> p(math::sqrt(double(dt(X[i]))),X[i]);
+ Q = insertDicho(Q,p);
+ }
+ }
+
+ // fill R
+ for (uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ double min = 1023.99;
+ mln_niter(N) r(nbh, X[i]);
+ for_all(r)
+ {
+ if (Y.has(r))
+ {
+ double tmp = distance(r[0], r[1], X[i][0], X[i][1]);
+ double d = math::sqrt(double(dt(r)))+(math::sqrt(double(dt(X[i])))-math::sqrt(double(dt(r))))/tmp;
+ min = math::min(min,d);
+ }
+ }
+ if (min!=1023.99)
+ {
+ std::pair<double, mln_psite(N)> p(min,X[i]);
+ R = insertDicho(R, p);
+ }
+ }
+ }
+
+ while (!Q.empty() || !R.empty())
+ {
+ mln_psite(N) tmp;
+ if (Q[0].first < R[0].first)
+ {
+ tmp = Q[0].second;
+ }
+ else
+ {
+ tmp = R[0].second;
+ }
+
+ Q = remove(Q, tmp);
+ R = remove(R, tmp);
+
+ if (!Y.has(tmp) && X.has(tmp))
+ {
+ if (simple_point(X, nbh, X_complement, tmp, local))
+ {
+ X.remove(tmp);
+ X_complement.insert(tmp);
+ }
+ else
+ {
+ Y.insert(tmp);
+ mln_niter(N) r(nbh, tmp);
+ for_all(r)
+ {
+ if (!Y.has(r) && X.has(r))
+ {
+ double dist = distance(r[0], r[1], tmp[0], tmp[1]);
+ double d = math::sqrt(double(dt(tmp)))+(math::sqrt(double(dt(r)))-math::sqrt(double(dt(tmp))))/dist;
+ std::pair<double, mln_psite(N)> p(d,r);
+ R = insertDicho(R, p);
+ }
+ }
+
+ }
+ }
+
+ }
+ return X;
+ }
+
+
+ p_set<point2d> EP(image2d<value::int_u8> dt, point2d x, std::vector< std::vector<std::pair< int, int> > > lut, const neighb2d& nbh)
+ {
+ p_set<point2d> EP;
+ p_set<point2d> tmp;
+ int w = geom::ncols(dt);
+ int h = geom::nrows(dt);
+
+
+ mln_niter_(neighb2d) r(nbh, x);
+ for_all(r)
+ {
+ if (dt(r) <= dt(x))
+ {
+ for (uint i=0; i<lut[dt(r)].size(); i++)
+ {
+ if ((r[0]+lut[dt(r)][i].first < h) && (r[1]+lut[dt(r)][i].second < w))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second));
+ }
+ if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]-lut[dt(r)][i].second >= 0))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second));
+ }
+ if ((r[0]+lut[dt(r)][i].first < h) && (r[1]-lut[dt(r)][i].second >= 0))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second));
+ }
+ if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]+lut[dt(r)][i].second < w))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second));
+ }
+ if ((r[0]+lut[dt(r)][i].second < h) && (r[1]+lut[dt(r)][i].first < w))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first));
+ }
+ if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]-lut[dt(r)][i].first >= 0))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first));
+ }
+ if ((r[0]+lut[dt(r)][i].second < h) && (r[1]-lut[dt(r)][i].first >= 0))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first));
+ }
+ if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]+lut[dt(r)][i].first < w))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first));
+ }
+ }
+ }
+ }
+
+ return EP;
+ }
+
+ std::vector< std::vector<std::pair< int, int> > > Lut2d(int N)
+ {
+ int n = int(sqrt(N))+1;
+ int i=0;
+ std::vector< std::vector<std::pair< int, int> > > lut;
+
+ for(i = 0; i <= N; i++)
+ {
+ std::vector<std::pair< int, int> > vect;
+ lut.push_back(vect);
+ }
+
+ for(int x = 0; x <= n; x++)
+ {
+ for(int y = 0; y <= x; y++)
+ {
+ i=x*x+y*y;
+ if(i<=N)
+ {
+ std::pair<int,int> p(x,y);
+ lut[i].push_back(p);
+ }
+ }
+ }
+
+ return lut;
+}
+
+ image2d<value::int_u8> DiscreteBisector(image2d<value::int_u8> dt, p_set<point2d> Y, const neighb2d& nbh, int N)
+ {
+ int w = geom::ncols(dt);
+ int h = geom::nrows(dt);
+
+ int ux,uy,vx,vy, produit, angle, max;
+ double cos, normu, normv;
+
+ std::vector< std::vector<std::pair< int, int> > > lut;
+ lut = Lut2d(N);
+
+ p_set<point2d> proj;
+
+ image2d<value::int_u8> bisector(h, w);
+ level::fill(bisector, 0);
+
+ for (uint i=0; i<Y.nsites(); i++)
+ {
+ proj = EP(dt, Y[i], lut, nbh);
+
+ int n=proj.nsites();
+
+ if (n>1)
+ {
+ max = 0;
+ for (int y=0; y<n; y++)
+ {
+ for (int z=0; z<y; z++)
+ {
+ ux = proj[y][0]-Y[i][0];
+ uy = proj[y][1]-Y[i][1];
+ vx = proj[z][0]-Y[i][0];
+ vy = proj[z][1]-Y[i][1];
+
+ produit = ux * vx + uy * vy;
+
+ normu = sqrt(ux*ux + uy*uy);
+ normv = sqrt(vx*vx + vy*vy);
+
+ cos = produit/(normu*normv);
+ angle = int(acos(cos)*180.0/3.1415);
+
+ max = math::max(max, angle);
+ }
+ }
+ bisector(Y[i]) = max;
+ }
+
+ }
+
+ return bisector;
+
+ }
+
+
+
+const neighb2d& max_neighborhood(const Neighborhood<neighb2d>& nbh)
+{
+ return c8();
+}
+template <typename N>
+ p_set<mln_psite(N)> ultimateSkeleton(p_set<mln_psite(N)> X, p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt, p_set<mln_psite(N)> Y, const Neighborhood<N>& nbh_, bool local)
+{
+ std::vector< std::pair< double, mln::point2d> > Q;
+
+ N nbh = exact(nbh_);
+ // fill Q
+ for(uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ std::pair<double, mln_psite(N)> p(dt(X[i]),X[i]);
+ Q = insertDicho(Q,p);
+ }
+ }
+
+
+ while(!Q.empty())
+ {
+ mln_psite(N) tmp = Q[0].second;
+
+ Q = remove(Q, tmp);
+
+ if(simple_point(X, nbh, X_complement, tmp, local))
+ {
+ X.remove(tmp);
+ X_complement.insert(tmp);
+ mln_niter(N) r(nbh, tmp);
+ for_all(r)
+ {
+ if(!Y.has(r) && X.has(r))
+ {
+ std::pair<double, mln_psite(N)> p(dt(r),r);
+ Q = insertDicho(Q, p);
+ }
+ }
+ }
+
+ }
+ return X;
+}
+
+ image2d<value::int_u8> intImage(image2d<bool> pic)
+{
+ int w = geom::ncols(pic);
+ int h = geom::nrows(pic);
+
+ image2d<value::int_u8> out(h,w);
+ for(int i=0; i<w; i++)
+ for(int j=0; j<h; j++)
+ {
+ if(pic.at(j,i))
+ out.at(j,i) = 1;
+ else
+ out.at(j,i) = 0;
+ }
+ return out;
+}
+ image2d<bool> filteredSkeleton(image2d<bool> pic, const neighb2d& nbh, uint r, uint alpha, bool local)
+ {
+ using value::int_u8;
+
+ typedef image2d<bool> I;
+ typedef p_set<point2d> S;
+
+ image2d<value::int_u8> pic1 = intImage(pic);
+ image2d<value::int_u8> dt = sedt(pic1);
+
+ mln::io::pgm::save(dt, "dt.pgm");
+
+ int w = geom::ncols(pic);
+ int h = geom::nrows(pic);
+ int l= math::min(w, h);
+ uint rmax = getRMax(dt);
+ uint rknown = 0;
+ p_set<point2d> X,Y,Z;
+ p_set<point2d> X_complement, Z_complement;
+
+ image2d<value::int_u8> DTg(l,l,0);
+ std::vector< std::vector<int> > Mgl;
+ std::vector< std::vector<int> > Lut;
+
+ Mgl = CompLutMask (DTg,Mgl,Lut,l,0,rmax);
+
+ rknown =rmax;
+
+ mln_fwd_piter_(image2d<bool>) p(pic.domain());
+
+ for_all(p)
+ {
+ if (pic(p)==1)
+ {
+ X.insert(p);
+ }
+ else
+ {
+ X_complement.insert(p);
+ }
+ }
+ std::cout << " medial axis " << std::endl;
+ pic = MA(pic, Mgl, dt, Lut);
+
+ mln::io::pbm::save(pic, "ma.pbm");
+
+ for_all(p)
+ {
+ if (pic(p)==1)
+ {
+ Y.insert(p);
+ }
+ }
+
+ std::cout << " euclidean skeleton " << std::endl;
+ Z = euclideanSkeleton(X, X_complement, dt, Y, nbh, local);
+
+ sub_image<I, S> es = pic | Z;
+ I es1(pic.domain());
+ level::fill(es1, false);
+
+ level::paste(es, es1);
+
+ mln::io::pbm::save(es1, "euclidean.pbm");
+
+ for_all(p)
+ {
+ if (!Z.has(p))
+ {
+ Z_complement.insert(p);
+ }
+ }
+ std::cout << " discrete bisector " << std::endl;
+ pic1 = DiscreteBisector(dt, Y, nbh, rmax);
+
+
+ mln::io::pgm::save(pic1, "bisector.pgm");
+
+ uint cpt=0;
+ while (cpt!=Y.nsites())
+ {
+ if (dt(Y[cpt])>=r && pic1(Y[cpt])>=alpha)
+ {
+ cpt++;
+ }
+ else
+ {
+ Y.remove(Y[cpt]);
+ }
+ }
+
+
+ sub_image<I, S> skel = pic | Y;
+ I test(pic.domain());
+ level::fill(test, false);
+
+ level::paste(skel, test);
+
+ mln::io::pbm::save(test, "Y.pbm");
+
+ std::cout << " ultimate skeleton " << std::endl;
+ Z = ultimateSkeleton(Z, Z_complement, dt, Y, nbh, local);
+
+
+
+ sub_image<I, S> skeleton = pic | Z;
+ I output(pic.domain());
+ level::fill(output, false);
+
+ level::paste(skeleton, output);
+
+ return output;
+ }
+
+} // End of namespace mln
+#endif // ! SKELETON_HH
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc (revision 2670)
@@ -0,0 +1,30 @@
+
+#include <mln/core/alias/point2d.hh>
+#include "skeleton.hh"
+#include <mln/level/paste.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/sub_image.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/io/pbm/load.hh>
+
+
+int main(int argc, char* argv[])
+{
+ if(argc!=5)
+ {
+ std::cout << "arguments: filename voisinage R alpha" << std::endl;
+ exit(1);
+ }
+ image2d<bool> output;
+ std::string filename = argv[1];
+ int r = atoi(argv[3]);
+ int alpha = atoi(argv[4]);
+
+ image2d<bool> pic = io::pbm::load(filename);
+ if(atoi(argv[2])==4)
+ output = filteredSkeleton( pic, c4(), r, alpha, true);
+ else
+ output = filteredSkeleton( pic, c8(), r, alpha, true);
+ mln::io::pbm::save(output, "FS-"+std::string(argv[2])+"_"+std::string(argv[3])+"_"+std::string(argv[4])+"_"+filename);
+}
1
0
URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-24 Jimmy Ma <jimmy.ma(a)lrde.epita.fr>
Update OCR using tesseract.
* garrigues/ocr/enlarge.hh: New.
New enlargement algorithm better than the naive resize.
* garrigues/ocr/ocr.cc: Provide sample code to link milena against
tesseract.
---
enlarge.hh | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ocr.cc | 91 ++++++++++++++++++++++++++++++++++++++-------
2 files changed, 198 insertions(+), 14 deletions(-)
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr.cc (revision 2668)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr.cc (revision 2669)
@@ -36,40 +36,103 @@
#include <mln/value/int_u8.hh>
#include "resize.hh"
-#include <mln/linear/convolve.hh>
+#include "enlarge.hh"
+//#include "skeleton.hh"
#include <mln/linear/gaussian.hh>
#include <mln/trace/all.hh>
-#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
#include <mln/core/alias/w_window2d_float.hh>
+#include <mln/debug/println.hh>
+#include <mln/geom/chamfer.hh>
+#include <mln/make/win_chamfer.hh>
+#include <mln/labeling/regional_maxima.hh>
+#include <mln/morpho/dilation.hh>
+
+#include <tesseract/baseapi.h>
+
+// _COMPILATION_
+// g++ -DNDEBUG -O3 -I../../.. ocr.cc -L/usr/lib -ltesseract_full -lpthread
+
+
+// Call tesseract
+// lang: expected language
+template <typename T>
+char* tesseract(const char* lang, const mln::image2d<T>& input)
+{
+ TessBaseAPI::InitWithLanguage(NULL, NULL, lang, NULL, false, 0, NULL);
+ char* s = TessBaseAPI::TesseractRect(
+ (unsigned char*) input.buffer(),
+ sizeof (T),
+ input.ncols() * sizeof (T),
+ 0, 0,
+ input.ncols(),
+ input.nrows());
+ return s;
+}
int main(int argc, char** argv)
{
- mln::trace::quiet = false;
-
using namespace mln;
using value::int_u8;
image2d<bool> input;
- image2d<int_u8> output;
- image2d<int_u8> output2;
- if (argc != 3)
+ if (argc < 2)
return 1;
-
+ mln::border::thickness = 0;
io::pbm::load(input, argv[1]);
+ std::cout << "> without any preprocessing." << std::endl;
+ char* s = tesseract("fra", input);
+ std::cout << s;
+ free(s);
+
+ //
+ // PREPROCESS !!
+ //
+ // Resize
+// output2 = geom::resize(cast_image<int_u8>(input), 3);
+ image2d<int_u8> output = enlarge(input, 1);
+
+ // TODO CLEANUP
+#if 0
+ // Blur.
+ image2d<int_u8> output;
+ initialize(output, output2);
+ linear::gaussian(output2, 1, output);
+#endif
+
+#if 0
+ // Threshold
+ mln_piter_(image2d<unsigned>) p(output.domain());
+ for_all(p)
+ {
+ output(p) = output(p) > 127 ? 1 : 0;
+ }
+#endif
- // Step 1: Enlarge input.
- output = geom::resize(cast_image<int_u8>(input), 4);
+#if 0
+ // Compute chamfer distance map.
+ const w_window2d_int& w_win = make::mk_chamfer_3x3_int<8, 0> ();
+ image2d<unsigned> out = geom::chamfer(output, w_win, 255);
+
+ for_all(p)
+ {
+ out(p) = out(p) > 10 ? 255 : 0;
+ }
+#endif
- // Step 2: Blur.
- initialize(output2, output);
- linear::gaussian(output, 15, output2);
+ io::pgm::save(cast_image<int_u8>(output), argv[2]);
- io::pgm::save(output2, argv[2]);
+ std::cout << "> with preprocessing." << std::endl;
+ s = tesseract("fra", output);
+ std::cout << s;
+ free(s);
}
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh (revision 2669)
@@ -0,0 +1,121 @@
+#ifndef ENLARGE_HH
+# define ENLARGE_HH
+
+# include <iostream>
+
+# include <mln/core/image/image2d.hh>
+# include <mln/value/int_u8.hh>
+
+
+float val(bool b) { return b ? 1 : 0; }
+
+int do_threshold(float value)
+{
+ return 255.f * value;
+}
+
+
+mln::image2d<mln::value::int_u8>
+enlargex2(mln::image2d<bool> input)
+{
+ using namespace mln;
+ using value::int_u8;
+
+ unsigned nrows, ncols;
+
+ nrows = input.nrows();
+ ncols = input.ncols();
+
+ image2d<int_u8> output(2 * nrows, 2 * ncols);
+ float value;
+
+ // row 0
+
+ output.at(0, 0) = do_threshold(input.at(0, 0));
+
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(0, col / 2));
+ value += val(input.at(0, col / 2 - 1));
+ output.at(0, col) = do_threshold(value / 2);
+ }
+
+ for (int col = 1; col < output.ncols(); col += 2)
+ output.at(0, col) = do_threshold(input.at(0, col / 2));
+
+ // col 0
+
+ for (int row = 2; row < output.nrows(); row += 2)
+ {
+ value = val(input.at(row / 2, 0));
+ value += val(input.at(row / 2 - 1, 0));
+ output.at(row, 0) = do_threshold(value / 2);
+ }
+
+ for (int row = 1; row < output.nrows(); row += 2)
+ output.at(row, 0) = do_threshold(input.at(row / 2, 0));
+
+ // others
+
+ for (int row = 2; row < output.nrows(); row += 2)
+ {
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(row / 2, col / 2));
+ value += val(input.at(row / 2 - 1, col / 2));
+ value += val(input.at(row / 2, col / 2 - 1));
+ value += val(input.at(row / 2 - 1, col / 2 - 1));
+ output.at(row, col) = do_threshold(value / 4);
+ }
+ for (int col = 1; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(row / 2, col / 2));
+ value += val(input.at(row / 2 - 1, col / 2));
+ output.at(row, col) = do_threshold(value / 2);
+ }
+ }
+
+ for (int row = 1; row < output.nrows(); row += 2)
+ {
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(row / 2, col / 2));
+ value += val(input.at(row / 2, col / 2 - 1));
+ output.at(row, col) = do_threshold(value / 2);
+ }
+ for (int col = 1; col < output.ncols(); col += 2)
+ output.at(row, col) = do_threshold(input.at(row / 2, col / 2));
+ }
+
+ return output;
+}
+
+
+// enlarge 2^n times
+mln::image2d<mln::value::int_u8>
+enlarge(mln::image2d<bool> input, unsigned int n)
+{
+ using namespace mln;
+ using value::int_u8;
+
+ image2d<int_u8> output;
+
+ do
+ {
+ output = enlargex2(input);
+
+ if (--n > 0)
+ {
+ initialize(input, output);
+ mln_piter_(image2d<bool>) p(input.domain());
+ for_all(p)
+ input(p) = output(p) > 0;
+ }
+ else
+ break;
+ }
+ while (1);
+ return output;
+}
+
+#endif // ! ENLARGE_HH
1
0
cleanup-2008 2668: Update directional erosion so that it can now be used on sets.
by Thierry Geraud 23 Oct '08
by Thierry Geraud 23 Oct '08
23 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Update directional erosion so that it can now be used on sets.
* mln/accu/rank.hh (todo): New.
* mln/accu/rank_bool.hh (todo): New.
Fix doc.
(rank): Fix ctor.
(take_as_init): Fix.
* mln/accu/land.hh: New.
* mln/morpho/erosion.spe.hh
(erosion_directional_nd_functor),
(erosion_directional_nd_fastest_functor): Add accumulator type
as parameter and rename min as accu.
(erosion_directional_nd),
(erosion_directional_nd_fastest): Update; compute A.
(erosion_dispatch_wrt_win): Update overload for hline2d and
vline2d.
* mln/morpho/includes.hh: Update.
accu/land.hh | 81 ++++++++++++++++++++++++--------------------------
accu/rank.hh | 3 +
accu/rank_bool.hh | 18 +++++------
morpho/erosion.spe.hh | 58 ++++++++++++++++++-----------------
morpho/includes.hh | 2 +
5 files changed, 83 insertions(+), 79 deletions(-)
Index: mln/accu/rank.hh
--- mln/accu/rank.hh (revision 2667)
+++ mln/accu/rank.hh (working copy)
@@ -31,6 +31,9 @@
/*! \file mln/accu/rank.hh
*
* \brief Define an rank accumulator.
+ *
+ * \todo It should be renamed as rank_h since it relies on histogram
+ * (thus low quantization).
*/
# include <vector>
Index: mln/accu/rank_bool.hh
--- mln/accu/rank_bool.hh (revision 2667)
+++ mln/accu/rank_bool.hh (working copy)
@@ -28,16 +28,17 @@
#ifndef MLN_ACCU_RANK_BOOL_HH
# define MLN_ACCU_RANK_BOOL_HH
-/*! \file mln/accu/rankbool.hh
+/*! \file mln/accu/rank_bool.hh
*
* \brief Define an rank accumulator.
+ *
+ * \todo There is no-arg-ctor so this accumulator does not support
+ * deferred initialization!
+ *
+ * \todo Add untake routines...
*/
-# include <vector>
# include <mln/accu/internal/base.hh>
-# include <mln/core/concept/meta_accumulator.hh>
-# include <mln/trait/value_.hh>
-# include <mln/util/pix.hh>
namespace mln
@@ -49,7 +50,7 @@
// Fwd declaration.
template <typename T> struct rank;
- /*! \brief rank accumulator class for boolean.
+ /*! \brief rank accumulator class for Boolean.
*
*/
template <>
@@ -85,8 +86,7 @@
inline
rank<bool>::rank(unsigned k, unsigned n)
- : nfalse_(0),
- k_(k),
+ : k_(k),
n_(n)
{
mln_assertion(k_ < n_);
@@ -105,7 +105,7 @@
inline
void rank<bool>::take_as_init(const argument& t)
{
- nfalse_ += !t;
+ nfalse_ = t ? 0 : 1;
}
Index: mln/accu/land.hh
--- mln/accu/land.hh (revision 2667)
+++ mln/accu/land.hh (working copy)
@@ -25,19 +25,15 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_ACCU_RANK_BOOL_HH
-# define MLN_ACCU_RANK_BOOL_HH
+#ifndef MLN_ACCU_LAND_HH
+# define MLN_ACCU_LAND_HH
-/*! \file mln/accu/rankbool.hh
+/*! \file mln/accu/land.hh
*
- * \brief Define an rank accumulator.
+ * \brief Define a 'logical-and' accumulator.
*/
-# include <vector>
# include <mln/accu/internal/base.hh>
-# include <mln/core/concept/meta_accumulator.hh>
-# include <mln/trait/value_.hh>
-# include <mln/util/pix.hh>
namespace mln
@@ -46,25 +42,23 @@
namespace accu
{
- // Fwd declaration.
- template <typename T> struct rank;
-
- /*! \brief rank accumulator class for boolean.
- *
- */
- template <>
- struct rank<bool> : public mln::accu::internal::base< bool, rank<bool> >
+ /// "Logical-and" accumulator class.
+ struct land : public mln::accu::internal::base< bool, land >
{
typedef bool argument;
- rank(unsigned k, unsigned n);
+ land();
/// Manipulators.
/// \{
void init();
void take_as_init(const argument& t);
+
void take(const argument& t);
- void take(const rank<bool>& other);
+ void take(const land& other);
+
+ void untake(const argument& t);
+ void untake(const land& other);
/// \}
/// Get the value of the accumulator.
@@ -76,67 +70,71 @@
protected:
unsigned nfalse_;
- unsigned k_; // 0 <= k_ < n
- unsigned n_;
};
# ifndef MLN_INCLUDE_ONLY
inline
- rank<bool>::rank(unsigned k, unsigned n)
- : nfalse_(0),
- k_(k),
- n_(n)
+ land::land()
{
- mln_assertion(k_ < n_);
init();
}
-
inline
void
- rank<bool>::init()
+ land::init()
{
nfalse_ = 0;
}
-
inline
- void rank<bool>::take_as_init(const argument& t)
+ void land::take_as_init(const argument& t)
{
- nfalse_ += !t;
+ nfalse_ = t ? 0 : 1;
}
-
inline
- void rank<bool>::take(const argument& t)
+ void land::take(const argument& t)
{
- nfalse_ += !t;
+ if (t == false)
+ ++nfalse_;
}
-
inline
void
- rank<bool>::take(const rank<bool>& other)
+ land::take(const land& other)
{
nfalse_ += other.nfalse_;
}
+ inline
+ void land::untake(const argument& t)
+ {
+ if (t == false)
+ --nfalse_;
+ }
+
+ inline
+ void
+ land::untake(const land& other)
+ {
+ mln_precondition(other.nfalse_ <= nfalse_);
+ nfalse_ -= other.nfalse_;
+ }
inline
bool
- rank<bool>::to_result() const
+ land::to_result() const
{
- mln_assertion(nfalse_ <= n_);
- return k_ >= nfalse_;
+ return nfalse_ == 0;
}
inline
bool
- rank<bool>::is_valid() const
+ land::is_valid() const
{
- return nfalse_ <= n_;
+ return true;
}
# endif // ! MLN_INCLUDE_ONLY
@@ -145,5 +143,4 @@
} // end of namespace mln
-
-#endif // ! MLN_ACCU_RANK_BOOL_HH
+#endif // ! MLN_ACCU_AND_HH
Index: mln/morpho/erosion.spe.hh
--- mln/morpho/erosion.spe.hh (revision 2667)
+++ mln/morpho/erosion.spe.hh (working copy)
@@ -636,7 +636,7 @@
return dp;
}
- template <typename I_, typename W>
+ template <typename I_, typename W, typename A>
struct erosion_directional_nd_functor
{
typedef I_ I;
@@ -645,7 +645,7 @@
const I& input;
const W& win;
mln_concrete(I) output;
- accu::min_h<mln_value(I)> min;
+ A accu;
enum { dim = I::site::dim };
mln_psite(I) p;
@@ -662,7 +662,7 @@
erosion_directional_nd_functor(const I& input, const W& win, int dir)
: input(input),
win(win),
- min(),
+ accu(),
dir(dir),
win_left(win::shift(win, -dp_directional<dpsite>(dir)) - win),
win_right(win - win::shift(win, -dp_directional<dpsite>(dir))),
@@ -675,27 +675,27 @@
void init()
{
// FIXME: border::adjust(input, win.delta());
- extension::fill(input, mln_max(mln_value(I)));
+ extension::fill(input, accu);
initialize(output, input);
}
void init_run()
{
- min.init();
+ accu.init();
p[dir]--;
mln_qiter(W) q(win, p);
for_all(q) if (input.has(q))
- min.take(input(q));
+ accu.take(input(q));
p[dir]++;
}
void next()
{
for_all(q_l) if (input.has(q_l))
- min.untake(input(q_l));
+ accu.untake(input(q_l));
for_all(q_r) if (input.has(q_r))
- min.take(input(q_r));
- output(p) = min;
+ accu.take(input(q_r));
+ output(p) = accu;
}
void final()
@@ -711,7 +711,11 @@
{
trace::entering("morpho::impl:erosion_directional_nd");
- typedef erosion_directional_nd_functor<I, W> F;
+ typedef mlc_is(mln_trait_image_kind(I),
+ trait::image::kind::binary) is_binary;
+ typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A;
+
+ typedef erosion_directional_nd_functor<I, W, A> F;
F f(exact(input), exact(win), dir);
canvas::browsing::directional(f);
@@ -721,7 +725,7 @@
}
- template <typename I_, typename W>
+ template <typename I_, typename W, typename A>
struct erosion_directional_nd_fastest_functor
{
typedef I_ I;
@@ -730,7 +734,7 @@
const I& input;
const W& win;
mln_concrete(I) output;
- accu::min_h<mln_value(I)> min;
+ A accu;
mln_psite(I) p;
enum { dim = I::site::dim };
@@ -743,7 +747,7 @@
erosion_directional_nd_fastest_functor(const I& input, const W& win, unsigned dir)
: input(input),
win(win),
- min(),
+ accu(),
dir(dir),
win_left(win::shift(win, -dp_directional<dpsite>(dir)) - win),
win_right(win - win::shift(win, -dp_directional<dpsite>(dir))),
@@ -755,27 +759,27 @@
void init()
{
// FIXME: border::adjust(input, win.delta());
- extension::fill(input, mln_max(mln_value(I)));
+ extension::fill(input, accu);
initialize(output, input);
}
void next()
{
for_all(q_l)
- min.untake(q_l.val());
+ accu.untake(q_l.val());
for_all(q_r)
- min.take(q_r.val());
- output(p) = min;
+ accu.take(q_r.val());
+ output(p) = accu;
}
void init_run()
{
- min.init();
+ accu.init();
p[dir]--;
mln_qixter(const I, W) q(input, win, p);
for_all(q)
- min.take(q.val());
+ accu.take(q.val());
p[dir]++;
}
@@ -793,7 +797,11 @@
{
trace::entering("morpho::impl:erosion_directional_nd_fastest");
- typedef erosion_directional_nd_fastest_functor<I, W> F;
+ typedef mlc_is(mln_trait_image_kind(I),
+ trait::image::kind::binary) is_binary;
+ typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A;
+
+ typedef erosion_directional_nd_fastest_functor<I, W, A> F;
F f(exact(input), exact(win), dir);
canvas::browsing::directional(f);
@@ -1400,13 +1408,10 @@
return erosion_dispatch_for_generic(input, win);
else
{
- typedef mlc_is_not(mln_trait_image_kind(I),
- mln::trait::image::kind::logic) test_not_logic;
typedef mlc_is_a(mln_pset(I), Box) test_box;
typedef mlc_equal(mln_trait_image_quant(I),
mln::trait::image::quant::low) test_lowq;
- typedef mlc_and(test_not_logic, test_box) temp;
- typedef mlc_and(temp, test_lowq) tests;
+ typedef mlc_and(test_box, test_lowq) tests;
return erosion_dispatch_wrt_win(typename tests::eval (),
input, win);
}
@@ -1445,13 +1450,10 @@
return erosion_dispatch_for_generic(input, win);
else
{
- typedef mlc_is_not(mln_trait_image_kind(I),
- mln::trait::image::kind::logic) test_not_logic;
typedef mlc_is_a(mln_pset(I), Box) test_box;
typedef mlc_equal(mln_trait_image_quant(I),
mln::trait::image::quant::low) test_lowq;
- typedef mlc_and(test_not_logic, test_box) temp;
- typedef mlc_and(temp, test_lowq) tests;
+ typedef mlc_and(test_box, test_lowq) tests;
return erosion_dispatch_wrt_win(typename tests::eval (),
input, win);
}
Index: mln/morpho/includes.hh
--- mln/morpho/includes.hh (revision 2667)
+++ mln/morpho/includes.hh (working copy)
@@ -44,6 +44,8 @@
# include <mln/value/ops.hh>
+# include <mln/accu/land.hh>
+// # include <mln/accu/lor.hh>
# include <mln/accu/min.hh>
# include <mln/accu/max.hh>
# include <mln/accu/min_h.hh>
1
0
* scribo/demat.hh: Fix a endless loop.
---
milena/sandbox/ChangeLog | 6 +++
milena/sandbox/scribo/demat.hh | 95 +++++++++++++++++++++++++++++++++++-----
2 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog
index 512eac2..9faa0a9 100644
--- a/milena/sandbox/ChangeLog
+++ b/milena/sandbox/ChangeLog
@@ -1,3 +1,9 @@
+2008-10-23 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Fix an endless loop.
+
+ * scribo/demat.hh: Fix a endless loop.
+
2008-10-22 Maxime van Noppen <yabo(a)lrde.epita.fr>
Work on ICCVG04 for INIM.
diff --git a/milena/sandbox/scribo/demat.hh b/milena/sandbox/scribo/demat.hh
index a6985d5..5f01993 100644
--- a/milena/sandbox/scribo/demat.hh
+++ b/milena/sandbox/scribo/demat.hh
@@ -100,6 +100,13 @@ namespace scribo
using value::rgb8;
+ void draw_component_boxes(image2d<rgb8>& output, const util::array<box2d>& boxes)
+ {
+ for (unsigned i = 1; i < boxes.nelements(); ++i)
+ if (boxes[i].is_valid())
+ draw::box(output, boxes[i], literal::red);
+ }
+
template <typename V>
void save_lbl_image(const image2d<V>& lbl, unsigned nlabels,
const char *filename)
@@ -126,6 +133,14 @@ namespace scribo
return level::transform(input, fconvert);
}
+ void negate(image2d<bool>& in)
+ {
+ fun::i2v::array<unsigned> negate(2);
+ negate(0) = 1;
+ negate(1) = 0;
+ level::apply(in, negate);
+ }
+
/// Functions related to the table removal
/// \{
@@ -207,8 +222,8 @@ namespace scribo
#ifndef NOUT
image2d<rgb8> tmp = clone(output);
- erase_table_boxes(tmp, vboxes, n);
- erase_table_boxes(tmp, hboxes, n);
+ draw_component_boxes(tmp, vboxes);
+ draw_component_boxes(tmp, hboxes);
io::ppm::save(tmp, "./table-filtered.ppm");
#endif
@@ -222,6 +237,7 @@ namespace scribo
/// Function related to text extraction
/// \{
+ inline
int_u16
most_left(const fun::i2v::array<int_u16>& left_link, unsigned i)
{
@@ -230,6 +246,15 @@ namespace scribo
return i;
}
+ inline
+ int_u16
+ uncurri_left_link(const fun::i2v::array<int_u16>& left_link, unsigned i)
+ {
+ if (left_link(i) != i)
+ left_link(i) = most_left(left_link, left_link(i));
+ return left_link(i);
+ }
+
template <typename V>
void
remove_small_comps_i2v(image2d<V>& lbl,
@@ -276,12 +301,14 @@ namespace scribo
tboxes.resize(ncomp + 1);
for (unsigned i = 1; i <= ncomp; ++i)
{
- if (left_link(i) != i)
- left_link(i) = most_left(left_link, left_link(i));
- tboxes[left_link(i)].take(cboxes[i]);
+ //if (left_link(i) != i)
+ // left_link(i) = most_left(left_link, left_link(i));
+ tboxes[most_left(left_link, i)].take(cboxes[i]);
}
//Update labels
+ for (unsigned i = 1; i <= ncomp; ++i)
+ uncurri_left_link(left_link, i);
level::apply(lbl, left_link);
#ifndef NOUT
@@ -290,7 +317,8 @@ namespace scribo
util::array<box2d> result;
for (unsigned i = 1; i <= ncomp; ++i)
- result.append(tboxes[i].to_result());
+ if (tboxes[i].is_valid())
+ result.append(tboxes[i].to_result());
return result;
}
@@ -305,7 +333,7 @@ namespace scribo
if (lbl.domain().has(p) && lbl(p) != 0 && lbl(p) != i
&& (p.col() - c.col()) < dmax)
{
- if (left_link(lbl(p)) == lbl(p))
+ if (left_link(lbl(p)) == lbl(p) && most_left(left_link, i) != lbl(p))
left_link(lbl(p)) = i;
// else
// left_link(lbl(p)) = 0;//FIXME: should be uncommented?
@@ -350,7 +378,39 @@ namespace scribo
return left_link;
}
+/*
+ void merge_bboxes(util::array<box2d>& cboxes,
+ image2d<int_u16>& lbl, unsigned &nlabels)
+ {
+ fun::i2v::array<int_u16> merge;
+ unsigned current = 1;
+ for (unsigned i = 1; i <= nlabels;)
+ {
+ unsigned midcol = (cboxes[i].pmax().col() - cboxes[i].pmin().col()) / 2;
+ /// FIXME: Box center => Routine?
+ point2d c (cboxes[i].pmin().row()
+ + ((cboxes[i].pmax().row() - cboxes[i].pmin().row()) / 2),
+ cboxes[i].pmin().col() + midcol);
+ /// First site on the right of the center site
+ point2d p(c.row(), c.col() + 1);
+
+ // FIXME: Lemmings with a condition on the distance => write a special version?
+ while (lbl.domain().has(p) && (lbl(p) == 0 || lbl(p) == i)
+ && (p.col() - c.col()) <= midcol)
+ ++p.col();
+
+ if (lbl.domain().has(p) && lbl(p) != 0 && lbl(p) != i
+ && (p.col() - c.col()) <= midcol)
+ {
+
+ }
+ }
+
+ level::apply(lbl, merge);
+ cboxes.resize(nlabels);
+ }
+*/
util::array<box2d>
extract_text(image2d<bool>& in,
@@ -373,6 +433,14 @@ namespace scribo
boxes_t cboxes = labeling::compute(accu::meta::bbox(), lbl, nlabels);
+#ifndef NOUT
+ image2d<rgb8> tmp = clone(output);
+ draw_component_boxes(tmp, cboxes);
+ io::ppm::save(tmp, "character-bboxes.ppm");
+#endif
+
+ //merge_bboxes(cboxes, lbl, nlabels);
+
//Link character bboxes to their left neighboor if possible.
fun::i2v::array<int_u16> left =
link_character_bboxes(lbl, cboxes, nlabels, bbox_distance);
@@ -407,6 +475,12 @@ namespace scribo
//Load image
image2d<bool> in;
io::pbm::load(in, argv[1]);
+ internal::negate(in);
+
+#ifndef NOUT
+ io::pbm::save(in, "in-neg.pbm");
+#endif
+
image2d<rgb8> output = internal::to_color(in);
internal::extract_tables(in, output, l, bbox_larger);
@@ -414,13 +488,12 @@ namespace scribo
util::array<box2d> tboxes =
internal::extract_text(in, output, bbox_distance, min_comp_size);
- for (unsigned i = 1; i < tboxes.nelements(); ++i)
- if (tboxes[i].is_valid())
- draw::box(output, tboxes[i], literal::red);
+ internal::draw_component_boxes(output, tboxes);
io::ppm::save(output, argv[2]);
/// Use txt bboxes here with Tesseract
- /// => in | tboxes[i]
+ /// for (i = 1; i < tboxes.nelements(); ++i)
+ /// tesseract(in | tboxes[i])
}
} // end of namespace scribo
--
1.5.6.5
1
0
* mln/io/off/load.hh (mln::io::off:load): Ensure the end of the
file is reached.
---
milena/ChangeLog | 7 +++++++
milena/mln/io/off/load.hh | 11 +++++++++++
2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 4d2c9e9..2c8f00d 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,12 @@
2008-10-23 Roland Levillain <roland(a)lrde.epita.fr>
+ Improve mln::io::off:load.
+
+ * mln/io/off/load.hh (mln::io::off:load): Ensure the end of the
+ file is reached.
+
+2008-10-23 Roland Levillain <roland(a)lrde.epita.fr>
+
Adjust I/O routines to algebraic faces.
* mln/io/off/load.hh (mln::io::off::load): Adjust.
diff --git a/milena/mln/io/off/load.hh b/milena/mln/io/off/load.hh
index 38e6b6e..60c534b 100644
--- a/milena/mln/io/off/load.hh
+++ b/milena/mln/io/off/load.hh
@@ -264,6 +264,17 @@ namespace mln
// Image.
ima.init_(pc, values);
+ /*--------------.
+ | End of file. |
+ `--------------*/
+
+ istr >> internal::eat_comment;
+ if (!istr.eof())
+ {
+ std::cerr << me << ": `" << filename
+ << "': end of file not reached" << std::endl;
+ std::exit(1);
+ }
istr.close();
}
--
1.5.6.5
1
0
* mln/io/off/load.hh (mln::io::off::load): Adjust.
---
milena/ChangeLog | 6 ++++++
milena/mln/io/off/load.hh | 6 ++++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index e32143d..4d2c9e9 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,11 @@
2008-10-23 Roland Levillain <roland(a)lrde.epita.fr>
+ Adjust I/O routines to algebraic faces.
+
+ * mln/io/off/load.hh (mln::io::off::load): Adjust.
+
+2008-10-23 Roland Levillain <roland(a)lrde.epita.fr>
+
Convert iterators on complexes to algebraic faces.
* mln/topo/internal/complex_relative_iterator_base.hh
diff --git a/milena/mln/io/off/load.hh b/milena/mln/io/off/load.hh
index 6cdf3d5..38e6b6e 100644
--- a/milena/mln/io/off/load.hh
+++ b/milena/mln/io/off/load.hh
@@ -220,14 +220,16 @@ namespace mln
topo::n_face<0, D> vertex(c, vertex_id);
topo::n_face<0, D> next_vertex(c, next_vertex_id);
// The current edge.
- topo::n_face<1, D> edge;
+ topo::algebraic_n_face<1, D> edge;
// If the edge has been constructed yet, create it;
// otherwise, retrieve its id from the complex.
if (!complex_edges[vertex_id][next_vertex_id])
{
complex_edges[vertex_id][next_vertex_id] = true;
complex_edges[next_vertex_id][vertex_id] = true;
- edge = c.add_face(vertex + next_vertex);
+ edge =
+ make_algebraic_n_face(c.add_face(vertex - next_vertex),
+ true);
}
else
{
--
1.5.6.5
1
0