tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/wordrec/lm_pain_points.cpp
Go to the documentation of this file.
00001 
00002 // File:        pain_points.cpp
00003 // Description: Functions that utilize the knowledge about the properties
00004 //              of the paths explored by the segmentation search in order
00005 //              to "pain points" - the locations in the ratings matrix
00006 //              which should be classified next.
00007 // Author:      Rika Antonova
00008 // Created:     Mon Jun 20 11:26:43 PST 2012
00009 //
00010 // (C) Copyright 2012, 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 #include "lm_pain_points.h"
00024 
00025 #include "associate.h"
00026 #include "dict.h"
00027 #include "genericheap.h"
00028 #include "lm_state.h"
00029 #include "matrix.h"
00030 #include "pageres.h"
00031 
00032 namespace tesseract {
00033 
00034 const float LMPainPoints::kDefaultPainPointPriorityAdjustment = 2.0f;
00035 const float LMPainPoints::kLooseMaxCharWhRatio = 2.5f;
00036 
00037 LMPainPointsType LMPainPoints::Deque(MATRIX_COORD *pp, float *priority) {
00038   for (int h = 0; h < LM_PPTYPE_NUM; ++h) {
00039     if (pain_points_heaps_[h].empty()) continue;
00040     *priority = pain_points_heaps_[h].PeekTop().key;
00041     *pp = pain_points_heaps_[h].PeekTop().data;
00042     pain_points_heaps_[h].Pop(NULL);
00043     return static_cast<LMPainPointsType>(h);
00044   }
00045   return LM_PPTYPE_NUM;
00046 }
00047 
00048 void LMPainPoints::GenerateInitial(WERD_RES *word_res) {
00049   MATRIX *ratings = word_res->ratings;
00050   AssociateStats associate_stats;
00051   for (int col = 0; col < ratings->dimension(); ++col) {
00052     int row_end = MIN(ratings->dimension(), col + ratings->bandwidth() + 1);
00053     for (int row = col + 1; row < row_end; ++row) {
00054       MATRIX_COORD coord(col, row);
00055       if (coord.Valid(*ratings) &&
00056           ratings->get(col, row) != NOT_CLASSIFIED) continue;
00057       // Add an initial pain point if needed.
00058       if (ratings->Classified(col, row - 1, dict_->WildcardID()) ||
00059           (col + 1 < ratings->dimension() &&
00060               ratings->Classified(col + 1, row, dict_->WildcardID()))) {
00061         GeneratePainPoint(col, row, LM_PPTYPE_SHAPE, 0.0,
00062                           true, max_char_wh_ratio_, word_res);
00063       }
00064     }
00065   }
00066 }
00067 
00068 void LMPainPoints::GenerateFromPath(float rating_cert_scale,
00069                                     ViterbiStateEntry *vse,
00070                                     WERD_RES *word_res) {
00071   ViterbiStateEntry *curr_vse = vse;
00072   BLOB_CHOICE *curr_b = vse->curr_b;
00073   // The following pain point generation and priority calculation approaches
00074   // prioritize exploring paths with low average rating of the known part of
00075   // the path, while not relying on the ratings of the pieces to be combined.
00076   //
00077   // A pain point to combine the neighbors is generated for each pair of
00078   // neighboring blobs on the path (the path is represented by vse argument
00079   // given to GenerateFromPath()). The priority of each pain point is set to
00080   // the average rating (per outline length) of the path, not including the
00081   // ratings of the blobs to be combined.
00082   // The ratings of the blobs to be combined are not used to calculate the
00083   // priority, since it is not possible to determine from their magnitude
00084   // whether it will be beneficial to combine the blobs. The reason is that
00085   // chopped junk blobs (/ | - ') can have very good (low) ratings, however
00086   // combining them will be beneficial. Blobs with high ratings might be
00087   // over-joined pieces of characters, but also could be blobs from an unseen
00088   // font or chopped pieces of complex characters.
00089   while (curr_vse->parent_vse != NULL) {
00090     ViterbiStateEntry* parent_vse = curr_vse->parent_vse;
00091     const MATRIX_COORD& curr_cell = curr_b->matrix_cell();
00092     const MATRIX_COORD& parent_cell = parent_vse->curr_b->matrix_cell();
00093     MATRIX_COORD pain_coord(parent_cell.col, curr_cell.row);
00094     if (!pain_coord.Valid(*word_res->ratings) ||
00095         !word_res->ratings->Classified(parent_cell.col, curr_cell.row,
00096                                        dict_->WildcardID())) {
00097       // rat_subtr contains ratings sum of the two adjacent blobs to be merged.
00098       // rat_subtr will be subtracted from the ratings sum of the path, since
00099       // the blobs will be joined into a new blob, whose rating is yet unknown.
00100       float rat_subtr = curr_b->rating() + parent_vse->curr_b->rating();
00101       // ol_subtr contains the outline length of the blobs that will be joined.
00102       float ol_subtr =
00103           AssociateUtils::ComputeOutlineLength(rating_cert_scale, *curr_b) +
00104           AssociateUtils::ComputeOutlineLength(rating_cert_scale,
00105                                                *(parent_vse->curr_b));
00106       // ol_dif is the outline of the path without the two blobs to be joined.
00107       float ol_dif = vse->outline_length - ol_subtr;
00108       // priority is set to the average rating of the path per unit of outline,
00109       // not counting the ratings of the pieces to be joined.
00110       float priority = ol_dif > 0 ? (vse->ratings_sum-rat_subtr)/ol_dif : 0.0;
00111       GeneratePainPoint(pain_coord.col, pain_coord.row, LM_PPTYPE_PATH,
00112                         priority, true, max_char_wh_ratio_, word_res);
00113     } else if (debug_level_ > 3) {
00114       tprintf("NO pain point (Classified) for col=%d row=%d type=%s\n",
00115               pain_coord.col, pain_coord.row,
00116               LMPainPointsTypeName[LM_PPTYPE_PATH]);
00117       BLOB_CHOICE_IT b_it(word_res->ratings->get(pain_coord.col,
00118                                                  pain_coord.row));
00119       for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
00120         BLOB_CHOICE* choice = b_it.data();
00121         choice->print_full();
00122       }
00123     }
00124 
00125     curr_vse = parent_vse;
00126     curr_b = curr_vse->curr_b;
00127   }
00128 }
00129 
00130 void LMPainPoints::GenerateFromAmbigs(const DANGERR &fixpt,
00131                                       ViterbiStateEntry *vse,
00132                                       WERD_RES *word_res) {
00133   // Begins and ends in DANGERR vector now record the blob indices as used
00134   // by the ratings matrix.
00135   for (int d = 0; d < fixpt.size(); ++d) {
00136     const DANGERR_INFO &danger = fixpt[d];
00137     // Only use dangerous ambiguities.
00138     if (danger.dangerous) {
00139       GeneratePainPoint(danger.begin, danger.end - 1,
00140                         LM_PPTYPE_AMBIG, vse->cost, true,
00141                         kLooseMaxCharWhRatio, word_res);
00142     }
00143   }
00144 }
00145 
00146 bool LMPainPoints::GeneratePainPoint(
00147     int col, int row, LMPainPointsType pp_type, float special_priority,
00148     bool ok_to_extend, float max_char_wh_ratio,
00149     WERD_RES *word_res) {
00150   MATRIX_COORD coord(col, row);
00151   if (coord.Valid(*word_res->ratings) &&
00152       word_res->ratings->Classified(col, row, dict_->WildcardID())) {
00153     return false;
00154   }
00155   if (debug_level_ > 3) {
00156     tprintf("Generating pain point for col=%d row=%d type=%s\n",
00157             col, row, LMPainPointsTypeName[pp_type]);
00158   }
00159   // Compute associate stats.
00160   AssociateStats associate_stats;
00161   AssociateUtils::ComputeStats(col, row, NULL, 0, fixed_pitch_,
00162                                max_char_wh_ratio, word_res, debug_level_,
00163                                &associate_stats);
00164   // For fixed-pitch fonts/languages: if the current combined blob overlaps
00165   // the next blob on the right and it is ok to extend the blob, try extending
00166   // the blob until there is no overlap with the next blob on the right or
00167   // until the width-to-height ratio becomes too large.
00168   if (ok_to_extend) {
00169     while (associate_stats.bad_fixed_pitch_right_gap &&
00170            row + 1 < word_res->ratings->dimension() &&
00171            !associate_stats.bad_fixed_pitch_wh_ratio) {
00172       AssociateUtils::ComputeStats(col, ++row, NULL, 0, fixed_pitch_,
00173                                    max_char_wh_ratio, word_res, debug_level_,
00174                                    &associate_stats);
00175     }
00176   }
00177   if (associate_stats.bad_shape) {
00178     if (debug_level_ > 3) {
00179       tprintf("Discarded pain point with a bad shape\n");
00180     }
00181     return false;
00182   }
00183 
00184   // Insert the new pain point into pain_points_heap_.
00185   if (pain_points_heaps_[pp_type].size() < max_heap_size_) {
00186     // Compute pain point priority.
00187     float priority;
00188     if (pp_type == LM_PPTYPE_PATH) {
00189       priority = special_priority;
00190     } else {
00191       priority = associate_stats.gap_sum;
00192     }
00193     MatrixCoordPair pain_point(priority, MATRIX_COORD(col, row));
00194     pain_points_heaps_[pp_type].Push(&pain_point);
00195     if (debug_level_) {
00196       tprintf("Added pain point with priority %g\n", priority);
00197     }
00198     return true;
00199   } else {
00200     if (debug_level_) tprintf("Pain points heap is full\n");
00201     return false;
00202   }
00203 }
00204 
00205 // Adjusts the pain point coordinates to cope with expansion of the ratings
00206 // matrix due to a split of the blob with the given index.
00207 void LMPainPoints::RemapForSplit(int index) {
00208   for (int i = 0; i < LM_PPTYPE_NUM; ++i) {
00209     GenericVector<MatrixCoordPair>* heap = pain_points_heaps_[i].heap();
00210     for (int j = 0; j < heap->size(); ++j)
00211       (*heap)[j].data.MapForSplit(index);
00212   }
00213 }
00214 
00215 }  //  namespace tesseract
00216 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines