* src/text_in_article_pbm.cc: Update call to text::recognition.
* text/clean.hh: Resize text lines according to their x_height.
* text/extract_lines.hh: Update call to extract::components.
* text/merging.hh: Remove Debug.
* text/recognition.hh: Update call to text::clean and do
recognition only on lines considered as text.
* subsampling/bilinear.hh,
* upsampling/bs2x.hh: New.
---
scribo/ChangeLog | 18 +++++
scribo/src/text_in_article_pbm.cc | 147 +++++++++++++++++++------------------
scribo/subsampling/bilinear.hh | 114 ++++++++++++++++++++++++++++
scribo/text/clean.hh | 86 ++++++++++------------
scribo/text/extract_lines.hh | 6 +-
scribo/text/merging.hh | 30 ++++----
scribo/text/recognition.hh | 5 +-
scribo/upsampling/bs2x.hh | 147 +++++++++++++++++++++++++++++++++++++
8 files changed, 413 insertions(+), 140 deletions(-)
create mode 100644 scribo/subsampling/bilinear.hh
create mode 100644 scribo/upsampling/bs2x.hh
diff --git a/scribo/ChangeLog b/scribo/ChangeLog
index 97f15b8..f2850e0 100644
--- a/scribo/ChangeLog
+++ b/scribo/ChangeLog
@@ -1,5 +1,23 @@
2010-04-30 Guillaume Lazzara <z(a)lrde.epita.fr>
+ Improve OCR recognition.
+
+ * src/text_in_article_pbm.cc: Update call to text::recognition.
+
+ * text/clean.hh: Resize text lines according to their x_height.
+
+ * text/extract_lines.hh: Update call to extract::components.
+
+ * text/merging.hh: Remove Debug.
+
+ * text/recognition.hh: Update call to text::clean and do
+ recognition only on lines considered as text.
+
+ * subsampling/bilinear.hh,
+ * upsampling/bs2x.hh: New.
+
+2010-04-30 Guillaume Lazzara <z(a)lrde.epita.fr>
+
* postprocessing/fill_object_holes.hh: New routine.
2010-04-30 Guillaume Lazzara <z(a)lrde.epita.fr>
diff --git a/scribo/src/text_in_article_pbm.cc b/scribo/src/text_in_article_pbm.cc
index 3f37529..e71d21b 100644
--- a/scribo/src/text_in_article_pbm.cc
+++ b/scribo/src/text_in_article_pbm.cc
@@ -48,12 +48,14 @@
#include <scribo/primitive/remove/separators.hh>
#include <scribo/primitive/link/merge_double_link.hh>
+#include <scribo/primitive/link/internal/dmax_width_and_height.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/from_single_link.hh>
#include <scribo/filter/object_links_bbox_h_ratio.hh>
+#include <scribo/filter/objects_small.hh>
#include <scribo/debug/usage.hh>
@@ -71,6 +73,7 @@
#include <scribo/preprocessing/denoise_fg.hh>
+#include <scribo/io/xml/save_text_lines.hh>
// #include <mln/morpho/closing/structural.hh>
// #include <mln/win/rectangle2d.hh>
@@ -80,6 +83,7 @@ const char *args_desc[][2] =
{
{ "input.pbm", "A binary image. 'False' for object,
'True'\
for the background." },
+ { "out.txt", "Text output" },
{ "denoise", "1 enables denoising, 0 disables it. (enabled by
default)" },
{ "debug_dir", "Output directory for debug image" },
{0, 0}
@@ -95,8 +99,7 @@ int main(int argc, char* argv[])
return scribo::debug::usage(argv,
"Find text lines using left/right validation and display x-height in a binarized
article.",
"input.pbm out.txt <denoise: 0|1> <debug_dir>",
- args_desc,
- "Text output.");
+ args_desc);
if (argc == 5)
scribo::make::internal::debug_filename_prefix = argv[4];
@@ -151,13 +154,19 @@ int main(int argc, char* argv[])
components.add_separators(separators);
// components.add_separators(whitespaces);
+ components = scribo::filter::components_small(components, 3);
+
/// Linking potential objects
std::cout << "Linking objects..." << std::endl;
object_links<L> left_link
- = primitive::link::with_single_left_link_dmax_ratio(components, 2);
+ = primitive::link::with_single_left_link_dmax_ratio(components,
+ primitive::link::internal::dmax_width_and_height(1),
+ anchor::MassCenter);
object_links<L> right_link
- = primitive::link::with_single_right_link_dmax_ratio(components, 2);
+ = primitive::link::with_single_right_link_dmax_ratio(components,
+ primitive::link::internal::dmax_width_and_height(1),
+ anchor::MassCenter);
// Validating left and right links.
object_links<L>
@@ -218,38 +227,38 @@ int main(int argc, char* argv[])
scribo::make::debug_filename("step1_looks_like_a_text_line.ppm"));
- // Bboxes + line infos
- {
- std::ofstream
file(scribo::make::debug_filename("step1_bboxes_100p.txt").c_str());
- std::ofstream
file_50p(scribo::make::debug_filename("step1_bboxes_50p.txt").c_str());
-
- for_all_lines(l, lines)
- if (lines(l).tag() != line::Merged
- && lines(l).tag() != line::Ignored
- && lines(l).tag() != line::Pathological)
- {
- file << lines(l).bbox().pmin().row() << " "
- << lines(l).bbox().pmin().col() << " "
- << lines(l).bbox().pmax().row() << " "
- << lines(l).bbox().pmax().col() << " "
- << lines(l).card() << " "
- << lines(l).baseline() << " "
- << lines(l).x_height() << " "
- << lines(l).meanline() << " "
- << lines(l).d_height() << " "
- << lines(l).a_height() << " "
- << lines(l).char_space() << " "
- << lines(l).char_width() << std::endl;
+// // Bboxes + line infos
+// {
+// std::ofstream
file(scribo::make::debug_filename("step1_bboxes_100p.txt").c_str());
+// // std::ofstream
file_50p(scribo::make::debug_filename("step1_bboxes_50p.txt").c_str());
- file_50p << lines(l).bbox().pmin().row() / 2 << " "
- << lines(l).bbox().pmin().col() / 2 << " "
- << lines(l).bbox().pmax().row() / 2 << " "
- << lines(l).bbox().pmax().col() / 2 << std::endl;
- }
+// for_all_lines(l, lines)
+// if (lines(l).tag() != line::Merged
+// && lines(l).tag() != line::Ignored
+// && lines(l).tag() != line::Pathological)
+// {
+// file << lines(l).bbox().pmin().row() << " "
+// << lines(l).bbox().pmin().col() << " "
+// << lines(l).bbox().pmax().row() << " "
+// << lines(l).bbox().pmax().col() << " "
+// << lines(l).card() << " "
+// << lines(l).baseline() << " "
+// << lines(l).x_height() << " "
+// << lines(l).meanline() << " "
+// << lines(l).d_height() << " "
+// << lines(l).a_height() << " "
+// << lines(l).char_space() << " "
+// << lines(l).char_width() << std::endl;
+
+// // file_50p << lines(l).bbox().pmin().row() / 2 << " "
+// // << lines(l).bbox().pmin().col() / 2 << " "
+// // << lines(l).bbox().pmax().row() / 2 << " "
+// // << lines(l).bbox().pmax().col() / 2 << std::endl;
+// }
- file.close();
- file_50p.close();
- }
+// file.close();
+// // file_50p.close();
+// }
// mean and base lines.
@@ -280,57 +289,49 @@ int main(int argc, char* argv[])
scribo::debug::save_bboxes_image(input, lines,
scribo::make::debug_filename("step2_bboxes.ppm"));
- //===== END OF DEBUG =====
-
+ {
+ std::ofstream
file(scribo::make::debug_filename("step2_bboxes_100p.txt").c_str());
+// std::ofstream
file_50p(scribo::make::debug_filename("step2_bboxes_50p.txt").c_str());
- scribo::text::recognition(lines, "fra", argv[2]);
+ for_all_lines(l, lines)
+ if (lines(l).tag() != line::Merged
+ && lines(l).tag() != line::Ignored
+ && lines(l).tag() != line::Pathological)
+ {
+ file << lines(l).bbox().pmin().row() << " "
+ << lines(l).bbox().pmin().col() << " "
+ << lines(l).bbox().pmax().row() << " "
+ << lines(l).bbox().pmax().col() << " "
+ << lines(l).card() << " "
+ << lines(l).baseline() << " "
+ << lines(l).x_height() << " "
+ << lines(l).meanline() << " "
+ << lines(l).d_height() << " "
+ << lines(l).a_height() << " "
+ << lines(l).char_space() << " "
+ << lines(l).char_width() << std::endl;
+// file_50p << lines(l).bbox().pmin().row() / 2 << " "
+// << lines(l).bbox().pmin().col() / 2 << " "
+// << lines(l).bbox().pmax().row() / 2 << " "
+// << lines(l).bbox().pmax().col() / 2 << std::endl;
+ }
-// // Display median character space.
-// {
-// image2d<value::rgb8> output = data::convert(value::rgb8(), input);
-// typedef mln::value::int_u<8> median_t;
-// typedef mln::accu::stat::median_h<median_t> accu_t;
-// util::array<accu_t>
-// lspace_med(static_cast<unsigned>(grouped_objects.nlabels()) + 1);
-
-// for_all_components(i, filtered_objects.bboxes())
-// if (groups_packed(i) != 0)
-// {
-// if (hratio_filtered_links(i) != i)
-// {
-// unsigned
-// space = filtered_objects.bbox(i).pmin().col() -
filtered_objects.bbox(hratio_filtered_links(i)).pmax().col();
+ file.close();
+// file_50p.close();
+ }
-// lspace_med(groups_packed(i)).take(space);
-// }
-// }
+ //===== END OF DEBUG =====
-// std::cout << "Drawing median character space" << std::endl;
-// for_all_components(i, filtered_objects.bboxes())
-// if (groups_packed(i) != 0 && lspace_med(groups_packed(i)).card() >
1)
-// {
-// unsigned med = lspace_med(groups_packed(i)).to_result();
-// mln::draw::box(output, grouped_objects.bbox(groups_packed(i)),
-// literal::purple);
+ scribo::io::xml::save_text_lines(argv[1], lines, "out.xml");
-// point2d
-// beg = filtered_objects.bbox(i).pmax(),
-// end = beg;
-// beg.row() = filtered_objects.bbox(i).pmin().row();
-// mln::draw::line(output, beg, end, literal::cyan);
-// beg.col() += med;
-// end.col() += med;
-// mln::draw::line(output, beg, end, literal::cyan);
-// }
-// io::ppm::save(output, "median_wspace.ppm");
+ scribo::text::recognition(lines, "fra", argv[2]);
-// }
trace::exiting("main");
}
diff --git a/scribo/subsampling/bilinear.hh b/scribo/subsampling/bilinear.hh
new file mode 100644
index 0000000..cb95a11
--- /dev/null
+++ b/scribo/subsampling/bilinear.hh
@@ -0,0 +1,114 @@
+// Copyright (C) 2010 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.
+
+#ifndef SCRIBO_SUBSAMPLING_BILINEAR_HH
+# define SCRIBO_SUBSAMPLING_BILINEAR_HH
+
+/// \file
+///
+/// Bilinear subsampling.
+
+# include <mln/core/concept/image.hh>
+# include <mln/opt/at.hh>
+
+
+namespace scribo
+{
+
+ namespace subsampling
+ {
+
+
+ template <typename I>
+ mln_concrete(I)
+ bilinear(const Image<I>& input_, int sub_ratio);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename I>
+ mln_concrete(I)
+ bilinear(const Image<I>& input_, int sub_ratio)
+ {
+ trace::entering("scribo::subsampling::bilinear");
+
+ const I& input = exact(input_);
+ mln_precondition(input.is_valid());
+ mlc_is(mln_domain(I), box2d)::check();
+
+ mln_concrete(I) output(input.domain().nrows() / sub_ratio,
+ input.domain().ncols() / sub_ratio);
+
+ std::cout << "output domain = " << output.domain() <<
std::endl;
+
+ mln_piter(I) p(output.domain());
+ mln_value(I) pixels[4];
+
+ def::coord
+ x_offset = input.domain().pmin().col(),
+ y_offset = input.domain().pmin().row();
+
+ for_all(p)
+ {
+ int x = round(-0.5 + p.col() * sub_ratio);
+ int y = round(-0.5 + p.row() * sub_ratio);
+
+ if (x < 0)
+ x = 0;
+ else if (x >= geom::max_col(input))
+ x = input.ncols() - 1;
+
+ if (y < 0)
+ y = 0;
+ else if (y >= geom::max_row(input))
+ y = input.nrows() - 1;
+
+ double dx = (p.col() * sub_ratio) - x;
+ double dy = (p.row() * sub_ratio) - y;
+
+ pixels[0] = opt::at(input, y + y_offset, x + x_offset);
+ pixels[1] = opt::at(input, y + y_offset, x + x_offset + 1);
+ pixels[2] = opt::at(input, y + y_offset + 1, x + x_offset);
+ pixels[3] = opt::at(input, y + y_offset + 1, x + x_offset + 1);
+
+ output(p) = pixels[0] * (1 - dx) * (1 - dy) + pixels[1] * dx * (1 - dy) +
+ pixels[2] * (1 - dx) * dy + pixels[3] * dx * dy;
+
+ }
+
+ trace::exiting("scribo::subsampling::bilinear");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace subsampling
+
+} // end of namespace scribo
+
+
+#endif // SCRIBO_SUBSAMPLING_BILINEAR_HH
diff --git a/scribo/text/clean.hh b/scribo/text/clean.hh
index ba200fc..fa31ebe 100644
--- a/scribo/text/clean.hh
+++ b/scribo/text/clean.hh
@@ -64,8 +64,9 @@
#include <mln/value/rgb8.hh>
#include <mln/io/pgm/all.hh>
-#include <sandbox/inim/2009/ocr/resize.hh>
-#include <sandbox/fabien/mln/upsampling/hq2x.hh>
+#include <scribo/upsampling/bs2x.hh>
+#include <scribo/subsampling/bilinear.hh>
+
namespace scribo
{
@@ -80,69 +81,60 @@ namespace scribo
///
/// \param[in] input_ A binary image. Object are set to 'false'
/// and backgroud to 'true'.
- /// \param[in] dmap_win_ A weighted window.
///
/// \return An image. The text have better quality.
//
- template <typename I, typename W>
+ template <typename L, typename I>
mln_concrete(I)
- clean(const Image<I>& input_, const Weighted_Window<W>&
dmap_win_);
+ clean(const line_info<L>& line, const Image<I>& input_);
# ifndef MLN_INCLUDE_ONLY
- template <typename I, typename W>
+ template <typename L, typename I>
mln_concrete(I)
- clean(const Image<I>& input_, const Weighted_Window<W>&
dmap_win_)
+ clean(const line_info<L>& line, const Image<I>& input_)
{
trace::entering("scribo::text::clean");
const I& input = exact(input_);
- const W& dmap_win = exact(dmap_win_);
mlc_bool(mln_site_(I)::dim == 2)::check();
mlc_equal(mln_value(I),bool)::check();
mln_precondition(input.is_valid());
- mln_precondition(dmap_win.is_valid());
- (void) dmap_win;
-
-
- // Resize
- typedef image2d<value::rgb8> J;
- J tmp = data::convert(value::rgb8(), input);
- J clarge = tmp;//mln::upsampling::hq2x(tmp); (FIXME: re-enable)
-
- //FIXME: not generic!
-// if (input.domain().pmax()[0] - input.domain().pmin()[0] <= 10)
-// clarge = mln::upsampling::hq4x(clarge);
-
- I input_large = data::convert(bool(), clarge);
-
- // Blur
- image2d<value::int_u8>
- blur = linear::gaussian(data::convert(value::int_u8(), input_large), 2);
-
- // Skeleton constraint
- I K = topo::skeleton::crest(input_large, blur, c8());
-
- // Skeleton
- I skel_on_gaussian =
- morpho::skeleton_constrained(input_large, c8(),
- topo::skeleton::is_simple_point<I,neighb2d>,
- extend(K, false), arith::revert(blur));
-
- // Dilation
- win::octagon2d oct(7);
- I dilate_on_gaussian = morpho::dilation(skel_on_gaussian, oct);
-
-// io::pgm::save(arith::revert(blur), "blur_revert.pgm");
-// io::pgm::save(blur, "gaussian.pgm");
-// io::pbm::save(input_large, mln::debug::filename("input_large_4x.pbm"));
-// io::pbm::save(K, mln::debug::filename("K.pbm"));
-// io::pbm::save(skel_on_gaussian,
mln::debug::filename("skeleton_on_gaussian.pbm"));
-// io::pbm::save(dilate_on_gaussian,
mln::debug::filename("dilation_on_gaussian.pbm"));
+ mln_precondition(line.is_valid());
+
+ mln_concrete(I) output = duplicate(input);
+
+ if (line.x_height() < 5) // Non significative text/remaining lines...
+ return output;
+
+ float fact = line.x_height() / 40.0f;
+ std::cout << fact << " - " << output.domain() <<
std::endl;
+ if (fact < 1)
+ {
+ std::cout << "Upsampling..." << " - "
+ << std::ceil(fact) << std::endl;
+ while (fact < 1)
+ {
+ output = scribo::upsampling::bs2x(output); // 2x upsampling
+ fact *= 2.0f;
+// std::cout << "fact = " << fact
+// << " - output.domain = " << output.domain()
+// << std::endl;
+ }
+ }
+ else if (fact > 2.5f)
+ {
+ std::cout << "subsampling::bilinear" << " - "
+ << std::ceil(fact) << std::endl;
+ output = subsampling::bilinear(output, std::ceil(fact - 0.5)); // math::floor instead?
+
+ }
+ else
+ std::cout << "not cleaning text. Seems ok." << std::endl;
trace::exiting("scribo::text::clean");
- return dilate_on_gaussian;
+ return output;
}
# endif // ! MLN_INCLUDE_ONLY
diff --git a/scribo/text/extract_lines.hh b/scribo/text/extract_lines.hh
index 44dca50..c720d70 100644
--- a/scribo/text/extract_lines.hh
+++ b/scribo/text/extract_lines.hh
@@ -47,7 +47,7 @@
# include <mln/util/graph.hh>
# include <mln/value/label_16.hh>
-# include <scribo/primitive/extract/objects.hh>
+# include <scribo/primitive/extract/components.hh>
# include <scribo/primitive/group/apply.hh>
# include <scribo/primitive/link/with_several_left_links.hh>
# include <scribo/primitive/link/with_several_right_links.hh>
@@ -75,7 +75,7 @@ namespace scribo
** \param[in,out] nbboxes Will hold the number of bounding boxes
** at the end of the routine.
**
- ** \return An object image with grouped potential text objects.
+ ** \return An object image with grouped potential text components.
*/
template <typename I, typename N, typename V>
object_image(mln_ch_value(I,V))
@@ -103,7 +103,7 @@ namespace scribo
typedef mln_ch_value(I,V) L;
typedef object_image(L) text_t;
- text_t text = scribo::primitive::extract::objects(input, nbh, nbboxes);
+ text_t text = scribo::primitive::extract::components(input, nbh, nbboxes);
# ifndef SCRIBO_NDEBUG
debug::save_bboxes_image(input, text.bboxes(), literal::red,
diff --git a/scribo/text/merging.hh b/scribo/text/merging.hh
index e509475..b29e63f 100644
--- a/scribo/text/merging.hh
+++ b/scribo/text/merging.hh
@@ -800,21 +800,21 @@ namespace scribo
(void) ith_pass;
- if (ith_pass == 1)
- {
- mln::io::pgm::save(log, "log_1.pgm");
- mln::io::pgm::save(data::wrap(int_u8(), billboard), "log_1e.pgm");
- }
- else if (ith_pass == 2)
- {
- mln::io::pgm::save(log, "log_2.pgm");
- mln::io::pgm::save(data::wrap(int_u8(), billboard), "log_2e.pgm");
- }
- else if (ith_pass == 3)
- {
- mln::io::pgm::save(log, "log_3.pgm");
- mln::io::pgm::save(data::wrap(int_u8(), billboard), "log_3e.pgm");
- }
+// if (ith_pass == 1)
+// {
+// mln::io::pgm::save(log, "log_1.pgm");
+// mln::io::pgm::save(data::wrap(int_u8(), billboard), "log_1e.pgm");
+// }
+// else if (ith_pass == 2)
+// {
+// mln::io::pgm::save(log, "log_2.pgm");
+// mln::io::pgm::save(data::wrap(int_u8(), billboard), "log_2e.pgm");
+// }
+// else if (ith_pass == 3)
+// {
+// mln::io::pgm::save(log, "log_3.pgm");
+// mln::io::pgm::save(data::wrap(int_u8(), billboard), "log_3e.pgm");
+// }
}
diff --git a/scribo/text/recognition.hh b/scribo/text/recognition.hh
index 5927d44..72df1e2 100644
--- a/scribo/text/recognition.hh
+++ b/scribo/text/recognition.hh
@@ -128,11 +128,12 @@ namespace scribo
/// Use text bboxes with Tesseract
for_all_lines(i, lines)
{
- if (! lines(i).is_valid())
+ if (! lines(i).is_valid() || lines(i).tag() != line::None || lines(i).type() !=
line::Text)
continue;
std::cout << "Text recognition... ("
<< i << "/" << lines.nelements() << ")"
<< std::endl;
+ std::cout << "x_height = " << lines(i).x_height() <<
std::endl;
mln_domain(I) box = lines(i).bbox();
// Make sure characters are isolated from the borders.
@@ -157,7 +158,7 @@ namespace scribo
/// Improve text quality.
/// text_ima_cleaned domain is larger than text_ima's.
- I text_ima_cleaned = text::clean(text_ima, dmap_win);
+ I text_ima_cleaned = text::clean(lines(i), text_ima);
mln::io::pbm::save(text_ima_cleaned, mln::debug::filename("line.pbm",
debug_id++));
// Setting objects to 'True'
diff --git a/scribo/upsampling/bs2x.hh b/scribo/upsampling/bs2x.hh
new file mode 100644
index 0000000..6ff8546
--- /dev/null
+++ b/scribo/upsampling/bs2x.hh
@@ -0,0 +1,147 @@
+// Copyright (C) 2010 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.
+
+#ifndef SCRIBO_UPSAMPLING_BS2X_HH
+# define SCRIBO_UPSAMPLING_BS2X_HH
+
+/// \file
+///
+/// Scale 2x algorithm for binary images.
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/alias/box2d.hh>
+# include <mln/opt/at.hh>
+# include <mln/geom/all.hh>
+
+
+
+namespace scribo
+{
+
+ namespace upsampling
+ {
+ using namespace mln;
+
+
+ /// \brief Scale 2x algorithm for binary images.
+ ///
+ //
+ template <typename I>
+ mln_concrete(I)
+ bs2x(const Image<I>& input);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ template <typename I>
+ mln_concrete(I)
+ bs2x(const mln::Image<I>& input_)
+ {
+ trace::entering("scribo::upsampling::bs2x");
+
+ const I& input = exact(input_);
+
+ mlc_is(mln_domain(I), mln::box2d)::check();
+ mlc_is(mln_value(I), bool)::check();
+
+ mln_precondition(input.is_valid());
+
+ typedef mln_value(I) V;
+
+ def::coord
+ mrow = geom::min_row(input),
+ mcol = geom::min_col(input);
+
+
+ mln_piter(I) p(input.domain());
+ mln_concrete(I) output(mln::make::box2d(mrow, mcol,
+ mrow + 2 * input.nrows() - 1,
+ mcol + 2 * input.ncols() - 1));
+ for_all(p)
+ {
+ def::coord
+ row = mrow + 2 * (p.row() - mrow),
+ col = mcol + 2 * (p.col() - mcol);
+
+ if(p.row() == geom::min_row(input)
+ || p.col() == geom::min_col(input)
+ || p.row() == geom::max_row(input)
+ || p.col() == geom::max_col(input))
+ {
+ mln::box2d b = mln::make::box2d(row, col,
+ row + 1, col + 1);
+ V value = opt::at(input, p.row(), p.col());
+
+ data::fill((output | b).rw(), value);
+ }
+ else
+ {
+ // nw n ne
+ //
+ // w value e
+ //
+ // sw s se
+
+ V n = input(p + mln::up),
+ s = input(p + mln::down),
+ e = input(p + mln::right),
+ w = input(p + mln::left),
+ nw = input(p + mln::up_left),
+ ne = input(p + mln::up_right),
+ sw = input(p + mln::down_left),
+ se = input(p + mln::down_right),
+ value = input(p);
+
+ if(e != w && n != s)
+ {
+ opt::at(output, row, col) = (w == n &&((se != nw) || !value)) ? w : value;
+ opt::at(output, row, col + 1) = (e == n &&((sw != ne) || !value)) ? e :
value;
+ opt::at(output, row + 1, col) = (w == s &&((ne != sw) || !value)) ? w :
value;
+ opt::at(output, row + 1, col + 1) = (e == s &&((nw != se) || !value)) ? e :
value;
+ }
+ else
+ {
+ mln::box2d b = mln::make::box2d(row, col,
+ row + 1, col + 1);
+ data::fill((output | b).rw(), value);
+ }
+ }
+ }
+
+ trace::exiting("scribo::upsampling::bs2x");
+ return output;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace upsampling
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_UPSAMPLING_BS2X_HH
--
1.5.6.5