21 #define _USE_MATH_DEFINES // for M_PI
42 #include "config_auto.h"
48 #define PROTO_PRUNER_SCALE (4.0)
50 #define INT_DESCENDER (0.0 * INT_CHAR_NORM_RANGE)
51 #define INT_BASELINE (0.25 * INT_CHAR_NORM_RANGE)
52 #define INT_XHEIGHT (0.75 * INT_CHAR_NORM_RANGE)
53 #define INT_CAPHEIGHT (1.0 * INT_CHAR_NORM_RANGE)
55 #define INT_XCENTER (0.5 * INT_CHAR_NORM_RANGE)
56 #define INT_YCENTER (0.5 * INT_CHAR_NORM_RANGE)
57 #define INT_XRADIUS (0.2 * INT_CHAR_NORM_RANGE)
58 #define INT_YRADIUS (0.2 * INT_CHAR_NORM_RANGE)
61 #define INT_MAX_X INT_CHAR_NORM_RANGE
62 #define INT_MAX_Y INT_CHAR_NORM_RANGE
65 #define HV_TOLERANCE (0.0025)
70 #define MAX_NUM_SWITCHES 3
86 uint8_t AngleStart, AngleEnd;
89 int16_t StartDelta, EndDelta;
100 uint8_t AngleStart, AngleEnd;
108 #define OLD_MAX_NUM_CONFIGS 32
109 #define OLD_WERDS_PER_CONFIG_VEC ((OLD_MAX_NUM_CONFIGS + BITS_PER_WERD - 1) /\
116 #define CircularIncrement(i,r) (((i) < (r) - 1)?((i)++):((i) = 0))
119 #define MapParam(P,O,N) (std::floor(((P) + (O)) * (N)))
124 float BucketStart(
int Bucket,
float Offset,
int NumBuckets);
126 float BucketEnd(
int Bucket,
float Offset,
int NumBuckets);
138 int Bit,
float Center,
float Spread,
bool debug);
141 int Bit,
float Center,
float Spread,
bool debug);
158 #ifndef GRAPHICS_DISABLED
166 #endif // GRAPHICS_DISABLED
176 static ScrollView* FeatureDisplayWindow =
nullptr;
177 static ScrollView* ProtoDisplayWindow =
nullptr;
184 static INT_VAR(classify_num_cp_levels, 3,
"Number of Class Pruner Levels");
185 static double_VAR(classify_cp_angle_pad_loose, 45.0,
186 "Class Pruner Angle Pad Loose");
187 static double_VAR(classify_cp_angle_pad_medium, 20.0,
188 "Class Pruner Angle Pad Medium");
189 static double_VAR(classify_cp_angle_pad_tight, 10.0,
190 "CLass Pruner Angle Pad Tight");
191 static double_VAR(classify_cp_end_pad_loose, 0.5,
"Class Pruner End Pad Loose");
192 static double_VAR(classify_cp_end_pad_medium, 0.5,
"Class Pruner End Pad Medium");
193 static double_VAR(classify_cp_end_pad_tight, 0.5,
"Class Pruner End Pad Tight");
194 static double_VAR(classify_cp_side_pad_loose, 2.5,
"Class Pruner Side Pad Loose");
195 static double_VAR(classify_cp_side_pad_medium, 1.2,
"Class Pruner Side Pad Medium");
196 static double_VAR(classify_cp_side_pad_tight, 0.6,
"Class Pruner Side Pad Tight");
197 static double_VAR(classify_pp_angle_pad, 45.0,
"Proto Pruner Angle Pad");
198 static double_VAR(classify_pp_end_pad, 0.5,
"Proto Prune End Pad");
199 static double_VAR(classify_pp_side_pad, 2.5,
"Proto Pruner Side Pad");
207 : X(
ClipToRange<int16_t>(static_cast<int16_t>(pos.x() + 0.5), 0, 255)),
208 Y(
ClipToRange<int16_t>(static_cast<int16_t>(pos.y() + 0.5), 0, 255)),
216 Theta(static_cast<uint8_t>(
ClipToRange<
int>(theta, 0, UINT8_MAX))),
236 fprintf(stderr,
"Please make sure that classes are added to templates");
237 fprintf(stderr,
" in increasing order of ClassIds\n");
299 memset(ProtoSet, 0,
sizeof(*ProtoSet));
337 float EndPad, SidePad, AnglePad;
345 for (Level = classify_num_cp_levels - 1; Level >= 0; Level--) {
352 DoFill(&FillSpec, Pruner, ClassMask, ClassCount, WordIndex);
369 float Angle, X, Y, Length;
375 cprintf(
"AddProtoToProtoPruner:assert failed: %d < %d",
377 assert(ProtoId < Class->NumProtos);
382 Angle = Proto->
Angle;
384 assert(!std::isnan(Angle));
388 Angle +
ANGLE_SHIFT, classify_pp_angle_pad / 360.0,
395 Pad = std::max(fabs (cos (Angle)) * (Length / 2.0 +
396 classify_pp_end_pad *
398 fabs (sin (Angle)) * (classify_pp_side_pad *
404 Pad = std::max(fabs (sin (Angle)) * (Length / 2.0 +
405 classify_pp_end_pad *
407 fabs (cos (Angle)) * (classify_pp_side_pad *
418 uint8_t
Bucket8For(
float param,
float offset,
int num_buckets) {
420 return static_cast<uint8_t>(ClipToRange<int>(bucket, 0, num_buckets - 1));
422 uint16_t
Bucket16For(
float param,
float offset,
int num_buckets) {
424 return static_cast<uint16_t>(ClipToRange<int>(bucket, 0, num_buckets - 1));
432 uint8_t
CircBucketFor(
float param,
float offset,
int num_buckets) {
434 return static_cast<uint8_t>(
Modulo(bucket, num_buckets));
438 #ifndef GRAPHICS_DISABLED
448 if (IntMatchWindow !=
nullptr)
468 for (ProtoId = 0, TotalLength = 0;
492 assert(ProtoId < Class->NumProtos);
496 Param = Proto->
A * 128;
499 Param = -Proto->
B * 256;
502 Param = Proto->
C * 128;
505 Param = Proto->
Angle * 256;
506 if (Param < 0 || Param >= 256)
509 P->
Angle = static_cast<uint8_t>(Param);
515 cprintf(
"Converted ffeat to (A=%d,B=%d,C=%d,L=%d)",
539 for (ClassId = 0; ClassId < target_unicharset.
size(); ClassId++) {
540 FClass = &(FloatProtos[ClassId]);
542 strcmp(target_unicharset.
id_to_unichar(ClassId),
" ") != 0) {
543 cprintf(
"Warning: no protos/configs for %s in CreateIntTemplates()\n",
551 for (
int i = 0; i < fs.
size; ++i) {
562 for (ProtoId = 0; ProtoId < FClass->
NumProtos; ProtoId++) {
570 for (ConfigId = 0; ConfigId < FClass->
NumConfigs; ConfigId++) {
575 return (IntTemplates);
580 #ifndef GRAPHICS_DISABLED
593 if (FeatureDisplayWindow) {
611 if (ProtoDisplayWindow) {
645 memset(ProtoSet, 0,
sizeof(*ProtoSet));
664 static void free_int_class(
INT_CLASS int_class) {
702 free_int_class(templates->
Class[i]);
719 int i, j, w, x, y, z;
729 int b, bit_number, last_cp_bit_number, new_b, new_i, new_w;
733 auto **TempClassPruner =
735 uint32_t SetBitsForMask =
737 uint32_t Mask, NewMask, ClassBits;
744 if (fp->FReadEndian(&unicharset_size,
sizeof(unicharset_size), 1) != 1)
745 tprintf(
"Bad read of inttemp!\n");
750 tprintf(
"Bad read of inttemp!\n");
756 tprintf(
"Bad read of inttemp!\n");
759 if (version_id < 3) {
764 if (version_id < 2) {
765 if (fp->FReadEndian(IndexFor,
sizeof(IndexFor[0]), unicharset_size) !=
767 tprintf(
"Bad read of inttemp!\n");
769 if (fp->FReadEndian(ClassIdFor,
sizeof(ClassIdFor[0]),
771 tprintf(
"Bad read of inttemp!\n");
776 const int kNumBuckets =
780 if (fp->FReadEndian(Pruner,
sizeof(Pruner->
p[0][0][0][0]), kNumBuckets) !=
782 tprintf(
"Bad read of inttemp!\n");
784 if (version_id < 2) {
785 TempClassPruner[i] = Pruner;
792 if (version_id < 2) {
796 if (ClassIdFor[i] > max_class_id)
797 max_class_id = ClassIdFor[i];
810 if (TempClassPruner[i]->p[x][y][z][w] == 0)
814 if (bit_number > last_cp_bit_number)
818 Mask = SetBitsForMask << b;
819 ClassBits = TempClassPruner[i]->p[x][y][z][w] & Mask;
826 ClassBits <<= (new_b - b);
828 ClassBits >>= (b - new_b);
832 NewMask = SetBitsForMask << new_b;
833 Templates->
ClassPruners[new_i]->
p[x][y][z][new_w] &= ~NewMask;
834 Templates->
ClassPruners[new_i]->
p[x][y][z][new_w] |= ClassBits;
839 delete TempClassPruner[i];
850 tprintf(
"Bad read of inttemp!\n");
851 if (version_id == 0) {
853 for (j = 0; j < 5; ++j) {
855 if (fp->FRead(&junk,
sizeof(junk), 1) != 1)
856 tprintf(
"Bad read of inttemp!\n");
859 int num_configs = version_id < 4 ? MaxNumConfigs : Class->
NumConfigs;
861 if (fp->FReadEndian(Class->
ConfigLengths,
sizeof(uint16_t), num_configs) !=
863 tprintf(
"Bad read of inttemp!\n");
865 if (version_id < 2) {
877 tprintf(
"Bad read of inttemp!\n");
887 num_buckets) != num_buckets)
888 tprintf(
"Bad read of inttemp!\n");
890 if (fp->FRead(&ProtoSet->
Protos[x].
A,
sizeof(ProtoSet->
Protos[x].
A),
898 tprintf(
"Bad read of inttemp!\n");
901 WerdsPerConfigVec) != WerdsPerConfigVec)
902 cprintf(
"Bad read of inttemp!\n");
906 if (version_id < 4) {
913 if (version_id < 2) {
921 if (i < Templates->NumClasses) {
923 fprintf(stderr,
"Non-contiguous class ids in inttemp\n");
928 fprintf(stderr,
"Class id %d exceeds NumClassesIn (Templates) %d\n",
935 if (version_id >= 4) {
936 using namespace std::placeholders;
938 if (version_id >= 5) {
948 delete[] TempClassPruner;
954 #ifndef GRAPHICS_DISABLED
965 if (ProtoDisplayWindow) {
966 ProtoDisplayWindow->
Clear();
968 if (FeatureDisplayWindow) {
969 FeatureDisplayWindow->
Clear();
976 if (ProtoDisplayWindow) {
980 if (FeatureDisplayWindow) {
1022 int unicharset_size = target_unicharset.
size();
1023 int version_id = -5;
1025 if (Templates->
NumClasses != unicharset_size) {
1026 cprintf(
"Warning: executing WriteIntTemplates() with %d classes in"
1027 " Templates, while target_unicharset size is %d\n",
1032 fwrite(&unicharset_size,
sizeof(unicharset_size), 1, File);
1033 fwrite(&version_id,
sizeof(version_id), 1, File);
1044 for (i = 0; i < Templates->
NumClasses; i++) {
1045 Class = Templates->
Class[i];
1053 fwrite(&Class->
ConfigLengths[j],
sizeof(uint16_t), 1, File);
1067 fwrite(&Class->
font_set_id,
sizeof(
int), 1, File);
1071 using namespace std::placeholders;
1094 float BucketStart(
int Bucket,
float Offset,
int NumBuckets) {
1095 return ((static_cast<float>(Bucket) / NumBuckets) - Offset);
1110 float BucketEnd(
int Bucket,
float Offset,
int NumBuckets) {
1111 return ((static_cast<float>(Bucket + 1) / NumBuckets) - Offset);
1127 uint32_t ClassCount,
1128 uint32_t WordIndex) {
1138 if (FillSpec->
YStart < 0)
1143 for (Y = FillSpec->
YStart; Y <= FillSpec->YEnd; Y++)
1146 OldWord = Pruner->
p[X][Y][Angle][WordIndex];
1147 if (ClassCount > (OldWord & ClassMask)) {
1148 OldWord &= ~ClassMask;
1149 OldWord |= ClassCount;
1150 Pruner->
p[X][Y][Angle][WordIndex] = OldWord;
1187 int Bit,
float Center,
float Spread,
bool debug) {
1188 int i, FirstBucket, LastBucket;
1193 FirstBucket = static_cast<int>(std::floor((Center - Spread) *
NUM_PP_BUCKETS));
1194 if (FirstBucket < 0)
1197 LastBucket = static_cast<int>(std::floor((Center + Spread) *
NUM_PP_BUCKETS));
1200 if (debug)
tprintf(
"Circular fill from %d to %d", FirstBucket, LastBucket);
1205 if (i == LastBucket)
1226 int Bit,
float Center,
float Spread,
bool debug) {
1227 int i, FirstBucket, LastBucket;
1229 FirstBucket = static_cast<int>(std::floor((Center - Spread) *
NUM_PP_BUCKETS));
1230 if (FirstBucket < 0)
1233 LastBucket = static_cast<int>(std::floor((Center + Spread) *
NUM_PP_BUCKETS));
1237 if (debug)
tprintf(
"Linear fill from %d to %d", FirstBucket, LastBucket);
1238 for (i = FirstBucket; i <= LastBucket; i++)
1245 #ifndef GRAPHICS_DISABLED
1258 bool* pretrained_on,
int* shape_id) {
1262 int unichar_id = INVALID_UNICHAR_ID;
1271 *adaptive_on =
false;
1272 *pretrained_on =
true;
1273 if (*shape_id >= 0 && *shape_id < shape_table_->NumShapes()) {
1277 tprintf(
"Shape %d, first unichar=%d, font=%d\n",
1278 *shape_id, unichar_id, font_id);
1283 tprintf(
"No shape table loaded!\n");
1289 *adaptive_on =
true;
1290 *pretrained_on =
false;
1293 *adaptive_on =
false;
1294 *pretrained_on =
true;
1296 *adaptive_on =
true;
1297 *pretrained_on =
true;
1309 tprintf(
"Char class '%s' not found in unicharset",
1341 *AnglePad = classify_cp_angle_pad_loose / 360.0;
1347 *AnglePad = classify_cp_angle_pad_medium / 360.0;
1353 *AnglePad = classify_cp_angle_pad_tight / 360.0;
1359 *AnglePad = classify_cp_angle_pad_tight / 360.0;
1362 if (*AnglePad > 0.5)
1373 assert (Evidence >= 0.0);
1374 assert (Evidence <= 1.0);
1376 if (Evidence >= 0.90)
1378 else if (Evidence >= 0.75)
1380 else if (Evidence >= 0.50)
1400 Fill->
X = Filler->
X;
1406 while (Filler->
X >= Next->
X) {
1407 Fill->
X = Filler->
X = Next->
X;
1414 Fill->
YEnd = Next->
Y;
1445 #define AS ANGLE_SHIFT
1446 #define NB NUM_CP_BUCKETS
1449 float X, Y, HalfLength;
1451 float XAdjust, YAdjust;
1452 FPOINT Start, Switch1, Switch2, End;
1456 Angle = Proto->
Angle;
1459 HalfLength = Proto->
Length / 2.0;
1487 if ((Angle > 0.0 && Angle < 0.25) || (Angle > 0.5 && Angle < 0.75)) {
1489 Angle *= 2.0 * M_PI;
1490 Cos = fabs(cos(Angle));
1491 Sin = fabs(sin(Angle));
1494 Start.
x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
1495 Start.
y = Y - (HalfLength + EndPad) * Sin + SidePad * Cos;
1496 End.
x = 2.0 * X - Start.
x;
1497 End.
y = 2.0 * Y - Start.
y;
1498 Switch1.
x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
1499 Switch1.
y = Y - (HalfLength + EndPad) * Sin - SidePad * Cos;
1500 Switch2.
x = 2.0 * X - Switch1.
x;
1501 Switch2.
y = 2.0 * Y - Switch1.
y;
1503 if (Switch1.
x > Switch2.
x) {
1510 Filler->
StartDelta = -static_cast<int16_t>((Cos / Sin) * 256);
1511 Filler->
EndDelta = static_cast<int16_t>((Sin / Cos) * 256);
1514 YAdjust = XAdjust * Cos / Sin;
1516 YAdjust = XAdjust * Sin / Cos;
1523 YAdjust = XAdjust * Sin / Cos;
1531 YAdjust = XAdjust * Cos / Sin;
1539 Angle *= 2.0 * M_PI;
1540 Cos = fabs(cos(Angle));
1541 Sin = fabs(sin(Angle));
1544 Start.
x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
1545 Start.
y = Y + (HalfLength + EndPad) * Sin - SidePad * Cos;
1546 End.
x = 2.0 * X - Start.
x;
1547 End.
y = 2.0 * Y - Start.
y;
1548 Switch1.
x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
1549 Switch1.
y = Y + (HalfLength + EndPad) * Sin + SidePad * Cos;
1550 Switch2.
x = 2.0 * X - Switch1.
x;
1551 Switch2.
y = 2.0 * Y - Switch1.
y;
1553 if (Switch1.
x > Switch2.
x) {
1560 Filler->
StartDelta = static_cast<int16_t>(ClipToRange<int>(
1562 Filler->
EndDelta = static_cast<int16_t>(ClipToRange<int>(
1566 YAdjust = XAdjust * Sin / Cos;
1568 YAdjust = XAdjust * Cos / Sin;
1575 YAdjust = XAdjust * Sin / Cos;
1583 YAdjust = XAdjust * Cos / Sin;
1595 #ifndef GRAPHICS_DISABLED
1606 float X, Y, Dx, Dy, Length;
1609 assert(Feature !=
nullptr);
1617 Dx = (Length / 2.0) * cos((Feature->
Theta / 256.0) * 2.0 * M_PI - M_PI);
1618 Dy = (Length / 2.0) * sin((Feature->
Theta / 256.0) * 2.0 * M_PI - M_PI);
1621 window->
DrawTo(X + Dx, Y + Dy);
1647 int Xmin, Xmax, Ymin, Ymax;
1652 assert(ProtoId >= 0);
1653 assert(Class !=
nullptr);
1654 assert(ProtoId < Class->NumProtos);
1660 Proto = &(ProtoSet->
Protos[ProtoSetIndex]);
1682 Dx = (Length / 2.0) * cos((Proto->
Angle / 256.0) * 2.0 * M_PI - M_PI);
1683 Dy = (Length / 2.0) * sin((Proto->
Angle / 256.0) * 2.0 * M_PI - M_PI);
1686 window->
DrawTo(X + Dx, Y + Dy);
1703 int TruncateParam(
float Param,
int Min,
int Max,
char *Id) {
1706 cprintf(
"Warning: Param %s truncated from %f to %d!\n",
1709 }
else if (Param > Max) {
1711 cprintf(
"Warning: Param %s truncated from %f to %d!\n",
1715 return static_cast<int>(std::floor(Param));
1719 #ifndef GRAPHICS_DISABLED
1725 if (IntMatchWindow ==
nullptr) {
1729 popup_menu->AddChild(
"Debug Adapted classes",
IDA_ADAPTIVE,
1730 "x",
"Class to debug");
1731 popup_menu->AddChild(
"Debug Static classes",
IDA_STATIC,
1732 "x",
"Class to debug");
1733 popup_menu->AddChild(
"Debug Both",
IDA_BOTH,
1734 "x",
"Class to debug");
1736 "0",
"Index to debug");
1737 popup_menu->BuildMenu(IntMatchWindow,
false);
1746 if (ProtoDisplayWindow ==
nullptr) {
1757 if (FeatureDisplayWindow ==
nullptr) {
1766 return new ScrollView(name, xpos, ypos, 520, 520, 260, 260,
true);
1768 #endif // GRAPHICS_DISABLED