00001 /*!@file BeoSub/HoughTransform.C find hough transform for an image */ 00002 // //////////////////////////////////////////////////////////////////// // 00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00004 // University of Southern California (USC) and the iLab at USC. // 00005 // See http://iLab.usc.edu for information about this project. // 00006 // //////////////////////////////////////////////////////////////////// // 00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00009 // in Visual Environments, and Applications'' by Christof Koch and // 00010 // Laurent Itti, California Institute of Technology, 2001 (patent // 00011 // pending; application number 09/912,225 filed July 23, 2001; see // 00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00013 // //////////////////////////////////////////////////////////////////// // 00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00015 // // 00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00017 // redistribute it and/or modify it under the terms of the GNU General // 00018 // Public License as published by the Free Software Foundation; either // 00019 // version 2 of the License, or (at your option) any later version. // 00020 // // 00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00024 // PURPOSE. See the GNU General Public License for more details. // 00025 // // 00026 // You should have received a copy of the GNU General Public License // 00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00029 // Boston, MA 02111-1307 USA. // 00030 // //////////////////////////////////////////////////////////////////// // 00031 // 00032 // Primary maintainer for this file: Michael Montalbo <montalbo@usc.edu> 00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/HoughTransform.C $ 00034 // $Id: HoughTransform.C 9412 2008-03-10 23:10:15Z farhan $ 00035 00036 00037 #ifndef HoughTransform_C 00038 #define HoughTransform_C 00039 00040 #include "BeoSub/HoughTransform.H" 00041 00042 #include "Image/Image.H" 00043 #include "Image/Pixels.H" 00044 #include "Util/Timer.H" 00045 #include "Util/Types.H" 00046 #include "Util/log.H" 00047 #include "Image/ColorOps.H" 00048 #include "Image/Image.H" 00049 #include "Image/MathOps.H" 00050 #include "Image/DrawOps.H" 00051 #include "Image/FilterOps.H" 00052 #include "Image/Transforms.H" 00053 #include "Raster/Raster.H" 00054 #include "rutz/shared_ptr.h" 00055 #include "BeoSub/hysteresis.H" 00056 #include "VFAT/segmentImageTrackMC.H" 00057 #include <cstdio> 00058 #include <cstdlib> 00059 #include <cstring> 00060 #include <iostream> //needed for segmentImageTrackMC! 00061 #include <math.h> 00062 #include <list> 00063 #include "Image/MatrixOps.H" 00064 #include "BeoSub/CannyEdge.H" 00065 #include "MBARI/Geometry2D.H" 00066 using namespace std; 00067 00068 // finds all the lines in an image by using the hough transform 00069 // thetaRes is the resolution of each theta 00070 // dRes is the resolution of the D 00071 // returns a vector with the line segments found 00072 std::vector <LineSegment2D> houghTransform 00073 (Image<byte> &inputImage, float thetaRes, float dRes, int threshold, 00074 Image< PixRGB<byte> > &output) 00075 { 00076 //Timer tim(1000000); 00077 //uint t; 00078 00079 uint w = inputImage.getWidth(); 00080 uint h = inputImage.getHeight(); 00081 00082 // get the total number of angles and delta from the resolution of theta and D's 00083 int numAngle = (int) (M_PI / thetaRes); 00084 int numD = (int)(sqrt((w*w + h*h)/ dRes) / 2); 00085 int centerX = (int)(w/2); 00086 int centerY = (int)(h/2); 00087 00088 std::vector <LineSegment2D> lines; 00089 std::vector <Point2D<int> > edgePoints; 00090 00091 //find all the white edge pixels in the image and store them 00092 for(int y = 0; y < inputImage.getHeight(); y++) 00093 { 00094 for(int x = 0; x < inputImage.getWidth(); x++) 00095 { 00096 //if the pixel is an edge 00097 if(inputImage.getVal(x,y) == 255) 00098 // convert the x,y position of the pixel to an x,y position where 00099 // the center of the image is the origin as opposed to the top left corner 00100 // and store the pixel 00101 edgePoints.push_back(Point2D<int>(x - centerX, y - centerY)); 00102 } 00103 } 00104 00105 // store the edge points that belong to each line 00106 std::vector<std::vector<std::vector<Point2D<int> > > > ptList; 00107 ptList.resize(numD); 00108 for(int i = 0; i < numD; i++) ptList[i].resize(numAngle); 00109 00110 // equation of the line is x*cos(theta) + y*sin(theta) = D 00111 00112 // fill the accumulator 00113 for(uint c = 0; c < edgePoints.size(); c++) 00114 { 00115 int edgePointX = edgePoints[c].i; 00116 int edgePointY = edgePoints[c].j; 00117 00118 //get all possible D and theta that can fit to that point 00119 for(int n = 0; n < numAngle; n++) 00120 { 00121 int r = (int)(edgePointX * cos(n*thetaRes) + edgePointY * sin(n*thetaRes)); 00122 00123 // if the radius is negative, make it positive so as to avoid segfaults 00124 // (a point with radius r lies on the same line 00125 // as a point with radius -r if they share the same angle) 00126 r = abs(r); 00127 00128 ptList[r][n].push_back(edgePoints[c]); 00129 00130 } 00131 } 00132 00133 // find the peaks, ie any number of points greater 00134 // than the threshold as well as a local maximum is considered a line 00135 for(int i = 1; i < numD - 1; i++) { 00136 for(int j = 1; j < numAngle - 1; j++) 00137 { 00138 uint currentPointCount = ptList[i][j].size(); 00139 00140 if(currentPointCount > (unsigned int)(threshold) && 00141 currentPointCount > ptList[i-1][j].size() && 00142 currentPointCount > ptList[i+1][j].size() && 00143 currentPointCount > ptList[i][j-1].size() && 00144 currentPointCount > ptList[i][j+1].size() ) // found a peak 00145 { 00146 //find the endpoints of the line segment 00147 int minx = ptList[i][j][1].i, maxx = ptList[i][j][1].i; 00148 int miny = ptList[i][j][1].j, maxy = ptList[i][j][1].j; 00149 //the indexes of the two endpoints in the vector 00150 uint mini = 0, maxi = 0; 00151 for(uint k = 1; k < currentPointCount; k++) 00152 { 00153 if(minx > ptList[i][j][k].i) 00154 { minx = ptList[i][j][k].i; mini = k; } 00155 if(maxx < ptList[i][j][k].i) 00156 { maxx = ptList[i][j][k].i; maxi = k; } 00157 } 00158 // LINFO("ksize: %d, min[%d]:%d,%d max[%d]:%d,%d", ptList[i][j].size(), 00159 // mini, ptList[i][j][mini].i, ptList[i][j][mini].j, 00160 // maxi, ptList[i][j][maxi].i, ptList[i][j][maxi].j); 00161 00162 // if the line is vertical 00163 if(minx == maxx) 00164 { 00165 for(uint k = 1; k < currentPointCount; k++) 00166 { 00167 if(miny > ptList[i][j][k].j) 00168 { miny = ptList[i][j][k].j; mini = k; } 00169 if(maxy > ptList[i][j][k].j) 00170 { maxy = ptList[i][j][k].j; maxi = k; } 00171 } 00172 } 00173 00174 // the two endpoints of the line segment 00175 Point2D<int> p1 = ptList[i][j][mini]; 00176 Point2D<int> p2 = ptList[i][j][maxi]; 00177 00178 // convert from x,y where the center of the image is the origin 00179 // back to x,y where top left of image is the origin 00180 p1.i += centerX; 00181 p1.j += centerY; 00182 p2.i += centerX; 00183 p2.j += centerY; 00184 00185 LineSegment2D thisLine(p1,p2); 00186 00187 if(thisLine.isValid()) 00188 { 00189 lines.push_back(thisLine); 00190 drawLine(output, p1, p2, PixRGB<byte> (255,0,0), 1); 00191 } 00192 } 00193 } 00194 } 00195 00196 return lines; 00197 00198 } 00199 00200 #endif 00201 00202 // ###################################################################### 00203 /* So things look consistent in everyone's emacs... */ 00204 /* Local Variables: */ 00205 /* indent-tabs-mode: nil */ 00206 /* End: */