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> 2010-05-25 Guillaume Lazzara <z@lrde.epita.fr>
* io/text_boxes/save.hh: New. Save text boxes information. * io/text_boxes/save.hh: New. Save text boxes information.
......
...@@ -53,15 +53,30 @@ namespace scribo ...@@ -53,15 +53,30 @@ namespace scribo
using namespace mln; using namespace mln;
/// Extract horizontal lines matching a specific pattern. /*! \brief Extract horizontal lines matching a specific pattern.
///
/// \param[in] input A binary image. \param[in] input A binary image.
/// \param[in] length The minimum line length. \param[in] length The minimum line length.
/// \param[in] delta Distance between the object pixel and the \param[in] delta Distance between the object pixel and the
/// background pixel. background pixel.
///
/// \result An image of horizontal lines. \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> template <typename I>
mln_concrete(I) mln_concrete(I)
lines_h_pattern(const Image<I>& input, unsigned length, unsigned delta); lines_h_pattern(const Image<I>& input, unsigned length, unsigned delta);
...@@ -73,15 +88,16 @@ namespace scribo ...@@ -73,15 +88,16 @@ namespace scribo
mln_concrete(I) mln_concrete(I)
lines_h_pattern(const Image<I>& input, unsigned length, unsigned delta) 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(); mlc_is(mln_value(I), bool)::check();
mln_precondition(exact(input).is_valid()); mln_precondition(exact(input).is_valid());
mln_precondition(length % 2 == 1);
// FIXME: not generic. // FIXME: not generic.
window2d win; window2d win;
mln_deduce(I, site, dpsite) mln_deduce(I, site, dpsite)
dp1(-delta, 0), dp1(-delta - 1, 0),
dp2( delta, 0); dp2( delta + 1, 0);
win.insert(dp1); win.insert(dp1);
win.insert(dp2); win.insert(dp2);
......
...@@ -75,61 +75,216 @@ namespace scribo ...@@ -75,61 +75,216 @@ namespace scribo
# ifndef MLN_INCLUDE_ONLY # ifndef MLN_INCLUDE_ONLY
template <typename I, typename W>
mln_concrete(I) // Implementations
lines_pattern(const Image<I>& input_, unsigned length,
unsigned dir, const Window<W>& win_) namespace impl
{ {
trace::entering("scribo::primitive::extract::lines_pattern");
const I& input = exact(input_); namespace generic
const W& win = exact(win_); {
mlc_is(mln_value(I), bool)::check();
mln_precondition(input.is_valid()); 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. // If the foreground part of the pattern has more than 20%
extension::adjust_fill(input, length / 2, 0); // 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); // If the background parts of the pattern have exactly or
mln_ch_value(I,unsigned) // less than 95% of background pixels, the current pixel is
tmp = accu::transform_line(accu, input, length, dir); // 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; output(p) = is_foreground;
initialize(output, input); }
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; template <typename I, typename W>
for_all(p) 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% accu::count_value<bool> accu(true);
// of background pixels, the current pixel is considered as mln_ch_value(I,unsigned)
// background pixel. tmp = accu::transform_line(accu, input, length, dir);
if (length - tmp(p) > unsigned(0.2f * length) + 1)
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; unsigned pi = output.index_of_point(p);
continue; 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 for (; tmp_ptr < end_ptr; ++out_ptr, ++tmp_ptr)
// 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; // 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"); trace::exiting("scribo::primitive::extract::lines_pattern");
return output; return output;
} }
# endif // ! MLN_INCLUDE_ONLY # endif // ! MLN_INCLUDE_ONLY
} // end of namespace scribo::primitive::extract } // end of namespace scribo::primitive::extract
......
...@@ -30,15 +30,17 @@ ...@@ -30,15 +30,17 @@
/// ///
/// Extract vertical lines matching a specific pattern. /// Extract vertical lines matching a specific pattern.
#include <mln/core/concept/image.hh> # include <mln/core/concept/image.hh>
#include <mln/core/alias/window2d.hh> # include <mln/core/alias/window2d.hh>
# include <mln/win/rectangle2d.hh>
# include <mln/win/hline2d.hh>
# include <mln/morpho/dilation.hh> # include <mln/morpho/dilation.hh>
# include <mln/arith/times.hh>
# include <scribo/primitive/extract/lines_pattern.hh> # include <scribo/primitive/extract/lines_pattern.hh>
# include <scribo/primitive/internal/rd.hh>
namespace scribo namespace scribo
{ {
...@@ -70,26 +72,27 @@ namespace scribo ...@@ -70,26 +72,27 @@ namespace scribo
mln_concrete(I) mln_concrete(I)
lines_v_pattern(const Image<I>& input, unsigned length, unsigned delta) 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 } }; mln_precondition(length % 2 == 1);
// window2d win;
// convert::from_to(win_def, win);
// FIXME: not generic.
window2d win; window2d win;
mln_deduce(I, site, dpsite) mln_deduce(I, site, dpsite)
dp1(0, -delta), dp1(0, -delta - 1),
dp2(0, delta); dp2(0, delta + 1);
win.insert(dp1); win.insert(dp1);
win.insert(dp2); win.insert(dp2);
//FIXME: Add reconstruction instead of this arbitrary dilation. mln_concrete(I) output = lines_pattern(input, length, 0, win);
win::vline2d vwin(length/2 + 2);
// win::vline2d vwin(length); mln_concrete(I)
return morpho::dilation(lines_pattern(input, length, 0, win), vwin); output_dil = morpho::dilation(output,
// return lines_pattern(input, length, 0, win); 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