$search
00001 00005 #include "calibration.hpp" 00006 00007 void generateRandomIndexArray(int * randomArray, int maxElements, int maxVal) 00008 { 00009 00010 srand ( (unsigned int)(time(NULL)) ); 00011 00012 vector<int> validValuesVector, randomSelection; 00013 00014 for (int iii = 0; iii < maxVal; iii++) 00015 { 00016 validValuesVector.push_back(iii); 00017 } 00018 00019 for (int iii = 0; iii < maxElements; iii++) 00020 { 00021 int currIndex = rand() % validValuesVector.size(); 00022 00023 randomSelection.push_back(validValuesVector.at(currIndex)); 00024 validValuesVector.erase(validValuesVector.begin() + currIndex); 00025 } 00026 00027 sort(randomSelection.begin(), randomSelection.end()); 00028 00029 for (int iii = 0; iii < randomSelection.size(); iii++) 00030 { 00031 randomArray[iii] = randomSelection.at(iii); 00032 } 00033 } 00034 00035 mserPatch::mserPatch() 00036 { 00037 00038 } 00039 00040 mserPatch::mserPatch(vector<Point>& inputHull, const Mat& image) 00041 { 00042 double dbx, dby; 00043 int x, y, division = 0; 00044 meanIntensity = 0.0; 00045 00046 copyContour(inputHull, hull); 00047 00048 // get moments 00049 momentSet = moments(Mat(hull)); 00050 00051 // get centroid 00052 dbx = (momentSet.m10/momentSet.m00); 00053 dby = (momentSet.m01/momentSet.m00); 00054 x = (int) dbx; 00055 y = (int) dby; 00056 centroid = Point(x,y); 00057 centroid2f = Point2f(dbx, dby); 00058 00059 // get area 00060 area = contourArea(Mat(hull)); 00061 00062 int searchDist = 15; 00063 00064 // get mean pixel intensity 00065 for (int i = x-searchDist; i < x+searchDist+1; i++) 00066 { 00067 for (int j = y-searchDist; j < y+searchDist+1; j++) 00068 { 00069 00070 if (pointPolygonTest(Mat(hull), Point2f(i,j), false) > 0.0) 00071 { 00072 //printf("%s << (j, i) = (%d, %d)\n", __FUNCTION__, j, i); 00073 meanIntensity = meanIntensity + double(image.at<Vec3b>(j,i)[0]); 00074 division++; 00075 } 00076 } 00077 } 00078 00079 meanIntensity /= division; 00080 00081 // get variance 00082 varIntensity = 0.0; 00083 00084 for (int i = x-searchDist; i < x+searchDist+1; i++) 00085 { 00086 for (int j = y-searchDist; j < y+searchDist+1; j++) 00087 { 00088 00089 if (pointPolygonTest(Mat(hull), Point2f(i,j), false) > 0.0) 00090 { 00091 //printf("%s << (j, i) = (%d, %d)\n", __FUNCTION__, j, i); 00092 varIntensity += pow((meanIntensity - double(image.at<Vec3b>(j,i)[0])), 2); 00093 } 00094 } 00095 } 00096 00097 varIntensity /= division; 00098 00099 //printf("%s << variance = %f\n", __FUNCTION__, varIntensity); 00100 00101 // get mean pixel intensity 00102 /* 00103 for (int i = x-7; i < x+8; i++) { 00104 if ((i < 0) || (i >= image.cols)) { 00105 i++; 00106 } else { 00107 for (int j = y-7; j < y+8; j++) { 00108 if ((j < 0) || (j >= image.rows)) { 00109 j++; 00110 } else { 00111 //printf("center: %d, %d\n", x, y); 00112 //printf("%s << j = %d; i = %d\n", __FUNCTION__, j, i); 00113 meanIntensity = meanIntensity + double(image.at<Vec3b>(j,i)[0]); 00114 //printf("in loop: %d, %d\n", i, j); 00115 //cin.get(); 00116 division++; 00117 } 00118 00119 } 00120 } 00121 } 00122 */ 00123 00124 00125 00126 // get variance of pixel intensity 00127 } 00128 00129 bool findMaskCorners_1(const Mat& image, Size patternSize, vector<Point2f>& corners, int detector) 00130 { 00131 Mat grayIm; 00132 if (image.channels() > 1) { 00133 cvtColor(image, grayIm, CV_RGB2GRAY); 00134 } else { 00135 grayIm = Mat(image); 00136 } 00137 //cout << "ALPHA" << endl; 00138 return findPatternCorners(grayIm, patternSize, corners, 1, detector); 00139 } 00140 00141 //HGH 00142 bool findMaskCorners_2(const Mat& image, Size patternSize, vector<Point2f>& corners, int detector, int mserDelta, float max_var, float min_diversity, double area_threshold) 00143 { 00144 Mat grayIm; 00145 if (image.channels() > 1) { 00146 cvtColor(image, grayIm, CV_RGB2GRAY); 00147 } else { 00148 grayIm = Mat(image); 00149 } 00150 //cout << "ALPHA" << endl; 00151 return findPatternCorners2(grayIm, patternSize, corners, 1, detector, mserDelta, max_var, min_diversity, area_threshold); 00152 } 00153 00154 00155 bool checkAcutance() 00156 { 00157 bool retVal = true; 00158 00159 return retVal; 00160 } 00161 00162 void determinePatchDistribution(Size patternSize, int mode, int &rows, int &cols, int &quant) 00163 { 00164 if (mode == 0) 00165 { 00166 rows = patternSize.height + 1; 00167 cols = patternSize.width + 1; 00168 quant = patternSize.width*patternSize.height/2; 00169 } 00170 else 00171 { 00172 rows = patternSize.height / 2; 00173 cols = patternSize.width / 2; 00174 quant = patternSize.width*patternSize.height/4; 00175 } 00176 00177 } 00178 00179 void findAllPatches(const Mat& image, Size patternSize, vector<vector<Point> >& msers) 00180 { 00181 00182 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 0); 00183 00184 int64 t = getTickCount(); 00185 00186 int imWidth = image.size().width; 00187 int imHeight = image.size().height; 00188 int maxArea, minArea; 00189 00190 maxArea = 2 * (imWidth / (patternSize.width-1)) * (imHeight / (patternSize.height-1)); 00191 minArea = 100; 00192 00193 int X = patternSize.width/2, Y = patternSize.height/2; 00194 00195 Mat displayMat(image); 00196 Mat mask = Mat::ones(image.rows, image.cols, CV_8U); 00197 00198 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 1); 00199 00200 // 15 00201 MSER mserExtractor(7.5, minArea, maxArea, 0.25, 0.2, 200, 1.01, 0.003, 5); // delta = 8, max var = 0.1 00202 /* 00203 cvMSERParams(int delta = 5, int min_area = 60, int max_area = 14400, \n" 00204 " float max_variation = .25, float min_diversity = .2, \n" 00205 " int max_evolution = 200, double area_threshold = 1.01, \n" 00206 " double min_margin = .003, \n" 00207 " int edge_blur_size = 5) 00208 */ 00209 00210 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 2); 00211 00212 // Copy image but into greyscale 00213 Mat imGrey; 00214 if (image.channels() > 1) 00215 { 00216 cvtColor(image, imGrey, CV_RGB2GRAY); 00217 } 00218 else 00219 { 00220 image.copyTo(imGrey); 00221 } 00222 00223 // Blur image a bit... 00224 int kernelSize = min(imWidth, imHeight) / (5*max(patternSize.width, patternSize.height)); 00225 kernelSize = kernelSize + 1 + (kernelSize % 2); 00226 //printf("%s << kernelSize = %d\n", __FUNCTION__, kernelSize); 00227 GaussianBlur(imGrey, imGrey, Size(kernelSize,kernelSize), 0,0); 00228 00229 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 3); 00230 00231 //printf("%s << imGrey.size() = (%d,%d)\n", __FUNCTION__, imGrey.rows, imGrey.cols); 00232 00233 //imshow("blurred", imGrey); 00234 //waitKey(0); 00235 00236 00237 // Processing of greyscale version 00238 // thresholding? 00239 00240 00241 // Extract MSER features 00242 mserExtractor(imGrey, msers, mask); 00243 00244 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 4); 00245 00246 // Clean up MSER features by putting them in a convex hull 00247 for (unsigned int i = 0; i < msers.size(); i++) 00248 { 00249 convexHull(Mat(msers[i]), msers[i]); 00250 } 00251 00252 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 5); 00253 00254 if (DEBUG_MODE > 1) 00255 { 00256 printf("%s << MSERs found: %d\n", __FUNCTION__, msers.size()); 00257 } 00258 00259 if (DEBUG_MODE > 0) 00260 { 00261 t = getTickCount() - t; 00262 printf("%s << Algorithm duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 00263 } 00264 00265 // Extract SURF features 00266 /* 00267 SURF surfExtractor(); 00268 00269 vector<KeyPoint> surfs; 00270 surfExtractor(imGrey, mask, surfs); 00271 */ 00272 00273 if (DEBUG_MODE > 1) 00274 { 00275 printf("%s << Total patches found = %d\n", __FUNCTION__, msers.size()); 00276 } 00277 } 00278 00279 //HGH 00280 void findAllPatches2(const Mat& image, Size patternSize, vector<vector<Point> >& msers, int delta, float max_var, float min_diversity, double area_threshold) 00281 { 00282 00283 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 0); 00284 00285 int64 t = getTickCount(); 00286 00287 int imWidth = image.size().width; 00288 int imHeight = image.size().height; 00289 int maxArea, minArea; 00290 00291 maxArea = 2 * (imWidth / (patternSize.width-1)) * (imHeight / (patternSize.height-1)); 00292 minArea = 100; 00293 00294 int X = patternSize.width/2, Y = patternSize.height/2; 00295 00296 Mat displayMat(image); 00297 Mat mask = Mat::ones(image.rows, image.cols, CV_8U); 00298 00299 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 1); 00300 00301 // 15 00302 MSER mserExtractor(delta, minArea, maxArea, max_var, min_diversity, 200, area_threshold, 0.003, 5); // delta = 8, max var = 0.1 00303 /* 00304 cvMSERParams(int delta = 5, int min_area = 60, int max_area = 14400, \n" 00305 " float max_variation = .25, float min_diversity = .2, \n" 00306 " int max_evolution = 200, double area_threshold = 1.01, \n" 00307 " double min_margin = .003, \n" 00308 " int edge_blur_size = 5) 00309 */ 00310 00311 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 2); 00312 00313 // Copy image but into greyscale 00314 Mat imGrey; 00315 if (image.channels() > 1) 00316 { 00317 cvtColor(image, imGrey, CV_RGB2GRAY); 00318 } 00319 else 00320 { 00321 image.copyTo(imGrey); 00322 } 00323 00324 // Blur image a bit... 00325 int kernelSize = min(imWidth, imHeight) / (5*max(patternSize.width, patternSize.height)); 00326 kernelSize = kernelSize + 1 + (kernelSize % 2); 00327 //printf("%s << kernelSize = %d\n", __FUNCTION__, kernelSize); 00328 GaussianBlur(imGrey, imGrey, Size(kernelSize,kernelSize), 0,0); 00329 00330 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 3); 00331 00332 //printf("%s << imGrey.size() = (%d,%d)\n", __FUNCTION__, imGrey.rows, imGrey.cols); 00333 00334 //imshow("blurred", imGrey); 00335 //waitKey(0); 00336 00337 00338 // Processing of greyscale version 00339 // thresholding? 00340 00341 00342 // Extract MSER features 00343 mserExtractor(imGrey, msers, mask); 00344 00345 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 4); 00346 00347 // Clean up MSER features by putting them in a convex hull 00348 for (unsigned int i = 0; i < msers.size(); i++) 00349 { 00350 convexHull(Mat(msers[i]), msers[i]); 00351 } 00352 00353 //printf("%s << DEBUG {%d}{%d}\n", __FUNCTION__, 0, 5); 00354 00355 if (DEBUG_MODE > 1) 00356 { 00357 printf("%s << MSERs found: %d\n", __FUNCTION__, msers.size()); 00358 } 00359 00360 if (DEBUG_MODE > 0) 00361 { 00362 t = getTickCount() - t; 00363 printf("%s << Algorithm duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 00364 } 00365 00366 // Extract SURF features 00367 /* 00368 SURF surfExtractor(); 00369 00370 vector<KeyPoint> surfs; 00371 surfExtractor(imGrey, mask, surfs); 00372 */ 00373 00374 if (DEBUG_MODE > 1) 00375 { 00376 printf("%s << Total patches found = %d\n", __FUNCTION__, msers.size()); 00377 } 00378 } 00379 00380 void randomCulling(vector<std::string> &inputList, int maxSearch) 00381 { 00382 00383 srand ( (unsigned int)(time(NULL)) ); 00384 00385 int deletionIndex = 0; 00386 00387 while (inputList.size() > maxSearch) 00388 { 00389 deletionIndex = rand() % inputList.size(); 00390 inputList.erase(inputList.begin() + deletionIndex); 00391 } 00392 } 00393 00394 void randomCulling(vector<std::string> &inputList, int maxSearch, vector<vector<Point2f> >& patterns) 00395 { 00396 00397 srand ( (unsigned int)(time(NULL)) ); 00398 00399 int deletionIndex = 0; 00400 00401 while (inputList.size() > maxSearch) 00402 { 00403 deletionIndex = rand() % inputList.size(); 00404 inputList.erase(inputList.begin() + deletionIndex); 00405 patterns.erase(patterns.begin() + deletionIndex); 00406 } 00407 } 00408 00409 void randomCulling(vector<string>& inputList, int maxSearch, vector<vector<vector<Point2f> > >& patterns) 00410 { 00411 srand ( (unsigned int)(time(NULL)) ); 00412 00413 int deletionIndex = 0; 00414 00415 printf("%s << inputList.size() = %d / %d\n", __FUNCTION__, inputList.size(), maxSearch); 00416 00417 while (inputList.size() > maxSearch) 00418 { 00419 deletionIndex = rand() % inputList.size(); 00420 inputList.erase(inputList.begin() + deletionIndex); 00421 00422 for (int i = 0; i < patterns.size(); i++) 00423 { 00424 patterns.at(i).erase(patterns.at(i).begin() + deletionIndex); 00425 } 00426 00427 } 00428 00429 //printf("%s << patterns.at(i).size() = %d / %d\n", __FUNCTION__, patterns.at(0).size(), maxSearch); 00430 //printf("%s << Waiting for key...\n", __FUNCTION__); 00431 //cin.get(); 00432 } 00433 00434 void debugDisplayPatches(const Mat& image, vector<vector<Point> >& msers) 00435 { 00436 00437 Scalar color(0, 0, 255); 00438 Mat dispMat; 00439 00440 image.copyTo(dispMat); 00441 00442 drawContours(dispMat, msers, -1, color, 1); 00443 00444 if (image.cols > 640) 00445 { 00446 Mat dispMat2; 00447 resize(dispMat, dispMat2, Size(0,0), 0.5, 0.5); 00448 imshow("mainWin", dispMat2); 00449 } 00450 else 00451 { 00452 imshow("mainWin", dispMat); 00453 } 00454 00455 waitKey(0); 00456 } 00457 00458 void determineFindablePatches(Size patternSize, int mode, int *XVec, int *YVec) 00459 { 00460 int X, Y; 00461 00462 if (mode == 0) 00463 { 00464 00465 Y = patternSize.height + 1; 00466 00467 // XVec tells you how many 'black' patches to look for between extremes in that row 00468 00469 for (int i = 0; i < Y; i++) 00470 { 00471 if ((i % 2) > 0) // odd 00472 { 00473 XVec[i] = int(ceil(((double(patternSize.width) + 1)/2)-0.01)-1); 00474 } 00475 else // even 00476 { 00477 XVec[i] = int(floor(((double(patternSize.width) + 1)/2)+0.01)-1); 00478 } 00479 00480 } 00481 00482 // YVec tells you how many 'black' patches to look for between extremes on the LHS and RHS 00483 YVec[0] = int(floor(((patternSize.height + 1)/2)+0.01)-1); 00484 00485 if (patternSize.width % 2) // odd 00486 { 00487 if (patternSize.height % 2) // odd 00488 { 00489 YVec[1] = int(floor(((patternSize.height + 1)/2)+0.01)-1); 00490 } 00491 else 00492 { 00493 YVec[1] = int(floor(((patternSize.height + 1)/2)+0.01)); 00494 } 00495 00496 } 00497 else // even 00498 { 00499 YVec[1] = int(floor(((patternSize.height + 1)/2)+0.01)-1); 00500 } 00501 00502 } 00503 else 00504 { 00505 X = patternSize.width/2; 00506 Y = patternSize.height/2; 00507 00508 for (int i = 0; i < Y; i++) 00509 { 00510 if (i % 2) 00511 { 00512 XVec[i] = patternSize.width/2 - 2; 00513 } 00514 else 00515 { 00516 XVec[i] = patternSize.width/2 - 2; 00517 } 00518 00519 } 00520 00521 YVec[0] = Y-2; 00522 YVec[1] = Y-2; 00523 } 00524 00525 if (DEBUG_MODE > 3) 00526 { 00527 printf("%s << Total number of rows: %d\n", __FUNCTION__, Y); 00528 printf("%s << Number of findable patches in LHS: %d\n", __FUNCTION__, YVec[0]); 00529 printf("%s << Number of findable patches in RHS: %d\n", __FUNCTION__, YVec[1]); 00530 00531 for (int i = 0; i < Y; i++) 00532 { 00533 printf("%s << Number of findable patches in row[%d]: %d\n", __FUNCTION__, i, XVec[i]); 00534 } 00535 } 00536 } 00537 00538 void findCornerPatches(Size imageSize, Size patternSize, int mode, int *XVec, int *YVec, vector<Point2f>& patchCentres, vector<Point2f>& remainingPatches) 00539 { 00540 00541 Point2f center; 00542 float angle; 00543 Size2f size; 00544 vector<vector<Point> > sideCenters(1); 00545 vector<vector<Point> > fourCorners(1); 00546 vector<Point> orderedCorners; 00547 vector<vector<Point> > orderedForDisplay; 00548 double x,y,X,Y; 00549 //vector<Point> wrapperHull; 00550 00551 //convexHull(Mat(remainingPatches), wrapperHull); 00552 00553 RotatedRect wrapperRectangle; 00554 00555 wrapperRectangle = fitEllipse(Mat(remainingPatches)); 00556 00557 center = wrapperRectangle.center; 00558 angle = wrapperRectangle.angle; 00559 size = wrapperRectangle.size; 00560 00561 //printf("%s << Wrapper Rectangle params: center = [%f, %f]; angle = %f; size = [%f, %f]\n", __FUNCTION__, center.x, center.y, angle, size.width, size.height); 00562 00563 //vertices.push_back(Point2f(center.x - size.height*cos(angle), center.y - size.width*sin(angle))); 00564 //vertices.push_back(Point2f(center.x + size.height*cos(angle), center.y + size.width*sin(angle))); 00565 00566 x = center.x; 00567 y = center.y; 00568 X = (size.width / 2) * 1.2; // dilate the elipse otherwise it might 00569 Y = (size.height / 2) * 1.2; 00570 00571 //sideCenters.at(0).push_back(Point(x-X*cos((3.14/180)*angle),y+X*sin((3.14/180)*angle))); 00572 //sideCenters.at(0).push_back(Point(x, y)); 00573 /* 00574 sideCenters.at(0).push_back(Point(x-Y*sin((3.14/180)*angle),y+Y*cos((3.14/180)*angle))); 00575 sideCenters.at(0).push_back(Point(x+X*cos((3.14/180)*angle),y+X*sin((3.14/180)*angle))); 00576 sideCenters.at(0).push_back(Point(x+Y*sin((3.14/180)*angle),y-Y*cos((3.14/180)*angle))); 00577 sideCenters.at(0).push_back(Point(x-X*cos((3.14/180)*angle),y-X*sin((3.14/180)*angle))); 00578 */ 00579 00580 fourCorners.at(0).push_back(Point(int(x-X*cos((3.14/180)*angle)-Y*sin((3.14/180)*angle)), int(y-X*sin((3.14/180)*angle)+Y*cos((3.14/180)*angle)))); 00581 fourCorners.at(0).push_back(Point(int(x+Y*sin((3.14/180)*angle)-X*cos((3.14/180)*angle)), int(y-Y*cos((3.14/180)*angle)-X*sin((3.14/180)*angle)))); 00582 fourCorners.at(0).push_back(Point(int(x+X*cos((3.14/180)*angle)+Y*sin((3.14/180)*angle)), int(y+X*sin((3.14/180)*angle)-Y*cos((3.14/180)*angle)))); 00583 fourCorners.at(0).push_back(Point(int(x-Y*sin((3.14/180)*angle)+X*cos((3.14/180)*angle)), int(y+Y*cos((3.14/180)*angle)+X*sin((3.14/180)*angle)))); 00584 00585 00586 for (int i = 0; i < 4; i++) 00587 { 00588 //printf("x = %d, y = %d\n", fourCorners.at(0).at(i).x, fourCorners.at(0).at(i).y); 00589 } 00590 00591 //waitKey(0); 00592 00593 Mat imCpy(imageSize, CV_8UC3); 00594 imCpy.setTo(0); 00595 Scalar color( rand()&255, rand()&255, rand()&255 ); 00596 00597 ellipse(imCpy, wrapperRectangle, color); 00598 00599 color = Scalar(rand()&255, rand()&255, rand()&255); 00600 00601 00602 //drawContours(imCpy, fourCorners, -1, color, 3); 00603 //rectangle(imCpy, vertices.at(0), vertices.at(1), color, 2); 00604 //imshow("testWin", imCpy); 00605 //waitKey(0); 00606 00607 00608 // Now re-order these points according to which one is closest to each image corner: 00609 00610 double distMin[4] = {99999999, 99999999, 99999999, 99999999}; 00611 double dist; 00612 int distIndex[4] = {0, 0, 0, 0}; 00613 float extremesX[4] = {0.0, float(imageSize.width), float(imageSize.width), 0.0}; // TL, TR, BR, BL 00614 float extremesY[4] = {0.0, 0.0, float(imageSize.height), float(imageSize.height)}; 00615 Point tmpPoint; 00616 double minDist; 00617 int minIndex = 0; 00618 double sumDist; 00619 //int bestConfiguration; 00620 00621 // For each of the four configurations 00622 minDist = 9e9; 00623 00624 for (int k = 0; k < 4; k++) 00625 { 00626 orderedCorners.clear(); 00627 sumDist = 0; 00628 // For each of the remaining rectangle corners 00629 for (int i = 0; i < 4; i++) 00630 { 00631 tmpPoint = Point(int(extremesX[i]), int(extremesY[i])); 00632 dist = distBetweenPts(fourCorners.at(0).at((k+i)%4), tmpPoint); 00633 //printf("dist[%d,%d] = %f\n", k, i, dist); 00634 00635 sumDist += dist; 00636 } 00637 00638 //printf("sumDist[%d] = %f\n", k, sumDist); 00639 00640 if (sumDist < minDist) 00641 { 00642 minDist = sumDist; 00643 minIndex = k; 00644 } 00645 } 00646 00647 //printf("minIndex = %d\n", minIndex); 00648 00649 // now minIndex represents the best configuration 00650 orderedCorners.push_back(fourCorners.at(0).at((minIndex)%4)); 00651 orderedCorners.push_back(fourCorners.at(0).at((minIndex+1)%4)); 00652 orderedCorners.push_back(fourCorners.at(0).at((minIndex+3)%4)); 00653 orderedCorners.push_back(fourCorners.at(0).at((minIndex+2)%4)); 00654 00655 for (int i = 0; i < 4; i++) 00656 { 00657 //printf("x = %d, y = %d\n", orderedCorners.at(i).x, orderedCorners.at(i).y); 00658 } 00659 00660 //waitKey(0); 00661 00662 /* 00663 orderedForDisplay.push_back(orderedCorners); 00664 drawContours(imCpy, orderedForDisplay, -1, color, 3); 00665 //rectangle(imCpy, vertices.at(0), vertices.at(1), color, 2); 00666 imshow("testWin", imCpy); 00667 waitKey(40); 00668 */ 00669 00670 vector<Point> pointPair; 00671 00672 // go thru remaining points and add the ones that are closest to these 00673 for (int k = 0; k < 4; k++) 00674 { 00675 minDist = 9e9; 00676 for (unsigned int i = 0; i < remainingPatches.size(); i++) 00677 { 00678 00679 //printf("%s << remainingPatches.at(%d) = (%f, %f)\n", __FUNCTION__, i, remainingPatches.at(i).x, remainingPatches.at(i).y); 00680 00681 pointPair.clear(); 00682 pointPair.push_back(orderedCorners.at(k)); 00683 pointPair.push_back(remainingPatches.at(i)); 00684 dist = arcLength(Mat(pointPair), false); // total distance to extremes 00685 00686 //printf("distance for point [%d] to corner [%d] = %f\n", i, k, dist); 00687 00688 if (dist < minDist) 00689 { 00690 //printf("minimum found.\n"); 00691 minDist = dist; 00692 minIndex = i; 00693 } 00694 00695 } 00696 00697 //printf("Best point for %d: %d\n", k, minIndex); 00698 //circle(imCpy, corners.at(minIndex), 8, color, 3, 8, 0); 00699 transferElement(patchCentres, remainingPatches, minIndex); 00700 } 00701 00702 if (DEBUG_MODE > 3) 00703 { 00704 for (unsigned int i = 0; i < patchCentres.size(); i++) 00705 { 00706 printf("%s << patchCentres.at(%d) = (%f, %f)\n", __FUNCTION__, i, patchCentres.at(i).x, patchCentres.at(i).y); 00707 } 00708 00709 printf("%s << remainingPatches.size() = %d\n", __FUNCTION__, remainingPatches.size()); 00710 } 00711 00712 return; 00713 00714 // TODO: 00715 // Depending on the pattern dimensions, not all corners will be occupied by black squares (for chessboard). 00716 // However, at least 2 will definitely be. If it's not a single black patch in a corner, it will be 00717 // 2 black patches in a corner 00718 00719 // Real or virtual corners are now stored in cornerPoints 00720 // Could also try to look at which patches have an insufficient number of near-neighbours to be interior 00721 00722 // Once corners and virtual corners are found, figure out which corner of the image to attach them to 00723 // based on a minimization of distances between the four pattern corners and the four image corners 00724 00725 // This function should create virtual corners as necessary 00726 00727 // Correct order of points 00728 //double imgCornerDistances[remainingPatches.size()][4]; 00729 //double distMin[4] = {99999999, 99999999, 99999999, 99999999}; 00730 //double dist; 00731 //int distIndex[4] = {0, 0, 0, 0}; 00732 //float extremesX[4] = {0, imageSize.width, 0, imageSize.width}; 00733 //float extremesY[4] = {0, 0, imageSize.height, imageSize.height}; 00734 00735 if (DEBUG_MODE > 3) 00736 { 00737 printf("%s << imageSize.width = %d; imageSize.height = %d\n", __FUNCTION__, imageSize.width, imageSize.height); 00738 } 00739 //int cornerIndex[4] = {0, X-1, X*Y-X, X*Y-1}; // this should depend on pattern size 00740 //int cornerIndex[4] = {0, 1, 2, 3}; 00741 00742 00743 Point intermediatePt; 00744 00745 Point tempPt; 00746 00747 //printf("%s << DEBUG 000\n", __FUNCTION__); 00748 00749 if (DEBUG_MODE > 3) 00750 { 00751 printf("%s << remainingPatches.size() = %d\n", __FUNCTION__, remainingPatches.size()); 00752 } 00753 00754 // For all 4 corners... 00755 for (int k = 0; k < 4; k++) 00756 { 00757 minDist = 99999999; 00758 // Search all remaining patches 00759 for (unsigned int i = 0; i < remainingPatches.size(); i++) 00760 { 00761 00762 //printf("%s << remainingPatches.at(%d) = (%f, %f)\n", __FUNCTION__, i, remainingPatches.at(i).x, remainingPatches.at(i).y); 00763 00764 pointPair.clear(); 00765 pointPair.push_back(Point(int(extremesX[k]), int(extremesY[k]))); 00766 pointPair.push_back(remainingPatches.at(i)); 00767 dist = arcLength(Mat(pointPair), false); // total distance to extremes 00768 00769 //printf("distance for point [%d] to corner [%d] = %f\n", i, k, dist); 00770 00771 if (dist < minDist) 00772 { 00773 //printf("minimum found.\n"); 00774 minDist = dist; 00775 minIndex = i; 00776 } 00777 00778 } 00779 00780 //printf("Best point for %d: %d\n", k, minIndex); 00781 //circle(imCpy, corners.at(minIndex), 8, color, 3, 8, 0); 00782 transferElement(patchCentres, remainingPatches, minIndex); 00783 00784 //imshow("MSERwin", imCpy); 00785 //waitKey(0); 00786 } 00787 00788 if (DEBUG_MODE > 3) 00789 { 00790 for (unsigned int i = 0; i < patchCentres.size(); i++) 00791 { 00792 printf("%s << patchCentres.at(%d) = (%f, %f)\n", __FUNCTION__, i, patchCentres.at(i).x, patchCentres.at(i).y); 00793 } 00794 00795 printf("%s << remainingPatches.size() = %d\n", __FUNCTION__, remainingPatches.size()); 00796 } 00797 00798 00799 } 00800 00801 void findEdgePatches(Size patternSize, int mode, int *XVec, int *YVec, vector<Point2f>& patchCentres, vector<Point2f>& remainingPatches) 00802 { 00803 int minDist, minIndex, sortedIndex = patchCentres.size(); 00804 double dist; 00805 vector<Point2f> patchString; // to store some patches before you splice stuff inside 00806 Point2f interPoint; 00807 00808 //printf("sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 00809 00810 // LHS -> Get all the edge patches 00811 //printf("%s << YVec[0] = %d\n", __FUNCTION__, YVec[0]); 00812 for (int k = 0; k < YVec[0]; k++) 00813 { 00814 // go through each remaining point 00815 minDist = 99999999; 00816 00817 for (unsigned int i = 0; i < remainingPatches.size(); i++) 00818 { 00819 // get distance to line 00820 dist = perpDist(patchCentres.at(0), patchCentres.at(2), remainingPatches.at(i)); 00821 //printf("dist (from line) [%d] = %f\n", j, dist); 00822 if (dist < minDist) 00823 { 00824 minDist = int(dist); 00825 minIndex = i; 00826 } 00827 } 00828 //printf("minDist (from line) [%d] = %f\n", minIndex, minDist); 00829 00830 // Transfer the found patch 00831 transferElement(patchString, remainingPatches, minIndex); 00832 } 00833 00834 //printf("BLEEERGH!!!\n"); 00835 00836 //printf("sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 00837 00838 // LHS -> Get the edge patches in order within the string 00839 for (int k = 0; k < YVec[0]; k++) 00840 { 00841 // go through each remaining point 00842 minDist = 99999999; 00843 00844 for (int i = k; i < YVec[0]; i++) 00845 { 00846 // get distance to top left point 00847 dist = distBetweenPts2f(patchCentres.at(0), patchString.at(i)); 00848 //printf("dist (from line) [%d] = %f\n", j, dist); 00849 if (dist < minDist) 00850 { 00851 minDist = int(dist); 00852 minIndex = i; 00853 } 00854 } 00855 //printf("minDist (from line) [%d] = %f\n", minIndex, minDist); 00856 00857 // switch to end of these points 00858 swapElements(patchString, k, minIndex); 00859 00860 00861 } 00862 00863 //printf("sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 00864 00865 // Insert patches from string and any intermediate patches 00866 if (mode == 0) 00867 { 00868 // Between top left corner and first patch (should be conditional) 00869 interPoint = meanPoint(patchCentres.at(0), patchString.at(0)); 00870 patchCentres.push_back(interPoint); 00871 00872 // between all internal-edge patches 00873 for (int k = 0; k < YVec[0]-1; k++) 00874 { 00875 //insertIntermediateElement(patchCentres, 4+2*k-1, 4+2*k, 4+2*k); 00876 interPoint = meanPoint(patchString.at(0), patchString.at(1)); 00877 transferElement(patchCentres, patchString, 0); 00878 patchCentres.push_back(interPoint); 00879 00880 } 00881 00882 //printf("size() = %d\n", patchString.size()); 00883 00884 // between last on LHS and final point (should also be conditional) 00885 interPoint = meanPoint(patchCentres.at(2), patchString.at(0)); 00886 transferElement(patchCentres, patchString, 0); 00887 patchCentres.push_back(interPoint); 00888 00889 } 00890 else 00891 { 00892 for (int k = 0; k < YVec[0]; k++) 00893 { 00894 //printf("A sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 00895 00896 transferElement(patchCentres, patchString, 0); 00897 } 00898 00899 } 00900 00901 //printf("sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 00902 00903 sortedIndex += YVec[0]; 00904 00905 //printf("SNARF!!!\n"); 00906 00907 // RHS -> Get all the edge patches 00908 //printf("%s << YVec[1] = %d\n", __FUNCTION__, YVec[1]); 00909 for (int k = 0; k < YVec[1]; k++) 00910 { 00911 // go through each remaining point 00912 minDist = 99999999; 00913 00914 for (unsigned int i = 0; i < remainingPatches.size(); i++) 00915 { 00916 // get distance to line 00917 dist = perpDist(patchCentres.at(1), patchCentres.at(3), remainingPatches.at(i)); 00918 //printf("dist (from line) [%d] = %f\n", j, dist); 00919 if (dist < minDist) 00920 { 00921 minDist = int(dist); 00922 minIndex = i; 00923 } 00924 } 00925 //printf("minDist (from line) [%d] = %f\n", minIndex, minDist); 00926 00927 // switch to start of vector 00928 transferElement(patchString, remainingPatches, minIndex); 00929 } 00930 00931 //printf("SCHMIMF!!!\n"); 00932 00933 // RHS -> Get the edge patches in order 00934 for (int k = 0; k < YVec[1]; k++) 00935 { 00936 // go through each remaining point 00937 minDist = 99999999; 00938 00939 for (int i = k; i < YVec[1]; i++) 00940 { 00941 00942 //printf("k = %d; i = %d, size = %d\n", k, i, patchString.size()); 00943 00944 // get distance to top left point 00945 dist = distBetweenPts2f(patchCentres.at(1), patchString.at(i)); 00946 //printf("dist (from line) [%d] = %f\n", j, dist); 00947 if (dist < minDist) 00948 { 00949 minDist = int(dist); 00950 minIndex = i; 00951 } 00952 } 00953 //printf("minDist (from line) [%d] = %f\n", minIndex, minDist); 00954 00955 // switch to end of these points 00956 swapElements(patchString, k, minIndex); 00957 } 00958 00959 //printf("PREFROO!!!!\n"); 00960 00961 if (mode == 0) 00962 { 00963 // Between top left corner and first patch (should be conditional) 00964 interPoint = meanPoint(patchCentres.at(1), patchString.at(0)); 00965 patchCentres.push_back(interPoint); 00966 00967 // between all internal-edge patches 00968 for (int k = 0; k < YVec[1]-1; k++) 00969 { 00970 //insertIntermediateElement(patchCentres, 4+2*k-1, 4+2*k, 4+2*k); 00971 interPoint = meanPoint(patchString.at(0), patchString.at(1)); 00972 transferElement(patchCentres, patchString, 0); 00973 patchCentres.push_back(interPoint); 00974 00975 } 00976 00977 //printf("size() = %d\n", patchString.size()); 00978 00979 // between last on LHS and final point (should also be conditional) 00980 interPoint = meanPoint(patchCentres.at(3), patchString.at(0)); 00981 transferElement(patchCentres, patchString, 0); 00982 patchCentres.push_back(interPoint); 00983 00984 } 00985 else 00986 { 00987 for (int k = 0; k < YVec[1]; k++) 00988 { 00989 //printf("A sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 00990 00991 transferElement(patchCentres, patchString, 0); 00992 } 00993 00994 } 00995 00996 sortedIndex += YVec[1]; 00997 00998 //printf("PWOGGG!!!\n"); 00999 01000 if (DEBUG_MODE > 3) 01001 { 01002 01003 printf("%s << patchCentres.size() = %d\n", __FUNCTION__, patchCentres.size()); 01004 printf("%s << remainingPatches.size() = %d\n", __FUNCTION__, remainingPatches.size()); 01005 01006 for (unsigned int i = 0; i < patchCentres.size(); i++) 01007 { 01008 printf("%s << patchCentres.at(%d) = (%f, %f)\n", __FUNCTION__, i, patchCentres.at(i).x, patchCentres.at(i).y); 01009 } 01010 01011 01012 } 01013 } 01014 01015 void findInteriorPatches(Size patternSize, int mode, int *XVec, int *YVec, vector<Point2f>& patchCentres, vector<Point2f>& remainingPatches) 01016 { 01017 // Temporary: 01018 01019 int minDist, minIndex = 0, sortedIndex = patchCentres.size();; 01020 double dist; 01021 01022 vector<Point2f> patchString; // to store some patches before you splice stuff inside 01023 Point2f interPoint; 01024 01025 int nRows; 01026 01027 if (mode == 0) 01028 { 01029 nRows = patternSize.height + 1; 01030 } 01031 else 01032 { 01033 nRows = patternSize.height / 2; 01034 } 01035 01036 //printf("%s << nRows = %d\n", __FUNCTION__, nRows); 01037 01038 // For each row: 01039 for (int r = 0; r < nRows; r++) 01040 { 01041 01042 patchString.clear(); 01043 01044 //printf("%s << XVec[%d] = %d\n", __FUNCTION__, r, XVec[r]); 01045 01046 // For each patch that is present in that row 01047 for (int k = 0; k < XVec[r]; k++) 01048 { 01049 minDist = 99999999; 01050 01051 //printf("%s << row[%d] k = %d, XVec[r] = %d\n", __FUNCTION__, r, k, XVec[r]); 01052 01053 for (unsigned int i = 0; i < remainingPatches.size(); i++) 01054 { 01055 if (r == 0) // First Row 01056 { 01057 dist = perpDist(patchCentres.at(0), patchCentres.at(1), remainingPatches.at(i)); 01058 } 01059 else if (r == (nRows-1)) // Last Row 01060 { 01061 dist = perpDist(patchCentres.at(2), patchCentres.at(3), remainingPatches.at(i)); 01062 } 01063 else // Other Rows 01064 { 01065 dist = perpDist(patchCentres.at(4+r-1), patchCentres.at(4+nRows-2+r-1), remainingPatches.at(i)); 01066 } 01067 01068 if (dist < minDist) 01069 { 01070 minDist = int(dist); 01071 minIndex = i; 01072 } 01073 01074 } 01075 01076 transferElement(patchString, remainingPatches, minIndex); 01077 } 01078 01079 //printf("BLEEERGH!!! [%d]\n", r); 01080 01081 // try to sort the patchString elements 01082 for (int k = 0; k < XVec[r]; k++) 01083 { 01084 minDist = 99999999; 01085 01086 for (int i = k; i < XVec[r]; i++) 01087 { 01088 if (r == 0) // First Row 01089 { 01090 dist = distBetweenPts2f(patchCentres.at(0), patchString.at(i)); 01091 } 01092 else if (r == (nRows-1)) // Last Row 01093 { 01094 dist = distBetweenPts2f(patchCentres.at(2), patchString.at(i)); 01095 } 01096 else // Other Rows 01097 { 01098 dist = distBetweenPts2f(patchCentres.at(4+r-1), patchString.at(i)); 01099 } 01100 01101 //printf("%s << row[%d] k = %d, i = %d, dist = %f\n", __FUNCTION__, r, k, i, dist); 01102 01103 if (dist < minDist) 01104 { 01105 minDist = int(dist); 01106 minIndex = i; 01107 } 01108 } 01109 01110 //printf("%s << moving %d to %d\n", __FUNCTION__, minIndex, k); 01111 01112 swapElements(patchString, k, minIndex); 01113 } 01114 01115 for (int k = 0; k < XVec[r]; k++) 01116 { 01117 minDist = 99999999; 01118 01119 dist = distBetweenPts2f(patchCentres.at(0), patchString.at(k)); 01120 01121 //printf("%s << dist[%d] = %f\n", __FUNCTION__, k, dist); 01122 //printf("%s << at(%d,%d)\n", __FUNCTION__, patchString.at(k).x, patchString.at(k).y); 01123 } 01124 01125 //sortedIndex += XVec[r]; 01126 01127 if (mode == 0) 01128 { 01129 // Between left point and first patch (should be conditional) 01130 if (r == 0) // First Row 01131 { 01132 interPoint = meanPoint(patchCentres.at(0), patchString.at(0)); 01133 patchCentres.push_back(interPoint); 01134 } 01135 else if (r == nRows-1) // Last Row 01136 { 01137 interPoint = meanPoint(patchCentres.at(2), patchString.at(0)); 01138 patchCentres.push_back(interPoint); 01139 01140 } 01141 else // Other Rows 01142 { 01143 if (r % 2) 01144 { 01145 01146 } 01147 else 01148 { 01149 interPoint = meanPoint(patchCentres.at(4+r-1), patchString.at(0)); 01150 patchCentres.push_back(interPoint); 01151 } 01152 01153 } 01154 01155 01156 for (int k = 0; k < XVec[r]-1; k++) 01157 { 01158 interPoint = meanPoint(patchString.at(0), patchString.at(1)); 01159 transferElement(patchCentres, patchString, 0); 01160 patchCentres.push_back(interPoint); 01161 01162 } 01163 01164 // between all internal-edge patches 01165 01166 //printf("size() = %d\n", patchString.size()); 01167 01168 // between last on LHS and final point (should also be conditional) 01169 if (r == 0) // First Row 01170 { 01171 interPoint = meanPoint(patchCentres.at(1), patchString.at(0)); 01172 transferElement(patchCentres, patchString, 0); 01173 patchCentres.push_back(interPoint); 01174 } 01175 else if (r == (nRows-1)) // Last Row 01176 { 01177 interPoint = meanPoint(patchCentres.at(3), patchString.at(0)); 01178 transferElement(patchCentres, patchString, 0); 01179 patchCentres.push_back(interPoint); 01180 } 01181 else // Other Rows 01182 { 01183 if (r % 2) 01184 { 01185 transferElement(patchCentres, patchString, 0); 01186 } 01187 else 01188 { 01189 interPoint = meanPoint(patchCentres.at(4+r-1+nRows-2), patchString.at(0)); 01190 transferElement(patchCentres, patchString, 0); 01191 patchCentres.push_back(interPoint); 01192 } 01193 01194 } 01195 01196 } 01197 else 01198 { 01199 for (int k = 0; k < XVec[r]; k++) 01200 { 01201 //printf("A sizes: %d, %d, %d\n", patchCentres.size(), patchString.size(), remainingPatches.size()); 01202 transferElement(patchCentres, patchString, 0); 01203 } 01204 01205 } 01206 } 01207 01208 01209 01210 /* 01211 while (remainingPatches.size() > 0) { 01212 transferElement(patchCentres, remainingPatches, 0); 01213 } 01214 */ 01215 01216 if (DEBUG_MODE > 3) 01217 { 01218 01219 printf("%s << patchCentres.size() = %d\n", __FUNCTION__, patchCentres.size()); 01220 printf("%s << remainingPatches.size() = %d\n", __FUNCTION__, remainingPatches.size()); 01221 01222 for (unsigned int i = 0; i < patchCentres.size(); i++) 01223 { 01224 //printf("%s << patchCentres.at(%d) = (%d, %d)\n", __FUNCTION__, i, patchCentres.at(i).x, patchCentres.at(i).y); 01225 } 01226 01227 01228 } 01229 01230 } 01231 01232 void sortPatches(Size imageSize, Size patternSize, vector<Point2f>& patchCentres, int mode) 01233 { 01234 // TODO: 01235 // See the corresponding sections. 01236 01237 int desiredPatchCount, X, Y; 01238 01239 if (mode == 0) 01240 { 01241 desiredPatchCount = (patternSize.width + 1)*(patternSize.height + 1); 01242 } 01243 else 01244 { 01245 desiredPatchCount = (patternSize.width / 2)*(patternSize.height / 2); 01246 } 01247 01248 if (DEBUG_MODE > 3) 01249 { 01250 printf("%s << Looking for [%d] patches..\n", __FUNCTION__, desiredPatchCount); 01251 //printf("%s << Configuring for mode = %d\n", __FUNCTION__, mode); 01252 } 01253 01254 // Determine the number of "findable" patches in each row and at edge columns 01255 int *XVec; 01256 int YVec[2]; 01257 01258 // XVec tells you how many 'black' patches to look for between extremes in that row 01259 if (mode == 0) 01260 { 01261 Y = patternSize.height + 1; 01262 XVec = new int[Y]; 01263 } 01264 else 01265 { 01266 X = patternSize.width/2; 01267 Y = patternSize.height/2; 01268 XVec = new int[Y]; 01269 } 01270 01271 determineFindablePatches(patternSize, mode, XVec, YVec); 01272 01273 // Copy input patchCentres to remainingPatches vector, and clear patchCentres 01274 vector<Point2f> remainingPatches; 01275 remainingPatches.clear(); 01276 patchCentres.swap(remainingPatches); 01277 01278 // Find the 4 corners of the pattern (adding virtual points as necessary) 01279 findCornerPatches(imageSize, patternSize, mode, XVec, YVec, patchCentres, remainingPatches); 01280 01281 // Find the LHS edge points and RHS edge points (adding virtual points as necessary) 01282 findEdgePatches(patternSize, mode, XVec, YVec, patchCentres, remainingPatches); 01283 01284 // Find (or simulate) interior patches 01285 findInteriorPatches(patternSize, mode, XVec, YVec, patchCentres, remainingPatches); 01286 01287 // Check that there are no remaining patches and that there are the correct no. of patches 01288 if (remainingPatches.size() > 0) 01289 { 01290 printf("%s << ERROR. There are remaining patches when there shouldn't be.\n", __FUNCTION__); 01291 01292 /* 01293 patchCentres.clear(); 01294 return; 01295 */ 01296 } 01297 01298 if (patchCentres.size() != desiredPatchCount) 01299 { 01300 printf("%s << ERROR. An incorrect number (%d vs %d) of patches have been allocated.\n", __FUNCTION__, patchCentres.size(), desiredPatchCount); 01301 01302 //patchCentres.clear(); 01303 01304 // temp for testing: 01305 while (patchCentres.size() < (unsigned int)(desiredPatchCount)) 01306 { 01307 patchCentres.push_back(Point(0,0)); 01308 } 01309 01310 delete[] XVec; 01311 01312 return; 01313 } 01314 01315 // Remap order of patches to match OpenCV format 01316 //printf("GlERP!!!\n"); 01317 reorderPatches(patternSize, mode, XVec, YVec, patchCentres); 01318 01319 delete[] XVec; 01320 } 01321 01322 void reorderPatches(Size patternSize, int mode, int *XVec, int *YVec, vector<Point2f>& patchCentres) 01323 { 01324 // TODO: 01325 // Nothing much. 01326 01327 //printf("GWanGLE!!!\n"); 01328 01329 //int X = patternSize.width/2, Y = patternSize.height/2; 01330 vector<Point2f> reSortedCorners; 01331 01332 int nRows, nCols, nOffset; 01333 01334 //printf("FlAng!!!\n"); 01335 01336 if (mode == 0) 01337 { 01338 nRows = patternSize.height + 1; 01339 nCols = patternSize.width + 1; 01340 } 01341 else 01342 { 01343 nRows = patternSize.height / 2; 01344 nCols = patternSize.width / 2; 01345 } 01346 01347 //printf("Pring!!!\n"); 01348 01349 nOffset = 4+2*(nRows-2); 01350 01351 //printf("%s << nRows = %d; nCols = %d; nOffset = %d\n", __FUNCTION__, nRows, nCols, nOffset); 01352 01353 // For each row 01354 for (int r = 0; r < nRows; r++) 01355 { 01356 // First element of row 01357 if (r == 0) // if first row 01358 { 01359 reSortedCorners.push_back(patchCentres.at(0)); 01360 } 01361 else if (r == (nRows-1)) // if last row 01362 { 01363 reSortedCorners.push_back(patchCentres.at(2)); 01364 } 01365 else // if other row 01366 { 01367 reSortedCorners.push_back(patchCentres.at(4+r-1)); 01368 } 01369 01370 // In between 01371 for (int i = 0; i < nCols-2; i++) 01372 { 01373 //printf("%s << row [%d] current Index = %d\n", __FUNCTION__, r, nOffset + r*(nCols-2) + i); 01374 reSortedCorners.push_back(patchCentres.at(nOffset + r*(nCols-2) + i)); 01375 } 01376 01377 01378 // Last element of row 01379 if (r == 0) // if first row 01380 { 01381 reSortedCorners.push_back(patchCentres.at(1)); 01382 } 01383 else if (r == (nRows-1)) // if last row 01384 { 01385 reSortedCorners.push_back(patchCentres.at(3)); 01386 } 01387 else // if other row 01388 { 01389 reSortedCorners.push_back(patchCentres.at(4+nRows-2+r-1)); 01390 } 01391 } 01392 01393 reSortedCorners.swap(patchCentres); 01394 01395 if (DEBUG_MODE > 3) 01396 { 01397 01398 printf("%s << patchCentres.size() = %d\n", __FUNCTION__, patchCentres.size()); 01399 01400 for (unsigned int i = 0; i < patchCentres.size(); i++) 01401 { 01402 //printf("%s << patchCentres.at(%d) = (%d, %d)\n", __FUNCTION__, i, patchCentres.at(i).x, patchCentres.at(i).y); 01403 } 01404 01405 01406 } 01407 01408 } 01409 01410 void debugDisplayPattern(const Mat& image, Size patternSize, Mat& corners, bool mode) 01411 { 01412 01413 Mat tmpMat, dispMat; 01414 01415 mode = false; 01416 01417 if (image.channels() > 1) 01418 { 01419 cvtColor(image, tmpMat, CV_RGB2GRAY); 01420 } 01421 else 01422 { 01423 image.copyTo(tmpMat); 01424 } 01425 01426 cvtColor(tmpMat, dispMat, CV_GRAY2RGB); 01427 01428 01429 01430 drawChessboardCorners(dispMat, patternSize, corners, mode); 01431 01432 if (image.cols > 640) 01433 { 01434 Mat dispMat2; 01435 resize(dispMat, dispMat2, Size(0,0), 0.5, 0.5); 01436 imshow("mainWin", dispMat2); 01437 } 01438 else 01439 { 01440 imshow("mainWin", dispMat); 01441 } 01442 waitKey(0); 01443 } 01444 01445 bool findPatternCorners(const Mat& image, Size patternSize, vector<Point2f>& corners, int mode, int detector) 01446 { 01447 // mode 0: MSER chessboard finder 01448 // mode 1: MSER mask finder 01449 01450 if (!checkAcutance()) 01451 { 01452 return false; 01453 } 01454 01455 int patchCols, patchRows, desiredPatchQuantity; 01456 determinePatchDistribution(patternSize, mode, patchRows, patchCols, desiredPatchQuantity); 01457 01458 vector<vector<Point> > msers; 01459 //cout << "BETA" << endl; 01460 findAllPatches(image, patternSize, msers); 01461 //cout << "GAMMA" << endl; 01462 if (DEBUG_MODE > 2) 01463 { 01464 debugDisplayPatches(image, msers); 01465 } 01466 01467 if (msers.size() < desiredPatchQuantity) 01468 { 01469 corners.clear(); 01470 if (DEBUG_MODE > 1) 01471 { 01472 printf("%s << Insufficient patches found. Returning.\n", __FUNCTION__); 01473 } 01474 01475 return false; 01476 } 01477 01478 01479 01480 vector<Point2f> patchCentres2f; 01481 bool found = refinePatches(image, patternSize, msers, patchCentres2f, mode); 01482 01483 01484 if (DEBUG_MODE > 1) 01485 { 01486 printf("%s << Patches found after refinement = %d\n", __FUNCTION__, msers.size()); 01487 } 01488 01489 if (DEBUG_MODE > 2) 01490 { 01491 debugDisplayPatches(image, msers); 01492 } 01493 01494 01495 01496 // If patches still not found... 01497 if (!found) 01498 { 01499 corners.clear(); 01500 01501 if (DEBUG_MODE > 1) 01502 { 01503 printf("%s << Correct number of patches not found. Returning.\n", __FUNCTION__); 01504 } 01505 01506 return false; 01507 } 01508 01509 01510 found = patternInFrame(image.size(), patchCentres2f); 01511 01512 // If patches still not found... 01513 if (!found) 01514 { 01515 corners.clear(); 01516 01517 if (DEBUG_MODE > 1) 01518 { 01519 printf("%s << Some patch centres out of range...\n", __FUNCTION__); 01520 } 01521 01522 return false; 01523 } 01524 01525 sortPatches(image.size(), patternSize, patchCentres2f, mode); 01526 01527 if (DEBUG_MODE > 2) 01528 { 01529 Mat patchCentres_(patchCentres2f); 01530 debugDisplayPattern(image, cvSize(patchCols, patchRows), patchCentres_); 01531 } 01532 01533 found = verifyPatches(image.size(), patternSize, patchCentres2f, mode, 0, 1000); 01534 01535 if (!found) 01536 { 01537 corners.clear(); 01538 01539 if (DEBUG_MODE > 1) 01540 { 01541 printf("%s << Pattern verification failed. Returning.\n", __FUNCTION__); 01542 } 01543 01544 return false; 01545 } 01546 01547 // Correct patch centres (using histogram equalisation, single-frame calibration) 01548 correctPatchCentres(image, patternSize, patchCentres2f, mode); 01549 01550 if (DEBUG_MODE > 2) 01551 { 01552 Mat patchCentres_(patchCentres2f); 01553 debugDisplayPattern(image, cvSize(patchCols, patchRows), patchCentres_); 01554 } 01555 01556 Mat homography; 01557 found = findPatchCorners(image, patternSize, homography, corners, patchCentres2f, mode, detector); 01558 01559 // refineCornerPositions 01560 //fixFourCorners(image, corners, patternSize); 01561 01562 if (!found) 01563 { 01564 corners.clear(); 01565 01566 if (DEBUG_MODE > 1) 01567 { 01568 printf("%s << Patch corner search failed. Returning.\n", __FUNCTION__); 01569 } 01570 01571 return false; 01572 } 01573 01574 found = patternInFrame(image.size(), patchCentres2f); 01575 01576 // If patches still not found... 01577 if (!found) 01578 { 01579 corners.clear(); 01580 01581 if (DEBUG_MODE > 1) 01582 { 01583 printf("%s << Some corners out of range...\n", __FUNCTION__); 01584 } 01585 01586 return false; 01587 } 01588 01589 if (DEBUG_MODE > 2) 01590 { 01591 Mat cornersMat(corners); 01592 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersMat); 01593 } 01594 01595 return found; 01596 } 01597 01598 //HGH 01599 bool findPatternCorners2(const Mat& image, Size patternSize, vector<Point2f>& corners, int mode, int detector, int mserDelta, float max_var, float min_div, double area_threshold) 01600 { 01601 // mode 0: MSER chessboard finder 01602 // mode 1: MSER mask finder 01603 01604 if (!checkAcutance()) 01605 { 01606 return false; 01607 } 01608 01609 int patchCols, patchRows, desiredPatchQuantity; 01610 determinePatchDistribution(patternSize, mode, patchRows, patchCols, desiredPatchQuantity); 01611 01612 vector<vector<Point> > msers; 01613 //cout << "BETA" << endl; 01614 findAllPatches2(image, patternSize, msers, mserDelta, max_var, min_div, area_threshold); 01615 //cout << "GAMMA" << endl; 01616 if (DEBUG_MODE > 2) 01617 { 01618 debugDisplayPatches(image, msers); 01619 } 01620 01621 if (msers.size() < desiredPatchQuantity) 01622 { 01623 corners.clear(); 01624 if (DEBUG_MODE > 1) 01625 { 01626 printf("%s << Insufficient patches found. Returning.\n", __FUNCTION__); 01627 } 01628 01629 return false; 01630 } 01631 01632 01633 01634 vector<Point2f> patchCentres2f; 01635 bool found = refinePatches(image, patternSize, msers, patchCentres2f, mode); 01636 01637 01638 if (DEBUG_MODE > 1) 01639 { 01640 printf("%s << Patches found after refinement = %d\n", __FUNCTION__, msers.size()); 01641 } 01642 01643 if (DEBUG_MODE > 2) 01644 { 01645 debugDisplayPatches(image, msers); 01646 } 01647 01648 01649 01650 // If patches still not found... 01651 if (!found) 01652 { 01653 corners.clear(); 01654 01655 if (DEBUG_MODE > 1) 01656 { 01657 printf("%s << Correct number of patches not found. Returning.\n", __FUNCTION__); 01658 } 01659 01660 return false; 01661 } 01662 01663 01664 found = patternInFrame(image.size(), patchCentres2f); 01665 01666 // If patches still not found... 01667 if (!found) 01668 { 01669 corners.clear(); 01670 01671 if (DEBUG_MODE > 1) 01672 { 01673 printf("%s << Some patch centres out of range...\n", __FUNCTION__); 01674 } 01675 01676 return false; 01677 } 01678 01679 sortPatches(image.size(), patternSize, patchCentres2f, mode); 01680 01681 if (DEBUG_MODE > 2) 01682 { 01683 Mat patchCentres_(patchCentres2f); 01684 debugDisplayPattern(image, cvSize(patchCols, patchRows), patchCentres_); 01685 } 01686 01687 found = verifyPatches(image.size(), patternSize, patchCentres2f, mode, 0, 1000); 01688 01689 if (!found) 01690 { 01691 corners.clear(); 01692 01693 if (DEBUG_MODE > 1) 01694 { 01695 printf("%s << Pattern verification failed. Returning.\n", __FUNCTION__); 01696 } 01697 01698 return false; 01699 } 01700 01701 // Correct patch centres (using histogram equalisation, single-frame calibration) 01702 correctPatchCentres(image, patternSize, patchCentres2f, mode); 01703 01704 if (DEBUG_MODE > 2) 01705 { 01706 Mat patchCentres_(patchCentres2f); 01707 debugDisplayPattern(image, cvSize(patchCols, patchRows), patchCentres_); 01708 } 01709 01710 Mat homography; 01711 found = findPatchCorners(image, patternSize, homography, corners, patchCentres2f, mode, detector); 01712 01713 // refineCornerPositions 01714 //fixFourCorners(image, corners, patternSize); 01715 01716 if (!found) 01717 { 01718 corners.clear(); 01719 01720 if (DEBUG_MODE > 1) 01721 { 01722 printf("%s << Patch corner search failed. Returning.\n", __FUNCTION__); 01723 } 01724 01725 return false; 01726 } 01727 01728 found = patternInFrame(image.size(), patchCentres2f); 01729 01730 // If patches still not found... 01731 if (!found) 01732 { 01733 corners.clear(); 01734 01735 if (DEBUG_MODE > 1) 01736 { 01737 printf("%s << Some corners out of range...\n", __FUNCTION__); 01738 } 01739 01740 return false; 01741 } 01742 01743 if (DEBUG_MODE > 2) 01744 { 01745 Mat cornersMat(corners); 01746 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersMat); 01747 } 01748 01749 return found; 01750 } 01751 01752 01753 void interpolateCornerLocations2(const Mat& image, int mode, Size patternSize, vector<Point2f>& vCentres, vector<Point2f>& vCorners) 01754 { 01755 01756 if (DEBUG_MODE > 2) 01757 { 01758 printf("%s << Entered function...\n", __FUNCTION__); 01759 } 01760 01761 double minDimension = findMinimumSeparation(vCentres); 01762 01763 int correctionDistance = int(minDimension) / 4; 01764 01765 //printf("%s << minDimension = %f, correctionDistance = %d\n", __FUNCTION__, minDimension, correctionDistance); 01766 01767 Mat imGrey; 01768 01769 if (image.channels() > 1) 01770 { 01771 cvtColor(image, imGrey, CV_RGB2GRAY); 01772 } 01773 else 01774 { 01775 image.copyTo(imGrey); 01776 } 01777 01778 int X, Y; 01779 01780 X = patternSize.width/2; 01781 Y = patternSize.height/2; 01782 01783 vector<Point2f> fullCentroidGrid; 01784 01785 // Sets up all centroid grid points 01786 for (int i = 0; i < Y; i++) 01787 { 01788 for (int j = 0; j < X; j++) 01789 { 01790 Point2f pt; 01791 01792 pt = Point2f(j, i); 01793 fullCentroidGrid.push_back(pt); 01794 01795 } 01796 } 01797 01798 vector<Point2f> fullCornerGrid; 01799 01800 // Sets up all corner grid points 01801 for (int i = 0; i < Y; i++) 01802 { 01803 for (int j = 0; j < X; j++) 01804 { 01805 for (int k = 0; k < 4; k++) 01806 { 01807 Point2f pt; 01808 01809 if (k == 0) 01810 { 01811 pt = Point2f(j-0.25, i-0.25); 01812 } 01813 else if (k == 1) 01814 { 01815 pt = Point2f(j+0.25, i-0.25); 01816 } 01817 else if (k == 2) 01818 { 01819 pt = Point2f(j-0.25, i+0.25); 01820 } 01821 else if (k == 3) 01822 { 01823 pt = Point2f(j+0.25, i+0.25); 01824 } 01825 01826 fullCornerGrid.push_back(pt); 01827 } 01828 01829 } 01830 } 01831 01832 vector<Point2f> patchNeighbourhood; 01833 vector<Point2f> patchArrangement; 01834 vector<Point2f> newCorners, bestCorners; 01835 vector<Point2f> cornerArrangement; 01836 Mat cornerLocs(2, 2, CV_32FC2); 01837 Point2f *neighbourhoodArray; 01838 Point2f* arrangementArray; 01839 01840 Mat homography; 01841 01842 // Depending on the location of the patch, a different number of neighbouring patches 01843 // are used to determine an approximate homography 01844 int neighbourhoodCount = 0; 01845 01846 int index = 0; 01847 01848 // Initial estimate of all corners 01849 for (int i = 0; i < Y; i++) 01850 { 01851 for (int j = 0; j < X; j++) 01852 { 01853 01854 if (0) //((i == 0) || (i == Y-1) || (j == 0) || (j == X-1)) { 01855 { 01856 for (int k = 0; k < 4; k++) 01857 { 01858 newCorners.push_back(Point2f(0.0, 0.0)); // skip corners and edges 01859 index++; 01860 } 01861 01862 } 01863 else 01864 { 01865 patchNeighbourhood.clear(); 01866 patchArrangement.clear(); 01867 01868 neighbourhoodCount = 0; 01869 01870 // For each neighbourhood patch 01871 for (int k = max(0, i-1); k < min(Y, i+2); k++) // try to go 1 up and down 01872 { 01873 for (int l = max(0, j-1); l < min(X, j+2); l++) // try to go 1 left and right 01874 { 01875 // Add patch to patch vector 01876 patchNeighbourhood.push_back(vCentres.at(k*X+l)); 01877 // Add co-ordinate to arbitrary map vector 01878 patchArrangement.push_back(Point2f((float)l, (float)k)); 01879 01880 neighbourhoodCount++; 01881 } 01882 } 01883 01884 //neighbourhoodArray = new Point2f[neighbourhoodCount]; 01885 //arrangementArray = new Point2f[neighbourhoodCount]; 01886 01887 /* 01888 for (int k = 0; k < neighbourhoodCount; k++) { 01889 neighbourhoodArray[k] = patchNeighbourhood.at(k); 01890 arrangementArray[k] = patchArrangement.at(k); 01891 } 01892 */ 01893 01894 // find homography 01895 homography = findHomography(Mat(patchArrangement), Mat(patchNeighbourhood)); 01896 01897 cornerArrangement.clear(); 01898 01899 // define arbitrary corner co-ordinate 01900 for (int k = 0; k < 2; k++) 01901 { 01902 for (int l = 0; l < 2; l++) 01903 { 01904 cornerArrangement.push_back(Point2f((float)(j-0.25+0.5*l), (float)(i-0.25+0.5*k))); 01905 } 01906 } 01907 01908 01909 // apply homography to these co-ordinates 01910 Mat tmpMat1 = Mat(cornerArrangement); 01911 01912 perspectiveTransform(tmpMat1, cornerLocs, homography); 01913 01914 for (int k = 0; k < 4; k++) 01915 { 01916 //printf("%s << adding..\n", __FUNCTION__); 01917 newCorners.push_back(Point2f(cornerLocs.at<Vec3f>(k,0)[0], cornerLocs.at<Vec3f>(k,0)[1])); 01918 } 01919 01920 } 01921 01922 01923 01924 01925 } 01926 } 01927 01928 /* 01929 if (DEBUG_MODE > 2) { 01930 vector<Point2f> redistorted; 01931 Mat cornersForDisplay(newCorners); 01932 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 01933 printf("%s << DONE.\n", __FUNCTION__); 01934 } 01935 */ 01936 //printf("%s << pre cSP\n", __FUNCTION__); 01937 //cornerSubPix(imGrey, newCorners, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 01938 01939 01940 if (DEBUG_MODE > 2) 01941 { 01942 vector<Point2f> redistorted; 01943 Mat cornersForDisplay(newCorners); 01944 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 01945 printf("%s << DONE.\n", __FUNCTION__); 01946 } 01947 01948 vCorners.clear(); 01949 vCorners.assign(newCorners.begin(), newCorners.end()); 01950 01951 01952 } 01953 01954 void addToBinMap(Mat& binMap, cv::vector<Point2f>& cornerSet, Size imSize) 01955 { 01956 int x, y; 01957 for (unsigned int i = 0; i < cornerSet.size(); i++) 01958 { 01959 // Determine Bin Index for this specific corner 01960 x = (int)((cornerSet.at(i).x/(double(imSize.width)))*binMap.cols); 01961 y = (int)((cornerSet.at(i).y/(double(imSize.height)))*binMap.rows); 01962 01963 // Increment the count for this bin 01964 binMap.at<int>(y, x) += 1; 01965 } 01966 } 01967 01968 void prepForDisplay(const Mat& distributionMap, Mat& distributionDisplay) 01969 { 01970 01971 Mat distMapCpy(distributionMap.size(), CV_8UC1); 01972 01973 // Temp 01974 distributionMap.copyTo(distMapCpy); // distMapCpy should be 0s and 1s 01975 //distMapCpy += 100; 01976 equalizeHist(distMapCpy, distributionDisplay); // distDisplay should be 0s and 255s 01977 GaussianBlur(distributionDisplay, distMapCpy, Size(11, 11), 1.5, 1.5); // distMapCpy should range from 0 to 255 01978 //equalizeHist(distMapCpy, distributionDisplay); // distMapCpy should range from 0 to 255 01979 normalize(distMapCpy, distributionDisplay, 0, 255, NORM_MINMAX); 01980 01981 //distMapCpy.copyTo(distributionDisplay); 01982 01983 return; 01984 } 01985 01986 void addToRadialDistribution(double *radialDistribution, cv::vector<Point2f>& cornerSet, Size imSize) 01987 { 01988 01989 Point2f center((float)((double(imSize.height-1))/2), (float)((double(imSize.width-1))/2)); 01990 double dist, maxDist; 01991 int index; 01992 01993 //maxDist = max(double(imSize.height)/2, double(imSize.width)/2); 01994 01995 // Really max dist should be larger than half the major axis, although you don't know how large it really 01996 // needs to be until after you've calibrated.. 01997 maxDist = pow(pow(double(imSize.height)/2, 2) + pow(double(imSize.width)/2, 2), 0.5); 01998 01999 for (unsigned int i = 0; i < cornerSet.size(); i++) 02000 { 02001 02002 dist = distBetweenPts2f(center, cornerSet.at(i)); 02003 02004 // Only add the point to the distribution if it's within the desired range 02005 if (dist < maxDist) 02006 { 02007 index = int((dist/maxDist)*(RADIAL_LENGTH-0.00001)); 02008 radialDistribution[index]++; 02009 } 02010 02011 } 02012 02013 } 02014 02015 void addToDistributionMap(Mat& distributionMap, vector<Point2f>& corners) 02016 { 02017 for (unsigned int i = 0; i < corners.size(); i++) 02018 { 02019 distributionMap.at<unsigned char>((int)corners.at(i).y, (int)corners.at(i).x) += (unsigned char) 1; 02020 } 02021 } 02022 02023 double obtainSetScore(Mat& distributionMap, 02024 Mat& binMap, 02025 Mat& gaussianMat, 02026 cv::vector<Point2f>& cornerSet, 02027 double *radialDistribution) 02028 { 02029 double score = 1.0; 02030 double mean = 0.0, variance = 0.0; 02031 int count = 0; 02032 double area = 0.0; 02033 Point centroid, center; 02034 double centrality = 0.0; 02035 02036 Mat distributionDisplay(distributionMap.size(), CV_8UC1); 02037 Mat binTemp(binMap.size(), CV_8UC1); 02038 02039 center = Point(distributionMap.size().width/2 - 1, distributionMap.size().height/2 - 1); 02040 02041 cv::vector<Point> fullHull, simplifiedHull; 02042 02043 for (unsigned int i = 0; i < cornerSet.size(); i++) 02044 { 02045 fullHull.push_back(Point(int(cornerSet.at(i).x), int(cornerSet.at(i).y))); 02046 } 02047 02048 // Create a copy of bin Map 02049 Mat binMapCpy; 02050 binMap.copyTo(binMapCpy); 02051 02052 // Add corners to copy binMap 02053 addToBinMap(binMapCpy, cornerSet, distributionMap.size()); 02054 02055 count = binMapCpy.size().width * binMapCpy.size().height; 02056 02057 // SCORING CONTRIBUTIONS 02058 // Area as Fraction of FOV: 02059 convexHull(Mat(fullHull), simplifiedHull); 02060 02061 area = contourArea(Mat(simplifiedHull)); 02062 02063 area /= (distributionMap.size().width * distributionMap.size().height); 02064 02065 //printf("%s << area as fraction = %f\n", __FUNCTION__, area); 02066 02067 // Centrality 02068 centroid = findCentroid(simplifiedHull); 02069 centrality = distBetweenPts(centroid, center); 02070 centrality = 1 - (centrality / (distributionMap.size().height/2)); 02071 02072 // Calculate mean value per bin for spreadiness 02073 for (int i = 0; i < binMapCpy.size().width; i++) 02074 { 02075 for (int j = 0; j < binMapCpy.size().height; j++) 02076 { 02077 mean += binMapCpy.at<int>(j, i); 02078 } 02079 } 02080 02081 // Radial Distribution 02082 02083 //printf("%s << DEBUG %d\n", __FUNCTION__, 0); 02084 02085 // Make copy of radial distribution 02086 double *radialDistCpy; 02087 radialDistCpy = new double[RADIAL_LENGTH]; 02088 for (int i = 0; i < RADIAL_LENGTH; i++) 02089 { 02090 radialDistCpy[i] = radialDistribution[i]; 02091 } 02092 02093 // Add current pointset to radial distribution copy 02094 addToRadialDistribution(radialDistCpy, cornerSet, distributionMap.size()); 02095 02096 double radialMean = 0.0, radialVariance = 0.0, desiredCount; 02097 double *radialCumulative; 02098 radialCumulative = new double[RADIAL_LENGTH]; 02099 02100 // Calculate cumulative Distribution and mean (avg points per quantization bin) 02101 //printf("debugging radialCumulative: "); 02102 for (int i = 0; i < RADIAL_LENGTH; i++) 02103 { 02104 radialMean += radialDistCpy[i]; 02105 radialCumulative[i] = radialMean; 02106 //printf("%f\t", radialCumulative[i]); 02107 } 02108 radialMean /= RADIAL_LENGTH; 02109 //printf("\n"); 02110 //cin.get(); 02111 02112 // Calculate the variation from an ideal/uniform distribution with the new pointset included 02113 //printf("debugging radialVariance: "); 02114 for (int i = 0; i < RADIAL_LENGTH; i++) 02115 { 02116 desiredCount = double(i+1)*radialMean; 02117 // Variance is the sum of the differences of where the cumulative count is for each bin, and where it 02118 // should be if it's a uniform distribution over the full radial range 02119 radialVariance += pow(radialCumulative[i] - desiredCount, 2); 02120 //printf("%f\t", pow(radialCumulative[i] - desiredCount, 2)); 02121 02122 //radialVariance += pow(radialDistCpy[i]-radialMean, 2); 02123 } 02124 02125 //printf("\n"); 02126 02127 02128 //printf("%s << DEBUG %d\n", __FUNCTION__, 4); 02129 02130 // Turn variance count into standard deviation 02131 radialVariance /= RADIAL_LENGTH; 02132 radialVariance = pow(radialVariance, 0.5); 02133 02134 //printf("radialVariance = %f\n", radialVariance); // around about 5 - 20...? 02135 //cin.get(); 02136 02137 mean /= count; 02138 02139 //printf("mean = %f\n", mean); 02140 02141 // NEW 02142 // =================== 02143 // Add the test points to a double precision copy of the distribution map 02144 Mat distMapCpy(distributionMap.size(), CV_64FC1); 02145 02146 for (int i = 0; i < distMapCpy.size().width; i++) 02147 { 02148 for (int j = 0; j < distMapCpy.size().height; j++) 02149 { 02150 distMapCpy.at<double>(j,i) += double(distributionMap.at<unsigned char>(j,i)); 02151 } 02152 } 02153 02154 //printf("%s << DEBUG %d\n", __FUNCTION__, 5); 02155 02156 // Massively blur it 02157 // or could you just convolve it with optimum distribution to find correlation? 02158 02159 // Quantize it to same bins as gassian map 02160 // Then compare its variance with the gaussian distribution map 02161 // =================== 02162 02163 02164 // OLD 02165 // =================== 02166 02167 // Scale gaussian mat up 02168 gaussianMat *= mean; 02169 02170 for (int i = 0; i < binMapCpy.size().width; i++) 02171 { 02172 for (int j = 0; j < binMapCpy.size().height; j++) 02173 { 02174 variance += pow((double(binMapCpy.at<int>(j, i)) - gaussianMat.at<double>(j, i)), 2); 02175 } 02176 } 02177 02178 // Scale gaussian mat back 02179 gaussianMat /= mean; 02180 variance /= count; 02181 // =================== 02182 02183 /* 02184 printf("%s << area = %f\n", __FUNCTION__, area); 02185 printf("%s << centrality = %f\n", __FUNCTION__, centrality); 02186 printf("%s << radialVariance = %f\n", __FUNCTION__, radialVariance); 02187 cin.get(); 02188 */ 02189 02190 // Figure out total score 02191 //score = area; 02192 //score = double(pow(area, 1.0)) * variance; 02193 //score = (area*centrality) / radialVariance; 02194 //score = area / radialVariance; 02195 //score = area / radialVariance; 02196 //score = 1 / radialVariance; 02197 //score = centrality * area; 02198 score = pow(area, 2.0) / radialVariance; 02199 //score = area + (1 / radialVariance); 02200 02201 //printf("%s << score = %f [centrality = %f; area = %f\n", __FUNCTION__, score, centrality, area); 02202 02203 delete[] radialDistCpy; 02204 delete[] radialCumulative; 02205 02206 if (score < 0) 02207 { 02208 printf("%s << ERROR: Negative score acquired. Returning.\n", __FUNCTION__); 02209 return -1; 02210 } 02211 02212 return score; 02213 } 02214 02215 bool findPatchCorners(const Mat& image, Size patternSize, Mat& homography, vector<Point2f>& corners, vector<Point2f>& patchCentres2f, int mode, int detector) 02216 { 02217 02218 if (DEBUG_MODE > 2) 02219 { 02220 printf("%s << Entered function...\n", __FUNCTION__); 02221 } 02222 02223 Mat inputDisp; 02224 02225 vector<Point2f> cornerEstimates; 02226 vector<vector<Point2f> > vvOriginalCentres; 02227 vvOriginalCentres.push_back(patchCentres2f); 02228 02229 interpolateCornerLocations2(image, mode, patternSize, vvOriginalCentres.at(0), cornerEstimates); 02230 02231 //estimateUnknownPositions(XXX, vvOriginalCentres.at(0), XXX, cornerEstimates); 02232 02233 if (DEBUG_MODE > 2) 02234 { 02235 Mat cornersForDisplay(cornerEstimates); 02236 printf("%s << Step 3: cornerEstimates.size() = %d\n", __FUNCTION__, cornerEstimates.size()); 02237 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02238 printf("%s << DONE.\n", __FUNCTION__); 02239 } 02240 02241 corners.clear(); 02242 02243 //vector<Point2f> innerCornerEstimates; 02244 //cornerEstimates.copyTo(innerCornerEstimates); 02245 02246 sortCorners(image.size(), patternSize, cornerEstimates); 02247 02248 findBestCorners(image, cornerEstimates, corners, patternSize, detector); 02249 02250 //correctInnerCorners(innerCornerEstimates, cornerEstimates, ) 02251 02252 if (DEBUG_MODE > 3) 02253 { 02254 Mat cornersForDisplay(corners); 02255 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02256 } 02257 02258 bool retVal = false; 02259 02260 // sortCorners(image.size(), patternSize, corners); 02261 02262 retVal = verifyCorners(image.size(), patternSize, corners, 0, 1000); 02263 02264 if (!retVal) 02265 { 02266 corners.clear(); 02267 return retVal; 02268 } 02269 02270 groupPointsInQuads(patternSize, corners); 02271 02272 refineCornerPositions(image, patternSize, corners); 02273 sortCorners(image.size(), patternSize, corners); 02274 02275 if (DEBUG_MODE > 3) 02276 { 02277 Mat cornersForDisplay(corners); 02278 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02279 } 02280 02281 // 6. verify... 02282 02283 //printf("%s << patternSize = (%d, %d)\n", __FUNCTION__, patternSize.width, patternSize.height); 02284 retVal = verifyCorners(image.size(), patternSize, corners, 0, 1000); 02285 02286 if (!retVal) 02287 { 02288 corners.clear(); 02289 } 02290 02291 return retVal; 02292 02293 } 02294 02295 bool verifyCorners(Size imSize, Size patternSize, vector<Point2f>& patternPoints, double minDist, double maxDist) 02296 { 02297 vector<Point2f> simplePoints; 02298 02299 for (unsigned int i = 0; i < patternPoints.size(); i++) 02300 { 02301 simplePoints.push_back(Point(patternPoints.at(i).x, patternPoints.at(i).y)); 02302 } 02303 02304 return verifyPattern(imSize, patternSize, simplePoints, minDist, maxDist); 02305 } 02306 02307 void refineCornerPositions(const Mat& image, Size patternSize, vector<Point2f>& vCorners) 02308 { 02309 02310 Mat imGrey; 02311 02312 vector<Point2f> targetCorner; 02313 02314 if (image.channels() > 1) 02315 { 02316 cvtColor(image, imGrey, CV_RGB2GRAY); 02317 } 02318 else 02319 { 02320 image.copyTo(imGrey); 02321 } 02322 02323 vector<Point2f> neighbouringPts; 02324 02325 int X, Y; 02326 02327 X = patternSize.width/2; 02328 Y = patternSize.height/2; 02329 02330 vector<Point2f> fullCornerGrid; 02331 02332 double minDimension = findMinimumSeparation(vCorners); 02333 02334 int correctionDistance = int(minDimension) / 2.0; 02335 //printf("%s << correctionDistance = %d\n", __FUNCTION__, correctionDistance); 02336 //cin.get(); 02337 02338 // Sets up all corner grid points 02339 for (int i = 0; i < Y; i++) 02340 { 02341 for (int j = 0; j < X; j++) 02342 { 02343 for (int k = 0; k < 4; k++) 02344 { 02345 Point2f pt; 02346 02347 if (k == 0) 02348 { 02349 pt = Point2f(j-0.25, i-0.25); 02350 } 02351 else if (k == 1) 02352 { 02353 pt = Point2f(j+0.25, i-0.25); 02354 } 02355 else if (k == 2) 02356 { 02357 pt = Point2f(j-0.25, i+0.25); 02358 } 02359 else if (k == 3) 02360 { 02361 pt = Point2f(j+0.25, i+0.25); 02362 } 02363 02364 fullCornerGrid.push_back(pt); 02365 } 02366 02367 } 02368 } 02369 02370 vector<Point2f> patchNeighbourhood; 02371 vector<Point2f> patchArrangement; 02372 vector<Point2f> newCorners, bestCorners; 02373 vector<Point2f> cornerArrangement; 02374 Mat cornerLocs(2, 2, CV_32FC2); 02375 //Point2f *neighbourhoodArray; 02376 //Point2f* arrangementArray; 02377 02378 Mat homography; 02379 02380 // Depending on the location of the patch, a different number of neighbouring patches 02381 // are used to determine an approximate homography 02382 int neighbourhoodCount = 0; 02383 02384 int index = 0; 02385 02386 int groupedIndex = -1; 02387 02388 newCorners.assign(vCorners.begin(), vCorners.end()); 02389 02390 if (DEBUG_MODE > 2) 02391 { 02392 vector<Point2f> redistorted; 02393 Mat cornersForDisplay(newCorners); 02394 printf("%s << Initial corners.\n", __FUNCTION__); 02395 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02396 02397 } 02398 02399 index = 0; 02400 02401 // just edges 02402 for (int i = 0; i < 2*Y; i++) 02403 { 02404 for (int j = 0; j < 2*X; j++) 02405 { 02406 //if (((i != 0) && (i != 2*Y-1) && (j != 0) && (j != 2*X-1)) || (((i == 0) || (i == 2*Y-1)) && ((j == 0) || (j == 2*X-1)))) { 02407 02408 if (((i == 0) || (i == 2*Y-1) || (j == 0) || (j == 2*X-1)) && !(((i < 2) || (i > 2*Y-3)) && ((j < 2) || (j > 2*X-3)))) 02409 { 02410 02411 patchNeighbourhood.clear(); 02412 patchArrangement.clear(); 02413 02414 neighbourhoodCount = 0; 02415 02416 //index = 2*i + (4*(X-1))*(i/2) + 2*(j/2)+j; 02417 index = 2*X*i + j; 02418 groupedIndex = 4*(X*(i/2)+(j/2)) + (j%2) + 2*(i%2); 02419 02420 //printf("%s << (i, j) = (%d, %d); index = %d\n", __FUNCTION__, i, j, index); 02421 02422 int z[4], c[4]; 02423 02424 if (i == 0) // For top edge 02425 { 02426 c[0] = index+2*X-1; 02427 c[1] = index+2*X+1; 02428 c[2] = index+4*X-1; 02429 c[3] = index+4*X+1; 02430 } 02431 else if (i == 2*Y-1) // For bottom edge 02432 { 02433 c[0] = index-4*X-1; 02434 c[1] = index-4*X+1; 02435 c[2] = index-2*X-1; 02436 c[3] = index-2*X+1; 02437 } 02438 else if (j == 0) // For left edge 02439 { 02440 c[0] = index-2*X+1; 02441 c[1] = index-2*X+2; 02442 c[2] = index+2*X+1; 02443 c[3] = index+2*X+2; 02444 } 02445 else if (j == 2*X-1) // For right edge 02446 { 02447 c[0] = index-2*X-2; 02448 c[1] = index-2*X-1; 02449 c[2] = index+2*X-2; 02450 c[3] = index+2*X-1; 02451 } 02452 02453 int m, n; 02454 02455 for (int k = 0; k < 4; k++) 02456 { 02457 // row 02458 m = c[k] / (2*X); 02459 // col 02460 n = c[k] % (2*X); 02461 // grouped index 02462 //z[k] = 4*((n/2)*X+(m/2))+(m % 2) + 2*(n/2); 02463 //z[k] = 2*m + (4*(X-1))*(m/2) + 2*(n/2)+n; 02464 z[k] = 4*(X*(m/2)+(n/2)) + (n%2) + 2*(m%2); 02465 //z[k] = (X/2)*m + 2*(m%2) + 4*(n/2) ((n+1)%2); 02466 02467 //printf("%s << (m, n) = (%d, %d); c[%d] = %d; z[%d] = %d\n", __FUNCTION__, m, n, k, c[k], k, z[k]); 02468 } 02469 02470 //cin.get(); 02471 02472 for (int k = 0; k < 4; k++) 02473 { 02474 //printf("%s << z[%d] = %f\n", __FUNCTION__, k, z[k]); 02475 patchNeighbourhood.push_back(newCorners.at(z[k])); 02476 patchArrangement.push_back(fullCornerGrid.at(z[k])); 02477 //printf("%s << pn = (%f, %f)\n", __FUNCTION__, patchNeighbourhood.at(k).x, patchNeighbourhood.at(k).y); 02478 //printf("%s << pa = (%f, %f)\n", __FUNCTION__, patchArrangement.at(k).x, patchArrangement.at(k).y); 02479 neighbourhoodCount++; 02480 } 02481 02482 02483 // find homography 02484 //printf("%s << Finding homography...\n", __FUNCTION__); 02485 homography = findHomography(Mat(patchArrangement), Mat(patchNeighbourhood)); 02486 //printf("%s << Homography found!\n", __FUNCTION__); 02487 02488 cornerArrangement.clear(); 02489 02490 cornerArrangement.push_back(fullCornerGrid.at(groupedIndex)); 02491 02492 // apply homography to these co-ordinates 02493 Mat tmpMat1 = Mat(cornerArrangement); 02494 02495 perspectiveTransform(tmpMat1, cornerLocs, homography); 02496 02497 newCorners.at(groupedIndex) = Point2f(cornerLocs.at<Vec3f>(0,0)[0], cornerLocs.at<Vec3f>(0,0)[1]); 02498 02499 // Calculate maximum search distance for correcting this local point 02500 minDimension = findMinimumSeparation(patchNeighbourhood); 02501 correctionDistance = max(int(double(minDimension)/2.0), 5); 02502 02503 //printf("%s << correctionDistance = %d\n", __FUNCTION__, correctionDistance); 02504 02505 // Implement search for just this point 02506 targetCorner.clear(); 02507 targetCorner.push_back(newCorners.at(groupedIndex)); 02508 cornerSubPix(imGrey, targetCorner, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 02509 newCorners.at(groupedIndex) = targetCorner.at(0); 02510 02511 } 02512 } 02513 } 02514 02515 /* 02516 if (DEBUG_MODE > 2) { 02517 vector<Point2f> redistorted; 02518 Mat cornersForDisplay(newCorners); 02519 printf("%s << Fixing the edges...\n", __FUNCTION__); 02520 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02521 } 02522 02523 printf("%s << pre cSP\n", __FUNCTION__); 02524 cornerSubPix(imGrey, newCorners, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 02525 */ 02526 02527 if (DEBUG_MODE > 2) 02528 { 02529 vector<Point2f> redistorted; 02530 Mat cornersForDisplay(newCorners); 02531 printf("%s << Refinement of edges.\n", __FUNCTION__); 02532 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay, false); 02533 02534 } 02535 02536 index = 0; 02537 02538 // second last ring 02539 for (int i = 0; i < 2*Y; i++) 02540 { 02541 for (int j = 0; j < 2*X; j++) 02542 { 02543 //if (((i != 0) && (i != 2*Y-1) && (j != 0) && (j != 2*X-1)) || (((i == 0) || (i == 2*Y-1)) && ((j == 0) || (j == 2*X-1)))) { 02544 02545 if ((((i == 1) || (i == 2*Y-2)) && ((j == 0) || (j == 2*X-1))) || (((i == 0) || (i == 2*Y-1)) && ((j == 1) || (j == 2*X-2)))) 02546 { 02547 02548 patchNeighbourhood.clear(); 02549 patchArrangement.clear(); 02550 02551 neighbourhoodCount = 0; 02552 02553 //index = 2*i + (4*(X-1))*(i/2) + 2*(j/2)+j; 02554 index = 2*X*i + j; 02555 groupedIndex = 4*(X*(i/2)+(j/2)) + (j%2) + 2*(i%2); 02556 02557 //printf("%s << (i, j) = (%d, %d); index = %d\n", __FUNCTION__, i, j, index); 02558 02559 int z[4], c[4]; 02560 02561 // c = {0, 0, 0, 0}; 02562 02563 02564 if ((i == 0) && (j == 1)) // top left (top) 02565 { 02566 c[0] = index+1; 02567 c[1] = index+2*X; 02568 c[2] = index+2*X+2; 02569 c[3] = index+4*X+1; // c = {index+1, index+2*X, index+2*X+2, index+4*X+2}; 02570 } 02571 else if ((i == 1) && (j == 0)) // top left (bot) 02572 { 02573 c[0] = index+1; 02574 c[1] = index+2*X; 02575 c[2] = index+2*X+2; 02576 c[3] = index+4*X+1; 02577 } 02578 else if ((i == 0) && (j == 2*X-2)) // top right (top) 02579 { 02580 c[0] = index-1; 02581 c[1] = index+2*X-2; 02582 c[2] = index+2*X; 02583 c[3] = index+4*X-1; 02584 } 02585 else if ((i == 1) && (j == 2*X-1)) // top right (bot) 02586 { 02587 c[0] = index-1; 02588 c[1] = index+2*X-2; 02589 c[2] = index+2*X; 02590 c[3] = index+4*X-1; // c = {index-1, index+2*X-2, index+2*X-1, index+4*X-2}; 02591 } 02592 else if ((i == 2*Y-2) && (j == 0)) // bottom left (top) 02593 { 02594 c[0] = index-4*X+1; 02595 c[1] = index-2*X; 02596 c[2] = index-2*X+2; 02597 c[3] = index+1; 02598 } 02599 else if ((i == 2*Y-1) && (j == 1)) // bot left (bot) 02600 { 02601 c[0] = index-4*X+1; 02602 c[1] = index-2*X; 02603 c[2] = index-2*X+2; 02604 c[3] = index+1; // c = {index-4*X+1, index-4*X+2, index-2*X, index-2*X+1}; 02605 } 02606 else if ((i == 2*Y-2) && (j == 2*X-1)) // bottom right (top) 02607 { 02608 c[0] = index-4*X-1; 02609 c[1] = index-2*X-2; 02610 c[2] = index-2*X; 02611 c[3] = index-1; 02612 } 02613 else if ((i == 2*Y-1) && (j == 2*X-2)) // bot right (bot) 02614 { 02615 c[0] = index-4*X-1; 02616 c[1] = index-2*X-2; 02617 c[2] = index-2*X; 02618 c[3] = index-1; // c = {index-4*X-2, index-4*X-1, index-2*X-1, index-2*X}; 02619 } 02620 02621 02622 int m, n; 02623 02624 for (int k = 0; k < 4; k++) 02625 { 02626 // row 02627 m = c[k] / (2*X); 02628 // col 02629 n = c[k] % (2*X); 02630 // grouped index 02631 //z[k] = 4*((n/2)*X+(m/2))+(m % 2) + 2*(n/2); 02632 //z[k] = 2*m + (4*(X-1))*(m/2) + 2*(n/2)+n; 02633 z[k] = 4*(X*(m/2)+(n/2)) + (n%2) + 2*(m%2); 02634 //z[k] = (X/2)*m + 2*(m%2) + 4*(n/2) ((n+1)%2); 02635 02636 //printf("%s << (m, n) = (%d, %d); c[%d] = %d; z[%d] = %d\n", __FUNCTION__, m, n, k, c[k], k, z[k]); 02637 } 02638 02639 //cin.get(); 02640 02641 for (int k = 0; k < 4; k++) 02642 { 02643 //printf("%s << z[%d] = %f\n", __FUNCTION__, k, z[k]); 02644 patchNeighbourhood.push_back(newCorners.at(z[k])); 02645 patchArrangement.push_back(fullCornerGrid.at(z[k])); 02646 //printf("%s << pn = (%f, %f)\n", __FUNCTION__, patchNeighbourhood.at(k).x, patchNeighbourhood.at(k).y); 02647 //printf("%s << pa = (%f, %f)\n", __FUNCTION__, patchArrangement.at(k).x, patchArrangement.at(k).y); 02648 neighbourhoodCount++; 02649 } 02650 02651 02652 // find homography 02653 //printf("%s << Finding homography...\n", __FUNCTION__); 02654 homography = findHomography(Mat(patchArrangement), Mat(patchNeighbourhood)); 02655 //printf("%s << Homography found!\n", __FUNCTION__); 02656 02657 cornerArrangement.clear(); 02658 02659 cornerArrangement.push_back(fullCornerGrid.at(groupedIndex)); 02660 02661 // apply homography to these co-ordinates 02662 Mat tmpMat1 = Mat(cornerArrangement); 02663 02664 perspectiveTransform(tmpMat1, cornerLocs, homography); 02665 02666 newCorners.at(groupedIndex) = Point2f(cornerLocs.at<Vec3f>(0,0)[0], cornerLocs.at<Vec3f>(0,0)[1]); 02667 02668 02669 // Calculate maximum search distance for correcting this local point 02670 minDimension = findMinimumSeparation(patchNeighbourhood); 02671 correctionDistance = max(int(double(minDimension)/4.0), 5); 02672 02673 //printf("%s << correctionDistance = %d\n", __FUNCTION__, correctionDistance); 02674 02675 // Implement search for just this point 02676 targetCorner.clear(); 02677 targetCorner.push_back(newCorners.at(groupedIndex)); 02678 cornerSubPix(imGrey, targetCorner, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 02679 newCorners.at(groupedIndex) = targetCorner.at(0); 02680 02681 } 02682 } 02683 } 02684 02685 /* 02686 02687 if (DEBUG_MODE > 2) { 02688 vector<Point2f> redistorted; 02689 Mat cornersForDisplay(newCorners); 02690 printf("%s << Fixing the pseudocorners...\n", __FUNCTION__); 02691 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02692 } 02693 02694 printf("%s << pre cSP\n", __FUNCTION__); 02695 cornerSubPix(imGrey, newCorners, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 02696 02697 */ 02698 02699 if (DEBUG_MODE > 2) 02700 { 02701 vector<Point2f> redistorted; 02702 Mat cornersForDisplay(newCorners); 02703 printf("%s << Refinement of psuedocorners.\n", __FUNCTION__); 02704 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay, false); 02705 } 02706 02707 index = 0; 02708 02709 // final corners 02710 for (int i = 0; i < 2*Y; i++) 02711 { 02712 for (int j = 0; j < 2*X; j++) 02713 { 02714 //if (((i != 0) && (i != 2*Y-1) && (j != 0) && (j != 2*X-1)) || (((i == 0) || (i == 2*Y-1)) && ((j == 0) || (j == 2*X-1)))) { 02715 02716 if (((i == 0) || (i == 2*Y-1)) && ((j == 0) || (j == 2*X-1))) 02717 { 02718 02719 patchNeighbourhood.clear(); 02720 patchArrangement.clear(); 02721 02722 neighbourhoodCount = 0; 02723 02724 //index = 2*i + (4*(X-1))*(i/2) + 2*(j/2)+j; 02725 index = 2*X*i + j; 02726 groupedIndex = 4*(X*(i/2)+(j/2)) + (j%2) + 2*(i%2); 02727 02728 //printf("%s << (i, j) = (%d, %d); index = %d\n", __FUNCTION__, i, j, index); 02729 02730 int z[4], c[4]; 02731 02732 // c = {0, 0, 0, 0}; 02733 02734 02735 if ((i == 0) && (j == 0)) // top left 02736 { 02737 c[0] = index+1; 02738 c[1] = index+2*X; 02739 c[2] = index+2*X+2; 02740 c[3] = index+4*X+1; 02741 } 02742 else if ((i == 0) && (j == 2*X-1)) // top right 02743 { 02744 c[0] = index-1; 02745 c[1] =index+2*X-2; 02746 c[2] = index+2*X; 02747 c[3] = index+4*X-1; 02748 } 02749 else if ((i == 2*Y-1) && (j == 0)) // bot left 02750 { 02751 c[0] = index-4*X+1; 02752 c[1] = index-2*X; 02753 c[2] = index-2*X+2; 02754 c[3] = index+1; 02755 } 02756 else if ((i == 2*Y-1) && (j == 2*X-1)) // bot right 02757 { 02758 c[0] = index-4*X-1; 02759 c[1] = index-2*X-2; 02760 c[2] = index-2*X; 02761 c[3] = index-1; 02762 } 02763 02764 02765 int m, n; 02766 02767 for (int k = 0; k < 4; k++) 02768 { 02769 // row 02770 m = c[k] / (2*X); 02771 // col 02772 n = c[k] % (2*X); 02773 // grouped index 02774 //z[k] = 4*((n/2)*X+(m/2))+(m % 2) + 2*(n/2); 02775 //z[k] = 2*m + (4*(X-1))*(m/2) + 2*(n/2)+n; 02776 z[k] = 4*(X*(m/2)+(n/2)) + (n%2) + 2*(m%2); 02777 //z[k] = (X/2)*m + 2*(m%2) + 4*(n/2) ((n+1)%2); 02778 02779 //printf("%s << (m, n) = (%d, %d); c[%d] = %d; z[%d] = %d\n", __FUNCTION__, m, n, k, c[k], k, z[k]); 02780 } 02781 02782 //cin.get(); 02783 02784 for (int k = 0; k < 4; k++) 02785 { 02786 //printf("%s << z[%d] = %f\n", __FUNCTION__, k, z[k]); 02787 patchNeighbourhood.push_back(newCorners.at(z[k])); 02788 patchArrangement.push_back(fullCornerGrid.at(z[k])); 02789 //printf("%s << pn = (%f, %f)\n", __FUNCTION__, patchNeighbourhood.at(k).x, patchNeighbourhood.at(k).y); 02790 //printf("%s << pa = (%f, %f)\n", __FUNCTION__, patchArrangement.at(k).x, patchArrangement.at(k).y); 02791 neighbourhoodCount++; 02792 } 02793 02794 02795 // find homography 02796 //printf("%s << Finding homography...\n", __FUNCTION__); 02797 homography = findHomography(Mat(patchArrangement), Mat(patchNeighbourhood)); 02798 //printf("%s << Homography found!\n", __FUNCTION__); 02799 02800 cornerArrangement.clear(); 02801 02802 cornerArrangement.push_back(fullCornerGrid.at(groupedIndex)); 02803 02804 // apply homography to these co-ordinates 02805 Mat tmpMat1 = Mat(cornerArrangement); 02806 02807 perspectiveTransform(tmpMat1, cornerLocs, homography); 02808 02809 newCorners.at(groupedIndex) = Point2f(cornerLocs.at<Vec3f>(0,0)[0], cornerLocs.at<Vec3f>(0,0)[1]); 02810 02811 // Calculate maximum search distance for correcting this local point 02812 minDimension = findMinimumSeparation(patchNeighbourhood); 02813 correctionDistance = max(int(double(minDimension)/4.0), 5); 02814 02815 //printf("%s << correctionDistance = %d\n", __FUNCTION__, correctionDistance); 02816 02817 // Implement search for just this point 02818 targetCorner.clear(); 02819 targetCorner.push_back(newCorners.at(groupedIndex)); 02820 cornerSubPix(imGrey, targetCorner, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 02821 newCorners.at(groupedIndex) = targetCorner.at(0); 02822 02823 } 02824 } 02825 } 02826 02827 /* 02828 if (DEBUG_MODE > 2) { 02829 vector<Point2f> redistorted; 02830 Mat cornersForDisplay(newCorners); 02831 printf("%s << Fixing the true corners...\n", __FUNCTION__); 02832 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay); 02833 } 02834 02835 printf("%s << pre cSP\n", __FUNCTION__); 02836 cornerSubPix(imGrey, newCorners, Size(correctionDistance/2, correctionDistance/2), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 02837 */ 02838 02839 if (DEBUG_MODE > 2) 02840 { 02841 vector<Point2f> redistorted; 02842 Mat cornersForDisplay(newCorners); 02843 printf("%s << Refinement of true corners.\n", __FUNCTION__); 02844 debugDisplayPattern(image, cvSize(patternSize.width, patternSize.height), cornersForDisplay, false); 02845 02846 } 02847 02848 index = 0; 02849 02850 vCorners.clear(); 02851 vCorners.assign(newCorners.begin(), newCorners.end()); 02852 02853 } 02854 02855 void groupPointsInQuads(Size patternSize, vector<Point2f>& corners) 02856 { 02857 vector<Point2f> newCorners; 02858 02859 int id1, id2, id3, id4; 02860 02861 for (int i = 0; i < patternSize.height/2; i++) 02862 { 02863 for (int j = 0; j < patternSize.width/2; j++) 02864 { 02865 02866 id1 = 2*(i*patternSize.width+j); 02867 id2 = 2*(i*patternSize.width+j)+1; 02868 id3 = 2*(i*patternSize.width+j)+patternSize.width; 02869 id4 = 2*(i*patternSize.width+j)+patternSize.width+1; 02870 02871 //printf("%s << ids (%d, %d) = [%d, %d, %d, %d]\n", __FUNCTION__, i, j, id1, id2, id3, id4); 02872 newCorners.push_back(corners.at(id1)); 02873 newCorners.push_back(corners.at(id2)); 02874 newCorners.push_back(corners.at(id3)); 02875 newCorners.push_back(corners.at(id4)); 02876 } 02877 } 02878 02879 corners.assign(newCorners.begin(), newCorners.end()); 02880 } 02881 02882 int findBestCorners(const Mat& image, vector<Point2f>& src, vector<Point2f>& dst, Size patternSize, int detector, int searchDist) 02883 { 02884 //goodFeaturesToTrack(image, retCorner, 1, 0.05, 1.0, mask, 3, true, 0.04); 02885 int successfulMappings = 0; 02886 02887 double maxDist = 0.0; 02888 02889 vector<Point2f> foundCorners; 02890 int maxCorners = 4*src.size(); 02891 02892 unsigned int *srcBestMatches; 02893 unsigned int foundBestMatch; 02894 double bestDist, currDist; 02895 02896 /* 02897 Mat inputDisp; 02898 image.copyTo(inputDisp); 02899 drawChessboardCorners(inputDisp, cvSize(12, 8), Mat(src), true); 02900 imshow("debugWin", inputDisp); 02901 waitKey(500); 02902 */ 02903 02904 vector<KeyPoint> keypoints; 02905 02906 //printf("%s << About to grayify.\n", __FUNCTION__); 02907 02908 02909 Mat imGrey, tmpMat; 02910 if (image.channels() > 1) 02911 { 02912 cvtColor(image, imGrey, CV_RGB2GRAY); 02913 } 02914 else 02915 { 02916 image.copyTo(imGrey); 02917 } 02918 02919 02920 Mat imageCopy(480, 640, CV_8UC1); 02921 Mat inputDisp; 02922 02923 #ifdef _WIN32 02924 /* 02925 qacdtl::group_array<double> corners; 02926 vil_image_view<vxl_byte> vByteImage(imGrey.cols, imGrey.rows); 02927 vil_image_view<double> vDblImage(imGrey.cols, imGrey.rows); 02928 */ 02929 #endif 02930 02931 //printf("%s << Entered function.\n", __FUNCTION__); 02932 02933 switch (detector) 02934 { 02935 // ================================================== 02936 case 0: // NO ACTUAL CORNER DETECTOR USED 02937 // ================================================== 02938 02939 dst.assign(src.begin(), src.end()); 02940 return 0; 02941 02942 // ================================================== 02943 case 1: // BASIC HARRIS DETECTOR 02944 // ================================================== 02945 02946 // Blur 02947 //GaussianBlur(imGrey, tmpMat, Size(21,21), 5.0); 02948 //tmpMat.copyTo(imGrey); 02949 02950 // Sets maximum number of corners to 4 times the actual number 02951 goodFeaturesToTrack(imGrey, foundCorners, maxCorners, 0.001, 5.0, Mat(), 11, true, 0.04); // 3rd last should be small to limit scale... 02952 02953 //printf("%s << foundCorners.size() = %d\n", __FUNCTION__, foundCorners.size()); 02954 02955 break; 02956 // ================================================== 02957 case 2: // BIPOLAR HESSIAN DETECTOR 02958 // ================================================== 02959 #ifdef _WIN32 02960 /* 02961 // Copy from cv::Mat to vil_image view 02962 imageCopy.data = vByteImage.top_left_ptr(); // Point imageCopy data to vByteImage 02963 02964 02965 imGrey.copyTo(imageCopy); // Copy image data to this location 02966 //vByteImage.top_left_ptr() = image.data; 02967 02968 imshow("copiedImage", imageCopy); 02969 waitKey(50); 02970 //printf("%s << imageCopy.rows = %d; imageCopy.cols = %d\n", __FUNCTION__, imageCopy.rows, imageCopy.cols); 02971 02972 // Convert to double 02973 vil_convert_cast(vByteImage, vDblImage); 02974 02975 // Extract corners. 02976 qaclfl::extractor_hessian_graph::extract_corners(corners, vDblImage, 5.0); // 02977 02978 // Convert from VXL corners back to "foundCorners" vector 02979 for (unsigned int i = 0; i < corners.size(); i++) { 02980 // x, y, dx, dy, scale, strength ? 02981 foundCorners.push_back(Point2d(double(corners(i)[0]), double(corners(i)[1]))); // 2nd argument: double(corners(i)[0]) 02982 //printf("%s << pt(%d) = (%f; %f)\n", __FUNCTION__, i, corners(i)[1], corners(i)[0]); 02983 } 02984 02985 //printf("%s << foundCorners.size() = %d\n", __FUNCTION__, foundCorners.size()); 02986 */ 02987 // That's it! 02988 break; 02989 02990 #endif 02991 02992 #ifndef _WIN32 02993 // Same as case 0 02994 dst.assign(src.begin(), src.end()); 02995 return 0; 02996 #endif 02997 // ================================================== 02998 case 3: // BASIC FAST DETECTOR 02999 // ================================================== 03000 03001 //printf("%s << Using FAST detector..\n", __FUNCTION__); 03002 // Sets maximum number of corners to 4 times the actual number 03003 FAST(imGrey, keypoints, 16); 03004 03005 for (unsigned int i = 0; i < keypoints.size(); i++) 03006 { 03007 foundCorners.push_back(keypoints.at(i).pt); 03008 } 03009 03010 //printf("%s << foundCorners.size() = %d\n", __FUNCTION__, foundCorners.size()); 03011 03012 break; 03013 // ================================================== 03014 case 4: // cornerSubPix() 03015 // ================================================== 03016 //printf("%s << image.size() = (%d, %d)\n", __FUNCTION__, image.cols, image.rows); 03017 //printf("%s << src.size() = %d \n", __FUNCTION__, src.size()); 03018 //printf("%s << searchDist = %f \n", __FUNCTION__, searchDist); 03019 //printf("%s << pre cSP\n", __FUNCTION__); 03020 03021 // Rather than trying to correct all at one time, modify the distance 03022 03023 initialRefinementOfCorners(imGrey, src, patternSize); 03024 03025 dst.assign(src.begin(), src.end()); 03026 03027 if (DEBUG_MODE > 3) 03028 { 03029 image.copyTo(inputDisp); 03030 drawChessboardCorners(inputDisp, cvSize(12, 8), Mat(dst), true); 03031 imshow("mainWin", inputDisp); 03032 waitKey(0); 03033 } 03034 03035 return 0; 03036 //break; 03037 // ================================================== 03038 case 5: // cornerSubPix() + BIPOLAR HESSIAN DETECTOR 03039 // ================================================== 03040 cornerSubPix(image, src, Size(searchDist*2, searchDist*2), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 03041 03042 maxDist = 0.5; // reduce searchDist for using bipolar hessian to refine the cornerSubPix() values slightly, but not radically.. 03043 03044 #ifdef _WIN32 03045 /* 03046 // Copy from cv::Mat to vil_image view 03047 imageCopy.data = vByteImage.top_left_ptr(); // Point imageCopy data to vByteImage 03048 03049 03050 imGrey.copyTo(imageCopy); // Copy image data to this location 03051 //vByteImage.top_left_ptr() = image.data; 03052 03053 imshow("copiedImage", imageCopy); 03054 waitKey(50); 03055 //printf("%s << imageCopy.rows = %d; imageCopy.cols = %d\n", __FUNCTION__, imageCopy.rows, imageCopy.cols); 03056 03057 // Convert to double 03058 vil_convert_cast(vByteImage, vDblImage); 03059 03060 // Extract corners. 03061 qaclfl::extractor_hessian_graph::extract_corners(corners, vDblImage, 3.0); // 03062 03063 // Convert from VXL corners back to "foundCorners" vector 03064 for (unsigned int i = 0; i < corners.size(); i++) { 03065 // x, y, dx, dy, scale, strength ? 03066 foundCorners.push_back(Point2d(double(corners(i)[0]), double(corners(i)[1]))); // 2nd argument: double(corners(i)[0]) 03067 //printf("%s << pt(%d) = (%f; %f)\n", __FUNCTION__, i, corners(i)[1], corners(i)[0]); 03068 } 03069 03070 //printf("%s << foundCorners.size() = %d\n", __FUNCTION__, foundCorners.size()); 03071 */ 03072 // That's it! 03073 break; 03074 03075 #endif 03076 03077 #ifndef _WIN32 03078 // Same as case 0 03079 dst.assign(src.begin(), src.end()); 03080 return 0; 03081 #endif 03082 default: 03083 return -1; 03084 } 03085 03086 //printf("%s << Corners Detected.\n", __FUNCTION__); 03087 03088 // Display raw corners detected: 03089 //printf("%s << A...\n", __FUNCTION__); 03090 Mat imCpy(imGrey.rows, imGrey.cols, CV_8UC3); 03091 Mat imCpy2; 03092 //printf("%s << Trying to convert...\n", __FUNCTION__); 03093 cvtColor(imGrey, imCpy, CV_GRAY2RGB); 03094 //printf("%s << Converted.\n", __FUNCTION__); 03095 resize(imCpy, imCpy2, Size(), 2.0, 2.0); 03096 03097 Scalar color; 03098 03099 for (unsigned int i = 0; i < foundCorners.size(); i++) 03100 { 03101 color = Scalar( rand()&255, rand()&255, rand()&255 ); 03102 circle(imCpy2, Point2f(foundCorners.at(i).x * 2.0, foundCorners.at(i).y * 2.0), 4, color, 2); 03103 } 03104 03105 imshow("rawCorners", imCpy2); 03106 waitKey(20); 03107 03108 srcBestMatches = new unsigned int[src.size()]; 03109 03110 // Search for best matches between src and found 03111 for (unsigned int i = 0; i < src.size(); i++) 03112 { 03113 bestDist = 9e99; 03114 for (unsigned int j = 0; j < foundCorners.size(); j++) 03115 { 03116 currDist = pow(pow(double(src.at(i).x) - double(foundCorners.at(j).x), 2.0) + pow(double(src.at(i).y) - double(foundCorners.at(j).y), 2.0), 0.5); 03117 03118 if (currDist < bestDist) 03119 { 03120 bestDist = currDist; 03121 srcBestMatches[i] = j; 03122 } 03123 } 03124 } 03125 03126 // Check if these best matches are reversed 03127 for (unsigned int i = 0; i < src.size(); i++) 03128 { 03129 bestDist = 9e99; 03130 for (unsigned int k = 0; k < src.size(); k++) 03131 { 03132 // Distance between src.at(i)'s best match, and all other src elements 03133 currDist = pow(pow(double(src.at(k).x) - double(foundCorners.at(srcBestMatches[i]).x), 2.0) + pow(double(src.at(k).y) - double(foundCorners.at(srcBestMatches[i]).y), 2.0), 0.5); 03134 03135 if (currDist < bestDist) 03136 { 03137 bestDist = currDist; 03138 foundBestMatch = k; 03139 } 03140 } 03141 03142 // if src.at(i)'s best match is src.at(i), it's a besty! 03143 if ((foundBestMatch == i) && (bestDist < searchDist)) 03144 { 03145 successfulMappings++; 03146 dst.push_back(foundCorners.at(srcBestMatches[i])); 03147 } 03148 else 03149 { 03150 dst.push_back(src.at(i)); 03151 } 03152 } 03153 03154 //printf("%s << src.size() = %d\n", __FUNCTION__, src.size()); 03155 //printf("%s << dst.size() = %d\n", __FUNCTION__, dst.size()); 03156 03157 /* 03158 // Or, if you just want 1-way mappings: 03159 for (unsigned int i = 0; i < src.size(); i++) { 03160 dst.push_back(foundCorners.at(srcBestMatches[i])); 03161 } 03162 */ 03163 03164 delete[] srcBestMatches; 03165 03166 //printf("%s << successfulMappings = %d\n", __FUNCTION__, successfulMappings); 03167 03168 return successfulMappings; 03169 } 03170 03171 void initialRefinementOfCorners(const Mat& imGrey, vector<Point2f>& src, Size patternSize) 03172 { 03173 // ... 03174 03175 int correctionDistance; 03176 double minDimension; 03177 03178 Mat imDisplay; 03179 imGrey.copyTo(imDisplay); 03180 03181 Mat forDisplay(src); 03182 03183 Mat forDisp2; 03184 03185 if (DEBUG_MODE > 2) 03186 { 03187 debugDisplayPattern(imDisplay, patternSize, forDisplay, false); 03188 } 03189 03190 03191 vector<Point2f> ptNeighbourhood, targetCorner, dst; 03192 03193 dst.assign(src.begin(), src.end()); 03194 03195 // Go through all points and establish neighbourhood 03196 03197 for (int j = 1; j < patternSize.height-1; j++) 03198 { 03199 for (int i = 1; i < patternSize.width-1; i++) 03200 { 03201 03202 ptNeighbourhood.clear(); 03203 03204 //printf("%s << index = (%d, %d); vals = (", __FUNCTION__, i, j); 03205 03206 // add 4 surrounding points 03207 int val; 03208 03209 val = (j-1)*patternSize.width+(i-1); 03210 ptNeighbourhood.push_back(src.at(val)); 03211 //printf("%d, ", val); 03212 03213 val = (j-1)*patternSize.width+(i+1); 03214 ptNeighbourhood.push_back(src.at(val)); 03215 //printf("%d, ", val); 03216 03217 val = (j+1)*patternSize.width+(i-1); 03218 ptNeighbourhood.push_back(src.at(val)); 03219 //printf("%d, ", val); 03220 03221 val = (j+1)*patternSize.width+(i+1); 03222 ptNeighbourhood.push_back(src.at(val)); 03223 //printf("%d)\n", val); 03224 03225 imGrey.copyTo(imDisplay); 03226 03227 forDisp2 = Mat(ptNeighbourhood); 03228 03229 if (DEBUG_MODE > 2) 03230 { 03231 //debugDisplayPattern(imDisplay, Size(2, 2), forDisp2, true); 03232 } 03233 03234 03235 minDimension = findMinimumSeparation(ptNeighbourhood); 03236 03237 //printf("%s << minDimension = %f\n", __FUNCTION__, minDimension); 03238 03239 correctionDistance = max(int(double(minDimension)/4), 5); 03240 03241 //printf("%s << correctionDistance = %d\n", __FUNCTION__, correctionDistance); 03242 03243 targetCorner.clear(); 03244 targetCorner.push_back(src.at(j*patternSize.width+i)); 03245 03246 cornerSubPix(imGrey, targetCorner, Size(correctionDistance, correctionDistance), Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1)); 03247 03248 dst.at(j*patternSize.width+i) = targetCorner.at(0); 03249 03250 } 03251 } 03252 03253 Mat imCol; 03254 03255 cvtColor(imDisplay, imCol, CV_GRAY2RGB); 03256 03257 03258 03259 if (DEBUG_MODE > 2) 03260 { 03261 debugDisplayPattern(imDisplay, patternSize, forDisplay, false); 03262 03263 drawLinesBetweenPoints(imCol, src, dst); 03264 03265 imshow("lineDrawing", imCol); 03266 waitKey(0); 03267 } 03268 03269 03270 03271 src.assign(dst.begin(), dst.end()); 03272 03273 //imGrey.copyTo(imDisplay); 03274 //debugDisplayPattern(imGrey, patternSize, forDisplay, true); 03275 03276 03277 03278 } 03279 03280 void sortCorners(Size imageSize, Size patternSize, vector<Point2f>& corners) 03281 { 03282 vector<Point2f> newCorners; 03283 03284 int X = patternSize.width/2; 03285 int Y = patternSize.height/2; 03286 03287 // 0,1,4,5,8,9,12,13,16,17,20,21,2,3,6,7,10,11,14,15,18,19,22,23 03288 // 0,4,8,12,16,20 03289 03290 for (int i = 0; i < Y; i++) // for each row (square) 03291 { 03292 for (int j = 0; j < X; j++) // for each column (square) 03293 { 03294 if (DEBUG_MODE > 3) 03295 { 03296 printf("%d, %d, ", 4*i*X+j*4, 4*i*X+j*4+1); 03297 } 03298 newCorners.push_back(corners.at(4*i*X+j*4)); // push back first element 03299 newCorners.push_back(corners.at(4*i*X+j*4+1)); // push back second element 03300 } 03301 03302 for (int j = 0; j < X; j++) 03303 { 03304 if (DEBUG_MODE > 3) 03305 { 03306 printf("%d, %d, ", 4*i*X+j*4+2, 4*i*X+j*4+3); 03307 } 03308 newCorners.push_back(corners.at(4*i*X+j*4+2)); // push back third element 03309 newCorners.push_back(corners.at(4*i*X+j*4+3)); // push back fourth element // push back third element 03310 } 03311 //printf("\n"); 03312 } 03313 03314 corners.clear(); 03315 03316 for (unsigned int i = 0; i < newCorners.size(); i++) 03317 { 03318 corners.push_back(newCorners.at(i)); 03319 } 03320 } 03321 03322 bool correctPatchCentres(const Mat& image, Size patternSize, vector<Point2f>& patchCentres, int mode) 03323 { 03324 03325 bool found = true; 03326 03327 return found; 03328 03329 printf("%s << Entering...\n", __FUNCTION__); 03330 03331 Mat imGrey; 03332 if (image.channels() > 1) 03333 { 03334 cvtColor(image, imGrey, CV_RGB2GRAY); 03335 } 03336 else 03337 { 03338 image.copyTo(imGrey); 03339 } 03340 03341 Point3f newPoint; 03342 cv::vector<Point3f> row; 03343 03344 //printf("%s << patternSize = (%d, %d)\n", __FUNCTION__, patternSize.width, patternSize.height); 03345 03346 if (mode == 1) 03347 { 03348 for (int i = 0; i < patternSize.height/2; i++) 03349 { 03350 for (int j = 0; j < patternSize.width/2; j++) 03351 { 03352 newPoint = Point3f(float(i), float(j), 0.0); 03353 row.push_back(newPoint); 03354 } 03355 03356 } 03357 } 03358 else 03359 { 03360 for (int i = 0; i < patternSize.height+1; i++) 03361 { 03362 for (int j = 0; j < patternSize.width+1; j++) 03363 { 03364 newPoint = Point3f(float(i), float(j), 0.0); 03365 row.push_back(newPoint); 03366 } 03367 03368 } 03369 } 03370 03371 if (DEBUG_MODE > 2) 03372 { 03373 Mat cornersMat(patchCentres); 03374 debugDisplayPattern(image, cvSize(patternSize.width/2, patternSize.height/2), cornersMat); 03375 } 03376 03377 //printf("%s << row.size() = %d\n", __FUNCTION__, row.size()); 03378 03379 //printf("%s << STEP 1a...\n", __FUNCTION__); 03380 03381 cv::vector< cv::vector<Point3f> > objectPoints; 03382 objectPoints.push_back(row); 03383 03384 vector<vector<Point2f> > vvOriginalCentres; 03385 vvOriginalCentres.push_back(patchCentres); 03386 03387 //printf("%s << STEP 1b...\n", __FUNCTION__); 03388 03389 Mat cameraMatrix, distCoeffs, newCamMat; 03390 03391 cv::vector<Mat> rvecs, tvecs; 03392 03393 calibrateCamera(objectPoints, vvOriginalCentres, image.size(), cameraMatrix, distCoeffs, rvecs, tvecs, PATCH_CORRECTION_INTRINSICS_FLAGS); 03394 03395 double alpha = 0.5; 03396 03397 Rect validROI; 03398 newCamMat = getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, image.size(), alpha, image.size(), &validROI); 03399 03400 Mat undistortedImage; 03401 undistort(image, undistortedImage, cameraMatrix, distCoeffs, newCamMat); 03402 03403 vector<Point2f> newCentres; 03404 found = findPatternCentres(undistortedImage, patternSize, newCentres, mode); 03405 03406 if (!found) 03407 { 03408 printf("%s << Pattern could not be found once image was undistorted..\n", __FUNCTION__); 03409 //cin.get(); 03410 return found; 03411 } 03412 03413 printf("%s << Redistorting MSER centroids...\n", __FUNCTION__); 03414 //patchCentres.clear(); 03415 redistortPoints(newCentres, patchCentres, cameraMatrix, distCoeffs, newCamMat); 03416 printf("%s << newCentres.size() = %d\n", __FUNCTION__, newCentres.size()); 03417 printf("%s << patchCentres.size() = %d\n", __FUNCTION__, patchCentres.size()); 03418 printf("%s << DONE.\n", __FUNCTION__); 03419 03420 if (DEBUG_MODE > 2) 03421 { 03422 Mat cornersMat(patchCentres); 03423 debugDisplayPattern(image, cvSize(patternSize.width/2, patternSize.height/2), cornersMat); 03424 } 03425 03426 /* 03427 double meanVal = 0.0, maxVal = 0.0; 03428 03429 for (int i = 0; i < patchCentres.size(); i++) { 03430 for (int j = 0; j < 1; j++) { 03431 for (int k = 0; k < 1; k++) { 03432 if (imGrey.at<unsigned char>(patchCentres.at(i).y+j, patchCentres.at(i).x+k) > maxVal) { 03433 maxVal = imGrey.at<unsigned char>(patchCentres.at(i).y+j, patchCentres.at(i).x+k); 03434 } 03435 meanVal += imGrey.at<unsigned char>(patchCentres.at(i).y+j, patchCentres.at(i).x+k); 03436 } 03437 } 03438 } 03439 03440 03441 03442 meanVal /= (1*patchCentres.size()); 03443 03444 printf("%s << meanVal = %f\n", __FUNCTION__, meanVal); 03445 03446 Mat enhancedImage(imGrey.size(), imGrey.type()); 03447 03448 //imshow("correcting", imGrey); 03449 //waitKey(0); 03450 03451 //imGrey.copyTo(enhancedImage); 03452 contrastEnhance(imGrey, enhancedImage, int(0.5*meanVal), int(meanVal + 0.5*(255 - meanVal))); // int(meanVal*6) 03453 03454 imshow("correcting", enhancedImage); 03455 waitKey(40); 03456 03457 vector<Point2f> newCentres; 03458 03459 Mat enhancedCol; 03460 cvtColor(enhancedImage, enhancedCol, CV_GRAY2RGB); 03461 03462 03463 bool found = false; 03464 03465 printf("%s << Searching for pattern centres...\n", __FUNCTION__); 03466 found = findPatternCentres(enhancedCol, patternSize, newCentres, 0); 03467 printf("%s << Search complete.\n", __FUNCTION__); 03468 03469 if (found) { 03470 printf("%s << found 2nd time.\n", __FUNCTION__); 03471 patchCentres.assign(newCentres.begin(), newCentres.end()); 03472 } 03473 03474 printf("%s << Exiting...\n", __FUNCTION__); 03475 */ 03476 03477 return found; 03478 } 03479 03480 /* 03481 void redistortPoints(const vector<Point2f>& src, vector<Point2f>& dst, const Mat& cameraMatrix, const Mat& distCoeffs, const Mat& newCamMat) 03482 { 03483 03484 double fx, fy, ifx, ify, cx, cy; 03485 double fx0, fy0, ifx0, ify0, cx0, cy0; 03486 double k[8]= {0,0,0,0,0,0,0,0}, RR[3][3]= {{1,0,0},{0,1,0},{0,0,1}}; 03487 double r2, icdist, deltaX, deltaY; 03488 double x, y, x0, y0, x1, y1, xx, yy, ww; 03489 03490 Mat optimalMat(3, 3, CV_64FC1); 03491 03492 // optimalMat = getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, Size(640,48), 1.0); 03493 03494 //printf("%s << entered function.\n", __FUNCTION__); 03495 03496 // will probably crash if it receives the identity matrix etc... 03497 03498 fx0 = cameraMatrix.at<double>(0, 0); 03499 fy0 = cameraMatrix.at<double>(1, 1); 03500 ifx0 = 1./fx0; 03501 ify0 = 1./fy0; 03502 cx0 = cameraMatrix.at<double>(0, 2); 03503 cy0 = cameraMatrix.at<double>(1, 2); 03504 03505 fx = newCamMat.at<double>(0, 0); 03506 fy = newCamMat.at<double>(1, 1); 03507 ifx = 1./fx; 03508 ify = 1./fy; 03509 cx = newCamMat.at<double>(0, 2); 03510 cy = newCamMat.at<double>(1, 2); 03511 03512 for (unsigned int i = 0; i < 8; i++) 03513 { 03514 k[i] = distCoeffs.at<double>(0, i); 03515 } 03516 03517 //printf("%s << cx = %f; cy = %f\n", __FUNCTION__, cx, cy); 03518 03519 //cin.get(); 03520 03521 dst.clear(); 03522 03523 for (unsigned int i = 0; i < src.size(); i++) 03524 { 03525 // Points in undistorted image 03526 x = src.at(i).x; 03527 y = src.at(i).y; 03528 03529 // printf("%s << undistorted points at [%d] = (%f, %f)\n", __FUNCTION__, i, x, y); 03530 03531 // Apply cameraMatrix parameters (normalization) 03532 x0 = (x - cx)*ifx; 03533 y0 = (y - cy)*ify; 03534 03535 x = x0; 03536 y = y0; 03537 03538 // Determine radial and tangential distances/factors 03539 r2 = x*x + y*y; 03540 icdist = (1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2)/(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2); 03541 deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x); 03542 deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y; 03543 03544 //icdist *= 0.75; 03545 03546 // Redistort 03548 //x = (x0 - deltaX)/icdist; 03549 //y = (y0 - deltaY)/icdist; 03550 // 03551 03552 x = (x0/icdist) + deltaX; 03553 y = (y0/icdist) + deltaY; 03554 // 03555 //x = x0/icdist; 03556 //y = y0/icdist; 03557 03558 // Do something... 03559 03560 //xx = RR[0][0]*x + RR[0][1]*y + RR[0][2]; 03561 //yy = RR[1][0]*x + RR[1][1]*y + RR[1][2]; 03562 //ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]); 03563 //x = xx*ww; 03564 //y = yy*ww; 03565 03566 03567 x1 = x; 03568 y1 = y; 03569 03570 // Reverse cameraMatrix parameters (denormalization) 03571 x = (x1/ifx0) + cx0; 03572 y = (y1/ify0) + cy0; 03573 03574 // printf("%s << redistorted points at [%d] = (%f, %f)\n", __FUNCTION__, i, x, y); 03575 03576 //cin.get(); 03577 03578 dst.push_back(Point2f(x, y)); 03579 } 03580 03581 // Temporary... 03582 // dst.assign(src.begin(), src.end()); 03583 } 03584 */ 03585 bool findPatternCentres(const Mat& image, Size patternSize, vector<Point2f>& centres, int mode) 03586 { 03587 // mode 0: MSER chessboard finder 03588 // mode 1: MSER mask finder 03589 03590 if (!checkAcutance()) 03591 { 03592 return false; 03593 } 03594 03595 int patchCols, patchRows, desiredPatchQuantity; 03596 determinePatchDistribution(patternSize, mode, patchRows, patchCols, desiredPatchQuantity); 03597 03598 vector<vector<Point> > msers; 03599 findAllPatches(image, patternSize, msers); 03600 03601 if (DEBUG_MODE > 3) 03602 { 03603 debugDisplayPatches(image, msers); 03604 } 03605 03606 if (int(msers.size()) < desiredPatchQuantity) 03607 { 03608 centres.clear(); 03609 if (DEBUG_MODE > 1) 03610 { 03611 printf("%s << Insufficient patches found. Returning.\n", __FUNCTION__); 03612 } 03613 03614 return false; 03615 } 03616 03617 bool found = refinePatches(image, patternSize, msers, centres, mode); 03618 03619 if (DEBUG_MODE > 1) 03620 { 03621 printf("%s << Patches found after refinement = %d\n", __FUNCTION__, msers.size()); 03622 } 03623 03624 if (DEBUG_MODE > 3) 03625 { 03626 debugDisplayPatches(image, msers); 03627 } 03628 03629 // If patches still not found... 03630 if (!found) 03631 { 03632 centres.clear(); 03633 03634 if (DEBUG_MODE > 1) 03635 { 03636 printf("%s << Correct number of patches not found. Returning.\n", __FUNCTION__); 03637 } 03638 03639 return false; 03640 } 03641 03642 sortPatches(image.size(), patternSize, centres, mode); 03643 03644 if (DEBUG_MODE > 3) 03645 { 03646 Mat patchCentres_(centres); 03647 debugDisplayPattern(image, cvSize(patchCols, patchRows), patchCentres_); 03648 } 03649 03650 found = verifyPatches(image.size(), patternSize, centres, mode, 0, 1000); 03651 03652 if (!found) 03653 { 03654 centres.clear(); 03655 03656 if (DEBUG_MODE > 1) 03657 { 03658 printf("%s << Pattern verification failed. Returning.\n", __FUNCTION__); 03659 } 03660 03661 return false; 03662 } 03663 03664 return found; 03665 } 03666 03667 bool verifyPattern(Size imSize, Size patternSize, vector<Point2f>& patternPoints, double minDist, double maxDist) 03668 { 03669 03670 // Check that all points are within the image view: 03671 bool retVal = true; 03672 03673 retVal = patternInFrame(imSize, patternPoints); 03674 03675 if (retVal == false) 03676 { 03677 03678 if (DEBUG_MODE > 1) 03679 { 03680 printf("%s << Some pattern points are outside valid area.\n", __FUNCTION__); 03681 } 03682 03683 return retVal; 03684 } 03685 03686 double dist, dist1, dist2, factor; 03687 03688 double maxStraightnessDist = 30.0; 03689 03690 int index; 03691 03692 Mat blackImage = Mat::zeros(imSize, CV_8UC3); 03693 Scalar blue(255, 0, 0), green(0, 255, 0), red(0, 0, 255); 03694 03695 03696 // STRAIGHTNESS TEST 03697 // For each row 03698 for (int i = 0; i < patternSize.height; i++) 03699 { 03700 for (int j = 0; j < patternSize.width-2; j++) 03701 { 03702 // check distance of point with one to its right 03703 03704 index = i*patternSize.width + j; 03705 03706 blackImage.setTo(0); 03707 03708 /* 03709 if (DEBUG_MODE > 3) { 03710 circle(blackImage, patternPoints.at(index), 5, red, 3); 03711 circle(blackImage, patternPoints.at(index + 1), 5, green, 3); 03712 circle(blackImage, patternPoints.at(index + 2), 5, blue, 3); 03713 imshow("testImage", blackImage); 03714 waitKey(0); 03715 } 03716 */ 03717 03718 03719 dist = perpDist(patternPoints.at(index), patternPoints.at(index + 1), patternPoints.at(index + 2)); 03720 dist1 = distBetweenPts2f(patternPoints.at(index),patternPoints.at(index + 1)); 03721 dist2 = distBetweenPts2f(patternPoints.at(index + 1),patternPoints.at(index + 2)); 03722 03723 factor = max(dist1, dist2) / min(dist1, dist2); 03724 03725 //printf("%s << dist = %f\n", __FUNCTION__, dist); 03726 if (dist > maxStraightnessDist) 03727 { 03728 if (DEBUG_MODE > 0) 03729 { 03730 printf("%s << Row out of alignment.\n", __FUNCTION__); 03731 } 03732 03733 //waitKey(0); 03734 return false; 03735 } 03736 03737 if (factor > 2.0) 03738 { 03739 if (DEBUG_MODE > 0) 03740 { 03741 printf("%s << Row factor is out.\n", __FUNCTION__); 03742 printf("%s << factor / [dist1, dist2] = %f / [%f, %f].\n", __FUNCTION__, factor, dist1, dist2); 03743 } 03744 //waitKey(0); 03745 return false; 03746 } 03747 } 03748 } 03749 03750 //waitKey(0); 03751 03752 // For each column 03753 for (int i = 0; i < patternSize.height-2; i++) 03754 { 03755 for (int j = 0; j < patternSize.width; j++) 03756 { 03757 // check distance of point with one below it 03758 dist = perpDist(patternPoints.at(i*patternSize.width + j), patternPoints.at((i+1)*patternSize.width + j), patternPoints.at((i+2)*patternSize.width + j)); 03759 dist1 = distBetweenPts2f(patternPoints.at(i*patternSize.width + j), patternPoints.at((i+1)*patternSize.width + j)); 03760 dist2 = distBetweenPts2f(patternPoints.at((i+1)*patternSize.width + j), patternPoints.at((i+2)*patternSize.width + j)); 03761 03762 factor = max(dist1, dist2) / min(dist1, dist2); 03763 03764 if (dist > maxStraightnessDist) 03765 { 03766 if (DEBUG_MODE > 0) 03767 { 03768 printf("%s << Column out of alignment.\n", __FUNCTION__); 03769 } 03770 //waitKey(0); 03771 return false; 03772 } 03773 03774 if (factor > 2.0) 03775 { 03776 if (DEBUG_MODE > 0) 03777 { 03778 printf("%s << Column out of scale. 1\n", __FUNCTION__); 03779 } 03780 //waitKey(0); 03781 return false; 03782 } 03783 } 03784 } 03785 03786 // CLOSENESS TEST 03787 // For each row 03788 for (int i = 0; i < patternSize.height; i++) 03789 { 03790 for (int j = 0; j < patternSize.width-1; j++) 03791 { 03792 // check distance of point with one to its right 03793 dist = distBetweenPts2f(patternPoints.at(i*patternSize.width + j),patternPoints.at(i*patternSize.width + j + 1)); 03794 if ((dist > maxDist) || (dist < minDist)) 03795 { 03796 if (DEBUG_MODE > 0) 03797 { 03798 printf("%s << Row out of scale.\n", __FUNCTION__); 03799 printf("%s << dist / [min, max] = %f / [%f, %f].\n", __FUNCTION__, dist, minDist, maxDist); 03800 03801 } 03802 //waitKey(0); 03803 return false; 03804 } 03805 } 03806 } 03807 03808 // For each column 03809 for (int i = 0; i < patternSize.height-1; i++) 03810 { 03811 for (int j = 0; j < patternSize.width; j++) 03812 { 03813 // check distance of point with one below it 03814 dist = distBetweenPts2f(patternPoints.at(i*patternSize.width + j), patternPoints.at((i+1)*patternSize.width + j)); 03815 if ((dist > maxDist) || (dist < minDist)) 03816 { 03817 if (DEBUG_MODE > 0) 03818 { 03819 printf("%s << Column out of scale.\n", __FUNCTION__); 03820 } 03821 //waitKey(0); 03822 return false; 03823 } 03824 } 03825 } 03826 03827 // If it has still survived: 03828 return true; 03829 } 03830 03831 bool verifyPatches(Size imSize, Size patternSize, vector<Point2f>& patchCentres, int mode, double minDist, double maxDist) 03832 { 03833 03834 Size newPatternSize; 03835 03836 if (mode == 0) 03837 { 03838 newPatternSize = Size(patternSize.width+1, patternSize.height+1); 03839 } 03840 else 03841 { 03842 newPatternSize = Size(patternSize.width/2, patternSize.height/2); 03843 } 03844 03845 return verifyPattern(imSize, newPatternSize, patchCentres, minDist, maxDist); 03846 03847 // old stuff.. 03848 int64 t = getTickCount(); 03849 03850 // Some kind of big loop test, and if a failure is found return false immediately 03851 for (unsigned int i = 0; i < 10; i++) 03852 { 03853 if (0) 03854 { 03855 if (DEBUG_MODE > 0) 03856 { 03857 t = getTickCount() - t; 03858 printf("%s << Algorithm duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 03859 } 03860 return false; 03861 } 03862 } 03863 03864 if (DEBUG_MODE > 0) 03865 { 03866 t = getTickCount() - t; 03867 printf("%s << Algorithm duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 03868 } 03869 03870 return true; 03871 } 03872 03873 bool patternInFrame(Size imSize, vector<Point2f>& patternPoints, int minBorder) 03874 { 03875 03876 // Check that all points are within the image view: 03877 for (unsigned int i = 0; i < patternPoints.size(); i++) 03878 { 03879 if ((patternPoints.at(i).x >= imSize.width-minBorder) || (patternPoints.at(i).x < minBorder) || (patternPoints.at(i).y >= imSize.height-minBorder) || (patternPoints.at(i).y < minBorder)) 03880 { 03881 03882 patternPoints.clear(); 03883 03884 return false; 03885 } 03886 } 03887 03888 // None of the points are within minBorder pixels of the border 03889 return true; 03890 03891 } 03892 03893 void shapeFilter(vector<mserPatch>& patches, vector<vector<Point> >& msers) 03894 { 03895 // TODO: 03896 // Improve height/width measurement so that it more accurately detects skinniness, since 03897 // at the moment thin msers that are at angles are still accepted. 03898 // Once this has been implemented, you can relax the requirements so that it doesn't reject 03899 // the pattern when it is at a significant angle to the camera. 03900 03901 vector<mserPatch> newPatches; 03902 vector<vector<Point> > newMsers; 03903 03904 // Any MSERs that have a height/width ratio within the acceptableFactor are accepted 03905 double cWidth, cHeight; 03906 double acceptableFactor = 2.0; 03907 03908 for (unsigned int i = 0; i < patches.size(); i++) 03909 { 03910 cWidth = 0; 03911 cHeight = 0; 03912 //contourDimensions(patches.at(i).hull, cWidth, cHeight); 03913 contourDimensions(msers.at(i), cWidth, cHeight); 03914 //printf("contour [%d] dimensions: %f x %f\n", i, cWidth, cHeight); 03915 03916 if (((cHeight/cWidth) < acceptableFactor) && ((cWidth/cHeight) < acceptableFactor)) 03917 { 03918 newMsers.push_back(msers.at(i)); 03919 newPatches.push_back(patches.at(i)); 03920 } 03921 } 03922 03923 patches.clear(); 03924 msers.clear(); 03925 03926 for (unsigned int i = 0; i < newPatches.size(); i++) 03927 { 03928 patches.push_back(newPatches.at(i)); 03929 msers.push_back(newMsers.at(i)); 03930 } 03931 03932 } 03933 03934 void varianceFilter(vector<mserPatch>& patches, vector<vector<Point> >& msers) 03935 { 03936 vector<mserPatch> newPatches; 03937 vector<vector<Point> > newMsers; 03938 03939 //double maxAcceptableVariance = 256.0; // 16 squared... 03940 double maxAcceptableVariance = 1024.0; // 32 squared... 03941 03942 for (unsigned int i = 0; i < patches.size(); i++) 03943 { 03944 if (patches.at(i).varIntensity < maxAcceptableVariance) 03945 { 03946 newMsers.push_back(msers.at(i)); 03947 newPatches.push_back(patches.at(i)); 03948 } 03949 } 03950 03951 patches.clear(); 03952 msers.clear(); 03953 03954 for (unsigned int i = 0; i < newPatches.size(); i++) 03955 { 03956 patches.push_back(newPatches.at(i)); 03957 msers.push_back(newMsers.at(i)); 03958 } 03959 03960 } 03961 03962 void enclosureFilter(vector<mserPatch>& patches, vector<vector<Point> >& msers) 03963 { 03964 03965 unsigned int i = 0, j = 0; 03966 03967 bool encloses = false; 03968 03969 double enclosureScore = 0.0; 03970 03971 while (i < patches.size()) 03972 { 03973 encloses = false; 03974 j = 0; 03975 03976 //printf("%s << i = %d\n", __FUNCTION__, i); 03977 03978 while ((j < patches.size()) && !encloses) 03979 { 03980 03981 //printf("%s << j = %d\n", __FUNCTION__, j); 03982 03983 if (j != i) 03984 { 03985 if (patches.at(i).area >= patches.at(j).area) 03986 { 03987 03988 //printf("%s << i = %d\n", __FUNCTION__, i); 03989 //printf("%s << j = %d\n", __FUNCTION__, j); 03990 03991 //printf("%s << i area is larger than j.\n", __FUNCTION__); 03992 // Check if the first MSER is within the second MSER 03993 enclosureScore = pointPolygonTest(Mat(patches.at(i).hull), patches.at(j).centroid, false); 03994 03995 //printf("%s << enclosureScore = %f\n", __FUNCTION__, enclosureScore); 03996 03997 if (enclosureScore > 0.0) 03998 { 03999 encloses = true; 04000 //printf("%s << patch [%d] encloses patch [%d]\n", __FUNCTION__, i, j); 04001 } 04002 } 04003 } 04004 04005 j++; 04006 } 04007 04008 04009 04010 if (encloses) 04011 { 04012 patches.erase(patches.begin() + i); 04013 msers.erase(msers.begin() + i); 04014 } 04015 else 04016 { 04017 i++; 04018 } 04019 } 04020 04021 //printf("%s << patches.size() = %d\n", __FUNCTION__, patches.size()); 04022 04023 return; 04024 04025 // old enclosureFilter() ................ 04026 04027 //printf("patches.at(0).hull.size() = %d\n", patches.at(0).hull.size()); 04028 vector<mserPatch> newPatches; 04029 vector<vector<Point> > newMsers; 04030 double enclosed = -1.0; 04031 Point avCenter(0, 0); 04032 unsigned int accumulatedCount = 0; 04033 04034 for (unsigned int i = 0; i < patches.size()-1; i++) 04035 { 04036 // Assumed it's not 'enclosed' by another MSER 04037 enclosed = -1.0; 04038 04039 // First point will always be the smallest in a series 04040 if (i == 0) 04041 { 04042 newPatches.push_back(patches.at(i)); 04043 newMsers.push_back(msers.at(i)); 04044 04045 avCenter += patches.at(i).centroid; // Add centroid to accumulated center 04046 accumulatedCount++; 04047 } 04048 04049 04050 // If the area of the 2nd one is greater 04051 if (patches.at(i).area < patches.at(i+1).area) 04052 { 04053 // Check if the first MSER is within the second MSER 04054 enclosed = pointPolygonTest(Mat(patches.at(i+1).hull), patches.at(i).centroid, false); 04055 } 04056 04057 04058 // If new point does not enclose current point, you can add new point to the newMsers vector 04059 if (enclosed < 0.0) 04060 { 04061 //printf("not enclosed\n"); 04062 04063 // Want to correct the last added point to be the mean of all of the 'series' 04064 04065 //printf("%s << Changing centroid: (%d, %d) to ", __FUNCTION__, newPatches.at(newPatches.size()-1).centroid.x, newPatches.at(newPatches.size()-1).centroid.y); 04066 //newPatches.at(newPatches.size()-1).centroid = Point(avCenter.x/accumulatedCount, avCenter.y/accumulatedCount); 04067 //newPatches.at(newPatches.size()-1).centroid = patches.at(i).centroid; 04068 //printf("(%d, %d)\n", newPatches.at(newPatches.size()-1).centroid.x, newPatches.at(newPatches.size()-1).centroid.y); 04069 //cin.get(); 04070 04071 04072 accumulatedCount = 0; 04073 avCenter = Point(0, 0); 04074 04075 newPatches.push_back(patches.at(i+1)); 04076 newMsers.push_back(msers.at(i+1)); 04077 } 04078 04079 avCenter += patches.at(i+1).centroid; 04080 accumulatedCount++; 04081 04082 } 04083 04084 patches.clear(); 04085 msers.clear(); 04086 04087 for (unsigned int i = 0; i < newPatches.size(); i++) 04088 { 04089 patches.push_back(newPatches.at(i)); 04090 msers.push_back(newMsers.at(i)); 04091 } 04092 04093 } 04094 04095 void reduceCluster(vector<mserPatch>& patches, vector<vector<Point> >& msers, int totalPatches) 04096 { 04097 04098 04099 // While the number of patches is larger than totalPatches, this function will 04100 // eliminate the patch that causes the largest change in area of a convex hull fitted to all patch 04101 // centers, when it's removed 04102 04103 vector<Point> pointsForArea; 04104 RotatedRect wrapperRectangle; 04105 Point2f circleCenter; 04106 float radius; 04107 04108 double totalArea; 04109 double newArea; 04110 double maxDiff = 0; 04111 int maxIndex = 0; 04112 04113 // While there are too many patches 04114 while (patches.size() > ((unsigned int)totalPatches)) 04115 { 04116 maxDiff = 0; 04117 maxIndex = 0; 04118 04119 // calculate total current area 04120 pointsForArea.clear(); 04121 for (unsigned int i = 0; i < patches.size(); i++) 04122 { 04123 pointsForArea.push_back(patches.at(i).centroid); 04124 } 04125 04126 wrapperRectangle = fitEllipse(Mat(pointsForArea)); 04127 minEnclosingCircle(Mat(pointsForArea), circleCenter, radius); 04128 04129 // totalArea = contourArea(Mat(pointsForArea)); 04130 // totalArea = (wrapperRectangle.size.width) * (wrapperRectangle.size.height); 04131 totalArea = radius; 04132 04133 //printf("%s << totalArea = %f\n", __FUNCTION__, totalArea); 04134 04135 for (unsigned int i = 0; i < patches.size(); i++) 04136 { 04137 04138 // determine newArea when element i is removed: 04139 pointsForArea.clear(); 04140 for (unsigned int j = 0; j < patches.size(); j++) 04141 { 04142 if (j != i) 04143 { 04144 //printf("%s << pushing back... [%d] / %d,%d\n", __FUNCTION__, j, patches.at(j).centroid.x, patches.at(j).centroid.y); 04145 pointsForArea.push_back(patches.at(j).centroid); 04146 } 04147 } 04148 04149 wrapperRectangle = fitEllipse(Mat(pointsForArea)); 04150 minEnclosingCircle(Mat(pointsForArea), circleCenter, radius); 04151 04152 //newArea = contourArea(Mat(pointsForArea)); 04153 //newArea = (wrapperRectangle.size.width) * (wrapperRectangle.size.height); 04154 newArea = radius; 04155 04156 //printf("%s << newArea[%d] = %f\n", __FUNCTION__, i, newArea); 04157 04158 // If the area reduction is maximal, record: 04159 if ((totalArea - newArea) > maxDiff) 04160 { 04161 maxDiff = totalArea - newArea; 04162 maxIndex = i; 04163 04164 //printf("%s << maxIndex = [%d]\n", __FUNCTION__, i); 04165 } 04166 04167 } 04168 04169 // remove the offending patch from the patches vector 04170 04171 patches.erase(patches.begin() + maxIndex); 04172 msers.erase(msers.begin() + maxIndex); 04173 04174 } 04175 04176 return; 04177 04178 } 04179 04180 void clusterFilter(vector<mserPatch>& patches, vector<vector<Point> >& msers, int totalPatches) 04181 { 04182 // Try new approach which removes the most abnormal patch based on differences with median 04183 04184 vector<double> patchAreas, patchAreasSorted; 04185 04186 for (unsigned int iii = 0; iii < patches.size(); iii++) { 04187 04188 patchAreas.push_back(patches.at(iii).area); 04189 04190 } 04191 04192 while (patches.size() > ((unsigned int)totalPatches)) { 04193 04194 // Determine medians: 04195 patchAreasSorted.clear(); 04196 patchAreasSorted.insert(patchAreasSorted.end(), patchAreas.begin(), patchAreas.end()); 04197 sort(patchAreasSorted.begin(), patchAreasSorted.end()); 04198 04199 double medianVal = patchAreas.at(int(patchAreasSorted.size() / 2)); 04200 04201 //printf("%s << medianVal = %f\n", __FUNCTION__, medianVal); 04202 04203 double maxDiff = -1.0;; 04204 int maxDiffIndex = -1; 04205 04206 for (unsigned int iii = 0; iii < patchAreasSorted.size(); iii++) { 04207 04208 if ((abs(patchAreasSorted.at(iii) - medianVal)) > maxDiff) { 04209 maxDiff = abs(patchAreasSorted.at(iii) - medianVal); 04210 maxDiffIndex = iii; 04211 } 04212 04213 //printf("%s << area(%d) = %f (diff = %f\n", __FUNCTION__, iii, patchAreas.at(iii), abs(patchAreas.at(iii) - medianVal)); 04214 04215 } 04216 04217 //printf("%s << maxDiffIndex = %d / %d\n", __FUNCTION__, maxDiffIndex, patchAreasSorted.size()); 04218 04219 double badArea = patchAreasSorted.at(maxDiffIndex); 04220 04221 04222 bool culpritFound = false; 04223 unsigned int iii = 0; 04224 while (!culpritFound) { 04225 //printf("%s << iii = (%d / %d)\n", __FUNCTION__, iii, patchAreas.size()); 04226 if (patchAreas.at(iii) == badArea) { 04227 culpritFound = true; 04228 } else { 04229 iii++; 04230 } 04231 } 04232 04233 patchAreasSorted.erase(patchAreasSorted.begin() + maxDiffIndex); 04234 patchAreas.erase(patchAreas.begin() + iii); 04235 04236 patches.erase(patches.begin() + iii); 04237 msers.erase(msers.begin() + iii); 04238 04239 04240 } 04241 04242 04243 return; 04244 04245 // TODO: 04246 // maybe avoid discriminating based on intensity initially - since sometimes with the 04247 // chessboard you can get large clusters of white squares (and other background features) which 04248 // could throw off the algorithm. 04249 // get it to take into account colour if it's a multiple channel image 04250 04251 vector<mserPatch> newPatches; 04252 vector<vector<Point> > newMsers; 04253 04254 bool clusterFound = false; 04255 unsigned int ii = 0, jj = 0; 04256 double minDist, maxDist; 04257 double minArea, maxArea; 04258 Point centroidA, centroidB; 04259 double intensityA, intensityB; 04260 double areaA, areaB; 04261 double areaVar = 1.0; // 0.5 04262 double intensityVar = 32.0; // 32 04263 double distVar = 1.0; // 1.0 04264 04265 // newMsers is the new cluster: 04266 newPatches.push_back(patches.at(patches.size()-1)); 04267 patches.pop_back(); 04268 newMsers.push_back(msers.at(msers.size()-1)); 04269 msers.pop_back(); 04270 04271 while (!clusterFound) 04272 { 04273 04274 04275 while (jj < newPatches.size()) 04276 { 04277 04278 // obtain interest point values 04279 centroidA = newPatches.at(jj).centroid; 04280 areaA = newPatches.at(jj).area; 04281 intensityA = newPatches.at(jj).meanIntensity; 04282 04283 04284 04285 04286 // obtain limits 04287 minArea = areaA/(1+areaVar); 04288 maxArea = areaA*(1+areaVar); 04289 minDist = (2*pow(areaA, 0.5))/(1+distVar); 04290 maxDist = (2*pow(areaA, 0.5))*(1+distVar); 04291 04292 /* 04293 if (DEBUG_MODE > 3) { 04294 printf("%s << area = %f; intensity = %f\n", __FUNCTION__, areaA, intensityA); 04295 printf("%s << minArea = %f; maxArea = %f\n", __FUNCTION__, minArea, maxArea); 04296 printf("%s << minDist = %f; maxDist = %f\n", __FUNCTION__, minDist, maxDist); 04297 } 04298 */ 04299 04300 while (ii < patches.size()) 04301 { 04302 //printf("jj = %d; ii = %d.\n", jj, ii); 04303 04304 // obtain comparison point values 04305 centroidB = patches.at(ii).centroid; 04306 areaB = patches.at(ii).area; 04307 intensityB = patches.at(ii).meanIntensity; 04308 04309 /* 04310 if (DEBUG_MODE > 3) { 04311 printf("%s << test pt area = %f; test pt intensity = %f\n", __FUNCTION__, areaB, intensityB); 04312 waitKey(0); 04313 } 04314 */ 04315 04316 // Series of checks: 04317 04318 // Distance check 04319 if ((distBetweenPts(centroidA, centroidB) < maxDist) && (distBetweenPts(centroidA, centroidB) > minDist)) 04320 { 04321 // Intensity check 04322 if (abs(intensityA - intensityB) < intensityVar) 04323 { 04324 // Area check 04325 if (max(areaA/areaB, areaB/areaA) < (1 + areaVar)) 04326 { 04327 transferMserElement(newMsers, msers, ii); 04328 transferPatchElement(newPatches, patches, ii); 04329 } 04330 else 04331 { 04332 ii++; 04333 } 04334 } 04335 else 04336 { 04337 ii++; 04338 } 04339 } 04340 else 04341 { 04342 ii++; 04343 } 04344 } 04345 04346 jj++; 04347 ii = 0; 04348 } 04349 04350 if (DEBUG_MODE > 1) 04351 { 04352 printf("%s << Cluster Size = %d\n", __FUNCTION__, newMsers.size()); 04353 } 04354 04355 // Test 04356 if (newPatches.size() < ((unsigned int)totalPatches)) // if cluster has too few 04357 { 04358 if (patches.size() >= ((unsigned int)totalPatches)) // but remaining points are sufficient 04359 { 04360 newPatches.clear(); 04361 newMsers.clear(); 04362 04363 newPatches.push_back(patches.at(patches.size()-1)); 04364 patches.pop_back(); 04365 04366 newMsers.push_back(msers.at(msers.size()-1)); 04367 msers.pop_back(); 04368 04369 } 04370 else // and remaining points are insufficient 04371 { 04372 if (DEBUG_MODE > 1) 04373 { 04374 printf("%s << No cluster is large enough.\n", __FUNCTION__); 04375 04376 } 04377 return; 04378 } 04379 } 04380 else 04381 { 04382 clusterFound = true; 04383 if (DEBUG_MODE > 1) 04384 { 04385 printf("%s << Cluster found. size = %d.\n", __FUNCTION__, newPatches.size()); 04386 04387 } 04388 } 04389 04390 ii = 0; 04391 jj = 0; 04392 } 04393 04394 patches.clear(); 04395 msers.clear(); 04396 04397 for (unsigned int i = 0; i < newPatches.size(); i++) 04398 { 04399 patches.push_back(newPatches.at(i)); 04400 msers.push_back(newMsers.at(i)); 04401 } 04402 04403 } 04404 04405 void transferPatchElement(vector<mserPatch>& dst, vector<mserPatch>& src, int index) 04406 { 04407 // Move from old one to new one 04408 dst.push_back(src.at(index)); 04409 04410 // Replace point in old one with the end point 04411 src.at(index) = src.at(src.size()-1); 04412 04413 // Truncate the original vector (effectively discarding old point) 04414 src.pop_back(); 04415 } 04416 04417 void transferMserElement(vector<vector<Point> >& dst, vector<vector<Point> >& src, int index) 04418 { 04419 // Move from old one to new one 04420 dst.push_back(src.at(index)); 04421 04422 // Replace point in old one with the end point 04423 src.at(index) = src.at(src.size()-1); 04424 04425 // Truncate the original vector (effectively discarding old point) 04426 src.pop_back(); 04427 } 04428 04429 bool refinePatches(const Mat& image, Size patternSize, vector<vector<Point> >& msers, vector<Point2f>& patchCentres, int mode) 04430 { 04431 // TODO: 04432 // Lots of room for improvement here, in terms of both accuracy and speed. 04433 // For Mode 0: include white squares for as long as possible before applying the “colour” filter. 04434 // ensure that colour filter selects the darker of the two “modal” colours 04435 // (since a fair few will be white as well) 04436 // How about some kind of convex vs concave hull comparison? there shouldn't be much difference in area 04437 // between these two for a sold square MSER. 04438 // More specific "TODO"s are included throught this function. 04439 04440 int64 t = getTickCount(); 04441 04442 vector<mserPatch> patches; 04443 vector<vector<Point> > newMsers, newerMsers, tmpMsers; 04444 //int j = 0; 04445 //double area1, area2; 04446 vector<Point> hull; 04447 vector<Point> hull1, hull2; 04448 vector<Point> centroids; 04449 vector<Point> centroids2f; 04450 Moments moments1, moments2; 04451 //double x1c, y1c, x2c, y2c; 04452 Mat imCpy, dispMat; 04453 Scalar color(0, 0, 255); 04454 04455 int x = patternSize.width, y = patternSize.height; 04456 double Xdb = double(x)/2, Ydb = double(y)/2; 04457 int X = x/2, Y = y/2; 04458 int totalPatches; 04459 04460 if (mode == 0) 04461 { 04462 // Not fully tested or verified - check QCAT notebook for methodology 04463 totalPatches = int(floor(( 2*floor(Xdb)*floor(Ydb)+1+floor(Xdb)+floor(Ydb)+(ceil(Xdb)-floor(Xdb))*floor(Ydb)+(ceil(Ydb)-floor(Ydb))*floor(Xdb)+(ceil(Xdb)-floor(Xdb))*(ceil(Ydb)-floor(Ydb)) + 0.01))); 04464 } 04465 else if (mode == 1) 04466 { 04467 totalPatches = X*Y; 04468 } 04469 04470 04471 if (DEBUG_MODE > 1) 04472 { 04473 printf("%s << totalPatches = %d\n", __FUNCTION__, totalPatches); 04474 printf("%s << Patches found before refinement = %d\n", __FUNCTION__, msers.size()); 04475 } 04476 04477 04478 // Convert msers to mserPatches (including hulls) 04479 patches.clear(); 04480 for (unsigned int i = 0; i < msers.size(); i++) 04481 { 04482 patches.push_back(mserPatch(msers.at(i), image)); 04483 } 04484 04485 if (DEBUG_MODE > 3) 04486 { 04487 printf("%s << Patches found before filtering = %d\n", __FUNCTION__, msers.size()); 04488 04489 //color = Scalar(255, 255, 0); 04490 image.copyTo(imCpy); 04491 drawContours(imCpy, msers, -1, color, 2); 04492 imshow("mainWin", imCpy); 04493 waitKey(0); 04494 } 04495 04496 // ==============================SHAPE FILTER 04497 // TODO: 04498 // Improve height/width measurement so that it more accurately detects skinniness 04499 // (since angled, thin msers are still accepted at present) 04500 04501 // Other option is to create an arbitrary square contour and compare other contours with it using 04502 // that OpenCV function 04503 04504 t = getTickCount(); 04505 04506 shapeFilter(patches, msers); 04507 04508 if (DEBUG_MODE > 0) 04509 { 04510 t = getTickCount() - t; 04511 printf("%s << Shape Filter duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 04512 printf("%s << Patches found after shape filter = %d\n", __FUNCTION__, msers.size()); 04513 } 04514 04515 if (DEBUG_MODE > 6) 04516 { 04517 image.copyTo(imCpy); 04518 drawContours(imCpy, msers, -1, color, 2); 04519 imshow("mainWin", imCpy); 04520 waitKey(0); 04521 } 04522 04523 04524 // ==============================END OF SHAPE FILTER 04525 04526 // ==============================VARIANCE FILTER 04527 /* 04528 t = getTickCount(); 04529 04530 varianceFilter(patches, msers); 04531 04532 if (DEBUG_MODE > 6) 04533 { 04534 04535 //color = Scalar(255, 255, 0); 04536 image.copyTo(imCpy); 04537 drawContours(imCpy, msers, -1, color, 2); 04538 if (image.cols > 640) 04539 { 04540 resize(imCpy, dispMat, Size(0,0), 0.5, 0.5); 04541 imshow("mainWin", dispMat); 04542 } 04543 else 04544 { 04545 imshow("mainWin", imCpy); 04546 } 04547 waitKey(0); 04548 } 04549 04550 if (DEBUG_MODE > 0) 04551 { 04552 t = getTickCount() - t; 04553 printf("%s << Variance Filter duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 04554 printf("%s << Patches found after variance filter = %d\n", __FUNCTION__, msers.size()); 04555 } 04556 */ 04557 // ==============================END OF VARIANCE FILTER 04558 04559 // ==============================ENCLOSURE FILTER 04560 t = getTickCount(); 04561 04562 enclosureFilter(patches, msers); 04563 04564 // If you've lost too many, return a failure 04565 if (patches.size() < ((unsigned int)totalPatches)) 04566 { 04567 if (DEBUG_MODE > 1) 04568 { 04569 printf("There are an insufficient (%d/%d) number of patches after enclosure filter.\n", msers.size(), totalPatches); 04570 } 04571 return false; 04572 } 04573 04574 04575 if (DEBUG_MODE > 1) 04576 { 04577 printf("%s << Patches found after enclosure filter = %d\n", __FUNCTION__, msers.size()); 04578 } 04579 04580 if (DEBUG_MODE > 6) 04581 { 04582 image.copyTo(imCpy); 04583 color = Scalar(0, 255, 0); 04584 drawContours(imCpy, msers, -1, color, 2); 04585 imshow("mainWin", imCpy); 04586 waitKey(0); 04587 } 04588 04589 if (DEBUG_MODE > 0) 04590 { 04591 t = getTickCount() - t; 04592 printf("%s << Enclosure Filter duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 04593 } 04594 // ==============================END OF ENCLOSURE FILTER 04595 04596 04597 // ============================== 04598 // LOOPING FILTERS 04599 // ============================== 04600 //double minArea, maxArea, tmpArea; 04601 04602 int previousPatches = 9999; 04603 04604 // While the number of msers remaining is greater than the number you want 04605 // OR there has been no change since the previous cycle 04606 while ((msers.size() > ((unsigned int)totalPatches)) && (msers.size() < ((unsigned int)previousPatches))) 04607 { 04608 04609 if (DEBUG_MODE > 1) 04610 { 04611 printf("%s << Looping through filters again...\n", __FUNCTION__); 04612 } 04613 04614 previousPatches = msers.size(); 04615 04616 // ==============================CLUSTER FILTER 04617 t = getTickCount(); 04618 clusterFilter(patches, msers, totalPatches); 04619 04620 if (DEBUG_MODE > 1) 04621 { 04622 printf("%s << Patches found after cluster filter = %d\n", __FUNCTION__, msers.size()); 04623 } 04624 04625 if (DEBUG_MODE > 6) 04626 { 04627 //color = Scalar(0, 255, 0); 04628 image.copyTo(imCpy); 04629 drawContours(imCpy, msers, -1, color, 2); 04630 imshow("mainWin", imCpy); 04631 waitKey(0); 04632 } 04633 04634 // If the cluster was larger than m x n (probably (m x n)+1) 04635 if (patches.size() > ((unsigned int)totalPatches)) 04636 { 04637 reduceCluster(patches, msers, totalPatches); 04638 } 04639 04640 if (DEBUG_MODE > 1) 04641 { 04642 printf("%s << Patches remaining after area-based reduction = %d\n", __FUNCTION__, msers.size()); 04643 } 04644 04645 if (DEBUG_MODE > 6) 04646 { 04647 //color = Scalar(0, 255, 0); 04648 image.copyTo(imCpy); 04649 drawContours(imCpy, msers, -1, color, 2); 04650 if (image.cols > 640) 04651 { 04652 resize(imCpy, dispMat, Size(0,0), 0.5, 0.5); 04653 imshow("mainWin", dispMat); 04654 } 04655 else 04656 { 04657 imshow("mainWin", imCpy); 04658 } 04659 waitKey(0); 04660 } 04661 04662 if (DEBUG_MODE > 0) 04663 { 04664 t = getTickCount() - t; 04665 printf("%s << Cluster Filter duration: %fms\n", __FUNCTION__, t*1000/getTickFrequency()); 04666 } 04667 04668 04669 04670 // Anything else you can think of to remove outliers, if necessary 04671 04672 04673 } 04674 04675 if (DEBUG_MODE > 3) 04676 { 04677 color = Scalar(255, 0, 0); 04678 //image.copyTo(imCpy); 04679 drawContours(imCpy, msers, -1, color, 2); 04680 if (image.cols > 640) 04681 { 04682 resize(imCpy, dispMat, Size(0,0), 0.5, 0.5); 04683 imshow("mainWin", dispMat); 04684 } 04685 else 04686 { 04687 imshow("mainWin", imCpy); 04688 } 04689 waitKey(0); 04690 } 04691 04692 //bool acceptable = false; 04693 04694 if (int(msers.size()) == totalPatches) // if the correct number has now been found, clear the old set and add the new set 04695 { 04696 04697 // do some kind of check, to make sure that the last x*y/4 are truly a rectangular pattern 04698 if (DEBUG_MODE > 1) 04699 { 04700 printf("%s << Pattern believed to be found.\n", __FUNCTION__); 04701 } 04702 04703 04704 04705 // Assign patch centres 04706 for (unsigned int i = 0; i < patches.size(); i++) 04707 { 04708 patchCentres.push_back(patches.at(i).centroid2f); 04709 } 04710 04711 //acceptable = verifyPatches(image, patternSize, msers, patchCentres); 04712 //acceptable = verifyPatches(image.size(), patternSize, patchCentres, 0, 1000); 04713 04714 return true; 04715 } 04716 else if (msers.size() > ((unsigned int)totalPatches)) 04717 { 04718 if (DEBUG_MODE > 1) 04719 { 04720 printf("%s << Too many final patches = %d/%d\n", __FUNCTION__, msers.size(), totalPatches); 04721 } 04722 return false; 04723 } 04724 else 04725 { 04726 if (DEBUG_MODE > 1) 04727 { 04728 printf("%s << Too few final patches: %d/%d\n", __FUNCTION__, msers.size(), totalPatches); 04729 } 04730 return false; 04731 } 04732 }