$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
content_in_doc_functor.hh
1 // Copyright (C) 2010, 2011 EPITA Research and Development Laboratory
2 // (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef SCRIBO_TOOLCHAIN_INTERNAL_CONTENT_IN_DOC_FUNCTOR_HH
28 # define SCRIBO_TOOLCHAIN_INTERNAL_CONTENT_IN_DOC_FUNCTOR_HH
29 
33 
34 # ifndef SCRIBO_NDEBUG
35 # include <mln/util/timer.hh>
36 # endif // ! SCRIBO_NDEBUG
37 
38 # include <scribo/core/def/lbl_type.hh>
39 # include <scribo/core/document.hh>
40 # include <scribo/core/line_set.hh>
41 # include <scribo/core/paragraph_set.hh>
42 
43 # include <scribo/primitive/extract/non_text.hh>
44 # include <scribo/primitive/extract/components.hh>
45 # include <scribo/primitive/extract/separators.hh>
46 # include <scribo/primitive/extract/vertical_separators.hh>
47 # include <scribo/primitive/extract/horizontal_separators.hh>
48 
49 # include <scribo/primitive/extract/alignments.hh>
50 
51 # include <scribo/primitive/identify.hh>
52 
53 # include <scribo/primitive/remove/separators.hh>
54 
55 # include <scribo/filter/line_links_x_height.hh>
56 # include <scribo/filter/object_links_bbox_h_ratio.hh>
57 # include <scribo/filter/objects_small.hh>
58 
59 # include <scribo/primitive/group/from_single_link.hh>
60 
61 # include <scribo/primitive/link/merge_double_link.hh>
62 # include <scribo/primitive/link/internal/dmax_width_and_height.hh>
63 # include <scribo/primitive/link/with_single_left_link_dmax_ratio.hh>
64 # include <scribo/primitive/link/with_single_right_link_dmax_ratio.hh>
65 
66 # include <scribo/preprocessing/denoise_fg.hh>
67 
68 # ifndef SCRIBO_NOCR
69 # include <scribo/text/recognition.hh>
70 # endif // ! SCRIBO_NOCR
71 
72 # include <scribo/text/merging.hh>
73 # include <scribo/text/link_lines.hh>
74 # include <scribo/text/extract_paragraphs.hh>
75 
76 # include <scribo/make/debug_filename.hh>
77 
78 # include <scribo/debug/decision_image.hh>
79 # include <scribo/debug/bboxes_image.hh>
80 # include <scribo/debug/linked_bboxes_image.hh>
81 # include <scribo/debug/bboxes_enlarged_image.hh>
82 # include <scribo/debug/mean_and_base_lines_image.hh>
83 # include <scribo/debug/looks_like_a_text_line_image.hh>
84 
85 # include <scribo/toolchain/internal/toolchain_functor.hh>
86 
87 # include <scribo/io/xml/save.hh>
88 
89 
90 namespace scribo
91 {
92 
93  namespace toolchain
94  {
95 
96  namespace internal
97  {
98 
102  template <typename I>
104  : public Toolchain_Functor
105  {
106  typedef scribo::def::lbl_type V;
107  typedef mln_ch_value(I,V) L;
108 
109  content_in_doc_functor(const char *doc_filename);
110 
111  virtual int nsteps() const;
112 
113  virtual void on_xml_saved();
114 
115  //===============
116  // Core function
117  //===============
118 
119  template <typename J>
120  scribo::document<L> operator()(const Image<J>& original_image,
121  const Image<I>& processed_image);
122 
123 
124  //=========
125  // Options
126  //=========
127  bool enable_denoising;
128  bool enable_line_seps;
129  bool enable_whitespace_seps;
130  bool enable_ocr;
131  bool save_doc_as_xml;
132  scribo::io::xml::Format xml_format;
133 
134  //============
135  // Parameters
136  //============
137 
138  std::string ocr_language;
139  std::string output_file;
140 
141  //=========
142  // Results
143  //=========
144  document<L> doc;
145 
146 # ifndef SCRIBO_NDEBUG
147  //=============
148  // DEBUG TOOLS
149  //=============
150  virtual void on_start();
151  virtual void on_end();
152  virtual void on_progress();
153 
155  mln::util::timer gt;
156 # endif // ! SCRIBO_NDEBUG
157 
158  };
159 
160 
161 # ifndef MLN_INCLUDE_ONLY
162 
163  template <typename I>
164  content_in_doc_functor<I>::content_in_doc_functor(const char *doc_filename)
165  : enable_denoising(true),
166  enable_line_seps(true),
167  enable_whitespace_seps(true),
168  enable_ocr(true),
169  save_doc_as_xml(false),
170  xml_format(scribo::io::xml::PageExtended),
171  ocr_language("eng"),
172  output_file("/tmp/foo.xml"),
173  doc(doc_filename)
174  {
175  }
176 
177 
178  //===============
179  // Core function
180  //===============
181 
182  template <typename I>
183  template <typename J>
185  content_in_doc_functor<I>::operator()(const Image<J>& original_image,
186  const Image<I>& processed_image)
187  {
188  mln_precondition(exact(original_image).is_valid());
189  mln_precondition(exact(processed_image).is_valid());
190 
191  on_start();
192 
193  doc.set_image(exact(original_image));
194  doc.set_binary_image(exact(processed_image));
195 
196  // Remove separators
197  mln_ch_value(I,bool)
198  separators,
199  input_cleaned = exact(processed_image);
200  if (enable_line_seps)
201  {
202  // FIXME: SLOW
203  on_new_progress_label("Find vertical and horizontal separators...");
204 
205  // Vertical and horizontal separators
206  {
207  mln_ch_value(I,bool)
208  vseparators = primitive::extract::vertical_separators(processed_image, 81),
209  hseparators = primitive::extract::horizontal_separators(processed_image, 81);
210 
211  doc.set_vline_separators(vseparators);
212  doc.set_hline_separators(hseparators);
213 
214  separators = vseparators;
215  separators += hseparators;
216 
217  border::resize(processed_image, border::thickness);
218  }
219 
220  on_progress();
221 
222  on_new_progress_label("Remove separators...");
223 
224  input_cleaned = primitive::remove::separators(processed_image,
225  separators);
226 
227  on_progress();
228  }
229 
230 
231 # ifndef SCRIBO_NDEBUG
232  // Debug
233  if (enable_line_seps)
234  {
235  debug::logger().log_image(debug::AuxiliaryResults,
236  doc.vline_seps(),
237  "vseparators");
238 
239  debug::logger().log_image(debug::AuxiliaryResults,
240  doc.hline_seps(),
241  "hseparators");
242 
243  debug::logger().log_image(debug::AuxiliaryResults,
244  input_cleaned,
245  "input_wo_separators");
246  }
247 # endif // ! SCRIBO_NDEBUG
248 
249 
250  // Denoise
251  if (enable_denoising)
252  {
253  on_new_progress_label("Denoise...");
254 
255  input_cleaned = preprocessing::denoise_fg(input_cleaned, c8(), 3);
256 
257  // Debug
258 # ifndef SCRIBO_NDEBUG
259  debug::logger().log_image(debug::AuxiliaryResults,
260  input_cleaned, "denoised");
261 # endif // ! SCRIBO_NDEBUG
262 
263  on_progress();
264  }
265 
267  on_new_progress_label("Finding components...");
268 
269  V ncomponents;
270  component_set<L>
272  input_cleaned,
273  c8(),
274  ncomponents);
275 
276  on_progress();
277 
279  if (enable_line_seps)
280  components.add_separators(separators);
281 
282  on_new_progress_label("Filtering components");
283 
284  components = scribo::filter::components_small(components, 3);
285 
286  on_progress();
287 
288 
290  on_new_progress_label("Linking objects...");
291 
292  object_links<L> left_link
294  components,
295  primitive::link::internal::dmax_default(1),
296  anchor::MassCenter);
297 
298 
299  object_links<L> right_link
301  components,
302  primitive::link::internal::dmax_default(1),
303  anchor::MassCenter);
304 
305  // Debug
306 # ifndef SCRIBO_NDEBUG
307  if (debug::logger().is_enabled())
308  {
310  debug::AuxiliaryResults,
311  debug::linked_bboxes_image(processed_image,
312  left_link,
313  right_link,
314  literal::blue,
315  literal::cyan,
316  literal::yellow,
317  literal::green,
318  anchor::MassCenter),
319  "object_links");
320  }
321 # endif // ! SCRIBO_NDEBUG
322 
323  // Validating left and right links.
324  object_links<L>
325  merged_links = primitive::link::merge_double_link(left_link,
326  right_link);
327 
328  on_progress();
329 
330 
331  on_new_progress_label("Filtering objects");
332 
333  // Remove links if bboxes have too different sizes.
334  object_links<L> hratio_filtered_links
335  = filter::object_links_bbox_h_ratio(merged_links, 2.5f);
336 
337 
338 # ifndef SCRIBO_NDEBUG
339  if (debug::logger().is_enabled())
340  {
341  mln_ch_value(I,value::rgb8)
342  hratio_decision_image = scribo::debug::decision_image(processed_image,
343  merged_links,
344  hratio_filtered_links,
345  anchor::MassCenter);
346  // Debug
347  debug::logger().log_image(debug::AuxiliaryResults,
348  hratio_decision_image,
349  "hratio_links_decision_image");
350  }
351 # endif // ! SCRIBO_NDEBUG
352 
353  on_progress();
354 
355 
356  on_new_progress_label("Rebuilding lines");
357 
358  object_groups<L>
359  groups = primitive::group::from_single_link(hratio_filtered_links);
360 
361 
362 
363  // Construct a line set.
364  line_set<L>
365  lines = scribo::make::line_set(groups);
366 
367 
368  // Extract whitespace to improve text merging results afterwards.
369  mln_ch_value(L,bool) whitespaces;
370  if (enable_whitespace_seps)
371  {
373  doc.set_paragraphs(parset);
374 
375  // Whitespace separators
376  on_new_progress_label("Find whitespace separators...");
377 
379  res = primitive::extract::alignments(doc, 3, 3);
380  whitespaces = res.second();
381 
382  on_progress();
383 
384  components.add_separators(res.second());
385  doc.set_whitespace_separators(res.second(), res.first());
386  }
387 
388 
389  //===== DEBUG =====
390 # ifndef SCRIBO_NDEBUG
391  debug::logger().log_image(debug::AuxiliaryResults,
392  components.separators(),
393  "all_separators");
394 
395  if (debug::logger().is_enabled())
396  {
397  if (enable_whitespace_seps)
398  debug::logger().log_image(debug::AuxiliaryResults,
399  whitespaces, "whitespaces");
400 
401  // Bboxes image.
403  debug::AuxiliaryResults,
404  scribo::debug::bboxes_image(processed_image, lines),
405  "step1_bboxes");
406 
407  // Bboxes enlarged
409  debug::AuxiliaryResults,
410  scribo::debug::bboxes_enlarged_image(processed_image, lines),
411  "step1_bboxes_enlarged");
412 
413  // Looks like a text line
415  debug::AuxiliaryResults,
416  scribo::debug::looks_like_a_text_line_image(processed_image, lines),
417  "step1_looks_like_a_text_line");
418 
419  // mean and base lines.
421  debug::AuxiliaryResults,
422  scribo::debug::mean_and_base_lines_image(processed_image, lines),
423  "step1_x_height");
424  }
425 # endif // ! SCRIBO_NDEBUG
426  //===== END OF DEBUG =====
427 
428 
429 
430  lines = scribo::text::merging(lines);
431 
432 
433  //===== DEBUG =====
434 # ifndef SCRIBO_NDEBUG
435  if (debug::logger().is_enabled())
436  {
437 
438  // mean and base lines.
440  debug::AuxiliaryResults,
441  scribo::debug::mean_and_base_lines_image(processed_image, lines),
442  "step2_x_height");
443 
444  // Looks like a text line
446  debug::AuxiliaryResults,
447  scribo::debug::looks_like_a_text_line_image(processed_image, lines),
448  "step2_looks_like_a_text_line");
449 
450  // Bboxes image.
452  debug::AuxiliaryResults,
453  scribo::debug::bboxes_image(processed_image, lines),
454  "step2_bboxes");
455  }
456 # endif // ! SCRIBO_NDEBUG
457  //===== END OF DEBUG =====
458 
459  on_progress();
460 
461 
462 # ifndef SCRIBO_NOCR
463  // Text recognition
464  if (enable_ocr)
465  {
466  on_new_progress_label("Recognizing text");
467 
468  scribo::text::recognition(lines, ocr_language.c_str());
469 
470  on_progress();
471  }
472 # endif // ! SCRIBO_NOCR
473 
475  parset = text::extract_paragraphs(lines, doc.binary_image());
476  doc.set_paragraphs(parset);
477 
478  on_progress();
479 
480 
481  // Extract other Elements
482  on_new_progress_label("Extracting Elements");
483  component_set<L>
484  elements = scribo::primitive::extract::non_text(doc, 3);
485 
486  on_progress();
487 
488 
489  // Identify other Elements
490  on_new_progress_label("Identifying Elements");
491  elements = scribo::primitive::identify(elements);
492  doc.set_elements(elements);
493 
494  on_progress();
495 
496 
497 
498  // Saving results
499  if (save_doc_as_xml)
500  {
501  on_new_progress_label("Saving results");
502 
503  scribo::io::xml::save(doc, output_file, xml_format);
504  on_xml_saved();
505 
506  on_progress();
507  }
508 
509  on_end();
510 
511  return doc;
512  }
513 
514 
515 
516  template<typename I>
517  int
518  content_in_doc_functor<I>::nsteps() const
519  {
520  return 10 + enable_denoising + enable_line_seps
521  + enable_whitespace_seps + enable_ocr + save_doc_as_xml;
522  }
523 
524 
525  template<typename I>
526  void
527  content_in_doc_functor<I>::on_xml_saved()
528  {
529  // Nothing
530  }
531 
532 # ifndef SCRIBO_NDEBUG
533 
534  template <typename I>
535  void
536  content_in_doc_functor<I>::on_start()
537  {
538  gt.start();
539  t.start();
540  }
541 
542  template <typename I>
543  void
544  content_in_doc_functor<I>::on_end()
545  {
546  gt.stop();
547  if (verbose)
548  std::cout << "Total time: " << gt << std::endl;
549  }
550 
551  template <typename I>
552  void
553  content_in_doc_functor<I>::on_progress()
554  {
555  t.stop();
556  if (verbose)
557  std::cout << t << std::endl;
558  t.restart();
559  }
560 
561 
562 # endif // ! SCRIBO_NDEBUG
563 
564 # endif // ! MLN_INCLUDE_ONLY
565 
566  } // end of namespace scribo::toolchain::internal
567 
568  } // end of namespace scribo::toolchain
569 
570 } // end of namespace scribo
571 
572 #endif // ! SCRIBO_TOOLCHAIN_INTERNAL_CONTENT_IN_DOC_FUNCTOR_HH