|
tesseract 3.04.01
|
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