home *** CD-ROM | disk | FTP | other *** search
- /*
- * pccfeat.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /* PCCFEAT: program decodes primitives chain code (PCC) from file
- * and writes out features and chain codes
- * usage: pccfeat infile [-o outimg | -f | -c | -s] [-L]
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <tiffimage.h> /* picfile info on images */
- #include <images.h> /* images information file */
- #include "pcc2.h" /* header file for PCC programs */
- extern void print_sos_lic ();
-
- unsigned char *fcCode; /* code storage */
- long nByteCode; /* no. bytes in storage */
- long nEnd, nBif, nCross; /* no. of PCC features */
-
- long pccdeshow (short, unsigned char **, long, long, long *, long *, long *);
- int boxfeat (unsigned char **, long, long, long, long, short);
-
- unsigned char **image; /* image array */
- long widthO, heightO; /* image size */
- long x, y; /* feature location */
- short feat; /* =1 end; =2 bif; =3 cross */
-
- long pccuntrack (int *, int *, long, long *, long *, long *);
- long pccdelst (short, long *, long *, long *);
- long usage (short);
- long input (int, char **, short *, char *);
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- Image *imgO; /* output image structure */
- unsigned char **image; /* image array */
- long widthO, heightO; /* output image size */
- char outFile[256]; /* output image filename */
- short featsFlag; /* flag=1 print feats; =2 coords,
- * =3 summary, =4 just image */
- long x, y;
-
- if (input (argc, argv, &featsFlag, outFile) < 0)
- return (-1);
-
- /* open input PCC file */
- if (pccread (argv[1], &fcCode, &nByteCode, &widthO, &heightO) == -1)
- exit (1);
- printf ("image size: %dx%d, PCC length = %d\n",
- widthO, heightO, nByteCode);
-
- /* construct tables of feature chain decodes */
- pccdecodes ();
-
- /* if output image chosen, display features and write file */
- nEnd = nBif = nCross = 0;
- if (featsFlag == 4) {
- imgO = ImageAlloc (heightO, widthO, 8);
- image = ImageGetPtr (imgO);
- for (y = 0; y < heightO; y++)
- for (x = 0; x < widthO; x++)
- image[y][x] = 255;
- pccdeshow (featsFlag, image, widthO, heightO, &nEnd, &nBif, &nCross);
- ImageOut (outFile, imgO);
- }
- /* if feature list chosen, write features */
- else
- pccdeshow (featsFlag, 0, 0, 0, &nEnd, &nBif, &nCross);
-
- printf ("Summary: %d endlines, %d bifurcations, %d crosses.\n",
- nEnd, nBif, nCross);
-
- return (0);
-
- }
-
-
- /* PCCDESHOW: function reads PCC code from code storage, and displays
- * features on image
- * usage: pccdeshow (featsFlag, image, widthO, heightO,
- * &nEnd, &nBif, &nCross);
- */
-
- #define MAX_PER_LINE 5 /* maximum coordinates printed per line */
-
- long
- pccdeshow (featsFlag, image, widthO, heightO, nEnd, nBif, nCross)
- short featsFlag; /* flag=1 print feats; =2 coords,
- * =3 summary, =4 just image */
- unsigned char **image; /* image array */
- long widthO, heightO; /* output image size */
- long *nEnd, *nBif, *nCross; /* no. of PCC features */
- {
- register int iByteCode, /* code storage incrementor */
- codeWord; /* code word contains up to 3 dirn.s */
- struct branch1 *branch; /* stack of branches to be decoded */
- struct branch1 branchTop; /* first branch */
- long nBranch; /* no. of branches in stack */
- int xTrack, yTrack; /* decode tracking coord.s */
- long xList[3], yList[3]; /* list of x,y coord.s from 1 PCC */
- long nList; /* no. x,y coord.s in xList and yList */
- long xyOnLine; /* no. coordinates printed on line */
- long i;
-
- /* initialize branches */
- nBranch = 0;
- branch = &branchTop;
- branch->previous = branch;
- xyOnLine = 0;
-
- /* decode from storage region to original position on screen */
- for (iByteCode = 0; iByteCode < nByteCode;) {
- codeWord = (int) fcCode[iByteCode++];
-
- /* if it is a feature: find start location if break, push branches
- * if junction, pop branches if endpoint */
-
- if (codeWord >= MINFEATCODE) {
- if (xyOnLine > 0) {
- if (featsFlag < 3)
- printf ("\n");
- xyOnLine = 0;
- }
- switch (codeWord) {
- case BIFCODE:
- if (featsFlag < 2)
- printf ("BIFURCATION at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- if (featsFlag == 4)
- boxfeat (image, widthO, heightO, xTrack, yTrack, 2);
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- (*nBif)++;
- break;
- case CROSSCODE:
- if (featsFlag < 2)
- printf ("CROSS at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- if (featsFlag == 4)
- boxfeat (image, widthO, heightO, xTrack, yTrack, 3);
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- (*nCross)++;
- break;
- case ENDCODE: /* pop branches */
- if (featsFlag < 2)
- printf ("ENDLINE at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- if (featsFlag == 4)
- boxfeat (image, widthO, heightO, xTrack, yTrack, 1);
- if (nBranch > 0) {
- nBranch--;
- branch = branch->previous;
- xTrack = branch->x;
- yTrack = branch->y;
- }
- (*nEnd)++;
- break;
- case STARTCODE:
- xTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- yTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- if (featsFlag < 2)
- printf ("START at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- if (featsFlag == 4) {
- boxfeat (image, widthO, heightO, xTrack, yTrack, 1);
- image[yTrack][xTrack] = 128;
- }
- iByteCode += 2;
- (*nEnd)++;
- break;
- case LINEBRCODE:
- xTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- yTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- if (featsFlag < 2)
- printf ("LINEBREAK at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- break;
- case BIFBRCODE:
- xTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- yTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- if (featsFlag < 2)
- printf ("BIFURCATION BREAK at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- if (featsFlag == 4)
- boxfeat (image, widthO, heightO, xTrack, yTrack, 2);
- (*nBif)++;
- break;
- case CROSSBRCODE:
- xTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- yTrack = (long) *(fcCode + iByteCode)
- | ((long) *(fcCode + iByteCode + 1) << 8);
- iByteCode += 2;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- pccbranch (&branch, xTrack, yTrack, 0);
- nBranch++;
- if (featsFlag < 2)
- printf ("CROSS BREAK at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- if (featsFlag == 4)
- boxfeat (image, widthO, heightO, xTrack, yTrack, 3);
- (*nCross)++;
- break;
- case LINECODE:
- if (featsFlag < 2)
- printf ("LINE (no-op) at ");
- if (featsFlag < 3)
- printf ("(%d,%d)\n", xTrack, yTrack);
- break;
- case STOPCODE:
- if (featsFlag < 3)
- printf ("STOPCODE\n");
- return (0);
- default:
- break;
- }
- }
-
- /* if it is a direction segment, write at proper location */
- else {
-
- if (featsFlag == 4)
- pccdetrack (image, &xTrack, &yTrack, codeWord, widthO, heightO, 128);
- else {
- pccuntrack (&xTrack, &yTrack, codeWord, xList, yList, &nList);
- for (i = 0; i < nList; i++) {
- if (featsFlag == 0 || featsFlag == 2) {
- if (xyOnLine > MAX_PER_LINE) {
- xyOnLine = 0;
- printf ("\n");
- }
- if (xyOnLine == 0)
- printf (" ");
- printf ("(%d,%d) ", xList[i], yList[i]);
- xyOnLine++;
- }
- }
- }
- }
- }
-
- printf ("PCCDECODE: missing STOPCODE in PCC storage \n");
- return (-1);
- }
-
-
- /* BOXFEAT: function displays box around PCC feature location */
-
- #define BOX1 5 /* size of box around minutia */
-
- int
- boxfeat (image, widthO, heightO, x, y, feat)
- unsigned char **image; /* image array */
- long widthO, heightO; /* image size */
- long x, y; /* feature location */
- short feat; /* =1 end; =2 bif; =3 cross */
-
- {
- long j;
-
- if (y + BOX1 >= heightO || y - BOX1 < 0)
- return (-1);
- if (x + BOX1 >= widthO || x - BOX1 < 0)
- return (-1);
-
- /* boxes at locations of minutia */
- for (j = -BOX1; j <= BOX1; j++) {
- image[y + j][x - BOX1] = image[y + j][x + BOX1] = 0;
- image[y - BOX1][x + j] = image[y + BOX1][x + j] = 0;
- if (feat == 2) {
- image[y + j][x - BOX1 + 1] = image[y + j][x + BOX1 - 1] = 0;
- image[y - BOX1 + 1][x + j] = image[y + BOX1 - 1][x + j] = 0;
- }
- if (feat == 3) {
- image[y + j][x - BOX1 + 2] = image[y + j][x + BOX1 - 2] = 0;
- image[y - BOX1 + 2][x + j] = image[y + BOX1 - 2][x + j] = 0;
- }
- }
- return (0);
- }
-
- /* PCCUNTRACK: function decodes codeword and tracks directions
- * usage: pccuntrack (&x, &y, codeWord)
- */
-
- extern int deCode[NDECODE]; /* decode table */
-
- #define DECODE(BITSHIFT) \
- dirn = ((deCode[codeWord] >> BITSHIFT) & 07) + 1; \
- nbrtoxy (dirn, (long)*x, (long)*y, (long *)x, (long *)y); \
- xList[*nList] = *x; \
- yList[(*nList)++] = *y; \
-
- long
- pccuntrack (x, y, codeWord, xList, yList, nList)
- int *x, *y; /* input/output line coordinates */
- register long codeWord; /* code word contains up to 3 directions */
- long *xList, *yList, *nList; /* list of x,y coord.s */
- {
- register long dirn; /* direction of next segment */
-
- *nList = 0;
-
- /* 3 direction segments per code word */
- if (MINCODE3 <= codeWord && MAXCODE3 >= codeWord) {
- DECODE (0);
- DECODE (3);
- DECODE (6);
- return (3);
- }
-
- /* 2 direction segments per code word */
- if (MINCODE2 <= codeWord && MAXCODE2 >= codeWord) {
- DECODE (0);
- DECODE (3);
- return (2);
- }
-
- /* 1 direction segment per code word */
- if (MINCODE1 <= codeWord && MAXCODE1 >= codeWord) {
- DECODE (0);
- return (1);
- }
-
- /* 0 direction segment per code word */
- if (codeWord == CODE0) {
- return (0);
- }
- }
-
-
-
- /* USAGE: function gives instructions on usage of program
- * usage: usage (flag)
- * When flag is 1, the long message is given, 0 gives short.
- */
-
- long
- usage (flag)
- short flag; /* flag =1 for long message; =0 for short message */
- {
-
- /* print short usage message or long */
- printf ("USAGE: pccfeat infile [-o outimg | -f | -c | -s] [-L]\n");
- if (flag == 0)
- return (-1);
-
- printf ("\npccfeat decodes Primitives Chain Code (PCC)\n");
- printf ("in input file and displays features on image \n");
- printf ("or lists features and chain codes.\n\n");
- printf ("ARGUMENTS:\n");
- printf (" infile: input PCC filename (BINARY)\n\n");
- printf ("OPTIONS:\n");
- printf (" -o outimg: name of output image file (TIF) displaying features\n");
- printf (" box is 1-pixel thick for end, 2 for 3-junction, 3 for 4-junction\n");
- printf (" -f: FEATURES_FLAG when set, lists only PCC features, not chains.\n");
- printf (" -c: COORDS_FLAG when set, lists only (x,y) coordinates.\n");
- printf (" -s: SUMMARY_FLAG when set, lists only total number of features.\n");
- printf (" -L: print Software License for this module\n");
-
- return (-1);
- }
-
-
- /* INPUT: function reads input parameters
- * usage: input (argc, argv, &featsFlag)
- */
-
- #define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
-
- long
- input (argc, argv, featsFlag, outFile)
- int argc;
- char *argv[];
- short *featsFlag; /* flag=1 print feats; =2 coords, =0 both */
- char *outFile; /* output image filename */
- {
- long n;
-
- if (argc == 1)
- USAGE_EXIT (1);
-
- *featsFlag = 0;
-
- for (n = 2; n < argc; n++) {
- if (strcmp (argv[n], "-o") == 0) {
- if (++n == argc || argv[n][0] == '-')
- USAGE_EXIT (0);
- strcpy (outFile, argv[n]);
- *featsFlag = 4;
- }
- else if (strcmp (argv[n], "-f") == 0)
- *featsFlag = 1;
- else if (strcmp (argv[n], "-c") == 0)
- *featsFlag = 2;
- else if (strcmp (argv[n], "-s") == 0)
- *featsFlag = 3;
- else if (strcmp (argv[n], "-L") == 0) {
- print_sos_lic ();
- exit (0);
- }
- else
- USAGE_EXIT (0);
- }
-
- return (0);
- }
-