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
eec4ffe4
Commit
eec4ffe4
authored
Nov 15, 2010
by
Guillaume Lazzara
Browse files
scribo/primitive/extract/separators_nonvisible.hh: New routine.
parent
964a8b8a
Changes
2
Hide whitespace changes
Inline
Side-by-side
scribo/ChangeLog
View file @
eec4ffe4
2010-11-15 Guillaume Lazzara <z@lrde.epita.fr>
* scribo/primitive/extract/separators_nonvisible.hh: New routine.
2010-11-15 Guillaume Lazzara <z@lrde.epita.fr>
Import rgb8 to rgbn conversion function from Yann's sandbox.
...
...
scribo/scribo/primitive/extract/separators_nonvisible.hh
0 → 100644
View file @
eec4ffe4
// 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.
/// \file
///
/// \brief Find non visible separators (whitespaces)
///
/// \fixme To be cleaned up
#ifndef SCRIBO_PRIMITIVE_EXTRACT_SEPARATORS_NONVISIBLE_HH
# define SCRIBO_PRIMITIVE_EXTRACT_SEPARATORS_NONVISIBLE_HH
#include
<mln/core/concept/image.hh>
#include
<mln/core/image/dmorph/image_if.hh>
#include
<mln/pw/all.hh>
#include
<mln/draw/line.hh>
#include
<mln/data/wrap.hh>
#include
<mln/data/fill.hh>
#include
<mln/data/convert.hh>
#include
<mln/labeling/colorize.hh>
#include
<mln/labeling/relabel.hh>
#include
<mln/labeling/blobs.hh>
#include
<mln/morpho/closing/structural.hh>
#include
<mln/morpho/closing/area.hh>
#include
<mln/morpho/opening/structural.hh>
#include
<mln/win/rectangle2d.hh>
#include
<mln/win/vline2d.hh>
#include
<mln/logical/not.hh>
#include
<mln/io/pbm/all.hh>
#include
<mln/io/pgm/all.hh>
#include
<mln/io/ppm/save.hh>
#include
<mln/literal/colors.hh>
#include
<mln/value/label_16.hh>
#include
<mln/value/int_u8.hh>
#include
<mln/value/int_u12.hh>
#include
<mln/value/int_u16.hh>
#include
<mln/value/rgb8.hh>
#include
<mln/draw/box_plain.hh>
#include
<mln/transform/influence_zone_geodesic.hh>
#include
<mln/data/stretch.hh>
#include
<mln/util/timer.hh>
#include
<mln/norm/l1.hh>
#include
<scribo/core/object_groups.hh>
#include
<scribo/core/component_set.hh>
#include
<scribo/primitive/extract/components.hh>
#include
<scribo/primitive/extract/lines_h_pattern.hh>
#include
<scribo/primitive/remove/separators.hh>
#include
<scribo/preprocessing/denoise_fg.hh>
#include
<scribo/preprocessing/rotate_90.hh>
#include
<scribo/primitive/link/internal/dmax_default.hh>
#include
<scribo/primitive/link/with_single_right_link_dmax_ratio.hh>
#include
<scribo/primitive/link/with_single_right_link_dmax_ratio_aligned.hh>
#include
<scribo/primitive/group/from_double_link_any.hh>
#include
<scribo/filter/object_links_top_aligned.hh>
#include
<scribo/filter/object_groups_small.hh>
#include
<scribo/filter/object_links_bottom_aligned.hh>
#include
<scribo/debug/save_linked_bboxes_image.hh>
#include
<scribo/debug/decision_image.hh>
namespace
scribo
{
namespace
primitive
{
namespace
extract
{
using
namespace
mln
;
/// \brief Find non visible separators (whitespaces)
//
template
<
typename
I
>
mln_concrete
(
I
)
separators_nonvisible
(
const
Image
<
I
>&
in_
);
# ifndef MLN_INCLUDE_ONLY
namespace
internal
{
// Enable debug.
bool
_debug_
;
template
<
typename
L
>
void
filter_bad_groups
(
object_groups
<
L
>&
top_groups
,
object_groups
<
L
>&
bot_groups
)
{
const
component_set
<
L
>&
comps
=
top_groups
.
components
();
const
L
&
lbl
=
comps
.
labeled_image
();
for_all_groups
(
c
,
top_groups
)
{
box2d
b
=
comps
(
c
).
bbox
();
b
.
enlarge
(
0
,
comps
(
c
).
bbox
().
height
());
b
.
crop_wrt
(
lbl
.
domain
());
typedef
mln_value
(
L
)
V
;
const
V
*
top_ptr
=
&
lbl
(
b
.
pmin
());
const
V
*
bot_ptr
=
&
lbl
(
point2d
(
b
.
pmax
().
row
(),
b
.
pmin
().
col
()));
unsigned
ntop
=
0
,
nbot
=
0
;
for
(
unsigned
n
=
0
;
n
<
b
.
width
();
++
n
)
{
if
(
*
top_ptr
)
++
ntop
;
if
(
*
bot_ptr
)
++
nbot
;
}
if
(
ntop
/
b
.
width
()
>
0.50
f
)
top_groups
(
c
)
=
c
;
if
(
nbot
/
b
.
width
()
>
0.50
f
)
bot_groups
(
c
)
=
c
;
}
}
template
<
typename
L
>
mln_site
(
L
)
my_anchors
(
const
component_set
<
L
>&
comps
,
unsigned
current_object
,
anchor
::
Type
anchor
)
{
mln_site
(
L
)
sp
;
// = comps(current_object).bbox().pcenter();
unsigned
h
=
comps
(
current_object
).
bbox
().
height
();
switch
(
anchor
)
{
default:
return
sp
;
// Bounding box top center
case
anchor
::
Top
:
// FIXME: rename as TopLeft
sp
.
col
()
=
comps
(
current_object
).
bbox
().
pmin
().
col
();
sp
.
row
()
=
comps
(
current_object
).
bbox
().
pmin
().
row
()
+
math
::
min
(
2u
,
(
h
+
1
)
/
2
-
1
);
break
;
// Bounding box bottom center
case
anchor
::
Bottom
:
// FIXME: rename as BottomLeft
sp
.
col
()
=
comps
(
current_object
).
bbox
().
pmax
().
col
();
sp
.
row
()
=
comps
(
current_object
).
bbox
().
pmax
().
row
()
-
math
::
min
(
2u
,
(
h
+
1
)
/
2
-
1
);
break
;
}
return
sp
;
}
using
namespace
primitive
::
link
::
internal
;
template
<
typename
L
,
typename
E
>
class
single_dmax_ratio_aligned_functor_base
:
public
link_single_dmax_ratio_base
<
L
,
dmax_default
,
E
>
{
typedef
link_single_dmax_ratio_base
<
L
,
dmax_default
,
E
>
super_
;
public:
typedef
mln_site
(
L
)
P
;
single_dmax_ratio_aligned_functor_base
(
const
mln_ch_value
(
L
,
bool
)
&
input
,
const
component_set
<
L
>&
components
,
unsigned
dmax
,
float
min_angle
,
float
max_angle
,
anchor
::
Type
anchor_
)
:
super_
(
components
,
anchor
::
Horizontal
,
dmax_default
(
dmax
)),
anchor
(
anchor_
),
debug_
(
data
::
convert
(
value
::
rgb8
(),
input
)),
debug_angle_
(
data
::
convert
(
value
::
rgb8
(),
input
))
{
min_alpha_rad
=
(
min_angle
/
180.0
f
)
*
math
::
pi
;
max_alpha_rad
=
(
max_angle
/
180.0
f
)
*
math
::
pi
;
}
void
compute_next_site_
(
P
&
p
)
{
++
p
.
col
();
}
void
compute_next_site_f_
(
unsigned
&
p
)
{
++
p
;
}
mln_site
(
L
)
start_point_
(
unsigned
current_object
,
anchor
::
Type
anchor
)
{
return
my_anchors
(
this
->
components_
,
current_object
,
anchor
);
}
inline
bool
valid_link_
(
unsigned
current_object
,
const
P
&
start_point
,
const
P
&
p
)
{
if
(
!
super_
::
valid_link_
(
current_object
,
start_point
,
p
))
return
false
;
box
<
P
>
b
=
this
->
components_
(
current_object
).
bbox
();
// Distance between the two components.
float
dist
;
// current object is on the left.
if
(
p
[
this
->
direction_
]
>
b
.
pmax
()[
this
->
direction_
])
dist
=
math
::
abs
(
p
[
this
->
direction_
]
-
b
.
pmax
()[
this
->
direction_
]);
// current object is on the right.
else
dist
=
math
::
abs
(
p
[
this
->
direction_
]
-
b
.
pmin
()[
this
->
direction_
]);
int
ldist
=
this
->
components_
(
current_object
).
bbox
().
width
();
// Components are really close, so the angle is more permissive.
if
(
dist
<
3
*
ldist
)
{
return
filter
::
internal
::
component_aligned_rad
(
this
->
components_
,
current_object
,
this
->
labeled_image_
(
p
),
anchor
,
max_alpha_rad
);
}
// Components are really far, so the angle is less permissive.
return
filter
::
internal
::
component_aligned_rad
(
this
->
components_
,
current_object
,
this
->
labeled_image_
(
p
),
anchor
,
min_alpha_rad
);
}
void
validate_link_
(
unsigned
current_object
,
const
P
&
start_point
,
const
P
&
p
,
anchor
::
Type
anchor
)
{
super_
::
validate_link_
(
current_object
,
start_point
,
p
,
anchor
);
if
(
_debug_
)
{
mln_site
(
L
)
p1
=
my_anchors
(
this
->
components_
,
current_object
,
anchor
),
p2
=
my_anchors
(
this
->
components_
,
this
->
labeled_image_
(
p
),
anchor
);
mln
::
draw
::
line
(
debug_
,
p1
,
p2
,
literal
::
green
);
float
angle
=
filter
::
internal
::
alignment_angle
(
this
->
components_
,
current_object
,
this
->
labeled_image_
(
p
),
anchor
);
angle
=
(
angle
*
180.0
f
)
/
math
::
pi
;
angle
=
angle
*
20.0
f
+
1.0
f
;
mln
::
draw
::
line
(
debug_angle_
,
p1
,
p2
,
value
::
rgb8
(
angle
,
angle
,
angle
));
}
}
void
invalidate_link_
(
unsigned
current_object
,
const
P
&
start_point
,
const
P
&
p
,
anchor
::
Type
anchor
)
{
super_
::
invalidate_link_
(
current_object
,
start_point
,
p
,
anchor
);
if
(
_debug_
)
{
if
(
this
->
labeled_image_
.
domain
().
has
(
p
)
&&
this
->
labeled_image_
(
p
)
!=
0
)
{
mln_site
(
L
)
p1
=
my_anchors
(
this
->
components_
,
current_object
,
anchor
),
p2
=
my_anchors
(
this
->
components_
,
this
->
labeled_image_
(
p
),
anchor
);
if
(
this
->
labeled_image_
.
domain
().
has
(
p2
)
&&
norm
::
l1_distance
(
p1
.
to_vec
(),
p2
.
to_vec
())
<
300
)
{
mln
::
draw
::
line
(
debug_
,
p1
,
p2
,
literal
::
red
);
}
float
angle
=
filter
::
internal
::
alignment_angle
(
this
->
components_
,
current_object
,
this
->
labeled_image_
(
p
),
anchor
);
angle
=
(
angle
*
180.0
f
)
/
math
::
pi
;
angle
=
angle
*
20.0
f
+
1.0
f
;
mln
::
draw
::
line
(
debug_angle_
,
p1
,
p2
,
value
::
rgb8
(
angle
,
angle
,
angle
));
}
}
}
float
min_alpha_rad
;
float
max_alpha_rad
;
anchor
::
Type
anchor
;
mln_ch_value
(
L
,
value
::
rgb8
)
debug_
;
mln_ch_value
(
L
,
value
::
rgb8
)
debug_angle_
;
};
template
<
typename
L
>
class
single_right_dmax_ratio_aligned_functor
:
public
single_dmax_ratio_aligned_functor_base
<
L
,
single_right_dmax_ratio_aligned_functor
<
L
>
>
{
typedef
single_right_dmax_ratio_aligned_functor
<
L
>
self_t
;
typedef
single_dmax_ratio_aligned_functor_base
<
L
,
self_t
>
super_
;
public:
typedef
mln_site
(
L
)
P
;
single_right_dmax_ratio_aligned_functor
(
const
mln_ch_value
(
L
,
bool
)
&
input
,
const
component_set
<
L
>&
components
,
unsigned
dmax
,
float
min_angle
,
float
max_angle
,
anchor
::
Type
anchor
)
:
super_
(
input
,
components
,
dmax
,
min_angle
,
max_angle
,
anchor
)
{
}
void
compute_next_site_
(
P
&
p
)
{
++
p
.
col
();
}
void
compute_next_site_f_
(
unsigned
&
p
)
{
++
p
;
}
};
template
<
typename
L
>
class
single_left_dmax_ratio_aligned_functor
:
public
single_dmax_ratio_aligned_functor_base
<
L
,
single_left_dmax_ratio_aligned_functor
<
L
>
>
{
typedef
single_left_dmax_ratio_aligned_functor
<
L
>
self_t
;
typedef
single_dmax_ratio_aligned_functor_base
<
L
,
self_t
>
super_
;
public:
typedef
mln_site
(
L
)
P
;
single_left_dmax_ratio_aligned_functor
(
const
mln_ch_value
(
L
,
bool
)
&
input
,
const
component_set
<
L
>&
components
,
unsigned
dmax
,
float
min_angle
,
float
max_angle
,
anchor
::
Type
anchor
)
:
super_
(
input
,
components
,
dmax
,
min_angle
,
max_angle
,
anchor
)
{
}
void
compute_next_site_
(
P
&
p
)
{
--
p
.
col
();
}
void
compute_next_site_f_
(
unsigned
&
p
)
{
--
p
;
}
};
}
// end of namespace scribo::primitive::extract::internal
// FACADE
template
<
typename
I
>
mln_concrete
(
I
)
separators_nonvisible
(
const
Image
<
I
>&
in_
)
{
const
I
&
in
=
exact
(
in_
);
mln_precondition
(
in
.
is_valid
());
typedef
mln_value
(
I
)
Vi
;
mlc_is
(
Vi
,
bool
)
::
check
();
internal
::
_debug_
=
false
;
unsigned
min_angle
=
3
,
max_angle
=
5
,
min_card
=
3
;
util
::
timer
t
;
util
::
timer
gt
;
// Load (OK)
t
.
start
();
float
t_
=
t
;
std
::
cout
<<
"Image loaded - "
<<
t_
<<
std
::
endl
;
gt
.
start
();
// Remove horizontal lines.
t
.
restart
();
mln_concrete
(
I
)
hlines
=
primitive
::
extract
::
lines_h_pattern
(
in
,
50
,
3
);
mln_concrete
(
I
)
input
=
primitive
::
remove
::
separators
(
in
,
hlines
);
t_
=
t
;
std
::
cout
<<
"Horizontal lines removed - "
<<
t_
<<
std
::
endl
;
// Closing structural - Connect characters.
t
.
restart
();
win
::
hline2d
vl
(
17
);
mln_concrete
(
I
)
input_clo
=
morpho
::
closing
::
structural
(
input
,
vl
);
// input_clo = scribo::preprocessing::rotate_90(input_clo, true);
t_
=
t
;
std
::
cout
<<
"closing_structural - "
<<
t_
<<
std
::
endl
;
if
(
internal
::
_debug_
)
{
// Restore input orientation.
input
=
scribo
::
preprocessing
::
rotate_90
(
input
,
false
);
io
::
pbm
::
save
(
input_clo
,
"input_clo.pbm"
);
}
// Rotate (OK)
t
.
restart
();
input_clo
=
scribo
::
preprocessing
::
rotate_90
(
input_clo
,
false
);
t_
=
t
;
std
::
cout
<<
"rotate_90 - "
<<
t_
<<
std
::
endl
;
/// Finding components.
typedef
value
::
int_u16
V
;
typedef
mln_ch_value
(
I
,
V
)
L
;
t
.
restart
();
V
ncomponents
;
component_set
<
L
>
components
=
scribo
::
primitive
::
extract
::
components
(
input_clo
,
c8
(),
ncomponents
);
t_
=
t
;
std
::
cout
<<
"extract::components - "
<<
t_
<<
std
::
endl
;
if
(
internal
::
_debug_
)
io
::
pgm
::
save
(
data
::
convert
(
value
::
int_u8
(),
components
.
labeled_image
()),
"lbl.pgm"
);
unsigned
dmax
=
5
;
t
.
restart
();
object_links
<
L
>
top_right
,
bot_right
;
object_links
<
L
>
top_left
,
bot_left
;
// Top
{
// Right
internal
::
single_right_dmax_ratio_aligned_functor
<
L
>
functor
(
input_clo
,
components
,
dmax
,
min_angle
,
max_angle
,
anchor
::
Top
);
// top_right = primitive::link::impl::compute_fastest(functor, anchor::Top);
top_right
=
primitive
::
link
::
compute
(
functor
,
anchor
::
Top
);
t
.
stop
();
if
(
internal
::
_debug_
)
{
io
::
ppm
::
save
(
functor
.
debug_
,
"right_top.ppm"
);
io
::
ppm
::
save
(
functor
.
debug_angle_
,
"right_top_angle.ppm"
);
}
t
.
resume
();
// Left
internal
::
single_left_dmax_ratio_aligned_functor
<
L
>
lfunctor
(
input_clo
,
components
,
dmax
,
min_angle
,
max_angle
,
anchor
::
Top
);
top_left
=
primitive
::
link
::
compute
(
lfunctor
,
anchor
::
Top
);
t
.
stop
();
if
(
internal
::
_debug_
)
{
io
::
ppm
::
save
(
lfunctor
.
debug_
,
"left_top.ppm"
);
io
::
ppm
::
save
(
lfunctor
.
debug_angle_
,
"left_top_angle.ppm"
);
mln_ch_value
(
I
,
value
::
rgb8
)
output
=
duplicate
(
functor
.
debug_
);
data
::
paste
((
lfunctor
.
debug_
|
(
pw
::
value
(
lfunctor
.
debug_
)
!=
pw
::
cst
(
literal
::
black
)))
|
(
pw
::
value
(
lfunctor
.
debug_
)
!=
pw
::
cst
(
literal
::
white
)),
output
);
io
::
ppm
::
save
(
output
,
"left_right_top.ppm"
);
}
t
.
resume
();
}
// Bottom
{
// Right
internal
::
single_right_dmax_ratio_aligned_functor
<
L
>
functor
(
input_clo
,
components
,
dmax
,
min_angle
,
max_angle
,
anchor
::
Bottom
);
bot_right
=
primitive
::
link
::
compute
(
functor
,
anchor
::
Bottom
);
t
.
stop
();
if
(
internal
::
_debug_
)
{
io
::
ppm
::
save
(
functor
.
debug_
,
"right_bot.ppm"
);
io
::
ppm
::
save
(
functor
.
debug_angle_
,
"right_bot_angle.ppm"
);
}
t
.
resume
();