Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
April 2009
- 11 participants
- 187 discussions
* icdar/2009/hsc/clean_lines_with_grouped_bboxes.hh: new routine.
---
milena/sandbox/ChangeLog | 6 +
.../2009/hsc/clean_lines_with_grouped_bboxes.hh | 104 ++++++++++++++++++++
2 files changed, 110 insertions(+), 0 deletions(-)
create mode 100644 milena/sandbox/icdar/2009/hsc/clean_lines_with_grouped_bboxes.hh
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog
index 3dcb53c..cb72928 100644
--- a/milena/sandbox/ChangeLog
+++ b/milena/sandbox/ChangeLog
@@ -1,3 +1,9 @@
+2009-04-08 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Add a new variant of clean_lines.
+
+ * icdar/2009/hsc/clean_lines_with_grouped_bboxes.hh: new routine.
+
2009-04-08 Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Update.
diff --git a/milena/sandbox/icdar/2009/hsc/clean_lines_with_grouped_bboxes.hh b/milena/sandbox/icdar/2009/hsc/clean_lines_with_grouped_bboxes.hh
new file mode 100644
index 0000000..8942e83
--- /dev/null
+++ b/milena/sandbox/icdar/2009/hsc/clean_lines_with_grouped_bboxes.hh
@@ -0,0 +1,104 @@
+#ifndef CLEAN_LINESWITH_GROUPED_BBOXES_HH
+# define CLEAN_LINESWITH_GROUPED_BBOXES_HH
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/labeling/background.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/value/label_8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/all.hh>
+#include <mln/labeling/compute.hh>
+#include <mln/pw/all.hh>
+#include <mln/core/image/image_if.hh>
+#include <mln/data/fill.hh>
+#include <mln/literal/colors.hh>
+#include <mln/logical/not.hh>
+#include "label_maj.hh"
+
+#include <scribo/text/grouping/group_with_single_left_link.hh>
+#include <scribo/text/grouping/group_with_single_right_link.hh>
+#include <scribo/text/grouping/group_from_double_link.hh>
+#include <scribo/make/text.hh>
+#include <scribo/util/text.hh>
+#include <scribo/debug/save_textbboxes_image.hh>
+
+namespace mln
+{
+
+ template <typename I, typename L>
+ mln_concrete(L)
+ clean_lines_with_grouped_bboxes(const Image<I>& input,
+ const Image<L>& lines_,
+ float maj_threshold);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I, typename L>
+ mln_concrete(L)
+ clean_lines_with_grouped_bboxes(const Image<I>& input,
+ const Image<L>& lines_,
+ float maj_threshold)
+ {
+ trace::entering("clean_lines_with_grouped_bboxes");
+
+ const L& lines = exact(lines_);
+ mln_precondition(lines.is_valid());
+ typedef value::label_16 LV;
+
+ LV nlabels;
+ scribo::util::text<mln_ch_value(I,LV)>
+ text = scribo::make::text(logical::not_(input), c8(), nlabels);
+
+ //Link character bboxes to their left neighboor if possible.
+ mln::util::array<unsigned>
+ left_link = scribo::text::grouping::group_with_single_left_link(text, 30);
+ mln::util::array<unsigned>
+ right_link = scribo::text::grouping::group_with_single_right_link(text, 30);
+
+ text = scribo::text::grouping::group_from_double_link(text,
+ left_link,
+ right_link);
+
+
+// mln_ch_value(L,LV) lbl = labeling::background(input, c8(), nlabels);
+// util::array<box<mln_site(L)> >
+// bboxes = labeling::compute(accu::meta::bbox(), lbl, nlabels);
+
+ nlabels = text.nbboxes();
+ const image2d<value::label_16>& lbl = text.label_image();
+ util::array<box<mln_site(L)> >
+ bboxes = labeling::compute(accu::meta::bbox(), lbl, nlabels);
+ text.bboxes() = bboxes;
+ scribo::debug::save_textbboxes_image(input, text.bboxes(), literal::red, "plop.ppm");
+
+ /// Compute the most represented label for each component.
+ accu::label_maj<LV, mln_value(L)> accu(nlabels.next());
+ mln_piter(image2d<mln_value(L)>) p(lbl.domain());
+ for_all(p)
+ if (lines(p) != 0u)
+ accu.take(lbl(p), lines(p));
+
+ mln_concrete(L) output = duplicate(lines);
+
+ // Rebuild components.
+ util::array<util::couple<mln_value(L), float> > res = accu.to_result();
+ for (unsigned i = 1; i < res.nelements(); ++i)
+ if (res[i].second() >= maj_threshold)
+ data::fill(((output | bboxes[i]).rw()
+ | (pw::value(lbl) == pw::cst(i))).rw(),
+ res[i].first());
+// else
+// std::cout << res[i].first() << " - " << res[i].second() << std::endl;
+
+ trace::exiting("clean_lines_with_grouped_bboxes");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+#endif // CLEAN_LINESWITH_GROUPED_BBOXES_HH
--
1.5.6.5
1
0
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Update.
* icdar/2009/hsc/clean_input.cc: New.
* icdar/2009/hsc/clean_input.hh: New.
* icdar/2009/hsc/lines_to_boxes.cc: New.
* icdar/2009/hsc/line_to_words.hh: Remove blank line.
* icdar/2009/hsc/io/icdar/save.hh: Fix warning.
* icdar/2009/hsc/ws_to_wsl.hh: Add log.
* icdar/2009/hsc/input_to_wsl.cc: Split into...
* icdar/2009/hsc/input_to_lines_dat.cc,
* icdar/2009/hsc/input_to_ws.hh: ...these new files.
* icdar/2009/hsc/line_to_words.cc: Rename as...
* icdar/2009/hsc/dummy_input_to_words_dat.cc: ...this.
clean_input.cc | 41 +++++++++++++++++
clean_input.hh | 45 +++++++++++++++++++
dummy_input_to_words_dat.cc | 59 ++++++++++++++++++++++++
input_to_lines_dat.cc | 87 ++++++++++++++++++++++++++++++++++++
input_to_ws.hh | 104 +++++++-------------------------------------
input_to_wsl.cc | 93 +++++----------------------------------
io/icdar/save.hh | 3 -
line_to_words.hh | 1
lines_to_boxes.cc | 54 ++++++++++++++++++++++
ws_to_wsl.hh | 42 +++++++++++++++++
10 files changed, 360 insertions(+), 169 deletions(-)
Index: icdar/2009/hsc/clean_input.cc
--- icdar/2009/hsc/clean_input.cc (revision 0)
+++ icdar/2009/hsc/clean_input.cc (revision 0)
@@ -0,0 +1,41 @@
+#include <sandbox/icdar/2009/hsc/clean_input.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+
+
+
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pbm output.pbm" << std::endl
+ << " HSC @ ICDAR'2009" << std::endl
+ << " input.pbm: input 2D binary image (text is black; background is white)" << std::endl
+ << " output.pbm: cleaned input." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 3)
+ usage(argv);
+
+
+ trace::entering("main");
+
+
+ image2d<bool> input;
+
+ io::pbm::load(input, argv[1]);
+ io::pbm::save(clean_input(input),
+ argv[2]);
+
+ trace::exiting("main");
+}
Index: icdar/2009/hsc/clean_input.hh
--- icdar/2009/hsc/clean_input.hh (revision 0)
+++ icdar/2009/hsc/clean_input.hh (revision 0)
@@ -0,0 +1,45 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/value/label_16.hh>
+
+#include <mln/labeling/background.hh>
+#include <mln/labeling/compute.hh>
+#include <mln/accu/count.hh>
+#include <mln/accu/bbox.hh>
+
+#include <mln/fun/i2v/array.hh>
+#include <mln/level/transform.hh>
+
+
+namespace mln
+{
+
+ image2d<bool>
+ clean_input(const image2d<bool>& input)
+ {
+ int max_col = input.domain().pmax().col();
+
+ typedef value::label_16 L;
+ L nlabels;
+ image2d<L> lab = labeling::background(input, c8(), nlabels);
+ util::array<unsigned> count = labeling::compute(accu::count<point2d>(), lab, nlabels);
+ util::array<box2d> box = labeling::compute(accu::bbox<point2d>(), lab, nlabels);
+
+ fun::i2v::array<bool> ok(nlabels.next(), false); // default is text
+ ok(0) = true; // bg is 'white'
+ for (L l = 1; l <= nlabels; ++l)
+ {
+ if (count[l] <= 3)
+ {
+ ok(l) = true; // into bg
+ continue;
+ }
+ int center_col = box[l].center().col();
+ if (center_col >= max_col - 3 ||
+ center_col <= 3)
+ ok(l) = true;
+ }
+ return level::transform(lab, ok);
+ }
+
+} // mln
Index: icdar/2009/hsc/lines_to_boxes.cc
--- icdar/2009/hsc/lines_to_boxes.cc (revision 0)
+++ icdar/2009/hsc/lines_to_boxes.cc (revision 0)
@@ -0,0 +1,54 @@
+#include <mln/labeling/compute.hh>
+#include <mln/util/array.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/literal/colors.hh>
+#include <mln/level/convert.hh>
+
+#include <mln/value/label_8.hh>
+#include <mln/estim/min_max.hh>
+#include <mln/core/image/violent_cast_image.hh>
+#include <mln/core/var.hh>
+
+#include <scribo/draw/bounding_boxes.hh>
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm output.ppm" << std::endl
+ << " HSC @ ICDAR'2009" << std::endl
+ << " input.pgm: labeled lines" << std::endl
+ << " output.ppm: with red boxes" << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::label_8;
+ using value::rgb8;
+
+ if (argc != 3)
+ usage(argv);
+
+ image2d<int_u8> input;
+ io::pgm::load(input, argv[1]);
+
+ int_u8 dummy, n_boxes;
+ estim::min_max(input, dummy, n_boxes);
+
+ label_8 n = unsigned(n_boxes);
+
+ mln_VAR(input_, violent_cast_image_<label_8>(input));
+ util::array<box2d> boxes = labeling::compute(accu::meta::bbox(),
+ input_,
+ n);
+
+ image2d<rgb8> out = level::convert(rgb8(), input);
+ scribo::draw::bounding_boxes(out, boxes, literal::red);
+ io::ppm::save(out, argv[2]);
+}
Index: icdar/2009/hsc/line_to_words.hh
--- icdar/2009/hsc/line_to_words.hh (revision 3641)
+++ icdar/2009/hsc/line_to_words.hh (working copy)
@@ -1,4 +1,3 @@
-
#include <mln/value/int_u.hh>
#include <mln/core/image/image2d.hh>
Index: icdar/2009/hsc/dummy_input_to_words_dat.cc
--- icdar/2009/hsc/dummy_input_to_words_dat.cc (revision 0)
+++ icdar/2009/hsc/dummy_input_to_words_dat.cc (revision 0)
@@ -0,0 +1,59 @@
+#include <mln/value/int_u16.hh>
+#include <mln/value/rgb8.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/debug/colorize.hh>
+
+#include <sandbox/icdar/2009/hsc/clean_input.hh>
+#include <sandbox/icdar/2009/hsc/line_to_words.hh>
+#include <sandbox/icdar/2009/hsc/io/icdar/save.hh>
+
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pbm output.dat [output.ppm]" << std::endl
+ << " HSC @ ICDAR'2009" << std::endl
+ << " input.pbm: a raw binary 2D image (either a line or a page)" << std::endl
+ << " output.dat: output image where words are labeled (int_u8)" << std::endl
+ << " 0 is the background label." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u16;
+
+ if (argc != 3 && argc != 4)
+ usage(argv);
+
+
+ trace::entering("main");
+
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ input = clean_input(input);
+
+
+ int_u16 n_words;
+ image2d<int_u16> output = line_to_words(input, n_words);
+
+ io::icdar::save(output, argv[2]);
+
+ if (argc == 4)
+ {
+ io::ppm::save(debug::colorize(value::rgb8(),
+ output,
+ n_words),
+ argv[3]);
+ }
+
+ trace::exiting("main");
+}
Index: icdar/2009/hsc/input_to_lines_dat.cc
--- icdar/2009/hsc/input_to_lines_dat.cc (revision 0)
+++ icdar/2009/hsc/input_to_lines_dat.cc (revision 0)
@@ -0,0 +1,87 @@
+#include <sandbox/icdar/2009/hsc/clean_input.hh>
+#include <sandbox/icdar/2009/hsc/input_to_ws.hh>
+#include <sandbox/icdar/2009/hsc/ws_to_wsl.hh>
+#include <sandbox/icdar/2009/hsc/io/icdar/save.hh>
+
+#include <mln/world/binary_2d/subsample.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/label.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/debug/colorize.hh>
+#include <mln/labeling/relabel.hh>
+
+#include <mln/level/transform.hh>
+#include <mln/fun/v2v/enc.hh>
+
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/core/image/violent_cast_image.hh>
+
+
+
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pbm output.dat [output.ppm]" << std::endl
+ << " HSC @ ICDAR'2009" << std::endl
+ << " input.pbm: input 2D binary image (text is black; background is white)" << std::endl
+ << " output.dat: line buffer (int; 0 is bg)." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 3 && argc != 4)
+ usage(argv);
+
+
+ trace::entering("main");
+
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+
+ // First clean.
+ input = clean_input(input);
+
+
+ // Sub-sample.
+ image2d<int_u8> small = world::binary_2d::subsample(input, 4);
+
+ typedef value::int_u<12> L;
+
+ L n_lines;
+ image2d<L>
+ // Get text regions.
+ ws = input_to_ws(input, small, n_lines),
+ // Merge regions.
+ wsl = ws_to_wslines(input, small, ws, n_lines);
+
+ typedef value::label<12> L_;
+ L_ n_lines_;
+ image2d<L_> wsl_ = labeling::relabel(violent_cast_image_<L_>(wsl),
+ n_lines_);
+
+ io::icdar::save(wsl_, argv[2]);
+
+ if (argc == 4)
+ {
+ io::ppm::save(debug::colorize(value::rgb8(),
+ wsl_,
+ n_lines_),
+ argv[3]);
+ }
+
+ trace::exiting("main");
+}
Index: icdar/2009/hsc/io/icdar/save.hh
--- icdar/2009/hsc/io/icdar/save.hh (revision 3641)
+++ icdar/2009/hsc/io/icdar/save.hh (working copy)
@@ -69,7 +69,8 @@
{
/// Probably too violent...
unsigned int value = static_cast<unsigned int>(ima(p));
- fwrite(&value, sizeof (int), 1, f);
+ int ret = fwrite(&value, sizeof (int), 1, f);
+ (void)(ret);
}
fclose(f);
Index: icdar/2009/hsc/input_to_ws.hh
--- icdar/2009/hsc/input_to_ws.hh (revision 3630)
+++ icdar/2009/hsc/input_to_ws.hh (working copy)
@@ -1,70 +1,37 @@
-#include <set>
-#include <vector>
-
#include <mln/core/image/image2d.hh>
-#include <mln/core/image/image_if.hh>
#include <mln/core/alias/neighb2d.hh>
-#include <mln/pw/all.hh>
#include <mln/data/fill.hh>
#include <mln/level/saturate.hh>
-#include <mln/level/convert.hh>
-#include <mln/arith/revert.hh>
#include <mln/value/int_u8.hh>
-#include <mln/value/rgb8.hh>
-#include <mln/literal/colors.hh>
-#include <mln/debug/colorize.hh>
-
-#include <mln/io/pbm/load.hh>
-#include <mln/io/pbm/save.hh>
-#include <mln/io/pgm/save.hh>
-#include <mln/io/ppm/save.hh>
-
-#include <mln/world/binary_2d/subsample.hh>
#define MLN_FLOAT double
#include <sandbox/theo/exec/gaussian_directional_2d.hh>
-#include <mln/morpho/closing/structural.hh>
-#include <mln/morpho/watershed/flooding.hh>
#include <mln/win/rectangle2d.hh>
-#include <sandbox/icdar/2009/hsc/ws_to_wsl.hh>
-
-
-
+#include <mln/morpho/closing/structural.hh>
+#include <mln/morpho/watershed/flooding.hh>
-void usage(char* argv[])
+namespace mln
{
- std::cerr << "usage: " << argv[0] << " input.pbm output.pgm [output.ppm]" << std::endl
- << " HSC @ ICDAR'2009" << std::endl
- << " input.pbm: input 2D binary image (text is black; background is white)" << std::endl
- << " output.pgm: output image where line components are labeled (int_u8)" << std::endl
- << " 0 is the background label." << std::endl;
- std::abort();
-}
-
-int main(int argc, char* argv[])
+ template <typename L>
+ image2d<L>
+ input_to_ws(const image2d<bool>& input,
+ const image2d<value::int_u8>& small,
+ L& n_lines)
{
- using namespace mln;
- using value::int_u8;
- using value::rgb8;
-
- if (argc != 3 && argc != 4)
- usage(argv);
-
// Parameters.
const unsigned
- subsampling_factor = 4,
height = 5,
- width = 25,
- n_min_stats = 1000;
+ width = 25;
+
const float
h_sigma = 31,
v_sigma = 1.3;
@@ -72,22 +39,8 @@
// end of Parameters.
- trace::entering("main");
-
- image2d<bool> input;
- io::pbm::load(input, argv[1]);
-
// Sub-sampling.
- image2d<int_u8>
- small = world::binary_2d::subsample(input, subsampling_factor),
- fuzzy, clo,
- ws,
- spc;
-
-
-# ifdef LOG
- io::pgm::save(small, "tmp_small.pgm");
-# endif
+ image2d<value::int_u8> fuzzy, clo;
// Fuzzifying.
@@ -98,38 +51,17 @@
out = linear::gaussian_directional_2d(temp, 1, h_sigma, 0);
out = linear::gaussian_directional_2d(out, 0, v_sigma, 0);
- fuzzy = level::saturate(int_u8(), out);
-
-# ifdef LOG
- io::pgm::save(fuzzy, "tmp_fuzzy.pgm");
-# endif
+ fuzzy = level::saturate(value::int_u8(), out);
}
-
+ // Closing.
clo = morpho::closing::structural(fuzzy, win::rectangle2d(height, width));
-# ifdef LOG
- io::pgm::save(clo, "tmp_clo.pgm");
-# endif
-
- int_u8 n_basins;
- ws = morpho::watershed::flooding(clo, c4(), n_basins);
+ // Watershed transform.
+ image2d<L> ws = morpho::watershed::flooding(clo, c4(), n_lines);
-# ifdef LOG
- io::pgm::save(ws, "tmp_ws.pgm");
- io::ppm::save(debug::colorize(rgb8(), ws, n_basins), "tmp_ws.ppm");
-# endif
-
-
- image2d<int_u8> wsl = ws_to_wslines(input, small, ws, n_basins);
-
- io::pgm::save(wsl, argv[2]);
-
- if (argc == 4)
- {
- io::ppm::save(debug::colorize(rgb8(), wsl, n_basins),
- argv[3]);
+ return ws;
}
- trace::exiting("main");
-}
+
+} // mln
Property changes on: icdar/2009/hsc/input_to_ws.hh
___________________________________________________________________
Added: svn:mergeinfo
Index: icdar/2009/hsc/input_to_wsl.cc
--- icdar/2009/hsc/input_to_wsl.cc (revision 3641)
+++ icdar/2009/hsc/input_to_wsl.cc (working copy)
@@ -1,36 +1,16 @@
-#include <set>
-#include <vector>
+#include <sandbox/icdar/2009/hsc/input_to_ws.hh>
+#include <sandbox/icdar/2009/hsc/ws_to_wsl.hh>
-#include <mln/core/image/image2d.hh>
-#include <mln/core/image/image_if.hh>
-#include <mln/core/alias/neighb2d.hh>
-
-#include <mln/pw/all.hh>
-#include <mln/data/fill.hh>
-#include <mln/level/saturate.hh>
-#include <mln/level/convert.hh>
-#include <mln/arith/revert.hh>
+#include <mln/world/binary_2d/subsample.hh>
#include <mln/value/int_u8.hh>
#include <mln/value/rgb8.hh>
-#include <mln/literal/colors.hh>
#include <mln/debug/colorize.hh>
#include <mln/io/pbm/load.hh>
-#include <mln/io/pbm/save.hh>
#include <mln/io/pgm/save.hh>
#include <mln/io/ppm/save.hh>
-#include <mln/world/binary_2d/subsample.hh>
-
-#define MLN_FLOAT double
-#include <sandbox/theo/exec/gaussian_directional_2d.hh>
-
-#include <mln/morpho/closing/structural.hh>
-#include <mln/morpho/watershed/flooding.hh>
-#include <mln/win/rectangle2d.hh>
-
-#include <sandbox/icdar/2009/hsc/ws_to_wsl.hh>
@@ -58,78 +38,31 @@
usage(argv);
- // Parameters.
-
- const unsigned
- subsampling_factor = 4,
- height = 5,
- width = 25,
- n_min_stats = 1000;
- const float
- h_sigma = 31,
- v_sigma = 1.3;
-
- // end of Parameters.
-
-
trace::entering("main");
+
image2d<bool> input;
io::pbm::load(input, argv[1]);
- // Sub-sampling.
- image2d<int_u8>
- small = world::binary_2d::subsample(input, subsampling_factor),
- fuzzy, clo,
- ws,
- spc;
-
-# ifdef LOG
- io::pgm::save(small, "tmp_small.pgm");
-# endif
-
-
- // Fuzzifying.
- {
- image2d<MLN_FLOAT> temp(small.domain()), out;
- data::fill(temp, small);
-
- out = linear::gaussian_directional_2d(temp, 1, h_sigma, 0);
- out = linear::gaussian_directional_2d(out, 0, v_sigma, 0);
-
- fuzzy = level::saturate(int_u8(), out);
-
-# ifdef LOG
- io::pgm::save(fuzzy, "tmp_fuzzy.pgm");
-# endif
- }
-
-
- clo = morpho::closing::structural(fuzzy, win::rectangle2d(height, width));
-
-# ifdef LOG
- io::pgm::save(clo, "tmp_clo.pgm");
-# endif
-
- int_u8 n_basins;
- ws = morpho::watershed::flooding(clo, c4(), n_basins);
-
-# ifdef LOG
- io::pgm::save(ws, "tmp_ws.pgm");
- io::ppm::save(debug::colorize(rgb8(), ws, n_basins), "tmp_ws.ppm");
-# endif
+ int_u8 n_lines;
+ image2d<int_u8>
+ small = world::binary_2d::subsample(input, 4),
+ ws = input_to_ws(input, small, n_lines),
+ wsl = ws_to_wslines(input, small, ws, n_lines);
- image2d<int_u8> wsl = ws_to_wslines(input, small, ws, n_basins);
io::pgm::save(wsl, argv[2]);
if (argc == 4)
{
- io::ppm::save(debug::colorize(rgb8(), wsl, n_basins),
+ io::ppm::save(debug::colorize(value::rgb8(),
+ wsl,
+ n_lines),
argv[3]);
}
+
trace::exiting("main");
}
Index: icdar/2009/hsc/ws_to_wsl.hh
--- icdar/2009/hsc/ws_to_wsl.hh (revision 3641)
+++ icdar/2009/hsc/ws_to_wsl.hh (working copy)
@@ -25,7 +25,17 @@
#include <mln/morpho/elementary/dilation.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/literal/colors.hh>
+#include <mln/level/convert.hh>
+#include <mln/pw/all.hh>
+#include <mln/core/image/image_if.hh>
+
+#include <mln/fun/i2v/array.hh>
+#include <mln/level/transform.hh>
+#include <mln/debug/colorize.hh>
@@ -296,7 +306,12 @@
& m1 = m[i1],
& m2 = m[i2];
- if (m1.n() > 1000 && m2.n() > 1000)
+// if (m1.n() != 0 && m2.n() != 0)
+// d(e) = dist(m1, m2);
+// else
+// d(e) = 666.f;
+
+ if (m1.n() > 10 && m2.n() > 10) // FIXME: was 1000
d(e) = dist(m1, m2);
else
d(e) = 666.f;
@@ -379,6 +394,31 @@
}
+#ifdef LOG
+ {
+ io::pgm::save(small, "tmp_small.pgm");
+ io::pgm::save(ws, "tmp_ws.pgm");
+
+ using value::rgb8;
+
+ image2d<rgb8> small_ws = level::convert(rgb8(), small);
+ data::fill((small_ws | (pw::value(ws) == pw::cst(0))).rw(),
+ literal::red);
+ io::ppm::save(small_ws, "tmp_small_ws.ppm");
+
+ fun::i2v::array<L> f_relab(n_basins + 1);
+ f_relab(0) = 0;
+ for (L l = 1; l <= n_basins; ++l)
+ f_relab(l) = parent[l];
+
+ image2d<L> ws_ = level::transform(ws, f_relab);
+ io::ppm::save(debug::colorize(rgb8(), ws_, n_basins), "tmp_ws.ppm");
+
+ }
+#endif // LOG
+
+
+
// Outputing.
image2d<L> output(input.domain());
1
0
* mln/io/all.hh,
* mln/io/tiff/all.hh,
* mln/io/tiff/load.hh: Add support for TIFF.
---
milena/ChangeLog | 8 ++
milena/mln/io/all.hh | 1 +
milena/mln/io/{ => tiff}/all.hh | 34 ++----
milena/mln/io/tiff/load.hh | 240 +++++++++++++++++++++++++++++++++++++++
4 files changed, 260 insertions(+), 23 deletions(-)
copy milena/mln/io/{ => tiff}/all.hh (65%)
create mode 100644 milena/mln/io/tiff/load.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 6ca5470..5fae96c 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,11 @@
+2009-04-07 Guillaume Lazzara <lazzara(a)lrde.epita.fr>
+
+ Add io::tiff::load
+
+ * mln/io/all.hh,
+ * mln/io/tiff/all.hh,
+ * mln/io/tiff/load.hh: Add support for TIFF.
+
2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
Make mln::topo::skeleton::breadth_first_thinning more generic.
diff --git a/milena/mln/io/all.hh b/milena/mln/io/all.hh
index 6d76c58..d2c7d66 100644
--- a/milena/mln/io/all.hh
+++ b/milena/mln/io/all.hh
@@ -55,6 +55,7 @@ namespace mln
# include <mln/io/pgm/all.hh>
# include <mln/io/pnm/all.hh>
# include <mln/io/ppm/all.hh>
+# include <mln/io/tiff/all.hh>
# include <mln/io/txt/all.hh>
//# include <mln/io/fits/all.hh>
//# include <mln/io/off/all.hh>
diff --git a/milena/mln/io/all.hh b/milena/mln/io/tiff/all.hh
similarity index 65%
copy from milena/mln/io/all.hh
copy to milena/mln/io/tiff/all.hh
index 6d76c58..d46dbdb 100644
--- a/milena/mln/io/all.hh
+++ b/milena/mln/io/tiff/all.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009 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
@@ -25,38 +25,26 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_IO_ALL_HH
-# define MLN_IO_ALL_HH
+#ifndef MLN_IO_TIFF_ALL_HH
+# define MLN_IO_TIFF_ALL_HH
-/// \file mln/io/all.hh
+/// \file mln/io/tiff/all.hh
///
-/// File that includes all io materials.
-
+/// File that includes all tiff io materials.
namespace mln
{
- /// Namespace of input/output handling.
namespace io
{
- /// Internal namespace of io namespace.
- namespace internal {}
+ /// Namespace of tiff input/output handling.
+ namespace tiff {}
}
}
-# include <mln/io/cloud/all.hh>
-# include <mln/io/dump/all.hh>
-# include <mln/io/dicom/load.hh>
-# include <mln/io/magick/all.hh>
-# include <mln/io/pbm/all.hh>
-# include <mln/io/pfm/all.hh>
-# include <mln/io/pgm/all.hh>
-# include <mln/io/pnm/all.hh>
-# include <mln/io/ppm/all.hh>
-# include <mln/io/txt/all.hh>
-//# include <mln/io/fits/all.hh>
-//# include <mln/io/off/all.hh>
-
-#endif // ! MLN_IO_ALL_HH
+# include <mln/io/tiff/load.hh>
+//# include <mln/io/tiff/save.hh>
+
+#endif // ! MLN_IO_TIFF_ALL_HH
diff --git a/milena/mln/io/tiff/load.hh b/milena/mln/io/tiff/load.hh
new file mode 100644
index 0000000..0cb2b86
--- /dev/null
+++ b/milena/mln/io/tiff/load.hh
@@ -0,0 +1,240 @@
+// Copyright (C) 2009 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_IO_TIFF_LOAD_HH
+# define MLN_IO_TIFF_LOAD_HH
+
+
+/// \file mln/io/tiff/load.hh
+///
+/// Load TIFF images to Milena images.
+///
+/// \todo Add support for several tiles.
+
+
+# include <iostream>
+# include <fstream>
+# include <tiffio.h>
+
+# include <mln/core/concept/image.hh>
+# include <mln/value/rgb8.hh>
+
+
+
+namespace mln
+{
+
+ namespace io
+ {
+
+ namespace tiff
+ {
+
+
+ /// Load a TIFF image to a Milena image.
+ //
+ template <typename I>
+ void load(Image<I>& ima_, const std::string& filename);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ namespace internal
+ {
+
+ template <typename I>
+ inline
+ void load_header(Image<I>& ima, TIFF *file)
+ {
+ uint32 width, height;
+
+ TIFFGetField(file, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(file, TIFFTAG_IMAGELENGTH, &height);
+
+ mln_concrete(I) new_ima(height, width, 0);
+ exact(ima) = new_ima;
+
+ }
+
+
+ template <typename I>
+ inline
+ void load_data_rgb8(I& ima, TIFF *file)
+ {
+ uint16 bits_per_sample, samples_per_pixel;
+ TIFFGetField(file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
+ TIFFGetField(file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
+ uint16 data_size = bits_per_sample * samples_per_pixel;
+ if (data_size != 24 || data_size != 32)
+ {
+ std::cout << "Trying to load a non color TIFF "
+ << "image into a color Milena image." << std::endl;
+ abort();
+ }
+
+ uint32 npixels = ima.ncols() * ima.nrows();
+ uint32 *raster = (uint32 *) _TIFFmalloc(npixels * sizeof (uint32));
+
+ if (!TIFFReadRGBAImage(file, ima.ncols(), ima.nrows(), raster, 0))
+ {
+ std::cout << "Error while reading the image file. Is it corrupted?"
+ << std::endl;
+ abort();
+ }
+
+ unsigned i = ima.ncols() - 1;
+ unsigned j = 0;
+ mln_piter(I) p(ima.domain());
+ for_all(p)
+ {
+ unsigned idx = i * ima.ncols() + j;
+ value::rgb8 v;
+ v.red() = (unsigned char) TIFFGetR(raster[idx]);
+ v.green() = (unsigned char) TIFFGetG(raster[idx]);
+ v.blue() = (unsigned char) TIFFGetB(raster[idx]);
+ ima(p) = v;
+ ++j;
+ if (!(j%ima.nrows()))
+ {
+ --i;
+ j = 0;
+ }
+ }
+
+ _TIFFfree(raster);
+ }
+
+ template <typename I>
+ inline
+ void load_data_scalar(I& ima, TIFF *file)
+ {
+ uint16 samples_per_pixel;
+ TIFFGetField(file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
+ if (samples_per_pixel != 1)
+ {
+ std::cout << "Trying to load a non grayscale TIFF "
+ << "image into a grayscale Milena image." << std::endl;
+ abort();
+ }
+
+ uint32 npixels = ima.ncols() * ima.nrows();
+ uint32 *raster = (uint32 *) _TIFFmalloc(npixels * sizeof (uint32));
+
+ TIFFReadRGBAImage(file, ima.ncols(), ima.nrows(), raster, 0);
+
+ unsigned i = ima.ncols() - 1;
+ unsigned j = 0;
+ mln_piter(I) p(ima.domain());
+ for_all(p)
+ {
+ unsigned idx = i * ima.ncols() + j;
+ ima(p) = (unsigned char) TIFFGetR(raster[idx]);
+ ++j;
+ if (!(j%ima.nrows()))
+ {
+ --i;
+ j = 0;
+ }
+ }
+
+ _TIFFfree(raster);
+ }
+
+ template <typename I>
+ inline
+ void
+ load_data_dispatch(const value::rgb8&, I& ima, TIFF *file)
+ {
+ load_data_rgb8(ima, file);
+ }
+
+ template <typename S, typename I>
+ inline
+ void
+ load_data_dispatch(const value::Scalar<S>&, I& ima, TIFF *file)
+ {
+ load_data_scalar(ima, file);
+ }
+
+ template <typename I>
+ inline
+ void
+ load_data_dispatch(const bool&, I& ima, TIFF *file)
+ {
+ load_data_scalar(ima, file);
+ }
+
+
+ template <typename I>
+ inline
+ void
+ load_data_dispatch(Image<I>& ima, TIFF *file)
+ {
+ load_data_dispatch(mln_value(I)(), exact(ima), file);
+ }
+
+
+ } // end of namespace mln::io::tiff::internal
+
+
+
+ // Facade
+
+ template <typename I>
+ inline
+ void load(Image<I>& ima, const std::string& filename)
+ {
+ trace::entering("mln::io::tiff::load");
+
+ TIFF *file = TIFFOpen(filename.c_str(), "r");
+ if (file == 0)
+ {
+ std::cerr << "io::tiff::load - Error: cannot open file '"
+ << filename << "'!"
+ << std::endl;
+ abort();
+ }
+
+ internal::load_header(ima, file);
+ internal::load_data_dispatch(ima, file);
+
+ mln_postcondition(exact(ima).is_valid());
+
+ trace::exiting("mln::io::tiff::load");
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::io::tiff
+
+ } // end of namespace mln::io
+
+} // end of namespace mln
+
+#endif // ! MLN_IO_TIFF_LOAD_HH
--
1.5.6.5
1
0
* icdar/2009/hsc/clean_lines.hh: new routine.
* icdar/2009/hsc/input_lines_to_lines.cc: use this new routine.
---
milena/sandbox/ChangeLog | 7 ++
milena/sandbox/icdar/2009/hsc/clean_lines.hh | 72 ++++++++++++++++++++
.../sandbox/icdar/2009/hsc/input_lines_to_lines.cc | 23 +------
3 files changed, 81 insertions(+), 21 deletions(-)
create mode 100644 milena/sandbox/icdar/2009/hsc/clean_lines.hh
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog
index 681b6bf..2d8698f 100644
--- a/milena/sandbox/ChangeLog
+++ b/milena/sandbox/ChangeLog
@@ -1,3 +1,10 @@
+2009-04-08 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Add clean_lines routine.
+
+ * icdar/2009/hsc/clean_lines.hh: new routine.
+ * icdar/2009/hsc/input_lines_to_lines.cc: use this new routine.
+
2009-04-07 Guillaume Lazzara <z(a)lrde.epita.fr>
Add icdar2ppm.
diff --git a/milena/sandbox/icdar/2009/hsc/clean_lines.hh b/milena/sandbox/icdar/2009/hsc/clean_lines.hh
new file mode 100644
index 0000000..956c150
--- /dev/null
+++ b/milena/sandbox/icdar/2009/hsc/clean_lines.hh
@@ -0,0 +1,72 @@
+#ifndef CLEAN_LINES_HH
+# define CLEAN_LINES_HH
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/labeling/background.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/value/label_8.hh>
+#include <mln/value/label_16.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/all.hh>
+#include <mln/labeling/compute.hh>
+#include <mln/pw/all.hh>
+#include <mln/core/image/image_if.hh>
+#include <mln/data/fill.hh>
+#include "label_maj.hh"
+
+
+namespace mln
+{
+
+ template <typename I, typename L>
+ mln_concrete(L)
+ clean_lines(const Image<I>& input, const Image<L>& lines_,
+ float maj_threshold);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I, typename L>
+ mln_concrete(L)
+ clean_lines(const Image<I>& input, const Image<L>& lines_,
+ float maj_threshold)
+ {
+ trace::entering("clean_lines");
+
+ const L& lines = exact(lines_);
+ mln_precondition(lines.is_valid());
+ typedef value::label_16 LV;
+
+ LV nlabels;
+ mln_ch_value(L,LV) lbl = labeling::background(input, c8(), nlabels);
+ util::array<box<mln_site(L)> > bboxes = labeling::compute(accu::meta::bbox(), lbl, nlabels);
+
+ /// Compute the most represented label for each component.
+ accu::label_maj<LV, mln_value(L)> accu(nlabels.next());
+ mln_piter(image2d<mln_value(L)>) p(lbl.domain());
+ for_all(p)
+ if (lines(p) != 0u)
+ accu.take(lbl(p), lines(p));
+
+ mln_concrete(L) output = duplicate(lines);
+
+ // Rebuild components.
+ util::array<util::couple<mln_value(L), float> > res = accu.to_result();
+ for (unsigned i = 1; i < res.nelements(); ++i)
+ if (res[i].second() >= maj_threshold)
+ data::fill(((output | bboxes[i]).rw()
+ | (pw::value(lbl) != pw::cst(literal::zero))).rw(),
+ res[i].first());
+// else
+// std::cout << res[i].first() << " - " << res[i].second() << std::endl;
+
+ trace::exiting("clean_lines");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+#endif // CLEAN_LINES_HH
diff --git a/milena/sandbox/icdar/2009/hsc/input_lines_to_lines.cc b/milena/sandbox/icdar/2009/hsc/input_lines_to_lines.cc
index 56aafab..18f7d3a 100644
--- a/milena/sandbox/icdar/2009/hsc/input_lines_to_lines.cc
+++ b/milena/sandbox/icdar/2009/hsc/input_lines_to_lines.cc
@@ -11,6 +11,7 @@
#include <mln/core/image/image_if.hh>
#include <mln/data/fill.hh>
#include "label_maj.hh"
+#include "clean_lines.hh"
void usage(char* argv[])
{
@@ -40,26 +41,6 @@ int main(int argc, char *argv[])
image2d<int_u8> lines;
io::pgm::load(lines, argv[2]);
- label_16 nlabels;
- image2d<label_16> lbl = labeling::background(input, c8(), nlabels);
- util::array<box2d> bboxes = labeling::compute(accu::meta::bbox(), lbl, nlabels);
-
- /// Compute the most represented label for each component.
- accu::label_maj<label_16, int_u8> accu(nlabels.next());
- mln_piter_(image2d<int_u8>) p(lbl.domain());
- for_all(p)
- if (lines(p) != 0u)
- accu.take(lbl(p), lines(p));
-
-
- // Rebuild components.
- util::array<util::couple<int_u8, float> > res = accu.to_result();
- for (unsigned i = 1; i < res.nelements(); ++i)
- if (res[i].second() >= 0.70f)
- data::fill(((lines | bboxes[i]).rw() | (pw::value(lbl) != 0u)).rw(), res[i].first());
- else
- std::cout << res[i].first() << " - " << res[i].second() << std::endl;
-
// Save result.
- io::pgm::save(lines, argv[3]);
+ io::pgm::save(clean_lines(input, lines, 0.7f), argv[3]);
}
--
1.5.6.5
1
0
URL: https://svn.lrde.epita.fr/svn/scool/branches/scool-ng
ChangeLog:
2009-04-07 Warren Seine <soow(a)lrde.epita.fr>
Use atdiff instead of diff when comparing ATerm's.
* tests/check.sh: Allow to run check.sh from outside the
"tests" folder.
* tests/config: Change to "atdiff".
---
check.sh | 14 ++++++++++++--
config | 2 +-
2 files changed, 13 insertions(+), 3 deletions(-)
Index: branches/scool-ng/tests/config
===================================================================
--- branches/scool-ng/tests/config (revision 148)
+++ branches/scool-ng/tests/config (revision 149)
@@ -4,7 +4,7 @@
{
desc="Scool parser"
cmd='sglri -p ../../src/scl-syn/Scool.tbl -i $input_file'
- cmp='diff -EwbB -u $ref $output'
+ cmp='atdiff --notemplate $ref $output'
print_input_cmd='cat $input_file'
print_output_cmd='pp-aterm -i $input_file'
Index: branches/scool-ng/tests/check.sh
===================================================================
--- branches/scool-ng/tests/check.sh (revision 148)
+++ branches/scool-ng/tests/check.sh (revision 149)
@@ -3,6 +3,7 @@
#FIXME: command line
+default="\033[0m"
white="\033[33;00;29m"
black="\033[33;01;30m"
grey="\033[33;01;30m"
@@ -173,10 +174,10 @@
if [ $print_diff -eq 1 ]; then
echo
if [ $exit_val -eq 2 ]; then
- echo -ne $grey; cat $cmd_log $cmd_err
+ echo -ne $default; cat $cmp_log $cmp_err
echo -n
else
- echo -ne $grey; cat $cmp_log $cmp_err
+ echo -ne $default; cat $cmp_log $cmp_err
fi
fi
fi
@@ -228,6 +229,15 @@
"
}
+enter_test_dir()
+{
+ local filename=`readlink -f $0`
+ local test_dir=`dirname $filename`
+ cd $test_dir
+}
+
+enter_test_dir
+
print_diff=0
gen_ref=0
flush_sk=0
--
:: Warren Seine // SooW ::
:: warren.seine @ gmail.com ::
:: EPITA CSI 2010 ::
1
0
URL: https://svn.lrde.epita.fr/svn/scool/branches/scool-ng
ChangeLog:
2009-04-07 Warren Seine <soow(a)lrde.epita.fr>
mini-std: Initial import.
Empty and non-compiling at this state.
* examples/mini-std/c++/Makefile: New.
* examples/mini-std/c++/main.cc: New.
* examples/mini-std/c++/mini-std.hh: New.
* examples/mini-std/c++: New.
* examples/mini-std/scool: New.
* examples/mini-std: New.
* examples: New.
---
0 files changed
--
:: Warren Seine // SooW ::
:: warren.seine @ gmail.com ::
:: EPITA CSI 2010 ::
1
0
[PATCH 7/7] Make mln::topo::skeleton::breadth_first_thinning more generic.
by Roland Levillain 07 Apr '09
by Roland Levillain 07 Apr '09
07 Apr '09
* mln/topo/skeleton/breadth_first_thinning.hh
(mln::topo::skeleton::breadth_first_thinning): Add a parameter I.
Take an Image<I> as argument instead of a bin_2complex_image3df.
Adjust return type.
Pass the `detach' function as an additional argument.
Adjust and complete the documentation.
* apps/statues/mesh-complex-skel.cc (main): Adjust caller.
* mln/topo/detach.hh (mln::topo::detach<D, G, V>): Get rid of
parameter V (replace it by `bool'), and turn the signature of
the function into...
(mln::topo::detach<D, G>): ...this.
Remove a (now) useless precondition.
---
milena/ChangeLog | 17 +++++
milena/apps/statues/mesh-complex-skel.cc | 5 +-
milena/mln/topo/detach.hh | 9 +--
milena/mln/topo/skeleton/breadth_first_thinning.hh | 71 +++++++++++---------
4 files changed, 65 insertions(+), 37 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 8b483cf..6ca5470 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,22 @@
2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+ Make mln::topo::skeleton::breadth_first_thinning more generic.
+
+ * mln/topo/skeleton/breadth_first_thinning.hh
+ (mln::topo::skeleton::breadth_first_thinning): Add a parameter I.
+ Take an Image<I> as argument instead of a bin_2complex_image3df.
+ Adjust return type.
+ Pass the `detach' function as an additional argument.
+ Adjust and complete the documentation.
+ * apps/statues/mesh-complex-skel.cc (main): Adjust caller.
+ * mln/topo/detach.hh (mln::topo::detach<D, G, V>): Get rid of
+ parameter V (replace it by `bool'), and turn the signature of
+ the function into...
+ (mln::topo::detach<D, G>): ...this.
+ Remove a (now) useless precondition.
+
+2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+
Split apps/statues/mesh-complex-skel.
* apps/statues/mesh-complex-skel.cc: Split reusable parts into...
diff --git a/milena/apps/statues/mesh-complex-skel.cc b/milena/apps/statues/mesh-complex-skel.cc
index 85a1581..77a11cf 100644
--- a/milena/apps/statues/mesh-complex-skel.cc
+++ b/milena/apps/statues/mesh-complex-skel.cc
@@ -44,6 +44,7 @@
#include <mln/topo/is_n_face.hh>
#include <mln/topo/is_simple_cell.hh>
+#include <mln/topo/detach.hh>
#include <mln/topo/skeleton/breadth_first_thinning.hh>
#include <mln/io/off/load.hh>
@@ -198,7 +199,9 @@ main(int argc, char* argv[])
skeleton routine to restrict the iteration to 2-cells. */
mln::topo::is_n_face<bin_ima_t::dim> constraint_p;
bin_ima_t skel =
- mln::topo::skeleton::breadth_first_thinning(surface, nbh, is_simple_p,
+ mln::topo::skeleton::breadth_first_thinning(surface, nbh,
+ is_simple_p,
+ mln::topo::detach<D, G>,
constraint_p);
/*---------.
diff --git a/milena/mln/topo/detach.hh b/milena/mln/topo/detach.hh
index e80a8a9..daae5b2 100644
--- a/milena/mln/topo/detach.hh
+++ b/milena/mln/topo/detach.hh
@@ -47,20 +47,19 @@ namespace mln
\pre \a f is a facet (it does not belong to any face of higher
dimension).
\pre \a ima is an image of Boolean values. */
- template <unsigned D, typename G, typename V>
+ template <unsigned D, typename G>
void
- detach(const complex_psite<D, G>& f, complex_image<D, G, V>& ima);
+ detach(const complex_psite<D, G>& f, complex_image<D, G, bool>& ima);
# ifndef MLN_INCLUDE_ONLY
- template <unsigned D, typename G, typename V>
+ template <unsigned D, typename G>
inline
void
- detach(const complex_psite<D, G>& f, complex_image<D, G, V>& ima)
+ detach(const complex_psite<D, G>& f, complex_image<D, G, bool>& ima)
{
mln_precondition(topo::is_facet(f));
- mlc_equal(V, bool)::check();
typedef complex_psite<D, G> psite;
typedef p_set<psite> faces_t;
diff --git a/milena/mln/topo/skeleton/breadth_first_thinning.hh b/milena/mln/topo/skeleton/breadth_first_thinning.hh
index ee4c5f2..6c28410 100644
--- a/milena/mln/topo/skeleton/breadth_first_thinning.hh
+++ b/milena/mln/topo/skeleton/breadth_first_thinning.hh
@@ -36,9 +36,10 @@
# include <mln/core/routine/duplicate.hh>
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+
# include <mln/core/site_set/p_set.hh>
-# include <mln/core/alias/complex_image.hh>
-# include <mln/topo/detach.hh>
# include <mln/fun/p2b/tautology.hh>
@@ -51,49 +52,46 @@ namespace mln
namespace skeleton
{
- /* FIXME: Use a generic `I' instead of
- `mln::bin_2complex_image3df', and adjust the
- documentation. */
-
- /* FIXME: Rename `constraint' to a verb or adjective?
- (validate_constraint? satisfy_constraint? pass_constraint?
- is_satisfying?) */
-
- /** \brief Breadth-First Thinning.
+ /** \brief Skeleton by Breadth-First Thinning.
- A semi-generic implementation of a binary skeleton on a triangle
- surface (mesh).
+ A generic implementation of the computation of a skeleton
+ using a breadth-first thinning on a binary.
\param input The input image.
\param nbh The adjacency relation between triangles.
- \param is_simple The predicate on the simplicity of points (sites).
+ \param is_simple The predicate on the simplicity of points
+ (sites). This functor must provide a method
+ <tt>void set_image(const Image<I>&)</tt>.
+ \param detach A function used to detach a cell from \a input.
\param constraint A constraint on point (site); if it
returns \c false for a point, this point
will not be removed. */
- template <typename N, typename F, typename G>
- bin_2complex_image3df
- breadth_first_thinning(const bin_2complex_image3df& input,
+ template <typename I, typename N, typename F, typename G, typename H>
+ mln_concrete(I)
+ breadth_first_thinning(const Image<I>& input,
const Neighborhood<N>& nbh,
Function_p2b<F>& is_simple,
- const Function_p2b<G>& constraint =
+ G detach,
+ const Function_p2b<H>& constraint =
fun::p2b::tautology());
# ifndef MLN_INCLUDE_ONLY
- template <typename N, typename F, typename G>
+ template <typename I, typename N, typename F, typename G, typename H>
inline
- bin_2complex_image3df
- breadth_first_thinning(const bin_2complex_image3df& input,
+ mln_concrete(I)
+ breadth_first_thinning(const Image<I>& input_,
const Neighborhood<N>& nbh_,
Function_p2b<F>& is_simple_,
- const Function_p2b<G>& constraint_)
+ G detach,
+ const Function_p2b<H>& constraint_)
{
+ const I& input = exact(input_);
const N& nbh = exact(nbh_);
F& is_simple = exact(is_simple_);
- const G& constraint = exact(constraint_);
+ const H& constraint = exact(constraint_);
- typedef bin_2complex_image3df I;
typedef mln_psite(I) psite;
I output = duplicate(input);
@@ -120,18 +118,29 @@ namespace mln
while (!set.is_empty())
{
set_t next_set;
- // FIXME: Use a piter on SET instead of this hand-made iteration.
+
+ /* FIXME: Using the following code does not work (it does
+ compiles, but does not behave like the code using a
+ hand-made loop). There must be a bug somewhere in
+ p_set or p_indexed_psite. */
+# if 0
+ mln_piter(set_t) ps(set);
+ for_all(ps);
+ {
+ // Same remark as above.
+ psite p = p_;
+# endif
for (unsigned i = 0; i < set.nsites(); ++i)
{
psite p = set[i];
- /* FIXME: We compute the cell and attachment of P
- twice: within is_simple and within detach. How
- could we reuse this elegantly, without breaking the
- genericity of the skeleton algorithm? */
+
+ /* FIXME: We compute the cell and attachment of P twice:
+ during the call to is_simple() and within detach().
+ How could we reuse this elegantly, without breaking
+ the genericity of the skeleton algorithm? */
if (constraint(p) && is_simple(p))
{
- // FIXME: `detach' could be a functor, as is `is_simple'.
- topo::detach(p, output);
+ detach(p, output);
mln_niter(N) n(nbh, p);
for_all(n)
if (output.domain().has(n)
--
1.6.1.2
1
0
* apps/statues/mesh-complex-skel.cc: Split reusable parts into...
* mln/make/attachment.hh,
* mln/make/cell.hh,
* mln/make/detachment.hh,
* mln/topo/detach.hh,
* mln/topo/is_facet.hh,
* mln/topo/is_n_face.hh,
* mln/topo/is_simple_cell.hh,
* mln/topo/skeleton/breadth_first_thinning.hh:
...these (new) files.
---
milena/ChangeLog | 15 +
milena/apps/statues/mesh-complex-skel.cc | 441 +-------------------
milena/mln/make/attachment.hh | 102 +++++
milena/mln/make/cell.hh | 97 +++++
milena/mln/make/detachment.hh | 103 +++++
milena/mln/topo/detach.hh | 86 ++++
milena/mln/topo/is_facet.hh | 79 ++++
milena/mln/topo/is_n_face.hh | 75 ++++
milena/mln/topo/is_simple_cell.hh | 220 ++++++++++
milena/mln/topo/skeleton/breadth_first_thinning.hh | 156 +++++++
10 files changed, 949 insertions(+), 425 deletions(-)
create mode 100644 milena/mln/make/attachment.hh
create mode 100644 milena/mln/make/cell.hh
create mode 100644 milena/mln/make/detachment.hh
create mode 100644 milena/mln/topo/detach.hh
create mode 100644 milena/mln/topo/is_facet.hh
create mode 100644 milena/mln/topo/is_n_face.hh
create mode 100644 milena/mln/topo/is_simple_cell.hh
create mode 100644 milena/mln/topo/skeleton/breadth_first_thinning.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index ce4316d..8b483cf 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,20 @@
2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+ Split apps/statues/mesh-complex-skel.
+
+ * apps/statues/mesh-complex-skel.cc: Split reusable parts into...
+ * mln/make/attachment.hh,
+ * mln/make/cell.hh,
+ * mln/make/detachment.hh,
+ * mln/topo/detach.hh,
+ * mln/topo/is_facet.hh,
+ * mln/topo/is_n_face.hh,
+ * mln/topo/is_simple_cell.hh,
+ * mln/topo/skeleton/breadth_first_thinning.hh:
+ ...these (new) files.
+
+2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+
* apps/statues/mesh-complex-skel.cc: Remove dead code.
2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
diff --git a/milena/apps/statues/mesh-complex-skel.cc b/milena/apps/statues/mesh-complex-skel.cc
index 7c103b2..85a1581 100644
--- a/milena/apps/statues/mesh-complex-skel.cc
+++ b/milena/apps/statues/mesh-complex-skel.cc
@@ -30,11 +30,6 @@
/// (triangle) mesh of a statue (by thinning), using a complex-based
/// image.
-#include <cstdlib>
-#include <cmath>
-
-#include <algorithm>
-#include <utility>
#include <iostream>
#include <mln/core/image/complex_image.hh>
@@ -42,431 +37,23 @@
#include <mln/core/site_set/p_set.hh>
-#include <mln/pw/value.hh>
-#include <mln/pw/cst.hh>
-
#include <mln/value/label_16.hh>
-#include <mln/literal/white.hh>
-
-#include <mln/core/routine/duplicate.hh>
#include <mln/labeling/regional_minima.hh>
-#include <mln/morpho/erosion.hh>
#include <mln/morpho/closing/area.hh>
-#include <mln/fun/p2b/tautology.hh>
+#include <mln/topo/is_n_face.hh>
+#include <mln/topo/is_simple_cell.hh>
+#include <mln/topo/skeleton/breadth_first_thinning.hh>
#include <mln/io/off/load.hh>
-#include <mln/io/off/save.hh>
/* FIXME: Remove as soon as mln::io::off::save is able to save a
morphed mln::complex_image (i.e., seen through image_if). */
#include "save_bin_alt.hh"
-// FIXME: This is bad. Remove as soon as all routines have been moved
-// to the library.
-using namespace mln;
-
-
-// FIXME: Doc.
-template <unsigned D, typename G>
-bool
-is_facet(const mln::complex_psite<D, G>& f)
-{
- typedef mln::complex_higher_neighborhood<D, G> higher_adj_nbh_t;
- higher_adj_nbh_t higher_adj_nbh;
- mln_niter(higher_adj_nbh_t) n(higher_adj_nbh, f);
- for_all(n)
- // If the neighborhood is not empty, then F is included in a face
- // of higher dimension.
- return false;
- // Otherwise, F is a facet.
- return true;
-}
-
-
-/** \brief Compute the set of faces of the cell corresponding to the
- facet \a f.
-
- \pre \a f is a facet (it does not belong to any face of higher
- dimension)
-
- \return a set of faces containing the attachment. */
-template <unsigned D, typename G>
-mln::p_set< complex_psite<D, G> >
-cell(const complex_psite<D, G>& f)
-{
- // Ensure the face F is a facet.
- mln_precondition(is_facet(f));
-
- typedef complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
-
- // Compute the cell F^HAT.
- faces_t f_hat;
- /* FIXME: We need a cell-iterator here
- (see https://trac.lrde.org/olena/ticket/162) */
- typedef complex_m_face_neighborhood<D, G> m_faces_nbh_t;
- m_faces_nbh_t m_faces_nbh;
- mln_niter(m_faces_nbh_t) g(m_faces_nbh, f);
- for (unsigned m = 0; m < f.n(); ++m)
- {
- g.iter().set_m(m);
- for_all(g)
- {
- f_hat.insert(g);
- }
- }
- f_hat.insert(f);
- return f_hat;
-}
-
-
-/** \brief Compute the attachment of the cell corresponding to the
- facet \a f to the image \a ima.
-
- \pre ima is an image of Boolean values.
-
- \return a set of faces containing the attachment.
-
- We do not use the fomal definition of the attachment here (see
- couprie.08.pami). We use the following (equivalent) definition:
- an N-face F in CELL is in the attachment of CELL to IMA if it is
- adjacent to at least an (N-1)-face or an (N+1)-face that does not
- belong to CELL. */
-template <unsigned D, typename G, typename V>
-mln::p_set< complex_psite<D, G> >
-attachment(const mln::complex_psite<D, G>& f,
- const mln::complex_image<D, G, V>& ima)
-{
- mlc_equal(V, bool)::check();
-
- typedef complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
-
- faces_t f_hat = cell(f);
- faces_t att_f;
-
- typedef complex_lower_higher_neighborhood<D, G> adj_nbh_t;
- adj_nbh_t adj_nbh;
- mln_piter(faces_t) g(f_hat);
- mln_niter(adj_nbh_t) n(adj_nbh, g);
- for_all(g)
- for_all(n)
- if (ima(n) && !f_hat.has(n))
- {
- att_f.insert(g);
- break;
- }
- return att_f;
-}
-
-
-/** \brief Compute the detachment of the cell corresponding to the
- facet \a f to the image \a ima.
-
- \pre ima is an image of Boolean values.
-
- \return a set of faces containing the detachment.
-
- We do not use the fomal definition of the detachment here (see
- couprie.08.pami). We use the following (equivalent) definition:
- an N-face F in CELL is not in the detachment of CELL from IMA if
- it is adjacent to at least an (N-1)-face or an (N+1)-face that
- does not belong to CELL. */
-template <unsigned D, typename G, typename V>
-mln::p_set< complex_psite<D, G> >
-detachment(const mln::complex_psite<D, G>& f,
- const mln::complex_image<D, G, V>& ima)
-{
- mlc_equal(V, bool)::check();
-
- typedef complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
-
- faces_t f_hat = cell(f);
- // Initialize DETACH_F to F_HAT.
- faces_t detach_f = f_hat;
-
- typedef complex_lower_higher_neighborhood<D, G> adj_nbh_t;
- adj_nbh_t adj_nbh;
- mln_piter(faces_t) g(f_hat);
- mln_niter(adj_nbh_t) n(adj_nbh, g);
- for_all(g)
- for_all(n)
- if (ima(n) && !f_hat.has(n))
- {
- detach_f.remove(g);
- break;
- }
- return detach_f;
-}
-
-
-/** \brief A predicate for the simplicity of a point based on the
- collapse property of the attachment.
-
- The functor does not actually take a cell as input, but a face
- that is expected to be a 2-facet. */
-template <typename I>
-class is_simple_cell
- : public mln::Function_p2b< is_simple_cell<I> >
-{
-public:
- /// Dimension of the image (and therefore of the complex).
- static const unsigned D = I::dim;
- /// Geometry of the image.
- typedef mln_geom(I) G;
- /// Psite type.
- typedef mln::complex_psite<D, G> psite;
-
- /// Result type of the functor.
- typedef bool result;
-
- is_simple_cell()
- : ima_(0)
- {
- }
-
- is_simple_cell(const mln::Image<I>& ima)
- : ima_(mln::exact(&ima))
- {
- }
-
- /* FIXME: Rename as init() or something like this? See how other
- functors are written. */
- /// Set the underlying image.
- void set_image(const mln::Image<I>& ima)
- {
- ima_ = mln::exact(&ima);
- }
-
- // Based on the algorithm A2 from couprie.08.pami.
- bool operator()(const psite& p) const
- {
- mln_precondition(ima_);
-
- typedef p_set<psite> faces_t;
-
- // Compute the attachment of the cell corresponding to P to he
- // domain of *IMA_.
- faces_t att = attachment(p, *ima_);
-
- // A cell with an empty attachment is not simple.
- /* FIXME: Why does p_set not provide an empty() predicate? */
- if (att.nsites() == 0)
- return false;
-
- /* FIXME: This part could be moved to its own function/method
- (`is_collapsible'). Moreover, the code could be split: looking
- up for a free pair (g, h) could be performed in another
- routine. */
- // Try to collapse the attachment (to a single point).
- {
- typedef complex_lower_neighborhood<D, G> lower_adj_nbh_t;
- typedef complex_higher_neighborhood<D, G> higher_adj_nbh_t;
- lower_adj_nbh_t lower_adj_nbh;
- higher_adj_nbh_t higher_adj_nbh;
- while (att.nsites() > 1)
- {
-
- bool simple_pair_collapsed = false;
- /* FIXME: The selection of G and H is probably suboptimal
- (i.e., selecting G has a face of highest avalaible
- dimension in CELL is probably smarter). */
- mln_piter(faces_t) g(att);
- for_all(g)
- /* G cannot have dimension 0, since we later look for an
- adjacent face H of lower dimension. */
- if (static_cast<psite>(g).n() > 0)
- {
- // Check whether G is a facet within ATT.
- bool g_is_facet = true;
- mln_niter(higher_adj_nbh_t) f(higher_adj_nbh, g);
- for_all(f)
- if (att.has(f))
- {
- g_is_facet = false;
- break;
- }
- if (!g_is_facet)
- break;
-
- // Look for a face H stricly included in G.
- bool gh_is_simple_pair = false;
- mln_niter(lower_adj_nbh_t) h(lower_adj_nbh, g);
- for_all(h)
- {
- bool h_strictly_in_g = true;
- if (att.has(h))
- {
- mln_niter(higher_adj_nbh_t) i(higher_adj_nbh, h);
- for_all(i)
- if (i != g && att.has(i))
- {
- h_strictly_in_g = false;
- break;
- }
- }
- if (h_strictly_in_g)
- {
- gh_is_simple_pair = true;
- att.remove(g);
- att.remove(h);
- mln_invariant(att.nsites() > 0);
- break;
- }
- } // for_all(h)
-
- // If a free pair (G, H) has been found and removed,
- // restart the free pair look up from the beginning.
- if (gh_is_simple_pair)
- {
- simple_pair_collapsed = true;
- break;
- }
- } // for_all(g)
-
- if (!simple_pair_collapsed)
- // If no free pair (G, H) was found, then the attachment is
- // not collapsible.
- return false;
-
- } // while (att.nsites() > 1)
-
- mln_postcondition(att.nsites() == 1);
- mln_postcondition(att[0].n() == 0);
- // If the attachment is collapsible to a 0-face, then the cell
- // corresponding to the (face) P is simple.
- return true;
- }
- }
-
-private:
- const I* ima_;
-};
-
-
-// FIXME: Doc.
-template <unsigned D, typename G, typename V>
-void
-detach (const mln::complex_psite<D, G>f, mln::complex_image<D, G, V>& ima)
-{
- mlc_equal(V, bool)::check();
-
- typedef mln::complex_psite<D, G> psite;
- typedef p_set<psite> faces_t;
-
- // Compute the detachment of P from IMA.
- faces_t detach = detachment(f, ima);
- // Detach all its faces from IMA.
-#if 0
- // FIXME: Does not work yet? Check again.
- data::fill(ima | detach, false);
-#endif
- mln_piter(faces_t) p(detach);
- for_all(p)
- ima(p) = false;
-}
-
-
-// FIXME: Move this elsewhere.
-// FIXME: Use a generic `I' instead of `mln::bin_2complex_image3df'.
-// FIXME: Update doc.
-/* FIXME: Rename `constraint' to a verb or adjective?
- (validate_constraint? satisfy_constraint? pass_constraint?
- is_satisfying?) */
-/** \brief Breadth-First Thinning.
-
- A non generic implementation of a binary skeleton on a triangle
- surface (mesh).
-
- \a N is the adjacency relation between triangles, but it probably
- does not make sense to use something other than an instance of
- mln::complex_lower_dim_connected_n_face_neighborhood if the image type is
- hard-coded as mln::bin_2complex_image3df. */
-template <typename N, typename F, typename G>
-mln::bin_2complex_image3df
-skeleton(const mln::bin_2complex_image3df& input,
- const mln::Neighborhood<N>& nbh_,
- mln::Function_p2b<F>& is_simple_,
- const mln::Function_p2b<G>& constraint_ = mln::fun::p2b::tautology())
-{
- const N& nbh = exact(nbh_);
- F& is_simple = exact(is_simple_);
- const G& constraint = exact(constraint_);
-
- typedef mln::bin_2complex_image3df I;
- typedef mln_psite(I) psite;
-
- I output = mln::duplicate(input);
- // Attach the work image to IS_SIMPLE.
- is_simple.set_image(output);
-
- typedef mln::p_set<psite> set_t;
- set_t set;
-
- // Populate the set with candiate simple points.
- mln_piter(I) p_(output.domain());
- for_all(p_)
- {
- /* CONSTRAINTS and IS_SIMPLE are site-to-boolean (p2b) predicate
- functors; passing an iterator as argument might not be possible
- (C++ cannot resolve template routines if an implicit conversion
- of the argument is needed). Help the compiler and pass an
- actual, explicit psite. */
- psite p = p_;
- if (output(p) && constraint(p) && is_simple(p))
- set.insert(p);
- }
-
- while (!set.is_empty())
- {
- set_t next_set;
- // FIXME: Use a piter on SET instead of this hand-made iteration.
- for (unsigned i = 0; i < set.nsites(); ++i)
- {
- psite p = set[i];
- /* FIXME: We compute the cell and attachment of P twice:
- within is_simple and within detach. How could we reuse
- this elegantly, without breaking the genericity of the
- skeleton algorithm? */
- if (constraint(p) && is_simple(p))
- {
- // FIXME: `detach' could be a functor, as is `is_simple'.
- detach(p, output);
- mln_niter(N) n(nbh, p);
- for_all(n)
- if (output.domain().has(n)
- && output(n) && constraint(p) && is_simple(n))
- next_set.insert(n);
- }
- }
- set.clear();
- std::swap(set, next_set);
- }
- return output;
-}
-
-
-// Fwd. decl.
-template <unsigned N> struct is_n_face;
-
-/// A functor testing wheter a mln::complex_psite is an \N-face.
-template <unsigned N>
-struct is_n_face : public mln::Function_p2b< is_n_face<N> >
-{
- typedef bool result;
-
- template <unsigned D, typename G>
- bool operator()(const mln::complex_psite<D, G>& p) const
- {
- return p.n() == N;
- }
-};
-
-
-int main(int argc, char* argv[])
+int
+main(int argc, char* argv[])
{
if (argc != 4)
{
@@ -476,7 +63,6 @@ int main(int argc, char* argv[])
}
std::string input_filename = argv[1];
- // FIXME: Use lambda to filter the input.
unsigned lambda = atoi(argv[2]);
std::string output_filename = argv[3];
@@ -601,14 +187,19 @@ int main(int argc, char* argv[])
| Skeleton. |
`-----------*/
- is_simple_cell<bin_ima_t> is_simple_p;
+ mln::topo::is_simple_cell<bin_ima_t> is_simple_p;
/* FIXME: Cheat! We'd like to iterate on cells of highest
dimension (2-cells) only, but we cannot constrain the domain of
- the input using image_if (yet). As a workaround, we use the
- constraint predicate of the skeleton routine to restrict the
- iteration to 2-cells. */
- is_n_face<bin_ima_t::dim> constraint;
- bin_ima_t skel = skeleton(surface, nbh, is_simple_p, constraint);
+ the input using image_if (yet) like this
+
+ breadth_first_thinning(surface | is_n_face<2>, nbh, is_simple_p);
+
+ As a workaround, we use the constraint predicate of the
+ skeleton routine to restrict the iteration to 2-cells. */
+ mln::topo::is_n_face<bin_ima_t::dim> constraint_p;
+ bin_ima_t skel =
+ mln::topo::skeleton::breadth_first_thinning(surface, nbh, is_simple_p,
+ constraint_p);
/*---------.
| Output. |
diff --git a/milena/mln/make/attachment.hh b/milena/mln/make/attachment.hh
new file mode 100644
index 0000000..6ac056b
--- /dev/null
+++ b/milena/mln/make/attachment.hh
@@ -0,0 +1,102 @@
+// Copyright (C) 2009 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_MAKE_ATTACHMENT_HH
+# define MLN_MAKE_ATTACHMENT_HH
+
+/// \file mln/make/attachment.hh
+/// \brief Compute the attachment of a cell to a binary
+/// complex-based image.
+
+# include <mln/core/image/complex_image.hh>
+# include <mln/make/cell.hh>
+# include <mln/topo/is_facet.hh>
+
+namespace mln
+{
+
+ namespace make
+ {
+
+ /** \brief Compute the attachment of the cell corresponding to the
+ facet \a f to the image \a ima.
+
+ \pre \a f is a facet (it does not belong to any face of higher
+ dimension).
+ \pre ima is an image of Boolean values.
+
+ \return a set of faces containing the attachment.
+
+ We do not use the fomal definition of the attachment here (see
+ couprie.08.pami). We use the following (equivalent) definition:
+ an N-face F in CELL is in the attachment of CELL to IMA if it is
+ adjacent to at least an (N-1)-face or an (N+1)-face that does not
+ belong to CELL. */
+ template <unsigned D, typename G, typename V>
+ p_set< complex_psite<D, G> >
+ attachment(const complex_psite<D, G>& f,
+ const complex_image<D, G, V>& ima);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned D, typename G, typename V>
+ inline
+ p_set< complex_psite<D, G> >
+ attachment(const complex_psite<D, G>& f,
+ const complex_image<D, G, V>& ima)
+ {
+ mln_precondition(topo::is_facet(f));
+ mlc_equal(V, bool)::check();
+
+ typedef complex_psite<D, G> psite;
+ typedef p_set<psite> faces_t;
+
+ faces_t f_hat = make::cell(f);
+ faces_t att_f;
+
+ typedef complex_lower_higher_neighborhood<D, G> adj_nbh_t;
+ adj_nbh_t adj_nbh;
+ mln_piter(faces_t) g(f_hat);
+ mln_niter(adj_nbh_t) n(adj_nbh, g);
+ for_all(g)
+ for_all(n)
+ if (ima(n) && !f_hat.has(n))
+ {
+ att_f.insert(g);
+ break;
+ }
+ return att_f;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::make
+
+} // end of namespace mln
+
+#endif // ! MLN_MAKE_ATTACHMENT_HH
diff --git a/milena/mln/make/cell.hh b/milena/mln/make/cell.hh
new file mode 100644
index 0000000..2f5a187
--- /dev/null
+++ b/milena/mln/make/cell.hh
@@ -0,0 +1,97 @@
+// Copyright (C) 2009 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_MAKE_CELL_HH
+# define MLN_MAKE_CELL_HH
+
+/// \file mln/topo/is_facet.hh
+/// \brief Computing the set of faces of the cell.
+
+# include <mln/core/site_set/p_set.hh>
+# include <mln/core/site_set/complex_psite.hh>
+# include <mln/core/image/complex_neighborhoods.hh>
+# include <mln/core/image/complex_neighborhood_piter.hh>
+
+# include <mln/topo/is_facet.hh>
+
+namespace mln
+{
+
+ namespace make
+ {
+
+ /** Compute the set of faces of the cell corresponding to the
+ facet \a f.
+
+ \pre \a f is a facet (it does not belong to any face of higher
+ dimension).
+
+ \return An mln::p_set of sites (faces) containing the
+ attachment. */
+ template <unsigned D, typename G>
+ p_set< complex_psite<D, G> >
+ cell(const complex_psite<D, G>& f);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned D, typename G>
+ inline
+ p_set< complex_psite<D, G> >
+ cell(const complex_psite<D, G>& f)
+ {
+ mln_precondition(topo::is_facet(f));
+
+ typedef complex_psite<D, G> psite;
+ typedef p_set<psite> faces_t;
+
+ // Compute the cell F^HAT.
+ faces_t f_hat;
+ /* FIXME: We need a cell-iterator here
+ (see https://trac.lrde.org/olena/ticket/162) */
+ typedef complex_m_face_neighborhood<D, G> m_faces_nbh_t;
+ m_faces_nbh_t m_faces_nbh;
+ mln_niter(m_faces_nbh_t) g(m_faces_nbh, f);
+ for (unsigned m = 0; m < f.n(); ++m)
+ {
+ g.iter().set_m(m);
+ for_all(g)
+ {
+ f_hat.insert(g);
+ }
+ }
+ f_hat.insert(f);
+ return f_hat;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::make
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_IS_FACET_HH
diff --git a/milena/mln/make/detachment.hh b/milena/mln/make/detachment.hh
new file mode 100644
index 0000000..c709a06
--- /dev/null
+++ b/milena/mln/make/detachment.hh
@@ -0,0 +1,103 @@
+// Copyright (C) 2009 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_MAKE_DETACHMENT_HH
+# define MLN_MAKE_DETACHMENT_HH
+
+/// \file mln/make/detachment.hh
+/// \brief Compute the detachment of a cell w.r.t. from a binary
+/// complex-based image.
+
+# include <mln/core/image/complex_image.hh>
+# include <mln/make/cell.hh>
+# include <mln/topo/is_facet.hh>
+
+namespace mln
+{
+
+ namespace make
+ {
+
+ /** \brief Compute the detachment of the cell corresponding to the
+ facet \a f to the image \a ima.
+
+ \pre \a f is a facet (it does not belong to any face of higher
+ dimension).
+ \pre \a ima is an image of Boolean values.
+
+ \return a set of faces containing the detachment.
+
+ We do not use the fomal definition of the detachment here (see
+ couprie.08.pami). We use the following (equivalent) definition:
+ an N-face F in CELL is not in the detachment of CELL from IMA if
+ it is adjacent to at least an (N-1)-face or an (N+1)-face that
+ does not belong to CELL. */
+ template <unsigned D, typename G, typename V>
+ p_set< complex_psite<D, G> >
+ detachment(const complex_psite<D, G>& f,
+ const complex_image<D, G, V>& ima);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned D, typename G, typename V>
+ inline
+ p_set< complex_psite<D, G> >
+ detachment(const complex_psite<D, G>& f,
+ const complex_image<D, G, V>& ima)
+ {
+ mln_precondition(topo::is_facet(f));
+ mlc_equal(V, bool)::check();
+
+ typedef complex_psite<D, G> psite;
+ typedef p_set<psite> faces_t;
+
+ faces_t f_hat = make::cell(f);
+ // Initialize DETACH_F to F_HAT.
+ faces_t detach_f = f_hat;
+
+ typedef complex_lower_higher_neighborhood<D, G> adj_nbh_t;
+ adj_nbh_t adj_nbh;
+ mln_piter(faces_t) g(f_hat);
+ mln_niter(adj_nbh_t) n(adj_nbh, g);
+ for_all(g)
+ for_all(n)
+ if (ima(n) && !f_hat.has(n))
+ {
+ detach_f.remove(g);
+ break;
+ }
+ return detach_f;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::make
+
+} // end of namespace mln
+
+#endif // ! MLN_MAKE_DETACHMENT_HH
diff --git a/milena/mln/topo/detach.hh b/milena/mln/topo/detach.hh
new file mode 100644
index 0000000..e80a8a9
--- /dev/null
+++ b/milena/mln/topo/detach.hh
@@ -0,0 +1,86 @@
+// Copyright (C) 2009 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_TOPO_DETACH_HH
+# define MLN_TOPO_DETACH_HH
+
+/// \file mln/topo/detach.hh
+/// \brief Detachin a cell from a binary complex-based image.
+
+# include <mln/core/site_set/p_set.hh>
+# include <mln/core/image/complex_image.hh>
+# include <mln/make/detachment.hh>
+# include <mln/topo/is_facet.hh>
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ /** Detach the cell corresponding to \a f from \a ima.
+
+ \pre \a f is a facet (it does not belong to any face of higher
+ dimension).
+ \pre \a ima is an image of Boolean values. */
+ template <unsigned D, typename G, typename V>
+ void
+ detach(const complex_psite<D, G>& f, complex_image<D, G, V>& ima);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned D, typename G, typename V>
+ inline
+ void
+ detach(const complex_psite<D, G>& f, complex_image<D, G, V>& ima)
+ {
+ mln_precondition(topo::is_facet(f));
+ mlc_equal(V, bool)::check();
+
+ typedef complex_psite<D, G> psite;
+ typedef p_set<psite> faces_t;
+
+ // Compute the detachment of P from IMA.
+ faces_t detach = make::detachment(f, ima);
+ // Detach all its faces from IMA.
+# if 0
+ // FIXME: Does not work yet? Check again.
+ data::fill(ima | detach, false);
+# endif
+ mln_piter(faces_t) p(detach);
+ for_all(p)
+ ima(p) = false;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_DETACH_HH
diff --git a/milena/mln/topo/is_facet.hh b/milena/mln/topo/is_facet.hh
new file mode 100644
index 0000000..8f6f33f
--- /dev/null
+++ b/milena/mln/topo/is_facet.hh
@@ -0,0 +1,79 @@
+// Copyright (C) 2009 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_TOPO_IS_FACET_HH
+# define MLN_TOPO_IS_FACET_HH
+
+/// \file mln/topo/is_facet.hh
+/// \brief Testing whether an mln::complex_psite is a facet.
+
+# include <mln/core/site_set/complex_psite.hh>
+# include <mln/core/image/complex_neighborhoods.hh>
+# include <mln/core/image/complex_neighborhood_piter.hh>
+
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ /* FIXME: Make this routine a method of mln::complex_psite? Or
+ better, a method of mln::topo::face? */
+
+ /// Is \a f a facet, i.e., a face not ``included in'' (adjacent
+ /// to) a face of higher dimension?
+ template <unsigned D, typename G>
+ bool
+ is_facet(const complex_psite<D, G>& f);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned D, typename G>
+ inline
+ bool
+ is_facet(const complex_psite<D, G>& f)
+ {
+ typedef complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ higher_adj_nbh_t higher_adj_nbh;
+ mln_niter(higher_adj_nbh_t) n(higher_adj_nbh, f);
+ for_all(n)
+ // If the neighborhood is not empty, then F is included in a face
+ // of higher dimension.
+ return false;
+ // Otherwise, F is a facet.
+ return true;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_IS_FACET_HH
diff --git a/milena/mln/topo/is_n_face.hh b/milena/mln/topo/is_n_face.hh
new file mode 100644
index 0000000..33bce33
--- /dev/null
+++ b/milena/mln/topo/is_n_face.hh
@@ -0,0 +1,75 @@
+// Copyright (C) 2009 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_TOPO_IS_N_FACE_HH
+# define MLN_TOPO_IS_N_FACE_HH
+
+/// \file mln/topo/is_facet.hh
+/// \brief Testing whether an mln::complex_psite is an n-face.
+
+# include <mln/core/site_set/complex_psite.hh>
+# include <mln/core/image/complex_neighborhoods.hh>
+# include <mln/core/image/complex_neighborhood_piter.hh>
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ // Forward declaration.
+ template <unsigned N> struct is_n_face;
+
+ /// A functor testing wheter a mln::complex_psite is an \N-face.
+ template <unsigned N>
+ struct is_n_face : public mln::Function_p2b< is_n_face<N> >
+ {
+ typedef bool result;
+
+ template <unsigned D, typename G>
+ bool operator()(const mln::complex_psite<D, G>& p) const;
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned N>
+ template <unsigned D, typename G>
+ inline
+ bool
+ is_n_face<N>::operator()(const mln::complex_psite<D, G>& p) const
+ {
+ return p.n() == N;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_IS_N_FACE_HH
diff --git a/milena/mln/topo/is_simple_cell.hh b/milena/mln/topo/is_simple_cell.hh
new file mode 100644
index 0000000..f81b7cc
--- /dev/null
+++ b/milena/mln/topo/is_simple_cell.hh
@@ -0,0 +1,220 @@
+// Copyright (C) 2009 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_TOPO_IS_SIMPLE_CELL_HH
+# define MLN_TOPO_IS_SIMPLE_CELL_HH
+
+/// \file mln/topo/is_simple_cell.hh
+/// \brief Testing whether a facet is a simple cell.
+
+# include <mln/core/concept/function.hh>
+# include <mln/core/concept/image.hh>
+
+# include <mln/core/site_set/p_set.hh>
+# include <mln/core/site_set/complex_psite.hh>
+# include <mln/core/site_set/p_complex_piter.hh>
+# include <mln/core/image/complex_neighborhoods.hh>
+# include <mln/core/image/complex_neighborhood_piter.hh>
+
+# include <mln/make/attachment.hh>
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ /** \brief A predicate for the simplicity of a point based on the
+ collapse property of the attachment.
+
+ The functor does not actually take a cell as input, but a face
+ that is expected to be a D-facet. */
+ template <typename I>
+ class is_simple_cell : public mln::Function_p2b< is_simple_cell<I> >
+ {
+ public:
+ /// Dimension of the image (and therefore of the complex).
+ static const unsigned D = I::dim;
+ /// Geometry of the image.
+ typedef mln_geom(I) G;
+ /// Psite type.
+ typedef mln::complex_psite<D, G> psite;
+
+ /// Result type of the functor.
+ typedef bool result;
+
+ is_simple_cell();
+ is_simple_cell(const mln::Image<I>& ima);
+
+ /* FIXME: Rename as init() or something like this? See how other
+ functors are written. */
+ /// Set the underlying image.
+ void set_image(const mln::Image<I>& ima);
+
+ /// Based on the algorithm A2 from couprie.08.pami.
+ bool operator()(const psite& p) const;
+
+ private:
+ const I* ima_;
+ };
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ inline
+ is_simple_cell<I>::is_simple_cell()
+ : ima_(0)
+ {
+ }
+
+ template <typename I>
+ inline
+ is_simple_cell<I>::is_simple_cell(const mln::Image<I>& ima)
+ : ima_(mln::exact(&ima))
+ {
+ }
+
+ template <typename I>
+ inline
+ void
+ is_simple_cell<I>::set_image(const mln::Image<I>& ima)
+ {
+ ima_ = mln::exact(&ima);
+ }
+
+ template <typename I>
+ inline
+ bool
+ is_simple_cell<I>::operator()(const is_simple_cell<I>::psite& p) const
+ {
+ mln_precondition(ima_);
+
+ typedef p_set<psite> faces_t;
+
+ // Compute the attachment of the cell corresponding to P to he
+ // domain of *IMA_.
+ faces_t att = make::attachment(p, *ima_);
+
+ // A cell with an empty attachment is not simple.
+ /* FIXME: Why does p_set not provide an empty() predicate? */
+ if (att.nsites() == 0)
+ return false;
+
+ /* FIXME: This part could be moved to its own function/method
+ (`is_collapsible'). Moreover, the code could be split: looking
+ up for a free pair (g, h) could be performed in another
+ routine. */
+ // Try to collapse the attachment (to a single point).
+ {
+ typedef complex_lower_neighborhood<D, G> lower_adj_nbh_t;
+ typedef complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ lower_adj_nbh_t lower_adj_nbh;
+ higher_adj_nbh_t higher_adj_nbh;
+ while (att.nsites() > 1)
+ {
+
+ bool simple_pair_collapsed = false;
+ /* FIXME: The selection of G and H is probably suboptimal
+ (i.e., selecting G has a face of highest avalaible
+ dimension in CELL is probably smarter). */
+ mln_piter(faces_t) g(att);
+ for_all(g)
+ /* G cannot have dimension 0, since we later look for an
+ adjacent face H of lower dimension. */
+ if (static_cast<psite>(g).n() > 0)
+ {
+ // Check whether G is a facet within ATT.
+ bool g_is_facet = true;
+ mln_niter(higher_adj_nbh_t) f(higher_adj_nbh, g);
+ for_all(f)
+ if (att.has(f))
+ {
+ g_is_facet = false;
+ break;
+ }
+ if (!g_is_facet)
+ break;
+
+ // Look for a face H stricly included in G.
+ bool gh_is_simple_pair = false;
+ mln_niter(lower_adj_nbh_t) h(lower_adj_nbh, g);
+ for_all(h)
+ {
+ bool h_strictly_in_g = true;
+ if (att.has(h))
+ {
+ mln_niter(higher_adj_nbh_t) i(higher_adj_nbh, h);
+ for_all(i)
+ if (i != g && att.has(i))
+ {
+ h_strictly_in_g = false;
+ break;
+ }
+ }
+ if (h_strictly_in_g)
+ {
+ gh_is_simple_pair = true;
+ att.remove(g);
+ att.remove(h);
+ mln_invariant(att.nsites() > 0);
+ break;
+ }
+ } // for_all(h)
+
+ // If a free pair (G, H) has been found and removed,
+ // restart the free pair look up from the beginning.
+ if (gh_is_simple_pair)
+ {
+ simple_pair_collapsed = true;
+ break;
+ }
+ } // for_all(g)
+
+ if (!simple_pair_collapsed)
+ // If no free pair (G, H) was found, then the attachment is
+ // not collapsible.
+ return false;
+
+ } // while (att.nsites() > 1)
+
+ mln_postcondition(att.nsites() == 1);
+ mln_postcondition(att[0].n() == 0);
+ // If the attachment is collapsible to a 0-face, then the cell
+ // corresponding to the (face) P is simple.
+ return true;
+ }
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_IS_SIMPLE_CELL_HH
diff --git a/milena/mln/topo/skeleton/breadth_first_thinning.hh b/milena/mln/topo/skeleton/breadth_first_thinning.hh
new file mode 100644
index 0000000..ee4c5f2
--- /dev/null
+++ b/milena/mln/topo/skeleton/breadth_first_thinning.hh
@@ -0,0 +1,156 @@
+// Copyright (C) 2009 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_TOPO_SKELETON_BREADTH_FIRST_THINNING_HH
+# define MLN_TOPO_SKELETON_BREADTH_FIRST_THINNING_HH
+
+/// \file mln/topo/skeleton/breadth_first_thinning.hh
+/// \brief Computing a skeleton by using breadth-first thinning on a
+/// binary image.
+
+# include <algorithm>
+
+# include <mln/core/routine/duplicate.hh>
+
+# include <mln/core/site_set/p_set.hh>
+# include <mln/core/alias/complex_image.hh>
+# include <mln/topo/detach.hh>
+
+# include <mln/fun/p2b/tautology.hh>
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ namespace skeleton
+ {
+
+ /* FIXME: Use a generic `I' instead of
+ `mln::bin_2complex_image3df', and adjust the
+ documentation. */
+
+ /* FIXME: Rename `constraint' to a verb or adjective?
+ (validate_constraint? satisfy_constraint? pass_constraint?
+ is_satisfying?) */
+
+ /** \brief Breadth-First Thinning.
+
+ A semi-generic implementation of a binary skeleton on a triangle
+ surface (mesh).
+
+ \param input The input image.
+ \param nbh The adjacency relation between triangles.
+ \param is_simple The predicate on the simplicity of points (sites).
+ \param constraint A constraint on point (site); if it
+ returns \c false for a point, this point
+ will not be removed. */
+ template <typename N, typename F, typename G>
+ bin_2complex_image3df
+ breadth_first_thinning(const bin_2complex_image3df& input,
+ const Neighborhood<N>& nbh,
+ Function_p2b<F>& is_simple,
+ const Function_p2b<G>& constraint =
+ fun::p2b::tautology());
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename N, typename F, typename G>
+ inline
+ bin_2complex_image3df
+ breadth_first_thinning(const bin_2complex_image3df& input,
+ const Neighborhood<N>& nbh_,
+ Function_p2b<F>& is_simple_,
+ const Function_p2b<G>& constraint_)
+ {
+ const N& nbh = exact(nbh_);
+ F& is_simple = exact(is_simple_);
+ const G& constraint = exact(constraint_);
+
+ typedef bin_2complex_image3df I;
+ typedef mln_psite(I) psite;
+
+ I output = duplicate(input);
+ // Attach the work image to IS_SIMPLE.
+ is_simple.set_image(output);
+
+ typedef p_set<psite> set_t;
+ set_t set;
+
+ // Populate the set with candiate simple points.
+ mln_piter(I) p_(output.domain());
+ for_all(p_)
+ {
+ /* CONSTRAINTS and IS_SIMPLE are site-to-boolean (p2b)
+ predicate functors; passing an iterator as argument might
+ not be possible (C++ cannot resolve template routines if
+ an implicit conversion of the argument is needed). Help
+ the compiler and pass an actual, explicit psite. */
+ psite p = p_;
+ if (output(p) && constraint(p) && is_simple(p))
+ set.insert(p);
+ }
+
+ while (!set.is_empty())
+ {
+ set_t next_set;
+ // FIXME: Use a piter on SET instead of this hand-made iteration.
+ for (unsigned i = 0; i < set.nsites(); ++i)
+ {
+ psite p = set[i];
+ /* FIXME: We compute the cell and attachment of P
+ twice: within is_simple and within detach. How
+ could we reuse this elegantly, without breaking the
+ genericity of the skeleton algorithm? */
+ if (constraint(p) && is_simple(p))
+ {
+ // FIXME: `detach' could be a functor, as is `is_simple'.
+ topo::detach(p, output);
+ mln_niter(N) n(nbh, p);
+ for_all(n)
+ if (output.domain().has(n)
+ && output(n) && constraint(p) && is_simple(n))
+ next_set.insert(n);
+ }
+ }
+ set.clear();
+ std::swap(set, next_set);
+ }
+ return output;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo::skeleton
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_SKELETON_BREADTH_FIRST_THINNING_HH
--
1.6.1.2
1
0
07 Apr '09
---
milena/ChangeLog | 4 ++
milena/apps/statues/mesh-complex-skel.cc | 63 ------------------------------
2 files changed, 4 insertions(+), 63 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 3ff49e1..ce4316d 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,9 @@
2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+ * apps/statues/mesh-complex-skel.cc: Remove dead code.
+
+2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+
Be more generic in mesh-complex-skel w.r.t. site constraints.
* apps/statues/mesh-complex-skel.cc (is_n_face<N>::operator()):
diff --git a/milena/apps/statues/mesh-complex-skel.cc b/milena/apps/statues/mesh-complex-skel.cc
index 9ddbafd..7c103b2 100644
--- a/milena/apps/statues/mesh-complex-skel.cc
+++ b/milena/apps/statues/mesh-complex-skel.cc
@@ -67,69 +67,6 @@
// to the library.
using namespace mln;
-// Fwd. decl.
-template <typename I> struct is_simple_triangle;
-
-// // A very simple and limited predicate for the simplicity of a point.
-// template <typename I>
-// class is_simple_triangle
-// : public mln::Function_p2b< is_simple_triangle<I> >
-// {
-// public:
-// /// Dimension of the image (and therefore of the complex).
-// static const unsigned D = I::dim;
-// /// Geometry of the image.
-// typedef mln_geom(I) G;
-// /// Psite type.
-// typedef mln::complex_psite<D, G> psite;
-
-// /// Result type of the functor.
-// typedef bool result;
-
-// is_simple_triangle()
-// : ima_(0), nbh_()
-// {
-// }
-
-// is_simple_triangle(const mln::Image<I>& ima)
-// : ima_(mln::exact(&ima)), nbh_()
-// {
-// }
-
-// /* FIXME: Rename as init() or something like this? See how other
-// functors are written. */
-// /// Set the underlying image.
-// void set_image(const mln::Image<I>& ima)
-// {
-// ima_ = mln::exact(&ima);
-// }
-
-// bool operator()(const psite& p) const
-// {
-// mln_precondition(ima_);
-// unsigned nneighbs = 0;
-// mln_niter(nbh_t) n(nbh_, p);
-// for_all(n)
-// if ((*ima_)(n))
-// ++nneighbs;
-// mln_invariant(n <= 3);
-// /* FIXME: Dummy: A triangle is considered simple if it is not
-// completely attached nor completely detached (i.e, if it has
-// more than 0 adjacent triangles but less than three). This test
-// is obiously simplistic and wrong, but we'll use it as a first
-// approximation. We should use the notion of free pair later.
-// And provide efficient, mask-based version as well. */
-// return 0 < nneighbs && nneighbs < 3;
-// }
-
-// private:
-// const I* ima_;
-
-// // FIXME: Make this type a parameter of the functor?
-// typedef mln::complex_lower_dim_connected_n_face_neighborhood<D, G> nbh_t;
-// nbh_t nbh_;
-// };
-
// FIXME: Doc.
template <unsigned D, typename G>
--
1.6.1.2
1
0
[PATCH 4/7] Be more generic in mesh-complex-skel w.r.t. site constraints.
by Roland Levillain 07 Apr '09
by Roland Levillain 07 Apr '09
07 Apr '09
* apps/statues/mesh-complex-skel.cc (is_n_face<N>::operator()):
Make it const.
(skeleton): Accept a constraint functor as fourth argument.
Remove non generic constraints on the dimension of the candidate
sites.
(main): Adjust caller: use is_n_face<N> to constrain the dimension
of the considered simple faces from the outside of skeleton().
---
milena/ChangeLog | 12 +++++
milena/apps/statues/mesh-complex-skel.cc | 71 +++++++++++++-----------------
2 files changed, 42 insertions(+), 41 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index b637f0a..3ff49e1 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,17 @@
2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+ Be more generic in mesh-complex-skel w.r.t. site constraints.
+
+ * apps/statues/mesh-complex-skel.cc (is_n_face<N>::operator()):
+ Make it const.
+ (skeleton): Accept a constraint functor as fourth argument.
+ Remove non generic constraints on the dimension of the candidate
+ sites.
+ (main): Adjust caller: use is_n_face<N> to constrain the dimension
+ of the considered simple faces from the outside of skeleton().
+
+2009-04-07 Roland Levillain <roland(a)lrde.epita.fr>
+
Add a tautology and an antilogy p2b functors.
* mln/fun/p2b/tautology.hh,
diff --git a/milena/apps/statues/mesh-complex-skel.cc b/milena/apps/statues/mesh-complex-skel.cc
index 1fa460e..9ddbafd 100644
--- a/milena/apps/statues/mesh-complex-skel.cc
+++ b/milena/apps/statues/mesh-complex-skel.cc
@@ -54,6 +54,8 @@
#include <mln/morpho/erosion.hh>
#include <mln/morpho/closing/area.hh>
+#include <mln/fun/p2b/tautology.hh>
+
#include <mln/io/off/load.hh>
#include <mln/io/off/save.hh>
/* FIXME: Remove as soon as mln::io::off::save is able to save a
@@ -433,7 +435,10 @@ detach (const mln::complex_psite<D, G>f, mln::complex_image<D, G, V>& ima)
// FIXME: Move this elsewhere.
// FIXME: Use a generic `I' instead of `mln::bin_2complex_image3df'.
-// FIXME: Add a constraint/priority argument (K/P).
+// FIXME: Update doc.
+/* FIXME: Rename `constraint' to a verb or adjective?
+ (validate_constraint? satisfy_constraint? pass_constraint?
+ is_satisfying?) */
/** \brief Breadth-First Thinning.
A non generic implementation of a binary skeleton on a triangle
@@ -443,14 +448,16 @@ detach (const mln::complex_psite<D, G>f, mln::complex_image<D, G, V>& ima)
does not make sense to use something other than an instance of
mln::complex_lower_dim_connected_n_face_neighborhood if the image type is
hard-coded as mln::bin_2complex_image3df. */
-template <typename N, typename F>
+template <typename N, typename F, typename G>
mln::bin_2complex_image3df
skeleton(const mln::bin_2complex_image3df& input,
const mln::Neighborhood<N>& nbh_,
- mln::Function_p2b<F>& is_simple_)
+ mln::Function_p2b<F>& is_simple_,
+ const mln::Function_p2b<G>& constraint_ = mln::fun::p2b::tautology())
{
const N& nbh = exact(nbh_);
F& is_simple = exact(is_simple_);
+ const G& constraint = exact(constraint_);
typedef mln::bin_2complex_image3df I;
typedef mln_psite(I) psite;
@@ -463,19 +470,16 @@ skeleton(const mln::bin_2complex_image3df& input,
set_t set;
// Populate the set with candiate simple points.
- mln_piter(I) p(output.domain());
- for_all(p)
+ mln_piter(I) p_(output.domain());
+ for_all(p_)
{
- /* FIXME: Cheat! We'd like to iterate on 2-cells only, but
- we cannot constrain the domain of the input using
- image_if (yet). Hence this filter to restrict the
- dimension of the considered cells. A less dirty
- approaach would be to use a constraint predicate (see
- comment above). */
- if (p.unproxy_().n() != I::dim)
- continue;
-
- if (output(p) && is_simple(p))
+ /* CONSTRAINTS and IS_SIMPLE are site-to-boolean (p2b) predicate
+ functors; passing an iterator as argument might not be possible
+ (C++ cannot resolve template routines if an implicit conversion
+ of the argument is needed). Help the compiler and pass an
+ actual, explicit psite. */
+ psite p = p_;
+ if (output(p) && constraint(p) && is_simple(p))
set.insert(p);
}
@@ -486,45 +490,24 @@ skeleton(const mln::bin_2complex_image3df& input,
for (unsigned i = 0; i < set.nsites(); ++i)
{
psite p = set[i];
-
- /* FIXME: Cheat! We'd like to iterate on 2-cells only, but
- we cannot constrain the domain of the input using
- image_if (yet). Hence this filter to restrict the
- dimension of the considered cells. A less dirty
- approaach would be to use a constraint predicate (see
- comment above). */
- if (p.n() != I::dim)
- continue;
-
/* FIXME: We compute the cell and attachment of P twice:
within is_simple and within detach. How could we reuse
this elegantly, without breaking the genericity of the
skeleton algorithm? */
- if (is_simple(p))
+ if (constraint(p) && is_simple(p))
{
// FIXME: `detach' could be a functor, as is `is_simple'.
detach(p, output);
mln_niter(N) n(nbh, p);
for_all(n)
- {
- /* FIXME: Cheat! We'd like to iterate on 2-cells only, but
- we cannot constrain the domain of the input using
- image_if (yet). Hence this filter to restrict the
- dimension of the considered cells. A less dirty
- approaach would be to use a constraint predicate (see
- comment above). */
- if (n.unproxy_().n() != I::dim)
- continue;
-
- if (output.domain().has(n) && output(n) && is_simple(n))
+ if (output.domain().has(n)
+ && output(n) && constraint(p) && is_simple(n))
next_set.insert(n);
- }
}
}
set.clear();
std::swap(set, next_set);
}
-
return output;
}
@@ -539,7 +522,7 @@ struct is_n_face : public mln::Function_p2b< is_n_face<N> >
typedef bool result;
template <unsigned D, typename G>
- bool operator()(const mln::complex_psite<D, G>& p)
+ bool operator()(const mln::complex_psite<D, G>& p) const
{
return p.n() == N;
}
@@ -682,7 +665,13 @@ int main(int argc, char* argv[])
`-----------*/
is_simple_cell<bin_ima_t> is_simple_p;
- bin_ima_t skel = skeleton(surface, nbh, is_simple_p);
+ /* FIXME: Cheat! We'd like to iterate on cells of highest
+ dimension (2-cells) only, but we cannot constrain the domain of
+ the input using image_if (yet). As a workaround, we use the
+ constraint predicate of the skeleton routine to restrict the
+ iteration to 2-cells. */
+ is_n_face<bin_ima_t::dim> constraint;
+ bin_ima_t skel = skeleton(surface, nbh, is_simple_p, constraint);
/*---------.
| Output. |
--
1.6.1.2
1
0