All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mftraining.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Filename: mftraining.c
3 ** Purpose: Separates training pages into files for each character.
4 ** Strips from files only the features and there parameters of
5  the feature type mf.
6 ** Author: Dan Johnson
7 ** Revisment: Christy Russon
8 ** Environment: HPUX 6.5
9 ** Library: HPUX 6.5
10 ** History: Fri Aug 18 08:53:50 1989, DSJ, Created.
11 ** 5/25/90, DSJ, Adapted to multiple feature types.
12 ** Tuesday, May 17, 1998 Changes made to make feature specific and
13 ** simplify structures. First step in simplifying training process.
14 **
15  ** (c) Copyright Hewlett-Packard Company, 1988.
16  ** Licensed under the Apache License, Version 2.0 (the "License");
17  ** you may not use this file except in compliance with the License.
18  ** You may obtain a copy of the License at
19  ** http://www.apache.org/licenses/LICENSE-2.0
20  ** Unless required by applicable law or agreed to in writing, software
21  ** distributed under the License is distributed on an "AS IS" BASIS,
22  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23  ** See the License for the specific language governing permissions and
24  ** limitations under the License.
25 ******************************************************************************/
26 /*----------------------------------------------------------------------------
27  Include Files and Type Defines
28 ----------------------------------------------------------------------------*/
29 #ifdef HAVE_CONFIG_H
30 #include "config_auto.h"
31 #endif
32 
33 #include <string.h>
34 #include <stdio.h>
35 #define _USE_MATH_DEFINES
36 #include <math.h>
37 #ifdef _WIN32
38 #ifndef M_PI
39 #define M_PI 3.14159265358979323846
40 #endif
41 #endif
42 
43 #include "classify.h"
44 #include "cluster.h"
45 #include "clusttool.h"
46 #include "commontraining.h"
47 #include "danerror.h"
48 #include "efio.h"
49 #include "emalloc.h"
50 #include "featdefs.h"
51 #include "fontinfo.h"
52 #include "genericvector.h"
53 #include "indexmapbidi.h"
54 #include "intproto.h"
55 #include "mastertrainer.h"
56 #include "mergenf.h"
57 #include "mf.h"
58 #include "ndminx.h"
59 #include "ocrfeatures.h"
60 #include "oldlist.h"
61 #include "protos.h"
62 #include "shapetable.h"
63 #include "tessopt.h"
64 #include "tprintf.h"
65 #include "unicity_table.h"
66 
72 using tesseract::Shape;
74 
75 #define PROGRAM_FEATURE_TYPE "mf"
76 
77 // Max length of a fake shape label.
78 const int kMaxShapeLabelLength = 10;
79 
81 
82 /*----------------------------------------------------------------------------
83  Public Function Prototypes
84 ----------------------------------------------------------------------------*/
85 int main (
86  int argc,
87  char **argv);
88 
89 
90 /*----------------------------------------------------------------------------
91  Public Code
92 -----------------------------------------------------------------------------*/
93 #ifndef GRAPHICS_DISABLED
94 static void DisplayProtoList(const char* ch, LIST protolist) {
95  void* window = c_create_window("Char samples", 50, 200,
96  520, 520, -130.0, 130.0, -130.0, 130.0);
97  LIST proto = protolist;
98  iterate(proto) {
99  PROTOTYPE* prototype = reinterpret_cast<PROTOTYPE *>(first_node(proto));
100  if (prototype->Significant)
101  c_line_color_index(window, Green);
102  else if (prototype->NumSamples == 0)
103  c_line_color_index(window, Blue);
104  else if (prototype->Merged)
105  c_line_color_index(window, Magenta);
106  else
107  c_line_color_index(window, Red);
108  float x = CenterX(prototype->Mean);
109  float y = CenterY(prototype->Mean);
110  double angle = OrientationOf(prototype->Mean) * 2 * M_PI;
111  float dx = static_cast<float>(LengthOf(prototype->Mean) * cos(angle) / 2);
112  float dy = static_cast<float>(LengthOf(prototype->Mean) * sin(angle) / 2);
113  c_move(window, (x - dx) * 256, (y - dy) * 256);
114  c_draw(window, (x + dx) * 256, (y + dy) * 256);
115  if (prototype->Significant)
116  tprintf("Green proto at (%g,%g)+(%g,%g) %d samples\n",
117  x, y, dx, dy, prototype->NumSamples);
118  else if (prototype->NumSamples > 0 && !prototype->Merged)
119  tprintf("Red proto at (%g,%g)+(%g,%g) %d samples\n",
120  x, y, dx, dy, prototype->NumSamples);
121  }
122  c_make_current(window);
123 }
124 #endif // GRAPHICS_DISABLED
125 
126 // Helper to run clustering on a single config.
127 // Mostly copied from the old mftraining, but with renamed variables.
128 static LIST ClusterOneConfig(int shape_id, const char* class_label,
129  LIST mf_classes,
130  const ShapeTable& shape_table,
131  MasterTrainer* trainer) {
132  int num_samples;
133  CLUSTERER *clusterer = trainer->SetupForClustering(shape_table,
134  feature_defs,
135  shape_id,
136  &num_samples);
137  Config.MagicSamples = num_samples;
138  LIST proto_list = ClusterSamples(clusterer, &Config);
139  CleanUpUnusedData(proto_list);
140 
141  // Merge protos where reasonable to make more of them significant by
142  // representing almost all samples of the class/font.
143  MergeInsignificantProtos(proto_list, class_label, clusterer, &Config);
144  #ifndef GRAPHICS_DISABLED
145  if (strcmp(FLAGS_test_ch.c_str(), class_label) == 0)
146  DisplayProtoList(FLAGS_test_ch.c_str(), proto_list);
147  #endif // GRAPHICS_DISABLED
148  // Delete the protos that will not be used in the inttemp output file.
149  proto_list = RemoveInsignificantProtos(proto_list, true,
150  false,
151  clusterer->SampleSize);
152  FreeClusterer(clusterer);
153  MERGE_CLASS merge_class = FindClass(mf_classes, class_label);
154  if (merge_class == NULL) {
155  merge_class = NewLabeledClass(class_label);
156  mf_classes = push(mf_classes, merge_class);
157  }
158  int config_id = AddConfigToClass(merge_class->Class);
159  merge_class->Class->font_set.push_back(shape_id);
160  LIST proto_it = proto_list;
161  iterate(proto_it) {
162  PROTOTYPE* prototype = reinterpret_cast<PROTOTYPE*>(first_node(proto_it));
163  // See if proto can be approximated by existing proto.
164  int p_id = FindClosestExistingProto(merge_class->Class,
165  merge_class->NumMerged, prototype);
166  if (p_id == NO_PROTO) {
167  // Need to make a new proto, as it doesn't match anything.
168  p_id = AddProtoToClass(merge_class->Class);
169  MakeNewFromOld(ProtoIn(merge_class->Class, p_id), prototype);
170  merge_class->NumMerged[p_id] = 1;
171  } else {
172  PROTO_STRUCT dummy_proto;
173  MakeNewFromOld(&dummy_proto, prototype);
174  // Merge with the similar proto.
175  ComputeMergedProto(ProtoIn(merge_class->Class, p_id), &dummy_proto,
176  static_cast<FLOAT32>(merge_class->NumMerged[p_id]),
177  1.0,
178  ProtoIn(merge_class->Class, p_id));
179  merge_class->NumMerged[p_id]++;
180  }
181  AddProtoToConfig(p_id, merge_class->Class->Configurations[config_id]);
182  }
183  FreeProtoList(&proto_list);
184  return mf_classes;
185 }
186 
187 // Helper to setup the config map.
188 // Setup an index mapping from the shapes in the shape table to the classes
189 // that will be trained. In keeping with the original design, each shape
190 // with the same list of unichars becomes a different class and the configs
191 // represent the different combinations of fonts.
192 static void SetupConfigMap(ShapeTable* shape_table, IndexMapBiDi* config_map) {
193  int num_configs = shape_table->NumShapes();
194  config_map->Init(num_configs, true);
195  config_map->Setup();
196  for (int c1 = 0; c1 < num_configs; ++c1) {
197  // Only process ids that are not already merged.
198  if (config_map->SparseToCompact(c1) == c1) {
199  Shape* shape1 = shape_table->MutableShape(c1);
200  // Find all the subsequent shapes that are equal.
201  for (int c2 = c1 + 1; c2 < num_configs; ++c2) {
202  if (shape_table->MutableShape(c2)->IsEqualUnichars(shape1)) {
203  config_map->Merge(c1, c2);
204  }
205  }
206  }
207  }
208  config_map->CompleteMerges();
209 }
210 
241 int main (int argc, char **argv) {
242  ParseArguments(&argc, &argv);
243 
244  ShapeTable* shape_table = NULL;
245  STRING file_prefix;
246  // Load the training data.
247  MasterTrainer* trainer = tesseract::LoadTrainingData(argc, argv,
248  false,
249  &shape_table,
250  &file_prefix);
251  if (trainer == NULL)
252  return 1; // Failed.
253 
254  // Setup an index mapping from the shapes in the shape table to the classes
255  // that will be trained. In keeping with the original design, each shape
256  // with the same list of unichars becomes a different class and the configs
257  // represent the different combinations of fonts.
258  IndexMapBiDi config_map;
259  SetupConfigMap(shape_table, &config_map);
260 
261  WriteShapeTable(file_prefix, *shape_table);
262  // If the shape_table is flat, then either we didn't run shape clustering, or
263  // it did nothing, so we just output the trainer's unicharset.
264  // Otherwise shape_set will hold a fake unicharset with an entry for each
265  // shape in the shape table, and we will output that instead.
266  UNICHARSET shape_set;
267  const UNICHARSET* unicharset = &trainer->unicharset();
268  // If we ran shapeclustering (and it worked) then at least one shape will
269  // have multiple unichars, so we have to build a fake unicharset.
270  if (shape_table->AnyMultipleUnichars()) {
271  unicharset = &shape_set;
272  // Now build a fake unicharset for the compact shape space to keep the
273  // output modules happy that we are doing things correctly.
274  int num_shapes = config_map.CompactSize();
275  for (int s = 0; s < num_shapes; ++s) {
276  char shape_label[kMaxShapeLabelLength + 1];
277  snprintf(shape_label, kMaxShapeLabelLength, "sh%04d", s);
278  shape_set.unichar_insert(shape_label);
279  }
280  }
281 
282  // Now train each config separately.
283  int num_configs = shape_table->NumShapes();
284  LIST mf_classes = NIL_LIST;
285  for (int s = 0; s < num_configs; ++s) {
286  int unichar_id, font_id;
287  if (unicharset == &shape_set) {
288  // Using fake unichar_ids from the config_map/shape_set.
289  unichar_id = config_map.SparseToCompact(s);
290  } else {
291  // Get the real unichar_id from the shape table/unicharset.
292  shape_table->GetFirstUnicharAndFont(s, &unichar_id, &font_id);
293  }
294  const char* class_label = unicharset->id_to_unichar(unichar_id);
295  mf_classes = ClusterOneConfig(s, class_label, mf_classes, *shape_table,
296  trainer);
297  }
298  STRING inttemp_file = file_prefix;
299  inttemp_file += "inttemp";
300  STRING pffmtable_file = file_prefix;
301  pffmtable_file += "pffmtable";
302  CLASS_STRUCT* float_classes = SetUpForFloat2Int(*unicharset, mf_classes);
303  // Now write the inttemp and pffmtable.
304  trainer->WriteInttempAndPFFMTable(trainer->unicharset(), *unicharset,
305  *shape_table, float_classes,
306  inttemp_file.string(),
307  pffmtable_file.string());
308  delete [] float_classes;
309  FreeLabeledClassList(mf_classes);
310  delete trainer;
311  delete shape_table;
312  printf("Done!\n");
313  if (!FLAGS_test_ch.empty()) {
314  // If we are displaying debug window(s), wait for the user to look at them.
315  printf("Hit return to exit...\n");
316  while (getchar() != '\n');
317  }
318  return 0;
319 } /* main */
void Init(int size, bool all_mapped)
void ComputeMergedProto(PROTO p1, PROTO p2, FLOAT32 w1, FLOAT32 w2, PROTO MergedProto)
Definition: mergenf.cpp:133
MERGE_CLASS NewLabeledClass(const char *Label)
int AddConfigToClass(CLASS_TYPE Class)
Definition: protos.cpp:63
bool Merge(int compact_index1, int compact_index2)
#define ProtoIn(Class, Pid)
Definition: protos.h:123
#define NIL_LIST
Definition: oldlist.h:126
void c_line_color_index(void *win, C_COL index)
Definition: callcpp.cpp:70
Definition: callcpp.h:37
#define tprintf(...)
Definition: tprintf.h:31
#define CenterY(M)
Definition: mergenf.h:50
LIST RemoveInsignificantProtos(LIST ProtoList, BOOL8 KeepSigProtos, BOOL8 KeepInsigProtos, int N)
FLOAT32 * Mean
Definition: cluster.h:78
UnicityTableEqEq< int > font_set
Definition: protos.h:65
void FreeLabeledClassList(LIST ClassList)
unsigned Significant
Definition: cluster.h:68
MERGE_CLASS FindClass(LIST List, const char *Label)
Definition: callcpp.h:35
#define AddProtoToConfig(Pid, Config)
Definition: protos.h:93
void CleanUpUnusedData(LIST ProtoList)
#define LengthOf(M)
Definition: mergenf.h:51
ScrollView * c_create_window(const char *name, inT16 xpos, inT16 ypos, inT16 xsize, inT16 ysize, double xmin, double xmax, double ymin, double ymax)
Definition: callcpp.cpp:55
bool IsEqualUnichars(Shape *other)
Definition: shapetable.cpp:226
int MagicSamples
Definition: cluster.h:55
#define CenterX(M)
Definition: mergenf.h:49
int FindClosestExistingProto(CLASS_TYPE Class, int NumMerged[], PROTOTYPE *Prototype)
Definition: mergenf.cpp:167
FEATURE_DEFS_STRUCT feature_defs
Shape * MutableShape(int shape_id)
Definition: shapetable.h:326
const char *const id_to_unichar(UNICHAR_ID id) const
Definition: unicharset.cpp:266
LIST ClusterSamples(CLUSTERER *Clusterer, CLUSTERCONFIG *Config)
Definition: cluster.cpp:515
void MergeInsignificantProtos(LIST ProtoList, const char *label, CLUSTERER *Clusterer, CLUSTERCONFIG *Config)
int AddProtoToClass(CLASS_TYPE Class)
Definition: protos.cpp:99
unsigned NumSamples
Definition: cluster.h:75
void FreeProtoList(LIST *ProtoList)
Definition: cluster.cpp:571
virtual int SparseToCompact(int sparse_index) const
Definition: indexmapbidi.h:138
int push_back(T object)
Add an element in the table.
int main(int argc, char **argv)
Definition: mftraining.cpp:241
#define NO_PROTO
Definition: matchdefs.h:42
DECLARE_STRING_PARAM_FLAG(test_ch)
void ParseArguments(int *argc, char ***argv)
const UNICHARSET & unicharset() const
void c_draw(void *win, double x, double y)
Definition: callcpp.cpp:88
void unichar_insert(const char *const unichar_repr)
Definition: unicharset.cpp:612
#define first_node(l)
Definition: oldlist.h:139
#define iterate(l)
Definition: oldlist.h:159
CLUSTERCONFIG Config
void c_make_current(void *win)
Definition: callcpp.cpp:97
const int kMaxShapeLabelLength
Definition: mftraining.cpp:78
int CompactSize() const
Definition: indexmapbidi.h:61
Definition: callcpp.h:39
MasterTrainer * LoadTrainingData(int argc, const char *const *argv, bool replication, ShapeTable **shape_table, STRING *file_prefix)
void WriteInttempAndPFFMTable(const UNICHARSET &unicharset, const UNICHARSET &shape_set, const ShapeTable &shape_table, CLASS_STRUCT *float_classes, const char *inttemp_file, const char *pffmtable_file)
CLASS_STRUCT * SetUpForFloat2Int(const UNICHARSET &unicharset, LIST LabeledClassList)
bool AnyMultipleUnichars() const
Definition: shapetable.cpp:454
void FreeClusterer(CLUSTERER *Clusterer)
Definition: cluster.cpp:543
Definition: strngs.h:44
#define NULL
Definition: host.h:144
void c_move(void *win, double x, double y)
Definition: callcpp.cpp:79
void GetFirstUnicharAndFont(int shape_id, int *unichar_id, int *font_id) const
Definition: shapetable.cpp:414
const char * string() const
Definition: strngs.cpp:193
unsigned Merged
Definition: cluster.h:69
CLUSTERER * SetupForClustering(const ShapeTable &shape_table, const FEATURE_DEFS_STRUCT &feature_defs, int shape_id, int *num_samples)
inT16 SampleSize
Definition: cluster.h:87
void WriteShapeTable(const STRING &file_prefix, const ShapeTable &shape_table)
int NumMerged[MAX_NUM_PROTOS]
CLASS_TYPE Class
CONFIGS Configurations
Definition: protos.h:64
int NumShapes() const
Definition: shapetable.h:278
#define OrientationOf(M)
Definition: mergenf.h:52
LIST push(LIST list, void *element)
Definition: oldlist.cpp:323
void MakeNewFromOld(PROTO New, PROTOTYPE *Old)
Definition: mergenf.cpp:208