30 #ifndef SCRIBO_LAYOUT_XY_CUT_HH
31 # define SCRIBO_LAYOUT_XY_CUT_HH
33 # include <mln/geom/min_row.hh>
34 # include <mln/geom/min_col.hh>
35 # include <mln/geom/max_row.hh>
36 # include <mln/geom/max_col.hh>
37 # include <mln/core/concept/image.hh>
38 # include <mln/core/macros.hh>
39 # include <mln/util/array.hh>
40 # include <scribo/layout/internal/hist_info.hh>
41 # include <scribo/layout/internal/node.hh>
72 # ifndef MLN_INCLUDE_ONLY
83 void compute_hist_info_h(
const Image<I>& input_,
86 mln_trace(
"compute_hist_info_h");
88 const I& input =
exact(input_);
90 mln_precondition(input.is_valid());
91 mln_precondition(hist.is_valid());
93 unsigned accumulator = 0;
103 hist.at_(i, j).horizontal = accumulator;
114 template <
typename I>
115 void compute_hist_info_v(
const Image<I>& input_,
118 mln_trace(
"compute_hist_info_v");
120 const I& input =
exact(input_);
122 mln_precondition(input.is_valid());
123 mln_precondition(hist.is_valid());
125 unsigned accumulator = 0;
135 hist.at_(i, j).vertical = accumulator;
143 template <
typename H>
144 void horizontal_whitespace(
const Image<H>& hist_,
145 const mln_site(H)& pmin,
146 const mln_site(H)& pmax,
151 mln_trace(
"horizontal_whitespace");
153 typedef mln_value(H) V;
154 mlc_is(V,internal::hist_info)::check();
156 const H& hist = exact(hist_);
158 mln_precondition(hist.is_valid());
160 const
int x_min = pmin.col();
161 const
int x_max = pmax.col();
162 const
int y_min = pmin.row();
163 const
int y_max = pmax.row();
165 for (
int y = y_min; y <= y_max; ++y)
167 const int n_white_pixels = hist.at_(y, x_max).horizontal -
168 hist.at_(y, x_min).horizontal;
175 for (; r <= y_max && !(hist.at_(r, x_max).horizontal -
176 hist.at_(r, x_min).horizontal); ++r);
178 const int count = r - y;
180 if (count > max_height)
183 ws_min_row = (y == y_min) ? y_min : y - 1;
194 template <
typename H>
195 void vertical_whitespace(
const Image<H>& hist_,
196 const mln_site(H)& pmin,
197 const mln_site(H)& pmax,
202 mln_trace(
"vertical_whitespace");
204 typedef mln_value(H) V;
205 mlc_is(V,internal::hist_info)::check();
207 const H& hist = exact(hist_);
209 mln_precondition(hist.is_valid());
211 const
int x_min = pmin.col();
212 const
int x_max = pmax.col();
213 const
int y_min = pmin.row();
214 const
int y_max = pmax.row();
216 for (
int x = x_min; x <= x_max; ++x)
218 const int n_white_pixels = hist.at_(y_max, x).vertical -
219 hist.at_(y_min, x).vertical;
226 for (; c <= x_max && !(hist.at_(y_max, c).vertical -
227 hist.at_(y_min, c).vertical); ++c);
229 const int count = c - x;
231 if (count > max_width)
234 ws_min_col = (x == x_min) ? x_min : x - 1;
245 template <
typename H>
246 void do_xy_cut(
const Image<H>& hist_,
247 node<mln_box(H)>* root,
248 const mln_box(H)& domain,
249 const bool horizontal,
250 const bool should_stop,
251 const int min_height,
254 mln_trace(
"do_xy_cut");
256 typedef mln_value(H) V;
257 mlc_is(V,internal::hist_info)::check();
259 const H& hist = exact(hist_);
261 mln_precondition(hist.is_valid());
262 mln_precondition(root != 0);
263 mln_precondition(domain.is_valid());
265 const mln_site(H)& pmin = domain.pmin();
266 const mln_site(H)& pmax = domain.pmax();
267 const
int x_min = pmin.col();
268 const
int x_max = pmax.col();
269 const
int y_min = pmin.row();
270 const
int y_max = pmax.row();
278 horizontal_whitespace(hist, pmin, pmax, max_height, ws_min_row, ws_max_row);
280 if (max_height < min_height || max_height == (pmax.row() - pmin.row()))
285 do_xy_cut(hist, root, domain,
false,
true, min_height, min_width);
289 typedef mln_box(H) B;
290 node<B>* ls = (ws_min_row == y_min) ? 0 :
291 new node<B>(
box2d(pmin,
point2d(ws_min_row, pmax.col())));
292 node<B>* rs = (ws_max_row >= y_max) ? 0 :
293 new node<B>(
box2d(
point2d(ws_max_row, pmin.col()), pmax));
299 do_xy_cut(hist, ls, ls->get_bbox(), false, false, min_height, min_width);
301 do_xy_cut(hist, rs, rs->get_bbox(), false, false, min_height, min_width);
310 vertical_whitespace(hist, pmin, pmax, max_width, ws_min_col, ws_max_col);
312 if (max_width < min_width || max_width == (pmax.col() - pmin.col()))
317 do_xy_cut(hist, root, domain,
true,
true, min_height, min_width);
321 typedef mln_box(H) B;
322 node<B>* ls = (ws_min_col == x_min) ? 0 :
323 new node<B>(
box2d(pmin,
point2d(pmax.row(), ws_min_col)));
324 node<B>* rs = (ws_max_col >= x_max) ? 0 :
325 new node<B>(
box2d(
point2d(pmin.row(), ws_max_col), pmax));
331 do_xy_cut(hist, ls, ls->get_bbox(), true, false, min_height, min_width);
333 do_xy_cut(hist, rs, rs->get_bbox(), true, false, min_height, min_width);
340 template <typename B>
341 void xy_dfs(const node<B>* root, util::array<B>& result)
345 result.append(root->get_bbox());
349 const node<B>* ls = root->get_ls();
350 const node<B>* rs = root->get_rs();
353 xy_dfs(root->get_ls(), result);
355 xy_dfs(root->get_rs(), result);
362 template <
typename I>
366 mln_trace(
"scribo::layout::xy_cut");
368 typedef mln_value(I) V;
369 typedef mln_box(I) B;
370 mlc_is(V,
bool)::check();
372 const I& ima = exact(ima_);
373 mln_precondition(ima.is_valid());
376 mln_ch_value(I,internal::hist_info) hist(ima.domain());
377 internal::compute_hist_info_h(ima, hist);
378 internal::compute_hist_info_v(ima, hist);
381 internal::node<B>* n = new internal::node<B>(ima.domain());
382 internal::do_xy_cut(hist, n, ima.domain(), true, false, min_height, min_width);
385 mln::util::array<B> output;
386 internal::xy_dfs(n, output);
395 # endif // ! MLN_INCLUDE_ONLY
401 #endif // ! SCRIBO_LAYOUT_XY_CUT_HH