last-svn-commit-131-gb8aaeba 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. --- scribo/ChangeLog | 10 ++ scribo/primitive/extract/lines_h_pattern.hh | 40 ++++-- scribo/primitive/extract/lines_pattern.hh | 227 ++++++++++++++++++++++----- scribo/primitive/extract/lines_v_pattern.hh | 39 +++-- 4 files changed, 250 insertions(+), 66 deletions(-) diff --git a/scribo/ChangeLog b/scribo/ChangeLog index fe1e390..a4e2373 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,15 @@ 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. 2010-05-25 Guillaume Lazzara <z@lrde.epita.fr> diff --git a/scribo/primitive/extract/lines_h_pattern.hh b/scribo/primitive/extract/lines_h_pattern.hh index 08025a1..0da7900 100644 --- a/scribo/primitive/extract/lines_h_pattern.hh +++ b/scribo/primitive/extract/lines_h_pattern.hh @@ -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); diff --git a/scribo/primitive/extract/lines_pattern.hh b/scribo/primitive/extract/lines_pattern.hh index 18cb784..5f9950a 100644 --- a/scribo/primitive/extract/lines_pattern.hh +++ b/scribo/primitive/extract/lines_pattern.hh @@ -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 diff --git a/scribo/primitive/extract/lines_v_pattern.hh b/scribo/primitive/extract/lines_v_pattern.hh index ccd21c5..cbdf080 100644 --- a/scribo/primitive/extract/lines_v_pattern.hh +++ b/scribo/primitive/extract/lines_v_pattern.hh @@ -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; } -- 1.5.6.5
participants (1)
-
Guillaume Lazzara