tesseract 4.1.1
Loading...
Searching...
No Matches
blamer.h
Go to the documentation of this file.
1
2// File: blamer.h
3// Description: Module allowing precise error causes to be allocated.
4// Author: Rike Antonova
5// Refactored: Ray Smith
6// Created: Mon Feb 04 14:37:01 PST 2013
7//
8// (C) Copyright 2013, 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#ifndef TESSERACT_CCSTRUCT_BLAMER_H_
22#define TESSERACT_CCSTRUCT_BLAMER_H_
23
24#include <cstdint> // for int16_t
25#include <cstring> // for memcpy
26#include "boxword.h" // for BoxWord
27#include "genericvector.h" // for GenericVector
28#ifndef DISABLED_LEGACY_ENGINE
29#include "params_training_featdef.h" // for ParamsTrainingBundle, ParamsTra...
30#endif // ndef DISABLED_LEGACY_ENGINE
31#include "ratngs.h" // for BLOB_CHOICE_LIST (ptr only)
32#include "rect.h" // for TBOX
33#include "strngs.h" // for STRING
34#include "tprintf.h" // for tprintf
35#include "unichar.h" // for UNICHAR_ID
36
37class DENORM;
38class MATRIX;
39class UNICHARSET;
40class WERD_RES;
41
42struct MATRIX_COORD;
43struct TWERD;
44
45template <class R, class A1, class A2> class TessResultCallback2;
46
47static const int16_t kBlamerBoxTolerance = 5;
48
49// Enum for expressing the source of error.
50// Note: Please update kIncorrectResultReasonNames when modifying this enum.
52 // The text recorded in best choice == truth text
54 // Either: Top choice is incorrect and is a dictionary word (language model
55 // is unlikely to help correct such errors, so blame the classifier).
56 // Or: the correct unichar was not included in shortlist produced by the
57 // classifier at all.
59 // Chopper have not found one or more splits that correspond to the correct
60 // character bounding boxes recorded in BlamerBundle::truth_word.
62 // Classifier did include correct unichars for each blob in the correct
63 // segmentation, however its rating could have been too bad to allow the
64 // language model to pull out the correct choice. On the other hand the
65 // strength of the language model might have been too weak to favor the
66 // correct answer, this we call this case a classifier-language model
67 // tradeoff error.
69 // Page layout failed to produce the correct bounding box. Blame page layout
70 // if the truth was not found for the word, which implies that the bounding
71 // box of the word was incorrect (no truth word had a similar bounding box).
73 // SegSearch heuristic prevented one or more blobs from the correct
74 // segmentation state to be classified (e.g. the blob was too wide).
76 // The correct segmentaiton state was not explored because of poor SegSearch
77 // pain point prioritization. We blame SegSearch pain point prioritization
78 // if the best rating of a choice constructed from correct segmentation is
79 // better than that of the best choice (i.e. if we got to explore the correct
80 // segmentation state, language model would have picked the correct choice).
82 // Same as IRR_CLASS_LM_TRADEOFF, but used when we only run chopper on a word,
83 // and thus use the old language model (permuters).
84 // TODO(antonova): integrate the new language mode with chopper
86 // If there is an incorrect adaptive template match with a better score than
87 // a correct one (either pre-trained or adapted), mark this as adaption error.
89 // split_and_recog_word() failed to find a suitable split in truth.
91 // Truth is not available for this word (e.g. when words in corrected content
92 // file are turned into ~~~~ because an appropriate alignment was not found.
94 // The text recorded in best choice != truth text, but none of the above
95 // reasons are set.
97
99};
100
101// Blamer-related information to determine the source of errors.
103 static const char *IncorrectReasonName(IncorrectResultReason irr);
104 BlamerBundle() : truth_has_char_boxes_(false),
105 incorrect_result_reason_(IRR_CORRECT),
106 lattice_data_(nullptr) { ClearResults(); }
108 this->CopyTruth(other);
109 this->CopyResults(other);
110 }
111 ~BlamerBundle() { delete[] lattice_data_; }
112
113 // Accessors.
115 STRING truth_str;
116 for (int i = 0; i < truth_text_.length(); ++i)
117 truth_str += truth_text_[i];
118 return truth_str;
119 }
121 return incorrect_result_reason_;
122 }
123 bool NoTruth() const {
124 return incorrect_result_reason_ == IRR_NO_TRUTH ||
125 incorrect_result_reason_ == IRR_PAGE_LAYOUT;
126 }
127 bool HasDebugInfo() const {
128 return debug_.length() > 0 || misadaption_debug_.length() > 0;
129 }
130 const STRING& debug() const {
131 return debug_;
132 }
133 const STRING& misadaption_debug() const {
134 return misadaption_debug_;
135 }
136 void UpdateBestRating(float rating) {
137 if (rating < best_correctly_segmented_rating_)
138 best_correctly_segmented_rating_ = rating;
139 }
141 return correct_segmentation_cols_.length();
142 }
143 // Returns true if the given ratings matrix col,row position is included
144 // in the correct segmentation path at the given index.
145 bool MatrixPositionCorrect(int index, const MATRIX_COORD& coord) {
146 return correct_segmentation_cols_[index] == coord.col &&
147 correct_segmentation_rows_[index] == coord.row;
148 }
150 best_choice_is_dict_and_top_choice_ = value;
151 }
152 const char* lattice_data() const {
153 return lattice_data_;
154 }
155 int lattice_size() const {
156 return lattice_size_; // size of lattice_data in bytes
157 }
158 void set_lattice_data(const char* data, int size) {
159 lattice_size_ = size;
160 delete [] lattice_data_;
161 lattice_data_ = new char[lattice_size_];
162 memcpy(lattice_data_, data, lattice_size_);
163 }
164#ifndef DISABLED_LEGACY_ENGINE
166 return params_training_bundle_;
167 }
168 // Adds a new ParamsTrainingHypothesis to the current hypothesis list.
170 params_training_bundle_.AddHypothesis(hypo);
171 }
172#endif // ndef DISABLED_LEGACY_ENGINE
173
174 // Functions to setup the blamer.
175 // Whole word string, whole word bounding box.
176 void SetWordTruth(const UNICHARSET& unicharset,
177 const char* truth_str, const TBOX& word_box);
178 // Single "character" string, "character" bounding box.
179 // May be called multiple times to indicate the characters in a word.
180 void SetSymbolTruth(const UNICHARSET& unicharset,
181 const char* char_str, const TBOX& char_box);
182 // Marks that there is something wrong with the truth text, like it contains
183 // reject characters.
184 void SetRejectedTruth();
185
186 // Returns true if the provided word_choice is correct.
187 bool ChoiceIsCorrect(const WERD_CHOICE* word_choice) const;
188
190 norm_truth_word_.DeleteAllBoxes();
191 norm_box_tolerance_ = 0;
192 if (!NoTruth()) incorrect_result_reason_ = IRR_CORRECT;
193 debug_ = "";
194 segsearch_is_looking_for_blame_ = false;
195 best_correctly_segmented_rating_ = WERD_CHOICE::kBadRating;
196 correct_segmentation_cols_.clear();
197 correct_segmentation_rows_.clear();
198 best_choice_is_dict_and_top_choice_ = false;
199 delete[] lattice_data_;
200 lattice_data_ = nullptr;
201 lattice_size_ = 0;
202 }
203 void CopyTruth(const BlamerBundle &other) {
204 truth_has_char_boxes_ = other.truth_has_char_boxes_;
205 truth_word_ = other.truth_word_;
206 truth_text_ = other.truth_text_;
207 incorrect_result_reason_ =
208 (other.NoTruth() ? other.incorrect_result_reason_ : IRR_CORRECT);
209 }
210 void CopyResults(const BlamerBundle &other) {
211 norm_truth_word_ = other.norm_truth_word_;
212 norm_box_tolerance_ = other.norm_box_tolerance_;
213 incorrect_result_reason_ = other.incorrect_result_reason_;
214 segsearch_is_looking_for_blame_ = other.segsearch_is_looking_for_blame_;
215 best_correctly_segmented_rating_ = other.best_correctly_segmented_rating_;
216 correct_segmentation_cols_ = other.correct_segmentation_cols_;
217 correct_segmentation_rows_ = other.correct_segmentation_rows_;
218 best_choice_is_dict_and_top_choice_ =
219 other.best_choice_is_dict_and_top_choice_;
220 if (other.lattice_data_ != nullptr) {
221 lattice_data_ = new char[other.lattice_size_];
222 memcpy(lattice_data_, other.lattice_data_, other.lattice_size_);
223 lattice_size_ = other.lattice_size_;
224 } else {
225 lattice_data_ = nullptr;
226 }
227 }
228 const char *IncorrectReason() const;
229
230 // Appends choice and truth details to the given debug string.
231 void FillDebugString(const STRING &msg, const WERD_CHOICE *choice,
232 STRING *debug);
233
234 // Sets up the norm_truth_word from truth_word using the given DENORM.
235 void SetupNormTruthWord(const DENORM& denorm);
236
237 // Splits *this into two pieces in bundle1 and bundle2 (preallocated, empty
238 // bundles) where the right edge/ of the left-hand word is word1_right,
239 // and the left edge of the right-hand word is word2_left.
240 void SplitBundle(int word1_right, int word2_left, bool debug,
241 BlamerBundle* bundle1, BlamerBundle* bundle2) const;
242 // "Joins" the blames from bundle1 and bundle2 into *this.
243 void JoinBlames(const BlamerBundle& bundle1, const BlamerBundle& bundle2,
244 bool debug);
245
246 // If a blob with the same bounding box as one of the truth character
247 // bounding boxes is not classified as the corresponding truth character
248 // blames character classifier for incorrect answer.
249 void BlameClassifier(const UNICHARSET& unicharset,
250 const TBOX& blob_box,
251 const BLOB_CHOICE_LIST& choices,
252 bool debug);
253
254
255 // Checks whether chops were made at all the character bounding box
256 // boundaries in word->truth_word. If not - blames the chopper for an
257 // incorrect answer.
258 void SetChopperBlame(const WERD_RES* word, bool debug);
259 // Blames the classifier or the language model if, after running only the
260 // chopper, best_choice is incorrect and no blame has been yet set.
261 // Blames the classifier if best_choice is classifier's top choice and is a
262 // dictionary word (i.e. language model could not have helped).
263 // Otherwise, blames the language model (formerly permuter word adjustment).
265 const WERD_RES* word,
266 const UNICHARSET& unicharset, bool valid_permuter, bool debug);
267 // Sets up the correct_segmentation_* to mark the correct bounding boxes.
268 void SetupCorrectSegmentation(const TWERD* word, bool debug);
269
270 // Returns true if a guided segmentation search is needed.
271 bool GuidedSegsearchNeeded(const WERD_CHOICE *best_choice) const;
272 // Setup ready to guide the segmentation search to the correct segmentation.
273 // The callback pp_cb is used to avoid a cyclic dependency.
274 // It calls into LMPainPoints::GenerateForBlamer by pre-binding the
275 // WERD_RES, and the LMPainPoints itself.
276 // pp_cb must be a permanent callback, and should be deleted by the caller.
277 void InitForSegSearch(const WERD_CHOICE *best_choice,
278 MATRIX* ratings, UNICHAR_ID wildcard_id,
279 bool debug, STRING *debug_str,
281 // Returns true if the guided segsearch is in progress.
282 bool GuidedSegsearchStillGoing() const;
283 // The segmentation search has ended. Sets the blame appropriately.
284 void FinishSegSearch(const WERD_CHOICE *best_choice,
285 bool debug, STRING *debug_str);
286
287 // If the bundle is null or still does not indicate the correct result,
288 // fix it and use some backup reason for the blame.
289 static void LastChanceBlame(bool debug, WERD_RES* word);
290
291 // Sets the misadaption debug if this word is incorrect, as this word is
292 // being adapted to.
293 void SetMisAdaptionDebug(const WERD_CHOICE *best_choice, bool debug);
294
295 private:
296 // Copy assignment operator (currently unused, therefore private).
297 BlamerBundle& operator=(const BlamerBundle& other);
298 void SetBlame(IncorrectResultReason irr, const STRING &msg,
299 const WERD_CHOICE *choice, bool debug) {
300 incorrect_result_reason_ = irr;
301 debug_ = IncorrectReason();
302 debug_ += " to blame: ";
303 FillDebugString(msg, choice, &debug_);
304 if (debug) tprintf("SetBlame(): %s", debug_.string());
305 }
306
307 private:
308 // Set to true when bounding boxes for individual unichars are recorded.
309 bool truth_has_char_boxes_;
310 // The true_word (in the original image coordinate space) contains ground
311 // truth bounding boxes for this WERD_RES.
312 tesseract::BoxWord truth_word_;
313 // Same as above, but in normalized coordinates
314 // (filled in by WERD_RES::SetupForRecognition()).
315 tesseract::BoxWord norm_truth_word_;
316 // Tolerance for bounding box comparisons in normalized space.
317 int norm_box_tolerance_;
318 // Contains ground truth unichar for each of the bounding boxes in truth_word.
319 GenericVector<STRING> truth_text_;
320 // The reason for incorrect OCR result.
321 IncorrectResultReason incorrect_result_reason_;
322 // Debug text associated with the blame.
323 STRING debug_;
324 // Misadaption debug information (filled in if this word was misadapted to).
325 STRING misadaption_debug_;
326 // Variables used by the segmentation search when looking for the blame.
327 // Set to true while segmentation search is continued after the usual
328 // termination condition in order to look for the blame.
329 bool segsearch_is_looking_for_blame_;
330 // Best rating for correctly segmented path
331 // (set and used by SegSearch when looking for blame).
332 float best_correctly_segmented_rating_;
333 // Vectors populated by SegSearch to indicate column and row indices that
334 // correspond to blobs with correct bounding boxes.
335 GenericVector<int> correct_segmentation_cols_;
336 GenericVector<int> correct_segmentation_rows_;
337 // Set to true if best choice is a dictionary word and
338 // classifier's top choice.
339 bool best_choice_is_dict_and_top_choice_;
340 // Serialized segmentation search lattice.
341 char *lattice_data_;
342 int lattice_size_; // size of lattice_data in bytes
343 // Information about hypotheses (paths) explored by the segmentation search.
344#ifndef DISABLED_LEGACY_ENGINE
345 tesseract::ParamsTrainingBundle params_training_bundle_;
346#endif // ndef DISABLED_LEGACY_ENGINE
347};
348
349
350#endif // TESSERACT_CCSTRUCT_BLAMER_H_
IncorrectResultReason
Definition: blamer.h:51
@ IRR_PAGE_LAYOUT
Definition: blamer.h:72
@ IRR_NO_TRUTH
Definition: blamer.h:93
@ IRR_ADAPTION
Definition: blamer.h:88
@ IRR_CHOPPER
Definition: blamer.h:61
@ IRR_CORRECT
Definition: blamer.h:53
@ IRR_NUM_REASONS
Definition: blamer.h:98
@ IRR_CLASS_LM_TRADEOFF
Definition: blamer.h:68
@ IRR_SEGSEARCH_PP
Definition: blamer.h:81
@ IRR_CLASSIFIER
Definition: blamer.h:58
@ IRR_UNKNOWN
Definition: blamer.h:96
@ IRR_NO_TRUTH_SPLIT
Definition: blamer.h:90
@ IRR_SEGSEARCH_HEUR
Definition: blamer.h:75
@ IRR_CLASS_OLD_LM_TRADEOFF
Definition: blamer.h:85
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
int UNICHAR_ID
Definition: unichar.h:34
int length() const
Definition: genericvector.h:86
void SetWordTruth(const UNICHARSET &unicharset, const char *truth_str, const TBOX &word_box)
Definition: blamer.cpp:74
bool MatrixPositionCorrect(int index, const MATRIX_COORD &coord)
Definition: blamer.h:145
void SetRejectedTruth()
Definition: blamer.cpp:113
void BlameClassifier(const UNICHARSET &unicharset, const TBOX &blob_box, const BLOB_CHOICE_LIST &choices, bool debug)
Definition: blamer.cpp:265
void CopyResults(const BlamerBundle &other)
Definition: blamer.h:210
bool HasDebugInfo() const
Definition: blamer.h:127
const char * lattice_data() const
Definition: blamer.h:152
void ClearResults()
Definition: blamer.h:189
int lattice_size() const
Definition: blamer.h:155
const tesseract::ParamsTrainingBundle & params_training_bundle() const
Definition: blamer.h:165
static void LastChanceBlame(bool debug, WERD_RES *word)
Definition: blamer.cpp:560
void JoinBlames(const BlamerBundle &bundle1, const BlamerBundle &bundle2, bool debug)
Definition: blamer.cpp:233
STRING TruthString() const
Definition: blamer.h:114
void FillDebugString(const STRING &msg, const WERD_CHOICE *choice, STRING *debug)
Definition: blamer.cpp:131
void UpdateBestRating(float rating)
Definition: blamer.h:136
void SetChopperBlame(const WERD_RES *word, bool debug)
Definition: blamer.cpp:318
bool GuidedSegsearchStillGoing() const
Definition: blamer.cpp:514
bool ChoiceIsCorrect(const WERD_CHOICE *word_choice) const
Definition: blamer.cpp:119
void SetMisAdaptionDebug(const WERD_CHOICE *best_choice, bool debug)
Definition: blamer.cpp:587
void FinishSegSearch(const WERD_CHOICE *best_choice, bool debug, STRING *debug_str)
Definition: blamer.cpp:519
void InitForSegSearch(const WERD_CHOICE *best_choice, MATRIX *ratings, UNICHAR_ID wildcard_id, bool debug, STRING *debug_str, TessResultCallback2< bool, int, int > *pp_cb)
Definition: blamer.cpp:484
void AddHypothesis(const tesseract::ParamsTrainingHypothesis &hypo)
Definition: blamer.h:169
void CopyTruth(const BlamerBundle &other)
Definition: blamer.h:203
static const char * IncorrectReasonName(IncorrectResultReason irr)
Definition: blamer.cpp:64
bool NoTruth() const
Definition: blamer.h:123
IncorrectResultReason incorrect_result_reason() const
Definition: blamer.h:120
const char * IncorrectReason() const
Definition: blamer.cpp:68
bool GuidedSegsearchNeeded(const WERD_CHOICE *best_choice) const
Definition: blamer.cpp:471
void SplitBundle(int word1_right, int word2_left, bool debug, BlamerBundle *bundle1, BlamerBundle *bundle2) const
Definition: blamer.cpp:177
const STRING & debug() const
Definition: blamer.h:130
const STRING & misadaption_debug() const
Definition: blamer.h:133
BlamerBundle()
Definition: blamer.h:104
void BlameClassifierOrLangModel(const WERD_RES *word, const UNICHARSET &unicharset, bool valid_permuter, bool debug)
Definition: blamer.cpp:377
void set_best_choice_is_dict_and_top_choice(bool value)
Definition: blamer.h:149
BlamerBundle(const BlamerBundle &other)
Definition: blamer.h:107
void SetupNormTruthWord(const DENORM &denorm)
Definition: blamer.cpp:153
int correct_segmentation_length() const
Definition: blamer.h:140
void SetupCorrectSegmentation(const TWERD *word, bool debug)
Definition: blamer.cpp:415
void SetSymbolTruth(const UNICHARSET &unicharset, const char *char_str, const TBOX &char_box)
Definition: blamer.cpp:94
void set_lattice_data(const char *data, int size)
Definition: blamer.h:158
~BlamerBundle()
Definition: blamer.h:111
Definition: blobs.h:418
void DeleteAllBoxes()
Definition: boxword.cpp:174
Definition: matrix.h:578
ParamsTrainingHypothesis & AddHypothesis(const ParamsTrainingHypothesis &other)
static const float kBadRating
Definition: ratngs.h:265
Definition: rect.h:34
Definition: strngs.h:45
int32_t length() const
Definition: strngs.cpp:189
const char * string() const
Definition: strngs.cpp:194