This commit is contained in:
Ger Hobbelt 2025-05-26 10:14:18 +02:00 committed by GitHub
commit 076ae90c22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 437 additions and 98 deletions

View File

@ -152,6 +152,17 @@ public:
*/ */
void PrintVariables(FILE *fp) const; void PrintVariables(FILE *fp) const;
/*
* Report parameters' usage statistics, i.e. report which params have been
* set, modified and read/checked until now during this run-time's lifetime.
*
* Use this method for run-time 'discovery' about which tesseract parameters
* are actually *used* during your particular usage of the library, ergo
* answering the question:
* "Which of all those parameters are actually *relevant* to my use case today?"
*/
void ReportParamsUsageStatistics() const;
/** /**
* Get value of named variable as a string, if it exists. * Get value of named variable as a string, if it exists.
*/ */

View File

@ -220,8 +220,8 @@ bool TessBaseAPI::SetDebugVariable(const char *name, const char *value) {
} }
bool TessBaseAPI::GetIntVariable(const char *name, int *value) const { bool TessBaseAPI::GetIntVariable(const char *name, int *value) const {
auto *p = ParamUtils::FindParam<IntParam>(name, GlobalParams()->int_params, auto *p = ParamUtils::FindParam<IntParam>(name, GlobalParams()->int_params(),
tesseract_->params()->int_params); tesseract_->params()->int_params());
if (p == nullptr) { if (p == nullptr) {
return false; return false;
} }
@ -230,8 +230,8 @@ bool TessBaseAPI::GetIntVariable(const char *name, int *value) const {
} }
bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const { bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const {
auto *p = ParamUtils::FindParam<BoolParam>(name, GlobalParams()->bool_params, auto *p = ParamUtils::FindParam<BoolParam>(name, GlobalParams()->bool_params(),
tesseract_->params()->bool_params); tesseract_->params()->bool_params());
if (p == nullptr) { if (p == nullptr) {
return false; return false;
} }
@ -240,14 +240,14 @@ bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const {
} }
const char *TessBaseAPI::GetStringVariable(const char *name) const { const char *TessBaseAPI::GetStringVariable(const char *name) const {
auto *p = ParamUtils::FindParam<StringParam>(name, GlobalParams()->string_params, auto *p = ParamUtils::FindParam<StringParam>(name, GlobalParams()->string_params(),
tesseract_->params()->string_params); tesseract_->params()->string_params());
return (p != nullptr) ? p->c_str() : nullptr; return (p != nullptr) ? p->c_str() : nullptr;
} }
bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const { bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const {
auto *p = ParamUtils::FindParam<DoubleParam>(name, GlobalParams()->double_params, auto *p = ParamUtils::FindParam<DoubleParam>(name, GlobalParams()->double_params(),
tesseract_->params()->double_params); tesseract_->params()->double_params());
if (p == nullptr) { if (p == nullptr) {
return false; return false;
} }
@ -285,6 +285,19 @@ void TessBaseAPI::PrintVariables(FILE *fp) const {
ParamUtils::PrintParams(fp, tesseract_->params()); ParamUtils::PrintParams(fp, tesseract_->params());
} }
// Report parameters' usage statistics, i.e. report which params have been
// set, modified and read/checked until now during this run-time's lifetime.
//
// Use this method for run-time 'discovery' about which tesseract parameters
// are actually *used* during your particular usage of the library, ergo
// answering the question:
// "Which of all those parameters are actually *relevant* to my use case today?"
void TessBaseAPI::ReportParamsUsageStatistics() const {
tesseract::ParamsVectors *vec = tesseract_->params();
ParamUtils::ReportParamsUsageStatistics(vec);
}
/** /**
* The datapath must be the name of the data directory or * The datapath must be the name of the data directory or
* some other file in which the data directory resides (for instance argv[0].) * some other file in which the data directory resides (for instance argv[0].)

View File

@ -210,16 +210,16 @@ SVMenuNode *ParamsEditor::BuildListOfAllLeaves(tesseract::Tesseract *tess) {
int num_iterations = (tess->params() == nullptr) ? 1 : 2; int num_iterations = (tess->params() == nullptr) ? 1 : 2;
for (int v = 0; v < num_iterations; ++v) { for (int v = 0; v < num_iterations; ++v) {
tesseract::ParamsVectors *vec = (v == 0) ? GlobalParams() : tess->params(); tesseract::ParamsVectors *vec = (v == 0) ? GlobalParams() : tess->params();
for (auto &param : vec->int_params) { for (auto &param : vec->int_params()) {
vc_it.add_after_then_move(new ParamContent(param)); vc_it.add_after_then_move(new ParamContent(param));
} }
for (auto &param : vec->bool_params) { for (auto &param : vec->bool_params()) {
vc_it.add_after_then_move(new ParamContent(param)); vc_it.add_after_then_move(new ParamContent(param));
} }
for (auto &param : vec->string_params) { for (auto &param : vec->string_params()) {
vc_it.add_after_then_move(new ParamContent(param)); vc_it.add_after_then_move(new ParamContent(param));
} }
for (auto &param : vec->double_params) { for (auto &param : vec->double_params()) {
vc_it.add_after_then_move(new ParamContent(param)); vc_it.add_after_then_move(new ParamContent(param));
} }
} }

View File

@ -18,11 +18,14 @@
#include "params.h" #include "params.h"
#include "helpers.h" // for chomp_string #include "helpers.h" // for chomp_string, mupdf imports, etc.: see also the header collision comment in there (MSVC-specific).
#include "host.h" // tesseract/export.h, windows.h for MAX_PATH #include "host.h" // tesseract/export.h, windows.h for MAX_PATH
#include "serialis.h" // for TFile #include "serialis.h" // for TFile
#include "tprintf.h" #include "tprintf.h"
#include <fmt/core.h>
#include <fmt/format.h>
#include <climits> // for INT_MIN, INT_MAX #include <climits> // for INT_MIN, INT_MAX
#include <cmath> // for NAN, std::isnan #include <cmath> // for NAN, std::isnan
#include <cstdio> #include <cstdio>
@ -31,10 +34,12 @@
#include <locale> // for std::locale::classic #include <locale> // for std::locale::classic
#include <sstream> // for std::stringstream #include <sstream> // for std::stringstream
namespace tesseract { namespace tesseract {
TESS_API
tesseract::ParamsVectors *GlobalParams() { tesseract::ParamsVectors *GlobalParams() {
static tesseract::ParamsVectors global_params = tesseract::ParamsVectors(); static tesseract::ParamsVectors global_params; // static auto-inits at startup
return &global_params; return &global_params;
} }
@ -42,7 +47,7 @@ bool ParamUtils::ReadParamsFile(const char *file, SetParamConstraint constraint,
ParamsVectors *member_params) { ParamsVectors *member_params) {
TFile fp; TFile fp;
if (!fp.Open(file, nullptr)) { if (!fp.Open(file, nullptr)) {
tprintf("read_params_file: Can't open %s\n", file); tprintf("ERROR: read_params_file: Can't open file {}\n", file);
return true; return true;
} }
return ReadParamsFromFp(constraint, &fp, member_params); return ReadParamsFromFp(constraint, &fp, member_params);
@ -71,18 +76,157 @@ bool ParamUtils::ReadParamsFromFp(SetParamConstraint constraint, TFile *fp,
if (!foundit) { if (!foundit) {
anyerr = true; // had an error anyerr = true; // had an error
tprintf("Warning: Parameter not found: %s\n", line); tprintf("WARNING: Parameter not found: {}\n", line);
} }
} }
} }
return anyerr; return anyerr;
} }
void ParamUtils::ReportParamsUsageStatistics(const ParamsVectors *member_params)
{
std::string report_path = vars_report_file;
FILE* f = nullptr;
if (report_path == "stdout" || report_path == "-" || report_path == "1")
f = stdout;
else if (report_path == "stdeerr" || report_path == "+" || report_path == "2")
f = stderr;
else if (!report_path.empty())
{
#if defined(HAVE_MUPDF)
fz_context* ctx = fz_get_global_context();
fz_mkdir_for_file(ctx, report_path.c_str());
f = fz_fopen_utf8(ctx, report_path.c_str(), "w");
#else
f = fopen(report_path.c_str(), "w");
#endif
if (!f)
{
tprintf("ERROR: Cannot produce paramater usage report file: {}\n", report_path);
}
}
if (!f)
return;
fprintf(f, "\n\nTesseract Parameter Usage Statistics: which params have been relevant?\n"
"----------------------------------------------------------------------\n\n");
// first collect all parameter names:
typedef enum {
INT_PARAM = 0,
BOOL_PARAM,
DOUBLE_PARAM,
STRING_PARAM,
} param_type_t;
typedef struct param_info {
const char* name;
bool global;
param_type_t type;
const Param* ref;
} param_info_t;
std::vector<param_info_t> param_names;
if (member_params != nullptr) {
for (auto p : member_params->int_params_c()) {
param_names.push_back({ p->name_str(), false, INT_PARAM, p });
}
for (auto p : member_params->bool_params_c()) {
param_names.push_back({ p->name_str(), false, BOOL_PARAM, p });
}
for (auto p : member_params->string_params_c()) {
param_names.push_back({ p->name_str(), false, STRING_PARAM, p });
}
for (auto p : member_params->double_params_c()) {
param_names.push_back({ p->name_str(), false, DOUBLE_PARAM, p });
}
}
const ParamsVectors* globals = GlobalParams();
for (auto p : globals->int_params_c()) {
param_names.push_back({ p->name_str(), true, INT_PARAM, p });
}
for (auto p : globals->bool_params_c()) {
param_names.push_back({ p->name_str(), true, BOOL_PARAM, p });
}
for (auto p : globals->string_params_c()) {
param_names.push_back({ p->name_str(), true, STRING_PARAM, p });
}
for (auto p : globals->double_params_c()) {
param_names.push_back({ p->name_str(), true, DOUBLE_PARAM, p });
}
sort(param_names.begin(), param_names.end(), [](param_info_t& a, param_info_t& b)
{
int rv = strcmp(b.name, a.name);
if (rv == 0)
{
rv = (int) b.global - (int) a.global;
}
#if !defined(NDEBUG)
if (rv == 0)
{
fprintf(stderr, "Apparently you have double-defined Tesseract Variable: '%s'! Fix that in the source code!\n", a.name);
ASSEERT0(!"Apparently you have double-defined a Tesseract Variable.");
}
#endif
return rv >= 0;
});
static const char* type_map[] = { "[Integer]", "[Boolean]", "[Float]", "[String]" };
static const char* categories[] = { "(Global)", "(Local)" };
static const char* write_access[] = { ".", "w", "W" };
static const char* read_access[] = { ".", "r", "R" };
auto acc = [](int access) {
if (access > 2)
access = 2;
return access;
};
for (auto item : param_names) {
const Param* p = item.ref;
auto stats = p->access_counts();
if (stats.reading > 0)
{
fmt::print(f, "* {:.<60} {:8} {}{} {:9} = {}\n", p->name_str(), categories[item.global], write_access[acc(stats.writing)], read_access[acc(stats.reading)], type_map[item.type], p->formatted_value_str());
}
}
if (report_all_variables)
{
fprintf(f, "\n\nUnused parameters:\n\n");
for (auto item : param_names) {
const Param* p = item.ref;
auto stats = p->access_counts();
if (stats.reading <= 0)
{
fmt::print(f, "* {:.<60} {:8} {}{} {:9} = {}\n", p->name_str(), categories[item.global], write_access[acc(stats.writing)], read_access[acc(stats.reading)], type_map[item.type], p->formatted_value_str());
}
}
}
if (f != stdout)
{
fclose(f);
}
else
{
fflush(stdout);
}
}
bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstraint constraint, bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstraint constraint,
ParamsVectors *member_params) { ParamsVectors *member_params) {
// Look for the parameter among string parameters. // Look for the parameter among string parameters.
auto *sp = auto *sp =
FindParam<StringParam>(name, GlobalParams()->string_params, member_params->string_params); FindParam<StringParam>(name, GlobalParams()->string_params(), member_params->string_params());
if (sp != nullptr && sp->constraint_ok(constraint)) { if (sp != nullptr && sp->constraint_ok(constraint)) {
sp->set_value(value); sp->set_value(value);
} }
@ -91,7 +235,7 @@ bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstrain
} }
// Look for the parameter among int parameters. // Look for the parameter among int parameters.
auto *ip = FindParam<IntParam>(name, GlobalParams()->int_params, member_params->int_params); auto *ip = FindParam<IntParam>(name, GlobalParams()->int_params(), member_params->int_params());
if (ip && ip->constraint_ok(constraint)) { if (ip && ip->constraint_ok(constraint)) {
int intval = INT_MIN; int intval = INT_MIN;
std::stringstream stream(value); std::stringstream stream(value);
@ -103,7 +247,7 @@ bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstrain
} }
// Look for the parameter among bool parameters. // Look for the parameter among bool parameters.
auto *bp = FindParam<BoolParam>(name, GlobalParams()->bool_params, member_params->bool_params); auto *bp = FindParam<BoolParam>(name, GlobalParams()->bool_params(), member_params->bool_params());
if (bp != nullptr && bp->constraint_ok(constraint)) { if (bp != nullptr && bp->constraint_ok(constraint)) {
if (*value == 'T' || *value == 't' || *value == 'Y' || *value == 'y' || *value == '1') { if (*value == 'T' || *value == 't' || *value == 'Y' || *value == 'y' || *value == '1') {
bp->set_value(true); bp->set_value(true);
@ -114,7 +258,7 @@ bool ParamUtils::SetParam(const char *name, const char *value, SetParamConstrain
// Look for the parameter among double parameters. // Look for the parameter among double parameters.
auto *dp = auto *dp =
FindParam<DoubleParam>(name, GlobalParams()->double_params, member_params->double_params); FindParam<DoubleParam>(name, GlobalParams()->double_params(), member_params->double_params());
if (dp != nullptr && dp->constraint_ok(constraint)) { if (dp != nullptr && dp->constraint_ok(constraint)) {
double doubleval = NAN; double doubleval = NAN;
std::stringstream stream(value); std::stringstream stream(value);
@ -131,26 +275,26 @@ bool ParamUtils::GetParamAsString(const char *name, const ParamsVectors *member_
std::string *value) { std::string *value) {
// Look for the parameter among string parameters. // Look for the parameter among string parameters.
auto *sp = auto *sp =
FindParam<StringParam>(name, GlobalParams()->string_params, member_params->string_params); FindParam<StringParam>(name, GlobalParams()->string_params_c(), member_params->string_params_c());
if (sp) { if (sp) {
*value = sp->c_str(); *value = sp->c_str();
return true; return true;
} }
// Look for the parameter among int parameters. // Look for the parameter among int parameters.
auto *ip = FindParam<IntParam>(name, GlobalParams()->int_params, member_params->int_params); auto *ip = FindParam<IntParam>(name, GlobalParams()->int_params_c(), member_params->int_params_c());
if (ip) { if (ip) {
*value = std::to_string(int32_t(*ip)); *value = std::to_string(int32_t(*ip));
return true; return true;
} }
// Look for the parameter among bool parameters. // Look for the parameter among bool parameters.
auto *bp = FindParam<BoolParam>(name, GlobalParams()->bool_params, member_params->bool_params); auto *bp = FindParam<BoolParam>(name, GlobalParams()->bool_params_c(), member_params->bool_params_c());
if (bp != nullptr) { if (bp != nullptr) {
*value = bool(*bp) ? "1" : "0"; *value = bool(*bp) ? "1" : "0";
return true; return true;
} }
// Look for the parameter among double parameters. // Look for the parameter among double parameters.
auto *dp = auto *dp =
FindParam<DoubleParam>(name, GlobalParams()->double_params, member_params->double_params); FindParam<DoubleParam>(name, GlobalParams()->double_params_c(), member_params->double_params_c());
if (dp != nullptr) { if (dp != nullptr) {
std::ostringstream stream; std::ostringstream stream;
stream.imbue(std::locale::classic()); stream.imbue(std::locale::classic());
@ -163,27 +307,55 @@ bool ParamUtils::GetParamAsString(const char *name, const ParamsVectors *member_
void ParamUtils::PrintParams(FILE *fp, const ParamsVectors *member_params) { void ParamUtils::PrintParams(FILE *fp, const ParamsVectors *member_params) {
int num_iterations = (member_params == nullptr) ? 1 : 2; int num_iterations = (member_params == nullptr) ? 1 : 2;
// When printing to stdout info text is included.
// Info text is omitted when printing to a file (would result in an invalid config file).
if (!fp)
fp = stdout;
bool print_info = (fp == stdout || fp == stderr);
std::ostringstream stream; std::ostringstream stream;
stream.imbue(std::locale::classic()); stream.imbue(std::locale::classic());
for (int v = 0; v < num_iterations; ++v) { for (int v = 0; v < num_iterations; ++v) {
const ParamsVectors *vec = (v == 0) ? GlobalParams() : member_params; const ParamsVectors *vec = (v == 0) ? GlobalParams() : member_params;
for (auto int_param : vec->int_params) { for (auto int_param : vec->int_params_c()) {
stream << int_param->name_str() << '\t' << (int32_t)(*int_param) << '\t' if (print_info) {
<< int_param->info_str() << '\n'; stream << int_param->name_str() << '\t' << (int32_t)(*int_param) << '\t'
<< int_param->info_str() << '\n';
} else {
stream << int_param->name_str() << '\t' << (int32_t)(*int_param) << '\n';
}
} }
for (auto bool_param : vec->bool_params) { for (auto bool_param : vec->bool_params_c()) {
stream << bool_param->name_str() << '\t' << bool(*bool_param) << '\t' if (print_info) {
<< bool_param->info_str() << '\n'; stream << bool_param->name_str() << '\t' << bool(*bool_param) << '\t'
<< bool_param->info_str() << '\n';
} else {
stream << bool_param->name_str() << '\t' << bool(*bool_param) << '\n';
}
} }
for (auto string_param : vec->string_params) { for (auto string_param : vec->string_params_c()) {
stream << string_param->name_str() << '\t' << string_param->c_str() << '\t' if (print_info) {
<< string_param->info_str() << '\n'; stream << string_param->name_str() << '\t' << string_param->c_str() << '\t'
<< string_param->info_str() << '\n';
} else {
stream << string_param->name_str() << '\t' << string_param->c_str() << '\n';
}
} }
for (auto double_param : vec->double_params) { for (auto double_param : vec->double_params_c()) {
stream << double_param->name_str() << '\t' << (double)(*double_param) << '\t' if (print_info) {
<< double_param->info_str() << '\n'; stream << double_param->name_str() << '\t' << (double)(*double_param) << '\t'
<< double_param->info_str() << '\n';
} else {
stream << double_param->name_str() << '\t' << (double)(*double_param) << '\n';
}
} }
} }
#ifdef HAVE_MUPDF
if (print_info)
{
tprintf("{}", stream.str().c_str());
return;
}
#endif
fprintf(fp, "%s", stream.str().c_str()); fprintf(fp, "%s", stream.str().c_str());
} }
@ -192,16 +364,16 @@ void ParamUtils::ResetToDefaults(ParamsVectors *member_params) {
int num_iterations = (member_params == nullptr) ? 1 : 2; int num_iterations = (member_params == nullptr) ? 1 : 2;
for (int v = 0; v < num_iterations; ++v) { for (int v = 0; v < num_iterations; ++v) {
ParamsVectors *vec = (v == 0) ? GlobalParams() : member_params; ParamsVectors *vec = (v == 0) ? GlobalParams() : member_params;
for (auto &param : vec->int_params) { for (auto &param : vec->int_params()) {
param->ResetToDefault(); param->ResetToDefault();
} }
for (auto &param : vec->bool_params) { for (auto &param : vec->bool_params()) {
param->ResetToDefault(); param->ResetToDefault();
} }
for (auto &param : vec->string_params) { for (auto &param : vec->string_params()) {
param->ResetToDefault(); param->ResetToDefault();
} }
for (auto &param : vec->double_params) { for (auto &param : vec->double_params()) {
param->ResetToDefault(); param->ResetToDefault();
} }
} }

View File

@ -2,6 +2,8 @@
* File: params.h * File: params.h
* Description: Class definitions of the *_VAR classes for tunable constants. * Description: Class definitions of the *_VAR classes for tunable constants.
* Author: Ray Smith * Author: Ray Smith
*
* UTF8 detect helper statement: «bloody MSVC»
* *
* (C) Copyright 1991, Hewlett-Packard Ltd. * (C) Copyright 1991, Hewlett-Packard Ltd.
** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License");
@ -43,11 +45,43 @@ enum SetParamConstraint {
SET_PARAM_CONSTRAINT_NON_INIT_ONLY, SET_PARAM_CONSTRAINT_NON_INIT_ONLY,
}; };
struct ParamsVectors { class ParamsVectors {
std::vector<IntParam *> int_params; std::vector<IntParam *> _int_params;
std::vector<BoolParam *> bool_params; std::vector<BoolParam *> _bool_params;
std::vector<StringParam *> string_params; std::vector<StringParam *> _string_params;
std::vector<DoubleParam *> double_params; std::vector<DoubleParam *> _double_params;
public:
ParamsVectors() {
}
~ParamsVectors() {
}
std::vector<IntParam *> &int_params() {
return _int_params;
}
std::vector<BoolParam *> &bool_params() {
return _bool_params;
}
std::vector<StringParam *> &string_params() {
return _string_params;
}
std::vector<DoubleParam *> &double_params() {
return _double_params;
}
const std::vector<IntParam *> &int_params_c() const {
return _int_params;
}
const std::vector<BoolParam *> &bool_params_c() const {
return _bool_params;
}
const std::vector<StringParam *> &string_params_c() const {
return _string_params;
}
const std::vector<DoubleParam *> &double_params_c() const {
return _double_params;
}
}; };
// Utility functions for working with Tesseract parameters. // Utility functions for working with Tesseract parameters.
@ -69,6 +103,25 @@ public:
static bool SetParam(const char *name, const char *value, SetParamConstraint constraint, static bool SetParam(const char *name, const char *value, SetParamConstraint constraint,
ParamsVectors *member_params); ParamsVectors *member_params);
// accept both - and _ in key names, e.g. user-specified 'debug-all' would match 'debug_all'
// in the database.
static inline bool CompareKeys(const char *db_key, const char *user_key)
{
// if (0 == strcmp(db_key, user_key))
// return true;
for (; *db_key && *user_key; db_key++, user_key++)
{
if (*db_key != *user_key)
{
if (*db_key == '_' && *user_key == '-')
continue;
return false;
}
}
return true;
}
// Returns the pointer to the parameter with the given name (of the // Returns the pointer to the parameter with the given name (of the
// appropriate type) if it was found in the vector obtained from // appropriate type) if it was found in the vector obtained from
// GlobalParams() or in the given member_params. // GlobalParams() or in the given member_params.
@ -76,16 +129,16 @@ public:
static T *FindParam(const char *name, const std::vector<T *> &global_vec, static T *FindParam(const char *name, const std::vector<T *> &global_vec,
const std::vector<T *> &member_vec) { const std::vector<T *> &member_vec) {
for (auto *param : global_vec) { for (auto *param : global_vec) {
if (strcmp(param->name_str(), name) == 0) { if (CompareKeys(param->name_str(), name)) {
return param; return param;
} }
} }
for (auto *param : member_vec) { for (auto *param : member_vec) {
if (strcmp(param->name_str(), name) == 0) { if (CompareKeys(param->name_str(), name)) {
return param; return param;
} }
} }
return nullptr; return nullptr;
} }
// Removes the given pointer to the param from the given vector. // Removes the given pointer to the param from the given vector.
template <class T> template <class T>
@ -105,6 +158,15 @@ public:
// Print parameters to the given file. // Print parameters to the given file.
static void PrintParams(FILE *fp, const ParamsVectors *member_params); static void PrintParams(FILE *fp, const ParamsVectors *member_params);
// Report parameters' usage statistics, i.e. report which params have been
// set, modified and read/checked until now during this run-time's lifetime.
//
// Use this method for run-time 'discovery' about which tesseract parameters
// are actually *used* during your particular usage of the library, ergo
// answering the question:
// "Which of all those parameters are actually *relevant* to my use case today?"
static void ReportParamsUsageStatistics(const ParamsVectors *member_params);
// Resets all parameters back to default values; // Resets all parameters back to default values;
static void ResetToDefaults(ParamsVectors *member_params); static void ResetToDefaults(ParamsVectors *member_params);
}; };
@ -133,16 +195,29 @@ public:
(constraint == SET_PARAM_CONSTRAINT_NON_INIT_ONLY && !this->is_init())); (constraint == SET_PARAM_CONSTRAINT_NON_INIT_ONLY && !this->is_init()));
} }
typedef struct access_counts {
int reading;
int writing;
} access_counts_t;
access_counts_t access_counts() const {
return access_counts_;
}
virtual std::string formatted_value_str() const = 0;
protected: protected:
Param(const char *name, const char *comment, bool init) Param(const char *name, const char *comment, bool init)
: name_(name), info_(comment), init_(init) { : name_(name), info_(comment), init_(init) {
debug_ = (strstr(name, "debug") != nullptr) || (strstr(name, "display")); debug_ = (strstr(name, "debug") != nullptr) || (strstr(name, "display"));
access_counts_ = {0,0};
} }
const char *name_; // name of this parameter const char *name_; // name of this parameter
const char *info_; // for menus const char *info_; // for menus
bool init_; // needs to be set before init bool init_; // needs to be set before init
bool debug_; bool debug_;
mutable access_counts_t access_counts_;
}; };
class IntParam : public Param { class IntParam : public Param {
@ -151,40 +226,51 @@ public:
: Param(name, comment, init) { : Param(name, comment, init) {
value_ = value; value_ = value;
default_ = value; default_ = value;
params_vec_ = &(vec->int_params); access_counts_.writing++;
vec->int_params.push_back(this); params_vec_ = vec;
vec->int_params().push_back(this);
} }
~IntParam() { ~IntParam() {
ParamUtils::RemoveParam<IntParam>(this, params_vec_); ParamUtils::RemoveParam<IntParam>(this, &params_vec_->int_params());
} }
operator int32_t() const { operator int32_t() const {
return value_; access_counts_.reading++;
return value_;
} }
void operator=(int32_t value) { void operator=(int32_t value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void set_value(int32_t value) { void set_value(int32_t value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void ResetToDefault() { void ResetToDefault() {
value_ = default_; access_counts_.writing++;
value_ = default_;
} }
void ResetFrom(const ParamsVectors *vec) { void ResetFrom(const ParamsVectors *vec) {
for (auto *param : vec->int_params) { for (auto *param : vec->int_params_c()) {
if (strcmp(param->name_str(), name_) == 0) { if (strcmp(param->name_str(), name_) == 0) {
// printf("overriding param %s=%d by =%d\n", name_, value_, // tprintf("overriding param {}={} by ={}\n", name_, value_,
// param); // *param);
value_ = *param; access_counts_.writing++;
value_ = *param;
break; break;
} }
} }
} }
virtual std::string formatted_value_str() const override {
return std::to_string(value_);
}
private: private:
int32_t value_; int32_t value_;
int32_t default_; int32_t default_;
// Pointer to the vector that contains this param (not owned by this class).
std::vector<IntParam *> *params_vec_; // Pointer to the vector that contains this param (not owned by this class). Used by the destructor.
ParamsVectors *params_vec_;
}; };
class BoolParam : public Param { class BoolParam : public Param {
@ -193,40 +279,51 @@ public:
: Param(name, comment, init) { : Param(name, comment, init) {
value_ = value; value_ = value;
default_ = value; default_ = value;
params_vec_ = &(vec->bool_params); access_counts_.writing++;
vec->bool_params.push_back(this); params_vec_ = vec;
vec->bool_params().push_back(this);
} }
~BoolParam() { ~BoolParam() {
ParamUtils::RemoveParam<BoolParam>(this, params_vec_); ParamUtils::RemoveParam<BoolParam>(this, &params_vec_->bool_params());
} }
operator bool() const { operator bool() const {
return value_; access_counts_.reading++;
return value_;
} }
void operator=(bool value) { void operator=(bool value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void set_value(bool value) { void set_value(bool value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void ResetToDefault() { void ResetToDefault() {
value_ = default_; access_counts_.writing++;
value_ = default_;
} }
void ResetFrom(const ParamsVectors *vec) { void ResetFrom(const ParamsVectors *vec) {
for (auto *param : vec->bool_params) { for (auto *param : vec->bool_params_c()) {
if (strcmp(param->name_str(), name_) == 0) { if (strcmp(param->name_str(), name_) == 0) {
// printf("overriding param %s=%s by =%s\n", name_, value_ ? "true" : // tprintf("overriding param {}={} by ={}\n", name_, value_ ? "true" :
// "false", *param ? "true" : "false"); // "false", *param ? "true" : "false");
value_ = *param; access_counts_.writing++;
value_ = *param;
break; break;
} }
} }
} }
virtual std::string formatted_value_str() const override {
return std::to_string(value_);
}
private: private:
bool value_; bool value_;
bool default_; bool default_;
// Pointer to the vector that contains this param (not owned by this class). // Pointer to the vector that contains this param (not owned by this class).
std::vector<BoolParam *> *params_vec_; ParamsVectors *params_vec_;
}; };
class StringParam : public Param { class StringParam : public Param {
@ -236,52 +333,74 @@ public:
: Param(name, comment, init) { : Param(name, comment, init) {
value_ = value; value_ = value;
default_ = value; default_ = value;
params_vec_ = &(vec->string_params); access_counts_.writing++;
vec->string_params.push_back(this); params_vec_ = vec;
vec->string_params().push_back(this);
} }
~StringParam() { ~StringParam() {
ParamUtils::RemoveParam<StringParam>(this, params_vec_); ParamUtils::RemoveParam<StringParam>(this, &params_vec_->string_params());
} }
operator std::string &() { operator std::string &() {
return value_; access_counts_.reading++;
return value_;
} }
const char *c_str() const { const char *c_str() const {
return value_.c_str(); access_counts_.reading++;
return value_.c_str();
} }
bool contains(char c) const { bool contains(char c) const {
return value_.find(c) != std::string::npos; access_counts_.reading++;
return value_.find(c) != std::string::npos;
} }
bool empty() const { bool empty() const {
return value_.empty(); access_counts_.reading++;
return value_.empty();
} }
bool operator==(const std::string &other) const { bool operator==(const std::string &other) const {
return value_ == other; access_counts_.reading++;
return value_ == other;
} }
void operator=(const std::string &value) { void operator=(const std::string &value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void set_value(const std::string &value) { void set_value(const std::string &value) {
value_ = value; access_counts_.writing++;
value_ = value;
}
const std::string &value() {
access_counts_.reading++;
return value_;
} }
void ResetToDefault() { void ResetToDefault() {
value_ = default_; access_counts_.writing++;
value_ = default_;
} }
void ResetFrom(const ParamsVectors *vec) { void ResetFrom(const ParamsVectors *vec) {
for (auto *param : vec->string_params) { for (auto *param : vec->string_params_c()) {
if (strcmp(param->name_str(), name_) == 0) { if (strcmp(param->name_str(), name_) == 0) {
// printf("overriding param %s=%s by =%s\n", name_, value_, // tprintf("overriding param {}={} by ={}\n", name_, value_,
// param->c_str()); // param->c_str());
value_ = *param; access_counts_.writing++;
value_ = *param;
break; break;
} }
} }
} }
virtual std::string formatted_value_str() const override {
std::string rv = (const char *)u8"«";
rv += value_;
rv += (const char *)u8"»";
return rv;
}
private: private:
std::string value_; std::string value_;
std::string default_; std::string default_;
// Pointer to the vector that contains this param (not owned by this class). // Pointer to the vector that contains this param (not owned by this class).
std::vector<StringParam *> *params_vec_; ParamsVectors *params_vec_;
}; };
class DoubleParam : public Param { class DoubleParam : public Param {
@ -290,40 +409,57 @@ public:
: Param(name, comment, init) { : Param(name, comment, init) {
value_ = value; value_ = value;
default_ = value; default_ = value;
params_vec_ = &(vec->double_params); access_counts_.writing++;
vec->double_params.push_back(this); params_vec_ = vec;
vec->double_params().push_back(this);
} }
~DoubleParam() { ~DoubleParam() {
ParamUtils::RemoveParam<DoubleParam>(this, params_vec_); ParamUtils::RemoveParam<DoubleParam>(this, &params_vec_->double_params());
} }
operator double() const { operator double() const {
return value_; access_counts_.reading++;
return value_;
} }
void operator=(double value) { void operator=(double value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void set_value(double value) { void set_value(double value) {
value_ = value; access_counts_.writing++;
value_ = value;
} }
void ResetToDefault() { void ResetToDefault() {
value_ = default_; access_counts_.writing++;
value_ = default_;
} }
void ResetFrom(const ParamsVectors *vec) { void ResetFrom(const ParamsVectors *vec) {
for (auto *param : vec->double_params) { for (auto *param : vec->double_params_c()) {
if (strcmp(param->name_str(), name_) == 0) { if (strcmp(param->name_str(), name_) == 0) {
// printf("overriding param %s=%f by =%f\n", name_, value_, // tprintf("overriding param {}={} by ={}\n", name_, value_,
// *param); // *param);
value_ = *param; access_counts_.writing++;
value_ = *param;
break; break;
} }
} }
} }
virtual std::string formatted_value_str() const override {
#if 0
return std::to_string(value_); // always outputs %.6f format style values
#else
char sbuf[40];
snprintf(sbuf, sizeof(sbuf), "%1.f", value_);
return sbuf;
#endif
}
private: private:
double value_; double value_;
double default_; double default_;
// Pointer to the vector that contains this param (not owned by this class). // Pointer to the vector that contains this param (not owned by this class).
std::vector<DoubleParam *> *params_vec_; ParamsVectors *params_vec_;
}; };
// Global parameter lists. // Global parameter lists.
@ -338,6 +474,7 @@ private:
TESS_API TESS_API
ParamsVectors *GlobalParams(); ParamsVectors *GlobalParams();
/************************************************************************* /*************************************************************************
* Note on defining parameters. * Note on defining parameters.
* *
@ -382,6 +519,12 @@ ParamsVectors *GlobalParams();
#define double_INIT_MEMBER(name, val, comment, vec) name(val, #name, comment, true, vec) #define double_INIT_MEMBER(name, val, comment, vec) name(val, #name, comment, true, vec)
// ------------------------------------
extern BOOL_VAR_H(debug_all);
extern STRING_VAR_H(vars_report_file);
extern BOOL_VAR_H(report_all_variables);
} // namespace tesseract } // namespace tesseract
#endif #endif