tesseract v5.3.3.20231005
paramsd.cpp
Go to the documentation of this file.
1
2// File: paramsd.cpp
3// Description: Tesseract parameter Editor
4// Author: Joern Wanke
5//
6// (C) Copyright 2007, Google Inc.
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10// http://www.apache.org/licenses/LICENSE-2.0
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
18//
19// The parameters editor is used to edit all the parameters used within
20// tesseract from the ui.
21
22// Include automatically generated configuration file if running autoconf.
23#ifdef HAVE_CONFIG_H
24# include "config_auto.h"
25#endif
26
27#ifndef GRAPHICS_DISABLED
28
29# include "params.h" // for ParamsVectors, StringParam, BoolParam
30# include "paramsd.h"
31# include "scrollview.h" // for SVEvent, ScrollView, SVET_POPUP
32# include "svmnode.h" // for SVMenuNode
33# include "tesseractclass.h" // for Tesseract
34
35# include <cstdio> // for fclose, fopen, fprintf, FILE
36# include <cstdlib> // for atoi
37# include <cstring> // for strcmp, strcspn, strlen, strncpy
38# include <locale> // for std::locale::classic
39# include <map> // for map, _Rb_tree_iterator, map<>::iterator
40# include <memory> // for unique_ptr
41# include <sstream> // for std::stringstream
42# include <utility> // for pair
43
44namespace tesseract {
45
46# define VARDIR "configs/" /*parameters files */
47# define MAX_ITEMS_IN_SUBMENU 30
48
49// The following variables should remain static globals, since they
50// are used by debug editor, which uses a single Tesseract instance.
51//
52// Contains the mappings from unique VC ids to their actual pointers.
53static std::map<int, ParamContent *> vcMap;
54static int nrParams = 0;
55static int writeCommands[2];
56
57// Constructors for the various ParamTypes.
59 my_id_ = nrParams;
60 nrParams++;
61 param_type_ = VT_STRING;
62 sIt = it;
63 vcMap[my_id_] = this;
64}
65// Constructors for the various ParamTypes.
67 my_id_ = nrParams;
68 nrParams++;
69 param_type_ = VT_INTEGER;
70 iIt = it;
71 vcMap[my_id_] = this;
72}
73// Constructors for the various ParamTypes.
75 my_id_ = nrParams;
76 nrParams++;
77 param_type_ = VT_BOOLEAN;
78 bIt = it;
79 vcMap[my_id_] = this;
80}
81// Constructors for the various ParamTypes.
83 my_id_ = nrParams;
84 nrParams++;
85 param_type_ = VT_DOUBLE;
86 dIt = it;
87 vcMap[my_id_] = this;
88}
89
90// Gets a VC object identified by its ID.
92 return vcMap[id];
93}
94
95// Copy the first N words from the source string to the target string.
96// Words are delimited by "_".
97void ParamsEditor::GetFirstWords(const char *s, // source string
98 int n, // number of words
99 char *t // target string
100) {
101 int full_length = strlen(s);
102 int reqd_len = 0; // No. of chars required
103 const char *next_word = s;
104
105 while ((n > 0) && reqd_len < full_length) {
106 reqd_len += strcspn(next_word, "_") + 1;
107 next_word += reqd_len;
108 n--;
109 }
110 strncpy(t, s, reqd_len);
111 t[reqd_len] = '\0'; // ensure null terminal
112}
113
114// Getter for the name.
115const char *ParamContent::GetName() const {
116 if (param_type_ == VT_INTEGER) {
117 return iIt->name_str();
118 } else if (param_type_ == VT_BOOLEAN) {
119 return bIt->name_str();
120 } else if (param_type_ == VT_DOUBLE) {
121 return dIt->name_str();
122 } else if (param_type_ == VT_STRING) {
123 return sIt->name_str();
124 } else {
125 return "ERROR: ParamContent::GetName()";
126 }
127}
128
129// Getter for the description.
130const char *ParamContent::GetDescription() const {
131 if (param_type_ == VT_INTEGER) {
132 return iIt->info_str();
133 } else if (param_type_ == VT_BOOLEAN) {
134 return bIt->info_str();
135 } else if (param_type_ == VT_DOUBLE) {
136 return dIt->info_str();
137 } else if (param_type_ == VT_STRING) {
138 return sIt->info_str();
139 } else {
140 return nullptr;
141 }
142}
143
144// Getter for the value.
145std::string ParamContent::GetValue() const {
146 std::string result;
147 if (param_type_ == VT_INTEGER) {
148 result += std::to_string(*iIt);
149 } else if (param_type_ == VT_BOOLEAN) {
150 result += std::to_string(*bIt);
151 } else if (param_type_ == VT_DOUBLE) {
152 result += std::to_string(*dIt);
153 } else if (param_type_ == VT_STRING) {
154 result = sIt->c_str();
155 }
156 return result;
157}
158
159// Setter for the value.
160void ParamContent::SetValue(const char *val) {
161 // TODO (wanke) Test if the values actually are properly converted.
162 // (Quickly visible impacts?)
163 changed_ = true;
164 if (param_type_ == VT_INTEGER) {
165 iIt->set_value(atoi(val));
166 } else if (param_type_ == VT_BOOLEAN) {
167 bIt->set_value(atoi(val));
168 } else if (param_type_ == VT_DOUBLE) {
169 std::stringstream stream(val);
170 // Use "C" locale for reading double value.
171 stream.imbue(std::locale::classic());
172 double d = 0;
173 stream >> d;
174 dIt->set_value(d);
175 } else if (param_type_ == VT_STRING) {
176 sIt->set_value(val);
177 }
178}
179
180// Gets the up to the first 3 prefixes from s (split by _).
181// For example, tesseract_foo_bar will be split into tesseract,foo and bar.
182void ParamsEditor::GetPrefixes(const char *s, std::string *level_one, std::string *level_two,
183 std::string *level_three) {
184 std::unique_ptr<char[]> p(new char[1024]);
185 GetFirstWords(s, 1, p.get());
186 *level_one = p.get();
187 GetFirstWords(s, 2, p.get());
188 *level_two = p.get();
189 GetFirstWords(s, 3, p.get());
190 *level_three = p.get();
191}
192
193// Compare two VC objects by their name.
194int ParamContent::Compare(const void *v1, const void *v2) {
195 const ParamContent *one = *static_cast<const ParamContent *const *>(v1);
196 const ParamContent *two = *static_cast<const ParamContent *const *>(v2);
197 return strcmp(one->GetName(), two->GetName());
198}
199
200// Find all editable parameters used within tesseract and create a
201// SVMenuNode tree from it.
202// TODO (wanke): This is actually sort of hackish.
203SVMenuNode *ParamsEditor::BuildListOfAllLeaves(tesseract::Tesseract *tess) {
204 auto *mr = new SVMenuNode();
205 ParamContent_LIST vclist;
206 ParamContent_IT vc_it(&vclist);
207 // Amount counts the number of entries for a specific char*.
208 // TODO(rays) get rid of the use of std::map.
209 std::map<const char *, int> amount;
210
211 // Add all parameters to a list.
212 int num_iterations = (tess->params() == nullptr) ? 1 : 2;
213 for (int v = 0; v < num_iterations; ++v) {
214 tesseract::ParamsVectors *vec = (v == 0) ? GlobalParams() : tess->params();
215 for (auto &param : vec->int_params) {
216 vc_it.add_after_then_move(new ParamContent(param));
217 }
218 for (auto &param : vec->bool_params) {
219 vc_it.add_after_then_move(new ParamContent(param));
220 }
221 for (auto &param : vec->string_params) {
222 vc_it.add_after_then_move(new ParamContent(param));
223 }
224 for (auto &param : vec->double_params) {
225 vc_it.add_after_then_move(new ParamContent(param));
226 }
227 }
228
229 // Count the # of entries starting with a specific prefix.
230 for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) {
231 ParamContent *vc = vc_it.data();
232 std::string tag;
233 std::string tag2;
234 std::string tag3;
235
236 GetPrefixes(vc->GetName(), &tag, &tag2, &tag3);
237 amount[tag.c_str()]++;
238 amount[tag2.c_str()]++;
239 amount[tag3.c_str()]++;
240 }
241
242 vclist.sort(ParamContent::Compare); // Sort the list alphabetically.
243
244 SVMenuNode *other = mr->AddChild("OTHER");
245
246 // go through the list again and this time create the menu structure.
247 vc_it.move_to_first();
248 for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) {
249 ParamContent *vc = vc_it.data();
250 std::string tag;
251 std::string tag2;
252 std::string tag3;
253 GetPrefixes(vc->GetName(), &tag, &tag2, &tag3);
254
255 if (amount[tag.c_str()] == 1) {
256 other->AddChild(vc->GetName(), vc->GetId(), vc->GetValue().c_str(), vc->GetDescription());
257 } else { // More than one would use this submenu -> create submenu.
258 SVMenuNode *sv = mr->AddChild(tag.c_str());
259 if ((amount[tag.c_str()] <= MAX_ITEMS_IN_SUBMENU) || (amount[tag2.c_str()] <= 1)) {
260 sv->AddChild(vc->GetName(), vc->GetId(), vc->GetValue().c_str(), vc->GetDescription());
261 } else { // Make subsubmenus.
262 SVMenuNode *sv2 = sv->AddChild(tag2.c_str());
263 sv2->AddChild(vc->GetName(), vc->GetId(), vc->GetValue().c_str(), vc->GetDescription());
264 }
265 }
266 }
267 return mr;
268}
269
270// Event listener. Waits for SVET_POPUP events and processes them.
272 if (sve->type == SVET_POPUP) { // only catch SVET_POPUP!
273 char *param = sve->parameter;
274 if (sve->command_id == writeCommands[0]) {
275 WriteParams(param, false);
276 } else if (sve->command_id == writeCommands[1]) {
277 WriteParams(param, true);
278 } else {
280 vc->SetValue(param);
281 sv_window_->AddMessageF("Setting %s to %s", vc->GetName(), vc->GetValue().c_str());
282 }
283 }
284}
285
286// Integrate the parameters editor as popupmenu into the existing scrollview
287// window (usually the pg editor). If sv == null, create a new empty
288// empty window and attach the parameters editor to that window (ugly).
290 if (sv == nullptr) {
291 const char *name = "ParamEditorMAIN";
292 sv = new ScrollView(name, 1, 1, 200, 200, 300, 200);
293 }
294
295 sv_window_ = sv;
296
297 // Only one event handler per window.
298 // sv->AddEventHandler((SVEventHandler*) this);
299
300 SVMenuNode *svMenuRoot = BuildListOfAllLeaves(tess);
301
302 std::string paramfile;
303 paramfile = tess->datadir;
304 paramfile += VARDIR; // parameters dir
305 paramfile += "edited"; // actual name
306
307 SVMenuNode *std_menu = svMenuRoot->AddChild("Build Config File");
308
309 writeCommands[0] = nrParams + 1;
310 std_menu->AddChild("All Parameters", writeCommands[0], paramfile.c_str(), "Config file name?");
311
312 writeCommands[1] = nrParams + 2;
313 std_menu->AddChild("changed_ Parameters Only", writeCommands[1], paramfile.c_str(),
314 "Config file name?");
315
316 svMenuRoot->BuildMenu(sv, false);
317}
318
319// Write all (changed_) parameters to a config file.
320void ParamsEditor::WriteParams(char *filename, bool changes_only) {
321 FILE *fp; // input file
322 // if file exists
323 if ((fp = fopen(filename, "rb")) != nullptr) {
324 fclose(fp);
325 std::stringstream msg;
326 msg << "Overwrite file " << filename << "? (Y/N)";
327 int a = sv_window_->ShowYesNoDialog(msg.str().c_str());
328 if (a == 'n') {
329 return;
330 } // don't write
331 }
332
333 fp = fopen(filename, "wb"); // can we write to it?
334 if (fp == nullptr) {
335 sv_window_->AddMessageF("Can't write to file %s", filename);
336 return;
337 }
338 for (auto &iter : vcMap) {
339 ParamContent *cur = iter.second;
340 if (!changes_only || cur->HasChanged()) {
341 fprintf(fp, "%-25s %-12s # %s\n", cur->GetName(), cur->GetValue().c_str(),
342 cur->GetDescription());
343 }
344 }
345 fclose(fp);
346}
347
348} // namespace tesseract
349
350#endif // !GRAPHICS_DISABLED
#define VARDIR
Definition: paramsd.cpp:46
#define MAX_ITEMS_IN_SUBMENU
Definition: paramsd.cpp:47
const char * p
@ SVET_POPUP
Definition: scrollview.h:62
@ VT_INTEGER
Definition: paramsd.h:40
@ VT_STRING
Definition: paramsd.h:40
@ VT_BOOLEAN
Definition: paramsd.h:40
@ VT_DOUBLE
Definition: paramsd.h:40
tesseract::ParamsVectors * GlobalParams()
Definition: params.cpp:36
void SetValue(const char *val)
Definition: paramsd.cpp:160
std::string GetValue() const
Definition: paramsd.cpp:145
static int Compare(const void *v1, const void *v2)
Definition: paramsd.cpp:194
tesseract::StringParam * sIt
Definition: paramsd.h:84
const char * GetDescription() const
Definition: paramsd.cpp:130
static ParamContent * GetParamContentById(int id)
Definition: paramsd.cpp:91
tesseract::IntParam * iIt
Definition: paramsd.h:85
const char * GetName() const
Definition: paramsd.cpp:115
tesseract::BoolParam * bIt
Definition: paramsd.h:86
tesseract::DoubleParam * dIt
Definition: paramsd.h:87
void Notify(const SVEvent *sve) override
Definition: paramsd.cpp:271
ParamsEditor(tesseract::Tesseract *, ScrollView *sv=nullptr)
Definition: paramsd.cpp:289
ParamsVectors * params()
Definition: ccutil.h:53
std::string datadir
Definition: ccutil.h:57
std::vector< BoolParam * > bool_params
Definition: params.h:48
std::vector< StringParam * > string_params
Definition: params.h:49
std::vector< IntParam * > int_params
Definition: params.h:47
std::vector< DoubleParam * > double_params
Definition: params.h:50
const char * name_str() const
Definition: params.h:117
const char * info_str() const
Definition: params.h:120
void set_value(int32_t value)
Definition: params.h:166
void set_value(bool value)
Definition: params.h:208
void set_value(const std::string &value)
Definition: params.h:263
const char * c_str() const
Definition: params.h:248
void set_value(double value)
Definition: params.h:305
SVEventType type
Definition: scrollview.h:74
int ShowYesNoDialog(const char *msg)
Definition: scrollview.cpp:732
void AddMessageF(const char *format,...) __attribute__((format(gnu_printf
Definition: scrollview.cpp:542
SVMenuNode * AddChild(const char *txt)
Definition: svmnode.cpp:59
void BuildMenu(ScrollView *sv, bool menu_bar=true)
Definition: svmnode.cpp:120