tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/classify/shapeclassifier.cpp
Go to the documentation of this file.
00001 // Copyright 2011 Google Inc. All Rights Reserved.
00002 // Author: rays@google.com (Ray Smith)
00004 // File:        shapeclassifier.h
00005 // Description: Base interface class for classifiers that return a
00006 //              shape index.
00007 // Author:      Ray Smith
00008 // Created:     Thu Dec 15 15:24:27 PST 2011
00009 //
00010 // (C) Copyright 2011, Google Inc.
00011 // Licensed under the Apache License, Version 2.0 (the "License");
00012 // you may not use this file except in compliance with the License.
00013 // You may obtain a copy of the License at
00014 // http://www.apache.org/licenses/LICENSE-2.0
00015 // Unless required by applicable law or agreed to in writing, software
00016 // distributed under the License is distributed on an "AS IS" BASIS,
00017 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00018 // See the License for the specific language governing permissions and
00019 // limitations under the License.
00020 //
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config_auto.h"
00025 #endif
00026 
00027 #include "shapeclassifier.h"
00028 #include "genericvector.h"
00029 #include "scrollview.h"
00030 #include "shapetable.h"
00031 #include "svmnode.h"
00032 #include "trainingsample.h"
00033 #include "tprintf.h"
00034 
00035 namespace tesseract {
00036 
00037 // Classifies the given [training] sample, writing to results.
00038 // See shapeclassifier.h for a full description.
00039 // Default implementation calls the ShapeRating version.
00040 int ShapeClassifier::UnicharClassifySample(
00041     const TrainingSample& sample, Pix* page_pix, int debug,
00042     UNICHAR_ID keep_this, GenericVector<UnicharRating>* results) {
00043   results->truncate(0);
00044   GenericVector<ShapeRating> shape_results;
00045   int num_shape_results = ClassifySample(sample, page_pix, debug, keep_this,
00046                                          &shape_results);
00047   const ShapeTable* shapes = GetShapeTable();
00048   GenericVector<int> unichar_map;
00049   unichar_map.init_to_size(shapes->unicharset().size(), -1);
00050   for (int r = 0; r < num_shape_results; ++r) {
00051     shapes->AddShapeToResults(shape_results[r], &unichar_map, results);
00052   }
00053   return results->size();
00054 }
00055 
00056 // Classifies the given [training] sample, writing to results.
00057 // See shapeclassifier.h for a full description.
00058 // Default implementation aborts.
00059 int ShapeClassifier::ClassifySample(const TrainingSample& sample, Pix* page_pix,
00060                            int debug, int keep_this,
00061                            GenericVector<ShapeRating>* results) {
00062   ASSERT_HOST("Must implement ClassifySample!" == NULL);
00063   return 0;
00064 }
00065 
00066 // Returns the shape that contains unichar_id that has the best result.
00067 // If result is not NULL, it is set with the shape_id and rating.
00068 // Does not need to be overridden if ClassifySample respects the keep_this
00069 // rule.
00070 int ShapeClassifier::BestShapeForUnichar(const TrainingSample& sample,
00071                                          Pix* page_pix, UNICHAR_ID unichar_id,
00072                                          ShapeRating* result) {
00073   GenericVector<ShapeRating> results;
00074   const ShapeTable* shapes = GetShapeTable();
00075   int num_results = ClassifySample(sample, page_pix, 0, unichar_id, &results);
00076   for (int r = 0; r < num_results; ++r) {
00077     if (shapes->GetShape(results[r].shape_id).ContainsUnichar(unichar_id)) {
00078       if (result != NULL)
00079         *result = results[r];
00080       return results[r].shape_id;
00081     }
00082   }
00083   return -1;
00084 }
00085 
00086 // Provides access to the UNICHARSET that this classifier works with.
00087 // Only needs to be overridden if GetShapeTable() can return NULL.
00088 const UNICHARSET& ShapeClassifier::GetUnicharset() const {
00089   return GetShapeTable()->unicharset();
00090 }
00091 
00092 // Visual debugger classifies the given sample, displays the results and
00093 // solicits user input to display other classifications. Returns when
00094 // the user has finished with debugging the sample.
00095 // Probably doesn't need to be overridden if the subclass provides
00096 // DisplayClassifyAs.
00097 void ShapeClassifier::DebugDisplay(const TrainingSample& sample,
00098                                    Pix* page_pix,
00099                                    UNICHAR_ID unichar_id) {
00100 #ifndef GRAPHICS_DISABLED
00101   static ScrollView* terminator = NULL;
00102   if (terminator == NULL) {
00103     terminator = new ScrollView("XIT", 0, 0, 50, 50, 50, 50, true);
00104   }
00105   ScrollView* debug_win = CreateFeatureSpaceWindow("ClassifierDebug", 0, 0);
00106   // Provide a right-click menu to choose the class.
00107   SVMenuNode* popup_menu = new SVMenuNode();
00108   popup_menu->AddChild("Choose class to debug", 0, "x", "Class to debug");
00109   popup_menu->BuildMenu(debug_win, false);
00110   // Display the features in green.
00111   const INT_FEATURE_STRUCT* features = sample.features();
00112   int num_features = sample.num_features();
00113   for (int f = 0; f < num_features; ++f) {
00114     RenderIntFeature(debug_win, &features[f], ScrollView::GREEN);
00115   }
00116   debug_win->Update();
00117   GenericVector<UnicharRating> results;
00118   // Debug classification until the user quits.
00119   const UNICHARSET& unicharset = GetUnicharset();
00120   SVEvent* ev;
00121   SVEventType ev_type;
00122   do {
00123     PointerVector<ScrollView> windows;
00124     if (unichar_id >= 0) {
00125       tprintf("Debugging class %d = %s\n",
00126               unichar_id, unicharset.id_to_unichar(unichar_id));
00127       UnicharClassifySample(sample, page_pix, 1, unichar_id, &results);
00128       DisplayClassifyAs(sample, page_pix, unichar_id, 1, &windows);
00129     } else {
00130       tprintf("Invalid unichar_id: %d\n", unichar_id);
00131       UnicharClassifySample(sample, page_pix, 1, -1, &results);
00132     }
00133     if (unichar_id >= 0) {
00134       tprintf("Debugged class %d = %s\n",
00135               unichar_id, unicharset.id_to_unichar(unichar_id));
00136     }
00137     tprintf("Right-click in ClassifierDebug window to choose debug class,");
00138     tprintf(" Left-click or close window to quit...\n");
00139     UNICHAR_ID old_unichar_id;
00140     do {
00141       old_unichar_id = unichar_id;
00142       ev = debug_win->AwaitEvent(SVET_ANY);
00143       ev_type = ev->type;
00144       if (ev_type == SVET_POPUP) {
00145         if (unicharset.contains_unichar(ev->parameter)) {
00146           unichar_id = unicharset.unichar_to_id(ev->parameter);
00147         } else {
00148           tprintf("Char class '%s' not found in unicharset", ev->parameter);
00149         }
00150       }
00151       delete ev;
00152     } while (unichar_id == old_unichar_id &&
00153              ev_type != SVET_CLICK && ev_type != SVET_DESTROY);
00154   } while (ev_type != SVET_CLICK && ev_type != SVET_DESTROY);
00155   delete debug_win;
00156 #endif  // GRAPHICS_DISABLED
00157 }
00158 
00159 // Displays classification as the given shape_id. Creates as many windows
00160 // as it feels fit, using index as a guide for placement. Adds any created
00161 // windows to the windows output and returns a new index that may be used
00162 // by any subsequent classifiers. Caller waits for the user to view and
00163 // then destroys the windows by clearing the vector.
00164 int ShapeClassifier::DisplayClassifyAs(
00165     const TrainingSample& sample, Pix* page_pix,
00166     UNICHAR_ID unichar_id, int index,
00167     PointerVector<ScrollView>* windows) {
00168   // Does nothing in the default implementation.
00169   return index;
00170 }
00171 
00172 // Prints debug information on the results.
00173 void ShapeClassifier::UnicharPrintResults(
00174     const char* context, const GenericVector<UnicharRating>& results) const {
00175   tprintf("%s\n", context);
00176   for (int i = 0; i < results.size(); ++i) {
00177     tprintf("%g: c_id=%d=%s", results[i].rating, results[i].unichar_id,
00178             GetUnicharset().id_to_unichar(results[i].unichar_id));
00179     if (results[i].fonts.size() != 0) {
00180       tprintf(" Font Vector:");
00181       for (int f = 0; f < results[i].fonts.size(); ++f) {
00182         tprintf(" %d", results[i].fonts[f]);
00183       }
00184     }
00185     tprintf("\n");
00186   }
00187 }
00188 void ShapeClassifier::PrintResults(
00189     const char* context, const GenericVector<ShapeRating>& results) const {
00190   tprintf("%s\n", context);
00191   for (int i = 0; i < results.size(); ++i) {
00192     tprintf("%g:", results[i].rating);
00193     if (results[i].joined)
00194       tprintf("[J]");
00195     if (results[i].broken)
00196       tprintf("[B]");
00197     tprintf(" %s\n", GetShapeTable()->DebugStr(results[i].shape_id).string());
00198   }
00199 }
00200 
00201 // Removes any result that has all its unichars covered by a better choice,
00202 // regardless of font.
00203 void ShapeClassifier::FilterDuplicateUnichars(
00204     GenericVector<ShapeRating>* results) const {
00205   GenericVector<ShapeRating> filtered_results;
00206   // Copy results to filtered results and knock out duplicate unichars.
00207   const ShapeTable* shapes = GetShapeTable();
00208   for (int r = 0; r < results->size(); ++r) {
00209     if (r > 0) {
00210       const Shape& shape_r = shapes->GetShape((*results)[r].shape_id);
00211       int c;
00212       for (c = 0; c < shape_r.size(); ++c) {
00213         int unichar_id = shape_r[c].unichar_id;
00214         int s;
00215         for (s = 0; s < r; ++s) {
00216           const Shape& shape_s = shapes->GetShape((*results)[s].shape_id);
00217           if (shape_s.ContainsUnichar(unichar_id))
00218             break;  // We found unichar_id.
00219         }
00220         if (s == r)
00221           break;  // We didn't find unichar_id.
00222       }
00223       if (c == shape_r.size())
00224         continue;  // We found all the unichar ids in previous answers.
00225     }
00226     filtered_results.push_back((*results)[r]);
00227   }
00228   *results = filtered_results;
00229 }
00230 
00231 }  // namespace tesseract.
00232 
00233 
00234 
00235 
00236 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines