home *** CD-ROM | disk | FTP | other *** search
- /*
- * cc.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /*
- * C(enter)C(ircular disks)
- *
- * functions required in determination of center positions of circular disks
- */
-
- #include "xcc.h"
-
- #define OFF 0
- #define ON 1
-
- #define NEW 1 /* flag to indicate init of new dsk */
- #define CUR 0
-
- #define LEFT -1
- #define RIGHT 1
-
- #define R_COMP 1 /* methods to estimate ctr r-coord */
- #define INTERS 2
- #define METHOD INTERS
-
- #define MAX_INDEX 255
-
- #define ID_OVLP_LM 0.1 /* cut-off for ``ideal'' circles */
- #define AP_OVLP_LM 3.0
- #define OVLP_LM AP_OVLP_LM
- #define SHIFT_LM OVLP_LM /* cut-off for rel segm pos (``shift'') */
-
-
- #undef DPRINT
- #undef DBG
- #undef SHOW_NEW_ADISK
- #undef DBG_ENC_ROW
- #undef DBG_OVLP
- #undef DBG_SYMM_OVLP
- #undef DBG_INSP
- #undef DBG_EVAL_CTR
-
- /* globals */
- extern int del_ir;
- extern float ddia;
-
-
-
- /*
- * initialize new disk structure (the structure itself already exists)
- */
- int
- init_disk (struct disk *ndsk, int nch)
- {
- int ich;
-
-
- if ((ndsk->chords = (struct triple *) calloc (nch + 1, sizeof (struct triple))) == NULL) {
- printf ("\n...mem alloc for *ndsk->chords failed!!\n");
- return (0);
- }
-
- /* initialize structure */
- ndsk->nch = 0;
- ndsk->ctr.y = ndsk->ctr.x = -1;
- ndsk->rad = -1;
- ndsk->Status = Active;
- ndsk->Type = Accept;
-
- for (ich = 0; ich < nch; ich++) {
- ndsk->chords[ich].r = -1;
- ndsk->chords[ich].cl = ndsk->chords[ich].cr = -1;
- }
- return (1);
- }
-
- /*
- * set current disk to InActive status
- */
- int
- close_disk (struct disk *cdsk)
- {
-
- if ((cdsk->Status == Active)) {
- cdsk->Status = InActive;
- return (1);
- }
- else {
- printf ("\nCLOSE_DISK: cur disk not Active\n");
- return (0);
- }
- }
-
-
-
- /*
- * set current disk to Reject type
- */
- int
- flag_disk (struct disk *cdsk)
- {
-
- if ((cdsk->Type == Accept)) {
- cdsk->Type = Reject;
- return (1);
- }
- else {
- printf ("\nFLAG_DISK: cur disk type not Accept\n");
- return (0);
- }
- }
-
-
- /*
- * fetch set of coefficients for 1d edge detector
- */
- void
- fetch_edge_det (float *ef, int nf)
- {
- }
-
-
-
- /*
- * apply edge detection filter to input array, y, via cyclic (1d)
- * convolution; return result in input array;
- */
- void
- edge_det (unsigned char *y, int n, float *f, int nf)
- {
- double *yy;
-
- /*
- * to be implemented
- */
- if ((yy = (double *) calloc (n, sizeof (double))) == NULL) {
- printf ("\n...mem alloc for array yy of type double failed");
- exit (1);
- }
-
- free (yy);
- }
-
-
- /*
- * given symmetric overlap between the current edge tuple and the last
- * chord in the array of chords associated with the Active disk currently
- * under inspection, determine whether to add cetpl to cdsk:
- * given cetpl and disk_dia, compute center positions for the two circles
- * of which cetpl may form a chord (one center position lying above, the
- * other below the current row); compare the estimate(s) so derived with
- * those computed in the same way for cdsk_ldchrd (in the case that
- * cdsk only contains that one chord) or with the center coordinates
- * currently stored in cdsk; test the separation between row-coordinates
- * (the column coordinate passes trivially, given the condition of symmetric
- * overlap !!), to make a decision about acceptance of cetpl into cdsk;
- *
- * in comparing row coordinates of potential center positions, take
- * advantage of simple geometrical facts, given that cetpl follows
- * cdsk_lchrd in the raster scan; thus if (cre-cle) >= (crc-clc), cetpl and
- * cdsk_lchrd can only be part of the same circle if that circle's center
- * r-coordinate exceeds rc; hence, only ruc need be inspected; the analogous
- * conclusion holds if (cre-cle) <= (crc-clc): cetpl and cdsk_lchrd can
- * only be part of the same circle if the center r-coordinate is smaller
- * than re; hence, only rle need be inspected;
- */
- Boolean
- insp_Adsk (int ir, struct edge_tuple *cetpl, struct disk *cdsk)
- {
- struct triple *cdsk_lchrd;
-
- double rue, rle;
- double rc, ruc, rlc;
- double del_ce, del_cc;
- double dcr, ec_r;
- double min_r_dist;
-
- Boolean AccRejStat;
-
-
- /* initialize variables */
-
- cdsk_lchrd = &cdsk->chords[(cdsk->nch) - 1];
-
- del_ce = (double) (cetpl->cr - cetpl->cl);
- del_cc = (double) (cdsk_lchrd->cr - cdsk_lchrd->cl);
-
-
- #ifdef DBG_INSP
- printf ("INSP_ADSK -- estimate ctr r-coord: METHOD %d\n", METHOD);
- #endif
-
- /*
- * estimate coordinates of circle center, based on those already stored in
- * cdsk and the vertex coords of cetpl; the column coord is trivially found
- * based on symmetry, the r-coord requires more effort;
- *
- * two methods are employed, depending on whether cdsk contains
- * only a single chord or several (more than one) chord
- *
- * Method 1:
- * ---------
- * compare the four possible center r-coords, a pair each derived from
- * the disk chord and from cetpl, relying on the initial estimate, disk_dia
- * of the disk size; this is robust only in the absence of contour noise
- * Method 2:
- * ---------
- * construct the normal to each of the line segments {(re, cle), (rc, clc)}
- * and {(re, cre), (rc, crc)} and find the r-coords of their intersection
- * point(s) with the line d(isk)c(center)c == 0.5(clc+crc)=const (which
- * contains the disk center); given dcc, the desired r-coords are readily
- * found by evaluating pertinent slopes;
- */
-
- switch (METHOD) {
- case 1:
- rue = (double) ir + 0.5 * sqrt (SQR (ddia) - SQR (del_ce));
- rle = (double) ir - 0.5 * sqrt (SQR (ddia) - SQR (del_ce));
-
- if (cdsk->nch == 1) {
- rc = (double) cdsk->chords[(cdsk->nch) - 1].r;
- ruc = rc + 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
- rlc = rc - 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
-
- if ((del_ce - del_cc) >= SHIFT_LM) { /* etpl > chord */
- if (MIN (fabs (rue - ruc), fabs (rle - ruc)) < del_ir)
- AccRejStat = Pass;
- else
- AccRejStat = Fail;
- }
- if ((del_cc - del_ce) >= SHIFT_LM) { /* chord > etpl */
- if ((min_r_dist = MIN (fabs (ruc - rle), fabs (rlc - rle))) < del_ir)
- AccRejStat = Pass;
- else
- AccRejStat = Fail;
- }
- }
- else {
- dcr = (double) cdsk->ctr.y;
-
- if ((min_r_dist = MIN (fabs (rue - dcr), fabs (rle - dcr))) < del_ir)
- AccRejStat = Pass;
- else
- AccRejStat = Fail;
- }
-
- #ifdef DBG_INSP
- if (cdsk->nch == 1) {
- printf (" ctr r-coord derived from chrd, ddia:\n");
- printf (" ruc=%lf, rlc=%lf\n", ruc, rlc);
- }
- else {
- printf (" ctr r-coord derived from etpl, ddia:\n");
- printf (" rue=%lf, rle=%lf\n", rue, rle);
- }
- printf ("-->min r-dist to estim center: %lf\n", min_r_dist);
- #endif
- break;
-
- case 2:
-
- ec_r = pbi_ctr (ir, cetpl, cdsk_lchrd); /* est ctr r-coord */
-
- if (cdsk->nch == 1) {
- rc = (double) cdsk->chords[(cdsk->nch) - 1].r;
- ruc = rc + 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
- rlc = rc - 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
-
- if ((min_r_dist = MIN (fabs (ruc - ec_r), fabs (rlc - ec_r))) < del_ir)
- AccRejStat = Pass;
- else
- AccRejStat = Fail;
- }
- else {
- dcr = (double) cdsk->ctr.y;
-
- if ((min_r_dist = fabs (dcr - ec_r)) < del_ir)
- AccRejStat = Pass;
- else
- AccRejStat = Fail;
- }
-
- #ifdef DBG_INSP
- if (cdsk->nch == 1) {
- printf (" ctr r-coord derived from chrd, ddia:\n");
- printf (" ruc=%lf, rlc=%lf\n", ruc, rlc);
- }
- else {
- printf (" cdsk cur ctr r-coord: dcr=%lf,\n", dcr);
- }
- printf (" ctr r-coord from inters of perp bis: ");
- printf (" ec_r=%lf\n", ec_r);
- printf ("-->min r-dist to estim center: %lf\n", min_r_dist);
- #endif
- break;
- }
- return (AccRejStat);
- }
-
-
- /*
- * find latest entry in chord array of current disk
- */
- int
- find_cdsk_lchrd (int ir, struct disk *cdsk)
- {
- int chrd_row;
-
-
- if (cdsk->nch == 0) {
- printf (" current disk structure empty\n");
- return (-1);
- }
- else if (((chrd_row = cdsk->chords[cdsk->nch - 1].r) != ir - del_ir) &&
- (chrd_row != ir)) {
- #ifdef DPRINT
- printf ("FIND_CDSK_LCHRD -- WARNING: ");
- printf ("--> row %3d out of order -- disk chord index: %3d\n",
- chrd_row, cdsk->nch - 1);
- #endif
- return (-1);
- }
- else {
- return (cdsk->nch - 1); /* return index of last filled chrd */
- }
- }
-
-
- /*
- * find all Active disks currently listed in dll:
- *
- * proceeding from list tail, reset dll list pointer to the position of
- * the ``oldest'' remaining Active disk which, by construction, is the
- * disk most distant from the tail of the list; an efficient way to
- * find the desired position entails ''rewinding'' the current list pointer
- * until either
- * -->the first InActive disk is encountered:
- * set AdskStatus to Fail, advance list pointer to point to Active disk
- *
- * or
- * -->the head of dll is reached (without encountering any InActive disk):
- * AdskStatus remains True, list pointer points to Active disk
- */
- struct linktype *
- find_all_Adsks (struct linklist *dll)
- {
- struct disk *cdsk;
- int nad, ndll;
- Boolean DllStatus;
- Boolean AdskStatus;
-
- lltail (dll);
- if ((ndll = ll_length (dll)) == 0)
- return (dll->clp);
-
- #ifdef DPRINT
- printf ("\nFIND_ALL_ADSKS -- rewind dll\n");
- #endif
- nad = 0;
- DllStatus = AdskStatus = True;
- do {
- if ((cdsk = (struct disk *) dll->clp->item)->Status == Active) {
- #ifdef DPRINT
- printf (" %d ", ++nad);
- #endif
- DllStatus = llprevious (dll);
- }
- else
- AdskStatus = False;
-
- } while ((DllStatus == True) && (AdskStatus == True));
- if (AdskStatus == False)
- llnext (dll);
-
- #ifdef DPRINT
- printf ("\n...rewinding dll (AdskStatus: %d)", AdskStatus);
- printf (" -->identified %d Active disks\n", nad);
- #endif
-
- return (dll->clp);
- }
-
-
- /*
- * find next disk in dll with Active status
- */
- struct linktype *
- find_next_Adsk (struct linklist *dll)
- {
- struct disk *cdsk;
-
- while (llnext (dll) == True) {
- if ((cdsk = (struct disk *) dll->clp->item)->Status == Active)
- return (dll->clp);
-
- }
-
- return ((struct linktype *) NULL);
- }
-
-
- /*
- * add new disk structure to tail of dll, reset list pointer to original pos
- */
- void
- app_ndsk_to_dll (char *ndsk, struct linklist *dll)
- {
- struct linktype *adlp;
-
- adlp = dll->clp;
- lltail (dll);
- lladd ((char *) ndsk, dll);
- dll->clp = adlp;
- }
-
-
- /*
- * insert new disk structure into dll so as to retain the list of Active
- * disks in the order of increasing etpl column coordinates; reset list
- * pointer to original pos
- */
- void
- ins_ndsk_to_dll (char *ndsk, struct linklist *dll, int shift)
- {
- struct linktype *adlp;
-
- adlp = dll->clp;
- if (shift == LEFT)
- lladdprev ((char *) ndsk, dll);
- if (shift == RIGHT)
- lladd ((char *) ndsk, dll);
- dll->clp = adlp;
- }
-
-
-
-
- /*
- * add new chord, converted from edge tuple, to disks's array of chords;
- * the disk may be a currently Active disk already containing chords or
- * a newly initialized disk
- */
- Boolean
- chord_to_Adsk (int ir, int nch, struct edge_tuple *cetpl, struct disk *cdsk, int disk_type, int ncch)
- {
- struct triple *cdsk_lchrd;
-
- int memalloc;
- int cl, cr;
- int cctr_r, nctr_r;
-
- if (disk_type == NEW) { /* init new disk */
- if ((memalloc = init_disk (cdsk, nch)) == 0) {
- #ifdef DPRINT
- printf ("\nCHORD_TO_DISK -- disk init failed\n");
- #endif
- return (Fail);
- }
- }
- else { /* posit chord array ptr of cur dsk */
- if (cdsk->Status != Active) {
- printf ("\nCHORD_TO_ADISK -- cur disk must be Active\n");
- return (Fail);
- }
- }
-
- /* store etpl in cdsk */
-
- cdsk->chords[ncch].r = ir;
- cdsk->chords[ncch].cl = cetpl->cl;
- cdsk->chords[ncch].cr = cetpl->cr;
- cdsk->nch++;
-
-
- /*
- * update circle center pos and radius
- */
- if (cdsk->nch == 1) { /* first estim of cntr pos and rad */
- cl = cdsk->chords[cdsk->nch - 1].cl;
- cr = cdsk->chords[cdsk->nch - 1].cr;
-
- cdsk->ctr.y = (short) (ir + 0.5 * sqrt (SQR (ddia) - SQR (cr - cl)));
- cdsk->ctr.x = (cetpl->cl + cetpl->cr) / 2;
- cdsk->rad = F_TO_INT (0.5 * ddia);
- }
- else {
- cdsk_lchrd = &cdsk->chords[(cdsk->nch) - 2];
- nctr_r = F_TO_INT (pbi_ctr (ir, cetpl, cdsk_lchrd));
- if (cdsk->nch == 2)
- cdsk->ctr.y = nctr_r;
- else {
- cctr_r = cdsk->ctr.y;
- #ifdef DPRINT
- printf ("\n...cctr_r: %d, nctr_r: %d\n", cctr_r, nctr_r);
- #endif
- cdsk->ctr.y = ((cdsk->nch - 1) * cctr_r + nctr_r) / cdsk->nch;
- }
- cdsk->rad = eval_rad (cdsk);
- #ifdef DPRINT
- printf ("\n...ctr y_coord just stored in cdsk: %3d\n", cdsk->ctr.y);
- printf ("...estimated radius: %d\n", cdsk->rad);
- #endif
- }
-
-
- #ifdef SHOW_NEW_ADISK
- printf ("\nCHORD_TO_ADISK: ");
- if (disk_type == NEW)
- printf ("initialize new Active disk\n");
- else
- printf ("update existing Active disk\n");
- printf (" nof chords in curr Active disk: %d\n", cdsk->nch);
- printf (" last (%d-th) chord: [%3d; %3d %3d]\n", ncch,
- cdsk->chords[cdsk->nch - 1].r,
- cdsk->chords[cdsk->nch - 1].cl,
- cdsk->chords[cdsk->nch - 1].cr);
- #endif
-
- return (Pass);
- }
-
-
-
- /*
- * determine relative displacement (along rows) of segments with partial
- * or vanishing overlap (see find_segm_ovlp())
- *
- * LEFT/RIGHT: etpl left/right-shifted w/r chord
- */
- int
- find_segm_shift (struct triple *chrd, struct edge_tuple *cetpl)
- {
-
- if (chrd->cl >= cetpl->cr)
- return (LEFT);
- if (cetpl->cl >= chrd->cr)
- return (RIGHT);
-
- }
-
-
- /*
- * given two segments, one disk chord, one edge tuple on successive
- * scan lines, establish their mode of overlap: the ovlp flag serves
- * to distinguish three cases:
- *
- * -- ovlp = 0: if no overlap exists, the disk containing the current chord
- * is set Inactive; however, a new disk to hold the current edge
- * tuple is not yet called for: the edge tuple may still belong
- * to another Active disk which would, however, have to lie
- * between the current chord and the edge tuple;
- *
- * -- ovlp =-1: finite partial overlap obtains, so that
- *
- * yO_et < yO_dc < yF_et < yF_dc,
- * or
- * yO_dc < yO_et < yF_dc < yF_et;
- *
- * in either case, a new disk must be inserted into dll to
- * hold the current edge tuple as a chord; the disk containing
- * the current disk chord is closed (given Inactive status);
- * finite overlap obtains if the following two inequalities hold:
- *
- * yO_et < yF_dc and yO_dc < yF_et,
- *
- * or vice versa; otherwise, there is no overlap: -->case 0;
- * complete overlap is ensured if, in addition to the previous
- * inequality, yF_dc < yF_et, or vice versa
- *
- * -- ovlp = 1: only if one segment symmetrically encloses the other, that is,
- * if, given complete overlap, one has in addition,
- *
- * abs( yO_dc - yO_et ) = abs( yF_et - yF_dc )
- *
- * or, alternatively,
- *
- * (yO_dc + yF_dc)/2 = (yO_et + yF_et)/2
- *
- * does the edge_tuple qualify for further consideration as an
- * additional disk chord;
- */
- int
- find_segm_ovlp (struct triple *chrd, struct edge_tuple *cetpl)
- {
- int ovlp = 77;
- int yOe, yFe, yOc, yFc;
-
- yOc = (int) chrd->cl;
- yFc = (int) chrd->cr;
- yOe = (int) cetpl->cl;
- yFe = (int) cetpl->cr;
-
- #ifdef DBG_OVLP
- printf ("FIND_SEGM_OVLP: ");
- #endif
- if ((yOe < yFc) && (yOc < yFe)) { /* partial ovlp */
- if ((yOe <= yOc) && (yFc <= yFe)) { /* etpl encl chrd */
- if (fabs ((yOc + yFc) - (yOe + yFe)) < OVLP_LM)
- ovlp = 1;
- }
- else if ((yOc <= yOe) && (yFe <= yFc)) { /* chrd encl etpl */
- if (fabs ((yOc + yFc) - (yOe + yFe)) < OVLP_LM)
- ovlp = 1;
- }
- else
- ovlp = -1; /* finite partial ovlp */
-
- }
- else /* no ovlp */
- ovlp = 0;
-
- #ifdef DBG_OVLP
- printf (" %d\n", ovlp);
- #endif
-
- return (ovlp);
- }
-
-
-
- /*
- * process current edge tuple list, generated in last row scan,
- * by assigning edge tuples to disk structures, either to currently
- * Active (Incomplete) or to new disks, to be added to disk list;
- * Active disks to which no new edge tuple is assigned are given
- * Inactive (Complete) status
- */
- int
- update_disk_list (int ir, int nch, struct linklist *dll, struct linklist *etll)
- {
- struct linktype *adlp; /* ptr to first Act disk in dll */
- struct linktype *sadlp; /* ptr to save init val of adlp */
- struct linktype *stdlp; /* ptr to save init val of dll->tail */
- struct disk *cdsk; /* pointer to disk at cur dll posit */
- struct disk new_disk, *ndsk = &new_disk;
-
- struct edge_tuple *cetpl;
-
-
- int nnad; /* nof Act disks added to dll */
- int ncd; /* nof Act disks closed in cur pass */
- int nfd; /* nof Act disks set to type Reject */
- int etll_to_dll = OFF;
-
- int ovlp;
- //int shift; /* used with ins_ndsk_to_dll() */
- int ncch; /* ind of last filled chrd in cdsk */
- Boolean AccRejStat; /* test status (Pass/Fail) of etpl */
-
- /*
- * scan (col-ordered) edge_tuple list, etll, and update the array of chords
- * associated with each disk: this may require inserting new disk structures
- * into dll, as well as updating disk structures already present in the list
- *
- * the emerging list contains disk structures in the order of their
- * acquiring Active (Open) status: a new disk, with Active status, is
- * added to dll, whenever an edge tuple on the current scan line does not
- * satisfy the overlap conditions which would identify it as a chord of one
- * of the already Active disks; the edge tuple under consideration is entered
- * as a chord of a new disk structure which is in turn inserted into dll;
- * any disk which is not intersected by the current scan line (and thus
- * acquires no new chord) is given InActive status;
- *
- * two modes of insertion with different advantages may be considered:
- * -- insert new disk at at the end (tail) of dll --> app_ndsk_to_dll();
- * dll is doubly sorted: primary key is the row-coord of its first chord,
- * secondary key is the col-coord of chords on the same row; this has the
- * advantage of maintaining Active disks in a contiguous sequence at the
- * end of dll and thus makes it easy to locate all Active disks
- * -- insert new disk in according to results of comparing ovlp and shift
- * (--> find_segm_shift()) of cdsk_lchrd and etpl --> ins_ndsk_to_dll();
- * dll is sorted according to the col-coord of its first chord; this has
- * the advantage of requiring only local operations of ovlp and segm
- * evaluations when examining a new etpl: only the c-adjacent disks need
- * be inspected; however, it has the disadvantage of fragmenting the
- * Active portion of dll
- * -->possible room for speed-ups at a later stage of development
- */
- #ifdef DPRINT
- printf ("\n\nUPDATE_DISKLIST -- process new etll\n");
- #endif
- if (ll_length (etll) == 0) {
- #ifdef DPRINT
- printf ("\nUPDATE_DISK_LIST -- edge_tuple list empty\n");
- printf (" -->no update of disk list required\n");
- #endif
-
- return (0);
- }
-
- /*
- * etll not empty: update disk list; find all Incomplete (Active) disks
- * by resetting dll to last Active disk, i.e. the Active disk farthest
- * from the tail of dll
- */
- sadlp = dll->head;
- stdlp = dll->tail;
- if ((adlp = find_all_Adsks (dll)) == stdlp) {
- if (ll_length (dll) == 0) {
- #ifdef DPRINT
- printf ("\n...currently no Active disks in dll\n");
- printf (" -->cp all chords in etll into Act disk in dll\n");
-
- #endif
- etll_to_dll = ON; /* copy etll to dll */
- }
- }
-
-
- llhead (etll);
- cetpl = (struct edge_tuple *) etll->clp->item;
- sadlp = adlp;
- nnad = 0;
- do { /* scan etll */
- /* process segm with matched status */
- #ifdef DPRINT
- printf ("\nUPDATE_DISK_LIST -- process new etpl\n");
- #endif
- cetpl = (struct edge_tuple *) etll->clp->item;
- if (cetpl->status != Matched)
- return (0);
-
- if (etll_to_dll == ON) { /* enter cur etpl into dll */
- AccRejStat = chord_to_Adsk (ir, nch, cetpl, ndsk, NEW, 0);
-
- app_ndsk_to_dll ((char *) ndsk, dll);
- nnad++;
- }
-
- /*
- * advance dll->clp by one to point to first Active disk in dll
- * (note: mem alloc for an Active disk has already been performed, see above!)
- *
- * determine ovlp between etpl and disk chord (see function find_segm_ovlp());
- * also examine the relative positioning of etpl and chrd: this serves to
- * insert new disks into dll in increasing order of segment column coords
- *
- * etpl l-shifted w/r chrd, i.e. etpl precedes chrd:
- * open new disk struct preceding cdsk to hold current tuple
- * maintain cdsk Active
- * etpl r-shifted w/r chrd, i.e., chrd precedes etpl:
- * set cdsk InActive
- * retain current etpl and check ovlp with next Adsk in dll
- */
- else { /* check overlap betw cur etpl, dsk chords */
- dll->clp = sadlp;
- AccRejStat = Fail;
- do { /* scan Adsks in dll */
- adlp = dll->clp;
- cdsk = (struct disk *) adlp->item;
- if ((ncch = find_cdsk_lchrd (ir, cdsk)) == -1) {
- #ifdef DPRINT
- printf ("\nUPDATE_DISK_LIST -- ");
- printf (" WARNING: row coords of last disk chord incorrect\n");
- printf (" ir: %3d, del_ir: %3d\n", ir, del_ir);
- /* PROC ERR: halt execution!! */
- #endif
- }
-
- ovlp = find_segm_ovlp (&(cdsk->chords[cdsk->nch - 1]), cetpl);
- if (ovlp == 1) { /* symmetric */
- if ((AccRejStat = insp_Adsk (ir, cetpl, cdsk)) == Pass) {
- chord_to_Adsk (ir, nch, cetpl, cdsk, CUR, ncch + 1);
- }
- else {
- /* PROC ERR */
- AccRejStat = chord_to_Adsk (ir, nch, cetpl, ndsk, NEW, 0);
- app_ndsk_to_dll ((char *) ndsk, dll);
- nnad++;
-
- }
- }
-
- } while ((AccRejStat == Fail) && (llnext (dll) == True));
-
- /* reached tail of dll without inserting etpl */
- if (AccRejStat == Fail) {
- #ifdef DPRINT
- printf ("\nUPDATE_DISK_LIST -- ");
- printf (" append new disk to dll\n");
- #endif
- AccRejStat = chord_to_Adsk (ir, nch, cetpl, ndsk, NEW, 0);
- app_ndsk_to_dll ((char *) ndsk, dll);
- nnad++;
- }
- }
- } while (llnext (etll) == True);
-
-
- /*
- * etll exhausted: inspect all Active disks which were present in dll prior
- * to processing the current etll, that is those between positions pointed
- * to by sadlp and stdlp; disks which were not updated in the current pass
- * (by receiving an etll segment as a new chord) must be closed
- */
- #ifdef DPRINT
- printf ("\nUPDATE_DISK_LIST -- etll (row %3d) exhausted\n", ir);
- #endif
- dll->clp = sadlp;
- ncd = nfd = 0;
- if (etll_to_dll == ON)
- return (nnad);
-
- do {
- if ((cdsk = (struct disk *) dll->clp->item)->Status == Active) {
- if (cdsk->nch == nch) { /* max nof chords attained */
- ncd += close_disk (cdsk);
- }
- else {
- if ((ncch = find_cdsk_lchrd (ir + del_ir, cdsk)) == -1) {
- ncd += close_disk (cdsk);
-
- /*
- * additional Type-checking may be performed here to Reject disks
- *
- * example:
- * -- segments of disks clipped by left or right edges all have identical
- * cl or cr coordinates which may be used to discriminate
- */
-
- /*
- * note: counting segments is not a robust criterion to identify clipped
- * disks in the presence of size variations
- *
- * if( cdsk->nch < nch-1 )
- * nfd += flag_disk(cdsk);
- */
-
- }
- }
- }
- } while (llnext (dll) == True);
- #ifdef DPRINT
- printf ("...closed %d disk(s), flagged %d disks\n", ncd, nfd);
- #endif
-
- return (nnad);
- }
-
- /*
- * determine and set status (Matched/UnMatched) currently last entry
- * in edge tuple list
- */
- Boolean
- ReptSegmStatus (struct edge_tuple * letpl, int pix)
- {
- Boolean Segm_Status;
-
-
- Segm_Status = letpl->status;
- switch (pix) {
- case OFF: /* OFF->ON: last tuple Matched? */
-
- if (Segm_Status == UnMatched) {
- #ifdef DPRINT
- printf ("\n...OFF->ON: last entry in etll UnMatched:");
-
- if (letpl->cr == -1)
- printf ("...cr invalid\n");
- else
- printf ("...unknown origin\n");
- #endif
- }
- else if (Segm_Status == Matched) { /* OK */
- }
- else {
- Segm_Status = UnKnown;
- #ifdef DPRINT
- printf ("\n...OFF->ON: segm status UnKnown\n");
- #endif
- }
- break;
-
- case ON: /* ON->OFF: last tuple UnMatched */
-
- if (Segm_Status == Matched) {
- #ifdef DPRINT
- printf ("\n...ON->OFF: last entry in etll already Matched: cr = %3d\n",
- (int) letpl->cr);
- #endif
- }
- else if (Segm_Status == UnMatched) { /* OK */
- }
- else {
- Segm_Status = UnKnown;
- #ifdef DPRINT
- printf ("\n...ON->OFF: segm status UnKnown\n");
- #endif
- }
- break;
- }
- return (Segm_Status);
- }
-
-
- /*
- * given a row extracted from the original image (GRAY_LEV = BNRY), or
- * an extracted row which has been subjected to 1d edge detection,
- * locate edge points and place successive edge points into tuples
- * (cl: OFF->ON transition, cr: ON->OFF transition); each such edge tuple
- * gives the y-coordinates delimiting ON-segments (``runs''); the status
- * of a segment is Matched if the pair {cl, cr} marks successive OFF->ON,
- * ON->OFF transitions in image intensity; otherwise, the segment status is
- * UnMatched; edge tuples are entered into a y-ordered edge tuple list;
- */
- int
- encode_row (unsigned char *row, int nc, struct linklist *etll, int gray_lev)
- {
- int jc;
- int pix;
- struct edge_tuple cur_etpl, *cetpl = &cur_etpl;
- Boolean Etpl_Status;
-
-
- if (gray_lev == 0) { /* binary input row */
-
- lltail (etll);
- Etpl_Status = Matched;
- cetpl->cl = cetpl->cr = -1;
- cetpl->status = UnMatched;
- pix = OFF;
-
- jc = 0;
- while (jc < nc) {
- if (*(row + jc) / MAX_INDEX == pix)
- jc++;
-
- else {
-
- switch (pix) {
-
- case OFF: /* handle OFF->ON transition */
-
- /* initialize new ON-segm */
- cetpl->cl = jc + 1;
- cetpl->cr = -1;
- cetpl->status = UnMatched;
-
- #ifdef DPRINT
- printf ("...jc=%3d: edge tup [%3d %3d] init",
- jc, cetpl->cl, cetpl->cr);
- #endif
-
- /* enter new tuple into edge_tuple_list */
- lltail (etll);
-
- /* status of last ON-segm Matched? */
- if (ll_length (etll) > 0) {
- Etpl_Status = ReptSegmStatus ((struct edge_tuple *) etll->clp->item, pix);
- #ifdef DPRINT
- if (Etpl_Status != Matched)
- printf ("\nWARNING: prev ON-segm not Matched\n");
- #endif
- }
- lladd ((char *) cetpl, etll);
- #ifdef DPRINT
- printf ("...entered into etll");
- printf (" -->cur list len: %d\n", ll_length (etll));
- #endif
-
- pix = ON;
- break;
-
- case ON: /* handle ON->OFF transition */
-
- /* complete current ON-segm */
- lltail (etll);
-
- /* status of last ON-segm UnMatched? */
- if (ll_length (etll) > 0) {
- Etpl_Status = ReptSegmStatus ((struct edge_tuple *) etll->clp->item, pix);
- if (Etpl_Status != UnMatched)
- printf ("\nWARNING: prev ON-segm not UnMatched\n");
- }
- ((struct edge_tuple *) etll->clp->item)->cr = jc;
- ((struct edge_tuple *) etll->clp->item)->status = Matched;
-
- #ifdef DPRINT
- printf ("...jc=%3d: edge tup [%3d %3d] compl", jc, ((struct edge_tuple *) etll->clp->item)->cl,
- ((struct edge_tuple *) etll->clp->item)->cr);
-
- printf (" -->cur list len: %d\n", ll_length (etll));
- #endif
-
- pix = OFF;
- break;
- }
- }
- }
- }
- else if (gray_lev == 1) {
- printf ("\n...1d edge detection: to be implemented\n");
- }
-
-
- #ifdef DBG_ENC_ROW
- printf ("\nCC.C: display current edge tuple list\n");
- show_etpl_list (etll);
- #endif
-
-
- return (etll->listlength);
- }
-