https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add ICDAR-related code.
* theo/icdar/dibco/wst-based.sh: New.
* theo/icdar/hsc/boxes.cc: New.
* theo/icdar/hsc/main.cc: New.
dibco/wst-based.sh | 8 +
hsc/boxes.cc | 102 ++++++++++++++
hsc/main.cc | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 495 insertions(+)
Index: theo/icdar/dibco/wst-based.sh
--- theo/icdar/dibco/wst-based.sh (revision 0)
+++ theo/icdar/dibco/wst-based.sh (revision 0)
@@ -0,0 +1,8 @@
+#! /bin/zsh
+
+./+bin/elementary_gradient $1 1 tmp_grad.pgm
+./+bin/closing_volume tmp_grad.pgm 500 tmp_clo.pgm
+./+bin/watershed_flooding tmp_clo.pgm tmp_wst.pgm
+./+bin/watershed_superpose $1 tmp_wst.pgm ${1%pgm}ppm
+
+rm tmp_grad.pgm tmp_clo.pgm tmp_wst.pgm
Property changes on: theo/icdar/dibco/wst-based.sh
___________________________________________________________________
Added: svn:executable
+ *
Index: theo/icdar/hsc/boxes.cc
--- theo/icdar/hsc/boxes.cc (revision 0)
+++ theo/icdar/hsc/boxes.cc (revision 0)
@@ -0,0 +1,102 @@
+// 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
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#include <iostream>
+
+#include <mln/essential/2d.hh>
+#include <mln/debug/colorize.hh>
+#include <mln/debug/println.hh>
+
+#include <scribo/text/extract_bboxes.hh>
+#include <scribo/text/grouping/group_with_single_left_link.hh>
+#include <scribo/text/grouping/group_with_single_right_link.hh>
+#include <scribo/debug/save_linked_textbboxes_image.hh>
+#include <scribo/text/grouping/group_from_double_link.hh>
+#include <scribo/filter/small_components.hh>
+
+#include <scribo/debug/save_textbboxes_image.hh>
+#include <scribo/make/debug_filename.hh>
+
+#include <mln/logical/not.hh>
+#include <mln/io/dump/save.hh>
+
+
+int usage(const char *name)
+{
+ std::cout << "Usage: " << name << " input.pbm
output.dump" << std::endl;
+ return 1;
+}
+
+
+int main(int argc, char* argv[])
+{
+ using namespace scribo;
+ using namespace mln;
+
+ if (argc != 3)
+ return usage(argv[0]);
+
+ scribo::make::internal::debug_filename_prefix = "extract_text_double_link";
+
+ image2d<bool> input;
+ io::pbm::load(input, argv[1]);
+
+ logical::not_inplace(input);
+
+ value::label_16 nbboxes;
+ scribo::util::text<image2d<value::label_16> >
+ text = text::extract_bboxes(input, c8(), nbboxes);
+
+ text = filter::small_components(text,4);
+
+ mln::util::array<unsigned>
+ left_link = text::grouping::group_with_single_left_link(text, 100),
+ right_link = text::grouping::group_with_single_right_link(text, 100);
+
+ std::cout << "BEFORE - nbboxes = " << nbboxes <<
std::endl;
+
+
+ scribo::debug::save_linked_textbboxes_image(input,
+ text, left_link, right_link,
+ literal::red, literal::cyan, literal::yellow,
+ literal::green,
+ scribo::make::debug_filename("links.ppm"));
+
+ // Validation.
+ scribo::util::text<image2d<value::label_16> > grouped_text
+ = text::grouping::group_from_double_link(text, left_link, right_link);
+
+ std::cout << "AFTER double grouping - nbboxes = " <<
grouped_text.bboxes().nelements() << std::endl;
+
+ io::dump::save(grouped_text.label_image(), argv[2]);
+
+ scribo::debug::save_textbboxes_image(input, grouped_text.bboxes(),
+ literal::red,
+ scribo::make::debug_filename("boxes.ppm"));
+
+}
+
Index: theo/icdar/hsc/main.cc
--- theo/icdar/hsc/main.cc (revision 0)
+++ theo/icdar/hsc/main.cc (revision 0)
@@ -0,0 +1,385 @@
+#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 <mln/accu/stat/variance.hh>
+
+
+
+namespace mln
+{
+
+
+ template <typename L>
+ inline
+ L find_root_(std::vector<L>& parent, L l)
+ {
+ if (parent[l] == l)
+ return l;
+ return parent[l] = find_root_(parent, parent[l]);
+ }
+
+
+
+ template <typename L>
+ image2d<L>
+ merge(const image2d<value::int_u8>& ima,
+ const image2d<L>& ws,
+ L n,
+ unsigned n_min_stats)
+ {
+ typedef accu::stat::variance<float> A;
+ std::vector<A>
+ vvar(n + 1),
+ hvar(n + 1);
+
+ mln_piter(box2d) p(ima.domain());
+ for_all(p)
+ if (ima(p) != 255 && ws(p) != 0)
+ vvar[ws(p)].take(255 - ima(p), p.row());
+
+
+ image2d<bool>
+ radj(n + 1, n + 1),
+ ladj(n + 1, n + 1);
+ data::fill(radj, false);
+ data::fill(ladj, false);
+
+ for_all(p) if (ws(p) == 0)
+ {
+ if (ws(p + left) == 0 || ws(p + right) == 0)
+ // ws is horizontal => forget it
+ continue;
+ L l1 = ws(p + left),
+ l2 = ws(p + right);
+ if (l1 == 0 || l2 == 0 || l2 == l1)
+ continue;
+ radj.at_(l1, l2) = true;
+ ladj.at_(l2, l1) = true;
+ }
+
+ std::vector<L>
+ best_right(n + 1, 0),
+ best_left(n + 1, 0);
+ L best_l2;
+ float best_score;
+
+ for (L l1 = 1; l1 <= n; ++l1)
+ {
+ if (! vvar[l1].is_valid() || vvar[l1].n_items() < n_min_stats)
+ // Non significative stats.
+ continue;
+
+
+ // Look right.
+
+# ifdef LOG
+ std::cout << l1 << ": ";
+# endif
+
+ best_l2 = 0;
+ best_score;
+
+ for (L l2 = 1; l2 <= n; ++l2)
+ {
+ if (! radj.at_(l1, l2)) // l1 -> l2
+ continue;
+
+ if (! vvar[l2].is_valid() || vvar[l2].n_items() < n_min_stats)
+ // Non significative stats.
+ continue;
+
+# ifdef LOG
+ std::cout << l2 << ' ';
+# endif
+
+ float vm, vM, sm, sM;
+ if (vvar[l1].mean() < vvar[l2].mean())
+ {
+ vm = vvar[l1].mean();
+ sm = vvar[l1].standard_deviation();
+ vM = vvar[l2].mean();
+ sM = vvar[l2].standard_deviation();
+ }
+ else
+ {
+ vm = vvar[l2].mean();
+ sm = vvar[l2].standard_deviation();
+ vM = vvar[l1].mean();
+ sM = vvar[l1].standard_deviation();
+ }
+
+ float score = (vm - sm) - (vM - sM);
+# ifdef LOG
+ std::cout << '(' << score << "), ";
+# endif
+ if (best_l2 == 0 || score > best_score)
+ {
+ best_score = score;
+ best_l2 = l2;
+ }
+ }
+
+ if (best_l2 != 0)
+ {
+ best_right[l1] = best_l2;
+# ifdef LOG
+ std::cout << " ... " << l1 << " -> "
<< best_l2 << std::endl;
+# endif
+ }
+
+ // Look left.
+
+# ifdef LOG
+ std::cout << l1 << ": ";
+# endif
+
+ best_l2 = 0;
+ best_score;
+
+ for (L l2 = 1; l2 <= n; ++l2)
+ {
+ if (! ladj.at_(l1, l2)) // l2 <- l1
+ continue;
+
+ if (! vvar[l2].is_valid() || vvar[l2].n_items() < n_min_stats)
+ // Non significative stats.
+ continue;
+
+# ifdef LOG
+ std::cout << l2 << ' ';
+# endif
+
+ float vm, vM, sm, sM;
+ if (vvar[l1].mean() < vvar[l2].mean())
+ {
+ vm = vvar[l1].mean();
+ sm = vvar[l1].standard_deviation();
+ vM = vvar[l2].mean();
+ sM = vvar[l2].standard_deviation();
+ }
+ else
+ {
+ vm = vvar[l2].mean();
+ sm = vvar[l2].standard_deviation();
+ vM = vvar[l1].mean();
+ sM = vvar[l1].standard_deviation();
+ }
+
+ float score = (vm - sm) - (vM - sM);
+# ifdef LOG
+ std::cout << '(' << score << "), ";
+# endif
+
+ if (best_l2 == 0 || score > best_score)
+ {
+ best_score = score;
+ best_l2 = l2;
+ }
+ }
+
+ if (best_l2 != 0)
+ {
+ best_left[l1] = best_l2;
+# ifdef LOG
+ std::cout << " ... " << best_l2 << " <-
" << l1 << std::endl;
+# endif
+ }
+
+ }
+
+
+ std::vector<L> parent(n + 1);
+ for (L l = 0; l <= n; ++l)
+ parent[l] = l;
+
+ for (L l1 = 1; l1 <= n; ++l1)
+ {
+ L l2 = best_right[l1];
+ if (l2 == 0)
+ continue;
+ if (best_left[l2] == l1)
+ {
+ // cross-validation
+ L l1r = find_root_(parent, l1),
+ l2r = find_root_(parent, l2);
+ if (l2r == l1r)
+ continue; // already merged
+ if (l1r < l2r)
+ parent[l1r] = l2r;
+ else
+ parent[l2r] = l1r;
+ }
+ }
+
+
+ for (L l = 1; l <= n; ++l)
+ parent[l] = find_root_(parent, l);
+
+
+ image2d<L> out(ima.domain());
+ for_all(p)
+ out(p) = parent[ws(p)];
+
+ // io::pgm::save(out, "tmp_out.pgm");
+
+ return out;
+
+ } // end of 'merge'
+
+
+
+} // ! mln
+
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pbm
output.pgm [output.ppm]" << std::endl
+ << " ICDAR'2009: HSC." << std::endl;
+ std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ 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;
+ 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));
+
+ int_u8 n_basins;
+ ws = morpho::watershed::flooding(clo, c4(), n_basins);
+
+
+ spc = merge(small, ws, n_basins, n_min_stats); // Merging!
+
+
+# ifdef LOG
+
+ {
+ io::ppm::save(debug::colorize(rgb8(), spc, n_basins),
+ "tmp_spc.ppm");
+
+ io::pgm::save(ws, "tmp_ws.pgm");
+
+ image2d<rgb8> cool = level::convert(rgb8(), small);
+ data::fill((cool | (pw::value(ws) == pw::cst(0))).rw(),
+ literal::red);
+ io::ppm::save(cool, "tmp_ws.ppm");
+ }
+# endif
+
+
+ // Outputing.
+ {
+ image2d<int_u8> output(input.domain());
+
+ image2d<rgb8>
+ cool = debug::colorize(rgb8(), spc, n_basins),
+ lab(input.domain());
+
+ mln_piter_(box2d) p(input.domain());
+ for_all(p)
+ if (input(p))
+ {
+ output(p) = 0;
+ lab(p) = literal::black;
+ }
+ else
+ {
+ output(p) = spc.at_(p.row() / subsampling_factor, p.col() / subsampling_factor);
+ lab(p) = cool.at_(p.row() / subsampling_factor, p.col() / subsampling_factor);
+ }
+
+ io::pgm::save(output, argv[2]);
+ if (argc == 4)
+ io::ppm::save(lab, argv[3]);
+ }
+
+
+ trace::exiting("main");
+}