/* Connected Components or COLORING program for identifying ---------------------------------------- objects which are connected "blobs" of '1's in a background of '0's. Program is written with clarity for beginners as the prime concern. The program will prompt for an image file name and 4 or 8 connectivity. 1) First, a binary image of '0's and '1's is input and echoed. 2) This char image is scanned top-to-bottom and left-to-right to find any 1 pixel indicating the presence of a blob. 2.1) When a 1 pixel is found, it is assigned a new color, 2 or >. 2.2) All 1 pixels connected to this pixel are then given the same color: connected pixels are located using a depth-first scan implemented via recursive function calls. All neighbors of all connecting pixels are checked; recursion stops when a neighbor is a color other than 1. 3) After all separate objects have separate colors assigned, additional passes through the image compute the centroid and bounding box of each object(blob). This inefficient, but obvious technique requires #objects passes through the entire image. V1.0 written 3 July 95 by GCS for HS95. V2.0 written Feb 97 by GCS. program tested using g++ version 2.7.2 */ #include #include #include /* handles up to MAXROW x MAXCOL images; for larger images enlarge these bounds and recompile the program. For more objects, increase the size of the colortable according to MAXOBJECTS. */ #define MAXROW 200 #define MAXCOL 200 #define MAXOBJECTS 70 /*can't increase without increasing colortable */ /* Global image and object data used by all procedures */ String imagetitle; int numberofrows, numberofcolumns; int numberofobjects, connectivity; char image[MAXROW][MAXCOL]; /* input binary image to be colored */ /* colortable converts integer object number into printable character */ static char colortable[MAXOBJECTS] = {' ','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f','g','h','i','j', 'l','m','n','o','p','q','r','s','t','u', 'w','x','y','z','A','B','C','D','E','F', 'G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z', '@','#','$','%','&','*','+','~','?','^'}; /*==========================INPUT_IMAGE================================*/ int input_image () // returns 0 if all is OK and 1 if insufficient storage { fstream Infile; String filename; /* This procedure inputs the image and checks for errors in its size */ int row, col; cout << "Please give name of file containing the input image: " << endl; cin >> filename; Infile.open ( filename, ios::in ); Infile >> imagetitle; cout << " Image is : " << imagetitle << endl << endl; Infile >> numberofrows; Infile >> numberofcolumns; cout << " The image size is " << numberofrows << " x " << numberofcolumns << endl; /* make sure that array is in storage bounds before reading image data */ if ( numberofrows>MAXROW || numberofcolumns>MAXCOL) { cout << " Image is too large for storage allocated." << endl; Infile.close (); return(1); } else /* read in the image */ { for(row=0; row> image[row][col]; } Infile.close(); return(0); } // end else } /*==========================OUTPUT_IMAGE================================*/ void output_image () /* This procedure prints the character image for the user to see */ { int row,col; cout << endl; cout << endl; cout << "Your image is as follows: " << endl << endl; for(row=0; row> connectivity; /* check all non border pixels and propagate object color */ for(row=1; row<(numberofrows-1); row++) for(col=1; col<(numberofcolumns-1); col++) if (image[row][col] == '1') /* new uncolored object found */ { if(numberofobjects == MAXOBJECTS) return(1); numberofobjects++; /* get new object color */ propagate_color(row, col, colortable[numberofobjects]); } return(numberofobjects); } /*======================REPORT_OBJECT_FEATURES========================*/ void report_object_features () /* scans through the image for each object and computes centroid and bbox */ { int r, c, Ncolor; int number_of_pixels, low_r, high_r, low_c, high_c; float rowsum, colsum; cout << endl << endl; cout << " Object Area Centroid Bounding Box " << endl; cout << "=================================================" << endl; for(Ncolor=2; Ncolor<=numberofobjects; Ncolor++) { /* initialize data for object of this color */ number_of_pixels = 0; rowsum = 0.0; colsum = 0.0; low_r = MAXROW; high_r = -1; low_c = MAXCOL; high_c = -1; /* scan image and account for all pixels of this color */ for(r=0; rhigh_r) high_r = r; if(chigh_c) high_c = c; } /* print out summary features of object of this color */ cout.width(5); cout << " " << colortable[Ncolor]; cout.width(8); cout << number_of_pixels << " ("; cout.width(5);cout.precision(3); cout << rowsum/number_of_pixels << " , " << colsum/number_of_pixels << ")"; cout.width(4); cout.precision(4); cout << " [ (" << low_r << ", " << low_c << ") (" << high_r << ", " << high_c << ") ]" << endl; } /* end of for color loop */ } /*============================MAIN PROGRAM============================*/ main () { int error_code, objectcount; error_code = input_image (); if( error_code != 0 ) { cout << " ERROR EXIT " << endl; return(0); } output_image(); cout << " Recall that image MUST have a border of all '0's " << endl; /* Now color each object with a different color(pixel value). */ objectcount = color_image( ); cout << " Number of objects = " << objectcount-1 << endl; cout << " Recall that no object has color label = 1 " << endl; output_image(); /* scan the colored image to compute the centroid and bounding boxes */ report_object_features(); }