Coverage Report

Created: 2025-06-13 07:15

/src/tesseract/src/ccmain/tesseractclass.cpp
Line
Count
Source (jump to first uncovered line)
1
///////////////////////////////////////////////////////////////////////
2
// File:        tesseractclass.cpp
3
// Description: The Tesseract class. It holds/owns everything needed
4
//              to run Tesseract on a single language, and also a set of
5
//              sub-Tesseracts to run sub-languages. For thread safety, *every*
6
//              variable that was previously global or static (except for
7
//              constant data, and some visual debugging flags) has been moved
8
//              in here, directly, or indirectly.
9
//              This makes it safe to run multiple Tesseracts in different
10
//              threads in parallel, and keeps the different language
11
//              instances separate.
12
//              Some global functions remain, but they are isolated re-entrant
13
//              functions that operate on their arguments. Functions that work
14
//              on variable data have been moved to an appropriate class based
15
//              mostly on the directory hierarchy. For more information see
16
//              slide 6 of "2ArchitectureAndDataStructures" in
17
// https://drive.google.com/file/d/0B7l10Bj_LprhbUlIUFlCdGtDYkE/edit?usp=sharing
18
//              Some global data and related functions still exist in the
19
//              training-related code, but they don't interfere with normal
20
//              recognition operation.
21
// Author:      Ray Smith
22
//
23
// (C) Copyright 2008, Google Inc.
24
// Licensed under the Apache License, Version 2.0 (the "License");
25
// you may not use this file except in compliance with the License.
26
// You may obtain a copy of the License at
27
// http://www.apache.org/licenses/LICENSE-2.0
28
// Unless required by applicable law or agreed to in writing, software
29
// distributed under the License is distributed on an "AS IS" BASIS,
30
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
// See the License for the specific language governing permissions and
32
// limitations under the License.
33
//
34
///////////////////////////////////////////////////////////////////////
35
36
// Include automatically generated configuration file if running autoconf.
37
#ifdef HAVE_CONFIG_H
38
#  include "config_auto.h"
39
#endif
40
41
#include "tesseractclass.h"
42
43
#include <allheaders.h>
44
#include "edgblob.h"
45
#ifndef DISABLED_LEGACY_ENGINE
46
#  include "equationdetect.h"
47
#endif
48
#include "lstmrecognizer.h"
49
#include "thresholder.h" // for ThresholdMethod
50
51
namespace tesseract {
52
53
Tesseract::Tesseract()
54
4
    : BOOL_MEMBER(tessedit_resegment_from_boxes, false,
55
                  "Take segmentation and labeling from box file", this->params())
56
4
    , BOOL_MEMBER(tessedit_resegment_from_line_boxes, false,
57
                  "Conversion of word/line box file to char box file", this->params())
58
4
    , BOOL_MEMBER(tessedit_train_from_boxes, false, "Generate training data from boxed chars",
59
                  this->params())
60
4
    , BOOL_MEMBER(tessedit_make_boxes_from_boxes, false, "Generate more boxes from boxed chars",
61
                  this->params())
62
4
    , BOOL_MEMBER(tessedit_train_line_recognizer, false,
63
                  "Break input into lines and remap boxes if present", this->params())
64
4
    , BOOL_MEMBER(tessedit_dump_pageseg_images, false,
65
                  "Dump intermediate images made during page segmentation", this->params())
66
    // TODO: remove deprecated tessedit_do_invert in release 6.
67
4
    , BOOL_MEMBER(tessedit_do_invert, true,
68
                  "Try inverted line image if necessary (deprecated, will be "
69
                  "removed in release 6, use the 'invert_threshold' parameter instead)",
70
                  this->params())
71
4
    , double_MEMBER(invert_threshold, 0.7,
72
                    "For lines with a mean confidence below this value, OCR is also tried with an inverted image",
73
                    this->params())
74
    ,
75
    // The default for pageseg_mode is the old behaviour, so as not to
76
    // upset anything that relies on that.
77
4
    INT_MEMBER(tessedit_pageseg_mode, PSM_SINGLE_BLOCK,
78
               "Page seg mode: 0=osd only, 1=auto+osd, 2=auto_only, 3=auto, "
79
               "4=column,"
80
               " 5=block_vert, 6=block, 7=line, 8=word, 9=word_circle, 10=char,"
81
               "11=sparse_text, 12=sparse_text+osd, 13=raw_line"
82
               " (Values from PageSegMode enum in tesseract/publictypes.h)",
83
               this->params())
84
4
    , INT_MEMBER(thresholding_method,
85
                 static_cast<int>(ThresholdMethod::Otsu),
86
                 "Thresholding method: 0 = Otsu, 1 = LeptonicaOtsu, 2 = "
87
                 "Sauvola",
88
                 this->params())
89
4
    , BOOL_MEMBER(thresholding_debug, false,
90
                  "Debug the thresholding process",
91
                  this->params())
92
4
    , double_MEMBER(thresholding_window_size, 0.33,
93
                    "Window size for measuring local statistics (to be "
94
                    "multiplied by image DPI). "
95
                    "This parameter is used by the Sauvola thresholding method",
96
                    this->params())
97
4
    , double_MEMBER(thresholding_kfactor, 0.34,
98
                    "Factor for reducing threshold due to variance. "
99
                    "This parameter is used by the Sauvola thresholding method."
100
                    " Normal range: 0.2-0.5",
101
                    this->params())
102
4
    , double_MEMBER(thresholding_tile_size, 0.33,
103
                    "Desired tile size (to be multiplied by image DPI). "
104
                    "This parameter is used by the LeptonicaOtsu thresholding "
105
                    "method",
106
                    this->params())
107
4
    , double_MEMBER(thresholding_smooth_kernel_size, 0.0,
108
                    "Size of convolution kernel applied to threshold array "
109
                    "(to be multiplied by image DPI). Use 0 for no smoothing. "
110
                    "This parameter is used by the LeptonicaOtsu thresholding "
111
                    "method",
112
                    this->params())
113
4
    , double_MEMBER(thresholding_score_fraction, 0.1,
114
                    "Fraction of the max Otsu score. "
115
                    "This parameter is used by the LeptonicaOtsu thresholding "
116
                    "method. "
117
                    "For standard Otsu use 0.0, otherwise 0.1 is recommended",
118
                    this->params())
119
4
    , INT_INIT_MEMBER(tessedit_ocr_engine_mode, tesseract::OEM_DEFAULT,
120
                      "Which OCR engine(s) to run (Tesseract, LSTM, both)."
121
                      " Defaults to loading and running the most accurate"
122
                      " available.",
123
                      this->params())
124
4
    , STRING_MEMBER(tessedit_char_blacklist, "", "Blacklist of chars not to recognize",
125
                    this->params())
126
4
    , STRING_MEMBER(tessedit_char_whitelist, "", "Whitelist of chars to recognize", this->params())
127
4
    , STRING_MEMBER(tessedit_char_unblacklist, "",
128
                    "List of chars to override tessedit_char_blacklist", this->params())
129
4
    , BOOL_MEMBER(tessedit_ambigs_training, false, "Perform training for ambiguities",
130
                  this->params())
131
4
    , INT_MEMBER(pageseg_devanagari_split_strategy, tesseract::ShiroRekhaSplitter::NO_SPLIT,
132
                 "Whether to use the top-line splitting process for Devanagari "
133
                 "documents while performing page-segmentation.",
134
                 this->params())
135
4
    , INT_MEMBER(ocr_devanagari_split_strategy, tesseract::ShiroRekhaSplitter::NO_SPLIT,
136
                 "Whether to use the top-line splitting process for Devanagari "
137
                 "documents while performing ocr.",
138
                 this->params())
139
4
    , STRING_MEMBER(tessedit_write_params_to_file, "", "Write all parameters to the given file.",
140
                    this->params())
141
4
    , BOOL_MEMBER(tessedit_adaption_debug, false,
142
                  "Generate and print debug"
143
                  " information for adaption",
144
                  this->params())
145
4
    , INT_MEMBER(bidi_debug, 0, "Debug level for BiDi", this->params())
146
4
    , INT_MEMBER(applybox_debug, 1, "Debug level", this->params())
147
4
    , INT_MEMBER(applybox_page, 0, "Page number to apply boxes from", this->params())
148
4
    , STRING_MEMBER(applybox_exposure_pattern, ".exp",
149
                    "Exposure value follows"
150
                    " this pattern in the image filename. The name of the image"
151
                    " files are expected to be in the form"
152
                    " [lang].[fontname].exp[num].tif",
153
                    this->params())
154
4
    , BOOL_MEMBER(applybox_learn_chars_and_char_frags_mode, false,
155
                  "Learn both character fragments (as is done in the"
156
                  " special low exposure mode) as well as unfragmented"
157
                  " characters.",
158
                  this->params())
159
4
    , BOOL_MEMBER(applybox_learn_ngrams_mode, false,
160
                  "Each bounding box"
161
                  " is assumed to contain ngrams. Only learn the ngrams"
162
                  " whose outlines overlap horizontally.",
163
                  this->params())
164
4
    , BOOL_MEMBER(tessedit_display_outwords, false, "Draw output words", this->params())
165
4
    , BOOL_MEMBER(tessedit_dump_choices, false, "Dump char choices", this->params())
166
4
    , BOOL_MEMBER(tessedit_timing_debug, false, "Print timing stats", this->params())
167
4
    , BOOL_MEMBER(tessedit_fix_fuzzy_spaces, true, "Try to improve fuzzy spaces", this->params())
168
4
    , BOOL_MEMBER(tessedit_unrej_any_wd, false, "Don't bother with word plausibility",
169
                  this->params())
170
4
    , BOOL_MEMBER(tessedit_fix_hyphens, true, "Crunch double hyphens?", this->params())
171
4
    , BOOL_MEMBER(tessedit_enable_doc_dict, true, "Add words to the document dictionary",
172
                  this->params())
173
4
    , BOOL_MEMBER(tessedit_debug_fonts, false, "Output font info per char", this->params())
174
4
    , INT_MEMBER(tessedit_font_id, 0, "Font ID to use or zero", this->params())
175
4
    , BOOL_MEMBER(tessedit_debug_block_rejection, false, "Block and Row stats", this->params())
176
4
    , BOOL_MEMBER(tessedit_enable_bigram_correction, true,
177
                  "Enable correction based on the word bigram dictionary.", this->params())
178
4
    , BOOL_MEMBER(tessedit_enable_dict_correction, false,
179
                  "Enable single word correction based on the dictionary.", this->params())
180
4
    , INT_MEMBER(tessedit_bigram_debug, 0, "Amount of debug output for bigram correction.",
181
                 this->params())
182
4
    , BOOL_MEMBER(enable_noise_removal, true,
183
                  "Remove and conditionally reassign small outlines when they"
184
                  " confuse layout analysis, determining diacritics vs noise",
185
                  this->params())
186
4
    , INT_MEMBER(debug_noise_removal, 0, "Debug reassignment of small outlines", this->params())
187
    ,
188
    // Worst (min) certainty, for which a diacritic is allowed to make the
189
    // base
190
    // character worse and still be included.
191
4
    double_MEMBER(noise_cert_basechar, -8.0, "Hingepoint for base char certainty", this->params())
192
    ,
193
    // Worst (min) certainty, for which a non-overlapping diacritic is allowed
194
    // to make the base character worse and still be included.
195
4
    double_MEMBER(noise_cert_disjoint, -1.0, "Hingepoint for disjoint certainty", this->params())
196
    ,
197
    // Worst (min) certainty, for which a diacritic is allowed to make a new
198
    // stand-alone blob.
199
4
    double_MEMBER(noise_cert_punc, -3.0, "Threshold for new punc char certainty", this->params())
200
    ,
201
    // Factor of certainty margin for adding diacritics to not count as worse.
202
4
    double_MEMBER(noise_cert_factor, 0.375, "Scaling on certainty diff from Hingepoint",
203
                  this->params())
204
4
    , INT_MEMBER(noise_maxperblob, 8, "Max diacritics to apply to a blob", this->params())
205
4
    , INT_MEMBER(noise_maxperword, 16, "Max diacritics to apply to a word", this->params())
206
4
    , INT_MEMBER(debug_x_ht_level, 0, "Reestimate debug", this->params())
207
4
    , STRING_MEMBER(chs_leading_punct, "('`\"", "Leading punctuation", this->params())
208
4
    , STRING_MEMBER(chs_trailing_punct1, ").,;:?!", "1st Trailing punctuation", this->params())
209
4
    , STRING_MEMBER(chs_trailing_punct2, ")'`\"", "2nd Trailing punctuation", this->params())
210
4
    , double_MEMBER(quality_rej_pc, 0.08, "good_quality_doc lte rejection limit", this->params())
211
4
    , double_MEMBER(quality_blob_pc, 0.0, "good_quality_doc gte good blobs limit", this->params())
212
4
    , double_MEMBER(quality_outline_pc, 1.0, "good_quality_doc lte outline error limit",
213
                    this->params())
214
4
    , double_MEMBER(quality_char_pc, 0.95, "good_quality_doc gte good char limit", this->params())
215
4
    , INT_MEMBER(quality_min_initial_alphas_reqd, 2, "alphas in a good word", this->params())
216
4
    , INT_MEMBER(tessedit_tess_adaption_mode, 0x27, "Adaptation decision algorithm for tess",
217
                 this->params())
218
4
    , BOOL_MEMBER(tessedit_minimal_rej_pass1, false, "Do minimal rejection on pass 1 output",
219
                  this->params())
220
4
    , BOOL_MEMBER(tessedit_test_adaption, false, "Test adaption criteria", this->params())
221
4
    , BOOL_MEMBER(test_pt, false, "Test for point", this->params())
222
4
    , double_MEMBER(test_pt_x, 99999.99, "xcoord", this->params())
223
4
    , double_MEMBER(test_pt_y, 99999.99, "ycoord", this->params())
224
4
    , INT_MEMBER(multilang_debug_level, 0, "Print multilang debug info.", this->params())
225
4
    , INT_MEMBER(paragraph_debug_level, 0, "Print paragraph debug info.", this->params())
226
4
    , BOOL_MEMBER(paragraph_text_based, true,
227
                  "Run paragraph detection on the post-text-recognition "
228
                  "(more accurate)",
229
                  this->params())
230
4
    , BOOL_MEMBER(lstm_use_matrix, 1, "Use ratings matrix/beam search with lstm", this->params())
231
4
    , STRING_MEMBER(outlines_odd, "%| ", "Non standard number of outlines", this->params())
232
4
    , STRING_MEMBER(outlines_2, "ij!?%\":;", "Non standard number of outlines", this->params())
233
4
    , BOOL_MEMBER(tessedit_good_quality_unrej, true, "Reduce rejection on good docs",
234
                  this->params())
235
4
    , BOOL_MEMBER(tessedit_use_reject_spaces, true, "Reject spaces?", this->params())
236
4
    , double_MEMBER(tessedit_reject_doc_percent, 65.00, "%rej allowed before rej whole doc",
237
                    this->params())
238
4
    , double_MEMBER(tessedit_reject_block_percent, 45.00, "%rej allowed before rej whole block",
239
                    this->params())
240
4
    , double_MEMBER(tessedit_reject_row_percent, 40.00, "%rej allowed before rej whole row",
241
                    this->params())
242
4
    , double_MEMBER(tessedit_whole_wd_rej_row_percent, 70.00,
243
                    "Number of row rejects in whole word rejects"
244
                    " which prevents whole row rejection",
245
                    this->params())
246
4
    , BOOL_MEMBER(tessedit_preserve_blk_rej_perfect_wds, true,
247
                  "Only rej partially rejected words in block rejection", this->params())
248
4
    , BOOL_MEMBER(tessedit_preserve_row_rej_perfect_wds, true,
249
                  "Only rej partially rejected words in row rejection", this->params())
250
4
    , BOOL_MEMBER(tessedit_dont_blkrej_good_wds, false, "Use word segmentation quality metric",
251
                  this->params())
252
4
    , BOOL_MEMBER(tessedit_dont_rowrej_good_wds, false, "Use word segmentation quality metric",
253
                  this->params())
254
4
    , INT_MEMBER(tessedit_preserve_min_wd_len, 2, "Only preserve wds longer than this",
255
                 this->params())
256
4
    , BOOL_MEMBER(tessedit_row_rej_good_docs, true, "Apply row rejection to good docs",
257
                  this->params())
258
4
    , double_MEMBER(tessedit_good_doc_still_rowrej_wd, 1.1,
259
                    "rej good doc wd if more than this fraction rejected", this->params())
260
4
    , BOOL_MEMBER(tessedit_reject_bad_qual_wds, true, "Reject all bad quality wds", this->params())
261
4
    , BOOL_MEMBER(tessedit_debug_doc_rejection, false, "Page stats", this->params())
262
4
    , BOOL_MEMBER(tessedit_debug_quality_metrics, false, "Output data to debug file",
263
                  this->params())
264
4
    , BOOL_MEMBER(bland_unrej, false, "unrej potential with no checks", this->params())
265
4
    , double_MEMBER(quality_rowrej_pc, 1.1, "good_quality_doc gte good char limit", this->params())
266
4
    , BOOL_MEMBER(unlv_tilde_crunching, false, "Mark v.bad words for tilde crunch", this->params())
267
4
    , BOOL_MEMBER(hocr_font_info, false, "Add font info to hocr output", this->params())
268
4
    , BOOL_MEMBER(hocr_char_boxes, false, "Add coordinates for each character to hocr output",
269
                  this->params())
270
4
    , BOOL_MEMBER(crunch_early_merge_tess_fails, true, "Before word crunch?", this->params())
271
4
    , BOOL_MEMBER(crunch_early_convert_bad_unlv_chs, false, "Take out ~^ early?", this->params())
272
4
    , double_MEMBER(crunch_terrible_rating, 80.0, "crunch rating lt this", this->params())
273
4
    , BOOL_MEMBER(crunch_terrible_garbage, true, "As it says", this->params())
274
4
    , double_MEMBER(crunch_poor_garbage_cert, -9.0, "crunch garbage cert lt this", this->params())
275
4
    , double_MEMBER(crunch_poor_garbage_rate, 60, "crunch garbage rating lt this", this->params())
276
4
    , double_MEMBER(crunch_pot_poor_rate, 40, "POTENTIAL crunch rating lt this", this->params())
277
4
    , double_MEMBER(crunch_pot_poor_cert, -8.0, "POTENTIAL crunch cert lt this", this->params())
278
4
    , double_MEMBER(crunch_del_rating, 60, "POTENTIAL crunch rating lt this", this->params())
279
4
    , double_MEMBER(crunch_del_cert, -10.0, "POTENTIAL crunch cert lt this", this->params())
280
4
    , double_MEMBER(crunch_del_min_ht, 0.7, "Del if word ht lt xht x this", this->params())
281
4
    , double_MEMBER(crunch_del_max_ht, 3.0, "Del if word ht gt xht x this", this->params())
282
4
    , double_MEMBER(crunch_del_min_width, 3.0, "Del if word width lt xht x this", this->params())
283
4
    , double_MEMBER(crunch_del_high_word, 1.5, "Del if word gt xht x this above bl", this->params())
284
4
    , double_MEMBER(crunch_del_low_word, 0.5, "Del if word gt xht x this below bl", this->params())
285
4
    , double_MEMBER(crunch_small_outlines_size, 0.6, "Small if lt xht x this", this->params())
286
4
    , INT_MEMBER(crunch_rating_max, 10, "For adj length in rating per ch", this->params())
287
4
    , INT_MEMBER(crunch_pot_indicators, 1, "How many potential indicators needed", this->params())
288
4
    , BOOL_MEMBER(crunch_leave_ok_strings, true, "Don't touch sensible strings", this->params())
289
4
    , BOOL_MEMBER(crunch_accept_ok, true, "Use acceptability in okstring", this->params())
290
4
    , BOOL_MEMBER(crunch_leave_accept_strings, false, "Don't pot crunch sensible strings",
291
                  this->params())
292
4
    , BOOL_MEMBER(crunch_include_numerals, false, "Fiddle alpha figures", this->params())
293
4
    , INT_MEMBER(crunch_leave_lc_strings, 4, "Don't crunch words with long lower case strings",
294
                 this->params())
295
4
    , INT_MEMBER(crunch_leave_uc_strings, 4, "Don't crunch words with long lower case strings",
296
                 this->params())
297
4
    , INT_MEMBER(crunch_long_repetitions, 3, "Crunch words with long repetitions", this->params())
298
4
    , INT_MEMBER(crunch_debug, 0, "As it says", this->params())
299
4
    , INT_MEMBER(fixsp_non_noise_limit, 1, "How many non-noise blbs either side?", this->params())
300
4
    , double_MEMBER(fixsp_small_outlines_size, 0.28, "Small if lt xht x this", this->params())
301
4
    , BOOL_MEMBER(tessedit_prefer_joined_punct, false, "Reward punctuation joins", this->params())
302
4
    , INT_MEMBER(fixsp_done_mode, 1, "What constitutes done for spacing", this->params())
303
4
    , INT_MEMBER(debug_fix_space_level, 0, "Contextual fixspace debug", this->params())
304
4
    , STRING_MEMBER(numeric_punctuation, ".,", "Punct. chs expected WITHIN numbers", this->params())
305
4
    , INT_MEMBER(x_ht_acceptance_tolerance, 8,
306
                 "Max allowed deviation of blob top outside of font data", this->params())
307
4
    , INT_MEMBER(x_ht_min_change, 8, "Min change in xht before actually trying it", this->params())
308
4
    , INT_MEMBER(superscript_debug, 0, "Debug level for sub & superscript fixer", this->params())
309
4
    , double_MEMBER(superscript_worse_certainty, 2.0,
310
                    "How many times worse "
311
                    "certainty does a superscript position glyph need to be for "
312
                    "us to try classifying it as a char with a different "
313
                    "baseline?",
314
                    this->params())
315
4
    , double_MEMBER(superscript_bettered_certainty, 0.97,
316
                    "What reduction in "
317
                    "badness do we think sufficient to choose a superscript "
318
                    "over what we'd thought.  For example, a value of 0.6 means "
319
                    "we want to reduce badness of certainty by at least 40%",
320
                    this->params())
321
4
    , double_MEMBER(superscript_scaledown_ratio, 0.4,
322
                    "A superscript scaled down more than this is unbelievably "
323
                    "small.  For example, 0.3 means we expect the font size to "
324
                    "be no smaller than 30% of the text line font size.",
325
                    this->params())
326
4
    , double_MEMBER(subscript_max_y_top, 0.5,
327
                    "Maximum top of a character measured as a multiple of "
328
                    "x-height above the baseline for us to reconsider whether "
329
                    "it's a subscript.",
330
                    this->params())
331
4
    , double_MEMBER(superscript_min_y_bottom, 0.3,
332
                    "Minimum bottom of a character measured as a multiple of "
333
                    "x-height above the baseline for us to reconsider whether "
334
                    "it's a superscript.",
335
                    this->params())
336
4
    , BOOL_MEMBER(tessedit_write_block_separators, false, "Write block separators in output",
337
                  this->params())
338
4
    , BOOL_MEMBER(tessedit_write_rep_codes, false, "Write repetition char code", this->params())
339
4
    , BOOL_MEMBER(tessedit_write_unlv, false, "Write .unlv output file", this->params())
340
4
    , BOOL_MEMBER(tessedit_create_txt, false, "Write .txt output file", this->params())
341
4
    , BOOL_MEMBER(tessedit_create_hocr, false, "Write .html hOCR output file", this->params())
342
4
    , BOOL_MEMBER(tessedit_create_alto, false, "Write .xml ALTO file", this->params())
343
4
    , BOOL_MEMBER(tessedit_create_page_xml, false, "Write .page.xml PAGE file", this->params())
344
4
    , BOOL_MEMBER(page_xml_polygon, true, "Create the PAGE file with polygons instead of box values", this->params())
345
4
    , INT_MEMBER(page_xml_level, 0, "Create the PAGE file on 0=line or 1=word level.", this->params())
346
4
    , BOOL_MEMBER(tessedit_create_lstmbox, false, "Write .box file for LSTM training",
347
                  this->params())
348
4
    , BOOL_MEMBER(tessedit_create_tsv, false, "Write .tsv output file", this->params())
349
4
    , BOOL_MEMBER(tessedit_create_wordstrbox, false, "Write WordStr format .box output file",
350
                  this->params())
351
4
    , BOOL_MEMBER(tessedit_create_pdf, false, "Write .pdf output file", this->params())
352
4
    , BOOL_MEMBER(textonly_pdf, false, "Create PDF with only one invisible text layer",
353
                  this->params())
354
4
    , INT_MEMBER(jpg_quality, 85, "Set JPEG quality level", this->params())
355
4
    , INT_MEMBER(user_defined_dpi, 0, "Specify DPI for input image", this->params())
356
4
    , INT_MEMBER(min_characters_to_try, 50, "Specify minimum characters to try during OSD",
357
                 this->params())
358
4
    , STRING_MEMBER(unrecognised_char, "|", "Output char for unidentified blobs", this->params())
359
4
    , INT_MEMBER(suspect_level, 99, "Suspect marker level", this->params())
360
4
    , INT_MEMBER(suspect_short_words, 2, "Don't suspect dict wds longer than this", this->params())
361
4
    , BOOL_MEMBER(suspect_constrain_1Il, false, "UNLV keep 1Il chars rejected", this->params())
362
4
    , double_MEMBER(suspect_rating_per_ch, 999.9, "Don't touch bad rating limit", this->params())
363
4
    , double_MEMBER(suspect_accept_rating, -999.9, "Accept good rating limit", this->params())
364
4
    , BOOL_MEMBER(tessedit_minimal_rejection, false, "Only reject tess failures", this->params())
365
4
    , BOOL_MEMBER(tessedit_zero_rejection, false, "Don't reject ANYTHING", this->params())
366
4
    , BOOL_MEMBER(tessedit_word_for_word, false, "Make output have exactly one word per WERD",
367
                  this->params())
368
4
    , BOOL_MEMBER(tessedit_zero_kelvin_rejection, false, "Don't reject ANYTHING AT ALL",
369
                  this->params())
370
4
    , INT_MEMBER(tessedit_reject_mode, 0, "Rejection algorithm", this->params())
371
4
    , BOOL_MEMBER(tessedit_rejection_debug, false, "Adaption debug", this->params())
372
4
    , BOOL_MEMBER(tessedit_flip_0O, true, "Contextual 0O O0 flips", this->params())
373
4
    , double_MEMBER(tessedit_lower_flip_hyphen, 1.5, "Aspect ratio dot/hyphen test", this->params())
374
4
    , double_MEMBER(tessedit_upper_flip_hyphen, 1.8, "Aspect ratio dot/hyphen test", this->params())
375
4
    , BOOL_MEMBER(rej_trust_doc_dawg, false, "Use DOC dawg in 11l conf. detector", this->params())
376
4
    , BOOL_MEMBER(rej_1Il_use_dict_word, false, "Use dictword test", this->params())
377
4
    , BOOL_MEMBER(rej_1Il_trust_permuter_type, true, "Don't double check", this->params())
378
4
    , BOOL_MEMBER(rej_use_tess_accepted, true, "Individual rejection control", this->params())
379
4
    , BOOL_MEMBER(rej_use_tess_blanks, true, "Individual rejection control", this->params())
380
4
    , BOOL_MEMBER(rej_use_good_perm, true, "Individual rejection control", this->params())
381
4
    , BOOL_MEMBER(rej_use_sensible_wd, false, "Extend permuter check", this->params())
382
4
    , BOOL_MEMBER(rej_alphas_in_number_perm, false, "Extend permuter check", this->params())
383
4
    , double_MEMBER(rej_whole_of_mostly_reject_word_fract, 0.85, "if >this fract", this->params())
384
4
    , INT_MEMBER(tessedit_image_border, 2, "Rej blbs near image edge limit", this->params())
385
4
    , STRING_MEMBER(ok_repeated_ch_non_alphanum_wds, "-?*\075", "Allow NN to unrej", this->params())
386
4
    , STRING_MEMBER(conflict_set_I_l_1, "Il1[]", "Il1 conflict set", this->params())
387
4
    , INT_MEMBER(min_sane_x_ht_pixels, 8, "Reject any x-ht lt or eq than this", this->params())
388
4
    , BOOL_MEMBER(tessedit_create_boxfile, false, "Output text with boxes", this->params())
389
4
    , INT_MEMBER(tessedit_page_number, -1, "-1 -> All pages, else specific page to process",
390
                 this->params())
391
4
    , BOOL_MEMBER(tessedit_write_images, false, "Capture the image from the IPE", this->params())
392
4
    , BOOL_MEMBER(interactive_display_mode, false, "Run interactively?", this->params())
393
4
    , STRING_MEMBER(file_type, ".tif", "Filename extension", this->params())
394
4
    , BOOL_MEMBER(tessedit_override_permuter, true, "According to dict_word", this->params())
395
4
    , STRING_MEMBER(tessedit_load_sublangs, "", "List of languages to load with this one",
396
                    this->params())
397
4
    , BOOL_MEMBER(tessedit_use_primary_params_model, false,
398
                  "In multilingual mode use params model of the"
399
                  " primary language",
400
                  this->params())
401
4
    , double_MEMBER(min_orientation_margin, 7.0, "Min acceptable orientation margin",
402
                    this->params())
403
4
    , BOOL_MEMBER(textord_tabfind_show_vlines, false, "Debug line finding", this->params())
404
4
    , BOOL_MEMBER(textord_use_cjk_fp_model, false, "Use CJK fixed pitch model", this->params())
405
4
    , BOOL_MEMBER(poly_allow_detailed_fx, false,
406
                  "Allow feature extractors to see the original outline", this->params())
407
4
    , BOOL_INIT_MEMBER(tessedit_init_config_only, false,
408
                       "Only initialize with the config file. Useful if the "
409
                       "instance is not going to be used for OCR but say only "
410
                       "for layout analysis.",
411
                       this->params())
412
#ifndef DISABLED_LEGACY_ENGINE
413
4
    , BOOL_MEMBER(textord_equation_detect, false, "Turn on equation detector", this->params())
414
#endif // ndef DISABLED_LEGACY_ENGINE
415
4
    , BOOL_MEMBER(textord_tabfind_vertical_text, true, "Enable vertical detection", this->params())
416
4
    , BOOL_MEMBER(textord_tabfind_force_vertical_text, false, "Force using vertical text page mode",
417
                  this->params())
418
4
    , double_MEMBER(textord_tabfind_vertical_text_ratio, 0.5,
419
                    "Fraction of textlines deemed vertical to use vertical page "
420
                    "mode",
421
                    this->params())
422
4
    , double_MEMBER(textord_tabfind_aligned_gap_fraction, 0.75,
423
                    "Fraction of height used as a minimum gap for aligned blobs.", this->params())
424
4
    , INT_MEMBER(tessedit_parallelize, 0, "Run in parallel where possible", this->params())
425
4
    , BOOL_MEMBER(preserve_interword_spaces, false, "Preserve multiple interword spaces",
426
                  this->params())
427
4
    , STRING_MEMBER(page_separator, "\f", "Page separator (default is form feed control character)",
428
                    this->params())
429
4
    , INT_MEMBER(lstm_choice_mode, 0,
430
                 "Allows to include alternative symbols choices in the hOCR output. "
431
                 "Valid input values are 0, 1 and 2. 0 is the default value. "
432
                 "With 1 the alternative symbol choices per timestep are included. "
433
                 "With 2 alternative symbol choices are extracted from the CTC "
434
                 "process instead of the lattice. The choices are mapped per "
435
                 "character.",
436
                 this->params())
437
4
    , INT_MEMBER(lstm_choice_iterations, 5,
438
                 "Sets the number of cascading iterations for the Beamsearch in "
439
                 "lstm_choice_mode. Note that lstm_choice_mode must be set to a "
440
                 "value greater than 0 to produce results.",
441
                 this->params())
442
4
    , double_MEMBER(lstm_rating_coefficient, 5,
443
                    "Sets the rating coefficient for the lstm choices. The smaller the "
444
                    "coefficient, the better are the ratings for each choice and less "
445
                    "information is lost due to the cut off at 0. The standard value is "
446
                    "5",
447
                    this->params())
448
4
    , BOOL_MEMBER(pageseg_apply_music_mask, false,
449
                  "Detect music staff and remove intersecting components", this->params())
450
    ,
451
452
4
    backup_config_file_(nullptr)
453
4
    , pix_binary_(nullptr)
454
4
    , pix_grey_(nullptr)
455
4
    , pix_original_(nullptr)
456
4
    , pix_thresholds_(nullptr)
457
4
    , source_resolution_(0)
458
4
    , textord_(this)
459
4
    , right_to_left_(false)
460
4
    , scaled_color_(nullptr)
461
4
    , scaled_factor_(-1)
462
4
    , deskew_(1.0f, 0.0f)
463
4
    , reskew_(1.0f, 0.0f)
464
4
    , gradient_(0.0f)
465
4
    , most_recently_used_(this)
466
4
    , font_table_size_(0)
467
#ifndef DISABLED_LEGACY_ENGINE
468
4
    , equ_detect_(nullptr)
469
#endif // ndef DISABLED_LEGACY_ENGINE
470
4
    , lstm_recognizer_(nullptr)
471
4
    , train_line_page_num_(0) {}
472
473
0
Tesseract::~Tesseract() {
474
0
  Clear();
475
0
  pix_original_.destroy();
476
0
  end_tesseract();
477
0
  for (auto *lang : sub_langs_) {
478
0
    delete lang;
479
0
  }
480
0
  delete lstm_recognizer_;
481
0
  lstm_recognizer_ = nullptr;
482
0
}
483
484
12.3M
Dict &Tesseract::getDict() {
485
12.3M
  if (0 == Classify::getDict().NumDawgs() && AnyLSTMLang()) {
486
12.3M
    if (lstm_recognizer_ && lstm_recognizer_->GetDict()) {
487
12.3M
      return *lstm_recognizer_->GetDict();
488
12.3M
    }
489
12.3M
  }
490
0
  return Classify::getDict();
491
12.3M
}
492
493
15.4k
void Tesseract::Clear() {
494
15.4k
  std::string debug_name = imagebasename + "_debug.pdf";
495
15.4k
  pixa_debug_.WritePDF(debug_name.c_str());
496
15.4k
  pix_binary_.destroy();
497
15.4k
  pix_grey_.destroy();
498
15.4k
  pix_thresholds_.destroy();
499
15.4k
  scaled_color_.destroy();
500
15.4k
  deskew_ = FCOORD(1.0f, 0.0f);
501
15.4k
  reskew_ = FCOORD(1.0f, 0.0f);
502
15.4k
  gradient_ = 0.0f;
503
15.4k
  splitter_.Clear();
504
15.4k
  scaled_factor_ = -1;
505
15.4k
  for (auto &sub_lang : sub_langs_) {
506
0
    sub_lang->Clear();
507
0
  }
508
15.4k
}
509
510
#ifndef DISABLED_LEGACY_ENGINE
511
512
0
void Tesseract::SetEquationDetect(EquationDetect *detector) {
513
0
  equ_detect_ = detector;
514
0
  equ_detect_->SetLangTesseract(this);
515
0
}
516
517
// Clear all memory of adaption for this and all subclassifiers.
518
0
void Tesseract::ResetAdaptiveClassifier() {
519
0
  ResetAdaptiveClassifierInternal();
520
0
  for (auto &sub_lang : sub_langs_) {
521
0
    sub_lang->ResetAdaptiveClassifierInternal();
522
0
  }
523
0
}
524
525
#endif // ndef DISABLED_LEGACY_ENGINE
526
527
// Clear the document dictionary for this and all subclassifiers.
528
0
void Tesseract::ResetDocumentDictionary() {
529
0
  getDict().ResetDocumentDictionary();
530
0
  for (auto &sub_lang : sub_langs_) {
531
0
    sub_lang->getDict().ResetDocumentDictionary();
532
0
  }
533
0
}
534
535
13.9k
void Tesseract::SetBlackAndWhitelist() {
536
  // Set the white and blacklists (if any)
537
13.9k
  unicharset.set_black_and_whitelist(tessedit_char_blacklist.c_str(),
538
13.9k
                                     tessedit_char_whitelist.c_str(),
539
13.9k
                                     tessedit_char_unblacklist.c_str());
540
13.9k
  if (lstm_recognizer_) {
541
13.9k
    UNICHARSET &lstm_unicharset = lstm_recognizer_->GetUnicharset();
542
13.9k
    lstm_unicharset.set_black_and_whitelist(tessedit_char_blacklist.c_str(),
543
13.9k
                                            tessedit_char_whitelist.c_str(),
544
13.9k
                                            tessedit_char_unblacklist.c_str());
545
13.9k
  }
546
  // Black and white lists should apply to all loaded classifiers.
547
13.9k
  for (auto &sub_lang : sub_langs_) {
548
0
    sub_lang->unicharset.set_black_and_whitelist(tessedit_char_blacklist.c_str(),
549
0
                                                 tessedit_char_whitelist.c_str(),
550
0
                                                 tessedit_char_unblacklist.c_str());
551
0
    if (sub_lang->lstm_recognizer_) {
552
0
      UNICHARSET &lstm_unicharset = sub_lang->lstm_recognizer_->GetUnicharset();
553
0
      lstm_unicharset.set_black_and_whitelist(tessedit_char_blacklist.c_str(),
554
0
                                              tessedit_char_whitelist.c_str(),
555
0
                                              tessedit_char_unblacklist.c_str());
556
0
    }
557
0
  }
558
13.9k
}
559
560
// Perform steps to prepare underlying binary image/other data structures for
561
// page segmentation.
562
15.4k
void Tesseract::PrepareForPageseg() {
563
15.4k
  textord_.set_use_cjk_fp_model(textord_use_cjk_fp_model);
564
  // Find the max splitter strategy over all langs.
565
15.4k
  auto max_pageseg_strategy = static_cast<ShiroRekhaSplitter::SplitStrategy>(
566
15.4k
      static_cast<int32_t>(pageseg_devanagari_split_strategy));
567
15.4k
  for (auto &sub_lang : sub_langs_) {
568
0
    auto pageseg_strategy = static_cast<ShiroRekhaSplitter::SplitStrategy>(
569
0
        static_cast<int32_t>(sub_lang->pageseg_devanagari_split_strategy));
570
0
    if (pageseg_strategy > max_pageseg_strategy) {
571
0
      max_pageseg_strategy = pageseg_strategy;
572
0
    }
573
0
    sub_lang->pix_binary_.destroy();
574
0
    sub_lang->pix_binary_ = pix_binary().clone();
575
0
  }
576
  // Perform shiro-rekha (top-line) splitting and replace the current image by
577
  // the newly split image.
578
15.4k
  splitter_.set_orig_pix(pix_binary());
579
15.4k
  splitter_.set_pageseg_split_strategy(max_pageseg_strategy);
580
15.4k
  if (splitter_.Split(true, &pixa_debug_)) {
581
0
    ASSERT_HOST(splitter_.splitted_image());
582
0
    pix_binary_.destroy();
583
0
    pix_binary_ = splitter_.splitted_image().clone();
584
0
  }
585
15.4k
}
586
587
// Perform steps to prepare underlying binary image/other data structures for
588
// OCR. The current segmentation is required by this method.
589
// Note that this method resets pix_binary_ to the original binarized image,
590
// which may be different from the image actually used for OCR depending on the
591
// value of devanagari_ocr_split_strategy.
592
15.4k
void Tesseract::PrepareForTessOCR(BLOCK_LIST *block_list, Tesseract *osd_tess, OSResults *osr) {
593
  // Find the max splitter strategy over all langs.
594
15.4k
  auto max_ocr_strategy = static_cast<ShiroRekhaSplitter::SplitStrategy>(
595
15.4k
      static_cast<int32_t>(ocr_devanagari_split_strategy));
596
15.4k
  for (auto &sub_lang : sub_langs_) {
597
0
    auto ocr_strategy = static_cast<ShiroRekhaSplitter::SplitStrategy>(
598
0
        static_cast<int32_t>(sub_lang->ocr_devanagari_split_strategy));
599
0
    if (ocr_strategy > max_ocr_strategy) {
600
0
      max_ocr_strategy = ocr_strategy;
601
0
    }
602
0
  }
603
  // Utilize the segmentation information available.
604
15.4k
  splitter_.set_segmentation_block_list(block_list);
605
15.4k
  splitter_.set_ocr_split_strategy(max_ocr_strategy);
606
  // Run the splitter for OCR
607
15.4k
  bool split_for_ocr = splitter_.Split(false, &pixa_debug_);
608
  // Restore pix_binary to the binarized original pix for future reference.
609
15.4k
  ASSERT_HOST(splitter_.orig_pix());
610
15.4k
  pix_binary_.destroy();
611
15.4k
  pix_binary_ = splitter_.orig_pix().clone();
612
  // If the pageseg and ocr strategies are different, refresh the block list
613
  // (from the last SegmentImage call) with blobs from the real image to be used
614
  // for OCR.
615
15.4k
  if (splitter_.HasDifferentSplitStrategies()) {
616
0
    BLOCK block("", true, 0, 0, 0, 0, pixGetWidth(pix_binary_), pixGetHeight(pix_binary_));
617
0
    Image pix_for_ocr = split_for_ocr ? splitter_.splitted_image() : splitter_.orig_pix();
618
0
    extract_edges(pix_for_ocr, &block);
619
0
    splitter_.RefreshSegmentationWithNewBlobs(block.blob_list());
620
0
  }
621
  // The splitter isn't needed any more after this, so save memory by clearing.
622
15.4k
  splitter_.Clear();
623
15.4k
}
624
625
} // namespace tesseract