LRE
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
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
List overview
Download
Olena-patches
October 2008
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
olena-patches@lrde.epita.fr
14 participants
373 discussions
Start a n
N
ew thread
r2674: Enhance the build-system
by Maxime van Noppen
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
16 years, 2 months
1
0
0
0
cleanup-2008 2673: Add bijective functors, 2-way functors and meta-fun.
by Alexandre Abraham
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>
16 years, 2 months
1
0
0
0
cleanup-2008 2672: De-activate not compiling tests in level transform.
by Thierry Geraud
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; }
16 years, 2 months
1
0
0
0
cleanup-2008 2671: Add a processing chain about segmentation on edges.
by Thierry Geraud
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; +}
16 years, 2 months
1
0
0
0
r2670: Fix the skeleton algorithm introduced by aroumougame
by Jimmy Ma
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); +}
16 years, 2 months
1
0
0
0
r2669: Update OCR using tesseract
by Jimmy Ma
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
16 years, 2 months
1
0
0
0
cleanup-2008 2668: Update directional erosion so that it can now be used on sets.
by Thierry Geraud
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>
16 years, 2 months
1
0
0
0
2667: Fix an endless loop.
by Guillaume Lazzara
* 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
16 years, 2 months
1
0
0
0
2666: Improve mln::io::off:load.
by Roland Levillain
* 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
16 years, 2 months
1
0
0
0
2665: Adjust I/O routines to algebraic faces.
by Roland Levillain
* 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
16 years, 2 months
1
0
0
0
← Newer
1
...
11
12
13
14
15
16
17
...
38
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Results per page:
10
25
50
100
200