/* Bruce A. Maxwell This program is an implementation of a 2-pass segmentation algorithm on a binary OpenCV 8U1 image. 0 is background, not zero is foreground. */ #include #include #include "opencv2/opencv.hpp" #include "segment.h" // uncomment to generate some debug statements //#define DEBUG /* */ int locateRegions(cv::Mat &src, cv::Mat ®map, const long sizeThresh, cv::Mat ¢roid, cv::Mat &bbox, cv::Mat &size, const int MaxLocations ) { // statics to reduce setup time when calling the function a lot static long *boundto = NULL; static long *regcard = NULL; // local variables const long imageSize = src.rows * src.cols; long i, j, k; unsigned char backpix, uppix, curpix; long nRegions=0; long *bt, *reg; unsigned long upID, backID; long *sizeid; long numLocations = MaxLocations; // static variable allocations if(boundto == NULL) boundto = (long *)malloc(sizeof(long) * imageSize/4); if(regcard == NULL) regcard = (long *)malloc(sizeof(long) * imageSize/4); // dynamic variable allocations sizeid = (long *)malloc(sizeof(long) * MaxLocations ); // allocate the region map (doesn't allocate more than once if already the right size) // initialize the region map to -1 regmap.create( src.rows, src.cols, CV_32SC1); regmap = -1; // initialize the region map and boundto variables #ifdef DEBUG printf("Initializing arrays\n"); #endif reg = regcard; bt = boundto; for(i=0;i(i, j); // if the current pixel is foreground if(curpix) { // get the up pixel uppix = i > 0 ? src.at(i-1, j) : 0; // test if up-pixel is foreground if(uppix) { // test if back-pixel is foreground if(backpix) { // similar to back pixel as well so get the region IDs upID = regmap.at(i-1, j); backID = regmap.at(i, j-1); if(backID == upID) { // equal region ids regmap.at(i, j) = upID; } else { // not equal region ids if(boundto[upID] < boundto[backID]) { regmap.at(i, j) = boundto[upID]; boundto[backID] = boundto[upID]; } else { regmap.at(i, j) = boundto[backID]; boundto[upID] = boundto[backID]; } } } else { // similar only to the top pixel regmap.at(i, j) = regmap.at(i-1, j); } } else if(backpix) { // similar only to back pixel regmap.at(i, j) = regmap.at(i, j-1); } else { // not similar to either pixel regmap.at(i, j) = nRegions++; } } backpix = curpix; } } // get out if there's nothing else to do if(nRegions == 0) { #ifdef DEBUG printf("No regions\n"); #endif return(0); } #ifdef DEBUG printf("Fixing IDs\n"); #endif // second pass, fix the IDs and calculate the region sizes for(i=0;i(i, j) >= 0) { regmap.at(i, j) = boundto[regmap.at(i, j)]; // need to follow the tree in some special cases while(boundto[regmap.at(i, j)] != regmap.at(i, j)) regmap.at(i, j) = boundto[regmap.at(i, j)]; regcard[regmap.at(i, j)]++; } } } #ifdef DEBUG printf("Calculating the N largest regions\n"); #endif size.create(numLocations, 1, CV_32SC1); // grab the N largest ones for(i=0;i(i, 0) = 0; sizeid[i] = -1; for(j=0;j sizeThresh) && (regcard[j] > size.at(i, 0))) { size.at(i, 0) = regcard[j]; sizeid[i] = j; } } if(size.at(i, 0) == 0) { break; } } numLocations = i; #ifdef DEBUG printf("Calculating centroids for %ld regions\n", numLocations); for(i=0;i(i, 0)); } #endif // now calculate centroids and bounding boxes bbox.create(numLocations, 4, CV_32SC1); centroid.create(numLocations, 2, CV_32SC1); centroid = 0; for(i=0;i(i, 0) = bbox.at(i, 1) = 10000; bbox.at(i, 2) = bbox.at(i, 3) = 0; } for(j=0;j(j, k) == sizeid[i]) { centroid.at(i, 0) += j; // rows centroid.at(i, 1) += k; // columns bbox.at(i, 0) = j < bbox.at(i, 0) ? j : bbox.at(i, 0); bbox.at(i, 1) = k < bbox.at(i, 1) ? k : bbox.at(i, 1); bbox.at(i, 2) = j > bbox.at(i, 2) ? j : bbox.at(i, 2); bbox.at(i, 3) = k > bbox.at(i, 3) ? k : bbox.at(i, 3); regmap.at(j, k) = i; break; } } if(i == numLocations) { regmap.at(j, k) = -1; } } } for(i=0;i(i, 0) /= size.at(i, 0); centroid.at(i, 1) /= size.at(i, 0); } #ifdef DEBUG printf("Terminating normally\n"); #endif free(sizeid); return(numLocations); }