⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 li_recognizer.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
static int lialg_preprocess_stroke(point_list *);
static point_list *lialg_compute_dominant_points(point_list *);
static point_list *lialg_interpolate_points(point_list *);
static void lialg_bresline(pen_point *, pen_point *, point_list *, int *);
static void lialg_compute_chain_code(point_list *);
static void lialg_compute_unit_chain_code(point_list *);
static region_list *lialg_compute_regions(point_list *);
static point_list *lialg_compute_dompts(point_list *, region_list *);
static int *lialg_compute_contour_angle_set(point_list *, region_list *);
static void lialg_score_stroke(point_list *, point_list *, int *, int *);
static int lialg_compute_similarity(point_list *, point_list *);
static int lialg_compute_distance(point_list *, point_list *);

static int lialg_read_classifier_digest(rClassifier *);

static int lialg_canonicalize_examples(rClassifier *);
static int lialg_canonicalize_example_stroke(point_list *);
static int lialg_compute_equipoints(point_list *);

static int lialg_compute_pathlen(point_list *);
static int lialg_compute_pathlen_subset(point_list *, int, int);
static int lialg_filter_points(point_list *);
static int lialg_translate_points(point_list *, int, int, int, int);
static void lialg_get_bounding_box(point_list *, int *, int *, int *, int *);
static void lialg_compute_lpf_parameters();
static int isqrt(int);
static int likeatan(int, int);
static int quadr(int);


/*************************************************************

  Core routines for the Li/Yeung recognition algorithm

 *************************************************************/

static void lialg_initialize(rClassifier *rec) {
    int i;

    /* Initialize the dompts arrays. */
    for (i = 0; i < MAXSCLASSES; i++) {
	rec->dompts[i] = NULL;
    }
}


/*
 *  Main recognition routine -- called by HRE API.
 */
static char *lialg_recognize_stroke(rClassifier *rec, point_list *stroke) {
    int i;
    char *name = NULL;
    point_list *input_dompts = NULL;
    char *best_name = NULL;
    int best_score = WORST_SCORE;
    char *curr_name;
    point_list *curr_dompts = NULL;
    /*struct timeval stv, etv;
    int	elapsed;*/

    /*    (void)gettimeofday(&stv, NULL);*/

    if (stroke->npts < 1) goto done;

    /* Check for tap. */
    {
/*
	pen_point *startpt = &stroke->pts[0];
	pen_point *endpt = &stroke->pts[stroke->npts - 1];
	int dt = endpt->time - startpt->time;
	int dx = endpt->x - startpt->x;
	int dy = endpt->y - startpt->y;
	int magsq = dx * dx + dy * dy;
*/

	/* First thing is to filter out ``close points.'' */
	if (lialg_filter_points(stroke) != 0) return(NULL);

	/* Unfortunately, we don't have the actual time that each point */
	/* was recorded (i.e., dt is invalid).  Hence, we have to use a */
	/* heuristic based on total distance and the number of points. */
	if (stroke->npts == 1 || lialg_compute_pathlen(stroke) < TAP_PATHLEN)
	    return(TAP_CHAR);
    }

    /* Pre-process input stroke. */
    if (lialg_preprocess_stroke(stroke) != 0) goto done;

    /* Compute its dominant points. */
    input_dompts = lialg_compute_dominant_points(stroke);
    if (input_dompts == NULL) goto done;

    /* Score input stroke against every class in classifier. */
    for (i = 0, curr_name = rec->cnames[i], curr_dompts = rec->dompts[i];
	  i < MAXSCLASSES && curr_name != NULL && curr_dompts != NULL;
	  i++, curr_name = rec->cnames[i], curr_dompts = rec->dompts[i]) {
	int sim;
	int dist;
	int curr_score;

	lialg_score_stroke(input_dompts, curr_dompts, &sim, &dist);
	curr_score = dist;

	if (lidebug && curr_score < DIST_THLD)
	    fprintf(stderr, "(%s, %d, %d) ", curr_name, sim, dist);

	/* Is it the best so far? */
	if (curr_score < best_score && curr_score <= DIST_THLD) {
	    best_score = curr_score;
	    best_name = curr_name;
	}
    }

    if (lidebug)
	fprintf(stderr, "\n");

    /* No errors. */
    name = best_name;

done:
    delete_examples(input_dompts);
    /*    (void)gettimeofday(&etv, NULL);
	  elapsed = (1000 * (etv.tv_sec - stv.tv_sec)) + ((etv.tv_usec - stv.tv_usec + 500) / 1000);
	  fprintf(stderr, "elapsed = %d\n", elapsed);
     */
    return(name);
}


static int lialg_preprocess_stroke(point_list *points) {
    int minx, miny, maxx, maxy, xrange, yrange, scale, xoff, yoff;

    /* Filter out points that are too close. */
    /* We did this earlier, when we checked for a tap. */
/*
    if (lialg_filter_points(points) != 0) return(-1);
*/

/*    assert(points->npts > 0);*/

    /* Scale up to avoid conversion errors. */
    lialg_get_bounding_box(points, &minx, &miny, &maxx, &maxy);
    xrange = maxx - minx;
    yrange = maxy - miny;
    scale = ( ((100 * xrange + CANONICAL_X / 2) / CANONICAL_X) > 
	      ((100 * yrange + CANONICAL_Y / 2) / CANONICAL_Y))
      ? (100 * CANONICAL_X + xrange / 2) / xrange
      : (100 * CANONICAL_Y + yrange / 2) / yrange;
    if (lialg_translate_points(points, minx, miny, scale, scale) != 0)
	return(-1);

    /* Center the stroke. */
    lialg_get_bounding_box(points, &minx, &miny, &maxx, &maxy);
    xrange = maxx - minx;
    yrange = maxy - miny;
    xoff = -((CANONICAL_X - xrange + 1) / 2);
    yoff = -((CANONICAL_Y - yrange + 1) / 2);
    if (lialg_translate_points(points, xoff, yoff, 100, 100) != 0) return(-1);

    /* Store the x and y ranges in the point list. */
    xrange = maxx - minx;
    yrange = maxy - miny;
    points->xrange = xrange;
    points->yrange = yrange;

    if (lidebug) {
	int i;
	fprintf(stderr, "After pre-processing:   %d %d %d %d\n",
		minx, miny, maxx, maxy);
	for (i = 0; i < points->npts; i++)
	    fprintf(stderr, "      (%d %d)\n",
		    points->pts[i].x, points->pts[i].y);
	fflush(stderr);
    }

    return(0);
}


static point_list *lialg_compute_dominant_points(point_list *points) {
    point_list *ipts = NULL;
    region_list *regions = NULL;
    point_list *dpts = NULL;

    /* Interpolate points. */
    ipts = lialg_interpolate_points(points);
    if (ipts == NULL) return(NULL);
    if (lidebug) {
	int j;
	fprintf(stderr, "After interpolation:  %d ipts\n", ipts->npts);
	for (j = 0; j < ipts->npts; j++) {
	    fprintf(stderr, "  (%d, %d), %ld\n",
		    ipts->pts[j].x, ipts->pts[j].y, ipts->pts[j].chaincode);
	}
	fflush(stderr);
    }

    /* Compute regions. */
    regions = lialg_compute_regions(ipts);
/*    assert(regions != NULL);*/

    /* Compute dominant points. */
    dpts = lialg_compute_dompts(ipts, regions);
    if (lidebug) {
	int j;
	fprintf(stderr, "Dominant points:  ");
	for (j = 0; j < dpts->npts; j++) {
	    fprintf(stderr, "%d %d (%ld)  ",
		    dpts->pts[j].x, dpts->pts[j].y, dpts->pts[j].chaincode);
	}
	fprintf(stderr, "\n");
	fflush(stderr);
    }

    /* Delete region data structure. */
    {
	region_list *curr, *next;
	for (curr = regions; curr != NULL; ) {
	    next = curr->next;
	    free(curr);
	    curr = next;
	}
    }
    delete_examples(ipts);
    return(dpts);
}


/* Input points are assumed to be integer-valued! */
static point_list *lialg_interpolate_points(point_list *points) {
    int i, j;
    int maxpts;
    point_list *newpts;

    /* Compute an upper-bound on the number of interpolated points. */
    maxpts = 0;
    for (i = 0; i < (points->npts - 1); i++) {
	pen_point *pta = &(points->pts[i]);
	pen_point *ptb = &(points->pts[i+1]);
	maxpts += abs(pta->x - ptb->x) + abs(pta->y - ptb->y);
    }

    /* Allocate an array of the requisite size. */
    maxpts += points->npts;
    /* newpts = (point_list *)safe_malloc(sizeof(point_list)); */
    newpts = allocate(1, point_list);
    newpts->pts = make_pen_point_array(maxpts);
    if (newpts->pts == NULL) {
	free(newpts);
	return(NULL);
    }
    newpts->npts = maxpts;
    newpts->next = NULL;

    /* Interpolate each of the segments. */
    j = 0;
    for (i = 0; i < (points->npts - 1); i++) {
	pen_point *startpt = &(points->pts[i]);
	pen_point *endpt = &(points->pts[i+1]);

	lialg_bresline(startpt, endpt, newpts, &j);

	j--;	/* end point gets recorded as start point of next segment! */
    }

    /* Add-in last point. */
    newpts->pts[j++] = points->pts[points->npts - 1];
    newpts->npts = j;

    /* Compute the chain code for P (the list of points). */
    lialg_compute_unit_chain_code(newpts);

    return(newpts);
}


/* This implementation is due to Kenny Hoff. */
static void lialg_bresline(pen_point *startpt, pen_point *endpt,
			    point_list *newpts, int *j) {
    int Ax, Ay, Bx, By, dX, dY, Xincr, Yincr;

    Ax = startpt->x;
    Ay = startpt->y;
    Bx = endpt->x;
    By = endpt->y;

    /* INITIALIZE THE COMPONENTS OF THE ALGORITHM THAT ARE NOT AFFECTED */
    /* BY THE SLOPE OR DIRECTION OF THE	LINE */
    dX = abs(Bx-Ax);	/* store the change in X and Y of the line endpoints */
    dY = abs(By-Ay);

    /* DETERMINE "DIRECTIONS" TO INCREMENT X AND Y (REGARDLESS OF DECISION) */
    if (Ax > Bx) { Xincr=-1; } else { Xincr=1; }    /* which direction in X? */
    if (Ay > By) { Yincr=-1; } else { Yincr=1; }    /* which direction in Y? */

    /* DETERMINE INDEPENDENT VARIABLE (ONE THAT ALWAYS INCREMENTS BY 1 (OR -1) ) */
    /* AND INITIATE APPROPRIATE LINE DRAWING ROUTINE (BASED ON FIRST OCTANT */
    /* ALWAYS). THE X AND Y'S MAY BE FLIPPED IF Y IS THE INDEPENDENT VARIABLE. */
    if (dX >= dY) {	    /* if X is the independent variable */
	int dPr	= dY<<1;	    /* amount to increment decision if right is chosen (always) */
	int dPru = dPr - (dX<<1);   /* amount to increment decision if up is chosen */
	int P =	dPr - dX;	    /* decision variable start value */

	/* process each point in the line one at a time (just use dX) */
	for (; dX>=0; dX--) {
	    newpts->pts[*j].x = Ax;
	    newpts->pts[*j].y = Ay;
	    (*j)++;

	    if (P > 0) {	/* is the pixel	going right AND	up? */
		Ax+=Xincr;	/* increment independent variable */
		Ay+=Yincr;	/* increment dependent variable */
		P+=dPru;	/* increment decision (for up) */
	    }
	    else {		/* is the pixel just going right? */
		Ax+=Xincr;	/* increment independent variable */
		P+=dPr;		/* increment decision (for right) */
	    }
	}
    }
    else {		    /* if Y is the independent variable */
	int dPr	= dX<<1;	    /* amount to increment decision if right is chosen (always) */
	int dPru = dPr - (dY<<1);   /* amount to increment decision if up is chosen */
	int P  = dPr - dY;	    /* decision variable start value */

	/* process each point in the line one at a time (just use dY) */
	for (; dY>=0; dY--) {
	    newpts->pts[*j].x = Ax;
	    newpts->pts[*j].y = Ay;
	    (*j)++;

	    if (P > 0) {	/* is the pixel going up AND right? */
		Ax+=Xincr;	/* increment dependent variable */
		Ay+=Yincr;	/* increment independent variable */
		P+=dPru;	/* increment decision (for up) */
	    }
	    else {		/* is the pixel just going up? */
		Ay+=Yincr;	/* increment independent variable */
		P+=dPr;		/* increment decision (for right) */
	    }
	}
    }
}


static void lialg_compute_chain_code(point_list *pts) {
    int i;

    for (i = 0; i < (pts->npts - 1); i++) {
	pen_point *startpt = &(pts->pts[i]);
	pen_point *endpt = &(pts->pts[i+1]);
	int dx = endpt->x - startpt->x;
	int dy = endpt->y - startpt->y;
/*
	int tmp	= rint(4.0 * atan2((double)dx, (double)dy) / M_PI);
	int dircode = (10 + tmp) % 8;
*/
	int tmp = quadr(likeatan(dy, dx));
	int dircode = (12 - tmp) % 8;

	startpt->chaincode = dircode;
    }
}


static void lialg_compute_unit_chain_code(point_list *pts) {
    int i;

    for (i = 0; i < (pts->npts - 1); i++) {
	pen_point *startpt = &(pts->pts[i]);
	pen_point *endpt = &(pts->pts[i+1]);
	int dx = endpt->x - startpt->x;
	int dy = endpt->y - startpt->y;
	int dircode = lialg_dctbl[dx+1][dy+1];

/*	assert(dircode < 8);*/
	startpt->chaincode = dircode;
    }
}


static region_list *lialg_compute_regions(point_list *pts) {
    region_list *regions = NULL;
    region_list *curr_reg = NULL;
    int *R[2 + LP_FILTER_ITERS];
    int *junk;
    int *curr, *next;
    int i, j;

    /* Initialize low-pass filter parameters if necessary. */
    if (lialg_lpfconst == -1)
	lialg_compute_lpf_parameters();

    /* Allocate a 2 x pts->npts array for use in computing the (filtered) Angle set, A_n. */
    /*    junk = (int *)safe_malloc((2 + LP_FILTER_ITERS) * pts->npts * sizeof(int)); */
    junk = allocate((2 + LP_FILTER_ITERS) * pts->npts, int);
    for (i = 0; i < (2 + LP_FILTER_ITERS); i++)
	R[i] = junk + (i * pts->npts);
    curr = R[0];

    /* Compute the Angle set, A, in the first element of array R. */
    /* Values in R are in degrees, x 100. */
    curr[0] = 18000;				/* a_0 */
    for (i = 1; i < (pts->npts - 1); i++) {
	int d_i = pts->pts[i].chaincode;
	int d_iminusone = pts->pts[i-1].chaincode;
	int a_i;

	if (d_iminusone < d_i)
	    d_iminusone += 8;

	a_i = (d_iminusone - d_i) % 8;

	/* convert to degrees, x 100 */
	curr[i] = ((12 - a_i) % 8) * 45 * 100;
    }
    curr[pts->npts - 1]	= 18000;		/* a_L-1 */

    /* Perform a number of filtering iterations. */
    next = R[1];
    for (j = 0; j < LP_FILTER_ITERS; j++, curr = R[j], next = R[j+1]) {
	for (i = 0; i < pts->npts; i++) {
	    int k;

	    next[i] = 0;

	    for (k = i - LP_FILTER_WIDTH; k <= i + LP_FILTER_WIDTH; k++) {
		int oldval = (k < 0 || k >= pts->npts) ? 18000 : curr[k];
		next[i]	+= oldval * lialg_lpfwts[k - (i	- LP_FILTER_WIDTH)];	/* overflow? */
	    }

	    next[i] /= lialg_lpfconst;
	}
    }

    /* Do final thresholding around PI. */
    /* curr and next are set-up correctly at end of previous loop! */
    for (i = 0; i < pts->npts; i++) {
	next[i] = (abs(curr[i] - 18000) < LP_FILTER_THLD)
	  ? 18000
	  : curr[i];
    }
    curr = next;

    /* Debugging. */
    if (lidebug > 1) {
	for (i = 0; i < pts->npts; i++) {
	    fprintf(stderr, "%3d:  (%3d, %3d)  %ld  ",
		    i, pts->pts[i].x, pts->pts[i].y, pts->pts[i].chaincode);
	    for (j = 0; j < 2 + LP_FILTER_ITERS; j++)
		fprintf(stderr, "%d  ", R[j][i]);
	    fprintf(stderr, "\n");
	}
    }

    /* Do the region segmentation. */
    {
	int start, end;
	int currtype;

#define	RGN_TYPE(val)\
    (((val) == 18000)\
	? RGN_PLAIN\
	: ((val) < 18000 ? RGN_CONCAVE : RGN_CONVEX))

	start = 0;
	currtype = RGN_TYPE(curr[0]);
	/*	regions = (region_list *)safe_malloc(sizeof(region_list));*/
	regions = allocate(1, region_list);
	curr_reg = regions;
	curr_reg->start = start;
	curr_reg->end = 0;
	curr_reg->type = currtype;
	curr_reg->next = NULL;
	for (i = 1; i < pts->npts; i++) {
	    int nexttype = RGN_TYPE(curr[i]);

	    if (nexttype != currtype) {
		region_list *next_reg = NULL;

		end = i - 1;
		curr_reg->end = end;
		if (lidebug > 1)
		    fprintf(stderr, "  (%d, %d), %d\n", start, end, currtype);

		start = i;
		currtype = nexttype;
		/* next_reg = (region_list *)safe_malloc(sizeof(region_list));*/
		next_reg = allocate(1, region_list);
		next_reg->start = start;
		next_reg->end = 0;
		next_reg->type = nexttype;
		next_reg->next = NULL;

		curr_reg->next = next_reg;
		curr_reg = next_reg;
	    }
	}
	end = i - 1;
	curr_reg->end = end;
	if (lidebug > 1)
	    fprintf(stderr, "  (%d, %d), %d\n", start, end, currtype);

	/* Filter out convex/concave regions that are too short. */
	for (curr_reg = regions; curr_reg; curr_reg = curr_reg->next)
	    if (curr_reg->type == RGN_PLAIN) {
		region_list *next_reg;

		for (next_reg = curr_reg->next;
		     next_reg != NULL &&

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -