Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ltrresultiterator.cpp
Go to the documentation of this file.
1
2 // 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
30 LTRResultIterator::LTRResultIterator(PAGE_RES* page_res, Tesseract* tesseract,
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 LTRResultIterator::~LTRResultIterator() {
41 }
42
43 // Returns the null terminated UTF-8 encoded text string for the current
44 // object at the given level. Use delete [] to free after use.
45 char* LTRResultIterator::GetUTF8Text(PageIteratorLevel level) const {
46 if (it_->word() == NULL) return NULL; // Already at the end!
47 STRING text;
48 PAGE_RES_IT res_it(*it_);
49 WERD_CHOICE* best_choice = res_it.word()->best_choice;
50 ASSERT_HOST(best_choice != NULL);
51 if (level == RIL_SYMBOL) {
52 text = res_it.word()->BestUTF8(blob_index_, false);
53 } else if (level == RIL_WORD) {
54 text = best_choice->unichar_string();
55 } else {
56 bool eol = false; // end of line?
57 bool eop = false; // end of paragraph?
58 do { // for each paragraph in a block
59 do { // for each text line in a paragraph
60 do { // for each word in a text line
61 best_choice = res_it.word()->best_choice;
62 ASSERT_HOST(best_choice != NULL);
63 text += best_choice->unichar_string();
64 text += " ";
65 res_it.forward();
66 eol = res_it.row() != res_it.prev_row();
67 } while (!eol);
68 text.truncate_at(text.length() - 1);
69 text += line_separator_;
70 eop = res_it.block() != res_it.prev_block() ||
71 res_it.row()->row->para() != res_it.prev_row()->row->para();
72 } while (level != RIL_TEXTLINE && !eop);
73 if (eop) text += paragraph_separator_;
74 } while (level == RIL_BLOCK && res_it.block() == res_it.prev_block());
75 }
76 int length = text.length() + 1;
77 char* result = new char[length];
78 strncpy(result, text.string(), length);
79 return result;
80 }
81
82 // Set the string inserted at the end of each text line. "\n" by default.
83 void LTRResultIterator::SetLineSeparator(const char *new_line) {
84 line_separator_ = new_line;
85 }
86
87 // Set the string inserted at the end of each paragraph. "\n" by default.
88 void LTRResultIterator::SetParagraphSeparator(const char *new_para) {
89 paragraph_separator_ = new_para;
90 }
91
92 // Returns the mean confidence of the current object at the given level.
93 // The number should be interpreted as a percent probability. (0.0f-100.0f)
94 float LTRResultIterator::Confidence(PageIteratorLevel level) const {
95 if (it_->word() == NULL) return 0.0f; // Already at the end!
96 float mean_certainty = 0.0f;
97 int certainty_count = 0;
98 PAGE_RES_IT res_it(*it_);
99 WERD_CHOICE* best_choice = res_it.word()->best_choice;
100 ASSERT_HOST(best_choice != NULL);
101 switch (level) {
102 case RIL_BLOCK:
103 do {
104 best_choice = res_it.word()->best_choice;
105 ASSERT_HOST(best_choice != NULL);
106 mean_certainty += best_choice->certainty();
107 ++certainty_count;
108 res_it.forward();
109 } while (res_it.block() == res_it.prev_block());
110 break;
111 case RIL_PARA:
112 do {
113 best_choice = res_it.word()->best_choice;
114 ASSERT_HOST(best_choice != NULL);
115 mean_certainty += best_choice->certainty();
116 ++certainty_count;
117 res_it.forward();
118 } while (res_it.block() == res_it.prev_block() &&
119 res_it.row()->row->para() == res_it.prev_row()->row->para());
120 break;
121 case RIL_TEXTLINE:
122 do {
123 best_choice = res_it.word()->best_choice;
124 ASSERT_HOST(best_choice != NULL);
125 mean_certainty += best_choice->certainty();
126 ++certainty_count;
127 res_it.forward();
128 } while (res_it.row() == res_it.prev_row());
129 break;
130 case RIL_WORD:
131 mean_certainty += best_choice->certainty();
132 ++certainty_count;
133 break;
134 case RIL_SYMBOL:
135 BLOB_CHOICE_LIST_CLIST* choices = best_choice->blob_choices();
136 if (choices != NULL) {
137 BLOB_CHOICE_LIST_C_IT blob_choices_it(choices);
138 for (int blob = 0; blob < blob_index_; ++blob)
139 blob_choices_it.forward();
140 BLOB_CHOICE_IT choice_it(blob_choices_it.data());
141 for (choice_it.mark_cycle_pt();
142 !choice_it.cycled_list();
143 choice_it.forward()) {
144 if (choice_it.data()->unichar_id() ==
145 best_choice->unichar_id(blob_index_))
146 break;
147 }
148 mean_certainty += choice_it.data()->certainty();
149 } else {
150 mean_certainty += best_choice->certainty();
151 }
152 ++certainty_count;
153 }
154 if (certainty_count > 0) {
155 mean_certainty /= certainty_count;
156 float confidence = 100 + 5 * mean_certainty;
157 if (confidence < 0.0f) confidence = 0.0f;
158 if (confidence > 100.0f) confidence = 100.0f;
159 return confidence;
160 }
161 return 0.0f;
162 }
163
164 // Returns the font attributes of the current word. If iterating at a higher
165 // level object than words, eg textlines, then this will return the
166 // attributes of the first word in that textline.
167 // The actual return value is a string representing a font name. It points
168 // to an internal table and SHOULD NOT BE DELETED. Lifespan is the same as
169 // the iterator itself, ie rendered invalid by various members of
170 // TessBaseAPI, including Init, SetImage, End or deleting the TessBaseAPI.
171 // Pointsize is returned in printers points (1/72 inch.)
172 const char* LTRResultIterator::WordFontAttributes(bool* is_bold,
173 bool* is_italic,
174 bool* is_underlined,
175 bool* is_monospace,
176 bool* is_serif,
177 bool* is_smallcaps,
178 int* pointsize,
179 int* font_id) const {
180 if (it_->word() == NULL) return NULL; // Already at the end!
181 if (it_->word()->fontinfo == NULL) {
182 *font_id = -1;
183 return NULL; // 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 float row_height = it_->row()->row->x_height() +
194 it_->row()->row->ascenders() - it_->row()->row->descenders();
195 // Convert from pixels to printers points.
196 *pointsize = scaled_yres_ > 0
197 ? static_cast<int>(row_height * kPointsPerInch / scaled_yres_ + 0.5)
198 : 0;
199
200 return font_info.name;
201 }
202
203 // Returns the name of the language used to recognize this word.
204 const char* LTRResultIterator::WordRecognitionLanguage() const {
205 if (it_->word() == NULL || it_->word()->tesseract == NULL) return NULL;
206 return it_->word()->tesseract->lang.string();
207 }
208
209 // Return the overall directionality of this word.
210 StrongScriptDirection LTRResultIterator::WordDirection() const {
211 if (it_->word() == NULL) return DIR_NEUTRAL;
212 bool has_rtl = it_->word()->AnyRtlCharsInWord();
213 bool has_ltr = it_->word()->AnyLtrCharsInWord();
214 if (has_rtl && !has_ltr)
215 return DIR_RIGHT_TO_LEFT;
216 if (has_ltr && !has_rtl)
217 return DIR_LEFT_TO_RIGHT;
218 if (!has_ltr && !has_rtl)
219 return DIR_NEUTRAL;
220 return DIR_MIX;
221 }
222
223 // Returns true if the current word was found in a dictionary.
224 bool LTRResultIterator::WordIsFromDictionary() const {
225 if (it_->word() == NULL) return false; // Already at the end!
226 int permuter = it_->word()->best_choice->permuter();
227 return permuter == SYSTEM_DAWG_PERM || permuter == FREQ_DAWG_PERM ||
228 permuter == USER_DAWG_PERM;
229 }
230
231 // Returns true if the current word is numeric.
232 bool LTRResultIterator::WordIsNumeric() const {
233 if (it_->word() == NULL) 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.
239 bool LTRResultIterator::HasBlamerInfo() const {
240 return (it_->word() != NULL && it_->word()->blamer_bundle != NULL &&
241 (it_->word()->blamer_bundle->debug.length() > 0 ||
242 it_->word()->blamer_bundle->misadaption_debug.length() > 0));
243 }
244
245 // Returns the pointer to ParamsTrainingBundle stored in the BlamerBundle
246 // of the current word.
247 void *LTRResultIterator::GetParamsTrainingBundle() const {
248 return (it_->word() != NULL && it_->word()->blamer_bundle != NULL) ?
249 &(it_->word()->blamer_bundle->params_training_bundle) : NULL;
250 }
251
252 // Returns the pointer to the string with blamer information for this word.
253 // Assumes that the word's blamer_bundle is not NULL.
254 const char *LTRResultIterator::GetBlamerDebug() const {
255 return it_->word()->blamer_bundle->debug.string();
256 }
257
258 // Returns the pointer to the string with misadaption information for this word.
259 // Assumes that the word's blamer_bundle is not NULL.
260 const char *LTRResultIterator::GetBlamerMisadaptionDebug() const {
261 return it_->word()->blamer_bundle->misadaption_debug.string();
262 }
263
264 // Returns the null terminated UTF-8 encoded truth string for the current word.
265 // Use delete [] to free after use.
266 char* LTRResultIterator::WordTruthUTF8Text() const {
267 if (it_->word() == NULL) return NULL; // Already at the end!
268 if (it_->word()->blamer_bundle == NULL ||
269 it_->word()->blamer_bundle->incorrect_result_reason == IRR_NO_TRUTH) {
270 return NULL; // no truth information for this word
271 }
272 const GenericVector<STRING> &truth_vec =
273 it_->word()->blamer_bundle->truth_text;
274 STRING truth_text;
275 for (int i = 0; i < truth_vec.size(); ++i) truth_text += truth_vec[i];
276 int length = truth_text.length() + 1;
277 char* result = new char[length];
278 strncpy(result, truth_text.string(), length);
279 return result;
280 }
281
282 // Returns a pointer to serialized choice lattice.
283 // Fills lattice_size with the number of bytes in lattice data.
284 const char *LTRResultIterator::WordLattice(int *lattice_size) const {
285 if (it_->word() == NULL) return NULL; // Already at the end!
286 if (it_->word()->blamer_bundle == NULL) return NULL;
287 *lattice_size = it_->word()->blamer_bundle->lattice_size;
288 return it_->word()->blamer_bundle->lattice_data;
289 }
290
291 // Returns true if the current symbol is a superscript.
292 // If iterating at a higher level object than symbols, eg words, then
293 // this will return the attributes of the first symbol in that word.
294 bool LTRResultIterator::SymbolIsSuperscript() const {
295 if (cblob_it_ == NULL && it_->word() != NULL)
296 return it_->word()->box_word->BlobPosition(blob_index_) == SP_SUPERSCRIPT;
297 return false;
298 }
299
300 // Returns true if the current symbol is a subscript.
301 // If iterating at a higher level object than symbols, eg words, then
302 // this will return the attributes of the first symbol in that word.
303 bool LTRResultIterator::SymbolIsSubscript() const {
304 if (cblob_it_ == NULL && it_->word() != NULL)
305 return it_->word()->box_word->BlobPosition(blob_index_) == SP_SUBSCRIPT;
306 return false;
307 }
308
309 // Returns true if the current symbol is a dropcap.
310 // If iterating at a higher level object than symbols, eg words, then
311 // this will return the attributes of the first symbol in that word.
312 bool LTRResultIterator::SymbolIsDropcap() const {
313 if (cblob_it_ == NULL && it_->word() != NULL)
314 return it_->word()->box_word->BlobPosition(blob_index_) == SP_DROPCAP;
315 return false;
316 }
317
318 ChoiceIterator::ChoiceIterator(const LTRResultIterator& result_it) {
319 ASSERT_HOST(result_it.it_->word() != NULL);
320 word_res_ = result_it.it_->word();
321 PAGE_RES_IT res_it(*result_it.it_);
322 WERD_CHOICE* best_choice = word_res_->best_choice;
323 BLOB_CHOICE_LIST_CLIST* choices = best_choice->blob_choices();
324 if (choices != NULL) {
325 BLOB_CHOICE_LIST_C_IT blob_choices_it(choices);
326 for (int blob = 0; blob < result_it.blob_index_; ++blob)
327 blob_choices_it.forward();
328 choice_it_ = new BLOB_CHOICE_IT(blob_choices_it.data());
329 choice_it_->mark_cycle_pt();
330 } else {
331 choice_it_ = NULL;
332 }
333 }
334
335 ChoiceIterator::~ChoiceIterator() {
336 delete choice_it_;
337 }
338
339 // Moves to the next choice for the symbol and returns false if there
340 // are none left.
341 bool ChoiceIterator::Next() {
342 if (choice_it_ == NULL)
343 return false;
344 choice_it_->forward();
345 return !choice_it_->cycled_list();
346 }
347
348 // Returns the null terminated UTF-8 encoded text string for the current
349 // choice. Use delete [] to free after use.
350 const char* ChoiceIterator::GetUTF8Text() const {
351 if (choice_it_ == NULL)
352 return NULL;
353 UNICHAR_ID id = choice_it_->data()->unichar_id();
354 return word_res_->uch_set->id_to_unichar_ext(id);
355 }
356
357 // Returns the confidence of the current choice.
358 // The number should be interpreted as a percent probability. (0.0f-100.0f)
359 float ChoiceIterator::Confidence() const {
360 if (choice_it_ == NULL)
361 return 0.0f;
362 float confidence = 100 + 5 * choice_it_->data()->certainty();
363 if (confidence < 0.0f) confidence = 0.0f;
364 if (confidence > 100.0f) confidence = 100.0f;
365 return confidence;
366 }
367
368
369 } // namespace tesseract.