Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Olena
olena
Commits
187ea036
Commit
187ea036
authored
Sep 22, 2010
by
Guillaume Lazzara
Browse files
Introduce text_in_picture toolchain.
parent
667167f7
Changes
1
Hide whitespace changes
Inline
Side-by-side
scribo/scribo/toolchain/text_in_picture.hh
0 → 100644
View file @
187ea036
// Copyright (C) 2009, 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_TOOLCHAIN_TEXT_IN_PICTURE_HH
# define SCRIBO_TOOLCHAIN_TEXT_IN_PICTURE_HH
/// \file
///
/// Localize text in a picture.
#include
<src/afp/components.hh>
#include
<src/afp/link.hh>
#include
<src/afp/regroup.hh>
# include <mln/util/timer.hh>
namespace
scribo
{
namespace
toolchain
{
using
namespace
mln
;
template
<
typename
I
>
component_set
<
mln_ch_value
(
I
,
value
::
label_16
)
>
text_in_picture
(
const
Image
<
I
>&
input_rgb_orig
,
bool
bg_removal
,
bool
multi_scale_bin
,
bool
negate
=
false
,
unsigned
max_dim_size
=
0
,
unsigned
lambda
=
0
,
const
char
*
debug_outdir
=
0
);
# ifndef MLN_INCLUDE_ONLY
namespace
internal
{
template
<
typename
I
>
unsigned
get_factor
(
const
I
&
ima
,
unsigned
max_dim_size
)
{
unsigned
nrows
=
ima
.
nrows
(),
ncols
=
ima
.
ncols
(),
max_dim
=
std
::
max
(
nrows
,
ncols
),
factor
=
max_dim
/
max_dim_size
;
return
factor
?
factor
:
1
;
}
struct
config
{
config
()
{
max_dim_size
=
1024
;
sauvola_s
=
2u
;
// 3?
sauvola_min_w
=
51u
;
// Group Filtering
bbox_h_ratio
=
1.60
f
;
bbox_overlap
=
0.80
f
;
small_groups
=
3
;
v_thickness
=
8
;
regroup_dmax
=
30
;
group_min_holes
=
3
;
}
// Image resizing factor
unsigned
max_dim_size
;
// Sauvola ms
unsigned
sauvola_s
;
unsigned
sauvola_min_w
;
// Group Filtering
float
bbox_h_ratio
;
float
bbox_overlap
;
unsigned
small_groups
;
unsigned
v_thickness
;
unsigned
regroup_dmax
;
unsigned
group_min_holes
;
};
}
// end of namespace scribo::toolchain::internal
template
<
typename
I
>
component_set
<
mln_ch_value
(
I
,
value
::
label_16
)
>
text_in_picture
(
const
Image
<
I
>&
input_rgb_orig_
,
bool
bg_removal
,
bool
multi_scale_bin
,
bool
negate
=
false
,
unsigned
max_dim_size
=
0
,
unsigned
lambda
=
0
,
const
char
*
debug_outdir
=
0
)
{
trace
::
entering
(
"scribo::toolchain::text_in_picture"
);
const
I
&
input_rgb_orig
=
exact
(
input_rgb_orig_
);
mln_precondition
(
input
.
is_valid
());
using
namespace
scribo
;
using
namespace
scribo
::
primitive
;
using
namespace
mln
;
// Global config variable.
internal
::
config
conf
;
bool
debug
=
false
;
if
(
debug_outdir
)
{
scribo
::
make
::
internal
::
debug_filename_prefix
=
debug_outdir
;
debug
=
true
;
}
if
(
max_dim_size
!=
0
)
conf
.
max_dim_size
=
max_dim_size
;
unsigned
factor
=
internal
::
get_factor
(
input_rgb_orig
,
conf
.
max_dim_size
);
std
::
cout
<<
"Reduction Factor : "
<<
factor
<<
std
::
endl
;
std
::
cout
<<
"Original domain: "
<<
input_rgb_orig
.
domain
()
<<
std
::
endl
;
mln_concrete
(
I
)
input_rgb
=
mln
::
subsampling
::
antialiased
(
input_rgb_orig
,
factor
);
std
::
cout
<<
"Resized domain: "
<<
input_rgb
.
domain
()
<<
std
::
endl
;
if
(
lambda
==
0
)
lambda
=
1.2
*
(
input_rgb
.
nrows
()
+
input_rgb
.
ncols
());
std
::
cout
<<
"Using lambda = "
<<
lambda
<<
std
::
endl
;
mln_ch_value
(
I
,
value
::
int_u8
)
intensity_ima
;
mln
::
util
::
timer
timer_
,
global_t_
;
float
t_
;
global_t_
.
start
();
if
(
bg_removal
)
{
// Extract foreground
timer_
.
start
();
std
::
cout
<<
"** Using split_bg_fg"
<<
std
::
endl
;
mln_ch_value
(
I
,
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
;
if
(
debug
)
{
io
::
ppm
::
save
(
fg
,
scribo
::
make
::
debug_filename
(
"foreground.ppm"
));
}
}
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
();
mln_ch_value
(
I
,
bool
)
input
;
unsigned
w
=
std
::
min
(
intensity_ima
.
nrows
()
/
3
,
intensity_ima
.
ncols
()
/
3
);
if
(
!
w
%
2
)
++
w
;
w
=
std
::
min
(
w
,
conf
.
sauvola_min_w
);
if
(
multi_scale_bin
)
{
std
::
cout
<<
"** Using sauvola_ms with w_1 = "
<<
w
<<
std
::
endl
;
input
=
scribo
::
binarization
::
sauvola_ms
(
intensity_ima
,
w
,
conf
.
sauvola_s
);
}
else
{
std
::
cout
<<
"** Using sauvola with w_1 = "
<<
w
<<
std
::
endl
;
input
=
scribo
::
binarization
::
sauvola
(
intensity_ima
,
w
);
}
if
(
debug
)
{
io
::
pbm
::
save
(
input
,
scribo
::
make
::
debug_filename
(
"binarization.pbm"
));
}
// Yeah, looks strange, but we need to negate by default to
// process dark objects on light background.
if
(
!
negate
)
logical
::
not_inplace
(
input
);
t_
=
timer_
;
std
::
cout
<<
"Foreground binarized. "
<<
t_
<<
std
::
endl
;
typedef
mln_ch_value
(
I
,
value
::
label_16
)
L
;
/// Finding components.
timer_
.
restart
();
typedef
component_set
<
L
>
Obj
;
Obj
filtered_components
;
{
mln
::
util
::
array
<
std
::
pair
<
box2d
,
std
::
pair
<
point2d
,
unsigned
>
>
>
attribs
;
value
::
label_16
ncomponents
;
L
components
=
extract_components
(
input
,
ncomponents
,
attribs
);
filtered_components
=
Obj
(
components
,
ncomponents
,
attribs
);
}
t_
=
timer_
;
std
::
cout
<<
"Object extracted "
<<
t_
<<
" - "
<<
filtered_components
.
nelements
()
<<
" components"
<<
std
::
endl
;
// if (debug)
// io::pgm::save(data::stretch(value::int_u8(), filtered_components), "ref_components.pgm");
/// linking potential components
timer_
.
restart
();
mln
::
util
::
couple
<
object_links
<
L
>
,
object_links
<
L
>
>
links
=
link
::
left_right
(
filtered_components
);
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_components, 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_components, 30);
t_
=
timer_
;
std
::
cout
<<
"Link done "
<<
t_
<<
std
::
endl
;
#ifndef NOUT
if
(
debug
)
{
std
::
cerr
<<
"BEFORE - ncomponents = "
<<
filtered_components
.
nelements
()
<<
std
::
endl
;
scribo
::
debug
::
save_linked_bboxes_image
(
input
,
left_link
,
right_link
,
literal
::
red
,
literal
::
cyan
,
literal
::
yellow
,
literal
::
green
,
anchor
::
MassCenter
,
scribo
::
make
::
debug_filename
(
"links.ppm"
));
}
#endif
// Validating left and right links.
timer_
.
restart
();
object_links
<
L
>
merged_links
=
link
::
merge_double_link
(
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
(
merged_links
,
conf
.
bbox_h_ratio
);
#ifndef NOUT
if
(
debug
)
{
mln_ch_value
(
I
,
value
::
rgb8
)
hratio_decision_image
=
scribo
::
debug
::
decision_image
(
input
,
merged_links
,
hratio_filtered_links
,
anchor
::
MassCenter
);
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
(
hratio_filtered_links
,
conf
.
bbox_overlap
);
#ifndef NOUT
if
(
debug
)
{
mln_ch_value
(
I
,
value
::
rgb8
)
overlap_decision_image
=
scribo
::
debug
::
decision_image
(
input
,
hratio_filtered_links
,
overlap_filtered_links
,
anchor
::
MassCenter
);
io
::
ppm
::
save
(
overlap_decision_image
,
scribo
::
make
::
debug_filename
(
"overlap_links_decision_image.ppm"
));
}
#endif
t_
=
timer_
;
std
::
cout
<<
"Components links filtered. "
<<
t_
<<
std
::
endl
;
timer_
.
restart
();
object_groups
<
L
>
groups
=
group
::
from_single_link
(
overlap_filtered_links
);
// Apply grouping in a temporary image (for debug purpose).
#ifndef NOUT
component_set
<
L
>
raw_group_image
=
group
::
apply
(
groups
);
#endif // !NOUT
t_
=
timer_
;
std
::
cout
<<
"Components grouped. "
<<
t_
<<
std
::
endl
;
#ifndef NOUT
if
(
debug
)
{
mln_ch_value
(
I
,
value
::
rgb8
)
decision_image
=
data
::
convert
(
value
::
rgb8
(),
input
);
scribo
::
draw
::
bounding_boxes
(
decision_image
,
filtered_components
,
literal
::
green
);
scribo
::
draw
::
bounding_boxes
(
decision_image
,
raw_group_image
,
literal
::
blue
);
io
::
ppm
::
save
(
decision_image
,
scribo
::
make
::
debug_filename
(
"group_and_object_image.ppm"
));
decision_image
=
data
::
convert
(
value
::
rgb8
(),
input
);
scribo
::
draw
::
bounding_boxes
(
decision_image
,
raw_group_image
,
literal
::
blue
);
io
::
ppm
::
save
(
decision_image
,
scribo
::
make
::
debug_filename
(
"group_image.ppm"
));
}
#endif // !NOUT
std
::
cout
<<
"Filtering groups..."
<<
std
::
endl
;
mln
::
util
::
timer
g_timer
;
timer_
.
restart
();
// Remove components part of groups with strictly less than 3 components.
g_timer
.
start
();
object_groups
<
L
>
filtered_small_groups
;
std
::
cout
<<
"** Using group too small"
<<
std
::
endl
;
filtered_small_groups
=
filter
::
object_groups_small
(
groups
,
conf
.
small_groups
);
t_
=
g_timer
;
std
::
cout
<<
"Small groups removed "
<<
t_
<<
std
::
endl
;
component_set
<
L
>
debug_image
;
mln_ch_value
(
I
,
value
::
rgb8
)
decision_image
;
if
(
debug
)
{
decision_image
=
data
::
convert
(
value
::
rgb8
(),
input
);
scribo
::
draw
::
groups_bboxes
(
decision_image
,
groups
,
literal
::
red
);
scribo
::
draw
::
groups_bboxes
(
decision_image
,
filtered_small_groups
,
literal
::
green
);
io
::
ppm
::
save
(
decision_image
,
scribo
::
make
::
debug_filename
(
"small_groups_filter.ppm"
));
}
// Remove components part of groups having a mean thickness lower than 8.
g_timer
.
restart
();
object_groups
<
L
>
filtered_thin_groups
;
std
::
cout
<<
"** Using group too thin"
<<
std
::
endl
;
filtered_thin_groups
=
filter
::
object_groups_v_thickness
(
filtered_small_groups
,
conf
.
v_thickness
);
t_
=
g_timer
;
std
::
cout
<<
"Groups too thin "
<<
t_
<<
std
::
endl
;
if
(
debug
)
{
decision_image
=
data
::
convert
(
value
::
rgb8
(),
input
);
scribo
::
draw
::
groups_bboxes
(
decision_image
,
filtered_small_groups
,
literal
::
red
);
scribo
::
draw
::
groups_bboxes
(
decision_image
,
filtered_thin_groups
,
literal
::
green
);
io
::
ppm
::
save
(
decision_image
,
scribo
::
make
::
debug_filename
(
"thin_groups_filter.ppm"
));
}
/// Apply grouping in the object image.
g_timer
.
restart
();
filtered_thin_groups
=
regroup
::
from_single_left_link
(
filtered_thin_groups
,
conf
.
regroup_dmax
);
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.
std
::
cout
<<
"** Using objects_with_two_holes"
<<
std
::
endl
;
groups
=
scribo
::
filter
::
object_groups_with_holes
(
filtered_thin_groups
,
conf
.
group_min_holes
);
t_
=
g_timer
;
std
::
cout
<<
"Objects_with_holes "
<<
t_
<<
std
::
endl
;
t_
=
timer_
;
std
::
cout
<<
"Objects groups filtered. "
<<
t_
<<
std
::
endl
;
t_
=
global_t_
;
std
::
cout
<<
"*** Result computed "
<<
t_
<<
std
::
endl
;
if
(
debug
)
{
decision_image
=
data
::
convert
(
value
::
rgb8
(),
input
);
scribo
::
draw
::
groups_bboxes
(
decision_image
,
filtered_thin_groups
,
literal
::
red
);
scribo
::
draw
::
groups_bboxes
(
decision_image
,
groups
,
literal
::
green
);
io
::
ppm
::
save
(
decision_image
,
scribo
::
make
::
debug_filename
(
"group_with_holes_filter.ppm"
));
}
timer_
.
restart
();
std
::
cout
<<
"Saving result..."
<<
std
::
endl
;
component_set
<
L
>
comps
=
primitive
::
group
::
apply
(
groups
);
t_
=
timer_
;
std
::
cout
<<
"Output saved "
<<
t_
<<
std
::
endl
;
std
::
cout
<<
"# objects = "
<<
comps
.
nelements
()
<<
std
::
endl
;
trace
::
exiting
(
"scribo::toolchain::text_in_picture"
);
return
comps
;
}
# endif // ! MLN_INCLUDE_ONLY
}
// end of namespace scribo::toolchain
}
// end of namespace scribo
#endif // SCRIBO_TOOLCHAIN_TEXT_IN_PICTURE_HH
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment