tesseract 3.04.01

classify/intproto.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  ** Filename:    intproto.c
00003  ** Purpose:     Definition of data structures for integer protos.
00004  ** Author:      Dan Johnson
00005  ** History:     Thu Feb  7 14:38:16 1991, DSJ, Created.
00006  **
00007  ** (c) Copyright Hewlett-Packard Company, 1988.
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  ******************************************************************************/
00018 /*-----------------------------------------------------------------------------
00019           Include Files and Type Defines
00020 -----------------------------------------------------------------------------*/
00021 
00022 #include <math.h>
00023 #include <stdio.h>
00024 #include <assert.h>
00025 #ifdef __UNIX__
00026 #include <unistd.h>
00027 #endif
00028 
00029 #include "classify.h"
00030 #include "const.h"
00031 #include "emalloc.h"
00032 #include "fontinfo.h"
00033 #include "genericvector.h"
00034 #include "globals.h"
00035 #include "helpers.h"
00036 #include "intproto.h"
00037 #include "mfoutline.h"
00038 #include "ndminx.h"
00039 #include "picofeat.h"
00040 #include "points.h"
00041 #include "shapetable.h"
00042 #include "svmnode.h"
00043 
00044 // Include automatically generated configuration file if running autoconf.
00045 #ifdef HAVE_CONFIG_H
00046 #include "config_auto.h"
00047 #endif
00048 
00049 using tesseract::FontInfo;
00050 using tesseract::FontSet;
00051 using tesseract::FontSpacingInfo;
00052 
00053 /* match debug display constants*/
00054 #define PROTO_PRUNER_SCALE  (4.0)
00055 
00056 #define INT_DESCENDER (0.0  * INT_CHAR_NORM_RANGE)
00057 #define INT_BASELINE  (0.25 * INT_CHAR_NORM_RANGE)
00058 #define INT_XHEIGHT (0.75 * INT_CHAR_NORM_RANGE)
00059 #define INT_CAPHEIGHT (1.0  * INT_CHAR_NORM_RANGE)
00060 
00061 #define INT_XCENTER (0.5  * INT_CHAR_NORM_RANGE)
00062 #define INT_YCENTER (0.5  * INT_CHAR_NORM_RANGE)
00063 #define INT_XRADIUS (0.2  * INT_CHAR_NORM_RANGE)
00064 #define INT_YRADIUS (0.2  * INT_CHAR_NORM_RANGE)
00065 #define INT_MIN_X 0
00066 #define INT_MIN_Y 0
00067 #define INT_MAX_X INT_CHAR_NORM_RANGE
00068 #define INT_MAX_Y INT_CHAR_NORM_RANGE
00069 
00071 #define HV_TOLERANCE  (0.0025)   /* approx 0.9 degrees */
00072 
00073 typedef enum
00074 { StartSwitch, EndSwitch, LastSwitch }
00075 SWITCH_TYPE;
00076 #define MAX_NUM_SWITCHES  3
00077 
00078 typedef struct
00079 {
00080   SWITCH_TYPE Type;
00081   inT8 X, Y;
00082   inT16 YInit;
00083   inT16 Delta;
00084 }
00085 
00086 
00087 FILL_SWITCH;
00088 
00089 typedef struct
00090 {
00091   uinT8 NextSwitch;
00092   uinT8 AngleStart, AngleEnd;
00093   inT8 X;
00094   inT16 YStart, YEnd;
00095   inT16 StartDelta, EndDelta;
00096   FILL_SWITCH Switch[MAX_NUM_SWITCHES];
00097 }
00098 
00099 
00100 TABLE_FILLER;
00101 
00102 typedef struct
00103 {
00104   inT8 X;
00105   inT8 YStart, YEnd;
00106   uinT8 AngleStart, AngleEnd;
00107 }
00108 
00109 
00110 FILL_SPEC;
00111 
00112 
00113 /* constants for conversion from old inttemp format */
00114 #define OLD_MAX_NUM_CONFIGS      32
00115 #define OLD_WERDS_PER_CONFIG_VEC ((OLD_MAX_NUM_CONFIGS + BITS_PER_WERD - 1) /\
00116                                   BITS_PER_WERD)
00117 
00118 /*-----------------------------------------------------------------------------
00119             Macros
00120 -----------------------------------------------------------------------------*/
00122 #define CircularIncrement(i,r)  (((i) < (r) - 1)?((i)++):((i) = 0))
00123 
00125 #define MapParam(P,O,N)   (floor (((P) + (O)) * (N)))
00126 
00127 /*---------------------------------------------------------------------------
00128             Private Function Prototypes
00129 ----------------------------------------------------------------------------*/
00130 FLOAT32 BucketStart(int Bucket, FLOAT32 Offset, int NumBuckets);
00131 
00132 FLOAT32 BucketEnd(int Bucket, FLOAT32 Offset, int NumBuckets);
00133 
00134 void DoFill(FILL_SPEC *FillSpec,
00135             CLASS_PRUNER_STRUCT* Pruner,
00136             register uinT32 ClassMask,
00137             register uinT32 ClassCount,
00138             register uinT32 WordIndex);
00139 
00140 BOOL8 FillerDone(TABLE_FILLER *Filler);
00141 
00142 void FillPPCircularBits(uinT32
00143                         ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
00144                         int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug);
00145 
00146 void FillPPLinearBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
00147                       int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug);
00148 
00149 void GetCPPadsForLevel(int Level,
00150                        FLOAT32 *EndPad,
00151                        FLOAT32 *SidePad,
00152                        FLOAT32 *AnglePad);
00153 
00154 ScrollView::Color GetMatchColorFor(FLOAT32 Evidence);
00155 
00156 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill);
00157 
00158 void InitTableFiller(FLOAT32 EndPad,
00159                      FLOAT32 SidePad,
00160                      FLOAT32 AnglePad,
00161                      PROTO Proto,
00162                      TABLE_FILLER *Filler);
00163 
00164 #ifndef GRAPHICS_DISABLED
00165 void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT* Feature,
00166                       ScrollView::Color color);
00167 
00168 void RenderIntProto(ScrollView *window,
00169                     INT_CLASS Class,
00170                     PROTO_ID ProtoId,
00171                     ScrollView::Color color);
00172 #endif  // GRAPHICS_DISABLED
00173 
00174 int TruncateParam(FLOAT32 Param, int Min, int Max, char *Id);
00175 
00176 /*-----------------------------------------------------------------------------
00177         Global Data Definitions and Declarations
00178 -----------------------------------------------------------------------------*/
00179 
00180 /* global display lists used to display proto and feature match information*/
00181 ScrollView *IntMatchWindow = NULL;
00182 ScrollView *FeatureDisplayWindow = NULL;
00183 ScrollView *ProtoDisplayWindow = NULL;
00184 
00185 /*-----------------------------------------------------------------------------
00186         Variables
00187 -----------------------------------------------------------------------------*/
00188 
00189 /* control knobs */
00190 INT_VAR(classify_num_cp_levels, 3, "Number of Class Pruner Levels");
00191 double_VAR(classify_cp_angle_pad_loose, 45.0,
00192            "Class Pruner Angle Pad Loose");
00193 double_VAR(classify_cp_angle_pad_medium, 20.0,
00194            "Class Pruner Angle Pad Medium");
00195 double_VAR(classify_cp_angle_pad_tight, 10.0,
00196            "CLass Pruner Angle Pad Tight");
00197 double_VAR(classify_cp_end_pad_loose, 0.5, "Class Pruner End Pad Loose");
00198 double_VAR(classify_cp_end_pad_medium, 0.5, "Class Pruner End Pad Medium");
00199 double_VAR(classify_cp_end_pad_tight, 0.5, "Class Pruner End Pad Tight");
00200 double_VAR(classify_cp_side_pad_loose, 2.5, "Class Pruner Side Pad Loose");
00201 double_VAR(classify_cp_side_pad_medium, 1.2, "Class Pruner Side Pad Medium");
00202 double_VAR(classify_cp_side_pad_tight, 0.6, "Class Pruner Side Pad Tight");
00203 double_VAR(classify_pp_angle_pad, 45.0, "Proto Pruner Angle Pad");
00204 double_VAR(classify_pp_end_pad, 0.5, "Proto Prune End Pad");
00205 double_VAR(classify_pp_side_pad, 2.5, "Proto Pruner Side Pad");
00206 
00207 /*-----------------------------------------------------------------------------
00208               Public Code
00209 -----------------------------------------------------------------------------*/
00212 INT_FEATURE_STRUCT::INT_FEATURE_STRUCT(const FCOORD& pos, uinT8 theta)
00213   : X(ClipToRange<inT16>(static_cast<inT16>(pos.x() + 0.5), 0, 255)),
00214     Y(ClipToRange<inT16>(static_cast<inT16>(pos.y() + 0.5), 0, 255)),
00215     Theta(theta),
00216     CP_misses(0) {
00217 }
00219 INT_FEATURE_STRUCT::INT_FEATURE_STRUCT(int x, int y, int theta)
00220   : X(static_cast<uinT8>(ClipToRange(x, 0, MAX_UINT8))),
00221     Y(static_cast<uinT8>(ClipToRange(y, 0, MAX_UINT8))),
00222     Theta(static_cast<uinT8>(ClipToRange(theta, 0, MAX_UINT8))),
00223     CP_misses(0) {
00224 }
00225 
00240 void AddIntClass(INT_TEMPLATES Templates, CLASS_ID ClassId, INT_CLASS Class) {
00241   int Pruner;
00242 
00243   assert (LegalClassId (ClassId));
00244   if (ClassId != Templates->NumClasses) {
00245     fprintf(stderr, "Please make sure that classes are added to templates");
00246     fprintf(stderr, " in increasing order of ClassIds\n");
00247     exit(1);
00248   }
00249   ClassForClassId (Templates, ClassId) = Class;
00250   Templates->NumClasses++;
00251 
00252   if (Templates->NumClasses > MaxNumClassesIn (Templates)) {
00253     Pruner = Templates->NumClassPruners++;
00254     Templates->ClassPruners[Pruner] = new CLASS_PRUNER_STRUCT;
00255     memset(Templates->ClassPruners[Pruner], 0, sizeof(CLASS_PRUNER_STRUCT));
00256   }
00257 }                                /* AddIntClass */
00258 
00259 
00272 int AddIntConfig(INT_CLASS Class) {
00273   int Index;
00274 
00275   assert(Class->NumConfigs < MAX_NUM_CONFIGS);
00276 
00277   Index = Class->NumConfigs++;
00278   Class->ConfigLengths[Index] = 0;
00279   return Index;
00280 }                                /* AddIntConfig */
00281 
00282 
00295 int AddIntProto(INT_CLASS Class) {
00296   int Index;
00297   int ProtoSetId;
00298   PROTO_SET ProtoSet;
00299   INT_PROTO Proto;
00300   uinT32 *Word;
00301 
00302   if (Class->NumProtos >= MAX_NUM_PROTOS)
00303     return (NO_PROTO);
00304 
00305   Index = Class->NumProtos++;
00306 
00307   if (Class->NumProtos > MaxNumIntProtosIn(Class)) {
00308     ProtoSetId = Class->NumProtoSets++;
00309 
00310     ProtoSet = (PROTO_SET) Emalloc(sizeof(PROTO_SET_STRUCT));
00311     Class->ProtoSets[ProtoSetId] = ProtoSet;
00312     memset(ProtoSet, 0, sizeof(*ProtoSet));
00313 
00314     /* reallocate space for the proto lengths and install in class */
00315     Class->ProtoLengths =
00316       (uinT8 *)Erealloc(Class->ProtoLengths,
00317                         MaxNumIntProtosIn(Class) * sizeof(uinT8));
00318     memset(&Class->ProtoLengths[Index], 0,
00319            sizeof(*Class->ProtoLengths) * (MaxNumIntProtosIn(Class) - Index));
00320   }
00321 
00322   /* initialize proto so its length is zero and it isn't in any configs */
00323   Class->ProtoLengths[Index] = 0;
00324   Proto = ProtoForProtoId (Class, Index);
00325   for (Word = Proto->Configs;
00326        Word < Proto->Configs + WERDS_PER_CONFIG_VEC; *Word++ = 0);
00327 
00328   return (Index);
00329 
00330 }
00331 
00332 
00346 void AddProtoToClassPruner (PROTO Proto, CLASS_ID ClassId,
00347                             INT_TEMPLATES Templates)
00348 #define MAX_LEVEL     2
00349 {
00350   CLASS_PRUNER_STRUCT* Pruner;
00351   uinT32 ClassMask;
00352   uinT32 ClassCount;
00353   uinT32 WordIndex;
00354   int Level;
00355   FLOAT32 EndPad, SidePad, AnglePad;
00356   TABLE_FILLER TableFiller;
00357   FILL_SPEC FillSpec;
00358 
00359   Pruner = CPrunerFor (Templates, ClassId);
00360   WordIndex = CPrunerWordIndexFor (ClassId);
00361   ClassMask = CPrunerMaskFor (MAX_LEVEL, ClassId);
00362 
00363   for (Level = classify_num_cp_levels - 1; Level >= 0; Level--) {
00364     GetCPPadsForLevel(Level, &EndPad, &SidePad, &AnglePad);
00365     ClassCount = CPrunerMaskFor (Level, ClassId);
00366     InitTableFiller(EndPad, SidePad, AnglePad, Proto, &TableFiller);
00367 
00368     while (!FillerDone (&TableFiller)) {
00369       GetNextFill(&TableFiller, &FillSpec);
00370       DoFill(&FillSpec, Pruner, ClassMask, ClassCount, WordIndex);
00371     }
00372   }
00373 }                                /* AddProtoToClassPruner */
00374 
00375 
00389 void AddProtoToProtoPruner(PROTO Proto, int ProtoId,
00390                            INT_CLASS Class, bool debug) {
00391   FLOAT32 Angle, X, Y, Length;
00392   FLOAT32 Pad;
00393   int Index;
00394   PROTO_SET ProtoSet;
00395 
00396   if (ProtoId >= Class->NumProtos)
00397     cprintf("AddProtoToProtoPruner:assert failed: %d < %d",
00398             ProtoId, Class->NumProtos);
00399   assert(ProtoId < Class->NumProtos);
00400 
00401   Index = IndexForProto (ProtoId);
00402   ProtoSet = Class->ProtoSets[SetForProto (ProtoId)];
00403 
00404   Angle = Proto->Angle;
00405 #ifndef _WIN32
00406   assert(!isnan(Angle));
00407 #endif
00408 
00409   FillPPCircularBits (ProtoSet->ProtoPruner[PRUNER_ANGLE], Index,
00410                       Angle + ANGLE_SHIFT, classify_pp_angle_pad / 360.0,
00411                       debug);
00412 
00413   Angle *= 2.0 * PI;
00414   Length = Proto->Length;
00415 
00416   X = Proto->X + X_SHIFT;
00417   Pad = MAX (fabs (cos (Angle)) * (Length / 2.0 +
00418                                    classify_pp_end_pad *
00419                                    GetPicoFeatureLength ()),
00420              fabs (sin (Angle)) * (classify_pp_side_pad *
00421                                    GetPicoFeatureLength ()));
00422 
00423   FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_X], Index, X, Pad, debug);
00424 
00425   Y = Proto->Y + Y_SHIFT;
00426   Pad = MAX (fabs (sin (Angle)) * (Length / 2.0 +
00427                                    classify_pp_end_pad *
00428                                    GetPicoFeatureLength ()),
00429              fabs (cos (Angle)) * (classify_pp_side_pad *
00430                                    GetPicoFeatureLength ()));
00431 
00432   FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_Y], Index, Y, Pad, debug);
00433 }                                /* AddProtoToProtoPruner */
00434 
00435 
00441 uinT8 Bucket8For(FLOAT32 param, FLOAT32 offset, int num_buckets) {
00442   int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
00443   return static_cast<uinT8>(ClipToRange(bucket, 0, num_buckets - 1));
00444 }
00445 uinT16 Bucket16For(FLOAT32 param, FLOAT32 offset, int num_buckets) {
00446   int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
00447   return static_cast<uinT16>(ClipToRange(bucket, 0, num_buckets - 1));
00448 }
00449 
00455 uinT8 CircBucketFor(FLOAT32 param, FLOAT32 offset, int num_buckets) {
00456   int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
00457   return static_cast<uinT8>(Modulo(bucket, num_buckets));
00458 }                                /* CircBucketFor */
00459 
00460 
00461 #ifndef GRAPHICS_DISABLED
00462 
00473 void UpdateMatchDisplay() {
00474   if (IntMatchWindow != NULL)
00475     IntMatchWindow->Update();
00476 }                                /* ClearMatchDisplay */
00477 #endif
00478 
00493 void ConvertConfig(BIT_VECTOR Config, int ConfigId, INT_CLASS Class) {
00494   int ProtoId;
00495   INT_PROTO Proto;
00496   int TotalLength;
00497 
00498   for (ProtoId = 0, TotalLength = 0;
00499     ProtoId < Class->NumProtos; ProtoId++) {
00500     if (test_bit(Config, ProtoId)) {
00501       Proto = ProtoForProtoId(Class, ProtoId);
00502       SET_BIT(Proto->Configs, ConfigId);
00503       TotalLength += Class->ProtoLengths[ProtoId];
00504     }
00505   }
00506   Class->ConfigLengths[ConfigId] = TotalLength;
00507 }                                /* ConvertConfig */
00508 
00509 
00510 namespace tesseract {
00522 void Classify::ConvertProto(PROTO Proto, int ProtoId, INT_CLASS Class) {
00523   INT_PROTO P;
00524   FLOAT32 Param;
00525 
00526   assert(ProtoId < Class->NumProtos);
00527 
00528   P = ProtoForProtoId(Class, ProtoId);
00529 
00530   Param = Proto->A * 128;
00531   P->A = TruncateParam(Param, -128, 127, NULL);
00532 
00533   Param = -Proto->B * 256;
00534   P->B = TruncateParam(Param, 0, 255, NULL);
00535 
00536   Param = Proto->C * 128;
00537   P->C = TruncateParam(Param, -128, 127, NULL);
00538 
00539   Param = Proto->Angle * 256;
00540   if (Param < 0 || Param >= 256)
00541     P->Angle = 0;
00542   else
00543     P->Angle = (uinT8) Param;
00544 
00545   /* round proto length to nearest integer number of pico-features */
00546   Param = (Proto->Length / GetPicoFeatureLength()) + 0.5;
00547   Class->ProtoLengths[ProtoId] = TruncateParam(Param, 1, 255, NULL);
00548   if (classify_learning_debug_level >= 2)
00549     cprintf("Converted ffeat to (A=%d,B=%d,C=%d,L=%d)",
00550             P->A, P->B, P->C, Class->ProtoLengths[ProtoId]);
00551 }                                /* ConvertProto */
00552 
00553 
00564 INT_TEMPLATES Classify::CreateIntTemplates(CLASSES FloatProtos,
00565                                            const UNICHARSET&
00566                                            target_unicharset) {
00567   INT_TEMPLATES IntTemplates;
00568   CLASS_TYPE FClass;
00569   INT_CLASS IClass;
00570   int ClassId;
00571   int ProtoId;
00572   int ConfigId;
00573 
00574   IntTemplates = NewIntTemplates();
00575 
00576   for (ClassId = 0; ClassId < target_unicharset.size(); ClassId++) {
00577     FClass = &(FloatProtos[ClassId]);
00578     if (FClass->NumProtos == 0 && FClass->NumConfigs == 0 &&
00579         strcmp(target_unicharset.id_to_unichar(ClassId), " ") != 0) {
00580       cprintf("Warning: no protos/configs for %s in CreateIntTemplates()\n",
00581               target_unicharset.id_to_unichar(ClassId));
00582     }
00583     assert(UnusedClassIdIn(IntTemplates, ClassId));
00584     IClass = NewIntClass(FClass->NumProtos, FClass->NumConfigs);
00585     FontSet fs;
00586     fs.size = FClass->font_set.size();
00587     fs.configs = new int[fs.size];
00588     for (int i = 0; i < fs.size; ++i) {
00589       fs.configs[i] = FClass->font_set.get(i);
00590     }
00591     if (this->fontset_table_.contains(fs)) {
00592       IClass->font_set_id = this->fontset_table_.get_id(fs);
00593       delete[] fs.configs;
00594     } else {
00595       IClass->font_set_id = this->fontset_table_.push_back(fs);
00596     }
00597     AddIntClass(IntTemplates, ClassId, IClass);
00598 
00599     for (ProtoId = 0; ProtoId < FClass->NumProtos; ProtoId++) {
00600       AddIntProto(IClass);
00601       ConvertProto(ProtoIn(FClass, ProtoId), ProtoId, IClass);
00602       AddProtoToProtoPruner(ProtoIn(FClass, ProtoId), ProtoId, IClass,
00603                             classify_learning_debug_level >= 2);
00604       AddProtoToClassPruner(ProtoIn(FClass, ProtoId), ClassId, IntTemplates);
00605     }
00606 
00607     for (ConfigId = 0; ConfigId < FClass->NumConfigs; ConfigId++) {
00608       AddIntConfig(IClass);
00609       ConvertConfig(FClass->Configurations[ConfigId], ConfigId, IClass);
00610     }
00611   }
00612   return (IntTemplates);
00613 }                                /* CreateIntTemplates */
00614 }  // namespace tesseract
00615 
00616 
00617 #ifndef GRAPHICS_DISABLED
00618 
00630 void DisplayIntFeature(const INT_FEATURE_STRUCT* Feature, FLOAT32 Evidence) {
00631   ScrollView::Color color = GetMatchColorFor(Evidence);
00632   RenderIntFeature(IntMatchWindow, Feature, color);
00633   if (FeatureDisplayWindow) {
00634     RenderIntFeature(FeatureDisplayWindow, Feature, color);
00635   }
00636 }                                /* DisplayIntFeature */
00637 
00638 
00652 void DisplayIntProto(INT_CLASS Class, PROTO_ID ProtoId, FLOAT32 Evidence) {
00653   ScrollView::Color color = GetMatchColorFor(Evidence);
00654   RenderIntProto(IntMatchWindow, Class, ProtoId, color);
00655   if (ProtoDisplayWindow) {
00656     RenderIntProto(ProtoDisplayWindow, Class, ProtoId, color);
00657   }
00658 }                                /* DisplayIntProto */
00659 #endif
00660 
00672 INT_CLASS NewIntClass(int MaxNumProtos, int MaxNumConfigs) {
00673   INT_CLASS Class;
00674   PROTO_SET ProtoSet;
00675   int i;
00676 
00677   assert(MaxNumConfigs <= MAX_NUM_CONFIGS);
00678 
00679   Class = (INT_CLASS) Emalloc(sizeof(INT_CLASS_STRUCT));
00680   Class->NumProtoSets = ((MaxNumProtos + PROTOS_PER_PROTO_SET - 1) /
00681                             PROTOS_PER_PROTO_SET);
00682 
00683   assert(Class->NumProtoSets <= MAX_NUM_PROTO_SETS);
00684 
00685   Class->NumProtos = 0;
00686   Class->NumConfigs = 0;
00687 
00688   for (i = 0; i < Class->NumProtoSets; i++) {
00689     /* allocate space for a proto set, install in class, and initialize */
00690     ProtoSet = (PROTO_SET) Emalloc(sizeof(PROTO_SET_STRUCT));
00691     memset(ProtoSet, 0, sizeof(*ProtoSet));
00692     Class->ProtoSets[i] = ProtoSet;
00693 
00694     /* allocate space for the proto lengths and install in class */
00695   }
00696   if (MaxNumIntProtosIn (Class) > 0) {
00697     Class->ProtoLengths =
00698       (uinT8 *)Emalloc(MaxNumIntProtosIn (Class) * sizeof (uinT8));
00699     memset(Class->ProtoLengths, 0,
00700            MaxNumIntProtosIn(Class) * sizeof(*Class->ProtoLengths));
00701   } else {
00702     Class->ProtoLengths = NULL;
00703   }
00704   memset(Class->ConfigLengths, 0, sizeof(Class->ConfigLengths));
00705 
00706   return (Class);
00707 
00708 }                                /* NewIntClass */
00709 
00710 
00711 void free_int_class(INT_CLASS int_class) {
00712   int i;
00713 
00714   for (i = 0; i < int_class->NumProtoSets; i++) {
00715     Efree (int_class->ProtoSets[i]);
00716   }
00717   if (int_class->ProtoLengths != NULL) {
00718     Efree (int_class->ProtoLengths);
00719   }
00720   Efree(int_class);
00721 }
00722 
00723 
00732 INT_TEMPLATES NewIntTemplates() {
00733   INT_TEMPLATES T;
00734   int i;
00735 
00736   T = (INT_TEMPLATES) Emalloc (sizeof (INT_TEMPLATES_STRUCT));
00737   T->NumClasses = 0;
00738   T->NumClassPruners = 0;
00739 
00740   for (i = 0; i < MAX_NUM_CLASSES; i++)
00741     ClassForClassId (T, i) = NULL;
00742 
00743   return (T);
00744 }                                /* NewIntTemplates */
00745 
00746 
00747 /*---------------------------------------------------------------------------*/
00748 void free_int_templates(INT_TEMPLATES templates) {
00749   int i;
00750 
00751   for (i = 0; i < templates->NumClasses; i++)
00752     free_int_class(templates->Class[i]);
00753   for (i = 0; i < templates->NumClassPruners; i++)
00754     delete templates->ClassPruners[i];
00755   Efree(templates);
00756 }
00757 
00758 
00759 namespace tesseract {
00770 INT_TEMPLATES Classify::ReadIntTemplates(FILE *File) {
00771   int i, j, w, x, y, z;
00772   BOOL8 swap;
00773   int nread;
00774   int unicharset_size;
00775   int version_id = 0;
00776   INT_TEMPLATES Templates;
00777   CLASS_PRUNER_STRUCT* Pruner;
00778   INT_CLASS Class;
00779   uinT8 *Lengths;
00780   PROTO_SET ProtoSet;
00781 
00782   /* variables for conversion from older inttemp formats */
00783   int b, bit_number, last_cp_bit_number, new_b, new_i, new_w;
00784   CLASS_ID class_id, max_class_id;
00785   inT16 *IndexFor = new inT16[MAX_NUM_CLASSES];
00786   CLASS_ID *ClassIdFor = new CLASS_ID[MAX_NUM_CLASSES];
00787   CLASS_PRUNER_STRUCT **TempClassPruner =
00788       new CLASS_PRUNER_STRUCT*[MAX_NUM_CLASS_PRUNERS];
00789   uinT32 SetBitsForMask =           // word with NUM_BITS_PER_CLASS
00790     (1 << NUM_BITS_PER_CLASS) - 1;  // set starting at bit 0
00791   uinT32 Mask, NewMask, ClassBits;
00792   int MaxNumConfigs = MAX_NUM_CONFIGS;
00793   int WerdsPerConfigVec = WERDS_PER_CONFIG_VEC;
00794 
00795   /* first read the high level template struct */
00796   Templates = NewIntTemplates();
00797   // Read Templates in parts for 64 bit compatibility.
00798   if (fread(&unicharset_size, sizeof(int), 1, File) != 1)
00799     cprintf("Bad read of inttemp!\n");
00800   if (fread(&Templates->NumClasses,
00801             sizeof(Templates->NumClasses), 1, File) != 1 ||
00802       fread(&Templates->NumClassPruners,
00803             sizeof(Templates->NumClassPruners), 1, File) != 1)
00804     cprintf("Bad read of inttemp!\n");
00805   // Swap status is determined automatically.
00806   swap = Templates->NumClassPruners < 0 ||
00807     Templates->NumClassPruners > MAX_NUM_CLASS_PRUNERS;
00808   if (swap) {
00809     Reverse32(&Templates->NumClassPruners);
00810     Reverse32(&Templates->NumClasses);
00811     Reverse32(&unicharset_size);
00812   }
00813   if (Templates->NumClasses < 0) {
00814     // This file has a version id!
00815     version_id = -Templates->NumClasses;
00816     if (fread(&Templates->NumClasses, sizeof(Templates->NumClasses),
00817               1, File) != 1)
00818       cprintf("Bad read of inttemp!\n");
00819     if (swap)
00820       Reverse32(&Templates->NumClasses);
00821   }
00822 
00823   if (version_id < 3) {
00824     MaxNumConfigs = OLD_MAX_NUM_CONFIGS;
00825     WerdsPerConfigVec = OLD_WERDS_PER_CONFIG_VEC;
00826   }
00827 
00828   if (version_id < 2) {
00829     for (i = 0; i < unicharset_size; ++i) {
00830       if (fread(&IndexFor[i], sizeof(inT16), 1, File) != 1)
00831         cprintf("Bad read of inttemp!\n");
00832     }
00833     for (i = 0; i < Templates->NumClasses; ++i) {
00834       if (fread(&ClassIdFor[i], sizeof(CLASS_ID), 1, File) != 1)
00835         cprintf("Bad read of inttemp!\n");
00836     }
00837     if (swap) {
00838       for (i = 0; i < Templates->NumClasses; i++)
00839         Reverse16(&IndexFor[i]);
00840       for (i = 0; i < Templates->NumClasses; i++)
00841         Reverse32(&ClassIdFor[i]);
00842     }
00843   }
00844 
00845   /* then read in the class pruners */
00846   for (i = 0; i < Templates->NumClassPruners; i++) {
00847     Pruner = new CLASS_PRUNER_STRUCT;
00848     if ((nread =
00849          fread(Pruner, 1, sizeof(CLASS_PRUNER_STRUCT),
00850                 File)) != sizeof(CLASS_PRUNER_STRUCT))
00851       cprintf("Bad read of inttemp!\n");
00852     if (swap) {
00853       for (x = 0; x < NUM_CP_BUCKETS; x++) {
00854         for (y = 0; y < NUM_CP_BUCKETS; y++) {
00855           for (z = 0; z < NUM_CP_BUCKETS; z++) {
00856             for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
00857               Reverse32(&Pruner->p[x][y][z][w]);
00858             }
00859           }
00860         }
00861       }
00862     }
00863     if (version_id < 2) {
00864       TempClassPruner[i] = Pruner;
00865     } else {
00866       Templates->ClassPruners[i] = Pruner;
00867     }
00868   }
00869 
00870   /* fix class pruners if they came from an old version of inttemp */
00871   if (version_id < 2) {
00872     // Allocate enough class pruners to cover all the class ids.
00873     max_class_id = 0;
00874     for (i = 0; i < Templates->NumClasses; i++)
00875       if (ClassIdFor[i] > max_class_id)
00876         max_class_id = ClassIdFor[i];
00877     for (i = 0; i <= CPrunerIdFor(max_class_id); i++) {
00878       Templates->ClassPruners[i] = new CLASS_PRUNER_STRUCT;
00879       memset(Templates->ClassPruners[i], 0, sizeof(CLASS_PRUNER_STRUCT));
00880     }
00881     // Convert class pruners from the old format (indexed by class index)
00882     // to the new format (indexed by class id).
00883     last_cp_bit_number = NUM_BITS_PER_CLASS * Templates->NumClasses - 1;
00884     for (i = 0; i < Templates->NumClassPruners; i++) {
00885       for (x = 0; x < NUM_CP_BUCKETS; x++)
00886         for (y = 0; y < NUM_CP_BUCKETS; y++)
00887           for (z = 0; z < NUM_CP_BUCKETS; z++)
00888             for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
00889               if (TempClassPruner[i]->p[x][y][z][w] == 0)
00890                 continue;
00891               for (b = 0; b < BITS_PER_WERD; b += NUM_BITS_PER_CLASS) {
00892                 bit_number = i * BITS_PER_CP_VECTOR + w * BITS_PER_WERD + b;
00893                 if (bit_number > last_cp_bit_number)
00894                   break; // the rest of the bits in this word are not used
00895                 class_id = ClassIdFor[bit_number / NUM_BITS_PER_CLASS];
00896                 // Single out NUM_BITS_PER_CLASS bits relating to class_id.
00897                 Mask = SetBitsForMask << b;
00898                 ClassBits = TempClassPruner[i]->p[x][y][z][w] & Mask;
00899                 // Move these bits to the new position in which they should
00900                 // appear (indexed corresponding to the class_id).
00901                 new_i = CPrunerIdFor(class_id);
00902                 new_w = CPrunerWordIndexFor(class_id);
00903                 new_b = CPrunerBitIndexFor(class_id) * NUM_BITS_PER_CLASS;
00904                 if (new_b > b) {
00905                   ClassBits <<= (new_b - b);
00906                 } else {
00907                   ClassBits >>= (b - new_b);
00908                 }
00909                 // Copy bits relating to class_id to the correct position
00910                 // in Templates->ClassPruner.
00911                 NewMask = SetBitsForMask << new_b;
00912                 Templates->ClassPruners[new_i]->p[x][y][z][new_w] &= ~NewMask;
00913                 Templates->ClassPruners[new_i]->p[x][y][z][new_w] |= ClassBits;
00914               }
00915             }
00916     }
00917     for (i = 0; i < Templates->NumClassPruners; i++) {
00918       delete TempClassPruner[i];
00919     }
00920   }
00921 
00922   /* then read in each class */
00923   for (i = 0; i < Templates->NumClasses; i++) {
00924     /* first read in the high level struct for the class */
00925     Class = (INT_CLASS) Emalloc (sizeof (INT_CLASS_STRUCT));
00926     if (fread(&Class->NumProtos, sizeof(Class->NumProtos), 1, File) != 1 ||
00927         fread(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File) != 1 ||
00928         fread(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File) != 1)
00929       cprintf ("Bad read of inttemp!\n");
00930     if (version_id == 0) {
00931       // Only version 0 writes 5 pointless pointers to the file.
00932       for (j = 0; j < 5; ++j) {
00933         int junk;
00934         if (fread(&junk, sizeof(junk), 1, File) != 1)
00935           cprintf ("Bad read of inttemp!\n");
00936       }
00937     }
00938     if (version_id < 4) {
00939       for (j = 0; j < MaxNumConfigs; ++j) {
00940         if (fread(&Class->ConfigLengths[j], sizeof(uinT16), 1, File) != 1)
00941           cprintf ("Bad read of inttemp!\n");
00942       }
00943       if (swap) {
00944         Reverse16(&Class->NumProtos);
00945         for (j = 0; j < MaxNumConfigs; j++)
00946           Reverse16(&Class->ConfigLengths[j]);
00947       }
00948     } else {
00949       ASSERT_HOST(Class->NumConfigs < MaxNumConfigs);
00950       for (j = 0; j < Class->NumConfigs; ++j) {
00951         if (fread(&Class->ConfigLengths[j], sizeof(uinT16), 1, File) != 1)
00952           cprintf ("Bad read of inttemp!\n");
00953       }
00954       if (swap) {
00955         Reverse16(&Class->NumProtos);
00956         for (j = 0; j < MaxNumConfigs; j++)
00957           Reverse16(&Class->ConfigLengths[j]);
00958       }
00959     }
00960     if (version_id < 2) {
00961       ClassForClassId (Templates, ClassIdFor[i]) = Class;
00962     } else {
00963       ClassForClassId (Templates, i) = Class;
00964     }
00965 
00966     /* then read in the proto lengths */
00967     Lengths = NULL;
00968     if (MaxNumIntProtosIn (Class) > 0) {
00969       Lengths = (uinT8 *)Emalloc(sizeof(uinT8) * MaxNumIntProtosIn(Class));
00970       if ((nread =
00971            fread((char *)Lengths, sizeof(uinT8),
00972                  MaxNumIntProtosIn(Class), File)) != MaxNumIntProtosIn (Class))
00973         cprintf ("Bad read of inttemp!\n");
00974     }
00975     Class->ProtoLengths = Lengths;
00976 
00977     /* then read in the proto sets */
00978     for (j = 0; j < Class->NumProtoSets; j++) {
00979       ProtoSet = (PROTO_SET)Emalloc(sizeof(PROTO_SET_STRUCT));
00980       if (version_id < 3) {
00981         if ((nread =
00982              fread((char *) &ProtoSet->ProtoPruner, 1,
00983                     sizeof(PROTO_PRUNER), File)) != sizeof(PROTO_PRUNER))
00984           cprintf("Bad read of inttemp!\n");
00985         for (x = 0; x < PROTOS_PER_PROTO_SET; x++) {
00986           if ((nread = fread((char *) &ProtoSet->Protos[x].A, 1,
00987                              sizeof(inT8), File)) != sizeof(inT8) ||
00988               (nread = fread((char *) &ProtoSet->Protos[x].B, 1,
00989                              sizeof(uinT8), File)) != sizeof(uinT8) ||
00990               (nread = fread((char *) &ProtoSet->Protos[x].C, 1,
00991                              sizeof(inT8), File)) != sizeof(inT8) ||
00992               (nread = fread((char *) &ProtoSet->Protos[x].Angle, 1,
00993                              sizeof(uinT8), File)) != sizeof(uinT8))
00994             cprintf("Bad read of inttemp!\n");
00995           for (y = 0; y < WerdsPerConfigVec; y++)
00996             if ((nread = fread((char *) &ProtoSet->Protos[x].Configs[y], 1,
00997                                sizeof(uinT32), File)) != sizeof(uinT32))
00998               cprintf("Bad read of inttemp!\n");
00999         }
01000       } else {
01001         if ((nread =
01002              fread((char *) ProtoSet, 1, sizeof(PROTO_SET_STRUCT),
01003                    File)) != sizeof(PROTO_SET_STRUCT))
01004           cprintf("Bad read of inttemp!\n");
01005       }
01006       if (swap) {
01007         for (x = 0; x < NUM_PP_PARAMS; x++)
01008           for (y = 0; y < NUM_PP_BUCKETS; y++)
01009             for (z = 0; z < WERDS_PER_PP_VECTOR; z++)
01010               Reverse32(&ProtoSet->ProtoPruner[x][y][z]);
01011         for (x = 0; x < PROTOS_PER_PROTO_SET; x++)
01012           for (y = 0; y < WerdsPerConfigVec; y++)
01013             Reverse32(&ProtoSet->Protos[x].Configs[y]);
01014       }
01015       Class->ProtoSets[j] = ProtoSet;
01016     }
01017     if (version_id < 4)
01018       Class->font_set_id = -1;
01019     else {
01020       fread(&Class->font_set_id, sizeof(int), 1, File);
01021       if (swap)
01022         Reverse32(&Class->font_set_id);
01023     }
01024   }
01025 
01026   if (version_id < 2) {
01027     /* add an empty NULL class with class id 0 */
01028     assert(UnusedClassIdIn (Templates, 0));
01029     ClassForClassId (Templates, 0) = NewIntClass (1, 1);
01030     ClassForClassId (Templates, 0)->font_set_id = -1;
01031     Templates->NumClasses++;
01032     /* make sure the classes are contiguous */
01033     for (i = 0; i < MAX_NUM_CLASSES; i++) {
01034       if (i < Templates->NumClasses) {
01035         if (ClassForClassId (Templates, i) == NULL) {
01036           fprintf(stderr, "Non-contiguous class ids in inttemp\n");
01037           exit(1);
01038         }
01039       } else {
01040         if (ClassForClassId (Templates, i) != NULL) {
01041           fprintf(stderr, "Class id %d exceeds NumClassesIn (Templates) %d\n",
01042                   i, Templates->NumClasses);
01043           exit(1);
01044         }
01045       }
01046     }
01047   }
01048   if (version_id >= 4) {
01049     this->fontinfo_table_.read(File, NewPermanentTessCallback(read_info), swap);
01050     if (version_id >= 5) {
01051       this->fontinfo_table_.read(File,
01052                                  NewPermanentTessCallback(read_spacing_info),
01053                                  swap);
01054     }
01055     this->fontset_table_.read(File, NewPermanentTessCallback(read_set), swap);
01056   }
01057 
01058   // Clean up.
01059   delete[] IndexFor;
01060   delete[] ClassIdFor;
01061   delete[] TempClassPruner;
01062 
01063   return (Templates);
01064 }                                /* ReadIntTemplates */
01065 
01066 
01067 #ifndef GRAPHICS_DISABLED
01068 
01079 void Classify::ShowMatchDisplay() {
01080   InitIntMatchWindowIfReqd();
01081   if (ProtoDisplayWindow) {
01082     ProtoDisplayWindow->Clear();
01083   }
01084   if (FeatureDisplayWindow) {
01085     FeatureDisplayWindow->Clear();
01086   }
01087   ClearFeatureSpaceWindow(
01088       static_cast<NORM_METHOD>(static_cast<int>(classify_norm_method)),
01089       IntMatchWindow);
01090   IntMatchWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
01091                                   INT_MAX_X, INT_MAX_Y);
01092   if (ProtoDisplayWindow) {
01093     ProtoDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
01094                                         INT_MAX_X, INT_MAX_Y);
01095   }
01096   if (FeatureDisplayWindow) {
01097     FeatureDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
01098                                           INT_MAX_X, INT_MAX_Y);
01099   }
01100 }                                /* ShowMatchDisplay */
01101 
01104 void ClearFeatureSpaceWindow(NORM_METHOD norm_method, ScrollView* window) {
01105   window->Clear();
01106 
01107   window->Pen(ScrollView::GREY);
01108   // Draw the feature space limit rectangle.
01109   window->Rectangle(0, 0, INT_MAX_X, INT_MAX_Y);
01110   if (norm_method == baseline) {
01111     window->SetCursor(0, INT_DESCENDER);
01112     window->DrawTo(INT_MAX_X, INT_DESCENDER);
01113     window->SetCursor(0, INT_BASELINE);
01114     window->DrawTo(INT_MAX_X, INT_BASELINE);
01115     window->SetCursor(0, INT_XHEIGHT);
01116     window->DrawTo(INT_MAX_X, INT_XHEIGHT);
01117     window->SetCursor(0, INT_CAPHEIGHT);
01118     window->DrawTo(INT_MAX_X, INT_CAPHEIGHT);
01119   } else {
01120     window->Rectangle(INT_XCENTER - INT_XRADIUS, INT_YCENTER - INT_YRADIUS,
01121                       INT_XCENTER + INT_XRADIUS, INT_YCENTER + INT_YRADIUS);
01122   }
01123 }
01124 #endif
01125 
01138 void Classify::WriteIntTemplates(FILE *File, INT_TEMPLATES Templates,
01139                                  const UNICHARSET& target_unicharset) {
01140   int i, j;
01141   INT_CLASS Class;
01142   int unicharset_size = target_unicharset.size();
01143   int version_id = -5;  // When negated by the reader -1 becomes +1 etc.
01144 
01145   if (Templates->NumClasses != unicharset_size) {
01146     cprintf("Warning: executing WriteIntTemplates() with %d classes in"
01147             " Templates, while target_unicharset size is %d\n",
01148             Templates->NumClasses, unicharset_size);
01149   }
01150 
01151   /* first write the high level template struct */
01152   fwrite(&unicharset_size, sizeof(unicharset_size), 1, File);
01153   fwrite(&version_id, sizeof(version_id), 1, File);
01154   fwrite(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners),
01155          1, File);
01156   fwrite(&Templates->NumClasses, sizeof(Templates->NumClasses), 1, File);
01157 
01158   /* then write out the class pruners */
01159   for (i = 0; i < Templates->NumClassPruners; i++)
01160     fwrite(Templates->ClassPruners[i],
01161            sizeof(CLASS_PRUNER_STRUCT), 1, File);
01162 
01163   /* then write out each class */
01164   for (i = 0; i < Templates->NumClasses; i++) {
01165     Class = Templates->Class[i];
01166 
01167     /* first write out the high level struct for the class */
01168     fwrite(&Class->NumProtos, sizeof(Class->NumProtos), 1, File);
01169     fwrite(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File);
01170     ASSERT_HOST(Class->NumConfigs == this->fontset_table_.get(Class->font_set_id).size);
01171     fwrite(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File);
01172     for (j = 0; j < Class->NumConfigs; ++j) {
01173       fwrite(&Class->ConfigLengths[j], sizeof(uinT16), 1, File);
01174     }
01175 
01176     /* then write out the proto lengths */
01177     if (MaxNumIntProtosIn (Class) > 0) {
01178       fwrite ((char *) (Class->ProtoLengths), sizeof (uinT8),
01179               MaxNumIntProtosIn (Class), File);
01180     }
01181 
01182     /* then write out the proto sets */
01183     for (j = 0; j < Class->NumProtoSets; j++)
01184       fwrite ((char *) Class->ProtoSets[j],
01185               sizeof (PROTO_SET_STRUCT), 1, File);
01186 
01187     /* then write the fonts info */
01188     fwrite(&Class->font_set_id, sizeof(int), 1, File);
01189   }
01190 
01191   /* Write the fonts info tables */
01192   this->fontinfo_table_.write(File, NewPermanentTessCallback(write_info));
01193   this->fontinfo_table_.write(File,
01194                               NewPermanentTessCallback(write_spacing_info));
01195   this->fontset_table_.write(File, NewPermanentTessCallback(write_set));
01196 }                                /* WriteIntTemplates */
01197 } // namespace tesseract
01198 
01199 
01200 /*-----------------------------------------------------------------------------
01201               Private Code
01202 -----------------------------------------------------------------------------*/
01216 FLOAT32 BucketStart(int Bucket, FLOAT32 Offset, int NumBuckets) {
01217   return (((FLOAT32) Bucket / NumBuckets) - Offset);
01218 
01219 }                                /* BucketStart */
01220 
01221 
01235 FLOAT32 BucketEnd(int Bucket, FLOAT32 Offset, int NumBuckets) {
01236   return (((FLOAT32) (Bucket + 1) / NumBuckets) - Offset);
01237 }                                /* BucketEnd */
01238 
01239 
01254 void DoFill(FILL_SPEC *FillSpec,
01255             CLASS_PRUNER_STRUCT* Pruner,
01256             register uinT32 ClassMask,
01257             register uinT32 ClassCount,
01258             register uinT32 WordIndex) {
01259   int X, Y, Angle;
01260   uinT32 OldWord;
01261 
01262   X = FillSpec->X;
01263   if (X < 0)
01264     X = 0;
01265   if (X >= NUM_CP_BUCKETS)
01266     X = NUM_CP_BUCKETS - 1;
01267 
01268   if (FillSpec->YStart < 0)
01269     FillSpec->YStart = 0;
01270   if (FillSpec->YEnd >= NUM_CP_BUCKETS)
01271     FillSpec->YEnd = NUM_CP_BUCKETS - 1;
01272 
01273   for (Y = FillSpec->YStart; Y <= FillSpec->YEnd; Y++)
01274     for (Angle = FillSpec->AngleStart;
01275          TRUE; CircularIncrement (Angle, NUM_CP_BUCKETS)) {
01276       OldWord = Pruner->p[X][Y][Angle][WordIndex];
01277       if (ClassCount > (OldWord & ClassMask)) {
01278         OldWord &= ~ClassMask;
01279         OldWord |= ClassCount;
01280         Pruner->p[X][Y][Angle][WordIndex] = OldWord;
01281       }
01282       if (Angle == FillSpec->AngleEnd)
01283         break;
01284     }
01285 }                                /* DoFill */
01286 
01287 
01297 BOOL8 FillerDone(TABLE_FILLER *Filler) {
01298   FILL_SWITCH *Next;
01299 
01300   Next = &(Filler->Switch[Filler->NextSwitch]);
01301 
01302   if (Filler->X > Next->X && Next->Type == LastSwitch)
01303     return (TRUE);
01304   else
01305     return (FALSE);
01306 
01307 }                                /* FillerDone */
01308 
01309 
01327 void FillPPCircularBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
01328                         int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug) {
01329   int i, FirstBucket, LastBucket;
01330 
01331   if (Spread > 0.5)
01332     Spread = 0.5;
01333 
01334   FirstBucket = (int) floor ((Center - Spread) * NUM_PP_BUCKETS);
01335   if (FirstBucket < 0)
01336     FirstBucket += NUM_PP_BUCKETS;
01337 
01338   LastBucket = (int) floor ((Center + Spread) * NUM_PP_BUCKETS);
01339   if (LastBucket >= NUM_PP_BUCKETS)
01340     LastBucket -= NUM_PP_BUCKETS;
01341   if (debug) tprintf("Circular fill from %d to %d", FirstBucket, LastBucket);
01342   for (i = FirstBucket; TRUE; CircularIncrement (i, NUM_PP_BUCKETS)) {
01343     SET_BIT (ParamTable[i], Bit);
01344 
01345     /* exit loop after we have set the bit for the last bucket */
01346     if (i == LastBucket)
01347       break;
01348   }
01349 
01350 }                                /* FillPPCircularBits */
01351 
01352 
01371 void FillPPLinearBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
01372                       int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug) {
01373   int i, FirstBucket, LastBucket;
01374 
01375   FirstBucket = (int) floor ((Center - Spread) * NUM_PP_BUCKETS);
01376   if (FirstBucket < 0)
01377     FirstBucket = 0;
01378 
01379   LastBucket = (int) floor ((Center + Spread) * NUM_PP_BUCKETS);
01380   if (LastBucket >= NUM_PP_BUCKETS)
01381     LastBucket = NUM_PP_BUCKETS - 1;
01382 
01383   if (debug) tprintf("Linear fill from %d to %d", FirstBucket, LastBucket);
01384   for (i = FirstBucket; i <= LastBucket; i++)
01385     SET_BIT (ParamTable[i], Bit);
01386 
01387 }                                /* FillPPLinearBits */
01388 
01389 
01390 /*---------------------------------------------------------------------------*/
01391 #ifndef GRAPHICS_DISABLED
01392 namespace tesseract {
01405 CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool* adaptive_on,
01406                                    bool* pretrained_on, int* shape_id) {
01407   tprintf("%s\n", Prompt);
01408   SVEvent* ev;
01409   SVEventType ev_type;
01410   int unichar_id = INVALID_UNICHAR_ID;
01411   // Wait until a click or popup event.
01412   do {
01413     ev = IntMatchWindow->AwaitEvent(SVET_ANY);
01414     ev_type = ev->type;
01415     if (ev_type == SVET_POPUP) {
01416       if (ev->command_id == IDA_SHAPE_INDEX) {
01417         if (shape_table_ != NULL) {
01418           *shape_id = atoi(ev->parameter);
01419           *adaptive_on = false;
01420           *pretrained_on = true;
01421           if (*shape_id >= 0 && *shape_id < shape_table_->NumShapes()) {
01422             int font_id;
01423             shape_table_->GetFirstUnicharAndFont(*shape_id, &unichar_id,
01424                                                  &font_id);
01425             tprintf("Shape %d, first unichar=%d, font=%d\n",
01426                     *shape_id, unichar_id, font_id);
01427             return unichar_id;
01428           }
01429           tprintf("Shape index '%s' not found in shape table\n", ev->parameter);
01430         } else {
01431           tprintf("No shape table loaded!\n");
01432         }
01433       } else {
01434         if (unicharset.contains_unichar(ev->parameter)) {
01435           unichar_id = unicharset.unichar_to_id(ev->parameter);
01436           if (ev->command_id == IDA_ADAPTIVE) {
01437             *adaptive_on = true;
01438             *pretrained_on = false;
01439             *shape_id = -1;
01440           } else if (ev->command_id == IDA_STATIC) {
01441             *adaptive_on = false;
01442             *pretrained_on = true;
01443           } else {
01444             *adaptive_on = true;
01445             *pretrained_on = true;
01446           }
01447           if (ev->command_id == IDA_ADAPTIVE || shape_table_ == NULL) {
01448             *shape_id = -1;
01449             return unichar_id;
01450           }
01451           for (int s = 0; s < shape_table_->NumShapes(); ++s) {
01452             if (shape_table_->GetShape(s).ContainsUnichar(unichar_id)) {
01453               tprintf("%s\n", shape_table_->DebugStr(s).string());
01454             }
01455           }
01456         } else {
01457           tprintf("Char class '%s' not found in unicharset",
01458                   ev->parameter);
01459         }
01460       }
01461     }
01462     delete ev;
01463   } while (ev_type != SVET_CLICK);
01464   return 0;
01465 }                                /* GetClassToDebug */
01466 
01467 }  // namespace tesseract
01468 #endif
01469 
01485 void GetCPPadsForLevel(int Level,
01486                        FLOAT32 *EndPad,
01487                        FLOAT32 *SidePad,
01488                        FLOAT32 *AnglePad) {
01489   switch (Level) {
01490     case 0:
01491       *EndPad = classify_cp_end_pad_loose * GetPicoFeatureLength ();
01492       *SidePad = classify_cp_side_pad_loose * GetPicoFeatureLength ();
01493       *AnglePad = classify_cp_angle_pad_loose / 360.0;
01494       break;
01495 
01496     case 1:
01497       *EndPad = classify_cp_end_pad_medium * GetPicoFeatureLength ();
01498       *SidePad = classify_cp_side_pad_medium * GetPicoFeatureLength ();
01499       *AnglePad = classify_cp_angle_pad_medium / 360.0;
01500       break;
01501 
01502     case 2:
01503       *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength ();
01504       *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength ();
01505       *AnglePad = classify_cp_angle_pad_tight / 360.0;
01506       break;
01507 
01508     default:
01509       *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength ();
01510       *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength ();
01511       *AnglePad = classify_cp_angle_pad_tight / 360.0;
01512       break;
01513   }
01514   if (*AnglePad > 0.5)
01515     *AnglePad = 0.5;
01516 
01517 }                                /* GetCPPadsForLevel */
01518 
01519 
01527 ScrollView::Color GetMatchColorFor(FLOAT32 Evidence) {
01528   assert (Evidence >= 0.0);
01529   assert (Evidence <= 1.0);
01530 
01531   if (Evidence >= 0.90)
01532     return ScrollView::WHITE;
01533   else if (Evidence >= 0.75)
01534     return ScrollView::GREEN;
01535   else if (Evidence >= 0.50)
01536     return ScrollView::RED;
01537   else
01538     return ScrollView::BLUE;
01539 }                                /* GetMatchColorFor */
01540 
01541 
01554 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill) {
01555   FILL_SWITCH *Next;
01556 
01557   /* compute the fill assuming no switches will be encountered */
01558   Fill->AngleStart = Filler->AngleStart;
01559   Fill->AngleEnd = Filler->AngleEnd;
01560   Fill->X = Filler->X;
01561   Fill->YStart = Filler->YStart >> 8;
01562   Fill->YEnd = Filler->YEnd >> 8;
01563 
01564   /* update the fill info and the filler for ALL switches at this X value */
01565   Next = &(Filler->Switch[Filler->NextSwitch]);
01566   while (Filler->X >= Next->X) {
01567     Fill->X = Filler->X = Next->X;
01568     if (Next->Type == StartSwitch) {
01569       Fill->YStart = Next->Y;
01570       Filler->StartDelta = Next->Delta;
01571       Filler->YStart = Next->YInit;
01572     }
01573     else if (Next->Type == EndSwitch) {
01574       Fill->YEnd = Next->Y;
01575       Filler->EndDelta = Next->Delta;
01576       Filler->YEnd = Next->YInit;
01577     }
01578     else {                       /* Type must be LastSwitch */
01579       break;
01580     }
01581     Filler->NextSwitch++;
01582     Next = &(Filler->Switch[Filler->NextSwitch]);
01583   }
01584 
01585   /* prepare the filler for the next call to this routine */
01586   Filler->X++;
01587   Filler->YStart += Filler->StartDelta;
01588   Filler->YEnd += Filler->EndDelta;
01589 
01590 }                                /* GetNextFill */
01591 
01592 
01607 void InitTableFiller (FLOAT32 EndPad, FLOAT32 SidePad,
01608                       FLOAT32 AnglePad, PROTO Proto, TABLE_FILLER * Filler)
01609 #define XS          X_SHIFT
01610 #define YS          Y_SHIFT
01611 #define AS          ANGLE_SHIFT
01612 #define NB          NUM_CP_BUCKETS
01613 {
01614   FLOAT32 Angle;
01615   FLOAT32 X, Y, HalfLength;
01616   FLOAT32 Cos, Sin;
01617   FLOAT32 XAdjust, YAdjust;
01618   FPOINT Start, Switch1, Switch2, End;
01619   int S1 = 0;
01620   int S2 = 1;
01621 
01622   Angle = Proto->Angle;
01623   X = Proto->X;
01624   Y = Proto->Y;
01625   HalfLength = Proto->Length / 2.0;
01626 
01627   Filler->AngleStart = CircBucketFor(Angle - AnglePad, AS, NB);
01628   Filler->AngleEnd = CircBucketFor(Angle + AnglePad, AS, NB);
01629   Filler->NextSwitch = 0;
01630 
01631   if (fabs (Angle - 0.0) < HV_TOLERANCE || fabs (Angle - 0.5) < HV_TOLERANCE) {
01632     /* horizontal proto - handle as special case */
01633     Filler->X = Bucket8For(X - HalfLength - EndPad, XS, NB);
01634     Filler->YStart = Bucket16For(Y - SidePad, YS, NB * 256);
01635     Filler->YEnd = Bucket16For(Y + SidePad, YS, NB * 256);
01636     Filler->StartDelta = 0;
01637     Filler->EndDelta = 0;
01638     Filler->Switch[0].Type = LastSwitch;
01639     Filler->Switch[0].X = Bucket8For(X + HalfLength + EndPad, XS, NB);
01640   } else if (fabs(Angle - 0.25) < HV_TOLERANCE ||
01641            fabs(Angle - 0.75) < HV_TOLERANCE) {
01642     /* vertical proto - handle as special case */
01643     Filler->X = Bucket8For(X - SidePad, XS, NB);
01644     Filler->YStart = Bucket16For(Y - HalfLength - EndPad, YS, NB * 256);
01645     Filler->YEnd = Bucket16For(Y + HalfLength + EndPad, YS, NB * 256);
01646     Filler->StartDelta = 0;
01647     Filler->EndDelta = 0;
01648     Filler->Switch[0].Type = LastSwitch;
01649     Filler->Switch[0].X = Bucket8For(X + SidePad, XS, NB);
01650   } else {
01651     /* diagonal proto */
01652 
01653     if ((Angle > 0.0 && Angle < 0.25) || (Angle > 0.5 && Angle < 0.75)) {
01654       /* rising diagonal proto */
01655       Angle *= 2.0 * PI;
01656       Cos = fabs(cos(Angle));
01657       Sin = fabs(sin(Angle));
01658 
01659       /* compute the positions of the corners of the acceptance region */
01660       Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
01661       Start.y = Y - (HalfLength + EndPad) * Sin + SidePad * Cos;
01662       End.x = 2.0 * X - Start.x;
01663       End.y = 2.0 * Y - Start.y;
01664       Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
01665       Switch1.y = Y - (HalfLength + EndPad) * Sin - SidePad * Cos;
01666       Switch2.x = 2.0 * X - Switch1.x;
01667       Switch2.y = 2.0 * Y - Switch1.y;
01668 
01669       if (Switch1.x > Switch2.x) {
01670         S1 = 1;
01671         S2 = 0;
01672       }
01673 
01674       /* translate into bucket positions and deltas */
01675       Filler->X = Bucket8For(Start.x, XS, NB);
01676       Filler->StartDelta = -(inT16) ((Cos / Sin) * 256);
01677       Filler->EndDelta = (inT16) ((Sin / Cos) * 256);
01678 
01679       XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
01680       YAdjust = XAdjust * Cos / Sin;
01681       Filler->YStart = Bucket16For(Start.y - YAdjust, YS, NB * 256);
01682       YAdjust = XAdjust * Sin / Cos;
01683       Filler->YEnd = Bucket16For(Start.y + YAdjust, YS, NB * 256);
01684 
01685       Filler->Switch[S1].Type = StartSwitch;
01686       Filler->Switch[S1].X = Bucket8For(Switch1.x, XS, NB);
01687       Filler->Switch[S1].Y = Bucket8For(Switch1.y, YS, NB);
01688       XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
01689       YAdjust = XAdjust * Sin / Cos;
01690       Filler->Switch[S1].YInit = Bucket16For(Switch1.y - YAdjust, YS, NB * 256);
01691       Filler->Switch[S1].Delta = Filler->EndDelta;
01692 
01693       Filler->Switch[S2].Type = EndSwitch;
01694       Filler->Switch[S2].X = Bucket8For(Switch2.x, XS, NB);
01695       Filler->Switch[S2].Y = Bucket8For(Switch2.y, YS, NB);
01696       XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
01697       YAdjust = XAdjust * Cos / Sin;
01698       Filler->Switch[S2].YInit = Bucket16For(Switch2.y + YAdjust, YS, NB * 256);
01699       Filler->Switch[S2].Delta = Filler->StartDelta;
01700 
01701       Filler->Switch[2].Type = LastSwitch;
01702       Filler->Switch[2].X = Bucket8For(End.x, XS, NB);
01703     } else {
01704       /* falling diagonal proto */
01705       Angle *= 2.0 * PI;
01706       Cos = fabs(cos(Angle));
01707       Sin = fabs(sin(Angle));
01708 
01709       /* compute the positions of the corners of the acceptance region */
01710       Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
01711       Start.y = Y + (HalfLength + EndPad) * Sin - SidePad * Cos;
01712       End.x = 2.0 * X - Start.x;
01713       End.y = 2.0 * Y - Start.y;
01714       Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
01715       Switch1.y = Y + (HalfLength + EndPad) * Sin + SidePad * Cos;
01716       Switch2.x = 2.0 * X - Switch1.x;
01717       Switch2.y = 2.0 * Y - Switch1.y;
01718 
01719       if (Switch1.x > Switch2.x) {
01720         S1 = 1;
01721         S2 = 0;
01722       }
01723 
01724       /* translate into bucket positions and deltas */
01725       Filler->X = Bucket8For(Start.x, XS, NB);
01726       Filler->StartDelta = -(inT16) ((Sin / Cos) * 256);
01727       Filler->EndDelta = (inT16) ((Cos / Sin) * 256);
01728 
01729       XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
01730       YAdjust = XAdjust * Sin / Cos;
01731       Filler->YStart = Bucket16For(Start.y - YAdjust, YS, NB * 256);
01732       YAdjust = XAdjust * Cos / Sin;
01733       Filler->YEnd = Bucket16For(Start.y + YAdjust, YS, NB * 256);
01734 
01735       Filler->Switch[S1].Type = EndSwitch;
01736       Filler->Switch[S1].X = Bucket8For(Switch1.x, XS, NB);
01737       Filler->Switch[S1].Y = Bucket8For(Switch1.y, YS, NB);
01738       XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
01739       YAdjust = XAdjust * Sin / Cos;
01740       Filler->Switch[S1].YInit = Bucket16For(Switch1.y + YAdjust, YS, NB * 256);
01741       Filler->Switch[S1].Delta = Filler->StartDelta;
01742 
01743       Filler->Switch[S2].Type = StartSwitch;
01744       Filler->Switch[S2].X = Bucket8For(Switch2.x, XS, NB);
01745       Filler->Switch[S2].Y = Bucket8For(Switch2.y, YS, NB);
01746       XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
01747       YAdjust = XAdjust * Cos / Sin;
01748       Filler->Switch[S2].YInit = Bucket16For(Switch2.y - YAdjust, YS, NB * 256);
01749       Filler->Switch[S2].Delta = Filler->EndDelta;
01750 
01751       Filler->Switch[2].Type = LastSwitch;
01752       Filler->Switch[2].X = Bucket8For(End.x, XS, NB);
01753     }
01754   }
01755 }                                /* InitTableFiller */
01756 
01757 
01758 /*---------------------------------------------------------------------------*/
01759 #ifndef GRAPHICS_DISABLED
01760 
01770 void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT* Feature,
01771                       ScrollView::Color color) {
01772   FLOAT32 X, Y, Dx, Dy, Length;
01773 
01774   window->Pen(color);
01775   assert(Feature != NULL);
01776   assert(color != 0);
01777 
01778   X = Feature->X;
01779   Y = Feature->Y;
01780   Length = GetPicoFeatureLength() * 0.7 * INT_CHAR_NORM_RANGE;
01781   // The -PI has no significant effect here, but the value of Theta is computed
01782   // using BinaryAnglePlusPi in intfx.cpp.
01783   Dx = (Length / 2.0) * cos((Feature->Theta / 256.0) * 2.0 * PI - PI);
01784   Dy = (Length / 2.0) * sin((Feature->Theta / 256.0) * 2.0 * PI - PI);
01785 
01786   window->SetCursor(X, Y);
01787   window->DrawTo(X + Dx, Y + Dy);
01788 }                                /* RenderIntFeature */
01789 
01790 
01807 void RenderIntProto(ScrollView *window,
01808                     INT_CLASS Class,
01809                     PROTO_ID ProtoId,
01810                     ScrollView::Color color) {
01811   PROTO_SET ProtoSet;
01812   INT_PROTO Proto;
01813   int ProtoSetIndex;
01814   int ProtoWordIndex;
01815   FLOAT32 Length;
01816   int Xmin, Xmax, Ymin, Ymax;
01817   FLOAT32 X, Y, Dx, Dy;
01818   uinT32 ProtoMask;
01819   int Bucket;
01820 
01821   assert(ProtoId >= 0);
01822   assert(Class != NULL);
01823   assert(ProtoId < Class->NumProtos);
01824   assert(color != 0);
01825   window->Pen(color);
01826 
01827   ProtoSet = Class->ProtoSets[SetForProto(ProtoId)];
01828   ProtoSetIndex = IndexForProto(ProtoId);
01829   Proto = &(ProtoSet->Protos[ProtoSetIndex]);
01830   Length = (Class->ProtoLengths[ProtoId] *
01831     GetPicoFeatureLength() * INT_CHAR_NORM_RANGE);
01832   ProtoMask = PPrunerMaskFor(ProtoId);
01833   ProtoWordIndex = PPrunerWordIndexFor(ProtoId);
01834 
01835   // find the x and y extent of the proto from the proto pruning table
01836   Xmin = Ymin = NUM_PP_BUCKETS;
01837   Xmax = Ymax = 0;
01838   for (Bucket = 0; Bucket < NUM_PP_BUCKETS; Bucket++) {
01839     if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_X][Bucket][ProtoWordIndex]) {
01840       UpdateRange(Bucket, &Xmin, &Xmax);
01841     }
01842 
01843     if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_Y][Bucket][ProtoWordIndex]) {
01844       UpdateRange(Bucket, &Ymin, &Ymax);
01845     }
01846   }
01847   X = (Xmin + Xmax + 1) / 2.0 * PROTO_PRUNER_SCALE;
01848   Y = (Ymin + Ymax + 1) / 2.0 * PROTO_PRUNER_SCALE;
01849   // The -PI has no significant effect here, but the value of Theta is computed
01850   // using BinaryAnglePlusPi in intfx.cpp.
01851   Dx = (Length / 2.0) * cos((Proto->Angle / 256.0) * 2.0 * PI - PI);
01852   Dy = (Length / 2.0) * sin((Proto->Angle / 256.0) * 2.0 * PI - PI);
01853 
01854   window->SetCursor(X - Dx, Y - Dy);
01855   window->DrawTo(X + Dx, Y + Dy);
01856 }                                /* RenderIntProto */
01857 #endif
01858 
01874 int TruncateParam(FLOAT32 Param, int Min, int Max, char *Id) {
01875   if (Param < Min) {
01876     if (Id)
01877       cprintf("Warning: Param %s truncated from %f to %d!\n",
01878               Id, Param, Min);
01879     Param = Min;
01880   } else if (Param > Max) {
01881     if (Id)
01882       cprintf("Warning: Param %s truncated from %f to %d!\n",
01883               Id, Param, Max);
01884     Param = Max;
01885   }
01886   return static_cast<int>(floor(Param));
01887 }                                /* TruncateParam */
01888 
01889 
01890 #ifndef GRAPHICS_DISABLED
01891 
01895 void InitIntMatchWindowIfReqd() {
01896   if (IntMatchWindow == NULL) {
01897     IntMatchWindow = CreateFeatureSpaceWindow("IntMatchWindow", 50, 200);
01898     SVMenuNode* popup_menu = new SVMenuNode();
01899 
01900     popup_menu->AddChild("Debug Adapted classes", IDA_ADAPTIVE,
01901                          "x", "Class to debug");
01902     popup_menu->AddChild("Debug Static classes", IDA_STATIC,
01903                          "x", "Class to debug");
01904     popup_menu->AddChild("Debug Both", IDA_BOTH,
01905                          "x", "Class to debug");
01906     popup_menu->AddChild("Debug Shape Index", IDA_SHAPE_INDEX,
01907                          "0", "Index to debug");
01908     popup_menu->BuildMenu(IntMatchWindow, false);
01909   }
01910 }
01911 
01916 void InitProtoDisplayWindowIfReqd() {
01917   if (ProtoDisplayWindow == NULL) {
01918     ProtoDisplayWindow = CreateFeatureSpaceWindow("ProtoDisplayWindow",
01919                                                   550, 200);
01920  }
01921 }
01922 
01927 void InitFeatureDisplayWindowIfReqd() {
01928   if (FeatureDisplayWindow == NULL) {
01929     FeatureDisplayWindow = CreateFeatureSpaceWindow("FeatureDisplayWindow",
01930                                                     50, 700);
01931   }
01932 }
01933 
01936 ScrollView* CreateFeatureSpaceWindow(const char* name, int xpos, int ypos) {
01937   return new ScrollView(name, xpos, ypos, 520, 520, 260, 260, true);
01938 }
01939 #endif  // GRAPHICS_DISABLED
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines