tesseract 4.1.1
Loading...
Searching...
No Matches
lm_pain_points.cpp
Go to the documentation of this file.
1
2// File: pain_points.cpp
3// Description: Functions that utilize the knowledge about the properties
4// of the paths explored by the segmentation search in order
5// to "pain points" - the locations in the ratings matrix
6// which should be classified next.
7// Author: Rika Antonova
8// Created: Mon Jun 20 11:26:43 PST 2012
9//
10// (C) Copyright 2012, Google Inc.
11// Licensed under the Apache License, Version 2.0 (the "License");
12// you may not use this file except in compliance with the License.
13// You may obtain a copy of the License at
14// http://www.apache.org/licenses/LICENSE-2.0
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20//
22
23#include "lm_pain_points.h"
24
25#include "associate.h"
26#include "dict.h"
27#include "genericheap.h"
28#include "lm_state.h"
29#include "matrix.h"
30#include "pageres.h"
31
32#include <algorithm>
33
34namespace tesseract {
35
37const float LMPainPoints::kLooseMaxCharWhRatio = 2.5f;
38
40 for (int h = 0; h < LM_PPTYPE_NUM; ++h) {
41 if (pain_points_heaps_[h].empty()) continue;
42 *priority = pain_points_heaps_[h].PeekTop().key;
43 *pp = pain_points_heaps_[h].PeekTop().data;
44 pain_points_heaps_[h].Pop(nullptr);
45 return static_cast<LMPainPointsType>(h);
46 }
47 return LM_PPTYPE_NUM;
48}
49
51 MATRIX *ratings = word_res->ratings;
52 AssociateStats associate_stats;
53 for (int col = 0; col < ratings->dimension(); ++col) {
54 int row_end = std::min(ratings->dimension(), col + ratings->bandwidth() + 1);
55 for (int row = col + 1; row < row_end; ++row) {
56 MATRIX_COORD coord(col, row);
57 if (coord.Valid(*ratings) &&
58 ratings->get(col, row) != NOT_CLASSIFIED) continue;
59 // Add an initial pain point if needed.
60 if (ratings->Classified(col, row - 1, dict_->WildcardID()) ||
61 (col + 1 < ratings->dimension() &&
62 ratings->Classified(col + 1, row, dict_->WildcardID()))) {
64 true, max_char_wh_ratio_, word_res);
65 }
66 }
67 }
68}
69
70void LMPainPoints::GenerateFromPath(float rating_cert_scale,
72 WERD_RES *word_res) {
73 ViterbiStateEntry *curr_vse = vse;
74 BLOB_CHOICE *curr_b = vse->curr_b;
75 // The following pain point generation and priority calculation approaches
76 // prioritize exploring paths with low average rating of the known part of
77 // the path, while not relying on the ratings of the pieces to be combined.
78 //
79 // A pain point to combine the neighbors is generated for each pair of
80 // neighboring blobs on the path (the path is represented by vse argument
81 // given to GenerateFromPath()). The priority of each pain point is set to
82 // the average rating (per outline length) of the path, not including the
83 // ratings of the blobs to be combined.
84 // The ratings of the blobs to be combined are not used to calculate the
85 // priority, since it is not possible to determine from their magnitude
86 // whether it will be beneficial to combine the blobs. The reason is that
87 // chopped junk blobs (/ | - ') can have very good (low) ratings, however
88 // combining them will be beneficial. Blobs with high ratings might be
89 // over-joined pieces of characters, but also could be blobs from an unseen
90 // font or chopped pieces of complex characters.
91 while (curr_vse->parent_vse != nullptr) {
92 ViterbiStateEntry* parent_vse = curr_vse->parent_vse;
93 const MATRIX_COORD& curr_cell = curr_b->matrix_cell();
94 const MATRIX_COORD& parent_cell = parent_vse->curr_b->matrix_cell();
95 MATRIX_COORD pain_coord(parent_cell.col, curr_cell.row);
96 if (!pain_coord.Valid(*word_res->ratings) ||
97 !word_res->ratings->Classified(parent_cell.col, curr_cell.row,
98 dict_->WildcardID())) {
99 // rat_subtr contains ratings sum of the two adjacent blobs to be merged.
100 // rat_subtr will be subtracted from the ratings sum of the path, since
101 // the blobs will be joined into a new blob, whose rating is yet unknown.
102 float rat_subtr = curr_b->rating() + parent_vse->curr_b->rating();
103 // ol_subtr contains the outline length of the blobs that will be joined.
104 float ol_subtr =
105 AssociateUtils::ComputeOutlineLength(rating_cert_scale, *curr_b) +
106 AssociateUtils::ComputeOutlineLength(rating_cert_scale,
107 *(parent_vse->curr_b));
108 // ol_dif is the outline of the path without the two blobs to be joined.
109 float ol_dif = vse->outline_length - ol_subtr;
110 // priority is set to the average rating of the path per unit of outline,
111 // not counting the ratings of the pieces to be joined.
112 float priority = ol_dif > 0 ? (vse->ratings_sum-rat_subtr)/ol_dif : 0.0;
113 GeneratePainPoint(pain_coord.col, pain_coord.row, LM_PPTYPE_PATH,
114 priority, true, max_char_wh_ratio_, word_res);
115 } else if (debug_level_ > 3) {
116 tprintf("NO pain point (Classified) for col=%d row=%d type=%s\n",
117 pain_coord.col, pain_coord.row,
118 LMPainPointsTypeName[LM_PPTYPE_PATH]);
119 BLOB_CHOICE_IT b_it(word_res->ratings->get(pain_coord.col,
120 pain_coord.row));
121 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
122 BLOB_CHOICE* choice = b_it.data();
123 choice->print_full();
124 }
125 }
126
127 curr_vse = parent_vse;
128 curr_b = curr_vse->curr_b;
129 }
130}
131
134 WERD_RES *word_res) {
135 // Begins and ends in DANGERR vector now record the blob indices as used
136 // by the ratings matrix.
137 for (int d = 0; d < fixpt.size(); ++d) {
138 const DANGERR_INFO &danger = fixpt[d];
139 // Only use dangerous ambiguities.
140 if (danger.dangerous) {
141 GeneratePainPoint(danger.begin, danger.end - 1,
142 LM_PPTYPE_AMBIG, vse->cost, true,
143 kLooseMaxCharWhRatio, word_res);
144 }
145 }
146}
147
149 int col, int row, LMPainPointsType pp_type, float special_priority,
150 bool ok_to_extend, float max_char_wh_ratio,
151 WERD_RES *word_res) {
152 MATRIX_COORD coord(col, row);
153 if (coord.Valid(*word_res->ratings) &&
154 word_res->ratings->Classified(col, row, dict_->WildcardID())) {
155 return false;
156 }
157 if (debug_level_ > 3) {
158 tprintf("Generating pain point for col=%d row=%d type=%s\n",
159 col, row, LMPainPointsTypeName[pp_type]);
160 }
161 // Compute associate stats.
162 AssociateStats associate_stats;
163 AssociateUtils::ComputeStats(col, row, nullptr, 0, fixed_pitch_,
164 max_char_wh_ratio, word_res, debug_level_,
165 &associate_stats);
166 // For fixed-pitch fonts/languages: if the current combined blob overlaps
167 // the next blob on the right and it is ok to extend the blob, try extending
168 // the blob until there is no overlap with the next blob on the right or
169 // until the width-to-height ratio becomes too large.
170 if (ok_to_extend) {
171 while (associate_stats.bad_fixed_pitch_right_gap &&
172 row + 1 < word_res->ratings->dimension() &&
173 !associate_stats.bad_fixed_pitch_wh_ratio) {
174 AssociateUtils::ComputeStats(col, ++row, nullptr, 0, fixed_pitch_,
175 max_char_wh_ratio, word_res, debug_level_,
176 &associate_stats);
177 }
178 }
179 if (associate_stats.bad_shape) {
180 if (debug_level_ > 3) {
181 tprintf("Discarded pain point with a bad shape\n");
182 }
183 return false;
184 }
185
186 // Insert the new pain point into pain_points_heap_.
187 if (pain_points_heaps_[pp_type].size() < max_heap_size_) {
188 // Compute pain point priority.
189 float priority;
190 if (pp_type == LM_PPTYPE_PATH) {
191 priority = special_priority;
192 } else {
193 priority = associate_stats.gap_sum;
194 }
195 MatrixCoordPair pain_point(priority, MATRIX_COORD(col, row));
196 pain_points_heaps_[pp_type].Push(&pain_point);
197 if (debug_level_) {
198 tprintf("Added pain point with priority %g\n", priority);
199 }
200 return true;
201 } else {
202 if (debug_level_) tprintf("Pain points heap is full\n");
203 return false;
204 }
205}
206
212 for (auto & pain_points_heap : pain_points_heaps_) {
213 GenericVector<MatrixCoordPair>* heap = pain_points_heap.heap();
214 for (int j = 0; j < heap->size(); ++j)
215 (*heap)[j].data.MapForSplit(index);
216 }
217}
218
219} // namespace tesseract
#define NOT_CLASSIFIED
Definition: matrix.h:44
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
int size() const
Definition: genericvector.h:72
T get(ICOORD pos) const
Definition: matrix.h:231
int bandwidth() const
Definition: matrix.h:538
int dimension() const
Definition: matrix.h:536
Definition: matrix.h:578
bool Classified(int col, int row, int wildcard_id) const
Definition: matrix.cpp:36
bool Valid(const MATRIX &m) const
Definition: matrix.h:618
MATRIX * ratings
Definition: pageres.h:237
const MATRIX_COORD & matrix_cell()
Definition: ratngs.h:117
float rating() const
Definition: ratngs.h:80
void print_full() const
Definition: ratngs.h:177
const Pair & PeekTop() const
Definition: genericheap.h:108
bool Pop(Pair *entry)
Definition: genericheap.h:118
void Push(Pair *entry)
Definition: genericheap.h:95
UNICHAR_ID WildcardID() const
Definition: dict.h:428
int begin
Definition: stopper.h:40
bool dangerous
Definition: stopper.h:42
static float ComputeOutlineLength(float rating_cert_scale, const BLOB_CHOICE &b)
Definition: associate.h:80
static void ComputeStats(int col, int row, const AssociateStats *parent_stats, int parent_path_length, bool fixed_pitch, float max_char_wh_ratio, WERD_RES *word_res, bool debug, AssociateStats *stats)
Definition: associate.cpp:34
bool GeneratePainPoint(int col, int row, LMPainPointsType pp_type, float special_priority, bool ok_to_extend, float max_char_wh_ratio, WERD_RES *word_res)
void RemapForSplit(int index)
void GenerateInitial(WERD_RES *word_res)
void GenerateFromPath(float rating_cert_scale, ViterbiStateEntry *vse, WERD_RES *word_res)
static const float kLooseMaxCharWhRatio
static const float kDefaultPainPointPriorityAdjustment
void GenerateFromAmbigs(const DANGERR &fixpt, ViterbiStateEntry *vse, WERD_RES *word_res)
LMPainPointsType Deque(MATRIX_COORD *pp, float *priority)
float outline_length
length of the outline so far
Definition: lm_state.h:186
BLOB_CHOICE * curr_b
Pointers to BLOB_CHOICE and parent ViterbiStateEntry (not owned by this).
Definition: lm_state.h:158
ViterbiStateEntry * parent_vse
Definition: lm_state.h:159
float ratings_sum
sum of ratings of character on the path
Definition: lm_state.h:182