tesseract
3.03
|
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(prioritize_division, FALSE, 00037 "Prioritize blob division over chopping", this->params()), 00038 INT_MEMBER(tessedit_single_match, FALSE, 00039 "Top choice only from CP", this->params()), 00040 BOOL_MEMBER(classify_enable_learning, true, 00041 "Enable adaptive classifier", this->params()), 00042 INT_MEMBER(classify_debug_level, 0, "Classify debug level", 00043 this->params()), 00044 INT_MEMBER(classify_norm_method, character, "Normalization Method ...", 00045 this->params()), 00046 double_MEMBER(classify_char_norm_range, 0.2, 00047 "Character Normalization Range ...", this->params()), 00048 double_MEMBER(classify_min_norm_scale_x, 0.0, "Min char x-norm scale ...", 00049 this->params()), /* PREV DEFAULT 0.1 */ 00050 double_MEMBER(classify_max_norm_scale_x, 0.325, "Max char x-norm scale ...", 00051 this->params()), /* PREV DEFAULT 0.3 */ 00052 double_MEMBER(classify_min_norm_scale_y, 0.0, "Min char y-norm scale ...", 00053 this->params()), /* PREV DEFAULT 0.1 */ 00054 double_MEMBER(classify_max_norm_scale_y, 0.325, "Max char y-norm scale ...", 00055 this->params()), /* PREV DEFAULT 0.3 */ 00056 double_MEMBER(classify_max_rating_ratio, 1.5, 00057 "Veto ratio between classifier ratings", this->params()), 00058 double_MEMBER(classify_max_certainty_margin, 5.5, 00059 "Veto difference between classifier certainties", 00060 this->params()), 00061 BOOL_MEMBER(tess_cn_matching, 0, "Character Normalized Matching", 00062 this->params()), 00063 BOOL_MEMBER(tess_bn_matching, 0, "Baseline Normalized Matching", 00064 this->params()), 00065 BOOL_MEMBER(classify_enable_adaptive_matcher, 1, 00066 "Enable adaptive classifier", 00067 this->params()), 00068 BOOL_MEMBER(classify_use_pre_adapted_templates, 0, 00069 "Use pre-adapted classifier templates", this->params()), 00070 BOOL_MEMBER(classify_save_adapted_templates, 0, 00071 "Save adapted templates to a file", this->params()), 00072 BOOL_MEMBER(classify_enable_adaptive_debugger, 0, "Enable match debugger", 00073 this->params()), 00074 BOOL_MEMBER(classify_nonlinear_norm, 0, 00075 "Non-linear stroke-density normalization", this->params()), 00076 INT_MEMBER(matcher_debug_level, 0, "Matcher Debug Level", this->params()), 00077 INT_MEMBER(matcher_debug_flags, 0, "Matcher Debug Flags", this->params()), 00078 INT_MEMBER(classify_learning_debug_level, 0, "Learning Debug Level: ", 00079 this->params()), 00080 double_MEMBER(matcher_good_threshold, 0.125, "Good Match (0-1)", 00081 this->params()), 00082 double_MEMBER(matcher_great_threshold, 0.0, "Great Match (0-1)", 00083 this->params()), 00084 double_MEMBER(matcher_perfect_threshold, 0.02, "Perfect Match (0-1)", 00085 this->params()), 00086 double_MEMBER(matcher_bad_match_pad, 0.15, "Bad Match Pad (0-1)", 00087 this->params()), 00088 double_MEMBER(matcher_rating_margin, 0.1, "New template margin (0-1)", 00089 this->params()), 00090 double_MEMBER(matcher_avg_noise_size, 12.0, "Avg. noise blob length", 00091 this->params()), 00092 INT_MEMBER(matcher_permanent_classes_min, 1, "Min # of permanent classes", 00093 this->params()), 00094 INT_MEMBER(matcher_min_examples_for_prototyping, 3, 00095 "Reliable Config Threshold", this->params()), 00096 INT_MEMBER(matcher_sufficient_examples_for_prototyping, 5, 00097 "Enable adaption even if the ambiguities have not been seen", 00098 this->params()), 00099 double_MEMBER(matcher_clustering_max_angle_delta, 0.015, 00100 "Maximum angle delta for prototype clustering", 00101 this->params()), 00102 double_MEMBER(classify_misfit_junk_penalty, 0.0, 00103 "Penalty to apply when a non-alnum is vertically out of " 00104 "its expected textline position", 00105 this->params()), 00106 double_MEMBER(rating_scale, 1.5, "Rating scaling factor", this->params()), 00107 double_MEMBER(certainty_scale, 20.0, "Certainty scaling factor", 00108 this->params()), 00109 double_MEMBER(tessedit_class_miss_scale, 0.00390625, 00110 "Scale factor for features not used", this->params()), 00111 double_MEMBER(classify_adapted_pruning_factor, 2.5, 00112 "Prune poor adapted results this much worse than best result", 00113 this->params()), 00114 double_MEMBER(classify_adapted_pruning_threshold, -1.0, 00115 "Threshold at which classify_adapted_pruning_factor starts", 00116 this->params()), 00117 INT_MEMBER(classify_adapt_proto_threshold, 230, 00118 "Threshold for good protos during adaptive 0-255", 00119 this->params()), 00120 INT_MEMBER(classify_adapt_feature_threshold, 230, 00121 "Threshold for good features during adaptive 0-255", 00122 this->params()), 00123 BOOL_MEMBER(disable_character_fragments, TRUE, 00124 "Do not include character fragments in the" 00125 " results of the classifier", this->params()), 00126 double_MEMBER(classify_character_fragments_garbage_certainty_threshold, 00127 -3.0, "Exclude fragments that do not look like whole" 00128 " characters from training and adaption", this->params()), 00129 BOOL_MEMBER(classify_debug_character_fragments, FALSE, 00130 "Bring up graphical debugging windows for fragments training", 00131 this->params()), 00132 BOOL_MEMBER(matcher_debug_separate_windows, FALSE, 00133 "Use two different windows for debugging the matching: " 00134 "One for the protos and one for the features.", this->params()), 00135 STRING_MEMBER(classify_learn_debug_str, "", "Class str to debug learning", 00136 this->params()), 00137 INT_MEMBER(classify_class_pruner_threshold, 229, 00138 "Class Pruner Threshold 0-255", this->params()), 00139 INT_MEMBER(classify_class_pruner_multiplier, 15, 00140 "Class Pruner Multiplier 0-255: ", this->params()), 00141 INT_MEMBER(classify_cp_cutoff_strength, 7, 00142 "Class Pruner CutoffStrength: ", this->params()), 00143 INT_MEMBER(classify_integer_matcher_multiplier, 10, 00144 "Integer Matcher Multiplier 0-255: ", this->params()), 00145 EnableLearning(true), 00146 INT_MEMBER(il1_adaption_test, 0, "Dont adapt to i/I at beginning of word", 00147 this->params()), 00148 BOOL_MEMBER(classify_bln_numeric_mode, 0, 00149 "Assume the input is numbers [0-9].", this->params()), 00150 double_MEMBER(speckle_large_max_size, 0.30, "Max large speckle size", 00151 this->params()), 00152 double_MEMBER(speckle_rating_penalty, 10.0, 00153 "Penalty to add to worst rating for noise", this->params()), 00154 shape_table_(NULL), 00155 dict_(this), 00156 static_classifier_(NULL) { 00157 fontinfo_table_.set_compare_callback( 00158 NewPermanentTessCallback(CompareFontInfo)); 00159 fontinfo_table_.set_clear_callback( 00160 NewPermanentTessCallback(FontInfoDeleteCallback)); 00161 fontset_table_.set_compare_callback( 00162 NewPermanentTessCallback(CompareFontSet)); 00163 fontset_table_.set_clear_callback( 00164 NewPermanentTessCallback(FontSetDeleteCallback)); 00165 AdaptedTemplates = NULL; 00166 PreTrainedTemplates = NULL; 00167 AllProtosOn = NULL; 00168 AllConfigsOn = NULL; 00169 AllConfigsOff = NULL; 00170 TempProtoMask = NULL; 00171 NormProtos = NULL; 00172 00173 NumAdaptationsFailed = 0; 00174 00175 learn_debug_win_ = NULL; 00176 learn_fragmented_word_debug_win_ = NULL; 00177 learn_fragments_debug_win_ = NULL; 00178 00179 CharNormCutoffs = new uinT16[MAX_NUM_CLASSES]; 00180 BaselineCutoffs = new uinT16[MAX_NUM_CLASSES]; 00181 } 00182 00183 Classify::~Classify() { 00184 EndAdaptiveClassifier(); 00185 delete learn_debug_win_; 00186 delete learn_fragmented_word_debug_win_; 00187 delete learn_fragments_debug_win_; 00188 delete[] CharNormCutoffs; 00189 delete[] BaselineCutoffs; 00190 } 00191 00192 00193 // Takes ownership of the given classifier, and uses it for future calls 00194 // to CharNormClassifier. 00195 void Classify::SetStaticClassifier(ShapeClassifier* static_classifier) { 00196 delete static_classifier_; 00197 static_classifier_ = static_classifier; 00198 } 00199 00200 // Moved from speckle.cpp 00201 // Adds a noise classification result that is a bit worse than the worst 00202 // current result, or the worst possible result if no current results. 00203 void Classify::AddLargeSpeckleTo(int blob_length, BLOB_CHOICE_LIST *choices) { 00204 BLOB_CHOICE_IT bc_it(choices); 00205 // If there is no classifier result, we will use the worst possible certainty 00206 // and corresponding rating. 00207 float certainty = -getDict().certainty_scale; 00208 float rating = rating_scale * blob_length; 00209 if (!choices->empty() && blob_length > 0) { 00210 bc_it.move_to_last(); 00211 BLOB_CHOICE* worst_choice = bc_it.data(); 00212 // Add speckle_rating_penalty to worst rating, matching old value. 00213 rating = worst_choice->rating() + speckle_rating_penalty; 00214 // Compute the rating to correspond to the certainty. (Used to be kept 00215 // the same, but that messes up the language model search.) 00216 certainty = -rating * getDict().certainty_scale / 00217 (rating_scale * blob_length); 00218 } 00219 BLOB_CHOICE* blob_choice = new BLOB_CHOICE(UNICHAR_SPACE, rating, certainty, 00220 -1, -1, 0, 0, MAX_FLOAT32, 0, 00221 BCC_SPECKLE_CLASSIFIER); 00222 bc_it.add_to_end(blob_choice); 00223 } 00224 00225 // Returns true if the blob is small enough to be a large speckle. 00226 bool Classify::LargeSpeckle(const TBLOB &blob) { 00227 double speckle_size = kBlnXHeight * speckle_large_max_size; 00228 TBOX bbox = blob.bounding_box(); 00229 return bbox.width() < speckle_size && bbox.height() < speckle_size; 00230 } 00231 00232 00233 } // namespace tesseract