* src/text_in_photo_ppm_fast.cc,
* src/debug/show_links_bottom_aligned.cc,
* src/debug/show_links_top_aligned.cc: Update calls to routines.
* src/preprocessing/trash.cc,
* src/text_in_photo_ppm_fast_2.cc,
* src/preprocessing/split_bg_fg_ms.cc,
* src/preprocessing/denoising.cc: Removed.
* src/preprocessing/denoise.cc,
* src/preprocessing/homogeneous_contrast.ccm,
* src/preprocessing/subsample.cc: New.
* src/preprocessing/Makefile.am: Add new files as target.
* src/preprocessing/split_bg_fg.cc: Fix usage.
* src/text_in_article.cc: Update processing chain.
---
scribo/ChangeLog | 23 +
scribo/src/debug/show_links_bottom_aligned.cc | 24 +-
scribo/src/debug/show_links_top_aligned.cc | 22 +-
scribo/src/preprocessing/Makefile.am | 13 +-
.../denoise.cc} | 31 +-
scribo/src/preprocessing/denoising.cc | 115 -----
scribo/src/preprocessing/homogeneous_contrast.cc | 44 ++
scribo/src/preprocessing/split_bg_fg.cc | 7 +-
scribo/src/preprocessing/split_bg_fg_ms.cc | 109 ----
.../subsample.cc} | 34 +-
scribo/src/text_in_article.cc | 289 +++--------
scribo/src/text_in_photo_ppm_fast.cc | 55 +-
scribo/src/text_in_photo_ppm_fast_2.cc | 541 --------------------
13 files changed, 242 insertions(+), 1065 deletions(-)
copy scribo/src/{filter/objects_with_holes.cc => preprocessing/denoise.cc} (70%)
delete mode 100644 scribo/src/preprocessing/denoising.cc
create mode 100644 scribo/src/preprocessing/homogeneous_contrast.cc
delete mode 100644 scribo/src/preprocessing/split_bg_fg_ms.cc
copy scribo/src/{text/pbm_recognition.cc => preprocessing/subsample.cc} (74%)
delete mode 100644 scribo/src/text_in_photo_ppm_fast_2.cc
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index f5deefc..87985ff 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,28 @@
2010-03-11 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Update examples.
+
+ * src/text_in_photo_ppm_fast.cc,
+ * src/debug/show_links_bottom_aligned.cc,
+ * src/debug/show_links_top_aligned.cc: Update calls to routines.
+
+ * src/preprocessing/trash.cc,
+ * src/text_in_photo_ppm_fast_2.cc,
+ * src/preprocessing/split_bg_fg_ms.cc,
+ * src/preprocessing/denoising.cc: Removed.
+
+ * src/preprocessing/denoise.cc,
+ * src/preprocessing/homogeneous_contrast.ccm,
+ * src/preprocessing/subsample.cc: New.
+
+ * src/preprocessing/Makefile.am: Add new files as target.
+
+ * src/preprocessing/split_bg_fg.cc: Fix usage.
+
+ * src/text_in_article.cc: Update processing chain.
+
+2010-03-11 Guillaume Lazzara <z(a)lrde.epita.fr>
+
Improve text line merging algorithm.
* text/merging.hh: Change merge rules and improve integration with
diff --git a/scribo/src/debug/show_links_bottom_aligned.cc
b/scribo/src/debug/show_links_bottom_aligned.cc
index 4751308..337032a 100644
--- a/scribo/src/debug/show_links_bottom_aligned.cc
+++ b/scribo/src/debug/show_links_bottom_aligned.cc
@@ -37,7 +37,9 @@
#include <mln/io/pbm/load.hh>
#include <mln/io/ppm/save.hh>
-#include <scribo/primitive/extract/objects.hh>
+#include <scribo/core/component_set.hh>
+
+#include <scribo/primitive/extract/components.hh>
#include <scribo/primitive/link/with_single_right_link_bottom.hh>
#include <scribo/filter/object_links_bottom_aligned.hh>
@@ -49,6 +51,7 @@
const char *args_desc[][2] =
{
{ "input.pbm", "A binary image. True for objects and False for the
background." },
+ { "max_dist", "Maximum distance lookup (common value 45)" },
{ "max_alpha", "Max angle between two object bottoms. (common value :
5)" },
{0, 0}
};
@@ -60,37 +63,38 @@ int main(int argc, char* argv[])
using namespace scribo::primitive::internal;
using namespace mln;
- if (argc != 4)
+ if (argc != 5)
return scribo::debug::usage(argv,
"Show valid or invalid links according the horizontal alignment (based on bottom
line).",
- "input.pbm max_alpha output.ppm",
+ "input.pbm max_dist max_alpha output.ppm",
args_desc,
"A color image. Valid links are drawn in green, invalid ones in red.");
image2d<bool> input;
io::pbm::load(input, argv[1]);
- // Finding objects.
+ // Finding components.
value::label_16 nbboxes;
typedef image2d<value::label_16> L;
- object_image(L) objects
- = scribo::primitive::extract::objects(input, c8(), nbboxes);
+ component_set<L> components
+ = scribo::primitive::extract::components(input, c8(), nbboxes);
// Finding right links.
object_links<L> right_links
- = primitive::link::with_single_right_link_bottom(objects);
+ = primitive::link::with_single_right_link_bottom(components, atoi(argv[2]));
// Filtering.
object_links<L> filtered_links
- = filter::object_links_bottom_aligned(objects, right_links, atof(argv[2]));
+ = filter::object_links_bottom_aligned(right_links, atof(argv[3]));
// Debug image.
image2d<value::rgb8> decision_image
= scribo::debug::alignment_decision_image(input,
right_links,
filtered_links,
- scribo::debug::bottom);
- io::ppm::save(decision_image, argv[3]);
+ scribo::debug::bottom,
+ atoi(argv[2]));
+ io::ppm::save(decision_image, argv[4]);
}
diff --git a/scribo/src/debug/show_links_top_aligned.cc
b/scribo/src/debug/show_links_top_aligned.cc
index 97b4a3b..ff01221 100644
--- a/scribo/src/debug/show_links_top_aligned.cc
+++ b/scribo/src/debug/show_links_top_aligned.cc
@@ -37,7 +37,7 @@
#include <mln/io/pbm/load.hh>
#include <mln/io/ppm/save.hh>
-#include <scribo/primitive/extract/objects.hh>
+#include <scribo/primitive/extract/components.hh>
#include <scribo/primitive/link/with_single_right_link_top.hh>
#include <scribo/filter/object_links_top_aligned.hh>
@@ -49,6 +49,7 @@
const char *args_desc[][2] =
{
{ "input.pbm", "A binary image. True for objects and False for the
background." },
+ { "max_dist", "Maximum distance lookup (common value 45)" },
{ "max_alpha", "Max angle between two object tops. (common value :
5)" },
{0, 0}
};
@@ -60,30 +61,30 @@ int main(int argc, char* argv[])
using namespace scribo::primitive::internal;
using namespace mln;
- if (argc != 4)
+ if (argc != 5)
return scribo::debug::usage(argv,
"Show valid or invalid links according the horizontal alignment (based on top
line).",
- "input.pbm max_alpha output.ppm",
+ "input.pbm max_dist max_alpha output.ppm",
args_desc,
"A color image. Valid links are drawn in green, invalid ones in red.");
image2d<bool> input;
io::pbm::load(input, argv[1]);
- // Finding objects.
+ // Finding components.
value::label_16 nbboxes;
typedef image2d<value::label_16> L;
- object_image(L) objects
- = scribo::primitive::extract::objects(input, c8(), nbboxes);
+ component_set<L> components
+ = scribo::primitive::extract::components(input, c8(), nbboxes);
// Finding right links.
object_links<L> right_links
- = primitive::link::with_single_right_link_top(objects);
+ = primitive::link::with_single_right_link_top(components, atoi(argv[2]));
// Filtering.
object_links<L> filtered_links
- = filter::object_links_top_aligned(objects, right_links, atof(argv[2]));
+ = filter::object_links_top_aligned(right_links, atof(argv[3]));
// Debug image.
@@ -91,7 +92,8 @@ int main(int argc, char* argv[])
= scribo::debug::alignment_decision_image(input,
right_links,
filtered_links,
- scribo::debug::top);
- io::ppm::save(decision_image, argv[3]);
+ scribo::debug::top,
+ atoi(argv[2]));
+ io::ppm::save(decision_image, argv[4]);
}
diff --git a/scribo/src/preprocessing/Makefile.am b/scribo/src/preprocessing/Makefile.am
index 2422d87..501233a 100644
--- a/scribo/src/preprocessing/Makefile.am
+++ b/scribo/src/preprocessing/Makefile.am
@@ -1,4 +1,5 @@
-# Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE).
+# Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
+# (LRDE).
#
# This file is part of Olena.
#
@@ -20,14 +21,16 @@
include $(top_srcdir)/scribo/scribo.mk
bin_PROGRAMS = \
- denoising \
+ denoise \
+ homogeneous_contrast \
preprocess \
split_bg_fg \
- split_bg_fg_ms \
+ subsample \
unskew
-denoising_SOURCES = denoising.cc
+denoise_SOURCES = denoise.cc
+homogeneous_contrast_SOURCES = homogeneous_contrast.cc
preprocess_SOURCES = preprocess.cc
split_bg_fg_SOURCES = split_bg_fg.cc
-split_bg_fg_ms_SOURCES = split_bg_fg_ms.cc
+subsample_SOURCES = subsample.cc
unskew_SOURCES = unskew.cc
diff --git a/scribo/src/filter/objects_with_holes.cc
b/scribo/src/preprocessing/denoise.cc
similarity index 70%
copy from scribo/src/filter/objects_with_holes.cc
copy to scribo/src/preprocessing/denoise.cc
index 0ebf89f..0eb567b 100644
--- a/scribo/src/filter/objects_with_holes.cc
+++ b/scribo/src/preprocessing/denoise.cc
@@ -1,4 +1,5 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of Olena.
//
@@ -24,30 +25,31 @@
// executable file might be covered by the GNU General Public License.
#include <mln/core/image/image2d.hh>
-#include <mln/core/alias/neighb2d.hh>
-#include <mln/data/convert.hh>
#include <mln/io/pbm/all.hh>
-#include <mln/value/label_16.hh>
-#include <scribo/filter/objects_with_holes.hh>
#include <scribo/debug/usage.hh>
+#include <scribo/preprocessing/denoise.hh>
+
+
const char *args_desc[][2] =
{
{ "input.pbm", "A binary image. 'True' for objects,
'False'\
for the background." },
- { "min_holes_count", "The minimum holes per objects." },
+ { "fg_min_card", "The minimum neighbor count to be set to true."
},
+ { "bg_min_card", "The minimum neighbor count to be set to false."
},
{0, 0}
};
+
int main(int argc, char *argv[])
{
using namespace mln;
- if (argc != 4)
+ if (argc != 5)
return scribo::debug::usage(argv,
- "Filter objects with holes",
- "input.pbm min_holes_count output.pbm",
+ "Remove noise.",
+ "input.pbm fg_min_card bg_min_card output.pbm",
args_desc,
"A binary image.");
@@ -57,14 +59,11 @@ int main(int argc, char *argv[])
I input;
io::pbm::load(input, argv[1]);
- value::label_16 nobjects;
- typedef object_image(mln_ch_value_(I,value::label_16)) obj_ima_t;
- obj_ima_t objects
- = scribo::primitive::extract::objects(input, c8(), nobjects);
+ unsigned fg_min_card = atoi(argv[2]);
+ unsigned bg_min_card = atoi(argv[3]);
- obj_ima_t filtered = scribo::filter::objects_with_holes(objects, atoi(argv[2]));
- io::pbm::save(data::convert(bool(), filtered), argv[3]);
+ io::pbm::save(scribo::preprocessing::denoise(input, fg_min_card, bg_min_card),
+ argv[4]);
trace::exiting("main");
-
}
diff --git a/scribo/src/preprocessing/denoising.cc
b/scribo/src/preprocessing/denoising.cc
deleted file mode 100644
index 769f75b..0000000
--- a/scribo/src/preprocessing/denoising.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
-//
-// This file is part of Olena.
-//
-// Olena is free software: you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation, version 2 of the License.
-//
-// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
-//
-// As a special exception, you may use this file as part of a free
-// software project without restriction. Specifically, if other files
-// instantiate templates or use macros or inline functions from this
-// file, or you compile this file and link it with other files to produce
-// an executable, this file does not by itself cause the resulting
-// executable to be covered by the GNU General Public License. This
-// exception does not however invalidate any other reasons why the
-// executable file might be covered by the GNU General Public License.
-
-#include <mln/core/image/image2d.hh>
-#include <mln/core/alias/neighb2d.hh>
-#include <mln/data/convert.hh>
-#include <mln/io/pbm/all.hh>
-#include <mln/value/label.hh>
-#include <mln/accu/math/count.hh>
-#include <mln/labeling/relabel.hh>
-#include <mln/labeling/compute.hh>
-#include <mln/labeling/foreground.hh>
-
-#include <scribo/debug/usage.hh>
-
-const char *args_desc[][2] =
-{
- { "input.pbm", "A binary image. 'True' for objects,
'False'\
-for the background." },
- { "nbh", "Select the neighborhood used for checking neighbors.
'4' will use C4, '8' will use C8." },
- { "n_nbh", "The minimum neighbor count to be set to true." },
- {0, 0}
-};
-
-int main(int argc, char *argv[])
-{
- using namespace mln;
-
- if (argc != 5)
- return scribo::debug::usage(argv,
- "Remove noise.",
- "input.pbm nbh min_nbh output.pbm",
- args_desc,
- "A binary image.");
-
- trace::entering("main");
-
- typedef image2d<bool> I;
- I input;
- io::pbm::load(input, argv[1]);
-
- typedef value::label<30> V;
-
- neighb2d nbh;
- if (atoi(argv[2]) == 4)
- nbh = c4();
- else if (atoi(argv[2]) == 8)
- nbh = c8();
- else
- {
- std::cout << "Error: nbh must be set to '4' or '8'!"
<< std::endl;
- return 1;
- }
-
- unsigned min_nbh = atoi(argv[3]);
-
-
- V nlabels;
- image2d<V> lbl = labeling::foreground(input, nbh, nlabels);
- std::cout << nlabels << std::endl;
-
-
- util::array<unsigned> result = labeling::compute(accu::meta::math::count(), lbl,
nlabels);
-
- fun::i2v::array<bool> f(static_cast<unsigned>(nlabels) + 1, true);
- for (unsigned i = 1; i <= nlabels; ++i)
- if (result(i) < min_nbh)
- f(i) = false;
-
- labeling::relabel_inplace(lbl, nlabels, f);
- std::cout << nlabels << std::endl;
-
-
-// mln_piter_(I) p(input.domain());
-// mln_niter_(neighb2d) n(nbh, p);
-// unsigned n_nbh;
-// for_all(p)
-// if (input(p))
-// {
-// n_nbh = 0;
-// for_all(n)
-// if (input(n))
-// ++n_nbh;
-
-// if (n_nbh < min_nbh)
-// input(p) = false;
-// }
-
- io::pbm::save(data::convert(bool(), lbl), argv[4]);
-
- trace::exiting("main");
-
-}
diff --git a/scribo/src/preprocessing/homogeneous_contrast.cc
b/scribo/src/preprocessing/homogeneous_contrast.cc
new file mode 100644
index 0000000..4930923
--- /dev/null
+++ b/scribo/src/preprocessing/homogeneous_contrast.cc
@@ -0,0 +1,44 @@
+#include <mln/value/int_u8.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+
+#include <scribo/preprocessing/homogeneous_contrast.hh>
+#include <scribo/debug/usage.hh>
+
+const char *args_desc[][2] =
+{
+ { "input.pgm", "A gray-level image." },
+ { "h", "The height attribute value for the leveling closing." },
+ {0, 0}
+};
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm h
output.pgm" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 4)
+ return scribo::debug::usage(argv,
+ "Remove noise.",
+ "input.pgm h output.pgm",
+ args_desc);
+
+
+ image2d<int_u8> input;
+ io::pgm::load(input, argv[1]);
+
+ int h = std::atoi(argv[2]);
+
+ io::pgm::save(scribo::preprocessing::homogeneous_contrast(input, h),
+ argv[3]);
+}
diff --git a/scribo/src/preprocessing/split_bg_fg.cc
b/scribo/src/preprocessing/split_bg_fg.cc
index 0d7ba8a..de7bd02 100644
--- a/scribo/src/preprocessing/split_bg_fg.cc
+++ b/scribo/src/preprocessing/split_bg_fg.cc
@@ -35,6 +35,7 @@ const char *args_desc[][2] =
{ "input.pbm", "A color image." },
{ "lambda", "Lambda value. (FIX Description)" },
{ "delta", "Delta value. (FIX Description)" },
+ { "fg.ppm", "The foreground image (1st output)." },
{ "bg.ppm", "The background image (2nd output)." },
{0, 0}
};
@@ -49,7 +50,7 @@ int main(int argc, char *argv[])
if (argc != 6)
return scribo::debug::usage(argv,
"Split background and foreground.",
- "input.pbm lambda delta bg.ppm fg.ppm",
+ "input.pbm lambda delta fg.ppm bg.ppm",
args_desc, "The foreground image.");
typedef image2d<value::rgb8> I;
@@ -60,8 +61,8 @@ int main(int argc, char *argv[])
bg_fg = scribo::preprocessing::split_bg_fg(input,
atoi(argv[2]),
atoi(argv[3]));
- io::ppm::save(bg_fg.first(), argv[4]);
- io::ppm::save(bg_fg.second(), argv[5]);
+ io::ppm::save(bg_fg.first(), argv[5]);
+ io::ppm::save(bg_fg.second(), argv[4]);
mln::trace::exiting("main");
}
diff --git a/scribo/src/preprocessing/split_bg_fg_ms.cc
b/scribo/src/preprocessing/split_bg_fg_ms.cc
deleted file mode 100644
index 4c0180a..0000000
--- a/scribo/src/preprocessing/split_bg_fg_ms.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
-//
-// This file is part of Olena.
-//
-// Olena is free software: you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation, version 2 of the License.
-//
-// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
-//
-// As a special exception, you may use this file as part of a free
-// software project without restriction. Specifically, if other files
-// instantiate templates or use macros or inline functions from this
-// file, or you compile this file and link it with other files to produce
-// an executable, this file does not by itself cause the resulting
-// executable to be covered by the GNU General Public License. This
-// exception does not however invalidate any other reasons why the
-// executable file might be covered by the GNU General Public License.
-
-#include <mln/core/image/image2d.hh>
-#include <mln/io/ppm/all.hh>
-
-#include <mln/debug/filename.hh>
-
-#include <mln/subsampling/subsampling.hh>
-
-#include <scribo/preprocessing/split_bg_fg.hh>
-#include <scribo/debug/usage.hh>
-
-
-const char *args_desc[][2] =
-{
- { "input.pbm", "A color image." },
- { "lambda", "Lambda value. (FIX Description)" },
- { "delta", "Delta value. (FIX Description)" },
- { "lambda_sub2", "Lambda value. (FIX Description)" },
- { "delta_sub2", "Delta value. (FIX Description)" },
- { "lambda_sub4", "Lambda value. (FIX Description)" },
- { "delta_sub4", "Delta value. (FIX Description)" },
- {0, 0}
-};
-
-
-
-int main(int argc, char *argv[])
-{
- mln::trace::entering("main");
- using namespace mln;
- dpoint2d none(0, 0);
-
- if (argc != 9)
- return scribo::debug::usage(argv,
- "Split background and foreground.",
- "input.pbm lambda delta lambda_sub2 delta_sub2 lambda_sub3 delta_sub3
output_prefix",
- args_desc, "The background and foreground images.");
-
- mln::debug::internal::filename_prefix = argv[8];
-
- typedef image2d<value::rgb8> I;
- I input;
- io::ppm::load(input, argv[1]);
-
- util::couple<I,I>
- bg_fg = scribo::preprocessing::split_bg_fg(input,
- atoi(argv[2]),
- atoi(argv[3]));
-
- io::ppm::save(bg_fg.first(), mln::debug::filename("out_bg.ppm"));
- io::ppm::save(bg_fg.second(), mln::debug::filename("out_fg.ppm"));
-
-
- {
- // 1/2
- std::cout << "1/2" << std::endl;
- I input_sub2x = mln::subsampling::subsampling(input, none, 2);
-
- util::couple<I,I>
- bg_fg = scribo::preprocessing::split_bg_fg(input_sub2x,
- atoi(argv[4]),
- atoi(argv[5]));
-
-
- io::ppm::save(bg_fg.first(), mln::debug::filename("out_bg_sub2x.ppm"));
- io::ppm::save(bg_fg.second(), mln::debug::filename("out_fg_sub2x.ppm"));
- }
-
- {
- // 1/4
- std::cout << "1/4" << std::endl;
- I input_sub4x = mln::subsampling::subsampling(input, none, 4);
-
- util::couple<I,I>
- bg_fg = scribo::preprocessing::split_bg_fg(input_sub4x,
- atoi(argv[6]),
- atoi(argv[7]));
-
-
- io::ppm::save(bg_fg.first(), mln::debug::filename("out_bg_sub4x.ppm"));
- io::ppm::save(bg_fg.second(), mln::debug::filename("out_fg_sub4x.ppm"));
- }
-
- mln::trace::exiting("main");
-}
diff --git a/scribo/src/text/pbm_recognition.cc b/scribo/src/preprocessing/subsample.cc
similarity index 74%
copy from scribo/src/text/pbm_recognition.cc
copy to scribo/src/preprocessing/subsample.cc
index 70ceca1..388d4d9 100644
--- a/scribo/src/text/pbm_recognition.cc
+++ b/scribo/src/preprocessing/subsample.cc
@@ -23,43 +23,43 @@
// 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/core/image/image2d.hh>
-#include <mln/io/pbm/load.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/io/pgm/all.hh>
+
+#include <mln/subsampling/antialiased.hh>
-#include <scribo/text/recognition.hh>
+#include <mln/value/int_u8.hh>
#include <scribo/debug/usage.hh>
const char *args_desc[][2] =
{
- { "input.pbm", "A binary image. 'True' for objects,
'False'\
-for the background." },
+ { "input.pgm", "A gray-scale image." },
+ { "ratio", "Scale ratio." },
{0, 0}
};
-
-int main(int argc, char* argv[])
+int main(int argc, char *argv[])
{
- using namespace scribo;
using namespace mln;
- if (argc != 2)
+ if (argc != 4)
return scribo::debug::usage(argv,
- "Text recognition",
- "input.pbm",
- args_desc,
- "The text is printed on the standard output");
+ "Subsample.",
+ "input.pgm ratio output.pgm",
+ args_desc);
trace::entering("main");
- image2d<bool> input;
- io::pbm::load(input, argv[1]);
+ typedef image2d<value::int_u8> I;
+ I input;
+ io::pgm::load(input, argv[1]);
- scribo::text::recognition(input, "fra");
+ unsigned ratio = atoi(argv[2]);
+ io::pgm::save(mln::subsampling::antialiased(input, ratio), argv[3]);
trace::exiting("main");
}
diff --git a/scribo/src/text_in_article.cc b/scribo/src/text_in_article.cc
index 876eba5..2e6b1a6 100644
--- a/scribo/src/text_in_article.cc
+++ b/scribo/src/text_in_article.cc
@@ -36,64 +36,45 @@
#include <mln/io/ppm/save.hh>
#include <mln/io/dump/save.hh>
-#include <mln/math/min.hh>
-
#include <mln/literal/colors.hh>
#include <mln/value/rgb8.hh>
#include <mln/value/label_16.hh>
-#include <mln/value/int_u16.hh>
-
-#include <mln/draw/box.hh>
-#include <mln/draw/line.hh>
-
-#include <mln/data/convert.hh>
-
-#include <mln/extension/adjust.hh>
-
-#include <mln/accu/stat/median_h.hh>
-
-#include <mln/labeling/colorize.hh>
-#include <mln/labeling/relabel.hh>
-//#include <scribo/draw/bounding_boxes.hh>
-#include <scribo/draw/bounding_box_links.hh>
+#include <scribo/core/line_set.hh>
#include <scribo/primitive/extract/components.hh>
+#include <scribo/primitive/extract/vertical_separators.hh>
+
+#include <scribo/primitive/remove/separators.hh>
#include <scribo/primitive/link/merge_double_link.hh>
#include <scribo/primitive/link/with_single_left_link_dmax_ratio.hh>
#include <scribo/primitive/link/with_single_right_link_dmax_ratio.hh>
-#include <scribo/primitive/group/apply.hh>
-// #include <scribo/primitive/group/from_double_link.hh>
#include <scribo/primitive/group/from_single_link.hh>
#include <scribo/filter/object_links_bbox_h_ratio.hh>
-#include <scribo/filter/objects_small.hh>
-// #include <scribo/filter/objects_thin.hh>
-// #include <scribo/filter/objects_thick.hh>
-
-// #include <scribo/filter/object_groups_small.hh>
-
-// #include <scribo/debug/decision_image.hh>
-// #include <scribo/debug/save_bboxes_image.hh>
-// #include <scribo/debug/save_bboxes_image.hh>
-// #include <scribo/debug/save_linked_bboxes_image.hh>
-
-#include <scribo/core/line_set.hh>
-#include <scribo/io/xml/save_text_lines.hh>
-
#include <scribo/debug/usage.hh>
+#include <scribo/debug/save_bboxes_image.hh>
+#include <scribo/debug/bboxes_enlarged_image.hh>
+#include <scribo/debug/mean_and_base_lines_image.hh>
+#include <scribo/debug/looks_like_a_text_line_image.hh>
#include <scribo/make/debug_filename.hh>
-//#include <scribo/text/recognition.hh>
+#include <scribo/text/recognition.hh>
#include <scribo/text/merging.hh>
+#include <scribo/preprocessing/denoise_fg.hh>
+
+
+// #include <mln/morpho/closing/structural.hh>
+// #include <mln/win/rectangle2d.hh>
+
const char *args_desc[][2] =
{
@@ -128,82 +109,60 @@ int main(int argc, char* argv[])
typedef value::label_16 V;
typedef image2d<V> L;
+
+ // Add whitespace separators.
+// win::rectangle2d win = win::rectangle2d(151, 41);
+// image2d<bool> whitespaces = morpho::closing::structural(input, win);
+// logical::not_inplace(whitespaces);
+
+ // Remove separators
+ std::cout << "Find vertical separators..." << std::endl;
+ image2d<bool> separators = primitive::extract::vertical_separators(input, 81);
+
+ std::cout << "Remove separators..." << std::endl;
+ image2d<bool> input_cleaned = primitive::remove::separators(input,
+ separators);
+
+// whitespaces += separators;
+
+ mln::io::pbm::save(separators, "vseparators.pbm");
+// mln::io::pbm::save(whitespaces, "separators.pbm");
+
+// mln::io::pbm::save(input_cleaned, "input_no_separators.pbm");
+
+ // Denoise
+ std::cout << "Denoise..." << std::endl;
+ input_cleaned = preprocessing::denoise_fg(input_cleaned, c8(), 3);
+
+// mln::io::pbm::save(input_cleaned, "input_denoised.pbm");
+
/// Finding components.
std::cout << "Finding components..." << std::endl;
V ncomponents;
component_set<L>
- components = scribo::primitive::extract::components(input,
- c8(),
+ components = scribo::primitive::extract::components(input_cleaned, c8(),
ncomponents);
- /// First filtering.
- std::cout << "Filtering components..." << std::endl;
- component_set<L> filtered_components
- = scribo::filter::components_small(components, 6);
-
- {
- unsigned none = 0, ignored = 0;
- for_all_comps(i, filtered_components)
- {
- if (filtered_components.info(i).tag() == component::Ignored)
- ++ignored;
- else
- ++none;
- }
- std::cout << "stats - none = " << none << " -
ignored = " << ignored << std::endl;
+ /// Set separator components.
+ components.add_separators(separators);
+// components.add_separators(whitespaces);
- }
/// Linking potential objects
std::cout << "Linking objects..." << std::endl;
object_links<L> left_link
- = primitive::link::with_single_left_link_dmax_ratio(filtered_components, 2);
+ = primitive::link::with_single_left_link_dmax_ratio(components, 2);
object_links<L> right_link
- = primitive::link::with_single_right_link_dmax_ratio(filtered_components, 2);
+ = primitive::link::with_single_right_link_dmax_ratio(components, 2);
// Validating left and right links.
object_links<L>
- merged_links = primitive::link::merge_double_link(filtered_components,
- left_link,
- right_link);
-
-// #ifndef NOUT
-// if (argc == 4)
-// {
-// image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-// scribo::draw::bounding_box_links(output,
-// merged_links,
-// literal::green);
-
-// mln::util::array<bool>
drawn(static_cast<unsigned>(filtered_components.nelements()) + 1, 0);
-// for_all_comps(i, filtered_components)
-// if (filtered_components(i).tag() != component::Ignored)
-// {
-// if (merged_links[i] == i && ! drawn(i))
-// {
-// mln::draw::box(output, filtered_components(i).bbox(), literal::orange);
-// drawn[i] = true;
-// }
-// else
-// {
-// mln::draw::box(output, filtered_components(i).bbox(), literal::blue);
-// mln::draw::box(output, filtered_components(merged_links[i]).bbox(),
literal::blue);
-// drawn[i] = true;
-// drawn[merged_links[i]] = true;
-// }
-// }
+ merged_links = primitive::link::merge_double_link(left_link, right_link);
-// mln::io::ppm::save(output, scribo::make::debug_filename("links.ppm"));
-// }
-// #endif
// Remove links if bboxes have too different sizes.
object_links<L> hratio_filtered_links
- = filter::object_links_bbox_h_ratio(filtered_components,
- merged_links,
- 2.5f);
-
-
+ = filter::object_links_bbox_h_ratio(merged_links, 2.5f);
// #ifndef NOUT
@@ -224,8 +183,7 @@ int main(int argc, char* argv[])
// //
// //######
object_groups<L>
- groups = primitive::group::from_single_link(filtered_components,
- hratio_filtered_links);
+ groups = primitive::group::from_single_link(hratio_filtered_links);
// value::label_16 n_groups;
// mln::fun::i2v::array<value::label_16>
// groups_packed = mln::make::relabelfun(groups,
@@ -235,64 +193,25 @@ int main(int argc, char* argv[])
-// mln::util::array<line_stats_extra> line_stats;
+ // Construct a line set.
line_set<L>
- lines = scribo::make::line_set(hratio_filtered_links, groups);
+ lines = scribo::make::line_set(groups);
+ //===== DEBUG =====
// Bboxes image.
- {
- image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-
- for_all_lines(l, lines)
- if (lines(l).tag() != line::Ignored)
- mln::draw::box(output, lines(l).bbox(), literal::red);
-
- mln::io::ppm::save(output,
- scribo::make::debug_filename("step1_bboxes.ppm"));
- }
+ scribo::debug::save_bboxes_image(input, lines,
+ scribo::make::debug_filename("step1_bboxes.ppm"));
// Bboxes enlarged
- {
- image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-
- for_all_lines(l, lines)
- if (lines(l).tag() != line::Ignored)
- {
- if (text::internal::looks_like_a_text_line(lines(l)))
- {
- box2d
- b = text::internal::enlarge(lines(l).bbox(),
- text::internal::delta_of_line(lines(l)));
- b.crop_wrt(input.domain());
- mln::draw::box(output, b, literal::green);
- }
- else
- mln::draw::box(output, lines(l).bbox(), literal::red);
- }
-
- mln::io::ppm::save(output,
- scribo::make::debug_filename("step1_bboxes_enlarged.ppm"));
- }
+ mln::io::ppm::save(scribo::debug::bboxes_enlarged_image(input, lines),
+ scribo::make::debug_filename("step1_bboxes_enlarged.ppm"));
// Looks like a text line
- {
- image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-
- for_all_lines(l, lines)
- if (lines(l).tag() != line::Ignored)
- {
- if (text::internal::looks_like_a_text_line(lines(l)))
- mln::draw::box(output, lines(l).bbox(), literal::green);
- else
- mln::draw::box(output, lines(l).bbox(), literal::red);
- }
-
- mln::io::ppm::save(output,
- scribo::make::debug_filename("step1_looks_like_a_text_line.ppm"));
- }
+ mln::io::ppm::save(scribo::debug::looks_like_a_text_line_image(input, lines),
+ scribo::make::debug_filename("step1_looks_like_a_text_line.ppm"));
// Bboxes + line infos
@@ -312,7 +231,7 @@ int main(int argc, char* argv[])
<< lines(l).card() << " "
<< lines(l).baseline() << " "
<< lines(l).x_height() << " "
- << lines(l).median() << " "
+ << lines(l).meanline() << " "
<< lines(l).d_height() << " "
<< lines(l).a_height() << " "
<< lines(l).char_space() << " "
@@ -329,88 +248,38 @@ int main(int argc, char* argv[])
}
- std::cout << "Merging lines..." << std::endl;
- lines = scribo::text::merging(input.domain(), lines);
+ // mean and base lines.
+ mln::io::ppm::save(scribo::debug::mean_and_base_lines_image(input, lines),
+ scribo::make::debug_filename("step1_x_height.ppm"));
- // Median and base lines.
- {
- image2d<value::rgb8> output = data::convert(value::rgb8(), input);
+ //===== END OF DEBUG =====
- for_all_lines(l, lines)
- {
- if (lines(l).tag() == line::Pathological)
- mln::draw::box(output, lines(l).bbox(), literal::orange);
- else if (lines(l).tag() != line::Merged)
- {
- if (lines(l).card() > 1)
- {
- point2d
- b_top(lines(l).baseline() - lines(l).median(), lines(l).bbox().pmin().col()),
- e_top(lines(l).baseline() - lines(l).median(), lines(l).bbox().pmax().col()),
- b_bot(lines(l).baseline(), lines(l).bbox().pmin().col()),
- e_bot(lines(l).baseline(), lines(l).bbox().pmax().col());
-
- mln::draw::line(output, b_top, e_top, literal::blue);
- mln::draw::line(output, b_bot, e_bot, literal::cyan);
-
-// std::cout << lines(l) << std::endl;
- }
- mln::draw::box(output, lines(l).bbox(), literal::purple);
- }
- }
- mln::io::ppm::save(output,
scribo::make::debug_filename("step2_x_height.ppm"));
- }
-
-
- // Bboxes image.
- {
- image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-
- for_all_lines(l, lines)
- if (lines(l).tag() != line::Merged
- && lines(l).tag() != line::Ignored
- && lines(l).tag() != line::Pathological)
- {
- mln::draw::box(output, lines(l).bbox(), literal::red);
- }
-
- mln::io::ppm::save(output, argv[2]);
- }
-// // line label image.
-// {
-// util::array<V>
-// f(static_cast<unsigned>(filtered_components.nelements()) + 1, 0);
-// for_all_lines(l, lines)
-// if (lines(l).tag() != line::Merged
-// && lines(l).tag() != line::Ignored
-// && lines(l).tag() != line::Pathological)
-// {
-// for_all_elements(c, lines(l).components())
-// f(lines(l).components()[c]) = l;
-// }
-// L line_label = duplicate(filtered_components.labeled_image());
-// V nlbl = filtered_components.nelements();
-// mln::labeling::relabel_inplace(line_label, nlbl, f);
-
-// mln::io::ppm::save(labeling::colorize(value::rgb8(), line_label),
-// scribo::make::debug_filename("labeled_lines.ppm"));
-// mln::io::dump::save(line_label,
scribo::make::debug_filename("labeled_lines.dump"));
-// }
+ std::cout << "Merging lines..." << std::endl;
+ lines = scribo::text::merging(lines);
-// scribo::io::xml::save_text_lines(argv[1], lines, "out.xml");
+ //===== DEBUG =====
+ // mean and base lines.
+ mln::io::ppm::save(scribo::debug::mean_and_base_lines_image(input, lines),
+ scribo::make::debug_filename("step2_x_height.ppm"));
+ // Looks like a text line
+ mln::io::ppm::save(scribo::debug::looks_like_a_text_line_image(input, lines),
+ scribo::make::debug_filename("step2_looks_like_a_text_line.ppm"));
+ // Bboxes image.
+ scribo::debug::save_bboxes_image(input, lines, argv[2]);
+ //===== END OF DEBUG =====
-// scribo::text::recognition(lines, "fra", "out.txt");
+ scribo::text::recognition(lines, "fra", "out.txt");
// // Display median character space.
@@ -458,5 +327,5 @@ int main(int argc, char* argv[])
// }
-// trace::exiting("main");
+ trace::exiting("main");
}
diff --git a/scribo/src/text_in_photo_ppm_fast.cc b/scribo/src/text_in_photo_ppm_fast.cc
index e4ddd48..0e35487 100644
--- a/scribo/src/text_in_photo_ppm_fast.cc
+++ b/scribo/src/text_in_photo_ppm_fast.cc
@@ -1,4 +1,5 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of Olena.
//
@@ -153,7 +154,7 @@ namespace mln
mask_non_text f(mask);
mln_concrete(I) output = data::transform(input_rgb, f);
- for_all_components(i, components)
+ for_all_comps(i, components)
if (components(i).is_valid())
mln::draw::box(output, components(i).bbox(), literal::red);
@@ -255,9 +256,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
timer_.start();
std::cout << "** Using split_bg_fg" << std::endl;
image2d<value::rgb8>
- fg = preprocessing::split_bg_fg(input_rgb,
- lambda,
- 32).second();
+ fg = preprocessing::split_bg_fg(input_rgb, lambda, 32).second();
intensity_ima = data::transform(fg, mln::fun::v2v::rgb_to_int_u<8>());
t_ = timer_;
std::cout << "Foreground extracted. " << t_ <<
std::endl;
@@ -379,9 +378,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
// Validating left and right links.
timer_.restart();
object_links<L>
- merged_links = primitive::link::merge_double_link(filtered_components,
- left_link,
- right_link);
+ merged_links = primitive::link::merge_double_link(left_link, right_link);
t_ = timer_;
std::cout << "Right/Left Validation. " << t_ << std::endl;
@@ -389,8 +386,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
// Remove links if bboxes have too different sizes.
timer_.restart();
object_links<L>
- hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_components,
- merged_links,
+ hratio_filtered_links = filter::object_links_bbox_h_ratio(merged_links,
1.50f);
@@ -413,9 +409,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
//Remove links if bboxes overlap too much.
object_links<L> overlap_filtered_links
- = filter::object_links_bbox_overlap(filtered_components,
- hratio_filtered_links,
- 0.80f);
+ = filter::object_links_bbox_overlap(hratio_filtered_links, 0.80f);
@@ -438,16 +432,14 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
timer_.restart();
object_groups<L>
- groups = primitive::group::from_single_link(filtered_components,
- overlap_filtered_links);
+ groups = primitive::group::from_single_link(overlap_filtered_links);
// Apply grouping in a temporary image (for debug purpose).
#ifndef NOUT
component_set<L>
- raw_group_image = primitive::group::apply(filtered_components,
- groups);
+ raw_group_image = primitive::group::apply(groups);
#endif // !NOUT
t_ = timer_;
@@ -505,10 +497,9 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
{
decision_image = data::convert(value::rgb8(), input);
component_set<L>
- grouped_objects = primitive::group::apply(filtered_components,
- filtered_small_groups);
+ grouped_objects = primitive::group::apply(filtered_small_groups);
- for_all_components(i, filtered_components)
+ for_all_comps(i, filtered_components)
if (filtered_components(i).is_valid()
&& filtered_small_groups(i) != 0)
mln::draw::box(decision_image, filtered_components(i).bbox(), literal::green);
@@ -544,10 +535,9 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
decision_image = data::convert(value::rgb8(), input);
component_set<L>
- grouped_components = primitive::group::apply(filtered_components,
- filtered_thin_groups);
+ grouped_components = primitive::group::apply(filtered_thin_groups);
- for_all_components(i, filtered_components)
+ for_all_comps(i, filtered_components)
if (filtered_components(i).is_valid()
&& filtered_thin_groups(i) != 0)
mln::draw::box(decision_image, filtered_components(i).bbox(), literal::green);
@@ -571,8 +561,7 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
// 30);
component_set<L>
- grouped_components = primitive::group::apply(filtered_components,
- filtered_thin_groups);
+ grouped_components = primitive::group::apply(filtered_thin_groups);
t_ = g_timer;
std::cout << "Group applied to object image " << t_ <<
std::endl;
@@ -588,10 +577,10 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
/// Grouping groups.
- groups = primitive::group::from_single_link(grouped_components, left_link);
+ groups = primitive::group::from_single_link(left_link);
-// component_set<L>
- grouped_components = primitive::group::apply(grouped_components, groups);
+// component_set<L>
+ grouped_components = primitive::group::apply(groups);
t_ = g_timer;
std::cout << "Link and group again " << t_ << std::endl;
@@ -663,9 +652,17 @@ Common usage: ./ppm_text_in_photo input.ppm output.ppm 1 1 1 1
1",
std::cout << "# objects = " << grouped_components.nelements()
<< std::endl;
+ std::cout << filtered_components << std::endl;
+
+ for_all_comps(c, filtered_components)
+ if (filtered_components(c).is_valid())
+ std::cout << filtered_components(c) << ", ";
+ std::cout << std::endl;
+
+ std::cout << filtered_thin_groups << std::endl;
scribo::line_set<L>
- lines = scribo::line_set<L>(filtered_components, filtered_thin_groups);
+ lines = scribo::make::line_set(filtered_thin_groups);
text::recognition(lines, "fra", "out.txt");
trace::exiting("main");
diff --git a/scribo/src/text_in_photo_ppm_fast_2.cc
b/scribo/src/text_in_photo_ppm_fast_2.cc
deleted file mode 100644
index bb24a11..0000000
--- a/scribo/src/text_in_photo_ppm_fast_2.cc
+++ /dev/null
@@ -1,541 +0,0 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
-//
-// This file is part of Olena.
-//
-// Olena is free software: you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation, version 2 of the License.
-//
-// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
-//
-// As a special exception, you may use this file as part of a free
-// software project 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 <libgen.h>
-#include <iostream>
-
-#include <mln/core/image/image2d.hh>
-#include <mln/core/image/imorph/tr_image.hh>
-#include <mln/core/alias/neighb2d.hh>
-
-#include <mln/labeling/colorize.hh>
-
-#include <mln/data/stretch.hh>
-
-#include <mln/io/pbm/all.hh>
-#include <mln/io/ppm/save.hh>
-
-#include <mln/math/min.hh>
-
-#include <mln/logical/not.hh>
-
-#include <mln/literal/colors.hh>
-#include <mln/value/rgb8.hh>
-#include <mln/value/label_16.hh>
-
-#include <mln/fun/v2v/rgb_to_int_u.hh>
-
-#include <mln/data/wrap.hh>
-
-#include <mln/draw/box.hh>
-
-#include <mln/geom/translate.hh>
-
-#include <scribo/draw/bounding_boxes.hh>
-
-#include <scribo/binarization/sauvola_ms.hh>
-#include <scribo/binarization/sauvola.hh>
-
-#include <scribo/primitive/extract/objects.hh>
-
-#include <scribo/primitive/link/merge_double_link.hh>
-#include <scribo/primitive/link/with_single_left_link.hh>
-#include <scribo/primitive/link/with_single_right_link.hh>
-
-#include <scribo/primitive/group/apply.hh>
-#include <scribo/primitive/group/from_double_link.hh>
-#include <scribo/primitive/group/from_single_link.hh>
-
-#include <scribo/filter/objects_with_holes.hh>
-#include <scribo/filter/object_links_bbox_h_ratio.hh>
-#include <scribo/filter/object_links_bbox_overlap.hh>
-
-#include <scribo/filter/common/objects_photo.hh>
-
-#include <scribo/filter/object_groups_small.hh>
-#include <scribo/filter/object_groups_v_thickness.hh>
-
-#include <scribo/debug/decision_image.hh>
-#include <scribo/debug/save_bboxes_image.hh>
-#include <scribo/debug/save_linked_bboxes_image.hh>
-
-#include <scribo/debug/usage.hh>
-
-#include <scribo/preprocessing/split_bg_fg.hh>
-
-#include <scribo/make/debug_filename.hh>
-
-#include <mln/util/timer.hh>
-#include <mln/core/var.hh>
-
-
-#include <scribo/src/afp/components.hh>
-#include <scribo/src/afp/link.hh>
-#include <scribo/src/afp/regroup.hh>
-
-const char *args_desc[][2] =
-{
- { "input.ppm", "A color image." },
- { "debug_output_dir", "Directory were debug images will be saved"
},
- { "lambda", "Lambda value used for foreground extraction" },
- {0, 0}
-};
-
-
-namespace mln
-{
-
- struct mask_non_text : Function_v2v<mask_non_text>
- {
- typedef value::rgb8 result;
- typedef image2d<bool> I;
-
- mask_non_text(const image2d<bool>& mask)
- : mask_(mask), p_(mask_)
- {
- p_.start();
- }
-
- result operator()(const result& v) const
- {
- bool b = p_.val();
- p_.next();
- if (!b)
- return v / 2;
- else
- return v;
-
- }
-
- I mask_;
- mutable mln_pixter_(I) p_;
- };
-
-
- template <typename I, typename L>
- mln_concrete(I)
- compute_highlight_image(const I& input_rgb,
- const object_image<L>& objects)
- {
- mln_ch_value(I, bool) mask;
- initialize(mask, input_rgb);
- data::fill(mask, false);
-
- for_all_components(i, objects.bboxes())
- data::fill((mask | objects.bbox(i)).rw(), true);
-
- mask_non_text f(mask);
- mln_concrete(I) output = data::transform(input_rgb, f);
-
- for_all_components(i, objects.bboxes())
- mln::draw::box(output, objects.bbox(i), literal::red);
-
- return output;
- }
-
- template <typename I, typename L>
- mln_concrete(I)
- compute_text_image(const I& input_rgb,
- const object_image<L>& grouped_objects)
- {
- const util::array<mln_domain(L)>& bboxes = grouped_objects.bboxes();
-
- unsigned shift = 5;
- float height = 1, width = 0;
- for_all_components(i, bboxes)
- {
- height += bboxes(i).nrows() + shift;
- width = math::max(static_cast<float>(bboxes(i).ncols()), width);
- }
- if (width == 0)
- width = 1;
-
- I output(height, width);
- data::fill(output, literal::black);
-
- algebra::vec<2, float> dv;
- dv[0] = 0;
- dv[1] = 0;
- for_all_ncomponents(i, grouped_objects.nlabels())
- {
- mln_VAR(tmp, duplicate(input_rgb | grouped_objects.bbox(i)));
-
- typedef fun::x2x::translation<mln_site_(I)::dim, float> trans_t;
- trans_t trans(dv - grouped_objects.bbox(i).pmin().to_vec());
-
- mln_domain(I) tr_box(grouped_objects.bbox(i).pmin().to_vec() + trans.t(),
- grouped_objects.bbox(i).pmax().to_vec() + trans.t());
-
- tr_image<mln_domain(I), tmp_t, trans_t> tr_ima(tr_box, tmp, trans);
-
- data::paste(tr_ima, output);
- dv[0] += grouped_objects.bbox(i).nrows() + shift;
- }
-
- return output;
- }
-
-} // end of namespace mln
-
-
-int main(int argc, char* argv[])
-{
- using namespace scribo;
- using namespace mln;
-
- if (argc < 3 || argc > 10)
- return scribo::debug::usage(argv,
- "Find text in a photo.",
- "input.ppm output.ppm [bg/fg enabled] [sauvola_ms enabled] [Bg comp filter
enabled] [small group filter enabled] [thin group filter enabled] [debug_output_dir]
[lambda]",
- args_desc,
- "A color image where the text is highlighted.");
-
- bool debug = false;
- if (argc > 8)
- {
- scribo::make::internal::debug_filename_prefix = argv[8];
- debug = true;
- }
-
- trace::entering("main");
-
- image2d<value::rgb8> input_rgb;
- io::ppm::load(input_rgb, argv[1]);
-
-
- unsigned lambda;
- if (argc == 6)
- lambda = atoi(argv[9]);
- else
- lambda = 1.2 * (input_rgb.nrows() + input_rgb.ncols());
-
-
- image2d<value::int_u8> intensity_ima;
- util::timer timer_, global_t_;
- float t_;
-
- global_t_.start();
-
- if (argc > 3 && atoi(argv[3]) != 0)
- {
- // Extract foreground
- timer_.start();
- std::cout << "** Using split_bg_fg" << std::endl;
- image2d<value::rgb8>
- fg = preprocessing::split_bg_fg(input_rgb,
- lambda,
- 32).second();
- intensity_ima = data::transform(fg, mln::fun::v2v::rgb_to_int_u<8>());
- t_ = timer_;
- std::cout << "Foreground extracted. " << t_ <<
std::endl;
- }
- else
- {
- timer_.start();
- std::cout << "** Using data::transform(intensity)" <<
std::endl;
- intensity_ima = data::transform(input_rgb,
- mln::fun::v2v::rgb_to_int_u<8>());
- t_ = timer_;
- std::cout << "Intensity image " << t_ << std::endl;
- }
-
-
- // Binarize foreground to use it in the processing chain.
- timer_.restart();
- image2d<bool> input;
- unsigned w = std::min(intensity_ima.nrows() / 3, intensity_ima.ncols() / 3);
- if (! w % 2)
- ++w;
- w = std::min(w, 101u);
- if (argc > 4 && atoi(argv[4]) != 0)
- {
- std::cout << "** Using sauvola_ms with w_1 = " << w <<
std::endl;
- input = binarization::sauvola_ms(intensity_ima, w, 3, 67);
- }
- else
- {
- std::cout << "** Using sauvola with w_1 = " << w <<
std::endl;
- input = binarization::sauvola(intensity_ima, w);
- }
-
-
-// if (debug)
-// io::pbm::save(input, "input.pbm");
- t_ = timer_;
- std::cout << "Foreground binarized. " << t_ << std::endl;
-
-
-
- typedef image2d<value::label_16> L;
-
- /// Finding objects.
- timer_.restart();
-
- typedef object_image(L) Obj;
- Obj filtered_objects;
-
- {
- util::array<box2d> bboxes;
- util::array<point2d> mass_centers;
-
- value::label_16 nobjects;
- L components = extract_components(input, nobjects, bboxes, mass_centers);
-
- filtered_objects = Obj(components, nobjects, bboxes, mass_centers);
- }
-
- t_ = timer_;
- std::cout << "Object extracted " << t_ << " - "
<< filtered_objects.nlabels() << " objects" << std::endl;
-
-// if (debug)
-// io::pgm::save(data::stretch(value::int_u8(), filtered_objects),
"ref_objects.pgm");
-
-
- /// linking potential objects
- timer_.restart();
- util::couple<object_links<L>, object_links<L> >
- links = primitive::link::left_right(filtered_objects);
-
- object_links<L>& left_link = links.first();
- object_links<L>& right_link = links.second();
-
-// object_links<L> left_link
-// = primitive::link::with_single_left_link(filtered_objects, 30);
-// t_ = timer_;
-// std::cout << "Left Link done " << t_ << std::endl;
-
-// timer_.restart();
-// object_links<L> right_link
-// = primitive::link::with_single_right_link(filtered_objects, 30);
- t_ = timer_;
- std::cout << "Link done " << t_ << std::endl;
-
-
-
-// #ifndef NOUT
-// if (argc > 4)
-// {
-// std::cerr << "BEFORE - nobjects = " <<
filtered_objects.nlabels() << std::endl;
-// scribo::debug::save_linked_bboxes_image(input,
-// filtered_objects,
-// left_link, right_link,
-// literal::red, literal::cyan,
-// literal::yellow,
-// literal::green,
-// scribo::make::debug_filename("links.ppm"));
-// }
-// #endif
-
-
-
- // Validating left and right links.
- timer_.restart();
- object_links<L>
- merged_links = primitive::link::merge_double_link(filtered_objects,
- left_link,
- right_link);
- t_ = timer_;
- std::cout << "Right/Left Validation. " << t_ << std::endl;
-
-
- // Remove links if bboxes have too different sizes.
- timer_.restart();
- object_links<L>
- hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_objects,
- merged_links,
- 1.50f);
-
-
-
-
-// #ifndef NOUT
-// if (argc > 4)
-// {
-// image2d<value::rgb8>
-// hratio_decision_image = scribo::debug::decision_image(input,
-// merged_links,
-// hratio_filtered_links);
-// io::ppm::save(hratio_decision_image,
-// scribo::make::debug_filename("hratio_links_decision_image.ppm"));
-// }
-// #endif
-
-
-
-
- //Remove links if bboxes overlap too much.
- object_links<L> overlap_filtered_links
- = filter::object_links_bbox_overlap(filtered_objects,
- hratio_filtered_links,
- 0.80f);
-
-
-
-
-// #ifndef NOUT
-// if (argc > 4)
-// {
-// image2d<value::rgb8> overlap_decision_image
-// = scribo::debug::decision_image(input,
-// hratio_filtered_links,
-// overlap_filtered_links);
-// io::ppm::save(overlap_decision_image,
-// scribo::make::debug_filename("overlap_links_decision_image.ppm"));
-// }
-// #endif
-
-
- t_ = timer_;
- std::cout << "Objects links filtered. " << t_ <<
std::endl;
-
- timer_.restart();
- object_groups<L>
- groups = primitive::group::from_single_link(filtered_objects,
- overlap_filtered_links);
-
-
-
- /// Apply grouping in a temporary image (for debug purpose).
-// #ifndef NOUT
-// object_image(L)
-// raw_group_image = primitive::group::apply(filtered_objects,
-// filter::object_groups_small(groups, 2));
-// #endif // !NOUT
-
- t_ = timer_;
- std::cout << "Objects grouped. " << t_ << std::endl;
-
-
- util::timer g_timer;
-
- object_image(L)
- grouped_objects = primitive::group::apply(filtered_objects,
- groups);
-
- t_ = g_timer;
- std::cout << "Group applied to object image " << t_ <<
std::endl;
-
- /// Objects have been grouped. We try to link groups together.
- /// This time a single link is enough since non-wanted objects have
- /// been removed.
- g_timer.restart();
-
- left_link = primitive::link::left(grouped_objects, 30);
-// left_link
-// = primitive::link::with_single_left_link(grouped_objects, 30);
-
-
- /// Grouping groups.
- groups = primitive::group::from_single_link(grouped_objects, left_link);
-
-// object_image(L)
- grouped_objects = primitive::group::apply(grouped_objects, groups);
-
-
-
- std::cout << "Filtering groups..." << std::endl;
-
- timer_.restart();
- // Remove objects part of groups with strictly less than 3 objects.
-
- g_timer.start();
- object_groups<L> filtered_small_groups;
- if (argc > 6 && atoi(argv[6]) != 0)
- {
- std::cout << "** Using group too small" << std::endl;
- filtered_small_groups = filter::object_groups_small(groups, 3);
- }
- else
- filtered_small_groups = groups;
- t_ = g_timer;
- std::cout << "Small groups removed " << t_ << std::endl;
-
-
-
- // Remove objects part of groups having a mean thickness lower than 8.
- g_timer.restart();
- object_groups<L> filtered_thin_groups;
- if (argc > 7 && atoi(argv[7]) != 0)
- {
- std::cout << "** Using group too thin" << std::endl;
- filtered_thin_groups
- = filter::object_groups_v_thickness(filtered_small_groups, 8);
- }
- else
- filtered_thin_groups = filtered_small_groups;
- t_ = g_timer;
- std::cout << "Groups too thin " << t_ << std::endl;
-
-
-
- t_ = g_timer;
- std::cout << "Link and group again " << t_ << std::endl;
-
- timer_.stop();
-
-
- timer_.resume();
-
- g_timer.restart();
- /// Filter grouped objects not having enough background components.
- if (argc > 5 && atoi(argv[5]) != 0)
- {
- std::cout << "** Using objects_with_two_holes" << std::endl;
- grouped_objects = scribo::filter::objects_with_two_holes(grouped_objects, 5);
- t_ = g_timer;
- std::cout << "Objects_with_holes " << t_ << std::endl;
- }
-
- t_ = timer_;
- std::cout << "Objects groups filtered. " << t_ <<
std::endl;
-
-// object_image(L)
- grouped_objects = primitive::group::apply(grouped_objects, groups);
-
-
- t_ = global_t_;
- std::cout << "*** Result computed " << t_ << std::endl;
-
- timer_.restart();
- std::cout << "Saving result..." << std::endl;
- io::ppm::save(mln::labeling::colorize(value::rgb8(),
- grouped_objects,
- grouped_objects.nlabels()),
- argv[2]);
-
-
- io::ppm::save(compute_highlight_image(input_rgb, grouped_objects),
- scribo::make::debug_filename("orig_with_bboxes.ppm"));
- io::ppm::save(compute_text_image(input_rgb, grouped_objects),
- scribo::make::debug_filename("out_text.ppm"));
-
- t_ = timer_;
- std::cout << "Output saved " << t_ << std::endl;
-
- std::cout << "# objects = " << grouped_objects.nlabels() <<
std::endl;
-
- trace::exiting("main");
- return grouped_objects.nlabels() != 0;
-}
--
1.5.6.5