Commit 619f727a authored by Guillaume Lazzara's avatar Guillaume Lazzara
Browse files

scribo/src/text_in_photo_ppm.cc: Improve output.

parent ca034dd5
2010-02-19 Guillaume Lazzara <z@lrde.epita.fr>
* scribo/src/text_in_photo_ppm.cc: Improve output.
2010-02-19 Guillaume Lazzara <z@lrde.epita.fr>
Cleanup and avoid warnings in Sauvola related files.
......
......@@ -27,6 +27,7 @@
#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>
......@@ -38,12 +39,16 @@
#include <mln/logical/not.hh>
#include <mln/fun/v2v/rgb_to_int_u.hh>
#include <mln/literal/colors.hh>
#include <mln/value/rgb8.hh>
#include <mln/value/label_16.hh>
#include <mln/draw/box.hh>
#include <mln/geom/translate.hh>
#include <scribo/binarization/sauvola.hh>
#include <scribo/draw/bounding_boxes.hh>
......@@ -58,6 +63,7 @@
#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>
......@@ -68,7 +74,6 @@
#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/debug/usage.hh>
......@@ -77,6 +82,9 @@
#include <scribo/make/debug_filename.hh>
#include <mln/util/timer.hh>
#include <mln/core/var.hh>
const char *args_desc[][2] =
{
{ "input.ppm", "A color image." },
......@@ -86,20 +94,117 @@ const char *args_desc[][2] =
};
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 != 4 && argc != 5)
if (argc != 3 && argc != 4 && argc != 5 && argc != 6)
return scribo::debug::usage(argv,
"Find text in a photo.",
"input.ppm output.ppm [debug_output_dir] [lambda]",
"input.ppm output.ppm [bg/fg] [debug_output_dir] [lambda]",
args_desc,
"A color image where the text is highlighted.");
if (argc > 3)
scribo::make::internal::debug_filename_prefix = argv[3];
if (argc > 4)
scribo::make::internal::debug_filename_prefix = argv[4];
trace::entering("main");
......@@ -108,22 +213,50 @@ int main(int argc, char* argv[])
unsigned lambda;
if (argc == 5)
lambda = atoi(argv[4]);
if (argc == 6)
lambda = atoi(argv[5]);
else
lambda = 1.2 * (input_rgb.nrows() + input_rgb.ncols());
util::timer timer_;
// Extract foreground
image2d<value::int_u8> intensity_ima;
std::cout << "Extracting foreground..." << std::endl;
timer_.start();
if (argc > 3 && atoi(argv[3]) != 0)
{
// Extract foreground
timer_.start();
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>());
float t_ = timer_;
std::cout << "Foreground extracted. " << t_ << std::endl;
}
else
{
timer_.start();
intensity_ima = data::transform(input_rgb,
mln::fun::v2v::rgb_to_int_u<8>());
float t_ = timer_;
std::cout << "Intensity image " << t_ << std::endl;
}
float t_ = timer_;
std::cout << "Foreground extracted. " << t_ << std::endl;
// Binarize foreground to use it in the processing chain.
// FIXME: TOO SLOW!
std::cout << "Binarizing foreground..." << std::endl;
image2d<bool> input = binarization::sauvola(fg);
timer_.restart();
image2d<bool> input = binarization::sauvola(intensity_ima, 11);
io::pbm::save(input, "input.pbm");
t_ = timer_;
std::cout << "Foreground binarized. " << t_ << std::endl;
......@@ -131,25 +264,35 @@ int main(int argc, char* argv[])
/// Finding objects.
std::cout << "Extracting objects..." << std::endl;
timer_.restart();
value::label_16 nobjects;
object_image(L)
objects = scribo::primitive::extract::objects(input, c8(), nobjects);
t_ = timer_;
std::cout << "Object extracted" << t_ << std::endl;
/// First filtering.
std::cout << "Filtering objects..." << std::endl;
timer_.restart();
object_image(L) filtered_objects = filter::common::objects_photo(objects);
t_ = timer_;
std::cout << "Object filtered" << t_ << std::endl;
/// linking potential objects
std::cout << "Linking objects..." << std::endl;
timer_.restart();
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 << "Right Link done" << t_ << std::endl;
......@@ -170,16 +313,22 @@ int main(int argc, char* argv[])
// 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.
std::cout << "Filtering object links..." << std::endl;
timer_.restart();
object_links<L>
hratio_filtered_links = filter::object_links_bbox_h_ratio(filtered_objects,
merged_links,
0.7f);
1.50f);
......@@ -221,8 +370,11 @@ int main(int argc, char* argv[])
#endif
t_ = timer_;
std::cout << "Objects links filtered. " << t_ << std::endl;
std::cout << "Grouping objects..." << std::endl;
timer_.restart();
object_groups<L>
groups = primitive::group::from_single_link(filtered_objects,
overlap_filtered_links);
......@@ -234,11 +386,31 @@ int main(int argc, char* argv[])
raw_group_image = primitive::group::apply(filtered_objects,
filter::object_groups_small(groups, 2));
t_ = timer_;
std::cout << "Objects grouped. " << t_ << std::endl;
#ifndef NOUT
if (argc > 3)
scribo::debug::save_bboxes_image(input,
raw_group_image.bboxes(),
literal::red,
scribo::make::debug_filename("group_image.ppm"));
#endif // !NOUT
std::cout << "Filtering groups..." << std::endl;
util::timer g_timer;
timer_.restart();
// Remove objects part of groups with strictly less than 3 objects.
g_timer.start();
object_groups<L>
filtered_small_groups = filter::object_groups_small(groups, 3);
t_ = g_timer;
std::cout << "Small groups removed " << t_ << std::endl;
#ifndef NOUT
......@@ -256,8 +428,11 @@ int main(int argc, char* argv[])
// Remove objects part of groups having a mean thickness lower than 8.
g_timer.restart();
object_groups<L> filtered_thin_groups
= filter::object_groups_v_thickness(filtered_small_groups, 8);
t_ = g_timer;
std::cout << "Groups too thin " << t_ << std::endl;
#ifndef NOUT
......@@ -275,14 +450,19 @@ int main(int argc, char* argv[])
/// Apply grouping in the object image.
g_timer.restart();
object_image(L)
grouped_objects = primitive::group::apply(filtered_objects,
filtered_thin_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::with_single_left_link(grouped_objects, 30);
......@@ -292,8 +472,28 @@ int main(int argc, char* argv[])
grouped_objects = primitive::group::apply(grouped_objects, groups);
t_ = g_timer;
std::cout << "Link and group again " << t_ << std::endl;
timer_.stop();
io::ppm::save(mln::labeling::colorize(value::rgb8(),
grouped_objects,
grouped_objects.nlabels()),
scribo::make::debug_filename("out_before_hole_filter.ppm"));
timer_.resume();
g_timer.restart();
/// Filter grouped objects not having enough background components.
grouped_objects = scribo::filter::objects_with_holes_slow(grouped_objects, 2);
// grouped_objects = scribo::filter::objects_with_holes(grouped_objects, 2, 2);
t_ = g_timer;
std::cout << "Objects_with_holes " << t_ << std::endl;
t_ = timer_;
std::cout << "Objects groups filtered. " << t_ << std::endl;
#ifndef NOUT
if (argc > 3)
......@@ -313,6 +513,20 @@ int main(int argc, char* argv[])
grouped_objects.nlabels()),
argv[2]);
#ifndef NOUT
io::ppm::save(compute_highlight_image(input_rgb, grouped_objects),
scribo::make::debug_filename("orig_with_bboxes.ppm"));
// scribo::debug::save_bboxes_image(input_rgb, grouped_objects.bboxes(),
// literal::red,
// scribo::make::debug_filename("orig_with_bboxes.ppm"));
#endif
io::ppm::save(compute_text_image(input_rgb, grouped_objects),
scribo::make::debug_filename("out_text.ppm"));
std::cout << "# objects = " << grouped_objects.nlabels() << std::endl;
trace::exiting("main");
return grouped_objects.nlabels() != 0;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment