2007-03-08 04:03:40 +08:00
|
|
|
/******************************************************************************
|
|
|
|
** Filename: normmatch.c
|
|
|
|
** Purpose: Simple matcher based on character normalization features.
|
|
|
|
** Author: Dan Johnson
|
|
|
|
** History: Wed Dec 19 16:18:06 1990, DSJ, Created.
|
|
|
|
**
|
|
|
|
** (c) Copyright Hewlett-Packard Company, 1988.
|
|
|
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
** you may not use this file except in compliance with the License.
|
|
|
|
** You may obtain a copy of the License at
|
|
|
|
** http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
** Unless required by applicable law or agreed to in writing, software
|
|
|
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
** See the License for the specific language governing permissions and
|
|
|
|
** limitations under the License.
|
|
|
|
******************************************************************************/
|
|
|
|
/**----------------------------------------------------------------------------
|
|
|
|
Include Files and Type Defines
|
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
#include "normmatch.h"
|
2009-07-11 10:17:36 +08:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "classify.h"
|
2007-03-08 04:03:40 +08:00
|
|
|
#include "clusttool.h"
|
|
|
|
#include "const.h"
|
|
|
|
#include "efio.h"
|
|
|
|
#include "emalloc.h"
|
|
|
|
#include "globals.h"
|
2009-07-11 10:17:36 +08:00
|
|
|
#include "helpers.h"
|
|
|
|
#include "normfeat.h"
|
2007-03-08 04:03:40 +08:00
|
|
|
#include "scanutils.h"
|
2009-07-11 10:17:36 +08:00
|
|
|
#include "unicharset.h"
|
|
|
|
#include "varable.h"
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:17:36 +08:00
|
|
|
struct NORM_PROTOS
|
2007-03-08 04:03:40 +08:00
|
|
|
{
|
|
|
|
int NumParams;
|
|
|
|
PARAM_DESC *ParamDesc;
|
2007-07-18 09:15:07 +08:00
|
|
|
LIST* Protos;
|
|
|
|
int NumProtos;
|
2009-07-11 10:17:36 +08:00
|
|
|
};
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/**----------------------------------------------------------------------------
|
|
|
|
Private Function Prototypes
|
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
FLOAT32 NormEvidenceOf(register FLOAT32 NormAdj);
|
|
|
|
|
|
|
|
void PrintNormMatch(FILE *File,
|
|
|
|
int NumParams,
|
|
|
|
PROTOTYPE *Proto,
|
|
|
|
FEATURE Feature);
|
|
|
|
|
|
|
|
NORM_PROTOS *ReadNormProtos(FILE *File);
|
|
|
|
|
|
|
|
/**----------------------------------------------------------------------------
|
2009-07-11 10:17:36 +08:00
|
|
|
Variables
|
2007-03-08 04:03:40 +08:00
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
|
|
|
|
/* control knobs used to control the normalization adjustment process */
|
2009-07-11 10:17:36 +08:00
|
|
|
double_VAR(classify_norm_adj_midpoint, 32.0, "Norm adjust midpoint ...");
|
|
|
|
double_VAR(classify_norm_adj_curl, 2.0, "Norm adjust curl ...");
|
|
|
|
|
2007-03-08 04:03:40 +08:00
|
|
|
/**----------------------------------------------------------------------------
|
|
|
|
Public Code
|
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2009-07-11 10:17:36 +08:00
|
|
|
namespace tesseract {
|
|
|
|
FLOAT32 Classify::ComputeNormMatch(CLASS_ID ClassId, FEATURE Feature,
|
|
|
|
BOOL8 DebugMatch) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
|
|
|
** Parameters:
|
|
|
|
** ClassId id of class to match against
|
|
|
|
** Feature character normalization feature
|
|
|
|
** DebugMatch controls dump of debug info
|
|
|
|
** Globals:
|
|
|
|
** NormProtos character normalization prototypes
|
|
|
|
** Operation: This routine compares Features against each character
|
|
|
|
** normalization proto for ClassId and returns the match
|
|
|
|
** rating of the best match.
|
|
|
|
** Return: Best match rating for Feature against protos of ClassId.
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Wed Dec 19 16:56:12 1990, DSJ, Created.
|
|
|
|
*/
|
|
|
|
LIST Protos;
|
|
|
|
FLOAT32 BestMatch;
|
|
|
|
FLOAT32 Match;
|
|
|
|
FLOAT32 Delta;
|
|
|
|
PROTOTYPE *Proto;
|
|
|
|
int ProtoId;
|
|
|
|
|
|
|
|
/* handle requests for classification as noise */
|
|
|
|
if (ClassId == NO_CLASS) {
|
|
|
|
/* kludge - clean up constants and make into control knobs later */
|
2009-03-11 03:03:06 +08:00
|
|
|
Match = (Feature->Params[CharNormLength] *
|
|
|
|
Feature->Params[CharNormLength] * 500.0 +
|
|
|
|
Feature->Params[CharNormRx] *
|
|
|
|
Feature->Params[CharNormRx] * 8000.0 +
|
|
|
|
Feature->Params[CharNormRy] *
|
|
|
|
Feature->Params[CharNormRy] * 8000.0);
|
2007-03-08 04:03:40 +08:00
|
|
|
return (1.0 - NormEvidenceOf (Match));
|
|
|
|
}
|
|
|
|
|
|
|
|
BestMatch = MAX_FLOAT32;
|
|
|
|
Protos = NormProtos->Protos[ClassId];
|
|
|
|
|
|
|
|
if (DebugMatch) {
|
|
|
|
cprintf ("\nFeature = ");
|
|
|
|
WriteFeature(stdout, Feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
ProtoId = 0;
|
|
|
|
iterate(Protos) {
|
2007-05-16 09:30:20 +08:00
|
|
|
Proto = (PROTOTYPE *) first_node (Protos);
|
2009-03-11 03:03:06 +08:00
|
|
|
Delta = Feature->Params[CharNormY] - Proto->Mean[CharNormY];
|
2007-03-08 04:03:40 +08:00
|
|
|
Match = Delta * Delta * Proto->Weight.Elliptical[CharNormY];
|
2009-03-11 03:03:06 +08:00
|
|
|
Delta = Feature->Params[CharNormRx] - Proto->Mean[CharNormRx];
|
2007-03-08 04:03:40 +08:00
|
|
|
Match += Delta * Delta * Proto->Weight.Elliptical[CharNormRx];
|
|
|
|
|
|
|
|
if (Match < BestMatch)
|
|
|
|
BestMatch = Match;
|
|
|
|
|
|
|
|
if (DebugMatch) {
|
|
|
|
cprintf ("Proto %1d = ", ProtoId);
|
|
|
|
WriteNFloats (stdout, NormProtos->NumParams, Proto->Mean);
|
|
|
|
cprintf (" var = ");
|
|
|
|
WriteNFloats (stdout, NormProtos->NumParams,
|
|
|
|
Proto->Variance.Elliptical);
|
|
|
|
cprintf (" match = ");
|
|
|
|
PrintNormMatch (stdout, NormProtos->NumParams, Proto, Feature);
|
|
|
|
}
|
|
|
|
ProtoId++;
|
|
|
|
}
|
|
|
|
return (1.0 - NormEvidenceOf (BestMatch));
|
|
|
|
} /* ComputeNormMatch */
|
|
|
|
|
2009-07-11 10:17:36 +08:00
|
|
|
void Classify::FreeNormProtos() {
|
2007-03-08 04:03:40 +08:00
|
|
|
if (NormProtos != NULL) {
|
2007-07-18 09:15:07 +08:00
|
|
|
for (int i = 0; i < NormProtos->NumProtos; i++)
|
2007-05-16 09:30:20 +08:00
|
|
|
FreeProtoList(&NormProtos->Protos[i]);
|
2007-07-18 09:15:07 +08:00
|
|
|
Efree(NormProtos->Protos);
|
2007-03-08 04:03:40 +08:00
|
|
|
Efree(NormProtos->ParamDesc);
|
|
|
|
Efree(NormProtos);
|
|
|
|
NormProtos = NULL;
|
|
|
|
}
|
|
|
|
}
|
2009-07-11 10:17:36 +08:00
|
|
|
} // namespace tesseract
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/**----------------------------------------------------------------------------
|
|
|
|
Private Code
|
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
/**********************************************************************
|
|
|
|
* NormEvidenceOf
|
|
|
|
*
|
|
|
|
* Return the new type of evidence number corresponding to this
|
|
|
|
* normalization adjustment. The equation that represents the transform is:
|
|
|
|
* 1 / (1 + (NormAdj / midpoint) ^ curl)
|
|
|
|
**********************************************************************/
|
|
|
|
FLOAT32 NormEvidenceOf(register FLOAT32 NormAdj) {
|
2009-07-11 10:17:36 +08:00
|
|
|
NormAdj /= classify_norm_adj_midpoint;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:17:36 +08:00
|
|
|
if (classify_norm_adj_curl == 3)
|
2007-03-08 04:03:40 +08:00
|
|
|
NormAdj = NormAdj * NormAdj * NormAdj;
|
2009-07-11 10:17:36 +08:00
|
|
|
else if (classify_norm_adj_curl == 2)
|
2007-03-08 04:03:40 +08:00
|
|
|
NormAdj = NormAdj * NormAdj;
|
|
|
|
else
|
2009-07-11 10:17:36 +08:00
|
|
|
NormAdj = pow(static_cast<double>(NormAdj), classify_norm_adj_curl);
|
2007-03-08 04:03:40 +08:00
|
|
|
return (1.0 / (1.0 + NormAdj));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
void PrintNormMatch(FILE *File,
|
|
|
|
int NumParams,
|
|
|
|
PROTOTYPE *Proto,
|
|
|
|
FEATURE Feature) {
|
|
|
|
/*
|
|
|
|
** Parameters:
|
|
|
|
** File open text file to dump match debug info to
|
|
|
|
** NumParams # of parameters in proto and feature
|
|
|
|
** Proto[] array of prototype parameters
|
|
|
|
** Feature[] array of feature parameters
|
|
|
|
** Globals: none
|
|
|
|
** Operation: This routine dumps out detailed normalization match info.
|
|
|
|
** Return: none
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Wed Jan 2 09:49:35 1991, DSJ, Created.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
FLOAT32 ParamMatch;
|
|
|
|
FLOAT32 TotalMatch;
|
|
|
|
|
|
|
|
for (i = 0, TotalMatch = 0.0; i < NumParams; i++) {
|
2009-07-11 10:17:36 +08:00
|
|
|
ParamMatch = (Feature->Params[i] - Mean(Proto, i)) /
|
|
|
|
StandardDeviation(Proto, i);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
fprintf (File, " %6.1f", ParamMatch);
|
|
|
|
|
|
|
|
if (i == CharNormY || i == CharNormRx)
|
|
|
|
TotalMatch += ParamMatch * ParamMatch;
|
|
|
|
}
|
|
|
|
fprintf (File, " --> %6.1f (%4.2f)\n",
|
|
|
|
TotalMatch, NormEvidenceOf (TotalMatch));
|
|
|
|
|
|
|
|
} /* PrintNormMatch */
|
|
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2009-07-11 10:17:36 +08:00
|
|
|
namespace tesseract {
|
|
|
|
NORM_PROTOS *Classify::ReadNormProtos(FILE *File, inT64 end_offset) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
|
|
|
** Parameters:
|
|
|
|
** File open text file to read normalization protos from
|
|
|
|
** Globals: none
|
|
|
|
** Operation: This routine allocates a new data structure to hold
|
|
|
|
** a set of character normalization protos. It then fills in
|
|
|
|
** the data structure by reading from the specified File.
|
|
|
|
** Return: Character normalization protos.
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Wed Dec 19 16:38:49 1990, DSJ, Created.
|
|
|
|
*/
|
|
|
|
NORM_PROTOS *NormProtos;
|
|
|
|
int i;
|
2007-07-18 09:15:07 +08:00
|
|
|
char unichar[UNICHAR_LEN + 1];
|
|
|
|
UNICHAR_ID unichar_id;
|
2007-03-08 04:03:40 +08:00
|
|
|
LIST Protos;
|
|
|
|
int NumProtos;
|
|
|
|
|
|
|
|
/* allocate and initialization data structure */
|
|
|
|
NormProtos = (NORM_PROTOS *) Emalloc (sizeof (NORM_PROTOS));
|
2007-07-18 09:15:07 +08:00
|
|
|
NormProtos->NumProtos = unicharset.size();
|
|
|
|
NormProtos->Protos = (LIST *) Emalloc (NormProtos->NumProtos * sizeof(LIST));
|
|
|
|
for (i = 0; i < NormProtos->NumProtos; i++)
|
2007-03-08 04:03:40 +08:00
|
|
|
NormProtos->Protos[i] = NIL;
|
|
|
|
|
|
|
|
/* read file header and save in data structure */
|
|
|
|
NormProtos->NumParams = ReadSampleSize (File);
|
|
|
|
NormProtos->ParamDesc = ReadParamDesc (File, NormProtos->NumParams);
|
|
|
|
|
|
|
|
/* read protos for each class into a separate list */
|
2009-07-11 10:17:36 +08:00
|
|
|
while ((end_offset < 0 || ftell(File) < end_offset) &&
|
|
|
|
fscanf(File, "%s %d", unichar, &NumProtos) == 2) {
|
2007-07-18 09:15:07 +08:00
|
|
|
if (unicharset.contains_unichar(unichar)) {
|
|
|
|
unichar_id = unicharset.unichar_to_id(unichar);
|
|
|
|
Protos = NormProtos->Protos[unichar_id];
|
|
|
|
for (i = 0; i < NumProtos; i++)
|
|
|
|
Protos =
|
|
|
|
push_last (Protos, ReadPrototype (File, NormProtos->NumParams));
|
|
|
|
NormProtos->Protos[unichar_id] = Protos;
|
|
|
|
} else
|
|
|
|
cprintf("Error: unichar %s in normproto file is not in unichar set.\n");
|
2009-07-11 10:17:36 +08:00
|
|
|
SkipNewline(File);
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
return (NormProtos);
|
|
|
|
} /* ReadNormProtos */
|
2009-07-11 10:17:36 +08:00
|
|
|
} // namespace tesseract
|