home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / ch_5.1 / pccfeat / pccfeat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-11  |  13.5 KB  |  447 lines

  1. /*
  2.  * pccfeat.c
  3.  *
  4.  * Practical Algorithms for Image Analysis
  5.  *
  6.  * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
  7.  */
  8.  
  9. /* PCCFEAT:     program decodes primitives chain code (PCC) from file
  10.  *            and writes out features and chain codes
  11.  *                      usage: pccfeat infile [-o outimg | -f | -c | -s] [-L]
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <tiffimage.h>          /* picfile info on images */
  18. #include <images.h>             /* images information file */
  19. #include "pcc2.h"               /* header file for PCC programs */
  20. extern void print_sos_lic ();
  21.  
  22. unsigned char *fcCode;          /* code storage */
  23. long nByteCode;                 /* no. bytes in storage */
  24. long nEnd, nBif, nCross;        /* no. of PCC features */
  25.  
  26. long pccdeshow (short, unsigned char **, long, long, long *, long *, long *);
  27. int boxfeat (unsigned char **, long, long, long, long, short);
  28.  
  29. unsigned char **image;          /* image array */
  30. long widthO, heightO;           /* image size */
  31. long x, y;                      /* feature location */
  32. short feat;                     /* =1 end; =2 bif; =3 cross */
  33.  
  34. long pccuntrack (int *, int *, long, long *, long *, long *);
  35. long pccdelst (short, long *, long *, long *);
  36. long usage (short);
  37. long input (int, char **, short *, char *);
  38.  
  39. main (argc, argv)
  40.      int argc;
  41.      char *argv[];
  42. {
  43.   Image *imgO;                  /* output image structure */
  44.   unsigned char **image;        /* image array */
  45.   long widthO, heightO;         /* output image size */
  46.   char outFile[256];            /* output image filename */
  47.   short featsFlag;              /* flag=1 print feats; =2 coords, 
  48.                                  * =3 summary, =4 just image */
  49.   long x, y;
  50.  
  51.   if (input (argc, argv, &featsFlag, outFile) < 0)
  52.     return (-1);
  53.  
  54. /* open input PCC file */
  55.   if (pccread (argv[1], &fcCode, &nByteCode, &widthO, &heightO) == -1)
  56.     exit (1);
  57.   printf ("image size: %dx%d, PCC length = %d\n",
  58.           widthO, heightO, nByteCode);
  59.  
  60. /* construct tables of feature chain decodes */
  61.   pccdecodes ();
  62.  
  63. /* if output image chosen, display features and write file */
  64.   nEnd = nBif = nCross = 0;
  65.   if (featsFlag == 4) {
  66.     imgO = ImageAlloc (heightO, widthO, 8);
  67.     image = ImageGetPtr (imgO);
  68.     for (y = 0; y < heightO; y++)
  69.       for (x = 0; x < widthO; x++)
  70.         image[y][x] = 255;
  71.     pccdeshow (featsFlag, image, widthO, heightO, &nEnd, &nBif, &nCross);
  72.     ImageOut (outFile, imgO);
  73.   }
  74. /* if feature list chosen, write features */
  75.   else
  76.     pccdeshow (featsFlag, 0, 0, 0, &nEnd, &nBif, &nCross);
  77.  
  78.   printf ("Summary: %d endlines, %d bifurcations, %d crosses.\n",
  79.           nEnd, nBif, nCross);
  80.  
  81.   return (0);
  82.  
  83. }
  84.  
  85.  
  86. /* PCCDESHOW:    function reads PCC code from code storage, and displays
  87.  *            features on image
  88.  *         usage: pccdeshow (featsFlag, image, widthO, heightO, 
  89.  *                &nEnd, &nBif, &nCross);
  90.  */
  91.  
  92. #define MAX_PER_LINE 5          /* maximum coordinates printed per line */
  93.  
  94. long
  95. pccdeshow (featsFlag, image, widthO, heightO, nEnd, nBif, nCross)
  96.      short featsFlag;           /* flag=1 print feats; =2 coords, 
  97.                                  * =3 summary, =4 just image */
  98.      unsigned char **image;     /* image array */
  99.      long widthO, heightO;      /* output image size */
  100.      long *nEnd, *nBif, *nCross;  /* no. of PCC features */
  101. {
  102.   register int iByteCode,       /* code storage incrementor */
  103.     codeWord;                   /* code word contains up to 3 dirn.s */
  104.   struct branch1 *branch;       /* stack of branches to be decoded */
  105.   struct branch1 branchTop;     /* first branch */
  106.   long nBranch;                 /* no. of branches in stack */
  107.   int xTrack, yTrack;           /* decode tracking  coord.s */
  108.   long xList[3], yList[3];      /* list of x,y coord.s from 1 PCC */
  109.   long nList;                   /* no. x,y coord.s in xList and yList */
  110.   long xyOnLine;                /* no. coordinates printed on line */
  111.   long i;
  112.  
  113. /* initialize branches */
  114.   nBranch = 0;
  115.   branch = &branchTop;
  116.   branch->previous = branch;
  117.   xyOnLine = 0;
  118.  
  119. /* decode from storage region to original position on screen */
  120.   for (iByteCode = 0; iByteCode < nByteCode;) {
  121.     codeWord = (int) fcCode[iByteCode++];
  122.  
  123.     /* if it is a feature: find start location if break, push branches
  124.      *        if junction, pop branches if endpoint */
  125.  
  126.     if (codeWord >= MINFEATCODE) {
  127.       if (xyOnLine > 0) {
  128.         if (featsFlag < 3)
  129.           printf ("\n");
  130.         xyOnLine = 0;
  131.       }
  132.       switch (codeWord) {
  133.       case BIFCODE:
  134.         if (featsFlag < 2)
  135.           printf ("BIFURCATION at ");
  136.         if (featsFlag < 3)
  137.           printf ("(%d,%d)\n", xTrack, yTrack);
  138.         if (featsFlag == 4)
  139.           boxfeat (image, widthO, heightO, xTrack, yTrack, 2);
  140.         pccbranch (&branch, xTrack, yTrack, 0);
  141.         nBranch++;
  142.         (*nBif)++;
  143.         break;
  144.       case CROSSCODE:
  145.         if (featsFlag < 2)
  146.           printf ("CROSS at ");
  147.         if (featsFlag < 3)
  148.           printf ("(%d,%d)\n", xTrack, yTrack);
  149.         if (featsFlag == 4)
  150.           boxfeat (image, widthO, heightO, xTrack, yTrack, 3);
  151.         pccbranch (&branch, xTrack, yTrack, 0);
  152.         nBranch++;
  153.         pccbranch (&branch, xTrack, yTrack, 0);
  154.         nBranch++;
  155.         (*nCross)++;
  156.         break;
  157.       case ENDCODE:            /* pop branches */
  158.         if (featsFlag < 2)
  159.           printf ("ENDLINE at ");
  160.         if (featsFlag < 3)
  161.           printf ("(%d,%d)\n", xTrack, yTrack);
  162.         if (featsFlag == 4)
  163.           boxfeat (image, widthO, heightO, xTrack, yTrack, 1);
  164.         if (nBranch > 0) {
  165.           nBranch--;
  166.           branch = branch->previous;
  167.           xTrack = branch->x;
  168.           yTrack = branch->y;
  169.         }
  170.         (*nEnd)++;
  171.         break;
  172.       case STARTCODE:
  173.         xTrack = (long) *(fcCode + iByteCode)
  174.           | ((long) *(fcCode + iByteCode + 1) << 8);
  175.         iByteCode += 2;
  176.         yTrack = (long) *(fcCode + iByteCode)
  177.           | ((long) *(fcCode + iByteCode + 1) << 8);
  178.         if (featsFlag < 2)
  179.           printf ("START at ");
  180.         if (featsFlag < 3)
  181.           printf ("(%d,%d)\n", xTrack, yTrack);
  182.         if (featsFlag == 4) {
  183.           boxfeat (image, widthO, heightO, xTrack, yTrack, 1);
  184.           image[yTrack][xTrack] = 128;
  185.         }
  186.         iByteCode += 2;
  187.         (*nEnd)++;
  188.         break;
  189.       case LINEBRCODE:
  190.         xTrack = (long) *(fcCode + iByteCode)
  191.           | ((long) *(fcCode + iByteCode + 1) << 8);
  192.         iByteCode += 2;
  193.         yTrack = (long) *(fcCode + iByteCode)
  194.           | ((long) *(fcCode + iByteCode + 1) << 8);
  195.         iByteCode += 2;
  196.         pccbranch (&branch, xTrack, yTrack, 0);
  197.         nBranch++;
  198.         if (featsFlag < 2)
  199.           printf ("LINEBREAK  at ");
  200.         if (featsFlag < 3)
  201.           printf ("(%d,%d)\n", xTrack, yTrack);
  202.         break;
  203.       case BIFBRCODE:
  204.         xTrack = (long) *(fcCode + iByteCode)
  205.           | ((long) *(fcCode + iByteCode + 1) << 8);
  206.         iByteCode += 2;
  207.         yTrack = (long) *(fcCode + iByteCode)
  208.           | ((long) *(fcCode + iByteCode + 1) << 8);
  209.         iByteCode += 2;
  210.         pccbranch (&branch, xTrack, yTrack, 0);
  211.         nBranch++;
  212.         pccbranch (&branch, xTrack, yTrack, 0);
  213.         nBranch++;
  214.         if (featsFlag < 2)
  215.           printf ("BIFURCATION BREAK  at ");
  216.         if (featsFlag < 3)
  217.           printf ("(%d,%d)\n", xTrack, yTrack);
  218.         if (featsFlag == 4)
  219.           boxfeat (image, widthO, heightO, xTrack, yTrack, 2);
  220.         (*nBif)++;
  221.         break;
  222.       case CROSSBRCODE:
  223.         xTrack = (long) *(fcCode + iByteCode)
  224.           | ((long) *(fcCode + iByteCode + 1) << 8);
  225.         iByteCode += 2;
  226.         yTrack = (long) *(fcCode + iByteCode)
  227.           | ((long) *(fcCode + iByteCode + 1) << 8);
  228.         iByteCode += 2;
  229.         pccbranch (&branch, xTrack, yTrack, 0);
  230.         nBranch++;
  231.         pccbranch (&branch, xTrack, yTrack, 0);
  232.         nBranch++;
  233.         pccbranch (&branch, xTrack, yTrack, 0);
  234.         nBranch++;
  235.         if (featsFlag < 2)
  236.           printf ("CROSS BREAK at ");
  237.         if (featsFlag < 3)
  238.           printf ("(%d,%d)\n", xTrack, yTrack);
  239.         if (featsFlag == 4)
  240.           boxfeat (image, widthO, heightO, xTrack, yTrack, 3);
  241.         (*nCross)++;
  242.         break;
  243.       case LINECODE:
  244.         if (featsFlag < 2)
  245.           printf ("LINE (no-op) at ");
  246.         if (featsFlag < 3)
  247.           printf ("(%d,%d)\n", xTrack, yTrack);
  248.         break;
  249.       case STOPCODE:
  250.         if (featsFlag < 3)
  251.           printf ("STOPCODE\n");
  252.         return (0);
  253.       default:
  254.         break;
  255.       }
  256.     }
  257.  
  258.     /* if it is a direction segment, write at proper location */
  259.     else {
  260.  
  261.       if (featsFlag == 4)
  262.         pccdetrack (image, &xTrack, &yTrack, codeWord, widthO, heightO, 128);
  263.       else {
  264.         pccuntrack (&xTrack, &yTrack, codeWord, xList, yList, &nList);
  265.         for (i = 0; i < nList; i++) {
  266.           if (featsFlag == 0 || featsFlag == 2) {
  267.             if (xyOnLine > MAX_PER_LINE) {
  268.               xyOnLine = 0;
  269.               printf ("\n");
  270.             }
  271.             if (xyOnLine == 0)
  272.               printf ("    ");
  273.             printf ("(%d,%d) ", xList[i], yList[i]);
  274.             xyOnLine++;
  275.           }
  276.         }
  277.       }
  278.     }
  279.   }
  280.  
  281.   printf ("PCCDECODE: missing STOPCODE in PCC storage \n");
  282.   return (-1);
  283. }
  284.  
  285.  
  286. /* BOXFEAT: function displays box around PCC feature location */
  287.  
  288. #define BOX1 5                  /* size of box around minutia */
  289.  
  290. int
  291. boxfeat (image, widthO, heightO, x, y, feat)
  292.      unsigned char **image;     /* image array */
  293.      long widthO, heightO;      /* image size */
  294.      long x, y;                 /* feature location */
  295.      short feat;                /* =1 end; =2 bif; =3 cross */
  296.  
  297. {
  298.   long j;
  299.  
  300.   if (y + BOX1 >= heightO || y - BOX1 < 0)
  301.     return (-1);
  302.   if (x + BOX1 >= widthO || x - BOX1 < 0)
  303.     return (-1);
  304.  
  305. /* boxes at locations of minutia */
  306.   for (j = -BOX1; j <= BOX1; j++) {
  307.     image[y + j][x - BOX1] = image[y + j][x + BOX1] = 0;
  308.     image[y - BOX1][x + j] = image[y + BOX1][x + j] = 0;
  309.     if (feat == 2) {
  310.       image[y + j][x - BOX1 + 1] = image[y + j][x + BOX1 - 1] = 0;
  311.       image[y - BOX1 + 1][x + j] = image[y + BOX1 - 1][x + j] = 0;
  312.     }
  313.     if (feat == 3) {
  314.       image[y + j][x - BOX1 + 2] = image[y + j][x + BOX1 - 2] = 0;
  315.       image[y - BOX1 + 2][x + j] = image[y + BOX1 - 2][x + j] = 0;
  316.     }
  317.   }
  318.   return (0);
  319. }
  320.  
  321. /* PCCUNTRACK:  function decodes codeword and tracks directions
  322.  *                    usage: pccuntrack (&x, &y, codeWord)
  323.  */
  324.  
  325. extern int deCode[NDECODE];     /* decode table */
  326.  
  327. #define DECODE(BITSHIFT) \
  328.         dirn = ((deCode[codeWord] >> BITSHIFT) & 07) + 1; \
  329.         nbrtoxy (dirn, (long)*x, (long)*y, (long *)x, (long *)y); \
  330.         xList[*nList] = *x; \
  331.         yList[(*nList)++] = *y; \
  332.  
  333. long
  334. pccuntrack (x, y, codeWord, xList, yList, nList)
  335.      int *x, *y;                /* input/output line coordinates */
  336.      register long codeWord;    /* code word contains up to 3 directions */
  337.      long *xList, *yList, *nList;  /* list of x,y coord.s */
  338. {
  339.   register long dirn;           /* direction of next segment */
  340.  
  341.   *nList = 0;
  342.  
  343. /* 3 direction segments per code word */
  344.   if (MINCODE3 <= codeWord && MAXCODE3 >= codeWord) {
  345.     DECODE (0);
  346.     DECODE (3);
  347.     DECODE (6);
  348.     return (3);
  349.   }
  350.  
  351. /* 2 direction segments per code word */
  352.   if (MINCODE2 <= codeWord && MAXCODE2 >= codeWord) {
  353.     DECODE (0);
  354.     DECODE (3);
  355.     return (2);
  356.   }
  357.  
  358. /* 1 direction segment per code word */
  359.   if (MINCODE1 <= codeWord && MAXCODE1 >= codeWord) {
  360.     DECODE (0);
  361.     return (1);
  362.   }
  363.  
  364. /* 0 direction segment per code word */
  365.   if (codeWord == CODE0) {
  366.     return (0);
  367.   }
  368. }
  369.  
  370.  
  371.  
  372. /* USAGE:       function gives instructions on usage of program
  373.  *                    usage: usage (flag)
  374.  *              When flag is 1, the long message is given, 0 gives short.
  375.  */
  376.  
  377. long
  378. usage (flag)
  379.      short flag;                /* flag =1 for long message; =0 for short message */
  380. {
  381.  
  382. /* print short usage message or long */
  383.   printf ("USAGE: pccfeat infile [-o outimg | -f | -c | -s] [-L]\n");
  384.   if (flag == 0)
  385.     return (-1);
  386.  
  387.   printf ("\npccfeat decodes Primitives Chain Code (PCC)\n");
  388.   printf ("in input file and displays features on image \n");
  389.   printf ("or lists features and chain codes.\n\n");
  390.   printf ("ARGUMENTS:\n");
  391.   printf ("    infile: input PCC filename (BINARY)\n\n");
  392.   printf ("OPTIONS:\n");
  393.   printf ("  -o outimg: name of output image file (TIF) displaying features\n");
  394.   printf ("             box is 1-pixel thick for end, 2 for 3-junction, 3 for 4-junction\n");
  395.   printf ("         -f: FEATURES_FLAG when set, lists only PCC features, not chains.\n");
  396.   printf ("         -c: COORDS_FLAG when set, lists only (x,y) coordinates.\n");
  397.   printf ("         -s: SUMMARY_FLAG when set, lists only total number of features.\n");
  398.   printf ("         -L: print Software License for this module\n");
  399.  
  400.   return (-1);
  401. }
  402.  
  403.  
  404. /* INPUT:       function reads input parameters
  405.  *                  usage: input (argc, argv, &featsFlag)
  406.  */
  407.  
  408. #define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
  409.  
  410. long
  411. input (argc, argv, featsFlag, outFile)
  412.      int argc;
  413.      char *argv[];
  414.      short *featsFlag;          /* flag=1 print feats; =2 coords, =0 both */
  415.      char *outFile;             /* output image filename */
  416. {
  417.   long n;
  418.  
  419.   if (argc == 1)
  420.     USAGE_EXIT (1);
  421.  
  422.   *featsFlag = 0;
  423.  
  424.   for (n = 2; n < argc; n++) {
  425.     if (strcmp (argv[n], "-o") == 0) {
  426.       if (++n == argc || argv[n][0] == '-')
  427.         USAGE_EXIT (0);
  428.       strcpy (outFile, argv[n]);
  429.       *featsFlag = 4;
  430.     }
  431.     else if (strcmp (argv[n], "-f") == 0)
  432.       *featsFlag = 1;
  433.     else if (strcmp (argv[n], "-c") == 0)
  434.       *featsFlag = 2;
  435.     else if (strcmp (argv[n], "-s") == 0)
  436.       *featsFlag = 3;
  437.     else if (strcmp (argv[n], "-L") == 0) {
  438.       print_sos_lic ();
  439.       exit (0);
  440.     }
  441.     else
  442.       USAGE_EXIT (0);
  443.   }
  444.  
  445.   return (0);
  446. }
  447.