📄 li_recognizer.c
字号:
(next_reg->end - next_reg->start) < LP_FILTER_MIN;
next_reg = curr_reg->next) {
/* next_reg must not be plain, and it must be followed by a plain */
/* assert(next_reg->type != RGN_PLAIN); */
/* assert(next_reg->next != NULL && (next_reg->next)->type == RGN_PLAIN); */
curr_reg->next = (next_reg->next)->next;
curr_reg->end = (next_reg->next)->end;
free(next_reg->next);
free(next_reg);
}
}
/* Add-in pseudo-extremes. */
{
region_list *tmp, *prev_reg;
tmp = regions;
regions = NULL;
prev_reg = NULL;
for (curr_reg = tmp; curr_reg; curr_reg = curr_reg->next) {
if (curr_reg->type == RGN_PLAIN) {
int arclen = lialg_compute_pathlen_subset(pts,
curr_reg->start,
curr_reg->end);
int dx = pts->pts[curr_reg->end].x -
pts->pts[curr_reg->start].x;
int dy = pts->pts[curr_reg->end].y -
pts->pts[curr_reg->start].y;
int chordlen = isqrt(10000 * (dx * dx + dy * dy));
int atcr = (chordlen == 0) ? 0 : (100 * arclen + chordlen / 2) / chordlen;
if (lidebug)
fprintf(stderr, "%d, %d, %d\n", arclen, chordlen, atcr);
/* Split region if necessary. */
if (arclen >= PE_AL_THLD && atcr >= PE_ATCR_THLD) {
int mid = curr_reg->start + (curr_reg->end - curr_reg->start) / 2;
int end = curr_reg->end;
region_list *saved_next = curr_reg->next;
curr_reg->end = mid - 1;
if (prev_reg == NULL)
regions = curr_reg;
else
prev_reg->next = curr_reg;
prev_reg = curr_reg;
/* curr_reg = (region_list *)safe_malloc(sizeof(region_list));*/
curr_reg = allocate(1, region_list);
curr_reg->start = mid;
curr_reg->end = mid;
curr_reg->type = RGN_PSEUDO;
curr_reg->next = NULL;
prev_reg->next = curr_reg;
prev_reg = curr_reg;
/* curr_reg = (region_list *)safe_malloc(sizeof(region_list)); */
curr_reg = allocate(1, region_list);
curr_reg->start = mid + 1;
curr_reg->end = end;
curr_reg->type = RGN_PLAIN;
curr_reg->next = NULL;
prev_reg->next = curr_reg;
prev_reg = curr_reg;
curr_reg->next = saved_next;
continue;
}
}
if (prev_reg == NULL)
regions = curr_reg;
else
prev_reg->next = curr_reg;
prev_reg = curr_reg;
}
}
}
free(junk);
return(regions);
}
static point_list *lialg_compute_dompts(point_list *pts, region_list *regions) {
point_list *dpts = NULL;
int ndpts;
int *cas = NULL;
int nonplain;
region_list *r;
/* Compute contour angle set. */
cas = lialg_compute_contour_angle_set(pts, regions);
/* assert(cas != NULL);*/
/* Dominant points include: start_pt, end_pt, extrema_of_non_plain_regions, midpts of the preceding. */
nonplain = 0;
for (r = regions; r != NULL; r = r->next)
if (r->type != RGN_PLAIN) nonplain++;
ndpts = 2 * (2 + nonplain) - 1;
/* dpts = (point_list *)safe_malloc(sizeof(point_list)); */
dpts = allocate(1, point_list);
dpts->pts = make_pen_point_array(ndpts);
if (dpts->pts == NULL) {
free(dpts);
return(NULL);
}
dpts->npts = ndpts;
dpts->next = NULL;
/* Pick out dominant points. */
{
region_list *curr;
int dp;
int previx;
int currix;
/* Record start point. */
dp = 0;
previx = 0;
dpts->pts[dp++] = pts->pts[previx];
for (curr = regions; curr != NULL; curr = curr->next)
if (curr->type != RGN_PLAIN) {
int max_v = 0;
int min_v = MAXINT;
int max_ix = -1;
int min_ix = -1;
int i;
for (i = curr->start; i <= curr->end; i++) {
int v = cas[i];
if (v > max_v) { max_v = v; max_ix = i; }
if (v < min_v) { min_v = v; min_ix = i; }
if (lidebug > 1)
fprintf(stderr, " %d\n", v);
}
currix = (curr->type == RGN_CONVEX ? max_ix : min_ix);
/* Record midpoint. */
dpts->pts[dp++] = pts->pts[previx + (currix - previx) / 2];
/* Record extreme point. */
dpts->pts[dp++] = pts->pts[currix];
previx = currix;
}
/* Record last mid-point and end point. */
currix = pts->npts - 1;
dpts->pts[dp++] = pts->pts[previx + (currix - previx) / 2];
dpts->pts[dp++] = pts->pts[currix];
}
/* Compute chain-code. */
lialg_compute_chain_code(dpts);
free(cas);
return(dpts);
}
static int *lialg_compute_contour_angle_set(point_list *pts,
region_list *regions) {
int *V = NULL;
region_list *curr_reg, *prev_reg;
int i;
/* V = (int *)safe_malloc(pts->npts * sizeof(int));*/
V = allocate(pts->npts, int);
V[0] = 18000;
for (curr_reg = regions; curr_reg != NULL;
prev_reg = curr_reg, curr_reg = curr_reg->next) {
for (i = curr_reg->start; i <= curr_reg->end; i++) {
if (curr_reg->type == RGN_PLAIN) {
V[i] = 18000;
}
else {
#ifdef notdef
/* XXX - eliminate floating point */
region_list *next_reg = curr_reg->next;
int b = curr_reg->start;
int h = prev_reg->start;
int t = next_reg->end;
int pts_before = i - h;
int pts_after = t - i;
int min_pts = (pts_before < pts_after)
? pts_before
: pts_after;
int k = (min_pts < T_ONE)
? T_ONE
: (min_pts > T_TWO)
? T_TWO
: min_pts;
float sum = 0.0;
for (j = 1; j <= k; j++) {
int ptA = i - j;
int ptB = i + j - 1;
int d_A = pts->pts[ptA].chaincode;
int d_B = pts->pts[ptB].chaincode;
int a_i;
if (d_A < d_B)
d_A += 8;
a_i = (d_A - d_B) % 8;
/* convert to radians */
if (a_i == 4 && curr_reg->type == RGN_CONVEX)
sum += M_2_PI;
else
sum += (float)((12 - a_i) % 8) / 4.0 * M_PI;
}
V[i] = sum / (float)k;
#else
/* For now, simply choose the mid-point. */
int isMidPt = (i == (curr_reg->start +
(curr_reg->end - curr_reg->start) / 2));
V[i] = (curr_reg->type == RGN_CONVEX)
? (isMidPt ? 18000 : 0)
: (isMidPt ? 0 : 18000);
#endif
}
}
}
V[pts->npts - 1] = 18000;
return(V);
}
/*
* First compute the similarity between the two strings.
* If it's above a threshold, compute the distance between
* the two and return it as the ``score.''
* Otherwise, return the constant WORST_SCORE.
*
*/
static void lialg_score_stroke(point_list *input_dompts, point_list *curr_dompts, int *sim, int *dist) {
*sim = MIN_SIM;
*dist = MAX_DIST;
*sim = lialg_compute_similarity(input_dompts, curr_dompts);
if (*sim < SIM_THLD) goto done;
*dist = lialg_compute_distance(input_dompts, curr_dompts);
done:
if (lidebug)
fprintf(stderr, "%d, %d\n", *sim, *dist);
}
static int lialg_compute_similarity(point_list *input_dompts,
point_list *curr_dompts) {
int sim = 0;
point_list *A, *B;
int N, M;
int **G = NULL;
int *junk = NULL;
int i, j;
/* A is the longer sequence, length N. */
/* B is the shorter sequence, length M. */
if (input_dompts->npts >= curr_dompts->npts) {
A = input_dompts;
N = input_dompts->npts;
B = curr_dompts;
M = curr_dompts->npts;
}
else {
A = curr_dompts;
N = curr_dompts->npts;
B = input_dompts;
M = input_dompts->npts;
}
/* Allocate and initialize the Gain matrix, G. */
/* The size of G is M x (N + 1). */
/* Note that row 0 is unused. */
/* Similarities are x 10. */
{
/* G = (int **)safe_malloc(M * sizeof(int *));*/
G = allocate(M, int *);
/* junk = (int *)safe_malloc(M * (N + 1) * sizeof(int)); */
junk = allocate(M * (N + 1), int);
for (i = 0; i < M; i++)
G[i] = junk + (i * (N + 1));
for (i = 1; i < M; i++) {
int bval = B->pts[i-1].chaincode;
/* Source column. */
G[i][0] = 0;
for (j = 1; j < N; j++) {
int aval = A->pts[j-1].chaincode;
int diff = abs(bval - aval);
if (diff > 4) diff = 8 - diff;
G[i][j] = (diff == 0)
? 10
: (diff == 1)
? 6
: 0;
}
/* Sink column. */
G[i][N] = 0;
}
}
/* Do the DP algorithm. */
/* Proceed in column order, from highest column to the lowest. */
/* Within each column, proceed from the highest row to the lowest. */
/* Skip the highest column. */
{
for (j = N - 1; j >= 0; j--)
for (i = M - 1; i > 0; i--) {
int max = G[i][j + 1];
if (i < (M - 1)) {
int tmp = G[i + 1][j + 1];
if (tmp > max) max = tmp;
}
G[i][j] += max;
}
sim = (10 * G[1][0] + (N - 1) / 2) / (N - 1);
}
if (G != NULL) free(G);
if (junk != NULL) free(junk);
return(sim);
}
static int lialg_compute_distance(point_list *input_dompts,
point_list *curr_dompts) {
int dist = MAX_DIST;
point_list *A, *B;
int N, M;
int **C = NULL;
int *junk = NULL;
int *BE = NULL;
int *TE = NULL;
int i, j;
/* A is the longer sequence, length N. */
/* B is the shorter sequence, length M. */
if (input_dompts->npts >= curr_dompts->npts) {
A = input_dompts;
N = input_dompts->npts;
B = curr_dompts;
M = curr_dompts->npts;
}
else {
A = curr_dompts;
N = curr_dompts->npts;
B = input_dompts;
M = input_dompts->npts;
}
/* Construct the helper vectors, BE and TE, which say for each column */
/* what are the ``bottom'' and ``top'' rows of interest. */
{
/* BE = (int *)safe_malloc((N + 1) * sizeof(int));*/
BE = allocate((N + 1), int);
/* TE = (int *)safe_malloc((N + 1) * sizeof(int)); */
TE = allocate((N + 1), int);
for (j = 1; j <= N; j++) {
int bot, top;
bot = j + (M - DP_BAND);
if (bot > M) bot = M;
BE[j] = bot;
top = j - (N - DP_BAND);
if (top < 1) top = 1;
TE[j] = top;
}
}
/* Allocate and initialize the Cost matrix, C. */
/* The size of C is (M + 1) x (N + 1). */
/* Note that row and column 0 are unused. */
/* Costs are x 100. */
{
/* C = (int **)safe_malloc((M + 1) * sizeof(int *)); */
C = allocate((M + 1), int *);
/* junk = (int *)safe_malloc((M + 1) * (N + 1) * sizeof(int)); */
junk = allocate((M + 1) * (N + 1), int);
for (i = 0; i <= M; i++)
C[i] = junk + (i * (N + 1));
for (i = 1; i <= M; i++) {
int bx = B->pts[i-1].x;
int by = B->pts[i-1].y;
for (j = 1; j <= N; j++) {
int ax = A->pts[j-1].x;
int ay = A->pts[j-1].y;
int dx = bx - ax;
int dy = by - ay;
int dist = isqrt(10000 * (dx * dx + dy * dy));
C[i][j] = dist;
}
}
}
/* Do the DP algorithm. */
/* Proceed in column order, from highest column to the lowest. */
/* Within each column, proceed from the highest row to the lowest. */
{
for (j = N; j > 0; j--)
for (i = M; i > 0; i--) {
int min = MAX_DIST;
if (i > BE[j] || i < TE[j] || (j == N && i == M))
continue;
if (j < N) {
if (i >= TE[j+1]) {
int tmp = C[i][j+1];
if (tmp < min) min = tmp;
}
if (i < M) {
int tmp = C[i+1][j+1];
if (tmp < min) min = tmp;
}
}
if (i < BE[j]) {
int tmp = C[i+1][j];
if (tmp < min) min = tmp;
}
C[i][j] += min;
}
dist = (C[1][1] + N / 2) / N;
}
if (C != NULL) free(C);
if (junk != NULL) free(junk);
if (BE != NULL) free(BE);
if (TE != NULL) free(TE);
return(dist);
}
/*************************************************************
Digest-processing routines
*************************************************************/
static int lialg_read_classifier_digest(rClassifier *rec) {
int nclasses;
FILE *fp = NULL;
/* Try to open the corresponding digest file. */
{
char *clx_path;
char *dot;
/* Get a copy of the filename, with some room on the end. */
/* clx_path = safe_malloc(strlen(rec->file_name) + 5); */
clx_path = allocate(strlen(rec->file_name) + 5, char);
strcpy(clx_path, rec->file_name);
/* Truncate the path after the last dot. */
dot = strrchr(clx_path, '.');
if (dot == NULL) { free(clx_path); return(-1); }
*(dot + 1) = 0;
/* Append the classifier-digest extension. */
strcat(clx_path, "clx");
fp = fopen(clx_path, "r");
if (fp == NULL) { free(clx_path); return(-1); }
free(clx_path);
}
/* Read-in the name and dominant points for each class. */
for (nclasses = 0; !feof(fp); nclasses++) {
point_list *dpts = NULL;
char class[BUFSIZ];
int npts;
int j;
if (fscanf(fp, "%s %d", class, &npts) != 2) {
if (feof(fp)) break;
goto failed;
}
rec->cnames[nclasses] = strdup(class);
/* Allocate a dominant-points list. */
/* dpts = (point_list *)safe_malloc(sizeof(point_list)); */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -