$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
paragraphs_closing.hh
1 // Copyright (C) 2009, 2010, 2011, 2013 EPITA Research and Development
2 // Laboratory (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_TEXT_PARAGRAPHS_CLOSING_HH
28 # define SCRIBO_TEXT_PARAGRAPHS_CLOSING_HH
29 
33 
34 # include <mln/draw/line.hh>
35 
36 # include <scribo/core/paragraph_set.hh>
37 # include <scribo/draw/line_components.hh>
38 # include <scribo/debug/logger.hh>
39 
40 namespace scribo
41 {
42 
43  namespace text
44  {
45 
46  using namespace mln;
47 
48  template< typename L>
49  mln_concrete(L)
50  paragraphs_closing(const paragraph_set<L>& parset);
51 
52 
53 # ifndef MLN_INCLUDE_ONLY
54 
55  namespace internal
56  {
57 
58  template<typename L>
59  inline
60  void horizontal_CRLA(const Image<L>& input_,
61  Image<L>& output_,
62  const mln::util::array<int>& deltas)
63  {
64  const L& input = exact(input_);
65  L& output = exact(output_);
66  mln_precondition(input.is_valid());
67  mln_precondition(output.is_valid());
68 
69  mln_piter(L) p(input.domain());
70  int count = 0;
71  unsigned nrows = input.nrows();
72  unsigned ncols = input.ncols();
73  mln_value(L) last_pixel_value = 0;
74 
75  for (unsigned i = 0; i < nrows; ++i)
76  {
77  for (unsigned j = 0; j < ncols; ++j)
78  {
79  const mln_value(L)& current_pixel = input.at_(i, j);
80 
81  if (!current_pixel)
82  {
83  if (last_pixel_value)
84  {
85  unsigned k = j + 1;
86  for ( ; !(input.at_(i, k)) && (k < ncols); ++k)
87  continue;
88 
89  count = k - j;
90  const int threshold = deltas(last_pixel_value);
91 
92  if (last_pixel_value == input.at_(i, k) && count < threshold)
93  for (unsigned l = j; l <= k; ++l)
94  output.at_(i, l) = last_pixel_value;
95 
96  j = k;
97  last_pixel_value = 0;
98  }
99  }
100  else
101  {
102  output.at_(i, j) = current_pixel;
103  last_pixel_value = current_pixel;
104  }
105  }
106  }
107  }
108 
109  template<typename L>
110  inline
111  void vertical_CRLA(const Image<L>& input_,
112  Image<L>& output_,
113  const mln::util::array<int>& deltas)
114  {
115  const L& input = exact(input_);
116  L& output = exact(output_);
117  mln_precondition(input.is_valid());
118  mln_precondition(output.is_valid());
119 
120  mln_piter(L) p(input.domain());
121  int count = 0;
122  unsigned nrows = input.nrows();
123  unsigned ncols = input.ncols();
124  mln_value(L) last_pixel_value = 0;
125 
126  for (unsigned j = 0; j < ncols; ++j)
127  {
128  for (unsigned i = 0; i < nrows; ++i)
129  {
130  const mln_value(L)& current_pixel = input.at_(i, j);
131 
132  if (!current_pixel)
133  {
134  if (last_pixel_value)
135  {
136  unsigned k = i + 1;
137  for ( ; !(input.at_(k, j)) && (k < nrows); ++k)
138  continue;
139 
140  count = k - i;
141  const int threshold = deltas(last_pixel_value);
142 
143  if (last_pixel_value == input.at_(k, j)
144  && count < threshold)
145  for (unsigned l = i; l <= k; ++l)
146  output.at_(l, j) = last_pixel_value;
147 
148  i = k;
149  last_pixel_value = 0;
150  }
151  }
152  else
153  {
154  output.at_(i, j) = current_pixel;
155  last_pixel_value = current_pixel;
156  }
157  }
158  }
159  }
160 
161  template<typename L>
162  inline
163  void CRLA(const Image<L>& input,
164  Image<L>& output,
165  const mln::util::array<int>& deltas,
166  const mln::util::array<int>& deltas_factor)
167  {
168  horizontal_CRLA(input, output, deltas_factor);
169 
170  debug::logger().log_image(debug::AuxiliaryResults,
171  output,
172  "paragraph_closing_horizontal_CRLA");
173 
174 
175  vertical_CRLA(output, output, deltas);
176 
177  debug::logger().log_image(debug::AuxiliaryResults,
178  output,
179  "paragraph_closing_vertical_CRLA");
180 
181  horizontal_CRLA(output, output, deltas_factor);
182  }
183 
184  } // end of namespace scribo::text::internal
185 
186 
187  template<typename L>
188  mln_concrete(L)
189  paragraphs_closing(const paragraph_set<L>& parset)
190  {
191  mln_trace("scribo::text::paragraphs_closing");
192 
193  // FIXME: 'debug' may be useless.
194  mln_concrete(L) output, debug;
195  initialize(output, parset.lines().components().labeled_image());
196  initialize(debug, output);
197 
198  mln::util::array<int> deltas(parset.nelements() + 1, 0);
199  mln::util::array<int> deltas_factor(parset.nelements() + 1, 0);
200 
201  data::fill(debug, 0);
202  data::fill(output, 0);
203 
204  const line_set<L>& lines = parset.lines();
205 
206  for_all_paragraphs(p, parset)
207  if (parset(p).is_valid())
208  {
209  const paragraph_info<L>& current_par = parset(p);
210  const mln::util::array<line_id_t>& line_ids = current_par.line_ids();
211 
212  for_all_elements(i, line_ids)
213  {
214  const line_id_t& line_id = line_ids(i);
215  const line_info<L>& current_line = lines(line_id);
216 
217  scribo::draw::line_components(debug, lines, current_line, p);
218 
219  // HACK DISCLAIMER : this line is drawn in order to be
220  // sure that every line will be reduced to a single
221  // component after closing. It is necessary to reduce a
222  // paragraph to one component in order to extract its
223  // outline correctly for xml/debug output.
224  component_id_t last_comp = lines(line_id).component_ids()(0);
225  for_all_elements(i, lines(line_id).component_ids())
226  {
227  const unsigned c = lines(line_id).component_ids()(i);
228  mln::draw::line(debug,
229  lines.components()(c).mass_center(),
230  lines.components()(last_comp).mass_center(),
231  p);
232  last_comp = c;
233  }
234 
235  }
236 
237  int delta_baseline = current_par.delta_baseline();
238 
239  if (delta_baseline % 2 == 0)
240  --delta_baseline;
241 
242  deltas(p) = 2 * delta_baseline; // Vertical
243  deltas_factor(p) = 3 * delta_baseline; // Horizontal
244  }
245 
246  debug::logger().log_image(debug::AuxiliaryResults,
247  debug,
248  "paragraph_closing_input_CRLA");
249 
250  internal::CRLA(debug, output, deltas, deltas_factor);
251 
252  debug::logger().log_image(debug::Results,
253  output,
254  "paragraph_closing");
255 
256  return output;
257  }
258 
259 # endif
260 
261  } // end of namespace scribo::text
262 
263 } // end of namespace scribo
264 
265 
266 #endif // ! SCRIBO_TEXT_PARAGRAPHS_CLOSING_HH
267