tesseract 3.04.01

classify/classify.cpp

Go to the documentation of this file.
00001 
00002 // File:        classify.cpp
00003 // Description: classify class.
00004 // Author:      Samuel Charron
00005 //
00006 // (C) Copyright 2006, Google Inc.
00007 // Licensed under the Apache License, Version 2.0 (the "License");
00008 // you may not use this file except in compliance with the License.
00009 // You may obtain a copy of the License at
00010 // http://www.apache.org/licenses/LICENSE-2.0
00011 // Unless required by applicable law or agreed to in writing, software
00012 // distributed under the License is distributed on an "AS IS" BASIS,
00013 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 // See the License for the specific language governing permissions and
00015 // limitations under the License.
00016 //
00018 
00019 // Include automatically generated configuration file if running autoconf.
00020 #ifdef HAVE_CONFIG_H
00021 #include "config_auto.h"
00022 #endif
00023 
00024 #include "classify.h"
00025 #include "fontinfo.h"
00026 #include "intproto.h"
00027 #include "mfoutline.h"
00028 #include "scrollview.h"
00029 #include "shapeclassifier.h"
00030 #include "shapetable.h"
00031 #include "unicity_table.h"
00032 #include <string.h>
00033 
00034 namespace tesseract {
00035 Classify::Classify()
00036     : BOOL_MEMBER(allow_blob_division, true, "Use divisible blobs chopping",
00037                   this->params()),
00038       BOOL_MEMBER(prioritize_division, FALSE,
00039                   "Prioritize blob division over chopping", this->params()),
00040       INT_MEMBER(tessedit_single_match, FALSE, "Top choice only from CP",
00041                  this->params()),
00042       BOOL_MEMBER(classify_enable_learning, true, "Enable adaptive classifier",
00043                   this->params()),
00044       INT_MEMBER(classify_debug_level, 0, "Classify debug level",
00045                  this->params()),
00046       INT_MEMBER(classify_norm_method, character, "Normalization Method   ...",
00047                  this->params()),
00048       double_MEMBER(classify_char_norm_range, 0.2,
00049                     "Character Normalization Range ...", this->params()),
00050       double_MEMBER(classify_min_norm_scale_x, 0.0, "Min char x-norm scale ...",
00051                     this->params()), /* PREV DEFAULT 0.1 */
00052       double_MEMBER(classify_max_norm_scale_x, 0.325,
00053                     "Max char x-norm scale ...",
00054                     this->params()), /* PREV DEFAULT 0.3 */
00055       double_MEMBER(classify_min_norm_scale_y, 0.0, "Min char y-norm scale ...",
00056                     this->params()), /* PREV DEFAULT 0.1 */
00057       double_MEMBER(classify_max_norm_scale_y, 0.325,
00058                     "Max char y-norm scale ...",
00059                     this->params()), /* PREV DEFAULT 0.3 */
00060       double_MEMBER(classify_max_rating_ratio, 1.5,
00061                     "Veto ratio between classifier ratings", this->params()),
00062       double_MEMBER(classify_max_certainty_margin, 5.5,
00063                     "Veto difference between classifier certainties",
00064                     this->params()),
00065       BOOL_MEMBER(tess_cn_matching, 0, "Character Normalized Matching",
00066                   this->params()),
00067       BOOL_MEMBER(tess_bn_matching, 0, "Baseline Normalized Matching",
00068                   this->params()),
00069       BOOL_MEMBER(classify_enable_adaptive_matcher, 1,
00070                   "Enable adaptive classifier", this->params()),
00071       BOOL_MEMBER(classify_use_pre_adapted_templates, 0,
00072                   "Use pre-adapted classifier templates", this->params()),
00073       BOOL_MEMBER(classify_save_adapted_templates, 0,
00074                   "Save adapted templates to a file", this->params()),
00075       BOOL_MEMBER(classify_enable_adaptive_debugger, 0, "Enable match debugger",
00076                   this->params()),
00077       BOOL_MEMBER(classify_nonlinear_norm, 0,
00078                   "Non-linear stroke-density normalization", this->params()),
00079       INT_MEMBER(matcher_debug_level, 0, "Matcher Debug Level", this->params()),
00080       INT_MEMBER(matcher_debug_flags, 0, "Matcher Debug Flags", this->params()),
00081       INT_MEMBER(classify_learning_debug_level, 0, "Learning Debug Level: ",
00082                  this->params()),
00083       double_MEMBER(matcher_good_threshold, 0.125, "Good Match (0-1)",
00084                     this->params()),
00085       double_MEMBER(matcher_reliable_adaptive_result, 0.0, "Great Match (0-1)",
00086                     this->params()),
00087       double_MEMBER(matcher_perfect_threshold, 0.02, "Perfect Match (0-1)",
00088                     this->params()),
00089       double_MEMBER(matcher_bad_match_pad, 0.15, "Bad Match Pad (0-1)",
00090                     this->params()),
00091       double_MEMBER(matcher_rating_margin, 0.1, "New template margin (0-1)",
00092                     this->params()),
00093       double_MEMBER(matcher_avg_noise_size, 12.0, "Avg. noise blob length",
00094                     this->params()),
00095       INT_MEMBER(matcher_permanent_classes_min, 1, "Min # of permanent classes",
00096                  this->params()),
00097       INT_MEMBER(matcher_min_examples_for_prototyping, 3,
00098                  "Reliable Config Threshold", this->params()),
00099       INT_MEMBER(matcher_sufficient_examples_for_prototyping, 5,
00100                  "Enable adaption even if the ambiguities have not been seen",
00101                  this->params()),
00102       double_MEMBER(matcher_clustering_max_angle_delta, 0.015,
00103                     "Maximum angle delta for prototype clustering",
00104                     this->params()),
00105       double_MEMBER(classify_misfit_junk_penalty, 0.0,
00106                     "Penalty to apply when a non-alnum is vertically out of "
00107                     "its expected textline position",
00108                     this->params()),
00109       double_MEMBER(rating_scale, 1.5, "Rating scaling factor", this->params()),
00110       double_MEMBER(certainty_scale, 20.0, "Certainty scaling factor",
00111                     this->params()),
00112       double_MEMBER(tessedit_class_miss_scale, 0.00390625,
00113                     "Scale factor for features not used", this->params()),
00114       double_MEMBER(
00115           classify_adapted_pruning_factor, 2.5,
00116           "Prune poor adapted results this much worse than best result",
00117           this->params()),
00118       double_MEMBER(classify_adapted_pruning_threshold, -1.0,
00119                     "Threshold at which classify_adapted_pruning_factor starts",
00120                     this->params()),
00121       INT_MEMBER(classify_adapt_proto_threshold, 230,
00122                  "Threshold for good protos during adaptive 0-255",
00123                  this->params()),
00124       INT_MEMBER(classify_adapt_feature_threshold, 230,
00125                  "Threshold for good features during adaptive 0-255",
00126                  this->params()),
00127       BOOL_MEMBER(disable_character_fragments, TRUE,
00128                   "Do not include character fragments in the"
00129                   " results of the classifier",
00130                   this->params()),
00131       double_MEMBER(classify_character_fragments_garbage_certainty_threshold,
00132                     -3.0,
00133                     "Exclude fragments that do not look like whole"
00134                     " characters from training and adaption",
00135                     this->params()),
00136       BOOL_MEMBER(classify_debug_character_fragments, FALSE,
00137                   "Bring up graphical debugging windows for fragments training",
00138                   this->params()),
00139       BOOL_MEMBER(matcher_debug_separate_windows, FALSE,
00140                   "Use two different windows for debugging the matching: "
00141                   "One for the protos and one for the features.",
00142                   this->params()),
00143       STRING_MEMBER(classify_learn_debug_str, "", "Class str to debug learning",
00144                     this->params()),
00145       INT_MEMBER(classify_class_pruner_threshold, 229,
00146                  "Class Pruner Threshold 0-255", this->params()),
00147       INT_MEMBER(classify_class_pruner_multiplier, 15,
00148                  "Class Pruner Multiplier 0-255:       ", this->params()),
00149       INT_MEMBER(classify_cp_cutoff_strength, 7,
00150                  "Class Pruner CutoffStrength:         ", this->params()),
00151       INT_MEMBER(classify_integer_matcher_multiplier, 10,
00152                  "Integer Matcher Multiplier  0-255:   ", this->params()),
00153       EnableLearning(true),
00154       INT_MEMBER(il1_adaption_test, 0, "Don't adapt to i/I at beginning of word",
00155                  this->params()),
00156       BOOL_MEMBER(classify_bln_numeric_mode, 0,
00157                   "Assume the input is numbers [0-9].", this->params()),
00158       double_MEMBER(speckle_large_max_size, 0.30, "Max large speckle size",
00159                     this->params()),
00160       double_MEMBER(speckle_rating_penalty, 10.0,
00161                     "Penalty to add to worst rating for noise", this->params()),
00162       shape_table_(NULL),
00163       dict_(this),
00164       static_classifier_(NULL) {
00165   fontinfo_table_.set_compare_callback(
00166       NewPermanentTessCallback(CompareFontInfo));
00167   fontinfo_table_.set_clear_callback(
00168       NewPermanentTessCallback(FontInfoDeleteCallback));
00169   fontset_table_.set_compare_callback(
00170       NewPermanentTessCallback(CompareFontSet));
00171   fontset_table_.set_clear_callback(
00172       NewPermanentTessCallback(FontSetDeleteCallback));
00173   AdaptedTemplates = NULL;
00174   BackupAdaptedTemplates = NULL;
00175   PreTrainedTemplates = NULL;
00176   AllProtosOn = NULL;
00177   AllConfigsOn = NULL;
00178   AllConfigsOff = NULL;
00179   TempProtoMask = NULL;
00180   NormProtos = NULL;
00181 
00182   NumAdaptationsFailed = 0;
00183 
00184   learn_debug_win_ = NULL;
00185   learn_fragmented_word_debug_win_ = NULL;
00186   learn_fragments_debug_win_ = NULL;
00187 
00188   CharNormCutoffs = new uinT16[MAX_NUM_CLASSES];
00189   BaselineCutoffs = new uinT16[MAX_NUM_CLASSES];
00190 }
00191 
00192 Classify::~Classify() {
00193   EndAdaptiveClassifier();
00194   delete learn_debug_win_;
00195   delete learn_fragmented_word_debug_win_;
00196   delete learn_fragments_debug_win_;
00197   delete[] CharNormCutoffs;
00198   delete[] BaselineCutoffs;
00199 }
00200 
00201 
00202 // Takes ownership of the given classifier, and uses it for future calls
00203 // to CharNormClassifier.
00204 void Classify::SetStaticClassifier(ShapeClassifier* static_classifier) {
00205   delete static_classifier_;
00206   static_classifier_ = static_classifier;
00207 }
00208 
00209 // Moved from speckle.cpp
00210 // Adds a noise classification result that is a bit worse than the worst
00211 // current result, or the worst possible result if no current results.
00212 void Classify::AddLargeSpeckleTo(int blob_length, BLOB_CHOICE_LIST *choices) {
00213     BLOB_CHOICE_IT bc_it(choices);
00214   // If there is no classifier result, we will use the worst possible certainty
00215   // and corresponding rating.
00216   float certainty = -getDict().certainty_scale;
00217   float rating = rating_scale * blob_length;
00218   if (!choices->empty() && blob_length > 0) {
00219     bc_it.move_to_last();
00220     BLOB_CHOICE* worst_choice = bc_it.data();
00221     // Add speckle_rating_penalty to worst rating, matching old value.
00222     rating = worst_choice->rating() + speckle_rating_penalty;
00223     // Compute the rating to correspond to the certainty. (Used to be kept
00224     // the same, but that messes up the language model search.)
00225     certainty = -rating * getDict().certainty_scale /
00226         (rating_scale * blob_length);
00227   }
00228   BLOB_CHOICE* blob_choice = new BLOB_CHOICE(UNICHAR_SPACE, rating, certainty,
00229                                              -1, 0.0f, MAX_FLOAT32, 0,
00230                                              BCC_SPECKLE_CLASSIFIER);
00231   bc_it.add_to_end(blob_choice);
00232 }
00233 
00234 // Returns true if the blob is small enough to be a large speckle.
00235 bool Classify::LargeSpeckle(const TBLOB &blob) {
00236   double speckle_size = kBlnXHeight * speckle_large_max_size;
00237   TBOX bbox = blob.bounding_box();
00238   return bbox.width() < speckle_size && bbox.height() < speckle_size;
00239 }
00240 
00241 
00242 }  // namespace tesseract
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines