Commit b8aaebae authored by Guillaume Lazzara's avatar Guillaume Lazzara
Browse files

Improve line detection.

	* primitive/extract/lines_h_pattern.hh,
	* primitive/extract/lines_v_pattern.hh: Use reconstruction
	algorithm.

	* primitive/extract/lines_pattern.hh: Add a fast implementation.
parent cbbbffd5
2010-05-25 Guillaume Lazzara <z@lrde.epita.fr>
Improve line detection.
* primitive/extract/lines_h_pattern.hh,
* primitive/extract/lines_v_pattern.hh: Use reconstruction
algorithm.
* primitive/extract/lines_pattern.hh: Add a fast implementation.
2010-05-25 Guillaume Lazzara <z@lrde.epita.fr>
* io/text_boxes/save.hh: New. Save text boxes information.
......
......@@ -53,15 +53,30 @@ namespace scribo
using namespace mln;
/// Extract horizontal lines matching a specific pattern.
///
/// \param[in] input A binary image.
/// \param[in] length The minimum line length.
/// \param[in] delta Distance between the object pixel and the
/// background pixel.
///
/// \result An image of horizontal lines.
//
/*! \brief Extract horizontal lines matching a specific pattern.
\param[in] input A binary image.
\param[in] length The minimum line length.
\param[in] delta Distance between the object pixel and the
background pixel.
\result An image of horizontal lines.
o
| ^
| | Delta
| v
X
| ^
| | Delta
| v
o
Using a delta of 0 is equivalent to the use of a c2_row
neighborhood.
*/
template <typename I>
mln_concrete(I)
lines_h_pattern(const Image<I>& input, unsigned length, unsigned delta);
......@@ -73,15 +88,16 @@ namespace scribo
mln_concrete(I)
lines_h_pattern(const Image<I>& input, unsigned length, unsigned delta)
{
trace::entering("scribo::primitive::extract::lines_h_pattern");
mlc_is(mln_value(I), bool)::check();
mln_precondition(exact(input).is_valid());
mln_precondition(length % 2 == 1);
// FIXME: not generic.
window2d win;
mln_deduce(I, site, dpsite)
dp1(-delta, 0),
dp2( delta, 0);
dp1(-delta - 1, 0),
dp2( delta + 1, 0);
win.insert(dp1);
win.insert(dp2);
......
......@@ -75,61 +75,216 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY
template <typename I, typename W>
mln_concrete(I)
lines_pattern(const Image<I>& input_, unsigned length,
unsigned dir, const Window<W>& win_)
// Implementations
namespace impl
{
trace::entering("scribo::primitive::extract::lines_pattern");
const I& input = exact(input_);
const W& win = exact(win_);
mlc_is(mln_value(I), bool)::check();
mln_precondition(input.is_valid());
namespace generic
{
template <typename I, typename W>
mln_concrete(I)
lines_pattern(const Image<I>& input_, unsigned length,
unsigned dir, const Window<W>& win_)
{
trace::entering("scribo::primitive::extract::impl::generic::lines_pattern");
const I& input = exact(input_);
const W& win = exact(win_);
mlc_is(mln_value(I), bool)::check();
mln_precondition(input.is_valid());
// Adjusting extension.
extension::adjust_fill(input, length / 2, 0);
accu::count_value<bool> accu(true);
mln_ch_value(I,unsigned)
tmp = accu::transform_line(accu, input, length, dir);
mln_concrete(I) output;
initialize(output, input);
mln_piter(I) p(input.domain());
mln_qiter(window2d) q(win, p);
bool is_foreground;
for_all(p)
{
// Adjusting extension.
extension::adjust_fill(input, length / 2, 0);
// If the foreground part of the pattern has more than 20%
// of background pixels, the current pixel is considered as
// background pixel.
if (length - tmp(p) > unsigned(0.2f * length) + 1)
{
output(p) = false;
continue;
}
accu::count_value<bool> accu(true);
mln_ch_value(I,unsigned)
tmp = accu::transform_line(accu, input, length, dir);
// If the background parts of the pattern have exactly or
// less than 95% of background pixels, the current pixel is
// considered as part of the background.
is_foreground = true;
for_all(q)
if ((length - tmp(q)) < unsigned(length * 0.95f) + 1)
{
is_foreground = false;
break;
}
mln_concrete(I) output;
initialize(output, input);
output(p) = is_foreground;
}
trace::exiting("scribo::primitive::extract::impl::generic::lines_pattern");
return output;
}
} // end of namespace scribo::primitive::extract::impl::generic
mln_piter(I) p(input.domain());
mln_qiter(window2d) q(win, p);
bool is_foreground;
for_all(p)
template <typename I, typename W>
mln_concrete(I)
lines_pattern_fast(const Image<I>& input_, unsigned length,
unsigned dir, const Window<W>& win_)
{
trace::entering("scribo::primitive::extract::impl::lines_pattern_fast");
const I& input = exact(input_);
const W& win = exact(win_);
mlc_is(mln_value(I), bool)::check();
mln_precondition(input.is_valid());
// Adjusting extension.
extension::adjust_fill(input, length / 2, 0);
// If the foreground part of the pattern has more than 20%
// of background pixels, the current pixel is considered as
// background pixel.
if (length - tmp(p) > unsigned(0.2f * length) + 1)
accu::count_value<bool> accu(true);
mln_ch_value(I,unsigned)
tmp = accu::transform_line(accu, input, length, dir);
mln_concrete(I) output;
initialize(output, input);
util::array<int>
q_arr = offsets_wrt(output, win);
bool is_foreground;
unsigned ncols = geom::ncols(output);
unsigned hit_ratio = 0.2f * length + 1;
unsigned miss_ratio = 0.95f * length + 1;
mln_box_runstart_piter(I) p(output.domain());
for_all(p)
{
output(p) = false;
continue;
}
unsigned pi = output.index_of_point(p);
unsigned *tmp_ptr = &tmp.element(pi);
unsigned *end_ptr = tmp_ptr + ncols;
mln_value(I) *out_ptr = &output.element(pi);
// If the background parts of the pattern have exactly or
// less than 95% of background pixels, the current pixel is
// considered as part of the background.
is_foreground = true;
for_all(q)
if ((length - tmp(q)) < unsigned(length * 0.95f) + 1)
for (; tmp_ptr < end_ptr; ++out_ptr, ++tmp_ptr)
{
is_foreground = false;
break;
// If the foreground part of the pattern has more than 20%
// of background pixels, the current pixel is considered as
// background pixel.
if (length - *tmp_ptr > hit_ratio)
{
*out_ptr = false;
continue;
}
// If the background parts of the pattern have exactly or
// less than 95% of background pixels, the current pixel is
// considered as part of the background.
is_foreground = true;
for (unsigned i = 0; i < q_arr.size(); ++i)
if ((length - *(tmp_ptr + q_arr[i])) < miss_ratio)
{
is_foreground = false;
break;
}
*out_ptr = is_foreground;
}
}
trace::exiting("scribo::primitive::extract::impl::lines_pattern_fast");
return output;
}
} // end of namespace scribo::primitive::extract::impl
// Dispatch
output(p) = is_foreground;
namespace internal
{
template <typename I, typename W>
mln_concrete(I)
lines_pattern_dispatch(mln::trait::image::value_storage::any,
mln::trait::image::value_access::any,
mln::trait::image::ext_domain::any,
const Image<I>& input, unsigned length,
unsigned dir, const Window<W>& win)
{
return impl::generic::lines_pattern(input, length, dir, win);
}
template <typename I, typename W>
mln_concrete(I)
lines_pattern_dispatch(mln::trait::image::value_storage::one_block,
mln::trait::image::value_access::direct,
mln::trait::image::ext_domain::some,
const Image<I>& input, unsigned length,
unsigned dir, const Window<W>& win)
{
return impl::lines_pattern_fast(input, length, dir, win);
}
template <typename I, typename W>
mln_concrete(I)
lines_pattern_dispatch(const Image<I>& input, unsigned length,
unsigned dir, const Window<W>& win)
{
return lines_pattern_dispatch(mln_trait_image_value_storage(I)(),
mln_trait_image_value_access(I)(),
mln_trait_image_ext_domain(I)(),
input,
length,
dir, win);
}
} // end of namespace scribo::primitive::extract::internal
// Facade
template <typename I, typename W>
mln_concrete(I)
lines_pattern(const Image<I>& input, unsigned length,
unsigned dir, const Window<W>& win)
{
trace::entering("scribo::primitive::extract::lines_pattern");
mlc_is(mln_value(I), bool)::check();
mln_precondition(exact(input).is_valid());
mln_precondition(exact(win).is_valid());
mln_precondition(length != 0);
mln_precondition(dir == 0 || dir == 1);
mln_concrete(I)
output = internal::lines_pattern_dispatch(input, length, dir, win);
trace::exiting("scribo::primitive::extract::lines_pattern");
return output;
}
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace scribo::primitive::extract
......
......@@ -30,15 +30,17 @@
///
/// Extract vertical lines matching a specific pattern.
#include <mln/core/concept/image.hh>
#include <mln/core/alias/window2d.hh>
# include <mln/win/hline2d.hh>
# include <mln/core/concept/image.hh>
# include <mln/core/alias/window2d.hh>
# include <mln/win/rectangle2d.hh>
# include <mln/morpho/dilation.hh>
# include <mln/arith/times.hh>
# include <scribo/primitive/extract/lines_pattern.hh>
# include <scribo/primitive/internal/rd.hh>
namespace scribo
{
......@@ -70,26 +72,27 @@ namespace scribo
mln_concrete(I)
lines_v_pattern(const Image<I>& input, unsigned length, unsigned delta)
{
mln_precondition(length % 2 == 1);
trace::entering("scribo::primitive::extract::lines_v_pattern");
// bool win_def[1][7] = { { 1, 0, 0, 0, 0, 0, 1 } };
// window2d win;
// convert::from_to(win_def, win);
mln_precondition(length % 2 == 1);
// FIXME: not generic.
window2d win;
mln_deduce(I, site, dpsite)
dp1(0, -delta),
dp2(0, delta);
dp1(0, -delta - 1),
dp2(0, delta + 1);
win.insert(dp1);
win.insert(dp2);
//FIXME: Add reconstruction instead of this arbitrary dilation.
win::vline2d vwin(length/2 + 2);
// win::vline2d vwin(length);
return morpho::dilation(lines_pattern(input, length, 0, win), vwin);
// return lines_pattern(input, length, 0, win);
mln_concrete(I) output = lines_pattern(input, length, 0, win);
mln_concrete(I)
output_dil = morpho::dilation(output,
win::rectangle2d(length / 2 + delta, 3));
output = scribo::primitive::internal::rd(output, input * output_dil);
trace::exiting("scribo::primitive::extract::lines_v_pattern");
return output;
}
......
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