#include "image_classes.h" #include // Function to compute the hough transform. Result // is stored in the accumulator[][][] array. This // array is not destroyed until the destructor is // called void HoughCircle::ComputeTransform() { int r, a, b, i; int x, y; unsigned char *edge_image; EdgeDetector ef; // Allocate a 3D array for the accumulator accumulator = (int ***) malloc(max_r * sizeof(int **)); for (r = 0; r < max_r; r++) { accumulator[r] = (int **) malloc(max_a * sizeof(int *)); for (a = 0; a < max_a; a++) accumulator[r][a] = (int *)calloc(max_b, sizeof(int)); } // Do edge detection using the EdgeDetector class ef.SetImage(in_image, width, height); if (use_direction) edge_image = ef.FindEdgesUsingGradientDirection(edge_threshold, edge_direction); else edge_image = ef.FindEdgesUsingGradient(edge_threshold); // Find edge pixels and draw cones in the hough space // corresponding to the edge pixels for (i = 0; i < numpixels; i++) { if (edge_image[i] > 0) // This is an edge pixel { // populate the accumulator array x = i%width; y = i/width; for (a = 0; a < max_a; a++) for (b = 0; b < max_b; b++) { r = (int) sqrt((x-a)*(x-a) + (y-b)*(y-b)); if ((r > 0) && (r < max_r)) ++accumulator[r][a][b]; } } } } // This function returns a slice of the hough transform. unsigned char *HoughCircle::GetHoughImage(int slice, int *w, int *h) { unsigned char *out_image; int a, b; if (accumulator == NULL) ComputeTransform(); out_image = (unsigned char *) malloc(numpixels); *w = max_a; *h = max_b; if ((slice > max_r) || (slice < 0)) // illegal value test slice = max_r; for (a = 0; a < max_a; a++) for (b = 0; b < max_b; b++) out_image[b*max_a + a] = accumulator[slice][a][b]; return out_image; } // This function does the actual circle detection by // scanning the accumulator array for a local maxima void HoughCircle::DetectCircles() { int a, b, r; int da, db, dr; int maxima, max_value=0; if (accumulator == NULL) ComputeTransform(); // Search hough space for the maximum value for (r = 3; r < 12; r++) for (a = 2; a < max_a-2; a++) for (b = 2; b < max_b-2; b++) if (accumulator[r][a][b] > max_value) max_value = accumulator[r][a][b]; // Look for a local maxima in the accumulator array for (r = 4; r < 12; r++) for (a = 4; a < max_a-4; a++) for (b = 4; b < max_b-4; b++) { if (accumulator[r][a][b] > 0.6*max_value) // value is among highest 40% { maxima = TRUE; // Check a 9x9x9 window (cube!) for (dr = r-4; dr < r+5; dr++) for (da = a-4; da < a+5; da++) for (db = b-4; db < b+5; db++) if (accumulator[dr][da][db] > accumulator[r][a][b]) maxima = FALSE; if (maxima) { // draw a 2 pixel thick circle DrawCircle(edge_image, a, b, r); DrawCircle(edge_image, a, b, r + 1); } } } } // Function to draw a circle with the given center and radius void HoughCircle::DrawCircle(unsigned char *image, int xc, int yc, int r) { int x = 0; int y = r; int d = 1 - r; while (y > x) { if (d<0) d += 2*x + 3; else { d += 2*(x-y) + 5; y--; } x++; // Check to see if the circle lies completely // within the image. if (((xc-r) < 0) || ((xc+r) > width) || ((yc-r) < 0) || ((yc+r) > height)) return; image[(y+yc)*width + (x+xc)] = 255; image[(x+yc)*width + (y+xc)] = 255; image[(-x+yc)*width + (y+xc)] = 255; image[(-y+yc)*width + (x+xc)] = 255; image[(-y+yc)*width + (-x+xc)] = 255; image[(-x+yc)*width + (-y+xc)] = 255; image[(x+yc)*width + (-y+xc)] = 255; image[(y+yc)*width + (-x+xc)] = 255; } } // Function sets the image and its dimensions void HoughCircle::SetImage(unsigned char *image, int w, int h) { width = w; height = h; numpixels = width * height; max_r = width/2; max_a = width; max_b = height; in_image = (unsigned char *) malloc(numpixels); memcpy(in_image, image, numpixels); edge_image = (unsigned char *) calloc(numpixels, 1); } // This function returns the binary edge image // containing just the detected circles unsigned char *HoughCircle::GetEdgeImage() { unsigned char *out_image; out_image = (unsigned char *)malloc(numpixels); memcpy(out_image, edge_image, numpixels); return out_image; } // This function superimposes the detected circles // onto the original image unsigned char *HoughCircle::GetSuperimposedImage() { int i; unsigned char *out_image; out_image = (unsigned char *) malloc(numpixels); memcpy(out_image, in_image, numpixels); for (i = 0; i < numpixels; i++) if (edge_image[i] > 0) out_image[i] = 255; return out_image; } // The constructor; HoughCircle::HoughCircle() { in_image = NULL; edge_image = NULL; accumulator = NULL; edge_threshold = 25; } // The destructor. Frees up the memory allocated for // the accumulator array. HoughCircle::~HoughCircle() { int r, a; if (in_image != NULL) free (in_image); if (edge_image != NULL) free (edge_image); if (accumulator != NULL) { for (r = 0; r < max_r; r++) { for (a = 0; a < max_a; a++) free (accumulator[r][a]); free(accumulator[r]); } } }