Commit 4e3ec57f for tesseract
commit 4e3ec57f3039fd09e183f6884b8e1b70a57e9b0f
Author: Stefan Weil <sw@weilnetz.de>
Date: Tue Nov 10 19:49:39 2026 +0100
wordrec: stop the diacritics reassignment when the budget is used up
ReassignDiacritics() only checks the classification budget before it
starts, but it classifies the noise outlines with many trial words
(ClassifyBlobAsWord() via SelectGoodDiacriticOutlines()), and the budget
is enforced between words. When the budget is used up during the trials,
the remaining trials get the fake result of a skipped word, whose raw
choice has certainty -1 (and a certainty of -0.1 for a new blob, where
the negated squared certainty over the rating is used). That beats the
thresholds noise_cert_basechar (-8), noise_cert_punc (-3) and
noise_cert_disjoint (-1), so unclassified noise would be added to the
word as diacritics.
Check the budget in SelectGoodDiacriticOutlines() before every trial
and give up without changing the outlines when no language can classify
any more. Decisions which were already made with real classifications
are kept.
Assisted-by: Claude Fable 5.1 (Anthropic)
Signed-off-by: Stefan Weil <sw@weilnetz.de>
diff --git a/src/ccmain/control.cpp b/src/ccmain/control.cpp
index c11f1650..235186fd 100644
--- a/src/ccmain/control.cpp
+++ b/src/ccmain/control.cpp
@@ -1182,6 +1182,13 @@ bool Tesseract::SelectGoodDiacriticOutlines(int pass, float certainty_threshold,
C_BLOB *blob,
const std::vector<C_OUTLINE *> &outlines,
int num_outlines, std::vector<bool> *ok_outlines) {
+ // The classification budget is enforced between words, so once it is used
+ // up, ClassifyBlobAsWord() returns the certainty of a fake result, which
+ // would beat the threshold. Give up before every probe when no language can
+ // classify any more, without touching the outlines.
+ if (AllClassificationBudgetsExhausted()) {
+ return false;
+ }
float target_cert = certainty_threshold;
if (blob != nullptr) {
std::string best_str;
@@ -1193,6 +1200,9 @@ bool Tesseract::SelectGoodDiacriticOutlines(int pass, float certainty_threshold,
blob->bounding_box().print();
}
target_cert -= (target_cert - certainty_threshold) * noise_cert_factor;
+ if (AllClassificationBudgetsExhausted()) {
+ return false;
+ }
}
std::vector<bool> test_outlines = *ok_outlines;
// Start with all the outlines in.
@@ -1218,6 +1228,9 @@ bool Tesseract::SelectGoodDiacriticOutlines(int pass, float certainty_threshold,
best_index = -1;
for (unsigned i = 0; i < outlines.size(); ++i) {
if (test_outlines[i]) {
+ if (AllClassificationBudgetsExhausted()) {
+ return false;
+ }
test_outlines[i] = false;
std::string str;
float cert = ClassifyBlobPlusOutlines(test_outlines, outlines, pass, pr_it, blob, str);