tesseract  4.1.1
blamer.h
Go to the documentation of this file.
1 // 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 
37 class DENORM;
38 class MATRIX;
39 class UNICHARSET;
40 class WERD_RES;
41 
42 struct MATRIX_COORD;
43 struct TWERD;
44 
45 template <class R, class A1, class A2> class TessResultCallback2;
46 
47 static 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.
102 struct BlamerBundle {
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(); }
107  BlamerBundle(const BlamerBundle &other) {
108  this->CopyTruth(other);
109  this->CopyResults(other);
110  }
111  ~BlamerBundle() { delete[] lattice_data_; }
112 
113  // Accessors.
114  STRING TruthString() const {
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 
189  void ClearResults() {
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_
int UNICHAR_ID
Definition: unichar.h:34
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
Definition: blobs.h:418
static const char * IncorrectReasonName(IncorrectResultReason irr)
Definition: blamer.cpp:64
bool NoTruth() const
Definition: blamer.h:123
Definition: matrix.h:578
const char * lattice_data() const
Definition: blamer.h:152
int lattice_size() const
Definition: blamer.h:155
bool GuidedSegsearchStillGoing() const
Definition: blamer.cpp:514
static void LastChanceBlame(bool debug, WERD_RES *word)
Definition: blamer.cpp:560
const char * IncorrectReason() const
Definition: blamer.cpp:68
void FinishSegSearch(const WERD_CHOICE *best_choice, bool debug, STRING *debug_str)
Definition: blamer.cpp:519
const char * string() const
Definition: strngs.cpp:194
int length() const
Definition: genericvector.h:86
void SetRejectedTruth()
Definition: blamer.cpp:113
BlamerBundle()
Definition: blamer.h:104
int32_t length() const
Definition: strngs.cpp:189
bool GuidedSegsearchNeeded(const WERD_CHOICE *best_choice) const
Definition: blamer.cpp:471
void UpdateBestRating(float rating)
Definition: blamer.h:136
IncorrectResultReason
Definition: blamer.h:51
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 set_best_choice_is_dict_and_top_choice(bool value)
Definition: blamer.h:149
void SetWordTruth(const UNICHARSET &unicharset, const char *truth_str, const TBOX &word_box)
Definition: blamer.cpp:74
void DeleteAllBoxes()
Definition: boxword.cpp:174
bool ChoiceIsCorrect(const WERD_CHOICE *word_choice) const
Definition: blamer.cpp:119
void JoinBlames(const BlamerBundle &bundle1, const BlamerBundle &bundle2, bool debug)
Definition: blamer.cpp:233
~BlamerBundle()
Definition: blamer.h:111
bool HasDebugInfo() const
Definition: blamer.h:127
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
Definition: strngs.h:45
void FillDebugString(const STRING &msg, const WERD_CHOICE *choice, STRING *debug)
Definition: blamer.cpp:131
int correct_segmentation_length() const
Definition: blamer.h:140
void SplitBundle(int word1_right, int word2_left, bool debug, BlamerBundle *bundle1, BlamerBundle *bundle2) const
Definition: blamer.cpp:177
static const float kBadRating
Definition: ratngs.h:265
Definition: rect.h:34
BlamerBundle(const BlamerBundle &other)
Definition: blamer.h:107
const tesseract::ParamsTrainingBundle & params_training_bundle() const
Definition: blamer.h:165
ParamsTrainingHypothesis & AddHypothesis(const ParamsTrainingHypothesis &other)
void CopyTruth(const BlamerBundle &other)
Definition: blamer.h:203
void SetupCorrectSegmentation(const TWERD *word, bool debug)
Definition: blamer.cpp:415
void set_lattice_data(const char *data, int size)
Definition: blamer.h:158
void SetChopperBlame(const WERD_RES *word, bool debug)
Definition: blamer.cpp:318
void SetMisAdaptionDebug(const WERD_CHOICE *best_choice, bool debug)
Definition: blamer.cpp:587
bool MatrixPositionCorrect(int index, const MATRIX_COORD &coord)
Definition: blamer.h:145
void SetupNormTruthWord(const DENORM &denorm)
Definition: blamer.cpp:153
STRING TruthString() const
Definition: blamer.h:114
void ClearResults()
Definition: blamer.h:189
void BlameClassifierOrLangModel(const WERD_RES *word, const UNICHARSET &unicharset, bool valid_permuter, bool debug)
Definition: blamer.cpp:377
IncorrectResultReason incorrect_result_reason() const
Definition: blamer.h:120
const STRING & misadaption_debug() const
Definition: blamer.h:133
void SetSymbolTruth(const UNICHARSET &unicharset, const char *char_str, const TBOX &char_box)
Definition: blamer.cpp:94
const STRING & debug() const
Definition: blamer.h:130