tesseract  4.0.0-1-g2a2b
mergenf.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Filename: MergeNF.c
3 ** Purpose: Program for merging similar nano-feature protos
4 ** Author: Dan Johnson
5 **
6  ** (c) Copyright Hewlett-Packard Company, 1988.
7  ** Licensed under the Apache License, Version 2.0 (the "License");
8  ** you may not use this file except in compliance with the License.
9  ** You may obtain a copy of the License at
10  ** http://www.apache.org/licenses/LICENSE-2.0
11  ** Unless required by applicable law or agreed to in writing, software
12  ** distributed under the License is distributed on an "AS IS" BASIS,
13  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  ** See the License for the specific language governing permissions and
15  ** limitations under the License.
16 ******************************************************************************/
17 #include "mergenf.h"
18 #include "host.h"
19 #include "clusttool.h"
20 #include "cluster.h"
21 #include "oldlist.h"
22 #include "protos.h"
23 #include "ocrfeatures.h"
24 #include "featdefs.h"
25 #include "intproto.h"
26 #include "params.h"
27 
28 #include <algorithm>
29 #include <cstdio>
30 #include <cstring>
31 #include <cmath>
32 
33 /*-------------------once in subfeat---------------------------------*/
34 double_VAR(training_angle_match_scale, 1.0, "Angle Match Scale ...");
35 
36 double_VAR(training_similarity_midpoint, 0.0075, "Similarity Midpoint ...");
37 
38 double_VAR(training_similarity_curl, 2.0, "Similarity Curl ...");
39 
40 /*-----------------------------once in fasttrain----------------------------------*/
41 double_VAR(training_tangent_bbox_pad, 0.5, "Tangent bounding box pad ...");
42 
43 double_VAR(training_orthogonal_bbox_pad, 2.5, "Orthogonal bounding box pad ...");
44 
45 double_VAR(training_angle_pad, 45.0, "Angle pad ...");
46 
61 float CompareProtos(PROTO p1, PROTO p2) {
62  FEATURE Feature;
63  float WorstEvidence = WORST_EVIDENCE;
64  float Evidence;
65  float Angle, Length;
66 
67  /* if p1 and p2 are not close in length, don't let them match */
68  Length = fabs (p1->Length - p2->Length);
69  if (Length > MAX_LENGTH_MISMATCH)
70  return (0.0);
71 
72  /* create a dummy pico-feature to be used for comparisons */
73  Feature = NewFeature (&PicoFeatDesc);
74  Feature->Params[PicoFeatDir] = p1->Angle;
75 
76  /* convert angle to radians */
77  Angle = p1->Angle * 2.0 * M_PI;
78 
79  /* find distance from center of p1 to 1/2 picofeat from end */
80  Length = p1->Length / 2.0 - GetPicoFeatureLength () / 2.0;
81  if (Length < 0) Length = 0;
82 
83  /* set the dummy pico-feature at one end of p1 and match it to p2 */
84  Feature->Params[PicoFeatX] = p1->X + cos (Angle) * Length;
85  Feature->Params[PicoFeatY] = p1->Y + sin (Angle) * Length;
86  if (DummyFastMatch (Feature, p2)) {
87  Evidence = SubfeatureEvidence (Feature, p2);
88  if (Evidence < WorstEvidence)
89  WorstEvidence = Evidence;
90  } else {
91  FreeFeature(Feature);
92  return 0.0;
93  }
94 
95  /* set the dummy pico-feature at the other end of p1 and match it to p2 */
96  Feature->Params[PicoFeatX] = p1->X - cos (Angle) * Length;
97  Feature->Params[PicoFeatY] = p1->Y - sin (Angle) * Length;
98  if (DummyFastMatch (Feature, p2)) {
99  Evidence = SubfeatureEvidence (Feature, p2);
100  if (Evidence < WorstEvidence)
101  WorstEvidence = Evidence;
102  } else {
103  FreeFeature(Feature);
104  return 0.0;
105  }
106 
107  FreeFeature (Feature);
108  return (WorstEvidence);
109 
110 } /* CompareProtos */
111 
126  PROTO p2,
127  float w1,
128  float w2,
129  PROTO MergedProto) {
130  float TotalWeight;
131 
132  TotalWeight = w1 + w2;
133  w1 /= TotalWeight;
134  w2 /= TotalWeight;
135 
136  MergedProto->X = p1->X * w1 + p2->X * w2;
137  MergedProto->Y = p1->Y * w1 + p2->Y * w2;
138  MergedProto->Length = p1->Length * w1 + p2->Length * w2;
139  MergedProto->Angle = p1->Angle * w1 + p2->Angle * w2;
140  FillABC(MergedProto);
141 } /* ComputeMergedProto */
142 
157 int FindClosestExistingProto(CLASS_TYPE Class, int NumMerged[],
158  PROTOTYPE *Prototype) {
159  PROTO_STRUCT NewProto;
160  PROTO_STRUCT MergedProto;
161  int Pid;
162  PROTO Proto;
163  int BestProto;
164  float BestMatch;
165  float Match, OldMatch, NewMatch;
166 
167  MakeNewFromOld (&NewProto, Prototype);
168 
169  BestProto = NO_PROTO;
170  BestMatch = WORST_MATCH_ALLOWED;
171  for (Pid = 0; Pid < Class->NumProtos; Pid++) {
172  Proto = ProtoIn(Class, Pid);
173  ComputeMergedProto(Proto, &NewProto,
174  (float) NumMerged[Pid], 1.0, &MergedProto);
175  OldMatch = CompareProtos(Proto, &MergedProto);
176  NewMatch = CompareProtos(&NewProto, &MergedProto);
177  Match = std::min(OldMatch, NewMatch);
178  if (Match > BestMatch) {
179  BestProto = Pid;
180  BestMatch = Match;
181  }
182  }
183  return BestProto;
184 } /* FindClosestExistingProto */
185 
195 void MakeNewFromOld(PROTO New, PROTOTYPE *Old) {
196  New->X = CenterX(Old->Mean);
197  New->Y = CenterY(Old->Mean);
198  New->Length = LengthOf(Old->Mean);
199  New->Angle = OrientationOf(Old->Mean);
200  FillABC(New);
201 } /* MakeNewFromOld */
202 
203 /*-------------------once in subfeat---------------------------------*/
204 
210 float SubfeatureEvidence(FEATURE Feature, PROTO Proto) {
211  float Distance;
212  float Dangle;
213 
214  Dangle = Proto->Angle - Feature->Params[PicoFeatDir];
215  if (Dangle < -0.5) Dangle += 1.0;
216  if (Dangle > 0.5) Dangle -= 1.0;
217  Dangle *= training_angle_match_scale;
218 
219  Distance = Proto->A * Feature->Params[PicoFeatX] +
220  Proto->B * Feature->Params[PicoFeatY] +
221  Proto->C;
222 
223  return (EvidenceOf (Distance * Distance + Dangle * Dangle));
224 }
225 
234 double EvidenceOf (double Similarity) {
235 
236  Similarity /= training_similarity_midpoint;
237 
238  if (training_similarity_curl == 3)
239  Similarity = Similarity * Similarity * Similarity;
240  else if (training_similarity_curl == 2)
241  Similarity = Similarity * Similarity;
242  else
243  Similarity = pow (Similarity, training_similarity_curl);
244 
245  return (1.0 / (1.0 + Similarity));
246 }
247 
261 bool DummyFastMatch(FEATURE Feature, PROTO Proto)
262 {
263  FRECT BoundingBox;
264  float MaxAngleError;
265  float AngleError;
266 
267  MaxAngleError = training_angle_pad / 360.0;
268  AngleError = fabs (Proto->Angle - Feature->Params[PicoFeatDir]);
269  if (AngleError > 0.5)
270  AngleError = 1.0 - AngleError;
271 
272  if (AngleError > MaxAngleError)
273  return false;
274 
278  &BoundingBox);
279 
280  return PointInside(&BoundingBox, Feature->Params[PicoFeatX],
281  Feature->Params[PicoFeatY]);
282 } /* DummyFastMatch */
283 
299 void ComputePaddedBoundingBox (PROTO Proto, float TangentPad,
300  float OrthogonalPad, FRECT *BoundingBox) {
301  float Length = Proto->Length / 2.0 + TangentPad;
302  float Angle = Proto->Angle * 2.0 * M_PI;
303  float CosOfAngle = fabs(cos(Angle));
304  float SinOfAngle = fabs(sin(Angle));
305 
306  float Pad = std::max(CosOfAngle * Length, SinOfAngle * OrthogonalPad);
307  BoundingBox->MinX = Proto->X - Pad;
308  BoundingBox->MaxX = Proto->X + Pad;
309 
310  Pad = std::max(SinOfAngle * Length, CosOfAngle * OrthogonalPad);
311  BoundingBox->MinY = Proto->Y - Pad;
312  BoundingBox->MaxY = Proto->Y + Pad;
313 
314 } /* ComputePaddedBoundingBox */
315 
323 bool PointInside(FRECT *Rectangle, float X, float Y) {
324  return (X >= Rectangle->MinX) &&
325  (X <= Rectangle->MaxX) &&
326  (Y >= Rectangle->MinY) &&
327  (Y <= Rectangle->MaxY);
328 } /* PointInside */
int16_t NumProtos
Definition: protos.h:61
float * Mean
Definition: cluster.h:78
void ComputeMergedProto(PROTO p1, PROTO p2, float w1, float w2, PROTO MergedProto)
Definition: mergenf.cpp:125
float MaxX
Definition: mergenf.h:44
#define MAX_LENGTH_MISMATCH
Definition: mergenf.h:33
void FreeFeature(FEATURE Feature)
Definition: ocrfeatures.cpp:56
#define WORST_MATCH_ALLOWED
Definition: mergenf.h:31
float X
Definition: protos.h:46
double training_angle_match_scale
Definition: mergenf.cpp:34
float B
Definition: protos.h:44
#define double_VAR(name, val, comment)
Definition: params.h:285
double training_tangent_bbox_pad
Definition: mergenf.cpp:41
#define CenterX(M)
Definition: mergenf.h:50
double training_angle_pad
Definition: mergenf.cpp:45
double training_similarity_midpoint
Definition: mergenf.cpp:36
#define ProtoIn(Class, Pid)
Definition: protos.h:121
double training_similarity_curl
Definition: mergenf.cpp:38
float Params[1]
Definition: ocrfeatures.h:62
float Y
Definition: protos.h:47
#define GetPicoFeatureLength()
Definition: picofeat.h:57
float Length
Definition: protos.h:49
#define CenterY(M)
Definition: mergenf.h:51
double EvidenceOf(double Similarity)
Definition: mergenf.cpp:234
Definition: mergenf.h:43
void ComputePaddedBoundingBox(PROTO Proto, float TangentPad, float OrthogonalPad, FRECT *BoundingBox)
Definition: mergenf.cpp:299
void MakeNewFromOld(PROTO New, PROTOTYPE *Old)
Definition: mergenf.cpp:195
bool PointInside(FRECT *Rectangle, float X, float Y)
Definition: mergenf.cpp:323
float C
Definition: protos.h:45
float MinY
Definition: mergenf.h:44
float CompareProtos(PROTO p1, PROTO p2)
Definition: mergenf.cpp:61
FEATURE NewFeature(const FEATURE_DESC_STRUCT *FeatureDesc)
Definition: ocrfeatures.cpp:81
float MaxY
Definition: mergenf.h:44
void FillABC(PROTO Proto)
Definition: protos.cpp:195
float SubfeatureEvidence(FEATURE Feature, PROTO Proto)
Definition: mergenf.cpp:210
float Angle
Definition: protos.h:48
#define LengthOf(M)
Definition: mergenf.h:52
#define WORST_EVIDENCE
Definition: mergenf.h:32
float MinX
Definition: mergenf.h:44
#define NO_PROTO
Definition: matchdefs.h:43
TESS_API const FEATURE_DESC_STRUCT PicoFeatDesc
double training_orthogonal_bbox_pad
Definition: mergenf.cpp:43
#define OrientationOf(M)
Definition: mergenf.h:53
float A
Definition: protos.h:43
bool DummyFastMatch(FEATURE Feature, PROTO Proto)
Definition: mergenf.cpp:261
int FindClosestExistingProto(CLASS_TYPE Class, int NumMerged[], PROTOTYPE *Prototype)
Definition: mergenf.cpp:157