27 #ifndef SCRIBO_PRIMITIVE_EXTRACT_LINES_H_THICK_AND_THIN_HH
28 # define SCRIBO_PRIMITIVE_EXTRACT_LINES_H_THICK_AND_THIN_HH
34 # include <mln/io/pbm/load.hh>
35 # include <mln/io/pbm/save.hh>
36 # include <mln/io/ppm/save.hh>
38 # include <mln/logical/and.hh>
39 # include <mln/logical/or.hh>
41 # include <mln/make/w_window2d.hh>
43 # include <mln/extension/adjust_fill.hh>
44 # include <mln/accu/transform_line.hh>
45 # include <mln/accu/count_value.hh>
46 # include <mln/data/fill.hh>
47 # include <mln/literal/grays.hh>
48 # include <mln/literal/colors.hh>
50 # include <mln/pw/all.hh>
51 # include <mln/core/routine/duplicate.hh>
52 # include <mln/win/rectangle2d.hh>
53 # include <mln/win/hline2d.hh>
54 # include <mln/morpho/dilation.hh>
56 # include <mln/data/convert.hh>
57 # include <mln/data/fill.hh>
58 # include <mln/core/image/dmorph/image_if.hh>
60 # include <mln/core/alias/neighb2d.hh>
61 # include <mln/labeling/compute.hh>
62 # include <mln/labeling/foreground.hh>
64 # include <scribo/core/macros.hh>
65 # include <scribo/core/def/lbl_type.hh>
66 # include <scribo/primitive/internal/rd.hh>
68 # include <scribo/debug/logger.hh>
87 unsigned length,
unsigned delta,
93 # ifndef MLN_INCLUDE_ONLY
115 mln_piter_(
box2d) p(input.domain());
121 output(p) = literal::black;
126 output(p) = literal::white;
131 output(p) = literal::red;
134 output(p) = literal::green;
137 output(p) = literal::blue;
142 output(p) = literal::dark_gray;
150 tag_it(
const image2d<bool>& input,
unsigned length,
unsigned delta,
152 float p_enough = 0.6)
155 few =
unsigned(p_few * length + 0.49999),
156 enough =
unsigned(p_enough * length + 0.49999),
157 a_lot = length - few;
161 accu::count_value<bool> accu(
true);
176 typedef const unsigned* ptr_t;
177 value::int_u8* p_out;
179 for (
unsigned row = 0; row <
nrows; ++row)
182 p_ = & count.
at_(row, -1),
183 p_top = p_ + offset_up,
184 p_bot = p_ + offset_down;
185 p_out = & output.
at_(row, -1);
186 for (
unsigned col = 0; col <
ncols; ++col)
193 if (*p_top <= few && *p_bot <= few)
197 else if (*p_ >= enough)
206 if (*p_top <= few && *p_bot >= a_lot)
212 if (*p_top >= a_lot && *p_bot <= few)
234 p_o.val() = p_i.val() == tag;
241 void flush_tag(const
image2d<
value::int_u8>& input,
unsigned col,
value::int_u8 tag,
243 int& row,
value::int_u8& next_tag)
246 const value::int_u8*
p = & input.at_(row, col);
256 void draw_vertical(
image2d<bool>& output,
unsigned col,
int row_start,
int row_end)
259 bool* p_out = & output.
at_(row_start, col);
260 for (
int row = row_start; row < row_end; ++row, p_out += offset)
284 const value::int_u8& t = input.
at_(row, col);
287 assert(t == tag_top);
289 value::int_u8 next_tag;
290 flush_tag(input, col, tag_top, r, next_tag);
291 if (next_tag == tag_mdl || next_tag == tag_thin)
293 flush_tag(input, col, next_tag, r, next_tag);
294 if (next_tag != tag_bot)
296 flush_tag(input, col, tag_bot, r, next_tag);
297 draw_vertical(output, col, row, r);
300 else if (next_tag == tag_bot)
302 flush_tag(input, col, tag_bot, r, next_tag);
303 draw_vertical(output, col, row, r);
307 while (row <= maxrow);
309 while (++col <= maxcol);
321 const value::int_u8* p_in = input.
buffer();
322 bool* p_out = output.
buffer();
323 for (
unsigned i = 0; i < N; ++i)
325 if (*p_in == tag_thin)
333 template <
typename I,
typename J,
334 typename N,
typename W,
typename D>
336 rd3_fast(const
Image<I>& f_,
342 const I& f =
exact(f_);
343 const J& g =
exact(g_);
345 const W& w_win =
exact(w_win_);
347 mln_precondition(f.is_valid());
348 mln_precondition(w_win.is_valid());
353 const unsigned n_ws = w_win.size();
354 util::array<int>
dp = offsets_wrt(f, w_win.win());
355 mln_invariant(dp.nelements() == n_ws);
359 if (o.border() != f.border())
363 mln_ch_value(I, D) dmap;
371 for (
unsigned i = 0; i < w_win.size(); ++i)
377 typedef std::vector<unsigned> bucket_t;
378 std::vector<bucket_t> bucket(mod);
379 unsigned bucket_size = 0;
387 mln_pixter(
const I) p(f);
388 mln_nixter(const I, N) n(p, nbh);
392 dmap.element(p.offset()) = 0;
394 if (n.val() == false)
396 bucket[0].push_back(p.offset());
407 for (
unsigned d = 0; bucket_size != 0; ++d)
409 bucket_t& bucket_d = bucket[d % mod];
410 for (
unsigned i = 0; i < bucket_d.size(); ++i)
414 if (dmap.element(p) ==
max)
417 bucket_size = bucket_d.size();
421 if (dmap.element(p) < d)
425 for (
unsigned i = 0; i < n_ws; ++i)
427 unsigned q = p + dp[i];
428 if (dmap.element(q) > d)
430 unsigned d_ = d + w_win.w(i);
431 if (d_ < dmap.element(q) && g.element(q) ==
true)
434 dmap.element(q) = d_;
435 bucket[d_ % mod].push_back(q);
441 bucket_size -= bucket_d.size();
450 template <
typename I,
typename J>
453 rd3_fast(const I& f, const J& g,
unsigned length,
unsigned delta)
456 unsigned ws[] = { mean, length, mean,
458 mean, length, mean };
460 unsigned max = length * delta + 1;
471 template <typename I>
474 unsigned length,
unsigned delta,
475 float p_few,
float p_enough,
478 mln_trace(
"scribo::primitive::extract::lines_h_thick_and_thin");
480 mlc_is(mln_value(I),
bool)::check();
482 const I& binary_image =
exact(binary_image_);
483 mln_precondition(binary_image.is_valid());
490 tags = internal::tag_it(binary_image, length, delta, p_few, p_enough);
491 mln_concrete(I) mask = internal::detect_thick(tags);
492 internal::add_thin(tags, mask);
495 debug::
logger().log_image(debug::AuxiliaryResults,
496 mask, "lines_h_thick_and_thin_mask");
498 image2d<
bool> output = internal::rd3_fast(mask, binary_image,
499 2 * length, 2 * delta);
501 debug::
logger().log_image(debug::AuxiliaryResults,
502 output, "lines_h_thick_and_thin_output_before_filter");
505 typedef scribo::def::lbl_type V;
508 mln::util::array<
box2d>
512 initialize(debug, binary_image);
514 for_all_ncomponents(e, nlabels)
516 if (
bbox(e).width() < length ||
520 | (
pw::value(lbl) == pw::cst(e))).rw(),
false);
524 output,
"lines_h_thick_and_thin_output");
530 # endif // ! MLN_INCLUDE_ONLY
538 #endif // ! SCRIBO_PRIMITIVE_EXTRACT_LINES_H_THICK_AND_THIN_HH