home *** CD-ROM | disk | FTP | other *** search
/ vis-ftp.cs.umass.edu / vis-ftp.cs.umass.edu.tar / vis-ftp.cs.umass.edu / pub / Software / ASCENDER / umass_foa.tar / mdt_NEW / foa / foa.cc < prev    next >
C/C++ Source or Header  |  1995-04-21  |  16KB  |  510 lines

  1. /* =============================================================
  2.    foa: Classifies a color (RGB) image based on the 
  3.             multivariate decision tree represented in the lookup table.
  4.         The result is a binary image with the 'target' regions,
  5.         along with the coordinates for those regions.
  6.  
  7.             Usage is as follows:
  8.               foa lookup_table_file(input) color_image(input) result_image(output)
  9.  
  10.  
  11.    Shashi Buluswar
  12.    Computer Vision Laboratory
  13.    Dept of Computer Science
  14.    University of Massachusetts
  15.    Amherst, MA  01003
  16.  
  17.    Copyright 1995, University of Massachusetts - Amherst
  18.  
  19.    =============================================================== */
  20. #define MAIN
  21. #include <foa.h>
  22.  
  23. /* ====================================================================
  24.    Morphological operations on binary image.  Eight-neighbor expansion/
  25.    contraction, based on NUM_NEIGH_EXP, NUM_NEIGH_CON, which define the
  26.    number of neighbors that have to be on or off for the pixel to be 
  27.    turned on or off.  NOTE: the corner neighbors have been commented out.
  28.    Feel free to add them back if it helps in the imagery being used.
  29.    ==================================================================== */
  30.  
  31. void ImgMorph (int flag, char *img_arr)
  32. {
  33.   int i, j, num_pos_neighbors;
  34.   
  35.   for (i=1; i<(imgNumR-1); i++) {
  36.     for (j=1; j<(imgNumC-1); j++) {
  37.       num_pos_neighbors = 0;
  38.  
  39.       /*if (img_arr[(((i-1)*imgNumC)+(j-1))] == BIT_ON) num_pos_neighbors ++;*/
  40.       if (img_arr[(((i-1)*imgNumC)+j)] == BIT_ON) num_pos_neighbors ++;
  41.       /*if (img_arr[(((i-1)*imgNumC)+(j+1))] == BIT_ON) num_pos_neighbors ++;*/
  42.       if (img_arr[(((i)*imgNumC)+(j-1))] == BIT_ON) num_pos_neighbors ++;
  43.       if (img_arr[(((i)*imgNumC)+(j+1))] == BIT_ON) num_pos_neighbors ++;
  44.       /*if (img_arr[(((i+1)*imgNumC)+(j-1))] == BIT_ON) num_pos_neighbors ++;*/
  45.       if (img_arr[(((i+1)*imgNumC)+(j))] == BIT_ON) num_pos_neighbors ++;
  46.       /*if (img_arr[(((i+1)*imgNumC)+(j+1))] == BIT_ON) num_pos_neighbors ++;*/
  47.       
  48.       if (flag == 1) {
  49.     if (num_pos_neighbors > NUM_NEIGH_EXP)img_arr[((i*imgNumC)+j)]=BIT_ON;
  50.       }
  51.       else if (flag == 0){
  52.     if (num_pos_neighbors < NUM_NEIGH_CON)img_arr[((i*imgNumC)+j)]=BIT_OFF;
  53.       }
  54.     }
  55.   }
  56. }
  57.  
  58.  
  59. /* ====================================================
  60.    BEGIN: code for extracting bounding rectangle
  61.    ==================================================== */
  62.  
  63. int left_bound (int i, int j, char *img_arr)
  64. {
  65.   if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
  66.       (img_arr[(i*imgNumC)+(j+1)]==BIT_ON) &&
  67.       (img_arr[(i*imgNumC)+(j-1)]==BIT_OFF))
  68.     return (1);
  69.   else return (0);
  70.   
  71. }
  72.  
  73. int right_bound (int i, int j, char *img_arr)
  74. {
  75.   if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
  76.       (img_arr[(i*imgNumC)+(j+1)]==BIT_OFF) &&
  77.       (img_arr[(i*imgNumC)+(j-1)]==BIT_ON))
  78.     return (1);
  79.   else return (0);
  80. }
  81.  
  82. int top_bound (int i, int j, char *img_arr)
  83. {
  84.   if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
  85.       (img_arr[((i-1)*imgNumC)+j]==BIT_OFF) &&
  86.       (img_arr[((i+1)*imgNumC)+j]==BIT_ON))
  87.     return (1);
  88.   else return (0);
  89. }
  90.  
  91. int bott_bound (int i, int j, char *img_arr)
  92. {
  93.   if ((img_arr[(i*imgNumC)+j]==BIT_ON) &&
  94.       (img_arr[((i-1)*imgNumC)+j]==BIT_ON) &&
  95.       (img_arr[((i+1)*imgNumC)+j]==BIT_OFF))
  96.     return (1);
  97.   else return (0);
  98. }
  99.  
  100. int bound_pixel (int i, int j, char *img_arr)
  101. {
  102.   if ((left_bound(i,j,img_arr)==1)||
  103.       (right_bound(i,j,img_arr)==1)||
  104.       (top_bound(i,j,img_arr)==1)||
  105.       (bott_bound(i,j,img_arr)==1))
  106.     return (1);
  107.   else return (0);
  108. }
  109.  
  110. void extend_rect (int i, int j,
  111.           short int *beg_r, short int *beg_c, 
  112.           short int *end_r, short int *end_c,
  113.           int num_regions)
  114. {
  115.   /*=== if previous boundary of region can be extended, do so ===*/
  116.   if (beg_r[num_regions] > i) beg_r[num_regions] = i;  
  117.   if (beg_c[num_regions] > j) beg_c[num_regions] = j;
  118.   if (end_r[num_regions] < i) end_r[num_regions] = i;
  119.   if (end_c[num_regions] < j) end_c[num_regions] = j;
  120.   
  121. }
  122.  
  123.  
  124. int col_overlap(int i, int j,
  125.         short int *beg_c, short int *end_c)
  126. {
  127.   if ((end_c[i]>end_c[j]) && (end_c[j]>beg_c[i]))
  128.     return (1);
  129.   else return(0);
  130. }
  131.  
  132. int row_overlap(int i, int j,
  133.         short int *beg_r, short int *end_r)
  134. {
  135.   if ((end_r[i]>end_r[j]) && (end_r[j]>beg_r[i]))
  136.     return (1);
  137.   else return(0);
  138. }
  139.  
  140. void ExtractBoundRect (char *img_arr,
  141.                short int *beg_r, short int *beg_c, 
  142.                short int *end_r, short int *end_c)
  143. {
  144.   int num_regions=0;                        /* # regions in the binary classified image */
  145.   int i, j, tmp_i, tmp_j, x, y, reg_area;
  146.   int trace_done;
  147.   short int bound_pix_list_i[1000], pix_ctr_i=0, bound_pix_list_j[1000], pix_ctr_j=0;
  148.   char *pix_proc_LUT;        /* LUT for marking processed pixels in boundary extraction
  149.                   if LUT[x][y] == 0, then [x][y] done,
  150.                   else not */
  151.   num_regions = 0;          /* init # regions found */
  152.   int SIZE=20, GROW=20;     /* for malloc & realloc */
  153.   short int *tmp_beg_r, *tmp_beg_c, *tmp_end_r, *tmp_end_c, ctr_tmp;
  154.  
  155.  
  156.   pix_proc_LUT = (char *)malloc(sizeof(char)*imgNumC*imgNumR);
  157.  
  158.   beg_r = (short int *) malloc(sizeof(short int)*GROW);
  159.   beg_c = (short int *) malloc(sizeof(short int)*GROW);
  160.   end_r = (short int *) malloc(sizeof(short int)*GROW);
  161.   end_c = (short int *) malloc(sizeof(short int)*GROW);
  162.   SIZE = GROW;
  163.  
  164.   for (i=0; i<imgNumR; i++) 
  165.     for (j=0; j<imgNumC; j++) {
  166.       
  167.       if ((bound_pixel(i,j,img_arr)==1)&&
  168.       (pix_proc_LUT[(i*imgNumC)+j]!=DONE)) {  /* found a boundary pixel -- start trace */
  169.     tmp_i=i; tmp_j=j;
  170.     pix_proc_LUT[(tmp_i*imgNumC)+tmp_j]=DONE;
  171.     trace_done=0;
  172.     beg_r[num_regions]=tmp_i;
  173.     beg_c[num_regions]=tmp_j;
  174.     end_r[num_regions]=tmp_i;
  175.     end_c[num_regions]=tmp_j;
  176.  
  177.     while (trace_done != 1) {
  178.  
  179.       for (x=tmp_i-1; x<=tmp_i+1; x++)   /* list of unexplored boundary pixels*/
  180.         for (y=tmp_j-1; y<=tmp_j+1; y++) {
  181.           if (pix_proc_LUT[(x*imgNumC)+y]!=DONE)
  182.         if (bound_pixel(x,y,img_arr)==1) {
  183.           bound_pix_list_i[pix_ctr_i]=x;
  184.           bound_pix_list_j[pix_ctr_i]=y;
  185.           pix_ctr_i++; pix_ctr_j++;
  186.         }
  187.         }
  188.       if (pix_ctr_i==0) trace_done=1;    /* if no unexplored bound-pixels, then done */
  189.       else {
  190.         pix_ctr_i--; tmp_i=bound_pix_list_i[pix_ctr_i]; 
  191.         pix_ctr_j--; tmp_j=bound_pix_list_j[pix_ctr_j]; 
  192.         pix_proc_LUT[(tmp_i*imgNumC)+tmp_j]=DONE;
  193.         extend_rect(tmp_i, tmp_j, beg_r, beg_c, end_r, end_c, num_regions);
  194.       }
  195.     }
  196.     reg_area = ((end_r[num_regions]-beg_r[num_regions])*
  197.             (end_c[num_regions]-beg_c[num_regions]));
  198.     if ((reg_area > MIN_REG_SIZE)&&(reg_area < MAX_REG_SIZE) &&
  199.         ((end_r[num_regions]-beg_r[num_regions])>MIN_REG_X) &&
  200.         ((end_c[num_regions]-beg_c[num_regions])>MIN_REG_Y) &&
  201.         ((end_r[num_regions]-beg_r[num_regions])<MAX_REG_X) &&
  202.         ((end_c[num_regions]-beg_c[num_regions])<MAX_REG_Y)) {
  203.       num_regions++;
  204.       if (num_regions >SIZE) {
  205.         beg_r = (short int *) realloc(beg_r, sizeof(short int)*(SIZE+GROW));
  206.         beg_c = (short int *) realloc(beg_c, sizeof(short int)*(SIZE+GROW));
  207.         end_r = (short int *) realloc(end_r, sizeof(short int)*(SIZE+GROW));
  208.         end_c = (short int *) realloc(end_c, sizeof(short int)*(SIZE+GROW));
  209.         SIZE += GROW;
  210.       }
  211.     }
  212.       }
  213.     }
  214.   
  215.   free((void *)(pix_proc_LUT));
  216.   free((void *)(beg_r)); free((void *)(beg_c)); free((void *)(end_r)); free((void *)(end_c));
  217.  
  218.   /* print coordinates of bounding rectangle after inverting them */
  219.   for (x=0; x<num_regions; x++) {
  220.     reg_area = ((end_r[x]-beg_r[x])*(end_c[x]-beg_c[x]));
  221.     
  222.     beg_r[x]=imgNumR-beg_r[x]; 
  223.     end_r[x]=imgNumR-end_r[x]; 
  224.     beg_c[x]=imgNumC-beg_c[x]; 
  225.     end_c[x]=imgNumC-end_c[x]; 
  226.  
  227.     /* ATTN: IF USING TIFF IMAGES, DO NOT USE THE NEXT FOUR LINES */
  228.     beg_r[x]=imgNumR-beg_r[x]; 
  229.     end_r[x]=imgNumR-end_r[x]; 
  230.     beg_c[x]=imgNumC-beg_c[x]; 
  231.     end_c[x]=imgNumC-end_c[x]; 
  232.  
  233.     printf ("region#%d: %dx%d - %dx%d; area: %d\n", 
  234.         x, beg_c[x], beg_r[x], end_c[x], end_r[x], reg_area);
  235.   }
  236.  
  237.   printf ("\nchecking for overlapping regions...\n");
  238.  
  239.  
  240.   for (i=0; i<num_regions; i++) {
  241.     for (j=0; j<num_regions; j++) { 
  242.  
  243.       if ((col_overlap(i, j, beg_c, end_c) && row_overlap(i, j, beg_r, end_r)) ||
  244.       (col_overlap(i, j, beg_c, end_c) && row_overlap(j, i, beg_r, end_r)) ||
  245.       (col_overlap(j, i, beg_c, end_c) && row_overlap(i, j, beg_r, end_r)) ||
  246.       (col_overlap(j, i, beg_c, end_c) && row_overlap(j, i, beg_r, end_r))) {
  247.  
  248.     printf ("regions %d & %d overlap\n", i, j);
  249.  
  250.     if (beg_c[i] < beg_c[j])  beg_c[j]=0;
  251.     else {
  252.       beg_c[i]=beg_c[j];
  253.       beg_c[j]=0;
  254.     }
  255.     if (end_c[i] > end_c[j])  end_c[j]=0;
  256.     else {
  257.       end_c[i]=end_c[j];
  258.       end_c[j]=0;
  259.     }
  260.     if (beg_r[i] < beg_r[j])  beg_r[j]=0;
  261.     else {
  262.       beg_r[i]=beg_r[j];
  263.       beg_r[j]=0;
  264.     }
  265.     if (end_r[i] > end_r[j])  end_r[j]=0;
  266.     else {
  267.       end_r[i]=end_r[j];
  268.       end_r[j]=0;
  269.     }
  270.       }
  271.       
  272.     }
  273.   }
  274.  
  275.   tmp_beg_r = (short int *) malloc(sizeof(short int)*num_regions);
  276.   tmp_beg_c = (short int *) malloc(sizeof(short int)*num_regions);
  277.   tmp_end_r = (short int *) malloc(sizeof(short int)*num_regions);
  278.   tmp_end_c = (short int *) malloc(sizeof(short int)*num_regions);
  279.  
  280.   /* remove zeroed out regions */
  281.   ctr_tmp=0;
  282.   for (x=0; x<num_regions; x++) {
  283.     if (((end_r[x]-beg_r[x])*(end_c[x]-beg_c[x])) != 0) {
  284.       tmp_beg_r[ctr_tmp]=beg_r[x];
  285.       tmp_beg_c[ctr_tmp]=beg_c[x];
  286.       tmp_end_r[ctr_tmp]=end_r[x];
  287.       tmp_end_c[ctr_tmp]=end_c[x];
  288.       ctr_tmp++;
  289.     }
  290.   }
  291.  
  292.   beg_r=tmp_beg_r; beg_c=tmp_beg_c; end_r=tmp_end_r; end_c=tmp_end_c;
  293.  
  294.   printf ("\nfinal regions...\n");
  295.   for (x=0; x<ctr_tmp; x++)
  296.     printf ("region#%d: %dx%d - %dx%d\n", 
  297.         x, beg_c[x], beg_r[x], end_c[x], end_r[x]);
  298.  
  299. }
  300.  
  301.  
  302. /* ====================================================
  303.    Load images from corresponding files
  304.    ==================================================== */
  305.  
  306. int ReadImages(char *RGB_IMG)
  307. {
  308.   TokenIStream RGBStream;                            /* ISR RGB input stream */
  309.   Token *rgb;                                        /* ISR RGB token */
  310.  
  311.   RGBStream.MatchFormatToFilename(RGB_IMG);
  312.   RGBStream.open(RGB_IMG);
  313.   if (!RGBStream) {
  314.     printf ("unable to open file %s\n", RGB_IMG);
  315.     return (-1);
  316.   }
  317.  
  318.   rgb = RGBStream.read_token_ptr();
  319.   if (strcmp(rgb->name(), "ColorImage") != 0) {
  320.     printf ("ERROR - %s is not a color image...\n", RGB_IMG);
  321.     return (-2);
  322.   }
  323.   else {
  324.     RImg = (BytePlane *) ((ColorImage*)rgb)->red();
  325.     GImg = (BytePlane *) ((ColorImage*)rgb)->green();
  326.     BImg = (BytePlane *) ((ColorImage*)rgb)->blue();
  327.     return (0);
  328.   }
  329. }
  330.  
  331. /* =====================================================
  332.    dec2bin: convert a decimal number to binary: for 
  333.    unpacking bytes read from LUT-file
  334.    ===================================================== */
  335. void dec2bin (int ascDec, int bitArr[CHAR_SIZE])
  336. {
  337.   int i;
  338.   int tmpNum;
  339.  
  340.   tmpNum=ascDec;
  341.   for (i=CHAR_SIZE-1; i>=0; i--) {
  342.     bitArr[i] = tmpNum%2;
  343.     tmpNum = tmpNum/2;
  344.   }
  345. }
  346.  
  347. /* =====================================================
  348.    Load a color image
  349.    Pixelwise classify it
  350.    Store the result as a BytePlane 
  351.    ===================================================== */
  352.  
  353.  
  354. int ReadAndClassifyImage (char *RGB_IMG, char *RESULT_IMG)
  355. {
  356.   TokenOStream OStream;   /* ISR output stream */
  357.   int i, j, iR, iG, iB, PixClass, irow, icol, byte_idx;
  358.   unsigned char LUT_char;
  359.   int LUT_dec, bitArr[CHAR_SIZE];
  360.   char *img_arr;
  361.   int StartCol, StartRow, EndCol, EndRow;            /* image coordinates */
  362.   short int *beg_r, *beg_c, *end_r, *end_c; /* coordiates for target regions */
  363.   int posCount=0;
  364.   
  365.   printf ("Reading input image...\n");
  366.   if (ReadImages(RGB_IMG)!=0) printf ("ERROR reading images\n");
  367.   printf ("DONE reading input image...\n");
  368.   
  369.   /* open and initialize output stream */
  370.   OStream.MatchFormatToFilename(RESULT_IMG);
  371.   OStream.open(RESULT_IMG);
  372.   if (!OStream) {
  373.     printf ("unable to open file %s\n", RESULT_IMG);
  374.     return(-1);
  375.   }
  376.  
  377.   ((BytePlane *)RImg)->GetMinMax (StartCol, EndCol, StartRow, EndRow);
  378.   
  379.   imgNumR = (EndRow-StartRow+1);
  380.   imgNumC = (EndCol-StartCol+1);
  381.   printf ("Image min-max: %d-%d x %d-%d, size: %d x %d\n",
  382.       StartRow, EndRow, StartCol, EndCol, imgNumR, imgNumC);
  383.  
  384.   img_arr = (char *)malloc(sizeof(char)*imgNumC*imgNumR);
  385.  
  386.   result = new BytePlane(*RImg);
  387.  
  388.   printf ("Starting pixel classification...\n");
  389.  
  390.   /* ========================================================
  391.      get pixel RGB
  392.      if it's outside the range, class = 0
  393.      if it's within range, look it up.
  394.      ======================================================== */
  395.  
  396.   for (i=StartRow, irow=0; i<=EndRow; i++, irow++) {
  397.     for (j=StartCol, icol=0; j<=EndCol; j++, icol++) {
  398.       iR = RImg->pixel(j,i);
  399.       iG = GImg->pixel(j,i);
  400.       iB = BImg->pixel(j,i);
  401.       
  402.       if ((iR<=RGB_min)||(iR>=RGB_max)||
  403.       (iG<=RGB_min)||(iG>=RGB_max)||
  404.       (iB<=RGB_min)||(iB>=RGB_max)) 
  405.     PixClass = 0;
  406.       
  407.       else {
  408.     iR=iR-RGB_min; iG=iG-RGB_min; iB=iB-RGB_min;
  409.     byte_idx = (((iR*iRange*iRange) + (iG*iRange) + iB)/CHAR_SIZE);
  410.     
  411.     LUT_char = LUT[byte_idx];
  412.     LUT_dec = (int)LUT_char;
  413.  
  414.     if (LUT_dec==0) PixClass = 0;
  415.     else {
  416.       if (LUT_dec==255) PixClass = 1;
  417.       else {
  418.         dec2bin(LUT_dec, bitArr);
  419.         PixClass = bitArr[byte_idx%CHAR_SIZE];
  420.       }
  421.     }
  422.       }
  423.       img_arr[(irow*imgNumC)+icol] = PixClass;
  424.       if (PixClass ==1) posCount++;
  425.     }
  426.   }
  427.   printf ("DONE with pixel classification\n");
  428.   printf ("Total target pixels: %d\n", posCount);
  429.   
  430.  
  431.   /* =====================================================================
  432.      series of morph operations -- sequence/number of ops is arbitrary --
  433.      for the Ft. Carson images, the following sequence seemed to work
  434.      best.
  435.      ===================================================================== */
  436.  
  437.   printf ("Starting morphological operations...\n");
  438.   ImgMorph (1, img_arr);
  439.   ImgMorph (1, img_arr);
  440.   ImgMorph (1, img_arr);
  441.   ImgMorph (0, img_arr);
  442.   ImgMorph (0, img_arr);
  443.   printf ("DONE performing morphological operations...\n");
  444.  
  445.   printf ("Writing output image...\n");
  446.   for (i=StartRow, irow=0; i<=EndRow; i++, irow++) {
  447.     for (j=StartCol, icol=0; j<=EndCol; j++, icol++) {
  448.       result->pixel(j, i) = img_arr [(irow*imgNumC)+icol]*255;
  449.     }
  450.   }
  451.  
  452.   OStream << result;
  453.   printf ("DONE writing output image...\n");
  454.   
  455.   /* === extract the bounding rectangles for target regions === */
  456.   printf ("Extracting bounding rectangles\n");
  457.   ExtractBoundRect (img_arr, beg_r, beg_c, end_r, end_c);   
  458.   printf ("ALL DONE...\n");
  459.  
  460.   free ((void *) img_arr);
  461.   return (0);
  462. }
  463.  
  464. /* =========================================================
  465.   Load the lookup table from LUT_file and store in LUT[][][]
  466.   ========================================================== */
  467.  
  468. int read_LUT_from_file (char *file_name) 
  469. {
  470.   FILE *LUT_file_ptr;
  471.   
  472.   if ((LUT_file_ptr = fopen (file_name, "rb")) == NULL) {
  473.     printf ("fopen error; exiting...\n");
  474.     return (-1);
  475.   }
  476.   else {
  477.     fread (LUT, sizeof(char), ARR_SIZE, LUT_file_ptr);
  478.     return(0);
  479.   }
  480. }
  481.   
  482. main (int argc, char *argv[])
  483. {
  484.   char *RGB_IMG, *RESULT_IMG;      /* image filenames */
  485.  
  486.  
  487.   /* === show usage === */
  488.   if (argc != 4) {
  489.     fprintf(stdout, "\nusage: foa LUT_file RGBImage ResultImage\n");
  490.     return (-1);
  491.   }
  492.  
  493.   /* === load lookup table === */
  494.   printf ("Reading LUT from file: %s...\n", argv[1]);  
  495.   if (read_LUT_from_file (argv[1]) != 0) {
  496.     printf ("ERROR reading LUT\n");
  497.     return (-2);
  498.   }else printf ("DONE reading input LUT\n");
  499.  
  500.   RGB_IMG = argv[2];
  501.   RESULT_IMG = argv[3];
  502.  
  503.   /* === load a color  image from disk and classify it === */
  504.   if (ReadAndClassifyImage(RGB_IMG, RESULT_IMG) != 0) {
  505.     printf ("ERROR in classification...bailed out!\n");
  506.     return (-3);
  507.   }
  508. }
  509.  
  510.