Tesseract  3.02
tesseract-ocr/ccmain/paramsd.cpp
Go to the documentation of this file.
00001 
00002 // File:        paramsd.cpp
00003 // Description: Tesseract parameter Editor
00004 // Author:      Joern Wanke
00005 // Created:     Wed Jul 18 10:05:01 PDT 2007
00006 //
00007 // (C) Copyright 2007, Google Inc.
00008 // Licensed under the Apache License, Version 2.0 (the "License");
00009 // you may not use this file except in compliance with the License.
00010 // You may obtain a copy of the License at
00011 // http://www.apache.org/licenses/LICENSE-2.0
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 //
00019 //
00020 // The parameters editor is used to edit all the parameters used within
00021 // tesseract from the ui.
00022 #ifdef _WIN32
00023 #else
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #endif
00027 
00028 #include <map>
00029 
00030 // Include automatically generated configuration file if running autoconf.
00031 #ifdef HAVE_CONFIG_H
00032 #include "config_auto.h"
00033 #endif
00034 
00035 #ifndef GRAPHICS_DISABLED
00036 #include "paramsd.h"
00037 
00038 
00039 #include "params.h"
00040 #include "scrollview.h"
00041 #include "svmnode.h"
00042 
00043 
00044 #define VARDIR        "configs/" /*parameters files */
00045 #define MAX_ITEMS_IN_SUBMENU 30
00046 
00047 // The following variables should remain static globals, since they
00048 // are used by debug editor, which uses a single Tesseract instance.
00049 //
00050 // Contains the mappings from unique VC ids to their actual pointers.
00051 static std::map<int, ParamContent*> vcMap;
00052 static int nrParams = 0;
00053 static int writeCommands[2];
00054 
00055 ELISTIZE(ParamContent)
00056 
00057 // Constructors for the various ParamTypes.
00058 ParamContent::ParamContent(tesseract::StringParam* it) {
00059   my_id_ = nrParams;
00060   nrParams++;
00061   param_type_ = VT_STRING;
00062   sIt = it;
00063   vcMap[my_id_] = this;
00064 }
00065 // Constructors for the various ParamTypes.
00066 ParamContent::ParamContent(tesseract::IntParam* it) {
00067   my_id_ = nrParams;
00068   nrParams++;
00069   param_type_ = VT_INTEGER;
00070   iIt = it;
00071   vcMap[my_id_] = this;
00072 }
00073 // Constructors for the various ParamTypes.
00074 ParamContent::ParamContent(tesseract::BoolParam* it) {
00075   my_id_ = nrParams;
00076   nrParams++;
00077   param_type_ = VT_BOOLEAN;
00078   bIt = it;
00079   vcMap[my_id_] = this;
00080 }
00081 // Constructors for the various ParamTypes.
00082 ParamContent::ParamContent(tesseract::DoubleParam* it) {
00083   my_id_ = nrParams;
00084   nrParams++;
00085   param_type_ = VT_DOUBLE;
00086   dIt = it;
00087   vcMap[my_id_] = this;
00088 }
00089 
00090 // Gets a VC object identified by its ID.
00091 ParamContent* ParamContent::GetParamContentById(int id) {
00092   return vcMap[id];
00093 }
00094 
00095 // Copy the first N words from the source string to the target string.
00096 // Words are delimited by "_".
00097 void ParamsEditor::GetFirstWords(
00098                      const char *s,  // source string
00099                      int n,          // number of words
00100                      char *t         // target string
00101                     ) {
00102   int full_length = strlen(s);
00103   int reqd_len = 0;              // No. of chars requird
00104   const char *next_word = s;
00105 
00106   while ((n > 0) && reqd_len < full_length) {
00107     reqd_len += strcspn(next_word, "_") + 1;
00108     next_word += reqd_len;
00109     n--;
00110   }
00111   strncpy(t, s, reqd_len);
00112   t[reqd_len] = '\0';            // ensure null terminal
00113 }
00114 
00115 // Getter for the name.
00116 const char* ParamContent::GetName() const {
00117   if (param_type_ == VT_INTEGER) { return iIt->name_str(); }
00118   else if (param_type_ == VT_BOOLEAN) { return bIt->name_str(); }
00119   else if (param_type_ == VT_DOUBLE) { return dIt->name_str(); }
00120   else if (param_type_ == VT_STRING) { return sIt->name_str(); }
00121   else
00122     return "ERROR: ParamContent::GetName()";
00123 }
00124 
00125 // Getter for the description.
00126 const char* ParamContent::GetDescription() const {
00127   if (param_type_ == VT_INTEGER) { return iIt->info_str(); }
00128   else if (param_type_ == VT_BOOLEAN) { return bIt->info_str(); }
00129   else if (param_type_ == VT_DOUBLE) { return dIt->info_str(); }
00130   else if (param_type_ == VT_STRING) { return sIt->info_str(); }
00131   else return NULL;
00132 }
00133 
00134 // Getter for the value.
00135 const char* ParamContent::GetValue() const {
00136 char* msg = new char[1024];
00137   if (param_type_ == VT_INTEGER) {
00138     sprintf(msg, "%d", ((inT32) *(iIt)));
00139   } else if (param_type_ == VT_BOOLEAN) {
00140     sprintf(msg, "%d", ((BOOL8) * (bIt)));
00141   } else if (param_type_ == VT_DOUBLE) {
00142     sprintf(msg, "%g", ((double) * (dIt)));
00143   } else if (param_type_ == VT_STRING) {
00144     if (((STRING) * (sIt)).string() != NULL) {
00145       sprintf(msg, "%s", ((STRING) * (sIt)).string());
00146     } else {
00147       sprintf(msg, "Null");
00148     }
00149   }
00150   return msg;
00151 }
00152 
00153 // Setter for the value.
00154 void ParamContent::SetValue(const char* val) {
00155 // TODO (wanke) Test if the values actually are properly converted.
00156 // (Quickly visible impacts?)
00157   changed_ = TRUE;
00158   if (param_type_ == VT_INTEGER) {
00159     iIt->set_value(atoi(val));
00160   } else if (param_type_ == VT_BOOLEAN) {
00161     bIt->set_value(atoi(val));
00162   } else if (param_type_ == VT_DOUBLE) {
00163     dIt->set_value(strtod(val, NULL));
00164   } else if (param_type_ == VT_STRING) {
00165     sIt->set_value(val);
00166   }
00167 }
00168 
00169 // Gets the up to the first 3 prefixes from s (split by _).
00170 // For example, tesseract_foo_bar will be split into tesseract,foo and bar.
00171 void ParamsEditor::GetPrefixes(const char* s, STRING* level_one,
00172                                STRING* level_two,
00173                                STRING* level_three) {
00174   char* p = new char[1024];
00175   GetFirstWords(s, 1, p);
00176   *level_one = p;
00177   GetFirstWords(s, 2, p);
00178   *level_two = p;
00179   GetFirstWords(s, 3, p);
00180   *level_three = p;
00181   delete[] p;
00182 }
00183 
00184 // Compare two VC objects by their name.
00185 int ParamContent::Compare(const void* v1, const void* v2) {
00186   const ParamContent* one =
00187     *reinterpret_cast<const ParamContent* const *>(v1);
00188   const ParamContent* two =
00189     *reinterpret_cast<const ParamContent* const *>(v2);
00190   return strcmp(one->GetName(), two->GetName());
00191 }
00192 
00193 // Find all editable parameters used within tesseract and create a
00194 // SVMenuNode tree from it.
00195 // TODO (wanke): This is actually sort of hackish.
00196 SVMenuNode* ParamsEditor::BuildListOfAllLeaves(tesseract::Tesseract *tess) {
00197   SVMenuNode* mr = new SVMenuNode();
00198   ParamContent_LIST vclist;
00199   ParamContent_IT vc_it(&vclist);
00200   // Amount counts the number of entries for a specific char*.
00201   // TODO(rays) get rid of the use of std::map.
00202   std::map<const char*, int> amount;
00203 
00204   // Add all parameters to a list.
00205   int v, i;
00206   int num_iterations = (tess->params() == NULL) ? 1 : 2;
00207   for (v = 0; v < num_iterations; ++v) {
00208     tesseract::ParamsVectors *vec = (v == 0) ? GlobalParams() : tess->params();
00209     for (i = 0; i < vec->int_params.size(); ++i) {
00210       vc_it.add_after_then_move(new ParamContent(vec->int_params[i]));
00211     }
00212     for (i = 0; i < vec->bool_params.size(); ++i) {
00213       vc_it.add_after_then_move(new ParamContent(vec->bool_params[i]));
00214     }
00215     for (i = 0; i < vec->string_params.size(); ++i) {
00216       vc_it.add_after_then_move(new ParamContent(vec->string_params[i]));
00217     }
00218     for (i = 0; i < vec->double_params.size(); ++i) {
00219       vc_it.add_after_then_move(new ParamContent(vec->double_params[i]));
00220     }
00221   }
00222 
00223   // Count the # of entries starting with a specific prefix.
00224   for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) {
00225     ParamContent* vc = vc_it.data();
00226     STRING tag;
00227     STRING tag2;
00228     STRING tag3;
00229 
00230     GetPrefixes(vc->GetName(), &tag, &tag2, &tag3);
00231     amount[tag.string()]++;
00232     amount[tag2.string()]++;
00233     amount[tag3.string()]++;
00234   }
00235 
00236   vclist.sort(ParamContent::Compare);  // Sort the list alphabetically.
00237 
00238   SVMenuNode* other = mr->AddChild("OTHER");
00239 
00240   // go through the list again and this time create the menu structure.
00241   vc_it.move_to_first();
00242   for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) {
00243     ParamContent* vc = vc_it.data();
00244     STRING tag;
00245     STRING tag2;
00246     STRING tag3;
00247     GetPrefixes(vc->GetName(), &tag, &tag2, &tag3);
00248 
00249     if (amount[tag.string()] == 1) { other->AddChild(vc->GetName(), vc->GetId(),
00250                                             vc->GetValue(),
00251                                             vc->GetDescription());
00252     } else {  // More than one would use this submenu -> create submenu.
00253       SVMenuNode* sv = mr->AddChild(tag.string());
00254       if ((amount[tag.string()] <= MAX_ITEMS_IN_SUBMENU) ||
00255           (amount[tag2.string()] <= 1)) {
00256         sv->AddChild(vc->GetName(), vc->GetId(),
00257                      vc->GetValue(), vc->GetDescription());
00258       } else {  // Make subsubmenus.
00259         SVMenuNode* sv2 = sv->AddChild(tag2.string());
00260         sv2->AddChild(vc->GetName(), vc->GetId(),
00261                       vc->GetValue(), vc->GetDescription());
00262       }
00263     }
00264   }
00265   return mr;
00266 }
00267 
00268 // Event listener. Waits for SVET_POPUP events and processes them.
00269 void ParamsEditor::Notify(const SVEvent* sve) {
00270   if (sve->type == SVET_POPUP) {  // only catch SVET_POPUP!
00271     char* param = sve->parameter;
00272     if (sve->command_id == writeCommands[0]) {
00273       WriteParams(param, false);
00274     } else if (sve->command_id == writeCommands[1]) {
00275       WriteParams(param, true);
00276     } else {
00277       ParamContent* vc = ParamContent::GetParamContentById(
00278           sve->command_id);
00279       vc->SetValue(param);
00280       sv_window_->AddMessage("Setting %s to %s",
00281                              vc->GetName(), vc->GetValue());
00282     }
00283   }
00284 }
00285 
00286 // Integrate the parameters editor as popupmenu into the existing scrollview
00287 // window (usually the pg editor). If sv == null, create a new empty
00288 // empty window and attach the parameters editor to that window (ugly).
00289 ParamsEditor::ParamsEditor(tesseract::Tesseract* tess,
00290                                  ScrollView* sv) {
00291   if (sv == NULL) {
00292     const char* name = "ParamEditorMAIN";
00293     sv = new ScrollView(name, 1, 1, 200, 200, 300, 200);
00294   }
00295 
00296   sv_window_ = sv;
00297 
00298   //Only one event handler per window.
00299   //sv->AddEventHandler((SVEventHandler*) this);
00300 
00301   SVMenuNode* svMenuRoot = BuildListOfAllLeaves(tess);
00302 
00303   STRING paramfile;
00304   paramfile = tess->datadir;
00305   paramfile += VARDIR;             // parameters dir
00306   paramfile += "edited";           // actual name
00307 
00308   SVMenuNode* std_menu = svMenuRoot->AddChild ("Build Config File");
00309 
00310   writeCommands[0] = nrParams+1;
00311   std_menu->AddChild("All Parameters", writeCommands[0],
00312                      paramfile.string(), "Config file name?");
00313 
00314   writeCommands[1] = nrParams+2;
00315   std_menu->AddChild ("changed_ Parameters Only", writeCommands[1],
00316                       paramfile.string(), "Config file name?");
00317 
00318   svMenuRoot->BuildMenu(sv, false);
00319 }
00320 
00321 
00322 // Write all (changed_) parameters to a config file.
00323 void ParamsEditor::WriteParams(char *filename,
00324                                bool changes_only) {
00325   FILE *fp;                      // input file
00326   char msg_str[255];
00327                                  // if file exists
00328   if ((fp = fopen (filename, "rb")) != NULL) {
00329     fclose(fp);
00330     sprintf (msg_str, "Overwrite file " "%s" "? (Y/N)", filename);
00331     int a = sv_window_->ShowYesNoDialog(msg_str);
00332     if (a == 'n') { return; }  // dont write
00333   }
00334 
00335 
00336   fp = fopen (filename, "wb");  // can we write to it?
00337   if (fp == NULL) {
00338     sv_window_->AddMessage("Cant write to file " "%s" "", filename);
00339     return;
00340   }
00341 
00342   for (std::map<int, ParamContent*>::iterator iter = vcMap.begin();
00343                                           iter != vcMap.end();
00344                                           ++iter) {
00345     ParamContent* cur = iter->second;
00346     if (!changes_only || cur->HasChanged()) {
00347       fprintf (fp, "%-25s   %-12s   # %s\n",
00348                cur->GetName(), cur->GetValue(), cur->GetDescription());
00349     }
00350   }
00351   fclose(fp);
00352 }
00353 #endif