tesseract  4.0.0-1-g2a2b
ltrresultiterator.cpp
Go to the documentation of this file.
1 // File: ltrresultiterator.cpp
3 // Description: Iterator for tesseract results in strict left-to-right
4 // order that avoids using tesseract internal data structures.
5 // Author: Ray Smith
6 // Created: Fri Feb 26 14:32:09 PST 2010
7 //
8 // (C) Copyright 2010, Google Inc.
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
20 
21 #include "ltrresultiterator.h"
22 
23 #include "allheaders.h"
24 #include "pageres.h"
25 #include "strngs.h"
26 #include "tesseractclass.h"
27 
28 namespace tesseract {
29 
31  int scale, int scaled_yres,
32  int rect_left, int rect_top,
33  int rect_width, int rect_height)
34  : PageIterator(page_res, tesseract, scale, scaled_yres,
35  rect_left, rect_top, rect_width, rect_height),
36  line_separator_("\n"),
37  paragraph_separator_("\n") {
38 }
39 
40 // Destructor.
41 // It is defined here, so the compiler can create a single vtable
42 // instead of weak vtables in every compilation unit.
44 
45 // Returns the null terminated UTF-8 encoded text string for the current
46 // object at the given level. Use delete [] to free after use.
48  if (it_->word() == nullptr) return nullptr; // Already at the end!
49  STRING text;
50  PAGE_RES_IT res_it(*it_);
51  WERD_CHOICE* best_choice = res_it.word()->best_choice;
52  ASSERT_HOST(best_choice != nullptr);
53  if (level == RIL_SYMBOL) {
54  text = res_it.word()->BestUTF8(blob_index_, false);
55  } else if (level == RIL_WORD) {
56  text = best_choice->unichar_string();
57  } else {
58  bool eol = false; // end of line?
59  bool eop = false; // end of paragraph?
60  do { // for each paragraph in a block
61  do { // for each text line in a paragraph
62  do { // for each word in a text line
63  best_choice = res_it.word()->best_choice;
64  ASSERT_HOST(best_choice != nullptr);
65  text += best_choice->unichar_string();
66  text += " ";
67  res_it.forward();
68  eol = res_it.row() != res_it.prev_row();
69  } while (!eol);
70  text.truncate_at(text.length() - 1);
71  text += line_separator_;
72  eop = res_it.block() != res_it.prev_block() ||
73  res_it.row()->row->para() != res_it.prev_row()->row->para();
74  } while (level != RIL_TEXTLINE && !eop);
75  if (eop) text += paragraph_separator_;
76  } while (level == RIL_BLOCK && res_it.block() == res_it.prev_block());
77  }
78  int length = text.length() + 1;
79  char* result = new char[length];
80  strncpy(result, text.string(), length);
81  return result;
82 }
83 
84 // Set the string inserted at the end of each text line. "\n" by default.
85 void LTRResultIterator::SetLineSeparator(const char *new_line) {
86  line_separator_ = new_line;
87 }
88 
89 // Set the string inserted at the end of each paragraph. "\n" by default.
90 void LTRResultIterator::SetParagraphSeparator(const char *new_para) {
91  paragraph_separator_ = new_para;
92 }
93 
94 // Returns the mean confidence of the current object at the given level.
95 // The number should be interpreted as a percent probability. (0.0f-100.0f)
97  if (it_->word() == nullptr) return 0.0f; // Already at the end!
98  float mean_certainty = 0.0f;
99  int certainty_count = 0;
100  PAGE_RES_IT res_it(*it_);
101  WERD_CHOICE* best_choice = res_it.word()->best_choice;
102  ASSERT_HOST(best_choice != nullptr);
103  switch (level) {
104  case RIL_BLOCK:
105  do {
106  best_choice = res_it.word()->best_choice;
107  ASSERT_HOST(best_choice != nullptr);
108  mean_certainty += best_choice->certainty();
109  ++certainty_count;
110  res_it.forward();
111  } while (res_it.block() == res_it.prev_block());
112  break;
113  case RIL_PARA:
114  do {
115  best_choice = res_it.word()->best_choice;
116  ASSERT_HOST(best_choice != nullptr);
117  mean_certainty += best_choice->certainty();
118  ++certainty_count;
119  res_it.forward();
120  } while (res_it.block() == res_it.prev_block() &&
121  res_it.row()->row->para() == res_it.prev_row()->row->para());
122  break;
123  case RIL_TEXTLINE:
124  do {
125  best_choice = res_it.word()->best_choice;
126  ASSERT_HOST(best_choice != nullptr);
127  mean_certainty += best_choice->certainty();
128  ++certainty_count;
129  res_it.forward();
130  } while (res_it.row() == res_it.prev_row());
131  break;
132  case RIL_WORD:
133  mean_certainty += best_choice->certainty();
134  ++certainty_count;
135  break;
136  case RIL_SYMBOL:
137  mean_certainty += best_choice->certainty(blob_index_);
138  ++certainty_count;
139  }
140  if (certainty_count > 0) {
141  mean_certainty /= certainty_count;
142  float confidence = 100 + 5 * mean_certainty;
143  if (confidence < 0.0f) confidence = 0.0f;
144  if (confidence > 100.0f) confidence = 100.0f;
145  return confidence;
146  }
147  return 0.0f;
148 }
149 
150 void LTRResultIterator::RowAttributes(float* row_height, float* descenders,
151  float* ascenders) const {
152  *row_height = it_->row()->row->x_height() + it_->row()->row->ascenders() -
153  it_->row()->row->descenders();
154  *descenders = it_->row()->row->descenders();
155  *ascenders = it_->row()->row->ascenders();
156 }
157 
158 // Returns the font attributes of the current word. If iterating at a higher
159 // level object than words, eg textlines, then this will return the
160 // attributes of the first word in that textline.
161 // The actual return value is a string representing a font name. It points
162 // to an internal table and SHOULD NOT BE DELETED. Lifespan is the same as
163 // the iterator itself, ie rendered invalid by various members of
164 // TessBaseAPI, including Init, SetImage, End or deleting the TessBaseAPI.
165 // Pointsize is returned in printers points (1/72 inch.)
166 const char* LTRResultIterator::WordFontAttributes(bool* is_bold,
167  bool* is_italic,
168  bool* is_underlined,
169  bool* is_monospace,
170  bool* is_serif,
171  bool* is_smallcaps,
172  int* pointsize,
173  int* font_id) const {
174  if (it_->word() == nullptr) return nullptr; // Already at the end!
175  float row_height = it_->row()->row->x_height() +
176  it_->row()->row->ascenders() - it_->row()->row->descenders();
177  // Convert from pixels to printers points.
178  *pointsize = scaled_yres_ > 0
179  ? static_cast<int>(row_height * kPointsPerInch / scaled_yres_ + 0.5)
180  : 0;
181  if (it_->word()->fontinfo == nullptr) {
182  *font_id = -1;
183  return nullptr; // No font information.
184  }
185  const FontInfo& font_info = *it_->word()->fontinfo;
186  *font_id = font_info.universal_id;
187  *is_bold = font_info.is_bold();
188  *is_italic = font_info.is_italic();
189  *is_underlined = false; // TODO(rays) fix this!
190  *is_monospace = font_info.is_fixed_pitch();
191  *is_serif = font_info.is_serif();
192  *is_smallcaps = it_->word()->small_caps;
193 
194  return font_info.name;
195 }
196 
197 // Returns the name of the language used to recognize this word.
199  if (it_->word() == nullptr || it_->word()->tesseract == nullptr) return nullptr;
200  return it_->word()->tesseract->lang.string();
201 }
202 
203 // Return the overall directionality of this word.
205  if (it_->word() == nullptr) return DIR_NEUTRAL;
206  bool has_rtl = it_->word()->AnyRtlCharsInWord();
207  bool has_ltr = it_->word()->AnyLtrCharsInWord();
208  if (has_rtl && !has_ltr)
209  return DIR_RIGHT_TO_LEFT;
210  if (has_ltr && !has_rtl)
211  return DIR_LEFT_TO_RIGHT;
212  if (!has_ltr && !has_rtl)
213  return DIR_NEUTRAL;
214  return DIR_MIX;
215 }
216 
217 // Returns true if the current word was found in a dictionary.
219  if (it_->word() == nullptr) return false; // Already at the end!
220  int permuter = it_->word()->best_choice->permuter();
221  return permuter == SYSTEM_DAWG_PERM || permuter == FREQ_DAWG_PERM ||
222  permuter == USER_DAWG_PERM;
223 }
224 
225 // Returns the number of blanks before the current word.
227  if (it_->word() == nullptr) return 1;
228  return it_->word()->word->space();
229 }
230 
231 // Returns true if the current word is numeric.
233  if (it_->word() == nullptr) return false; // Already at the end!
234  int permuter = it_->word()->best_choice->permuter();
235  return permuter == NUMBER_PERM;
236 }
237 
238 // Returns true if the word contains blamer information.
240  return it_->word() != nullptr && it_->word()->blamer_bundle != nullptr &&
242 }
243 
244 // Returns the pointer to ParamsTrainingBundle stored in the BlamerBundle
245 // of the current word.
247  return (it_->word() != nullptr && it_->word()->blamer_bundle != nullptr) ?
248  &(it_->word()->blamer_bundle->params_training_bundle()) : nullptr;
249 }
250 
251 // Returns the pointer to the string with blamer information for this word.
252 // Assumes that the word's blamer_bundle is not nullptr.
254  return it_->word()->blamer_bundle->debug().string();
255 }
256 
257 // Returns the pointer to the string with misadaption information for this word.
258 // Assumes that the word's blamer_bundle is not nullptr.
261 }
262 
263 // Returns true if a truth string was recorded for the current word.
265  if (it_->word() == nullptr) return false; // Already at the end!
266  if (it_->word()->blamer_bundle == nullptr ||
267  it_->word()->blamer_bundle->NoTruth()) {
268  return false; // no truth information for this word
269  }
270  return true;
271 }
272 
273 // Returns true if the given string is equivalent to the truth string for
274 // the current word.
275 bool LTRResultIterator::EquivalentToTruth(const char *str) const {
276  if (!HasTruthString()) return false;
277  ASSERT_HOST(it_->word()->uch_set != nullptr);
278  WERD_CHOICE str_wd(str, *(it_->word()->uch_set));
279  return it_->word()->blamer_bundle->ChoiceIsCorrect(&str_wd);
280 }
281 
282 // Returns the null terminated UTF-8 encoded truth string for the current word.
283 // Use delete [] to free after use.
285  if (!HasTruthString()) return nullptr;
286  STRING truth_text = it_->word()->blamer_bundle->TruthString();
287  int length = truth_text.length() + 1;
288  char* result = new char[length];
289  strncpy(result, truth_text.string(), length);
290  return result;
291 }
292 
293 // Returns the null terminated UTF-8 encoded normalized OCR string for the
294 // current word. Use delete [] to free after use.
296  if (it_->word() == nullptr) return nullptr; // Already at the end!
297  STRING ocr_text;
298  WERD_CHOICE* best_choice = it_->word()->best_choice;
299  const UNICHARSET *unicharset = it_->word()->uch_set;
300  ASSERT_HOST(best_choice != nullptr);
301  for (int i = 0; i < best_choice->length(); ++i) {
302  ocr_text += unicharset->get_normed_unichar(best_choice->unichar_id(i));
303  }
304  int length = ocr_text.length() + 1;
305  char* result = new char[length];
306  strncpy(result, ocr_text.string(), length);
307  return result;
308 }
309 
310 // Returns a pointer to serialized choice lattice.
311 // Fills lattice_size with the number of bytes in lattice data.
312 const char *LTRResultIterator::WordLattice(int *lattice_size) const {
313  if (it_->word() == nullptr) return nullptr; // Already at the end!
314  if (it_->word()->blamer_bundle == nullptr) return nullptr;
315  *lattice_size = it_->word()->blamer_bundle->lattice_size();
316  return it_->word()->blamer_bundle->lattice_data();
317 }
318 
319 // Returns true if the current symbol is a superscript.
320 // If iterating at a higher level object than symbols, eg words, then
321 // this will return the attributes of the first symbol in that word.
323  if (cblob_it_ == nullptr && it_->word() != nullptr)
326  return false;
327 }
328 
329 // Returns true if the current symbol is a subscript.
330 // If iterating at a higher level object than symbols, eg words, then
331 // this will return the attributes of the first symbol in that word.
333  if (cblob_it_ == nullptr && it_->word() != nullptr)
335  return false;
336 }
337 
338 // Returns true if the current symbol is a dropcap.
339 // If iterating at a higher level object than symbols, eg words, then
340 // this will return the attributes of the first symbol in that word.
342  if (cblob_it_ == nullptr && it_->word() != nullptr)
344  return false;
345 }
346 
348  ASSERT_HOST(result_it.it_->word() != nullptr);
349  word_res_ = result_it.it_->word();
350  BLOB_CHOICE_LIST* choices = nullptr;
351  if (word_res_->ratings != nullptr)
352  choices = word_res_->GetBlobChoices(result_it.blob_index_);
353  if (choices != nullptr && !choices->empty()) {
354  choice_it_ = new BLOB_CHOICE_IT(choices);
355  choice_it_->mark_cycle_pt();
356  } else {
357  choice_it_ = nullptr;
358  }
359 }
360 
362  delete choice_it_;
363 }
364 
365 // Moves to the next choice for the symbol and returns false if there
366 // are none left.
368  if (choice_it_ == nullptr)
369  return false;
370  choice_it_->forward();
371  return !choice_it_->cycled_list();
372 }
373 
374 // Returns the null terminated UTF-8 encoded text string for the current
375 // choice. Do NOT use delete [] to free after use.
376 const char* ChoiceIterator::GetUTF8Text() const {
377  if (choice_it_ == nullptr)
378  return nullptr;
379  UNICHAR_ID id = choice_it_->data()->unichar_id();
380  return word_res_->uch_set->id_to_unichar_ext(id);
381 }
382 
383 // Returns the confidence of the current choice.
384 // The number should be interpreted as a percent probability. (0.0f-100.0f)
386  if (choice_it_ == nullptr)
387  return 0.0f;
388  float confidence = 100 + 5 * choice_it_->data()->certainty();
389  if (confidence < 0.0f) confidence = 0.0f;
390  if (confidence > 100.0f) confidence = 100.0f;
391  return confidence;
392 }
393 
394 
395 } // namespace tesseract.
BLOCK_RES * block() const
Definition: pageres.h:757
const STRING & debug() const
Definition: blamer.h:128
int UNICHAR_ID
Definition: unichar.h:35
const char * WordLattice(int *lattice_size) const
const char * GetBlamerMisadaptionDebug() const
ROW_RES * row() const
Definition: pageres.h:754
const char * get_normed_unichar(UNICHAR_ID unichar_id) const
Definition: unicharset.h:823
const char * lattice_data() const
Definition: blamer.h:150
void RowAttributes(float *row_height, float *descenders, float *ascenders) const
const char * string() const
Definition: strngs.cpp:196
const char * GetBlamerDebug() const
BLOB_CHOICE_LIST * GetBlobChoices(int index) const
Definition: pageres.cpp:765
uint8_t permuter() const
Definition: ratngs.h:346
bool AnyRtlCharsInWord() const
Definition: pageres.h:391
constexpr int kPointsPerInch
Definition: publictypes.h:33
StrongScriptDirection
Definition: unichar.h:42
const FontInfo * fontinfo
Definition: pageres.h:304
float certainty() const
Definition: ratngs.h:330
void SetLineSeparator(const char *new_line)
bool is_bold() const
Definition: fontinfo.h:112
const char * WordRecognitionLanguage() const
uint8_t space()
Definition: werd.h:102
const tesseract::ParamsTrainingBundle & params_training_bundle() const
Definition: blamer.h:162
bool ChoiceIsCorrect(const WERD_CHOICE *word_choice) const
Definition: blamer.cpp:116
bool small_caps
Definition: pageres.h:299
ChoiceIterator(const LTRResultIterator &result_it)
const char * WordFontAttributes(bool *is_bold, bool *is_italic, bool *is_underlined, bool *is_monospace, bool *is_serif, bool *is_smallcaps, int *pointsize, int *font_id) const
float ascenders() const
Definition: ocrrow.h:82
StrongScriptDirection WordDirection() const
ROW_RES * prev_row() const
Definition: pageres.h:745
float x_height() const
Definition: ocrrow.h:64
STRING lang
Definition: ccutil.h:66
bool is_italic() const
Definition: fontinfo.h:111
const void * GetParamsTrainingBundle() const
STRING TruthString() const
Definition: blamer.h:112
WERD_RES * word() const
Definition: pageres.h:751
bool NoTruth() const
Definition: blamer.h:121
UNICHAR_ID unichar_id(int index) const
Definition: ratngs.h:315
int length() const
Definition: ratngs.h:303
void truncate_at(int32_t index)
Definition: strngs.cpp:267
const char * id_to_unichar_ext(UNICHAR_ID id) const
Definition: unicharset.cpp:298
BLOCK_RES * prev_block() const
Definition: pageres.h:748
bool AnyLtrCharsInWord() const
Definition: pageres.h:408
const char * BestUTF8(int blob_index, bool in_rtl_context) const
Definition: pageres.h:361
float descenders() const
Definition: ocrrow.h:85
tesseract::Tesseract * tesseract
Definition: pageres.h:282
Definition: strngs.h:45
const STRING & misadaption_debug() const
Definition: blamer.h:131
float Confidence(PageIteratorLevel level) const
const char * GetUTF8Text() const
const UNICHARSET * uch_set
Definition: pageres.h:206
BlamerBundle * blamer_bundle
Definition: pageres.h:246
bool is_serif() const
Definition: fontinfo.h:114
const STRING & unichar_string() const
Definition: ratngs.h:541
bool EquivalentToTruth(const char *str) const
tesseract::ScriptPos BlobPosition(int index) const
Definition: ratngs.h:322
int32_t universal_id
Definition: fontinfo.h:123
int lattice_size() const
Definition: blamer.h:153
WERD_RES * forward()
Definition: pageres.h:731
bool is_fixed_pitch() const
Definition: fontinfo.h:113
LTRResultIterator(PAGE_RES *page_res, Tesseract *tesseract, int scale, int scaled_yres, int rect_left, int rect_top, int rect_width, int rect_height)
void SetParagraphSeparator(const char *new_para)
int32_t length() const
Definition: strngs.cpp:191
WERD_CHOICE * best_choice
Definition: pageres.h:235
bool HasDebugInfo() const
Definition: blamer.h:125
ROW * row
Definition: pageres.h:143
#define ASSERT_HOST(x)
Definition: errcode.h:84
PARA * para() const
Definition: ocrrow.h:118
char * GetUTF8Text(PageIteratorLevel level) const
WERD * word
Definition: pageres.h:189