test-hough.C

Go to the documentation of this file.
00001 /*!@file BeoSub/test-hough.C */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file:
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/test-hough.C $
00035 // $Id: test-hough.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 #ifndef BEOSUB_TEST_HOUGH_C_DEFINED
00039 #define BEOSUB_TEST_HOUGH_C_DEFINED
00040 
00041 #include "GUI/XWindow.H"
00042 //CAMERA STUFF
00043 #include "Image/Image.H"
00044 #include "Image/Pixels.H"
00045 
00046 #include "Component/ModelManager.H"
00047 #include "Devices/FrameGrabberFactory.H"
00048 #include "Util/Timer.H"
00049 #include "Util/Types.H"
00050 #include "Util/log.H"
00051 #include "Image/ColorOps.H"
00052 #include "Image/Image.H"
00053 #include "Image/MathOps.H"
00054 #include "Image/DrawOps.H"
00055 #include "Image/FilterOps.H"
00056 #include "Image/Transforms.H"
00057 #include "Raster/Raster.H"
00058 #include "rutz/shared_ptr.h"
00059 #include "BeoSub/hysteresis.H"
00060 #include "VFAT/segmentImageTrackMC.H"
00061 #include <cstdio>
00062 #include <cstdlib>
00063 #include <cstring>
00064 #include <iostream> //needed for segmentImageTrackMC!
00065 #include <math.h>
00066 #include <list>
00067 #include "Image/MatrixOps.H"
00068 
00069 #include "MBARI/Geometry2D.H"
00070 #include "rutz/compat_cmath.h" // for isnan()
00071 
00072 using std::cout;
00073 using std::endl;
00074 using std::list;
00075 
00076 //END CAMERA STUFF
00077 //canny
00078 #define BOOSTBLURFACTOR 90.0
00079 #define FREE_ARG char*
00080 #define PI 3.14
00081 
00082 XWindow *xwin;
00083 XWindow *xwin2;
00084 XWindow *xwin3;
00085 
00086 void gaussian_smooth(unsigned char *image, int rows, int cols, float sigma,
00087         short int **smoothedim);
00088 void make_gaussian_kernel(float sigma, float **kernel, int *windowsize);
00089 void derrivative_x_y(short int *smoothedim, int rows, int cols,
00090                      short int **delta_x, short int **delta_y);
00091 void magnitude_x_y(short int *delta_x, short int *delta_y, int rows, int cols,
00092                    short int **magnitude);
00093 void radian_direction(short int *delta_x, short int *delta_y, int rows,
00094                       int cols, float **dir_radians, int xdirtag, int ydirtag);
00095 void radian_direction(short int *delta_x, short int *delta_y, int rows,
00096                       int cols, float **dir_radians, int xdirtag, int ydirtag);
00097 double angle_radians(double x, double y);
00098 
00099 std::vector <LineSegment2D> houghTransform(Image<byte> &inputImage, float thetaRes, float dRes, int threshold, Image< PixRGB<byte> > &output) ;
00100 
00101 /*******************************************************************************
00102 * PROCEDURE: canny
00103 * PURPOSE: To perform canny edge detection.
00104 * NAME: Mike Heath
00105 * DATE: 2/15/96
00106 //Pradeep: returns the centroid of the "white" pixels
00107 *******************************************************************************/
00108 int canny(unsigned char *image, int rows, int cols, float sigma,
00109          float tlow, float thigh, unsigned char **edge, char *fname)
00110 {
00111         FILE *fpdir=NULL;          /* File to write the gradient image to.     */
00112         unsigned char *nms;        /* Points that are local maximal magnitude. */
00113         short int *smoothedim,     /* The image after gaussian smoothing.      */
00114                               *delta_x,        /* The first devivative image, x-direction. */
00115                               *delta_y,        /* The first derivative image, y-direction. */
00116                               *magnitude;      /* The magnitude of the gadient image.      */
00117                               float *dir_radians=NULL;   /* Gradient direction image.                */
00118 
00119    /****************************************************************************
00120                               * Perform gaussian smoothing on the image using the input standard
00121                               * deviation.
00122    ****************************************************************************/
00123                               gaussian_smooth(image, rows, cols, sigma, &smoothedim);
00124 
00125 
00126    /****************************************************************************
00127                               * Compute the first derivative in the x and y directions.
00128    ****************************************************************************/
00129                               derrivative_x_y(smoothedim, rows, cols, &delta_x, &delta_y);
00130 
00131 
00132 
00133 
00134    /****************************************************************************
00135                               * This option to write out the direction of the edge gradient was added
00136                               * to make the information available for computing an edge quality figure
00137                               * of merit.
00138    ****************************************************************************/
00139                               if(fname != NULL){
00140       /*************************************************************************
00141                                       * Compute the direction up the gradient, in radians that are
00142                                       * specified counteclockwise from the positive x-axis.
00143       *************************************************************************/
00144                                       radian_direction(delta_x, delta_y, rows, cols, &dir_radians, -1, -1);
00145 
00146       /*************************************************************************
00147                                       * Write the gradient direction image out to a file.
00148       *************************************************************************/
00149                                       if((fpdir = fopen(fname, "wb")) == NULL){
00150                                               fprintf(stderr, "Error opening the file %s for writing.\n", fname);
00151                                               exit(1);
00152                                       }
00153                                       fwrite(dir_radians, sizeof(float), rows*cols, fpdir);
00154                                       fclose(fpdir);
00155                                       free(dir_radians);
00156                               }
00157 
00158    /****************************************************************************
00159                               * Compute the magnitude of the gradient.
00160    ****************************************************************************/
00161                               magnitude_x_y(delta_x, delta_y, rows, cols, &magnitude);
00162 
00163    /****************************************************************************
00164                               * Perform non-maximal suppression.
00165    ****************************************************************************/
00166                               if((nms = (unsigned char *) calloc(rows*cols,sizeof(unsigned char)))==NULL){
00167                                       fprintf(stderr, "Error allocating the nms image.\n");
00168                                       exit(1);
00169                               }
00170 
00171                               non_max_supp(magnitude, delta_x, delta_y, rows, cols, nms);
00172 
00173    /****************************************************************************
00174                               * Use hysteresis to mark the edge pixels.
00175    ****************************************************************************/
00176                               if((*edge=(unsigned char *)calloc(rows*cols,sizeof(unsigned char))) ==NULL){
00177                                       fprintf(stderr, "Error allocating the edge image.\n");
00178                                       exit(1);
00179                               }
00180    //printf("\n%d %d %d %d %d %d\n", magnitude, nms, rows, cols, tlow, thigh);
00181                               int centroid = apply_hysteresis(magnitude, nms, rows, cols, tlow, thigh, *edge);
00182    /****************************************************************************
00183                               * Free all of the memory that we allocated except for the edge image that
00184                               * is still being used to store out result.
00185    ****************************************************************************/
00186                               free(smoothedim);
00187                               free(delta_x);
00188                               free(delta_y);
00189                               free(magnitude);
00190                               free(nms);
00191                               return centroid;
00192 }
00193 
00194 /*******************************************************************************
00195 * Procedure: radian_direction
00196 * Purpose: To compute a direction of the gradient image from component dx and
00197 * dy images. Because not all derriviatives are computed in the same way, this
00198 * code allows for dx or dy to have been calculated in different ways.
00199 *
00200 * FOR X:  xdirtag = -1  for  [-1 0  1]
00201 *         xdirtag =  1  for  [ 1 0 -1]
00202 *
00203 * FOR Y:  ydirtag = -1  for  [-1 0  1]'
00204 *         ydirtag =  1  for  [ 1 0 -1]'
00205 *
00206 * The resulting angle is in radians measured counterclockwise from the
00207 * xdirection. The angle points "up the gradient".
00208 *******************************************************************************/
00209 void radian_direction(short int *delta_x, short int *delta_y, int rows,
00210                       int cols, float **dir_radians, int xdirtag, int ydirtag)
00211 {
00212         int r, c, pos;
00213         float *dirim=NULL;
00214         double dx, dy;
00215 
00216    /****************************************************************************
00217         * Allocate an image to store the direction of the gradient.
00218    ****************************************************************************/
00219         if((dirim = (float *) calloc(rows*cols, sizeof(float))) == NULL){
00220                 fprintf(stderr, "Error allocating the gradient direction image.\n");
00221                 exit(1);
00222         }
00223         *dir_radians = dirim;
00224 
00225         for(r=0,pos=0;r<rows;r++){
00226                 for(c=0;c<cols;c++,pos++){
00227                         dx = (double)delta_x[pos];
00228                         dy = (double)delta_y[pos];
00229 
00230                         if(xdirtag == 1) dx = -dx;
00231                         if(ydirtag == -1) dy = -dy;
00232 
00233                         dirim[pos] = (float)angle_radians(dx, dy);
00234                 }
00235         }
00236 }
00237 
00238 /*******************************************************************************
00239 * FUNCTION: angle_radians
00240 * PURPOSE: This procedure computes the angle of a vector with components x and
00241 * y. It returns this angle in radians with the answer being in the range
00242 * 0 <= angle <2*PI.
00243 *******************************************************************************/
00244 double angle_radians(double x, double y)
00245 {
00246         double xu, yu, ang;
00247 
00248         xu = fabs(x);
00249         yu = fabs(y);
00250 
00251         if((xu == 0) && (yu == 0)) return(0);
00252 
00253         ang = atan(yu/xu);
00254 
00255         if(x >= 0){
00256                 if(y >= 0) return(ang);
00257                 else return(2*M_PI - ang);
00258         }
00259         else{
00260                 if(y >= 0) return(M_PI - ang);
00261                 else return(M_PI + ang);
00262         }
00263 }
00264 
00265 /*******************************************************************************
00266 * PROCEDURE: magnitude_x_y
00267 * PURPOSE: Compute the magnitude of the gradient. This is the square root of
00268 * the sum of the squared derivative values.
00269 * NAME: Mike Heath
00270 * DATE: 2/15/96
00271 *******************************************************************************/
00272 void magnitude_x_y(short int *delta_x, short int *delta_y, int rows, int cols,
00273                    short int **magnitude)
00274 {
00275         int r, c, pos, sq1, sq2;
00276 
00277    /****************************************************************************
00278         * Allocate an image to store the magnitude of the gradient.
00279    ****************************************************************************/
00280         if((*magnitude = (short *) calloc(rows*cols, sizeof(short))) == NULL){
00281                 fprintf(stderr, "Error allocating the magnitude image.\n");
00282                 exit(1);
00283         }
00284 
00285         for(r=0,pos=0;r<rows;r++){
00286                 for(c=0;c<cols;c++,pos++){
00287                         sq1 = (int)delta_x[pos] * (int)delta_x[pos];
00288                         sq2 = (int)delta_y[pos] * (int)delta_y[pos];
00289                         (*magnitude)[pos] = (short)(0.5 + sqrt((float)sq1 + (float)sq2));
00290                 }
00291         }
00292 
00293 }
00294 
00295 /*******************************************************************************
00296 * PROCEDURE: derrivative_x_y
00297 * PURPOSE: Compute the first derivative of the image in both the x any y
00298 * directions. The differential filters that are used are:
00299 *
00300 *                                          -1
00301 *         dx =  -1 0 +1     and       dy =  0
00302 *                                          +1
00303 *
00304 * NAME: Mike Heath
00305 * DATE: 2/15/96
00306 *******************************************************************************/
00307 void derrivative_x_y(short int *smoothedim, int rows, int cols,
00308                      short int **delta_x, short int **delta_y)
00309 {
00310         int r, c, pos;
00311 
00312    /****************************************************************************
00313         * Allocate images to store the derivatives.
00314    ****************************************************************************/
00315         if(((*delta_x) = (short *) calloc(rows*cols, sizeof(short))) == NULL){
00316                 fprintf(stderr, "Error allocating the delta_x image.\n");
00317                 exit(1);
00318         }
00319         if(((*delta_y) = (short *) calloc(rows*cols, sizeof(short))) == NULL){
00320                 fprintf(stderr, "Error allocating the delta_x image.\n");
00321                 exit(1);
00322         }
00323 
00324    /****************************************************************************
00325         * Compute the x-derivative. Adjust the derivative at the borders to avoid
00326         * losing pixels.
00327    ****************************************************************************/
00328         for(r=0;r<rows;r++){
00329                 pos = r * cols;
00330                 (*delta_x)[pos] = smoothedim[pos+1] - smoothedim[pos];
00331                 pos++;
00332                 for(c=1;c<(cols-1);c++,pos++){
00333                         (*delta_x)[pos] = smoothedim[pos+1] - smoothedim[pos-1];
00334                 }
00335                 (*delta_x)[pos] = smoothedim[pos] - smoothedim[pos-1];
00336         }
00337 
00338    /****************************************************************************
00339         * Compute the y-derivative. Adjust the derivative at the borders to avoid
00340         * losing pixels.
00341    ****************************************************************************/
00342         for(c=0;c<cols;c++){
00343                 pos = c;
00344                 (*delta_y)[pos] = smoothedim[pos+cols] - smoothedim[pos];
00345                 pos += cols;
00346                 for(r=1;r<(rows-1);r++,pos+=cols){
00347                         (*delta_y)[pos] = smoothedim[pos+cols] - smoothedim[pos-cols];
00348                 }
00349                 (*delta_y)[pos] = smoothedim[pos] - smoothedim[pos-cols];
00350         }
00351 }
00352 
00353 /*******************************************************************************
00354 * PROCEDURE: gaussian_smooth
00355 * PURPOSE: Blur an image with a gaussian filter.
00356 * NAME: Mike Heath
00357 * DATE: 2/15/96
00358 *******************************************************************************/
00359 void gaussian_smooth(unsigned char *image, int rows, int cols, float sigma,
00360                      short int **smoothedim)
00361 {
00362         int r, c, rr, cc,     /* Counter variables. */
00363         windowsize,        /* Dimension of the gaussian kernel. */
00364         center;            /* Half of the windowsize. */
00365         float *tempim,        /* Buffer for separable filter gaussian smoothing. */
00366                          *kernel,        /* A one dimensional gaussian kernel. */
00367                          dot,            /* Dot product summing variable. */
00368                          sum;            /* Sum of the kernel weights variable. */
00369 
00370    /****************************************************************************
00371                          * Create a 1-dimensional gaussian smoothing kernel.
00372    ****************************************************************************/
00373                          make_gaussian_kernel(sigma, &kernel, &windowsize);
00374                          center = windowsize / 2;
00375 
00376    /****************************************************************************
00377                          * Allocate a temporary buffer image and the smoothed image.
00378    ****************************************************************************/
00379                          if((tempim = (float *) calloc(rows*cols, sizeof(float))) == NULL){
00380                                  fprintf(stderr, "Error allocating the buffer image.\n");
00381                                  exit(1);
00382                          }
00383                          if(((*smoothedim) = (short int *) calloc(rows*cols,
00384                                sizeof(short int))) == NULL){
00385                                        fprintf(stderr, "Error allocating the smoothed image.\n");
00386                                        exit(1);
00387                                }
00388 
00389    /****************************************************************************
00390                                * Blur in the x - direction.
00391    ****************************************************************************/
00392                                for(r=0;r<rows;r++){
00393                                        for(c=0;c<cols;c++){
00394                                                dot = 0.0;
00395                                                sum = 0.0;
00396                                                for(cc=(-center);cc<=center;cc++){
00397                                                        if(((c+cc) >= 0) && ((c+cc) < cols)){
00398                                                                dot += (float)image[r*cols+(c+cc)] * kernel[center+cc];
00399                                                                sum += kernel[center+cc];
00400                                                        }
00401                                                }
00402                                                tempim[r*cols+c] = dot/sum;
00403                                        }
00404                                }
00405 
00406    /****************************************************************************
00407                                * Blur in the y - direction.
00408    ****************************************************************************/
00409                                for(c=0;c<cols;c++){
00410                                        for(r=0;r<rows;r++){
00411                                                sum = 0.0;
00412                                                dot = 0.0;
00413                                                for(rr=(-center);rr<=center;rr++){
00414                                                        if(((r+rr) >= 0) && ((r+rr) < rows)){
00415                                                                dot += tempim[(r+rr)*cols+c] * kernel[center+rr];
00416                                                                sum += kernel[center+rr];
00417                                                        }
00418                                                }
00419                                                (*smoothedim)[r*cols+c] = (short int)(dot*BOOSTBLURFACTOR/sum + 0.5);
00420                                        }
00421                                }
00422 
00423                                free(tempim);
00424                                free(kernel);
00425 }
00426 
00427 /*******************************************************************************
00428 * PROCEDURE: make_gaussian_kernel
00429 * PURPOSE: Create a one dimensional gaussian kernel.
00430 * NAME: Mike Heath
00431 * DATE: 2/15/96
00432 *******************************************************************************/
00433 void make_gaussian_kernel(float sigma, float **kernel, int *windowsize)
00434 {
00435         int i, center;
00436         float x, fx, sum=0.0;
00437 
00438         *windowsize = int(1 + 2 * ceil(2.5 * sigma));
00439         center = (*windowsize) / 2;
00440 
00441         if((*kernel = (float *) calloc((*windowsize), sizeof(float))) == NULL){
00442                 fprintf(stderr, "Error callocing the gaussian kernel array.\n");
00443                 exit(1);
00444         }
00445 
00446         for(i=0;i<(*windowsize);i++){
00447                 x = (float)(i - center);
00448                 fx = pow(2.71828, -0.5*x*x/(sigma*sigma)) / (sigma * sqrt(6.2831853));
00449                 (*kernel)[i] = fx;
00450                 sum += fx;
00451         }
00452 
00453         for(i=0;i<(*windowsize);i++) (*kernel)[i] /= sum;
00454 
00455 }
00456 
00457 
00458 
00459 //finds the line by using hough transform
00460 //thetares is the resolution of each theta
00461 //dRes is the resolution of the D
00462 //returns the number of lines found
00463 std::vector <LineSegment2D> houghTransform(Image<byte> &inputImage, float thetaRes, float dRes, int threshold, Image< PixRGB<byte> > &output)
00464 {
00465         int r;
00466         //get the total number of angles and D from the resolution of theta and D's
00467         int numangle = (int) (PI / thetaRes); //in radians
00468         int numD = (int) (((inputImage.getWidth() + inputImage.getHeight()) * 2 + 1) / dRes);
00469 
00470         std::vector <LineSegment2D> lines;
00471    cout << "Performing Hough Line Transform:" << endl;
00472    cout << "numD: " << numD << endl;
00473    cout << "numangle: " << numangle << endl;
00474 
00475         //accumulator -> represents the hough space
00476         int accumulator[numD][numangle];
00477 
00478         for(int i = 0; i<numD; i++)
00479           for(int j = 0; j < numangle; j++)
00480             accumulator[i][j] = 0;
00481 
00482         //equation of the line is Xcos(theta)+ysin(theta) = D
00483         // fill the accumulator
00484         //        printf("numD is %d\n",numD);
00485     for(int j = 0; j < inputImage.getHeight(); j++ )
00486         for(int i = 0; i < inputImage.getWidth(); i++ )
00487         {
00488             if( inputImage.getVal(i,j) != 0 )//point is an edge
00489                 for(int n = 0; n < numangle; n++ )//get all possible D and theta that can fit to that point
00490                 {
00491                     r =  (int)(i * cos(n*thetaRes) + j * sin(n*thetaRes));
00492                     r += (numD -1)/2;
00493                     accumulator[r][n]++;
00494                 }
00495         }
00496 
00497     Point2D<int> p1;
00498     Point2D<int> p2;
00499     Point2D<int> storage[inputImage.getWidth()*inputImage.getHeight()];
00500     double a;
00501     int totalLines = 0;
00502     int pointCount = 0;
00503 
00504     // find the peaks, ie any number greater than the threshold is considered a line
00505     for(int i = 0; i<numD; i++)
00506       for(int j = 0; j < numangle; j++)
00507         {
00508           if(accumulator[i][j] > threshold && accumulator[i][j]> accumulator[i-1][j]
00509              && accumulator[i][j]> accumulator[i+1][j] && accumulator[i][j]> accumulator[i][j-1]
00510              && accumulator[i][j]> accumulator[i][j+1])//found a peak
00511             {
00512               totalLines++;
00513 
00514               //get the image coordinates for the 2 endpoint of the line
00515               a = cos(j*thetaRes);
00516               // b = sin(j*thetaRes);
00517 
00518               for(int x = 0; x < inputImage.getWidth(); x++)
00519                 for(int y = 0; y < inputImage.getHeight(); y++)
00520                   if( inputImage.getVal(x,y) != 0 )//point is an edge
00521                     if(((int)(x * cos(j*thetaRes) + y * sin(j*thetaRes))) + ((numD -1)/2) == i)
00522                       {
00523                         storage[pointCount].i = x;
00524                         storage[pointCount].j = y;
00525                         pointCount++;
00526                       }
00527 
00528               //check the distance between each point
00529               bool isolated = true;
00530               int numtoDiscard = 0;
00531               float discardPoints[inputImage.getWidth() * inputImage.getHeight()];
00532               for(int y = 0; y < pointCount; y++){
00533                 for(int x = 0; x <pointCount; x++){
00534                   if(storage[0].distance(storage[x]) < 1 && x != y)
00535                     isolated = false;
00536 
00537                 }
00538                 if(isolated)//discard this point
00539                   {
00540                     discardPoints[numtoDiscard++] = y;
00541                   }
00542               }
00543 
00544 
00545 
00546               //make sure that the point is not in the to be discarded list
00547               for(int x=0; x < numtoDiscard; x++)
00548                 for(int y = 0; y < pointCount; y++)
00549                   if(discardPoints[x] != y){
00550                     p1.i = p2.i = storage[y].i;
00551                     p1.j = p2.j = storage[y].j;
00552 
00553                   }
00554               //find the 2 endpoints of line
00555               //check if vertical
00556               if(fabs(a) < .001)
00557                 {
00558 
00559                   //search the 2 endpoints
00560                   for(int x = 0; x < pointCount; x++)
00561                     {
00562                       bool discard = false;
00563                       for(int k = 0; k < numtoDiscard; k++)
00564                         if(discardPoints[k] == x)
00565                           discard = true;
00566                       if(!discard){
00567                         if(p1.j < storage[x].j)
00568                           {
00569                             p1.j = storage[x].j;
00570                             p1.i = storage[x].i;
00571                           }
00572                         if(p2.j > storage[x].j)
00573                           {
00574                           p2.j = storage[x].j;
00575                           p2.i = storage[x].i;
00576 
00577                           }
00578                       }
00579                     }
00580 
00581                 }
00582               else // horizontal
00583                 {
00584                   //search the 2 endpoints
00585                   for(int x = 0; x < pointCount; x++)
00586                     {
00587                       bool discard = false;
00588                       for(int k = 0; k < numtoDiscard; k++)
00589                         if(discardPoints[k] == x)
00590                           discard = true;
00591                       if(!discard){
00592 
00593                         if(p1.i < storage[x].i)
00594                           {
00595                             p1.j = storage[x].j;
00596                             p1.i = storage[x].i;
00597                           }
00598                         if(p2.i > storage[x].i)
00599                           {
00600                             p2.j = storage[x].j;
00601                             p2.i = storage[x].i;
00602 
00603                           }
00604                       }
00605                     }
00606                 }
00607               pointCount = 0;
00608               LineSegment2D thisLine(p1, p2);
00609               lines.push_back(thisLine);
00610              drawLine(output,p1, p2,  PixRGB<byte> (255,0,0), 1);
00611 
00612 
00613             }
00614         }
00615      return lines;
00616 
00617 }
00618 
00619 /*
00620 functions to find the best fit line
00621 */
00622 
00623 double sigma(double* r, int N) {
00624    double sum=0.0;
00625    for(int i=0;i<N;++i)
00626     sum += r[i];
00627    return(sum);
00628 }
00629 double sigma(double* r,double* s, int N) {
00630    double sum=0.0;
00631    for(int i=0;i<N;++i)
00632     sum += r[i]*s[i];
00633    return(sum);
00634 }
00635 void findTanLine(int N, double *x, double *y, float &slope, float &Intercept) {
00636    float delta=N*sigma(x,x, N)-pow(sigma(x,N),2.0);
00637    Intercept =  (1.0/delta)*(sigma(x,x,N)*sigma(y,N)-sigma(x,N)*sigma(x,y,N));
00638    slope =  (1.0/delta)*(N*sigma(x,y, N)-sigma(x, N)*sigma(y,N));
00639 }
00640 
00641 
00642 /* note that the utility functions below are taken from Robert A. Mclaughlin's code on RHT.
00643 Only slight modification is done to them
00644 */
00645 
00646 
00647 /* Find largest (absolute) entry in a 2x2 matrix.
00648  * Return co-ords of entry in (i,j) (row, column)
00649    -Robert A. McLaughlin
00650  */
00651 void
00652 find_biggest_entry_2x2(double m[][3], int *i, int *j)
00653 {
00654     if ((fabs(m[1][1]) > fabs(m[1][2])) && (fabs(m[1][1]) > fabs(m[2][1])) && (fabs(m[1][1]) > fabs(m[2][2])))
00655         {
00656         *i = 1;
00657         *j = 1;
00658         }
00659     else if ((fabs(m[1][2]) > fabs(m[2][1])) && (fabs(m[1][2]) > fabs(m[2][2])))
00660         {
00661         *i = 1;
00662         *j = 2;
00663         }
00664     else if (fabs(m[2][1]) > fabs(m[2][2]))
00665         {
00666         *i = 2;
00667         *j = 1;
00668         }
00669     else
00670         {
00671         *i = 2;
00672         *j = 2;
00673         }
00674 
00675 }   /* end of find_biggest_entry_2x2() */
00676 
00677 /*
00678  function that finds the eigenvectors
00679  -Robert A. McLaughlin
00680 */
00681 void
00682 find_eigenvectors_2x2_positive_semi_def_real_matrix(double **covar, double *eig_val, double **eig_vec)
00683 {
00684     double  a, b, c, d;
00685     int     i, j;
00686     double  tmp[3][3];
00687 
00688     /* Find eigenvalues
00689      * Use characteristic equation.
00690      */
00691     a = 1;
00692     b = -covar[1][1] - covar[2][2];
00693     c = covar[1][1]*covar[2][2] - covar[1][2]*covar[2][1];
00694 
00695     d = squareOf(b) - 4*a*c;
00696     if (d <= 10e-5)
00697         {
00698         eig_val[1] = -b / 2.0;
00699         eig_val[2] = -b / 2.0;
00700         eig_vec[1][1] = 1.0;  eig_vec[1][2] = 0.0;
00701         eig_vec[2][1] = 0.0;  eig_vec[2][2] = 1.0;
00702         }
00703     else
00704         {
00705         eig_val[1] = (-b + sqrt(d)) / 2.0;
00706         eig_val[2] = (-b - sqrt(d)) / 2.0;
00707 
00708         /* Put eigenvalues in descending order.
00709          */
00710         if (eig_val[1] < eig_val[2])
00711             {
00712             d = eig_val[1];
00713             eig_val[1] = eig_val[2];
00714             eig_val[2] = d;
00715             }
00716 
00717         /* Find first eigenvector.
00718          */
00719         tmp[1][1] = covar[1][1] - eig_val[1];
00720         tmp[1][2] = covar[1][2];
00721         tmp[2][1] = covar[2][1];
00722         tmp[2][2] = covar[2][2] - eig_val[1];
00723 
00724 
00725         find_biggest_entry_2x2(tmp, &i, &j);
00726         if (j == 1)
00727             {
00728             eig_vec[2][1] = 1.0;
00729             eig_vec[1][1] = -tmp[i][2] / tmp[i][1];
00730             }
00731         else    /* j == 2 */
00732             {
00733             eig_vec[1][1] = 1.0;
00734             eig_vec[2][1] = -tmp[i][1] / tmp[i][2];
00735             }
00736         /* Normalise eigenvecotr.
00737          */
00738         d = sqrt(squareOf(eig_vec[1][1]) + squareOf(eig_vec[2][1]));
00739         eig_vec[1][1] /= d;
00740         eig_vec[2][1] /= d;
00741 
00742 
00743         /* Find secind eigenvector.
00744          */
00745         eig_vec[1][2] = -eig_vec[2][1];
00746         eig_vec[2][2] = eig_vec[1][1];
00747 
00748         }
00749 
00750 
00751 
00752 }   /* end of find_eigenvectors_2x2_positive_semi_def_real_matrix() */
00753 
00754 
00755 void
00756 SwapRows(double *A, double *B, int els)
00757 {
00758     double temp;
00759     int a;
00760 
00761     for(a=1;a<=els;a++)
00762         {
00763         temp=A[a];
00764         A[a]=B[a];
00765         B[a]=temp;
00766         }
00767 }   /* end of SwapRows() */
00768 
00769 
00770 void
00771 TakeWeightRow(double *A, double *B, double num, double denom, int els)
00772 {
00773     int a;
00774 
00775     for(a=1;a<=els;a++)
00776         A[a]=(A[a]*denom-B[a]*num)/denom;
00777 
00778 }   /* end of TakeWeightRow() */
00779 
00780 void
00781 ScaleRow(double *A, double fact, int els)
00782 {
00783     int a;
00784 
00785     for(a=1;a<=els;a++)
00786         A[a]/=fact;
00787 
00788 }   /* end of ScaleRow() */
00789 double **
00790 alloc_array(int row, int column)
00791 {
00792     double  **rowp;
00793     int     a;
00794 
00795 
00796     if ( (rowp=(double **)malloc((unsigned )(row+1) * sizeof(double *)) ) == NULL)
00797         return(NULL);
00798     for(a=1;a<=row;a++)
00799         {
00800         if ((rowp[a]=(double *)malloc((unsigned)(column+1)*sizeof(double))) == NULL)
00801             return(NULL);
00802         }
00803 
00804     return(rowp);
00805 
00806 }   /* end of alloc_array() */
00807 
00808 
00809 void
00810 free_array(double **A, int row)
00811 {
00812     int i;
00813 
00814     for (i=1; i <= row; i++)
00815         free(A[i]);
00816     free(A);
00817 
00818 }       /* end of free_array() */
00819 
00820 double  *alloc_vector(int dim)
00821 {
00822     return( (double *)malloc(( (unsigned )(dim+1) ) * sizeof(double)) );
00823 }
00824 
00825 /*
00826   finds the inverse of matrix taken from -Robert A. McLaughlin's code
00827 */
00828 void
00829 find_inverse(double **MAT, double **I, int dim)
00830 {
00831 
00832     int     a,b,R;
00833     double  num,denom;
00834     double  **M;
00835 
00836     M = alloc_array(dim, dim);
00837     for (a=1; a<=dim; a++)
00838         for (b=1; b<=dim; b++)
00839            M[a][b] = MAT[a][b];
00840 
00841     for(R=1;R<=dim;R++)
00842         for(a=1;a<=dim;a++)
00843             I[R][a]=(R==a)?1:0;
00844     for(R=1;R<=dim;R++)
00845         {
00846         if(M[R][R]==0)
00847             {
00848             for(a=R+1;a<=dim;a++)
00849                 if (M[a][R]!=0) break;
00850             if (a==(dim+1))
00851                 {
00852                 fprintf(stderr, "Matrix non-invertable, fail on row %d left.\n",R);
00853                 fprintf(stderr, "in find_inverse() in lin_algebra.c\n");
00854                 exit(1);
00855                 }
00856             SwapRows(M[R],M[a],dim);
00857             SwapRows(I[R],I[a],dim);
00858             }
00859         denom=M[R][R];
00860         for(a=R+1;a<=dim;a++)
00861             {
00862             num=M[a][R];
00863             TakeWeightRow(M[a],M[R],num,denom,dim);
00864             TakeWeightRow(I[a],I[R],num,denom,dim);
00865             }
00866         }
00867     for(R=dim;R>=1;R--)
00868         {
00869         for(a=R+1;a<=dim;a++)
00870             {
00871             num=M[R][a];
00872             denom=M[a][a];
00873             TakeWeightRow(M[R],M[a],num,denom,dim);
00874             TakeWeightRow(I[R],I[a],num,denom,dim);
00875             }
00876         }
00877     for(R=1;R<=dim;R++)
00878         ScaleRow(I[R],M[R][R],dim);
00879 
00880     free_array(M, dim);
00881 
00882 
00883 }   /* end of find_inverse() */
00884 
00885 
00886 
00887 /*
00888 function that does LU decomposition
00889 taken from Robert A. McLaughlin's code
00890 */
00891 #define TINY_VALUE 1.0e-20;
00892 int
00893 lu_decomposition(double **M, int n, int *indx, double *d)
00894 {
00895     int     i, imax, j, k;
00896     double  big,dum,sum,temp;
00897     double  *vec;
00898 
00899     vec = alloc_vector(n);
00900     *d = 1.0;
00901     for (i=1; i <= n; i++)
00902         {
00903         big=0.0;
00904         for (j=1; j <= n; j++)
00905             if ((temp=fabs(M[i][j])) > big) big=temp;
00906         if (big == 0.0)
00907             {
00908             /* Singular matrix in routine lu_decomposition
00909              */
00910             return(-1);
00911             }
00912         vec[i]=1.0/big;
00913         }
00914     for (j=1; j <= n; j++)
00915         {
00916         for (i=1; i < j; i++)
00917             {
00918             sum=M[i][j];
00919             for (k=1;k<i;k++)
00920                 sum -= M[i][k]*M[k][j];
00921             M[i][j]=sum;
00922             }
00923         big=0.0;
00924         imax = 0;
00925         for (i=j; i <= n; i++)
00926             {
00927             sum = M[i][j];
00928             for (k=1; k < j; k++)
00929                 sum -= M[i][k]*M[k][j];
00930             M[i][j]=sum;
00931             if ( (dum=vec[i]*fabs(sum)) >= big)
00932                 {
00933                 big = dum;
00934                 imax = i;
00935                 }
00936             }
00937         if (j != imax)
00938             {
00939             for (k=1; k <= n; k++)
00940                 {
00941                 dum=M[imax][k];
00942                 M[imax][k]=M[j][k];
00943                 M[j][k]=dum;
00944                 }
00945             *d = -(*d);
00946             vec[imax]=vec[j];
00947             }
00948         indx[j]=imax;
00949         if (M[j][j] == 0.0)
00950             M[j][j] = TINY_VALUE;
00951         if (j != n)
00952             {
00953             dum=1.0/(M[j][j]);
00954             for (i=j+1; i<=n; i++)
00955                 M[i][j] *= dum;
00956             }
00957         }
00958     free(vec);
00959 
00960 
00961     return(0);
00962 
00963 }           /* end of lu_decomposition() */
00964 #undef TINY_VALUE
00965 
00966 
00967 /*
00968 function that does LU back substitution
00969 taken from Robert A. McLaughlin's code
00970 */
00971 void
00972 lu_back_substitution(double **M, int n, int *indx, double *b)
00973 {
00974     int     i, ii=0, ip, j;
00975     double  sum;
00976 
00977     for (i=1;i<=n;i++)
00978         {
00979         ip=indx[i];
00980         sum=b[ip];
00981         b[ip]=b[i];
00982         if (ii)
00983             for (j=ii;j<=i-1;j++)
00984                 sum -= M[i][j]*b[j];
00985         else if (sum) ii=i;
00986         b[i] = sum;
00987         }
00988     for (i=n; i >=1 ;i--)
00989         {
00990         sum = b[i];
00991         for (j=i+1;j<=n;j++)
00992             sum -= M[i][j]*b[j];
00993         b[i] = sum/M[i][i];
00994         }
00995 }           /* end of lu_decomposition() */
00996 
00997 /* function that transforms the a,b,c parameter of the ellipse equation to r1,r2,theta
00998 taken from Robert A. McLaughlin's code
00999 */
01000 bool
01001 transform_ellipse_parameters(double a, double b, double c,
01002                                     double *r1, double *r2, double *theta)
01003 {
01004     double  **M, **C, **eig_vec;
01005     double  *eig_val;
01006 
01007 
01008     M = alloc_array(2, 2);
01009     C = alloc_array(2, 2);
01010     eig_vec = alloc_array(2, 2);
01011     eig_val = alloc_vector(2);
01012 
01013     if ((M == NULL) || (C == NULL) || (eig_val == NULL) || (eig_vec == NULL))
01014         {
01015         fprintf(stderr, "malloc failed in transform_ellipse_parameters() in rht.c\n");
01016         exit(1);
01017         }
01018 
01019 
01020     M[1][1] = a;
01021     M[1][2] = M[2][1] = b;
01022     M[2][2] = c;
01023     find_inverse(M, C, 2);
01024     find_eigenvectors_2x2_positive_semi_def_real_matrix(C, eig_val, eig_vec);
01025 
01026     if ((eig_val[1] <= 0) || (eig_val[2] <= 0))
01027         {
01028         return( false );
01029         }
01030 
01031 
01032     *r1 = sqrt(eig_val[1]);
01033     *r2 = sqrt(eig_val[2]);
01034     *theta = atan2(eig_vec[2][1], eig_vec[1][1]);
01035 
01036 
01037     free_array(M, 2);
01038     free_array(C, 2);
01039     free_array(eig_vec, 2);
01040     free(eig_val);
01041 
01042 
01043     return( true );
01044 
01045 }       /* end of transform_ellipse_parameters() */
01046 
01047 
01048 
01049 
01050 
01051 
01052 //ellipse parameter node
01053 struct ellipse {
01054   int x, y, confidence;
01055   double r1, r2, theta;
01056 };
01057 
01058 
01059 void drawEllipse(Image< PixRGB<byte> > &output, list<ellipse> &houghSpace)
01060 {
01061 
01062   list<ellipse>::iterator Iter;
01063   //draw the ellipses
01064   for(Iter = houghSpace.begin(); Iter != houghSpace.end(); Iter++)
01065     {
01066       //cout<<"drawing "<<endl;
01067       //drawCircle(output,Point2D<int>((*Iter).x,(*Iter).y),(int)(*Iter).c,PixRGB<byte> (255,0,0));
01068       // for(int u = 0; u < inputImage.getWidth(); u++)
01069       //for(int v = 0; v < inputImage.getHeight(); v++)
01070       //  if(((int)((*Iter).a * pow((float)(u - (*Iter).x),2)) + (2 * (*Iter).b * (u - (*Iter).x) * (v- (*Iter).y)) + ((*Iter).c * pow((float)(v-(*Iter).y),2)))== 1 && (*Iter).confidence > threshold){
01071       //    drawPoint(output,u,v,PixRGB<byte> (255,0,0));
01072             //   cout<<"drawing confidence is "<< (*Iter).confidence<<endl;
01073       //  }
01074 
01075       int width = 20;
01076       int                 x, y;
01077       int                 x1, y1, x2, y2;
01078       double              perimeter, incr, grad, rho;
01079       double              M[3][3];
01080       int                 offset;
01081       bool error = false;
01082 
01083       if (((*Iter).r1 <= 20) || ((*Iter).r2 <= 20))
01084         error = true;
01085 
01086 
01087       /* The ellipse will be contructed as a sequence of
01088        * line segments.
01089        * incr indicates how much of the ellipse
01090        * each line segments will cover.
01091        */
01092       perimeter = 3.14159 * ( 3*(fabs((*Iter).r1)+fabs((*Iter).r2)) - sqrt( (fabs((*Iter).r1)+3*fabs((*Iter).r2))*(3*fabs((*Iter).r1)+fabs((*Iter).r2)) ) );
01093       // cout<<"p is "<<(*Iter).x<<"q is "<<(*Iter).y<<"r1 is "<<(*Iter).r1<<"r2 is "<<(*Iter).r2<<"theta is "<<(*Iter).theta<<endl;
01094       // cout<<"confidence is "<<(*Iter).confidence<<endl;
01095       /* Error check.
01096        */
01097       //cout<<"perimeter is "<<perimeter<<endl;
01098       if (perimeter <= 20)
01099         error = true;
01100 
01101 
01102       if(!error && (*Iter).confidence > 10)
01103         {
01104           //          cout<<"!error"<<endl;
01105           incr = 60.0/perimeter;
01106 
01107 
01108           /* The ellipse is defined as all points [x,y] given by:
01109            *
01110            * { [x,y] : for all theta in [0, 2pi),
01111            *           [x,y] = E . D . E^-1 . [cos(theta), sin (theta)}
01112            *
01113            * where E is the matrix containing the direction of
01114            * the pricipal axes
01115            * of the ellipse
01116            * and D is:   -    -
01117            *            |r1  0 |
01118            *            | 0  r2|
01119            *             -    -
01120            * First calculate E . D . E^-1
01121            */
01122           M[1][1] = (*Iter).r1*pow(cos((*Iter).theta),2) + (*Iter).r2*pow(sin((*Iter).theta),2);
01123           M[1][2] = M[2][1] = ((*Iter).r1-(*Iter).r2)*sin((*Iter).theta)*cos((*Iter).theta);
01124           M[2][2] = (*Iter).r1*(pow(sin((*Iter).theta),2)) + (*Iter).r2*(pow(cos((*Iter).theta),2));
01125 
01126           x1 = (int )((*Iter).x + M[1][1]*cos(0.0) + M[1][2]*sin(0.0));
01127           y1 = (int )((*Iter).y + M[2][1]*cos(0.0) + M[2][2]*sin(0.0));
01128 
01129 
01130           for (rho=incr; rho < (2*M_PI + incr); rho += incr)
01131             {
01132               x2 = (int )((*Iter).x + M[1][1]*cos(rho) + M[1][2]*sin(rho));
01133               y2 = (int )((*Iter).y + M[2][1]*cos(rho) + M[2][2]*sin(rho));
01134               if ((x1 >= 0) && (x1 < output.getWidth()) && (y1 >= 0) && (y1 < output.getHeight()) &&
01135                   (x2 >= 0) && (x2 < output.getWidth()) && (y2 >= 0) && (y2 < output.getHeight()))
01136                 {
01137                   if (fabs(x2-x1) >= fabs(y2-y1))
01138                     {
01139                       /* x changes more than y
01140                        */
01141                       if (x1 < x2)
01142                         {
01143                           grad = ((double )(y2-y1)) / (double )(x2-x1);
01144                           for (x=x1; x <= x2; x++)
01145                             {
01146                               y = y1 + (int )(grad*(double )(x - x1));
01147                               for (offset=-width/2; offset < (width+1)/2; offset++)
01148                                 {
01149                                   if (((y+offset) >= 0) && ((y+offset) < output.getHeight()))
01150                                     {
01151                                       drawPoint(output,x,y/*+offset*/,PixRGB<byte> (255,0,0));
01152                                       //                                      cout<<"DRAWING POINT"<<endl;
01153                                     }
01154                                 }
01155                             }
01156                         }
01157                       else if (x1 > x2)
01158                         {
01159                           grad = ((double )(y1-y2)) / (double )(x1-x2);
01160                           for (x=x2; x <= x1; x++)
01161                             {
01162                               y = y2 + (int )(grad*(double )(x - x2));
01163                               for (offset=-width/2; offset < (width+1)/2; offset++)
01164                                 {
01165                                   if (((y+offset) >= 0) && ((y+offset) < output.getHeight()))
01166                                     {
01167                                       drawPoint(output,x,y/*+offset*/,PixRGB<byte> (255,0,0));
01168                                       // cout<<"DRAWING POINT"<<endl;
01169                                     }
01170                                 }
01171                             }
01172                         }
01173                     }
01174                   else        /* if (abs(x2-x1) < abs(y2-y1)) */
01175                     {
01176                       /* y changes more than x
01177                        */
01178                       if (y1 < y2)
01179                         {
01180                           grad = ((double )(x2-x1)) / (double )(y2-y1);
01181                           for (y=y1; y <= y2; y++)
01182                             {
01183                               x = x1 + (int )(grad*(double )(y-y1));
01184                               for (offset=-width/2; offset < (width+1)/2; offset++)
01185                                 {
01186                                   if (((x+offset) >= 0) && ((x+offset) < output.getWidth()))
01187                                     {
01188                                       drawPoint(output,x/*+offset*/,y,PixRGB<byte> (255,0,0));
01189                                       //cout<<"DRAWING POINT"<<endl;
01190                                     }
01191                                 }
01192                             }
01193                         }
01194                       else if (y1 > y2)
01195                         {
01196                           grad = ((double )(x1-x2)) / (double )(y1-y2);
01197                           for (y=y2; y <= y1; y++)
01198                             {
01199                               x = x2 + (int )(grad*(double )(y - y2));
01200                               for (offset=-width/2; offset < (width+1)/2; offset++)
01201                                 {
01202                                   if (((x+offset) >= 0) && ((x+offset) < output.getWidth()))
01203                                     {
01204                                       drawPoint(output,x/*+offset*/,y,PixRGB<byte> (255,0,0));
01205                                       // cout<<"DRAWING POINT"<<endl;
01206                                     }
01207                                 }
01208                             }
01209                         }
01210                     }
01211                 }   /* end of 'if ((x1 >= 0) && (x1 < aImage->x) &&...' */
01212               x1 = x2;
01213               y1 = y2;
01214             }
01215         }
01216     }
01217 
01218 }
01219 
01220 
01221 int
01222 count_pixels(Image<byte> &output, double x_centre, double y_centre,
01223                                         double r1, double r2, double theta)
01224 {
01225 /*
01226  *      x, y;       -- centre of ellipse
01227  *      r1, r2;     -- major/minor axis
01228  *      theta;      -- angle
01229  */
01230   int width = 20;
01231   int             x, y;
01232   int             x1, y1, x2, y2;
01233   double          perimeter, incr, grad, rho;
01234   double          M[3][3];
01235   int             offset;
01236   int             num_pixels = 0;
01237 
01238   if ((r1 <= width) || (r2 <= width))
01239     return(0);
01240 
01241 
01242 
01243     /* The ellipse will be contructed as a sequence of
01244      * line segments.
01245      * incr indicates how much of the ellipse
01246      * each line segments will cover.
01247      */
01248   perimeter = M_PI * ( 3*(fabs(r1)+fabs(r2)) - sqrt( (fabs(r1)+3*fabs(r2))*(3*fabs(r1)+fabs(r2)) ) );
01249 
01250 
01251     /* Error check.
01252      */
01253   if (perimeter <= width)
01254     return( 0 );        /* zero width or length ellipse.
01255                              * Don't bother counting pixels.
01256                              */
01257 
01258 
01259 
01260   incr = 60.0/perimeter;
01261 
01262 
01263     /* The ellipse is defined as all points [x,y] given by:
01264      *
01265      * { [x,y] : for all theta in [0, 2pi),
01266      *           [x,y] = E . D . E^-1 . [cos(theta), sin (theta)}
01267      *
01268      * where E is the matrix containing the direction of
01269      * the pricipal axes
01270      * of the ellipse
01271      * and D is:   -    -
01272      *            |r1  0 |
01273      *            | 0  r2|
01274      *             -    -
01275      * First calculate E . D . E^-1
01276      */
01277   M[1][1] = r1*squareOf(cos(theta)) + r2*squareOf(sin(theta));
01278   M[1][2] = M[2][1] = (r1-r2)*sin(theta)*cos(theta);
01279   M[2][2] = r1*squareOf(sin(theta)) + r2*squareOf(cos(theta));
01280 
01281   x1 = (int )(x_centre + M[1][1]*cos(0.0) + M[1][2]*sin(0.0));
01282   y1 = (int )(y_centre + M[2][1]*cos(0.0) + M[2][2]*sin(0.0));
01283 
01284 
01285   for (rho=incr; rho < (2*M_PI + incr); rho += incr)
01286     {
01287       x2 = (int )(x_centre + M[1][1]*cos(rho) + M[1][2]*sin(rho));
01288       y2 = (int )(y_centre + M[2][1]*cos(rho) + M[2][2]*sin(rho));
01289       if ((x1 >= 0) && (x1 < output.getWidth()) && (y1 >= 0) && (y1 < output.getHeight()) &&
01290           (x2 >= 0) && (x2 < output.getWidth()) && (y2 >= 0) && (y2 < output.getHeight()))
01291         {
01292           if (abs(x2-x1) >= abs(y2-y1))
01293             {
01294               /* x changes more than y
01295                */
01296               if (x1 < x2)
01297                 {
01298                   grad = ((double )(y2-y1)) / (double )(x2-x1);
01299                   for (x=x1; x <= x2; x++)
01300                     {
01301                       y = y1 + (int )(grad*(double )(x - x1));
01302                       for (offset=-width/2; offset < (width+1)/2; offset++)
01303                         {
01304                           if (((y+offset) >= 0) && ((y+offset) < output.getHeight()))
01305                             {
01306                               if ((output.getVal(x,y+offset) == 255))
01307                                 {
01308                                   num_pixels++;
01309                                 }
01310                             }
01311                         }
01312                     }
01313                 }
01314               else if (x1 > x2)
01315                 {
01316                   grad = ((double )(y1-y2)) / (double )(x1-x2);
01317                   for (x=x2; x <= x1; x++)
01318                     {
01319                       y = y2 + (int )(grad*(double )(x - x2));
01320                       for (offset=-width/2; offset < (width+1)/2; offset++)
01321                         {
01322                             if (((y+offset) >= 0) && ((y+offset) < output.getHeight()))
01323                               {
01324                                 if ((output.getVal(x,y+offset) == 255))
01325                                   {
01326                                     num_pixels++;
01327                                   }
01328                               }
01329                         }
01330                     }
01331                 }
01332             }
01333           else        /* if (abs(x2-x1) < abs(y2-y1)) */
01334             {
01335               /* y changes more than x
01336                */
01337               if (y1 < y2)
01338                 {
01339                   grad = ((double )(x2-x1)) / (double )(y2-y1);
01340                   for (y=y1; y <= y2; y++)
01341                     {
01342                       x = x1 + (int )(grad*(double )(y-y1));
01343                       for (offset=-width/2; offset < (width+1)/2; offset++)
01344                               {
01345                           if (((x+offset) >= 0) && ((x+offset) < output.getWidth()))
01346                             {
01347                               if ((output.getVal(x+offset,y) == 255))
01348                                 {
01349                                   num_pixels++;
01350                                 }
01351                             }
01352                         }
01353                     }
01354                 }
01355               else if (y1 > y2)
01356                     {
01357                       grad = ((double )(x1-x2)) / (double )(y1-y2);
01358                       for (y=y2; y <= y1; y++)
01359                         {
01360                           x = x2 + (int )(grad*(double )(y - y2));
01361                           for (offset=-width/2; offset < (width+1)/2; offset++)
01362                             {
01363                               if (((x+offset) >= 0) && ((x+offset) < output.getWidth()))
01364                                 {
01365                                   if ((output.getVal(x+offset,y) == 255))
01366                                     {
01367                                       num_pixels++;
01368                                     }
01369                                 }
01370                             }
01371                         }
01372                     }
01373             }
01374         }   /* end of 'if ((x1 >= 0) && (x1 < aImage->x) &&...' */
01375       x1 = x2;
01376       y1 = y2;
01377     }
01378 
01379 
01380   return( num_pixels );
01381 
01382 
01383 }   /* count_number_of_pixels_near_ellipse() */
01384 
01385 //Finds Ellipses in an image
01386 //going to use the randomized hough transform to do this
01387 void houghEllipse(Image<byte> inputImage, int threshold, Image< PixRGB<byte> > &output) {
01388 
01389   Point2D<int> randomPixels[3];
01390   double pointX[3][25];//the neighborhood pixels of the 3 chosen random "edge"pixels
01391   double pointY[3][25];
01392   float slopeTan[3];
01393   float InterTan[3];
01394   float slopeCenterLine[2] = { 0.0F, 0.0F };
01395   float InterCenterLine[2] = { 0.0F, 0.0F };
01396 
01397   bool foundCenterPoint = true;
01398   bool foundOtherParams = true;
01399 
01400   int p, q;
01401   double  a,b,c,r1,r2,theta;
01402   double **matrixA;
01403   double *vectorB;
01404   double d;
01405   int* indx= (int *)malloc(4 * sizeof(int) );
01406 
01407   matrixA = alloc_array(3,3);
01408   vectorB = alloc_vector(3);
01409 
01410   list<ellipse> houghSpace;
01411   list<ellipse>::iterator Iter;
01412   int NUMBER=0;
01413   int Iterations = 0;
01414 
01415   int max = 0;
01416   list<ellipse>::iterator indexOfMax;
01417   list<ellipse> tempSpace;
01418 
01419    srand( time(NULL));
01420    while(Iterations < inputImage.getWidth() * inputImage.getHeight())// && NUMBER < 6000)
01421     {
01422 
01423       //      cout<<"iterations"<<Iterations<<endl;
01424       int pixelCount = 0;
01425       while(pixelCount != 3)//get the initial random numbers
01426         {
01427           randomPixels[pixelCount].i = rand()%320;
01428           randomPixels[pixelCount].j = rand()%240;
01429           if(inputImage.getVal(randomPixels[pixelCount].i, randomPixels[pixelCount].j) == 255)
01430             {
01431               if(pixelCount == 1)
01432                 {
01433                   if(!(randomPixels[pixelCount].i == randomPixels[0].i))
01434                     {
01435                       pixelCount++;
01436                       //inputImage.setVal(randomPixels[pixelCount-1].i,randomPixels[pixelCount-1].j,0);
01437                       //                      cout<<"chosen points"<<randomPixels[pixelCount-1].i<<" "<<randomPixels[pixelCount-1].j<<endl;
01438                     }
01439 
01440                 }else if(pixelCount == 2)
01441                   {
01442                     if(!(randomPixels[pixelCount].i == randomPixels[0].i || randomPixels[pixelCount].i == randomPixels[1].i))
01443                     {
01444                       pixelCount++;
01445                       //inputImage.setVal(randomPixels[pixelCount-1].i,randomPixels[pixelCount-1].j,0);
01446                       //cout<<"chosen points"<<randomPixels[pixelCount-1].i<<" "<<randomPixels[pixelCount-1].j<<endl;
01447                     }
01448                   }
01449               else
01450                 {
01451                   pixelCount++;
01452                   //inputImage.setVal(randomPixels[pixelCount-1].i,randomPixels[pixelCount-1].j,0);
01453                   //          cout<<"chosen points"<<randomPixels[pixelCount-1].i<<" "<<randomPixels[pixelCount-1].j<<endl;
01454                 }
01455 
01456             }
01457           //          NUMBER++;
01458           //          if(NUMBER ==  1000)
01459           // break;
01460         }
01461       //      if(NUMBER == 1000)
01462       //        break;
01463 
01464       foundCenterPoint = true;
01465       foundOtherParams = true;
01466 
01467       //cout<<"after getting random pixels"<<endl;
01468       //find the tangent lines
01469       //get the neighboring pixels of each pixel
01470       int count[3] = {0,0,0};
01471       int tempI = 0, tempJ = 0;
01472       for(int j = 0; j < 3; j++)
01473         {
01474           for(int i = 0; i < 5; i++)
01475             for(int k = 0; k < 5; k++)
01476               {
01477                 tempI = randomPixels[j].i + (i-2);
01478                 tempJ = randomPixels[j].j + (k-2);
01479                 if(tempI >=0 && tempI <320 && tempJ >= 0 && tempJ < 240){
01480                   if(inputImage.getVal(tempI,tempJ)==255 || (tempI == randomPixels[j].i && tempJ == randomPixels[j].j))
01481                     {
01482                       if(randomPixels[j].j != tempJ || (randomPixels[j].j == tempJ && randomPixels[j].i == tempI)){
01483                       pointX[j][count[j]] = tempI;
01484                       pointY[j][count[j]] = tempJ;
01485                       count[j]++;
01486                       }
01487                     }
01488                 }
01489 
01490               }
01491 
01492         }
01493       //    cout<<"test2"<<endl;
01494       // solve for the slope of the tangent
01495       for(int i = 0; i < 3; i++){
01496         findTanLine(count[i], pointX[i], pointY[i], slopeTan[i], InterTan[i]);
01497         //cout<<"slopeTan is "<<slopeTan[i]<<endl;
01498       }
01499 
01500       //solve for the ellipse center
01501       for(int i = 0; i < 2; i++){
01502         if(!isnan(slopeTan[i]) && !isnan(slopeTan[i+1]))
01503           {
01504             slopeCenterLine[i] = ((slopeTan[i] *((InterTan[i+1]-InterTan[i])/(slopeTan[i]-slopeTan[i+1]))) + InterTan[i] - ((randomPixels[i].j+randomPixels[i+1].j)/2.0))/(((InterTan[i+1]-InterTan[i])/(slopeTan[i]-slopeTan[i+1])) - ((randomPixels[i].i+randomPixels[i+1].i)/2.0));
01505             InterCenterLine[i] = ((randomPixels[i].j + randomPixels[i+1].j)/2.0) - slopeCenterLine[i] * ((randomPixels[i].i + randomPixels[i+1].i)/2.0);
01506             if(isnan(slopeCenterLine[i]))
01507               {
01508                 InterCenterLine[i] = (randomPixels[i].i + randomPixels[i+1].i)/2.0;
01509               }
01510           }
01511         else if(!isnan(slopeTan[i]) && isnan(slopeTan[i+1])) //one is vertical
01512           {
01513             slopeCenterLine[i] = ((slopeTan[i] * randomPixels[i+1].i + InterTan[i]) - ((randomPixels[i].j + randomPixels[i+1].j)/2.0)) / (randomPixels[i+1].i - ((randomPixels[i].i + randomPixels[i+1].i)/2.0));
01514             InterCenterLine[i] = ((randomPixels[i].j + randomPixels[i+1].j)/2.0) - slopeCenterLine[i] * ((randomPixels[i].i + randomPixels[i+1].i)/2.0);
01515             if(isnan(slopeCenterLine[i]))
01516               {
01517                 InterCenterLine[i] = randomPixels[i].i; //store the x-intercept instead
01518               }
01519           }
01520         else if(!isnan(slopeTan[i+1]) && isnan(slopeTan[i]))//another one is vertical
01521           {
01522             slopeCenterLine[i] = ((slopeTan[i+1] * randomPixels[i].i + InterTan[i+1]) - ((randomPixels[i].j + randomPixels[i+1].j)/2.0)) / (randomPixels[i+1].i - ((randomPixels[i].i + randomPixels[i+1].i)/2.0));
01523             InterCenterLine[i] = ((randomPixels[i].j + randomPixels[i+1].j)/2.0) - slopeCenterLine[i] * ((randomPixels[i].i + randomPixels[i+1].i)/2.0);
01524             if(isnan(slopeCenterLine[i]))
01525               {
01526                 InterCenterLine[i] =  ((randomPixels[i].i + randomPixels[i+1].i)/2.0);
01527               }
01528           }
01529         else //both are vertical lines?
01530           {
01531             foundCenterPoint = false;
01532           }
01533 
01534       }
01535       if(foundCenterPoint)
01536         {
01537           //          cout<<"slope center line is "<<slopeCenterLine[0]<<" "<<slopeCenterLine[1]<<endl;
01538           if(!isnan(slopeCenterLine[0]) && !isnan(slopeCenterLine[1]))
01539             {
01540               //The intersection of the 2 lines above is the center
01541               p = (int)((InterCenterLine[1]-InterCenterLine[0])/(slopeCenterLine[0]-slopeCenterLine[1]));
01542               q = (int)((slopeCenterLine[0]*p)+InterCenterLine[0]);
01543             }
01544           else if(!isnan(slopeCenterLine[0]) && isnan(slopeCenterLine[1]) ) // one of the slope is vertical
01545             {
01546               p = (int) InterCenterLine[1];
01547               q = (int) ((slopeCenterLine[0] * InterCenterLine[1]) + InterCenterLine[0]);
01548             }
01549           else if(!isnan(slopeCenterLine[1]) && isnan(slopeCenterLine[0]) )//same as above
01550             {
01551               p = (int) InterCenterLine[0];
01552               q = (int) ((slopeCenterLine[1] * InterCenterLine[0]) + InterCenterLine[1]);
01553             }
01554           else
01555             {
01556               p = -1;
01557               q = -1;
01558               //both lines are vertical what to do?
01559               foundCenterPoint = false;
01560 
01561             }
01562           if(p < 0 || p > 320 || q < 0 || q > 240)
01563             foundCenterPoint = false;
01564         }
01565 
01566       if(foundCenterPoint) // continue only if successfully found the center point of the ellipse
01567         {
01568           for(int i = 1; i < 4; i++)
01569             {
01570               //          cout<<"point "<<i<<" is ("<<randomPixels[i].i<<","<<randomPixels[i].j<<")"<<endl;
01571               matrixA[i][1] = (randomPixels[i-1].i - p) * (randomPixels[i-1].i- p);
01572               matrixA[i][2] =(randomPixels[i-1].i-p) * (randomPixels[i-1].j-q) * 2;
01573               matrixA[i][3] = (randomPixels[i-1].j-q) * (randomPixels[i-1].j-q);
01574               vectorB[i] = 1;
01575             }
01576 
01577 
01578           if (lu_decomposition(matrixA, 3, indx, &d) != 0)
01579             {
01580               foundOtherParams = false;
01581             }
01582           if(foundOtherParams)
01583             {
01584               lu_back_substitution(matrixA, 3, indx,vectorB);
01585 
01586               a = vectorB[1];
01587               b = vectorB[2];
01588               c = vectorB[3];
01589               //cout << "a is "<<a<<" b is "<<b<<" c is "<<c<<" sqrt(a^2+b^2)"<<sqrt(a*a+b*b)<<endl;
01590               if(a * c - b * b > 0)
01591                 {
01592                   if(transform_ellipse_parameters(a, b, c,&r1, &r2, &theta))
01593                     {
01594                       //  double pixcnt = ((double)count_pixels(inputImage,p,q,r1,r2,theta))/( 3.14159 * ( 3*(r1+r2) - sqrt((r1+3*r2)*(3*r1+r2)) ));
01595                       // cout<<pixcnt<<endl;
01596                       //if(pixcnt > .5)
01597                                                if(true)
01598                         {
01599                           //cout<<" p is "<<p<<" q is "<<q<<endl;
01600                           //cout<<"found ellipse number so far is "<<houghSpace.size()<<" NUMBER IS"<<NUMBER<<endl;
01601                           bool found = false;
01602                           //ellipse
01603                           for(Iter = houghSpace.begin(); Iter != houghSpace.end(); Iter++)
01604                             {
01605                               if(( fabs((*Iter).x - p) < 10 && fabs((*Iter).y - q) < 10 && fabs((*Iter).r1 - r1) < 5 && fabs((*Iter).r2 - r2) < 5 && fabs((*Iter).theta - theta) < .4487))
01606                                 {
01607                                   found = true;
01608                                   (*Iter).confidence++;
01609                                   if((*Iter).confidence > max)
01610                                     {
01611                                       max = (*Iter).confidence;
01612                                       indexOfMax = Iter;
01613                                     }
01614                                 }
01615                             }
01616                           if(!found)
01617                             {
01618                               ellipse temp;
01619                               temp.x = p;
01620                               temp.y = q;
01621                               temp.r1 = r1;
01622                               temp.r2 = r2;
01623                               temp.theta = theta;
01624                               temp.confidence = 1;
01625                               houghSpace.push_back(temp);
01626                             }
01627                           NUMBER++;
01628                         }
01629                     }
01630                 }
01631             }
01632         }
01633       Iterations++;
01634 
01635     }
01636    //  cout <<  ((double)count_pixels(inputImage,(*indexOfMax).x,(*indexOfMax).y,(*indexOfMax).r1,(*indexOfMax).r2,(*indexOfMax).theta))/(3* 3.14159 * ( 3*((*indexOfMax).r1+(*indexOfMax).r2) - sqrt(((*indexOfMax).r1+3*(*indexOfMax).r2)*(3*(*indexOfMax).r1+(*indexOfMax).r2)) ))<<endl;
01637    ellipse temp;
01638    temp.x = (*indexOfMax).x;
01639    temp.y = (*indexOfMax).y;
01640    temp.r1 = (*indexOfMax).r1;
01641    temp.r2 = (*indexOfMax).r2;
01642    temp.theta = (*indexOfMax).theta;
01643    temp.confidence = (*indexOfMax).confidence;
01644    cout<<temp.confidence<<endl;
01645    tempSpace.push_back(temp);
01646     drawEllipse(output, tempSpace);
01647   free(indx);
01648 
01649 }
01650 
01651 
01652 
01653 
01654 
01655 
01656 
01657 
01658 int main() {
01659   float sigma = .7;
01660   float tlow = 0.2;
01661   float thigh = .97;
01662 
01663   unsigned char *edge;
01664 
01665   char *dirfilename = NULL;
01666 
01667 
01668   ModelManager camManager("ColorTracker Tester");
01669   nub::soft_ref<FrameIstream>
01670     gb(makeIEEE1394grabber(camManager, "COcam", "cocam"));
01671 
01672   camManager.addSubComponent(gb);
01673 
01674   camManager.loadConfig("camconfig.pmap");
01675 
01676   gb->setModelParamVal("FrameGrabberSubChan", 0);
01677   gb->setModelParamVal("FrameGrabberBrightness", 128);
01678   gb->setModelParamVal("FrameGrabberHue", 180);
01679 
01680 
01681 
01682   camManager.start();
01683 
01684   Image< PixRGB<byte> > cameraImage;
01685   Image<byte> grayImg;
01686   Image< PixRGB<byte> > houghImg(320,240,ZEROS) ;
01687   //Image<byte> houghImg;
01688   cameraImage = gb->readRGB();
01689   xwin = new XWindow(cameraImage.getDims());
01690   xwin2 = new XWindow(cameraImage.getDims());
01691   xwin3 = new XWindow(cameraImage.getDims());
01692 
01693   while(1) {
01694 
01695     printf(".");
01696     cameraImage = gb->readRGB();
01697 
01698     xwin->drawImage(cameraImage);
01699     grayImg = luminance(cameraImage);
01700 
01701     canny(grayImg.getArrayPtr(), grayImg.getHeight(), grayImg.getWidth(), sigma, tlow, thigh, &edge, dirfilename);
01702     Image<unsigned char> edgeImage(edge, grayImg.getWidth(), grayImg.getHeight());
01703     xwin2->drawImage(edgeImage);
01704     houghImg = edgeImage;
01705 
01706     std::vector <LineSegment2D> lines = houghTransform(edgeImage, PI/180, 1, 80, houghImg);
01707     //houghEllipse(edgeImage,0,houghImg);
01708      xwin3->drawImage(houghImg);
01709 
01710 
01711   }
01712 
01713 
01714 }
01715 
01716 // ######################################################################
01717 /* So things look consistent in everyone's emacs... */
01718 /* Local Variables: */
01719 /* mode: c++ */
01720 /* indent-tabs-mode: nil */
01721 /* End: */
01722 
01723 #endif // BEOSUB_TEST_HOUGH_C_DEFINED
Generated on Sun May 8 08:40:20 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3