00001 #ifndef HoughTransform2_C 00002 #define HoughTransform2_C 00003 00004 #include "BeoSub/HoughTransform2.H" 00005 00006 #include "Image/Image.H" 00007 #include "Image/Pixels.H" 00008 #include "Util/Timer.H" 00009 #include "Util/Types.H" 00010 #include "Util/log.H" 00011 #include "Image/ColorOps.H" 00012 #include "Image/Image.H" 00013 #include "Image/MathOps.H" 00014 #include "Image/DrawOps.H" 00015 #include "Image/FilterOps.H" 00016 #include "Image/Transforms.H" 00017 #include "Raster/Raster.H" 00018 #include "rutz/shared_ptr.h" 00019 #include "BeoSub/hysteresis.H" 00020 #include "VFAT/segmentImageTrackMC.H" 00021 #include <cstdio> 00022 #include <cstdlib> 00023 #include <cstring> 00024 #include <iostream> //needed for segmentImageTrackMC! 00025 #include <math.h> 00026 #include <list> 00027 #include "Image/MatrixOps.H" 00028 #include "BeoSub/CannyEdge.H" 00029 #include "MBARI/Geometry2D.H" 00030 using namespace std; 00031 00032 00033 void findEndPoints(int p, float theta, Point2D<int> *intercept1, Point2D<int> *intercept2, Dims dimensions) 00034 { 00035 int imageWidth = dimensions.w(); 00036 int imageHeight = dimensions.h(); 00037 00038 //convert d and angle to a pair of endpoints 00039 intercept1->i = -1; 00040 intercept2->i = -1; 00041 int tempX0, tempX1, tempY0, tempY1; 00042 int cosTheta = (int) cos(theta); 00043 int sinTheta = (int) sin(theta); 00044 00045 //Find the possible image border intersects 00046 tempX0 = (p) / cosTheta; //y=0 00047 tempX1 = (p-imageHeight*sinTheta)/cosTheta; //y=imageHeight 00048 tempY0 = (p / sinTheta); //x = 0 00049 tempY1 = (p - imageWidth * cosTheta) / sinTheta; //x = imageWidth 00050 00051 //Decide which two of the four intersects are valid and store them 00052 if(tempX0 > 0 && tempX0 < imageWidth) 00053 { 00054 intercept1->i = tempX0; 00055 intercept1->j = 0; 00056 } 00057 if(tempX1 > 0 && tempX1 < imageWidth) 00058 { 00059 if(intercept1->i == -1) { 00060 intercept1->i = tempX1; 00061 intercept1->j = imageHeight; 00062 } 00063 else { 00064 intercept2->i = tempX1; 00065 intercept2->j = imageHeight; 00066 } 00067 } 00068 if(tempY0 > 0 && tempY0 < imageHeight) 00069 { 00070 if(intercept1->i == -1) { 00071 intercept1->i = 0; 00072 intercept1->j = tempY0; 00073 } 00074 else { 00075 intercept2->i = 0; 00076 intercept2->j = tempY0; 00077 } 00078 } 00079 if(tempY1 > 0 && tempY1 < imageHeight) 00080 { 00081 if(intercept1->i == -1) { 00082 intercept1->i = imageWidth; 00083 intercept1->j = tempY1; 00084 } 00085 else { 00086 intercept2->i = imageWidth; 00087 intercept2->j = tempY1; 00088 } 00089 } 00090 00091 } 00092 //finds the line by using hough transform 00093 //thetaRes is the resolution of each theta 00094 //dRes is the resolution of the D 00095 //returns the number of lines found 00096 std::vector <LineSegment2D> houghTransform(Image<byte> &inputImage, 00097 float thetaRes, 00098 float dRes, 00099 int threshold, 00100 Image< PixRGB<byte> > &output) 00101 { 00102 LDEBUG("Inside houghTransform"); 00103 int imageWidth = inputImage.getWidth(); 00104 int imageHeight = inputImage.getHeight(); 00105 //get the total number of angles and P from the resolution of theta and P's 00106 int numAngle = (int) (360 / thetaRes); //in degrees 00107 int numP = (int) (((max(imageHeight, imageWidth) / 2) - 1) / dRes); 00108 00109 00110 //stores the lines found in the image 00111 std::vector <LineSegment2D> lines; 00112 00113 //accumulator -> represents the hough space 00114 int accumulator[numP][numAngle]; 00115 00116 LDEBUG("Clearing accumulator"); 00117 00118 //fill accumulator with zeroes 00119 for(int i = 0; i<numP; i++) 00120 { 00121 for(int j = 0; j < numAngle; j++) 00122 { 00123 accumulator[i][j] = 0; 00124 } 00125 } 00126 00127 // Normal Parameterization of a Line: 00128 // p = x * cos(theta) + y * sin(theta) 00129 //////////////////////////Mike///////////////////////////// 00130 00131 LDEBUG("Accumulator is cleared"); 00132 00133 float theta; 00134 for(int p = 0; p < numP; p++) 00135 { 00136 for(int angle = 0; angle < numAngle; angle++) 00137 { 00138 theta = angle * thetaRes; 00139 00140 //skip the thrid quadrant 00141 if(theta == 180) 00142 theta = 271; 00143 00144 Point2D<int> intercept1, intercept2; 00145 00146 findEndPoints(p, theta, &intercept1, &intercept2, Dims(imageWidth, imageHeight)); 00147 00148 //increment accumulator every time a white pixel lies on the 00149 //line plotted by bresenham algorithm using the endpoints found before 00150 00151 int x0 = intercept1.i; 00152 int x1 = intercept1.j; 00153 int y0 = intercept2.i; 00154 int y1 = intercept2.j; 00155 00156 bool steep = abs(y1 - y0) > abs(x1 - x0); 00157 if(steep) 00158 { 00159 swap(x0, y0); 00160 swap(x1, y1); 00161 } 00162 00163 if(x0 > x1) 00164 { 00165 swap(x0, x1); 00166 swap(y0, y1); 00167 } 00168 00169 int deltax = x1 - x0; 00170 int deltay = abs(y1 - y0); 00171 int error = -deltax / 2; 00172 int ystep; 00173 int y = y0; 00174 int x; 00175 00176 if(y0 < y1) 00177 { 00178 ystep = 1; 00179 } 00180 else 00181 { 00182 ystep = -1; 00183 } 00184 00185 for(x = x0; x < x1; x++) 00186 { 00187 if(steep) 00188 { 00189 if(inputImage.getVal(y,x) == 255) 00190 { 00191 accumulator[p][angle]++; 00192 } 00193 } 00194 else 00195 { 00196 if(inputImage.getVal(x,y) == 255) 00197 { 00198 accumulator[p][angle]++; 00199 } 00200 } 00201 00202 error = error + deltay; 00203 00204 if(error > 0) 00205 { 00206 y = y + ystep; 00207 error = error - deltax; 00208 } 00209 } 00210 00211 for(int i = 0; i<numP; i++) 00212 { 00213 for(int j = 0; j < numAngle; j++) 00214 { 00215 theta = j * thetaRes; 00216 if(accumulator[i][j] > threshold && accumulator[i][j] > accumulator[i-1][j] 00217 && accumulator[i][j] > accumulator[i+1][j] && accumulator[i][j] > accumulator[i][j-1] 00218 && accumulator[i][j] > accumulator[i][j+1])//found a peak 00219 { 00220 Point2D<int> lineEndPoint1, lineEndPoint2; 00221 findEndPoints(i , theta, &lineEndPoint1, &lineEndPoint2, Dims(imageWidth, imageHeight)); 00222 00223 LineSegment2D theLine(lineEndPoint1, lineEndPoint2); 00224 00225 lines.push_back(theLine); 00226 } 00227 } 00228 } 00229 00230 } 00231 } 00232 00233 return lines; 00234 } 00235 00236 00237 ////////////////////////////////////////////////////////// 00238 /* 00239 //equation of the line is Xcos(theta)+ysin(theta) = D 00240 // fill the accumulator 00241 // printf("numD is %d\n",numD); 00242 for(int j = 0; j < inputImage.getHeight(); j++ ) { 00243 for(int i = 0; i < inputImage.getWidth(); i++ ) 00244 { 00245 if( inputImage.getVal(i,j) != 0 )//point is an edge 00246 for(int n = 0; n < numangle; n++ )//get all possible D and theta that can fit to that point 00247 { 00248 r = (int)(i * cos(n*thetaRes) + j * sin(n*thetaRes)); 00249 r += (numD -1)/2; 00250 00251 if(r > 0 && r < numD) //Avoid segfaults 00252 accumulator[r][n]++; 00253 00254 00255 } 00256 } 00257 } 00258 00259 Point2D<int> p1; 00260 Point2D<int> p2; 00261 Point2D<int> storage[inputImage.getWidth()*inputImage.getHeight()]; 00262 double a, b; 00263 int totalLines = 0; 00264 int pointCount = 0; 00265 00266 00267 00268 // find the peaks, ie any number greater than the threshold is considered a line 00269 for(int i = 0; i<numD; i++) 00270 { 00271 for(int j = 0; j < numangle; j++) 00272 { 00273 if(accumulator[i][j] > threshold && accumulator[i][j]> accumulator[i-1][j] 00274 && accumulator[i][j]> accumulator[i+1][j] && accumulator[i][j]> accumulator[i][j-1] 00275 && accumulator[i][j]> accumulator[i][j+1])//found a peak 00276 { 00277 totalLines++; 00278 00279 //get the image coordinates for the 2 endpoint of the line 00280 a = cos(j*thetaRes); 00281 b = sin(j*thetaRes); 00282 00283 //TODO: ROOM FOR IMPROVEMENT! 00284 for(int x = 0; x < inputImage.getWidth(); x++) { 00285 for(int y = 0; y < inputImage.getHeight(); y++) { 00286 if( inputImage.getVal(x,y) != 0 )//point is an edge 00287 if(((int)(x * cos(j*thetaRes) + y * sin(j*thetaRes))) + ((numD -1)/2) == i) 00288 { 00289 storage[pointCount].i = x; 00290 storage[pointCount].j = y; 00291 pointCount++; 00292 } 00293 } 00294 } 00295 00296 //check the distance between each point 00297 bool isolated = true; 00298 int numtoDiscard = 0; 00299 float discardPoints[inputImage.getWidth() * inputImage.getHeight()]; 00300 for(int y = 0; y < pointCount; y++){ 00301 for(int x = 0; x <pointCount; x++){ 00302 if(storage[0].distance(storage[x]) < 1 && x != y) 00303 isolated = false; 00304 00305 } 00306 if(isolated)//discard this point 00307 { 00308 discardPoints[numtoDiscard++] = y; 00309 } 00310 } 00311 00312 00313 //make sure that the point is not in the to be discarded list 00314 for(int x=0; x < numtoDiscard; x++) { 00315 for(int y = 0; y < pointCount; y++) { 00316 if(discardPoints[x] != y){ 00317 p1.i = p2.i = storage[y].i; 00318 p1.j = p2.j = storage[y].j; 00319 00320 } 00321 00322 } 00323 } 00324 //find the 2 endpoints of line 00325 //check if vertical 00326 if(fabs(a) < .001) 00327 { 00328 00329 //search the 2 endpoints 00330 for(int x = 0; x < pointCount; x++) 00331 { 00332 00333 bool discard = false; 00334 for(int k = 0; k < numtoDiscard; k++) { 00335 if(discardPoints[k] == x) 00336 discard = true; 00337 } 00338 00339 if(!discard){ 00340 if(p1.j < storage[x].j) 00341 { 00342 p1.j = storage[x].j; 00343 p1.i = storage[x].i; 00344 } 00345 if(p2.j > storage[x].j) 00346 { 00347 p2.j = storage[x].j; 00348 p2.i = storage[x].i; 00349 00350 } 00351 } 00352 } 00353 00354 } 00355 else // horizontal 00356 { 00357 //search the 2 endpoints 00358 for(int x = 0; x < pointCount; x++) 00359 { 00360 bool discard = false; 00361 for(int k = 0; k < numtoDiscard; k++) { 00362 if(discardPoints[k] == x) 00363 discard = true; 00364 00365 } 00366 00367 if(!discard){ 00368 00369 if(p1.i < storage[x].i) 00370 { 00371 p1.j = storage[x].j; 00372 p1.i = storage[x].i; 00373 } 00374 if(p2.i > storage[x].i) 00375 { 00376 p2.j = storage[x].j; 00377 p2.i = storage[x].i; 00378 00379 } 00380 } 00381 } 00382 } 00383 pointCount = 0; 00384 00385 00386 LineSegment2D thisLine(p1, p2); 00387 00388 00389 if (thisLine.isValid()) { 00390 00391 00392 lines.push_back(thisLine); 00393 drawLine(output, p1, p2, PixRGB<byte> (255,0,0), 1); 00394 } 00395 00396 } 00397 } 00398 }*/ 00399 00400 /* 00401 functions to find the best fit line 00402 */ 00403 00404 00405 00406 #endif 00407