tesseract v5.3.3.20231005
tesseract::ClassPruner Class Reference

Public Member Functions

 ClassPruner (int max_classes)
 
 ~ClassPruner ()
 
void ComputeScores (const INT_TEMPLATES_STRUCT *int_templates, int num_features, const INT_FEATURE_STRUCT *features)
 
void AdjustForExpectedNumFeatures (const uint16_t *expected_num_features, int cutoff_strength)
 
void DisableDisabledClasses (const UNICHARSET &unicharset)
 
void DisableFragments (const UNICHARSET &unicharset)
 
void NormalizeForXheight (int norm_multiplier, const uint8_t *normalization_factors)
 
void NoNormalization ()
 
void PruneAndSort (int pruning_factor, int keep_this, bool max_of_non_fragments, const UNICHARSET &unicharset)
 
void DebugMatch (const Classify &classify, const INT_TEMPLATES_STRUCT *int_templates, const INT_FEATURE_STRUCT *features) const
 
void SummarizeResult (const Classify &classify, const INT_TEMPLATES_STRUCT *int_templates, const uint16_t *expected_num_features, int norm_multiplier, const uint8_t *normalization_factors) const
 
int SetupResults (std::vector< CP_RESULT_STRUCT > *results) const
 

Detailed Description

Definition at line 132 of file intmatcher.cpp.

Constructor & Destructor Documentation

◆ ClassPruner()

tesseract::ClassPruner::ClassPruner ( int  max_classes)
inline

Definition at line 134 of file intmatcher.cpp.

134 {
135 // The unrolled loop in ComputeScores means that the array sizes need to
136 // be rounded up so that the array is big enough to accommodate the extra
137 // entries accessed by the unrolling. Each pruner word is of sized
138 // BITS_PER_WERD and each entry is NUM_BITS_PER_CLASS, so there are
139 // BITS_PER_WERD / NUM_BITS_PER_CLASS entries.
140 // See ComputeScores.
141 max_classes_ = max_classes;
142 rounded_classes_ =
144 class_count_ = new int[rounded_classes_];
145 norm_count_ = new int[rounded_classes_];
146 sort_key_ = new int[rounded_classes_ + 1];
147 sort_index_ = new int[rounded_classes_ + 1];
148 for (int i = 0; i < rounded_classes_; i++) {
149 class_count_[i] = 0;
150 }
151 pruning_threshold_ = 0;
152 num_features_ = 0;
153 num_classes_ = 0;
154 }
#define BITS_PER_WERD
Definition: intproto.h:45
#define WERDS_PER_CP_VECTOR
Definition: intproto.h:61
#define NUM_BITS_PER_CLASS
Definition: intproto.h:55
int RoundUp(int n, int block_size)
Definition: helpers.h:99

◆ ~ClassPruner()

tesseract::ClassPruner::~ClassPruner ( )
inline

Definition at line 156 of file intmatcher.cpp.

156 {
157 delete[] class_count_;
158 delete[] norm_count_;
159 delete[] sort_key_;
160 delete[] sort_index_;
161 }

Member Function Documentation

◆ AdjustForExpectedNumFeatures()

void tesseract::ClassPruner::AdjustForExpectedNumFeatures ( const uint16_t *  expected_num_features,
int  cutoff_strength 
)
inline

Adjusts the scores according to the number of expected features. Used in lieu of a constant bias, this penalizes classes that expect more features than there are present. Thus an actual c will score higher for c than e, even though almost all the features match e as well as c, because e expects more features to be present.

Definition at line 235 of file intmatcher.cpp.

235 {
236 for (int class_id = 0; class_id < max_classes_; ++class_id) {
237 if (num_features_ < expected_num_features[class_id]) {
238 int deficit = expected_num_features[class_id] - num_features_;
239 class_count_[class_id] -=
240 class_count_[class_id] * deficit / (num_features_ * cutoff_strength + deficit);
241 }
242 }
243 }

◆ ComputeScores()

void tesseract::ClassPruner::ComputeScores ( const INT_TEMPLATES_STRUCT int_templates,
int  num_features,
const INT_FEATURE_STRUCT features 
)
inline

Computes the scores for every class in the character set, by summing the weights for each feature and stores the sums internally in class_count_.

Definition at line 165 of file intmatcher.cpp.

166 {
167 num_features_ = num_features;
168 auto num_pruners = int_templates->NumClassPruners;
169 for (int f = 0; f < num_features; ++f) {
170 const INT_FEATURE_STRUCT *feature = &features[f];
171 // Quantize the feature to NUM_CP_BUCKETS*NUM_CP_BUCKETS*NUM_CP_BUCKETS.
172 int x = feature->X * NUM_CP_BUCKETS >> 8;
173 int y = feature->Y * NUM_CP_BUCKETS >> 8;
174 int theta = feature->Theta * NUM_CP_BUCKETS >> 8;
175 int class_id = 0;
176 // Each CLASS_PRUNER_STRUCT only covers CLASSES_PER_CP(32) classes, so
177 // we need a collection of them, indexed by pruner_set.
178 for (unsigned pruner_set = 0; pruner_set < num_pruners; ++pruner_set) {
179 // Look up quantized feature in a 3-D array, an array of weights for
180 // each class.
181 const uint32_t *pruner_word_ptr = int_templates->ClassPruners[pruner_set]->p[x][y][theta];
182 for (int word = 0; word < WERDS_PER_CP_VECTOR; ++word) {
183 uint32_t pruner_word = *pruner_word_ptr++;
184 // This inner loop is unrolled to speed up the ClassPruner.
185 // Currently gcc would not unroll it unless it is set to O3
186 // level of optimization or -funroll-loops is specified.
187 /*
188uint32_t class_mask = (1 << NUM_BITS_PER_CLASS) - 1;
189for (int bit = 0; bit < BITS_PER_WERD/NUM_BITS_PER_CLASS; bit++) {
190 class_count_[class_id++] += pruner_word & class_mask;
191 pruner_word >>= NUM_BITS_PER_CLASS;
192}
193*/
194 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
195 pruner_word >>= NUM_BITS_PER_CLASS;
196 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
197 pruner_word >>= NUM_BITS_PER_CLASS;
198 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
199 pruner_word >>= NUM_BITS_PER_CLASS;
200 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
201 pruner_word >>= NUM_BITS_PER_CLASS;
202 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
203 pruner_word >>= NUM_BITS_PER_CLASS;
204 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
205 pruner_word >>= NUM_BITS_PER_CLASS;
206 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
207 pruner_word >>= NUM_BITS_PER_CLASS;
208 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
209 pruner_word >>= NUM_BITS_PER_CLASS;
210 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
211 pruner_word >>= NUM_BITS_PER_CLASS;
212 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
213 pruner_word >>= NUM_BITS_PER_CLASS;
214 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
215 pruner_word >>= NUM_BITS_PER_CLASS;
216 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
217 pruner_word >>= NUM_BITS_PER_CLASS;
218 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
219 pruner_word >>= NUM_BITS_PER_CLASS;
220 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
221 pruner_word >>= NUM_BITS_PER_CLASS;
222 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
223 pruner_word >>= NUM_BITS_PER_CLASS;
224 class_count_[class_id++] += pruner_word & CLASS_PRUNER_CLASS_MASK;
225 }
226 }
227 }
228 }
#define CLASS_PRUNER_CLASS_MASK
Definition: intproto.h:56
#define NUM_CP_BUCKETS
Definition: intproto.h:53
const double y

◆ DebugMatch()

void tesseract::ClassPruner::DebugMatch ( const Classify classify,
const INT_TEMPLATES_STRUCT int_templates,
const INT_FEATURE_STRUCT features 
) const
inline

Prints debug info on the class pruner matches for the pruned classes only.

Definition at line 324 of file intmatcher.cpp.

325 {
326 int num_pruners = int_templates->NumClassPruners;
327 int max_num_classes = int_templates->NumClasses;
328 for (int f = 0; f < num_features_; ++f) {
329 const INT_FEATURE_STRUCT *feature = &features[f];
330 tprintf("F=%3d(%d,%d,%d),", f, feature->X, feature->Y, feature->Theta);
331 // Quantize the feature to NUM_CP_BUCKETS*NUM_CP_BUCKETS*NUM_CP_BUCKETS.
332 int x = feature->X * NUM_CP_BUCKETS >> 8;
333 int y = feature->Y * NUM_CP_BUCKETS >> 8;
334 int theta = feature->Theta * NUM_CP_BUCKETS >> 8;
335 int class_id = 0;
336 for (int pruner_set = 0; pruner_set < num_pruners; ++pruner_set) {
337 // Look up quantized feature in a 3-D array, an array of weights for
338 // each class.
339 const uint32_t *pruner_word_ptr = int_templates->ClassPruners[pruner_set]->p[x][y][theta];
340 for (int word = 0; word < WERDS_PER_CP_VECTOR; ++word) {
341 uint32_t pruner_word = *pruner_word_ptr++;
342 for (int word_class = 0; word_class < 16 && class_id < max_num_classes;
343 ++word_class, ++class_id) {
344 if (norm_count_[class_id] >= pruning_threshold_) {
345 tprintf(" %s=%d,", classify.ClassIDToDebugStr(int_templates, class_id, 0).c_str(),
346 pruner_word & CLASS_PRUNER_CLASS_MASK);
347 }
348 pruner_word >>= NUM_BITS_PER_CLASS;
349 }
350 }
351 tprintf("\n");
352 }
353 }
354 }
void tprintf(const char *format,...)
Definition: tprintf.cpp:41

◆ DisableDisabledClasses()

void tesseract::ClassPruner::DisableDisabledClasses ( const UNICHARSET unicharset)
inline

Zeros the scores for classes disabled in the unicharset. Implements the black-list to recognize a subset of the character set.

Definition at line 247 of file intmatcher.cpp.

247 {
248 for (int class_id = 0; class_id < max_classes_; ++class_id) {
249 if (!unicharset.get_enabled(class_id)) {
250 class_count_[class_id] = 0; // This char is disabled!
251 }
252 }
253 }

◆ DisableFragments()

void tesseract::ClassPruner::DisableFragments ( const UNICHARSET unicharset)
inline

Zeros the scores of fragments.

Definition at line 256 of file intmatcher.cpp.

256 {
257 for (int class_id = 0; class_id < max_classes_; ++class_id) {
258 // Do not include character fragments in the class pruner
259 // results if disable_character_fragments is true.
260 if (unicharset.get_fragment(class_id)) {
261 class_count_[class_id] = 0;
262 }
263 }
264 }

◆ NoNormalization()

void tesseract::ClassPruner::NoNormalization ( )
inline

The nop normalization copies the class_count_ array to norm_count_.

Definition at line 278 of file intmatcher.cpp.

278 {
279 for (int class_id = 0; class_id < max_classes_; class_id++) {
280 norm_count_[class_id] = class_count_[class_id];
281 }
282 }

◆ NormalizeForXheight()

void tesseract::ClassPruner::NormalizeForXheight ( int  norm_multiplier,
const uint8_t *  normalization_factors 
)
inline

Normalizes the counts for xheight, putting the normalized result in norm_count_. Applies a simple subtractive penalty for incorrect vertical position provided by the normalization_factors array, indexed by character class, and scaled by the norm_multiplier.

Definition at line 270 of file intmatcher.cpp.

270 {
271 for (int class_id = 0; class_id < max_classes_; class_id++) {
272 norm_count_[class_id] =
273 class_count_[class_id] - ((norm_multiplier * normalization_factors[class_id]) >> 8);
274 }
275 }

◆ PruneAndSort()

void tesseract::ClassPruner::PruneAndSort ( int  pruning_factor,
int  keep_this,
bool  max_of_non_fragments,
const UNICHARSET unicharset 
)
inline

Prunes the classes using <the maximum count> * pruning_factor/256 as a threshold for keeping classes. If max_of_non_fragments, then ignore fragments in computing the maximum count.

Definition at line 287 of file intmatcher.cpp.

288 {
289 int max_count = 0;
290 for (int c = 0; c < max_classes_; ++c) {
291 if (norm_count_[c] > max_count &&
292 // This additional check is added in order to ensure that
293 // the classifier will return at least one non-fragmented
294 // character match.
295 // TODO(daria): verify that this helps accuracy and does not
296 // hurt performance.
297 (!max_of_non_fragments || !unicharset.get_fragment(c))) {
298 max_count = norm_count_[c];
299 }
300 }
301 // Prune Classes.
302 pruning_threshold_ = (max_count * pruning_factor) >> 8;
303 // Select Classes.
304 if (pruning_threshold_ < 1) {
305 pruning_threshold_ = 1;
306 }
307 num_classes_ = 0;
308 for (int class_id = 0; class_id < max_classes_; class_id++) {
309 if (norm_count_[class_id] >= pruning_threshold_ || class_id == keep_this) {
310 ++num_classes_;
311 sort_index_[num_classes_] = class_id;
312 sort_key_[num_classes_] = norm_count_[class_id];
313 }
314 }
315
316 // Sort Classes using Heapsort Algorithm.
317 if (num_classes_ > 1) {
318 HeapSort(num_classes_, sort_key_, sort_index_);
319 }
320 }

◆ SetupResults()

int tesseract::ClassPruner::SetupResults ( std::vector< CP_RESULT_STRUCT > *  results) const
inline

Copies the pruned, sorted classes into the output results and returns the number of classes.

Definition at line 374 of file intmatcher.cpp.

374 {
375 results->clear();
376 results->resize(num_classes_);
377 for (int c = 0; c < num_classes_; ++c) {
378 (*results)[c].Class = sort_index_[num_classes_ - c];
379 (*results)[c].Rating =
380 1.0f - sort_key_[num_classes_ - c] /
381 (static_cast<float>(CLASS_PRUNER_CLASS_MASK) * num_features_);
382 }
383 return num_classes_;
384 }

◆ SummarizeResult()

void tesseract::ClassPruner::SummarizeResult ( const Classify classify,
const INT_TEMPLATES_STRUCT int_templates,
const uint16_t *  expected_num_features,
int  norm_multiplier,
const uint8_t *  normalization_factors 
) const
inline

Prints a summary of the pruner result.

Definition at line 357 of file intmatcher.cpp.

359 {
360 tprintf("CP:%d classes, %d features:\n", num_classes_, num_features_);
361 for (int i = 0; i < num_classes_; ++i) {
362 int class_id = sort_index_[num_classes_ - i];
363 std::string class_string = classify.ClassIDToDebugStr(int_templates, class_id, 0);
364 tprintf(
365 "%s:Initial=%d, E=%d, Xht-adj=%d, N=%d, Rat=%.2f\n", class_string.c_str(),
366 class_count_[class_id], expected_num_features[class_id],
367 (norm_multiplier * normalization_factors[class_id]) >> 8, sort_key_[num_classes_ - i],
368 100.0 - 100.0 * sort_key_[num_classes_ - i] / (CLASS_PRUNER_CLASS_MASK * num_features_));
369 }
370 }

The documentation for this class was generated from the following file: