home *** CD-ROM | disk | FTP | other *** search
- /*
- * circ_geo.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /*
- * CIRC(le)_GEOM(etry)
- *
- * collection of routines to evaluate geometrical properties
- * of circular shapes
- */
-
- #include "xcc.h"
-
- #define SYMM 0
- #define ASYMM 1
- #define CCC_MODE ASYMM /* mode of center coord computation */
-
- /*
- * evaluate slope of linear segment
- */
- double
- slopev (struct spoint pt1, struct spoint pt2)
- {
- double m;
- double max_slope = 500.0; /* max. poss. slope */
- double r1, c1, r2, c2;
-
- r1 = (double) pt1.y;
- c1 = (double) pt1.x;
- r2 = (double) pt2.y;
- c2 = (double) pt2.x;
-
- if (F_TO_INT (r2 - r1) == 0) {
- if (F_TO_INT (c2 - c1) == 0)
- m = 0.0;
- else
- m = max_slope;
- }
- else
- m = (c2 - c1) / (r2 - r1);
-
- return (m);
- }
-
-
- /*
- * evaluate moments of order 0 (m00) and of order 1 (m10, m01)
- *
- * note: not very useful for evaluation of center coord, because disks
- * are not sampled ``symmetrically'': --> center pos biased
- */
- struct spoint
- eval_centroid (int *x, int *y, int n)
- {
- double xi, ximm, yi, yimm;
- double m00, m00_sum;
- double m10, m10_sum, m01, m01_sum;
- struct spoint ctr;
- int i;
-
- /*
- * compute moments
- * (reference: Hu, IRE Trans. Inf. Theory, IT-8, 179-187 (1962) )
- * (see also module pmom.c)
- */
- m00 = m10 = m01 = 0.0;
- for (i = 1; i < n; i++) {
- ximm = (double) (*(x + i - 1));
- xi = (double) (*(x + i));
- yimm = (double) (*(y + i - 1));
- yi = (double) (*(y + i));
-
- m00_sum = 0.5 * (yi * ximm - xi * yimm);
- m00 += m00_sum;
-
- m10_sum = 0.5 * (xi + ximm) * m00_sum;
- m10_sum -= 0.5 * ((yi - yimm) * (xi * xi + xi * ximm + ximm * ximm) / 6.0);
- m10 += m10_sum;
-
- m01_sum = 0.5 * (yi + yimm) * m00_sum;
- m01_sum += 0.5 * ((xi - ximm) * (yi * yi + yi * yimm + yimm * yimm) / 6.0);
- m01 += m01_sum;
- }
- ctr.y = (short) F_TO_INT (m10 / m00);
- ctr.x = (short) F_TO_INT (m01 / m00);
-
-
- #ifdef DBG_EVAL_CENTROID
- printf ("EVAL_CENTROID -- centroid of %3d-vertex polygon:", n);
- printf (" (%3d, %3d)\n", ctr.r, ctr.c);
- #endif
-
- return (ctr);
- }
-
-
-
- /*
- * estimate center coords of circular shape based on (horizontal)
- * disk chord and two line segments by constructing the intersection
- * of the respective perpendicular bisectors
- *
- * symmetric case (CCC_MODE = SYMM):
- * construct line segments connecting respective right and left end
- * points of disk chord and edge tuple;
- * asymmetric case (CCC_MODE = ASYMM):
- * construct line segment connecting respective left end points of
- * disk chord and edge tuple, as well as line segment connecting
- * left end point of disk chord with right end point of edge tuple
- * (preferred on basis of error analysis)
- */
- double
- pbi_ctr (int ir, struct edge_tuple *cetpl, struct triple *cdsk_lchrd)
- {
- struct spoint eL, eR;
- struct spoint cL, cR;
-
- double dcc;
- double ecL_r, ecR_r;
-
-
- /* initialize variables */
-
- cL.y = cR.y = cdsk_lchrd->r;
- cL.x = cdsk_lchrd->cl;
- cR.x = cdsk_lchrd->cr;
-
- eL.y = eR.y = ir;
- eL.x = cetpl->cl;
- eR.x = cetpl->cr;
-
- /* dcc = (double)cdsk->ctr.x; */
- dcc = 0.5 * (0.5 * (cL.x + cR.x) + 0.5 * (eL.x + eR.x));
-
-
- /* ctr r-coord derived from left edge points */
- ecL_r = 0.5 * (eL.y + cL.y) - (dcc - 0.5 * (eL.x + cL.x)) * slopev (cL, eL);
-
- /* ctr r-coord derived from right edge points */
- if (CCC_MODE == SYMM)
- ecR_r = 0.5 * (eR.y + cR.y) - (dcc - 0.5 * (eR.x + cR.x)) * slopev (cR, eR);
-
- /* ctr r-coord derived from right eTpl and left dChrd edge points */
- if (CCC_MODE == ASYMM)
- ecR_r = 0.5 * (eR.y + cL.y) - (dcc - 0.5 * (eR.x + cL.x)) * slopev (cL, eR);
-
- return (0.5 * (ecL_r + ecR_r));
- }
-
-
- /*
- * for future use (?) -- to be tested!!
- *
- * construct estimate of center coords on the basis of osculating circles
- * computed from successive triples of vertices
- *
- * for explicit formula, see e.g.:
- * ref: Pavlidis, ``Alg for Graphics and Img Proc'', sect 10, probl 10.11
- * Comp Sci Press, Rockville, Md, 1982
- */
- struct spoint
- eval_ctr (struct spoint *v, int n)
- {
- struct spoint ctr;
- struct spoint *pvmm, *pv, *pvpp;
-
- double dmr, dpr, dmc, dpc;
- double smr, spr, smc, spc;
- double c1, c2, d;
-
- double cr, scr, cc, scc;
- long nv;
- int i;
-
- scr = scc = 0.0;
- nv = 0;
- for (i = 0; i < n; i++) { /* form all triples of non-coll vertices */
- pv = &v[i];
- if (i == 0)
- pvmm = &v[n - 1];
- else
- pvmm = &v[i - 1];
- if (i == n - 1)
- pvpp = &v[0];
- else
- pvpp = &v[i + 1];
-
- dmr = pvmm->y - pv->y; /* x1-x2 */
- dmc = pvmm->x - pv->x; /* y1-y2 */
- dpr = pv->y - pvpp->y; /* x2-x3 */
- dpc = pv->x - pvpp->x; /* y2-y3 */
-
- if (fabs (d = (dmr * dpc - dpr * dmc)) < 0.000001) {
- d = 0.0;
- printf ("EVAL_CTR -- WARNING: vertices collinear\n");
- }
- else {
- smr = pvmm->y + pv->y; /* x1+x2 */
- smc = pvmm->x + pv->x; /* y1+y2 */
- spr = pv->y + pvpp->y; /* x2+x3 */
- spc = pv->x + pvpp->x; /* y2+y3 */
-
- c1 = dmr * smr + dmc * smc;
- c2 = dpr + spr + dpc * spc;
-
- /* evaluate sum of ctr coords, to be averaged */
- cr = 0.5 * (c1 * dpc - c2 * dmc) / d;
- scr += cr;
- cc = 0.5 * (c2 * dmr - c1 * dpr) / d;
- scc += cc;
- nv++;
-
- printf ("EVAL_CTR -- ");
- printf ("nv=%ld, cr=%lf, cc=%lf\n", nv, cr, cc);
- }
- }
- ctr.y = (short) F_TO_INT (scr / nv);
- ctr.x = (short) F_TO_INT (scc / nv);
-
-
- #ifdef DBG_EVAL_CTR
- printf ("EVAL_CTR -- center of circ, based on %3d-vertex polygon:", n);
- printf (" (%3d, %3d)\n", ctr.r, ctr.c);
- #endif
-
- return (ctr);
- }
-
-
- /*
- * find best circle to fit set of points {(x_i, y_i), 0<=i<n}
- * with center position given by centroid: compute radius of inertia
- *
- * ref: Pavlidis, ``Alg for Graphics and Img Proc'', sect 12.6.2, probl 12.5
- * Comp Sci Press, Rockville, Md, 1982
- */
- int
- oeval_rad (struct spoint *v, int n, struct disk *cdsk)
- {
- double sdrsq, sdcsq;
- double r_bar, c_bar;
- int i;
-
- r_bar = (double) cdsk->ctr.y;
- c_bar = (double) cdsk->ctr.x;
- sdrsq = sdcsq = 0.0;
- for (i = 0; i < n; i++) {
- sdrsq += SQR ((v + i)->y - r_bar);
- sdcsq += SQR ((v + i)->x - c_bar);
- }
-
- return (F_TO_INT (sqrt ((sdrsq + sdcsq) / n)));
- }
-
-
- /*
- * find best circle to fit set of points {(x_i, y_i), 0<=i<n}
- * with center position given by centroid: compute radius of inertia
- *
- * ref: Pavlidis, ``Alg for Graphics and Img Proc'', sect 12.6.2, probl 12.5
- * Comp Sci Press, Rockville, Md, 1982
- */
- int
- eval_rad (struct disk *cdsk)
- {
- struct spoint *v;
- double sdrsq, sdcsq;
- double r_bar, c_bar;
- int ich, nch;
- int iv, nv;
-
- nch = cdsk->nch;
- if ((v = (struct spoint *) calloc (2 * (nch + 1), sizeof (struct spoint))) == NULL) {
- printf ("\n...mem alloc for array of vertices v failed!!\n");
- return (0);
- }
-
- /*
- * extract vertex coords
- */
- for (ich = 0; ich < nch; ich++) {
- (v + ich)->y = (v + ((2 * nch - 1) - ich))->y = cdsk->chords[ich].r;
-
- (v + ich)->x = cdsk->chords[ich].cl;
- (v + ((2 * nch - 1) - ich))->x = cdsk->chords[ich].cr;
- }
-
-
- r_bar = (double) cdsk->ctr.y;
- c_bar = (double) cdsk->ctr.x;
- sdrsq = sdcsq = 0.0;
- nv = 2 * nch;
- for (iv = 0; iv < nv; iv++) {
- sdrsq += SQR ((v + iv)->y - r_bar);
- sdcsq += SQR ((v + iv)->x - c_bar);
- }
- free (v);
-
- return (F_TO_INT (sqrt ((sdrsq + sdcsq) / nv)));
- }
-
-
-
- /*
- * generate a new estimate of the best circle for the current set
- * of contour points: estimate the center in form of the centroid,
- * then compute a (suboptimal) value of the radius in form of the
- * radius of inertia
- */
- int
- oeval_circ (struct disk *cdsk)
- {
- struct spoint *v;
- int ich, nch;
-
- nch = cdsk->nch;
- if ((v = (struct spoint *) calloc (2 * (nch + 1), sizeof (struct spoint))) == NULL) {
- printf ("\n...mem alloc for array of vertices v failed!!\n");
- return (0);
- }
-
- /*
- * evaluate new centroid position and update entry in disk structure
- */
- for (ich = 0; ich < nch; ich++) {
- (v + ich)->y = (v + ((2 * nch - 1) - ich))->y = cdsk->chords[ich].r;
-
- (v + ich)->x = cdsk->chords[ich].cl;
- (v + ((2 * nch - 1) - ich))->x = cdsk->chords[ich].cr;
- }
-
- #ifdef DBG_EVAL_CTR
- printf ("EVAL_CIRC -- polygon vertex coords, {(r, c}\n");
- for (ich = 0; ich < 2 * nch; ich++)
- printf (" (%3d, %3d)\n", (v + ich)->y, (v + ich)->x);
- #endif
-
- cdsk->ctr = eval_ctr (v, 2 * nch);
- printf ("\n...new estimated center position: (%3d, %3d)\n",
- cdsk->ctr.y, cdsk->ctr.x);
-
- /*
- * estimate new radius
- */
- cdsk->rad = oeval_rad (v, 2 * nch, cdsk);
- printf ("...estimated radius: %d\n", cdsk->rad);
-
-
- free (v);
-
- return (1);
- }
-