//************************************************************************** #include <iostream.h> #include <fstream.h> #include <math.h> #include "image.h" #include "region.h" //************************************************************************** #define MAX_NUM_OF_REGIONS 500 #define JOIN_DIST_FACTOR 0.5 static Region R[MAX_NUM_OF_REGIONS]; static int numRegions; static GrayImage tagImage; //************************************************************************** void makeRegions(Matrix &Im, int thresholdsize) { Matrix img; numRegions = 0; img = Im; tagImage.Init(img.nx, img.ny, 255); cout << "Making regions....."; cout.flush(); for (int i = 0; i < img.nx; i++) for (int j = 0; j < img.ny; j++) { if (img.isBoundaryPixel(i,j)) { R[numRegions].reInitialize(); R[numRegions].Insert(i,j, img.p[i][j]); img.p[i][j] = 0.0; tagImage.p[i][j] = (unsigned char) numRegions; followAndfillRegion(&R[numRegions], &img); if (R[numRegions].size() >= thresholdsize) ++numRegions; if (numRegions == MAX_NUM_OF_REGIONS) { cout << "Max number of regions reached!!" << endl; // break; i = img.nx; j = img.ny; } } } cout << "done (" << numRegions << " regions created)" << endl; cout.flush(); //printRegionLengths(); } //************************************************************************** void followAndfillRegion(Region *R, Matrix *img) { Pixel P = (*R)(); int x = P.x; int y = P.y; float strength = P.strength; double err = 1.0e+30; int im = -1, jm = -1; int height = img->nx; int width = img->ny; for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) { int xn = x + i; int yn = y + j; if (xn >= 0 && xn < height && yn >=0 && yn < width && !(xn == x && yn == y) && img->p[xn][yn]) { float errlocal = fabs(strength - img->p[xn][yn]); if (err > errlocal) // find min err { err = errlocal; im = xn; jm = yn; } } } if (im >=0 && jm >= 0) // neighbouring pixel found { R->Insert(im, jm, img->p[im][jm]); img->p[im][jm] = 0.0; tagImage.p[im][jm] = (unsigned char) numRegions; followAndfillRegion(R, img); } } //************************************************************************** void makeRegions(GrayImage &Im, int thresholdsize) { Matrix img(Im.height, Im.width); Im.WriteToMatrix(&img); makeRegions(img, thresholdsize); } //************************************************************************** void writeAllRegions(GrayImage *img) { int height = img->height; int width = img->width; img->Zero(); for (int i = 0; i < numRegions; i++) { for (R[i].begin(); !R[i]; ++R[i]) { Pixel p = R[i](); img->p[p.x][p.y] = i+1; } } } //************************************************************************** void joinRegions(Region &r1, Region &r2, Region *final, int r_num) { Pixel pr1[2]; Pixel pr2[2]; pr1[0] = r1.head(); pr1[1] = r1.tail(); pr2[0] = r2.head(); pr2[1] = r2.tail(); int mindist = 100000; int min_i = -1; for (int i = 0; i < 4; i++) { int mydist = dist(pr1[i/2], pr2[i%2]); if (mydist < mindist) { mindist = mydist; min_i = i; } } final->reInitialize(); if (min_i/2 == 0) // Join head of r1 { Pixel *pR = new Pixel [r1.size()]; int k = 0; for (r1.begin(); !r1; ++r1) { pR[k] = r1(); ++k; } // insert in reverse order from tail to head for (int i = r1.size()-1; i >= 0; i--) final->Insert(pR[i]); delete pR; } else // Join tail of r1 { // insert in normal order from head to tail for (r1.begin(); !r1; ++r1) final->Insert(r1()); } // Fill the gap between the two regions (pixels pr1[min_i/2] and pr2[min_i%2]) insertLine(final, pr1[min_i/2], pr2[min_i%2], r_num); if (min_i%2 == 0) // Join head of r2 { // insert in normal order from head to tail for (r2.begin(); !r2; ++r2) final->Insert(r2()); } else // Join tail of r2 { Pixel *pR = new Pixel [r2.size()]; int k = 0; for (r2.begin(); !r2; ++r2) { pR[k] = r2(); ++k; } // insert in reverse order from tail to head for (int i = r2.size()-1; i >= 0; i--) final->Insert(pR[i]); delete pR; } } //************************************************************************** // MidPointLine algorithm from Foley & Van Dam pg 78 void insertLine(Region *r, Pixel &p0, Pixel &p1, int value) { int n = dist(p0, p1); for (int i = 1; i < n; i++) { double t = 1.0*i/n; int x = (int) (p0.x + t * (p1.x - p0.x)); int y = (int) (p0.y + t * (p1.y - p0.y)); r->Insert(x, y, (double) value); tagImage.p[x][y] = value; } //cout << "Inserting line between [" << p0.x << "," << p0.y << "] and [" // << p1.x << "," << p1.y << "] (" << n << " pixels)" << endl; } //************************************************************************** void joinRegions(void) { int k = 0; for (int i = 0; i < numRegions-1; i++) { if (R[i].isClosed() || R[i].size() == 0) continue; int n = FindNearestRegion(R[i], i); if (n == -1) continue; int newnum = numRegions+k; /* cout << "Creating region " << newnum+1 << " by joining regions " << i+1 << " and " << n+1 << endl; cout.flush(); */ joinRegions(R[i], R[n], &R[newnum], newnum); R[i].reInitialize(); R[n].reInitialize(); ++k; } numRegions += k; compactRegions(); } //************************************************************************** int FindNearestRegion(Region &r, int regnum) { int mindist = 100000; int minregnum = -1; for (int i = regnum+1; i < numRegions; i++) { if (R[i].isClosed()) continue; int mydist = dist(r, R[i]); if (mydist < mindist) { mindist = mydist; minregnum = i; } } if (mindist < JOIN_DIST_FACTOR*r.size()) return minregnum; else return -1; } //************************************************************************** int dist(Region &r1, Region &r2) { Pixel pr1[2]; Pixel pr2[2]; pr1[0] = r1.head(); pr1[1] = r1.tail(); pr2[0] = r2.head(); pr2[1] = r2.tail(); int mindist = 100000; for (int i = 0; i < 4; i++) { int mydist = dist(pr1[i/2], pr2[i%2]); if (mydist < mindist) mindist = mydist; } return mindist; } //************************************************************************** void printRegionLengths(void) { int n = 0; for (int i = 0; i < numRegions; i++) { if (R[i].size()) { cout << "Length of region " << i+1 << " = " << R[i].size() << endl; ++n; } } cout << "Number of non-zero regions = " << n << endl; cout.flush(); } //************************************************************************** int numNonzeroRegions(void) { int n = 0; for (int i = 0; i < numRegions; i++) { if (R[i].size()) ++n; } return n; } //************************************************************************** void compactRegions(void) { int n = numNonzeroRegions(); Region *Rnew = new Region [n]; int count = 0; for (int i = 0; i < numRegions; i++) { if (R[i].size()) { Rnew[count] = R[i]; ++count; R[i].reInitialize(); } } numRegions = count; for (int i = 0; i < numRegions; i++) { R[i] = Rnew[i]; } delete Rnew; } //************************************************************************** Region &Region::operator= (Region &Reg) { closed = Reg.closed; length = 0; for (Reg.begin(); !Reg; ++Reg) Insert(Reg()); if (length != Reg.length) { cerr << "Region: operator= Error!!" << endl; exit(-1); } return *this; } //************************************************************************** void refineRegions(int reg_size, int n) { for (int i = 0; i < n; i++) joinRegions(); GrayImage dummy; int height = tagImage.height; int width = tagImage.width; dummy.Init(height, width, 255); writeAllRegions(&dummy); makeRegions(dummy, 2*reg_size); joinRegions(); } //**************************************************************************