00001
00005 #include "features.hpp"
00006
00007
00008 double calculateFeatureSpeeds(const vector<cv::Point2f>& pts1, const vector<cv::Point2f>& pts2, vector<cv::Point2f>& velocities, double time1, double time2) {
00009
00010 if ((pts1.size() != pts2.size()) || (pts1.size() == 0)) {
00011 printf("%s << ERROR! pts vectors are of sizes (%d, %d)\n", __FUNCTION__, pts1.size(), pts2.size());
00012 return 0.0;
00013 }
00014
00015 double avSpeed = 0.0;
00016
00017 for (unsigned int iii = 0; iii < pts1.size(); iii++) {
00018
00019 float vel_x = (pts2.at(iii).x - pts1.at(iii).x) / (time2 - time1);
00020 float vel_y = (pts2.at(iii).y - pts1.at(iii).y) / (time2 - time1);
00021
00022 velocities.push_back(cv::Point2f(vel_x, vel_y));
00023 avSpeed += pow((pow(vel_x, 2.0) + pow(vel_y, 2.0)), 0.5);
00024 }
00025
00026 avSpeed /= float(pts1.size());
00027
00028 return avSpeed;
00029
00030 }
00031
00032 double generateVirtualPointset(const vector<cv::Point2f>& pts1, const vector<cv::Point2f>& pts2, vector<cv::Point2f>& virtual_pts, double bias_fraction) {
00033
00034 if (pts1.size() != pts2.size()) {
00035 return -1.0;
00036 }
00037
00038 double totalMotion = 0.0;
00039
00040 for (unsigned int iii = 0; iii < pts1.size(); iii++) {
00041 cv::Point2f vpt;
00042
00043 totalMotion += pow(pow(pts1.at(iii).x - pts2.at(iii).x, 2.0)+pow(pts1.at(iii).y - pts2.at(iii).y, 2.0),0.5);
00044
00045 vpt.x = (1.0 - bias_fraction)*pts1.at(iii).x + (bias_fraction)*pts2.at(iii).x;
00046 vpt.y = (1.0 - bias_fraction)*pts1.at(iii).y + (bias_fraction)*pts2.at(iii).y;
00047
00048 virtual_pts.push_back(vpt);
00049
00050 }
00051
00052 totalMotion /= double(pts1.size());
00053
00054 return totalMotion;
00055
00056 }
00057
00058
00059
00060
00061 void drawRichKeyPoints(const cv::Mat& src, std::vector<cv::KeyPoint>& kpts, cv::Mat& dst) {
00062
00063 cv::Mat grayFrame;
00064 cvtColor(src, grayFrame, CV_RGB2GRAY);
00065
00066 dst = cv::Mat::zeros(src.size(), src.type());
00067
00068
00069 if (kpts.size() == 0) {
00070 return;
00071 }
00072
00073 std::vector<cv::KeyPoint> kpts_cpy, kpts_sorted;
00074
00075 kpts_cpy.insert(kpts_cpy.end(), kpts.begin(), kpts.end());
00076
00077 double maxResponse = kpts_cpy.at(0).response;
00078 double minResponse = kpts_cpy.at(0).response;
00079
00080 while (kpts_cpy.size() > 0) {
00081
00082 double maxR = 0.0;
00083 unsigned int idx = 0;
00084
00085 for (unsigned int iii = 0; iii < kpts_cpy.size(); iii++) {
00086
00087 if (kpts_cpy.at(iii).response > maxR) {
00088 maxR = kpts_cpy.at(iii).response;
00089 idx = iii;
00090 }
00091
00092 if (kpts_cpy.at(iii).response > maxResponse) {
00093 maxResponse = kpts_cpy.at(iii).response;
00094 }
00095
00096 if (kpts_cpy.at(iii).response < minResponse) {
00097 minResponse = kpts_cpy.at(iii).response;
00098 }
00099 }
00100
00101 kpts_sorted.push_back(kpts_cpy.at(idx));
00102 kpts_cpy.erase(kpts_cpy.begin() + idx);
00103
00104 }
00105
00106 int thickness = 1;
00107 cv::Point center;
00108 cv::Scalar colour;
00109 int red = 0, blue = 0, green = 0;
00110 int radius;
00111 double normalizedScore;
00112
00113 if (minResponse == maxResponse) {
00114 colour = CV_RGB(255, 0, 0);
00115 }
00116
00117 for (int iii = kpts_sorted.size()-1; iii >= 0; iii--) {
00118
00119 if (minResponse != maxResponse) {
00120 normalizedScore = pow((kpts_sorted.at(iii).response - minResponse) / (maxResponse - minResponse), 0.25);
00121 red = int(255.0 * normalizedScore);
00122 green = int(255.0 - 255.0 * normalizedScore);
00123 colour = CV_RGB(red, green, blue);
00124 }
00125
00126 center = kpts_sorted.at(iii).pt;
00127 center.x *= 16.0;
00128 center.y *= 16.0;
00129
00130 radius = 16.0 * (double(kpts_sorted.at(iii).size)/2.0);
00131
00132 if (radius > 0) {
00133 circle(dst, center, radius, colour, -1, CV_AA, 4);
00134 }
00135
00136 }
00137
00138 fadeImage(src, dst);
00139
00140
00141 for (int iii = kpts_sorted.size()-1; iii >= 0; iii--) {
00142
00143 if (minResponse != maxResponse) {
00144 normalizedScore = pow((kpts_sorted.at(iii).response - minResponse) / (maxResponse - minResponse), 0.25);
00145 red = int(255.0 * normalizedScore);
00146 green = int(255.0 - 255.0 * normalizedScore);
00147 colour = CV_RGB(red, green, blue);
00148 }
00149
00150 center = kpts_sorted.at(iii).pt;
00151 center.x *= 16.0;
00152 center.y *= 16.0;
00153
00154 radius = 16.0 * (double(kpts_sorted.at(iii).size)/2.0);
00155
00156 if (radius > 0) {
00157 circle(dst, center, radius, colour, thickness, CV_AA, 4);
00158 }
00159
00160 }
00161
00162
00163
00164 }
00165
00166 void fadeImage(const cv::Mat& src, cv::Mat& dst) {
00167
00168 double frac = 0.65;
00169
00170 #pragma omp parallel for
00171 for (int iii = 0; iii < src.rows; iii++) {
00172 for (int jjj = 0; jjj < src.cols; jjj++) {
00173
00174 if ((src.at<cv::Vec3b>(iii,jjj)[0] != 0) && (src.at<cv::Vec3b>(iii,jjj)[1] != 0) && (src.at<cv::Vec3b>(iii,jjj)[2] != 0)) {
00175 for (unsigned int kkk = 0; kkk < 3; kkk++) {
00176
00177
00178 dst.at<cv::Vec3b>(iii,jjj)[0] = (unsigned char) ((1-frac) * double(src.at<cv::Vec3b>(iii,jjj)[0]) + frac * double(dst.at<cv::Vec3b>(iii,jjj)[0])) / 1.0;
00179 dst.at<cv::Vec3b>(iii,jjj)[1] = (unsigned char) ((1-frac) * double(src.at<cv::Vec3b>(iii,jjj)[1]) + frac * double(dst.at<cv::Vec3b>(iii,jjj)[1])) / 1.0;
00180 dst.at<cv::Vec3b>(iii,jjj)[2] = (unsigned char) ((1-frac) * double(src.at<cv::Vec3b>(iii,jjj)[2]) + frac * double(dst.at<cv::Vec3b>(iii,jjj)[2])) / 1.0;
00181
00182 }
00183 } else {
00184 dst.at<cv::Vec3b>(iii,jjj)[0] = src.at<cv::Vec3b>(iii,jjj)[0];
00185 dst.at<cv::Vec3b>(iii,jjj)[1] = src.at<cv::Vec3b>(iii,jjj)[1];
00186 dst.at<cv::Vec3b>(iii,jjj)[2] = src.at<cv::Vec3b>(iii,jjj)[2];
00187 }
00188
00189
00190 }
00191 }
00192
00193
00194 }
00195
00196
00197
00198
00199 void filterKeyPoints(std::vector<cv::KeyPoint>& kpts, unsigned int maxSize, unsigned int maxFeatures) {
00200
00201 if (maxSize == 0) {
00202 return;
00203 }
00204
00205 sortKeyPoints(kpts);
00206
00207 for (unsigned int iii = 0; iii < kpts.size(); iii++) {
00208
00209 if (kpts.at(iii).size > float(maxSize)) {
00210 kpts.erase(kpts.begin() + iii);
00211 iii--;
00212 }
00213 }
00214
00215 if ((maxFeatures != 0) && (kpts.size() > maxFeatures)) {
00216 kpts.erase(kpts.begin()+maxFeatures, kpts.end());
00217 }
00218
00219 }
00220
00221 void showMatches(const cv::Mat& pim1, vector<cv::Point2f>& pts1, const cv::Mat& pim2, vector<cv::Point2f>& pts2, cv::Mat& drawImg) {
00222
00223 drawImg = cv::Mat::zeros(pim1.rows, pim1.cols + pim2.cols, CV_8UC3);
00224
00225 #pragma omp parallel for
00226 for (int iii = 0; iii < pim1.rows; iii++) {
00227 for (int jjj = 0; jjj < pim1.cols; jjj++) {
00228
00229 drawImg.at<cv::Vec3b>(iii,jjj)[0] = pim1.at<unsigned char>(iii,jjj);
00230 drawImg.at<cv::Vec3b>(iii,jjj)[1] = pim1.at<unsigned char>(iii,jjj);
00231 drawImg.at<cv::Vec3b>(iii,jjj)[2] = pim1.at<unsigned char>(iii,jjj);
00232
00233 drawImg.at<cv::Vec3b>(iii,640+jjj)[0] = pim2.at<unsigned char>(iii,jjj);
00234 drawImg.at<cv::Vec3b>(iii,640+jjj)[1] = pim2.at<unsigned char>(iii,jjj);
00235 drawImg.at<cv::Vec3b>(iii,640+jjj)[2] = pim2.at<unsigned char>(iii,jjj);
00236 }
00237 }
00238
00239 cv::Point pt1, pt2;
00240 int radius = 4;
00241 int thickness = 1;
00242
00243 radius *= 16.0;
00244 for (unsigned int iii = 0; iii < pts1.size(); iii++) {
00245
00246 pt1.x = 16.0 * pts1.at(iii).x;
00247 pt1.y = 16.0 * pts1.at(iii).y;
00248
00249 pt2.x = 16.0 * (pts2.at(iii).x + 640.0);
00250 pt2.y = 16.0 * pts2.at(iii).y;
00251
00252 circle(drawImg, pt1, radius, CV_RGB(255, 0, 0), thickness, CV_AA, 4);
00253 circle(drawImg, pt2, radius, CV_RGB(255, 0, 0), thickness, CV_AA, 4);
00254 line(drawImg, pt1, pt2, CV_RGB(0, 0, 255), thickness, CV_AA, 4);
00255 }
00256
00257 }
00258
00259 void crossCheckMatching( cv::Ptr<cv::DescriptorMatcher>& descriptorMatcher,
00260 const cv::Mat& descriptors1, const cv::Mat& descriptors2,
00261 vector<cv::DMatch>& filteredMatches12, int knn )
00262 {
00263
00264
00265
00266 filteredMatches12.clear();
00267
00268
00269
00270 vector<vector<cv::DMatch> > matches12, matches21;
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 descriptorMatcher->knnMatch( descriptors1, descriptors2, matches12, knn );
00281
00282
00283
00284 descriptorMatcher->knnMatch( descriptors2, descriptors1, matches21, knn );
00285
00286
00287
00288 for( size_t m = 0; m < matches12.size(); m++ )
00289 {
00290 bool findCrossCheck = false;
00291
00292
00293
00294 for( size_t fk = 0; fk < matches12[m].size(); fk++ )
00295 {
00296 cv::DMatch forward = matches12[m][fk];
00297
00298
00299
00300 for( size_t bk = 0; bk < matches21[forward.trainIdx].size(); bk++ )
00301 {
00302 cv::DMatch backward = matches21[forward.trainIdx][bk];
00303 if( backward.trainIdx == forward.queryIdx )
00304 {
00305 filteredMatches12.push_back(forward);
00306 findCrossCheck = true;
00307 break;
00308 }
00309 }
00310 if( findCrossCheck ) break;
00311 }
00312 }
00313
00314 }
00315
00316 void filterTrackingsByRadialProportion(vector<cv::Point2f>& pts1, vector<cv::Point2f>& pts2, cv::Mat& K, cv::Mat& newCamMat, cv::Mat& distCoeffs, cv::Size& imSize, double prop) {
00317
00318
00319 vector<cv::Point2f> newPts;
00320 redistortPoints(pts2, newPts, K, distCoeffs, newCamMat);
00321
00322 cv::Point2f centrePt = cv::Point2f(double(imSize.width)/2.0,double(imSize.height)/2.0);
00323 double maxDist = prop * double(imSize.width)/2.0;
00324
00325 double dist;
00326
00327 unsigned int iii = 0;
00328
00329 while (iii < pts1.size()) {
00330
00331 dist = distBetweenPts2f(pts2.at(iii), centrePt);
00332
00333 if (dist > maxDist) {
00334
00335 pts1.erase(pts1.begin() + iii);
00336 pts2.erase(pts2.begin() + iii);
00337
00338 } else {
00339 iii++;
00340 }
00341
00342 }
00343
00344
00345 }
00346
00347 void reduceEdgyFeatures(vector<cv::KeyPoint>& KeyPoints, cameraParameters& camData) {
00348
00349 vector<cv::Point2f> candidates;
00350
00351 cv::KeyPoint::convert(KeyPoints, candidates);
00352
00353 vector<cv::Point2f> redistortedPoints;
00354 float minBorderDist = 2.0;
00355
00356 redistortPoints(candidates, redistortedPoints, camData.Kx, camData.distCoeffs, camData.expandedCamMat);
00357
00358 for (int iii = candidates.size()-1; iii >= 0; iii--) {
00359
00360 float xDist = min(abs(((float) camData.expandedSize.width) - redistortedPoints.at(iii).x), abs(redistortedPoints.at(iii).x));
00361 float yDist = min(abs(((float) camData.expandedSize.height) - redistortedPoints.at(iii).y), abs(redistortedPoints.at(iii).y));
00362 float dist = min(xDist, yDist) - KeyPoints.at(iii).size;
00363
00364 if (dist < minBorderDist) {
00365 KeyPoints.erase(KeyPoints.begin() + iii);
00366 }
00367
00368 }
00369
00370 }
00371
00372 void reduceEdgyCandidates(vector<cv::Point2f>& candidates, cameraParameters& camData) {
00373
00374 vector<cv::Point2f> redistortedPoints;
00375 float minBorderDist = 2.0;
00376
00377 redistortPoints(candidates, redistortedPoints, camData.Kx, camData.distCoeffs, camData.expandedCamMat);
00378
00379 for (int iii = candidates.size()-1; iii >= 0; iii--) {
00380
00381 float xDist = min(abs(((float) camData.expandedSize.width) - redistortedPoints.at(iii).x), abs(redistortedPoints.at(iii).x));
00382 float yDist = min(abs(((float) camData.expandedSize.height) - redistortedPoints.at(iii).y), abs(redistortedPoints.at(iii).y));
00383 float dist = min(xDist, yDist);
00384 if (dist < minBorderDist) {
00385 candidates.erase(candidates.begin() + iii);
00386 }
00387
00388 }
00389
00390 }
00391
00392 bool checkRoomForFeature(vector<cv::Point2f>& pts, cv::Point2f& candidate, double dist) {
00393
00394 double distance;
00395
00396 for (unsigned int iii = 0; iii < pts.size(); iii++) {
00397
00398 distance = distanceBetweenPoints(pts.at(iii), candidate);
00399
00400 if (distance < dist) {
00401 return false;
00402 }
00403
00404 }
00405
00406 return true;
00407
00408 }
00409
00410 void reduceUnrefinedCandidates(vector<cv::Point2f>& candidates) {
00411
00412 if (candidates.size() == 0) {
00413 return;
00414 }
00415
00416 for (int iii = candidates.size()-1; iii >= 0; iii--) {
00417
00418 if (((candidates.at(iii).x - floor(candidates.at(iii).x)) == 0.0) && ((candidates.at(iii).y - floor(candidates.at(iii).y)) == 0.0)) {
00419 printf("%s << erasing: (%f, %f)\n", __FUNCTION__, candidates.at(iii).x, candidates.at(iii).y);
00420 candidates.erase(candidates.begin() + iii);
00421 }
00422 }
00423
00424 }
00425
00426 void reduceProximalCandidates(vector<cv::Point2f>& existing, vector<cv::Point2f>& candidates) {
00427
00428 for (unsigned int iii = 0; iii < candidates.size(); iii++) {
00429
00430 bool isValid = checkRoomForFeature(existing, candidates.at(iii), 3.0);
00431
00432 if (!isValid) {
00433 candidates.erase(candidates.begin() + iii);
00434 iii--;
00435 }
00436
00437 }
00438
00439 }
00440
00441 void concatenateWithExistingPoints(vector<cv::Point2f>& pts, vector<cv::Point2f>& kps, int size, double min_sep, bool debug) {
00442
00443
00444 for (unsigned int iii = 0; iii < kps.size(); iii++) {
00445
00446 if (pts.size() >= size) {
00447 break;
00448 }
00449
00450 bool isValid = checkRoomForFeature(pts, kps.at(iii), min_sep);
00451
00452 if (!isValid) {
00453 kps.erase(kps.begin()+iii);
00454 iii--;
00455 } else {
00456 if (debug) { printf("%s << a valid point!!!!!!!\n", __FUNCTION__); }
00457 pts.push_back(kps.at(iii));
00458 }
00459
00460
00461
00462 }
00463
00464 }
00465
00466 void initializeDrawingColors(cv::Scalar* kColors, cv::Scalar* tColors, int num) {
00467
00468 for (int iii = 0; iii < num; iii++) {
00469 switch (iii) {
00470 case 0:
00471 tColors[iii] = CV_RGB(255, 128, 128);
00472 kColors[iii] = CV_RGB(255, 0, 0);
00473 break;
00474 case 1:
00475 tColors[iii] = CV_RGB(128, 128, 255);
00476 kColors[iii] = CV_RGB(0, 0, 255);
00477 break;
00478 case 2:
00479 tColors[iii] = CV_RGB(128, 255, 128);
00480 kColors[iii] = CV_RGB(0, 255, 0);
00481 break;
00482 case 3:
00483 tColors[iii] = CV_RGB(128, 255, 255);
00484 kColors[iii] = CV_RGB(0, 255, 255);
00485 break;
00486 case 4:
00487 tColors[iii] = CV_RGB(128, 128, 255);
00488 kColors[iii] = CV_RGB(255, 0, 255);
00489 break;
00490 case 5:
00491 tColors[iii] = CV_RGB(255, 255, 128);
00492 kColors[iii] = CV_RGB(255, 255, 0);
00493 break;
00494 default:
00495 tColors[iii] = CV_RGB(128, 128, 255);
00496 kColors[iii] = CV_RGB(255, 255, 255);
00497 break;
00498
00499 }
00500 }
00501
00502 }
00503
00504 void transformPoints(vector<cv::Point2f>& pts1, cv::Mat& H) {
00505 cv::Mat ptCol(3, 1, CV_64FC1), newPos(3, 1, CV_64FC1);
00506
00507
00508
00509
00510 for (unsigned int mmm = 0; mmm < pts1.size(); mmm++) {
00511
00512 ptCol.at<double>(0,0) = pts1.at(mmm).x;
00513 ptCol.at<double>(1,0) = pts1.at(mmm).y;
00514 ptCol.at<double>(2,0) = 1.0;
00515
00516 newPos = H * ptCol;
00517
00518
00519
00520 pts1.at(mmm).x = ((float) newPos.at<double>(0,0) / newPos.at<double>(2,0));
00521 pts1.at(mmm).y = ((float) newPos.at<double>(1,0) / newPos.at<double>(2,0));
00522
00523 }
00524 }
00525
00526 void reduceWeakFeatures(cv::Mat& im, vector<cv::KeyPoint>& feats, double minResponse) {
00527
00528
00529
00530 vector<float> responseLevels;
00531
00532 for (unsigned int iii = 0; iii < feats.size(); iii++) {
00533
00534 if (feats.at(iii).response == 0.0) {
00535 feats.at(iii).response = estimateSalience(im, feats.at(iii).pt, ((double) feats.at(iii).size / 2.0));
00536 responseLevels.push_back(feats.at(iii).response);
00537 }
00538
00539
00540
00541 }
00542
00543 sort(responseLevels.begin(), responseLevels.end());
00544
00545
00546
00547
00548
00549 for (int iii = feats.size()-1; iii >= 0; iii--) {
00550
00551
00552 if (feats.at(iii).response < minResponse) {
00553 feats.erase(feats.begin() + iii);
00554 }
00555
00556
00557 }
00558
00559 }
00560
00561 void trackPoints(const cv::Mat& im1, const cv::Mat& im2, vector<cv::Point2f>& pts1, vector<cv::Point2f>& pts2, int distanceConstraint, double thresh, vector<unsigned int>& lostIndices, cv::Mat H12, cameraParameters camData) {
00562
00563
00564
00565
00566 vector<cv::Point2f> originalGuides;
00567
00568
00569 bool debugFlag = false;
00570
00571 if (debugFlag) { printf("%s << ENTERED. im1 = (%u, %u); im2 = (%u, %u), pts1 = (%lu), pts2 = (%lu)\n", __FUNCTION__, im1.cols, im1.rows, im2.cols, im2.rows, pts1.size(), pts2.size()); }
00572
00573
00574
00575
00576 if (pts1.size() == 0) {
00577 return;
00578 }
00579
00580 if ((distanceConstraint % 2) == 0) {
00581 distanceConstraint++;
00582 }
00583
00584
00585
00586
00587 cv::Size winSize = cv::Size(distanceConstraint, distanceConstraint);
00588 int maxLevel = 3;
00589 cv::TermCriteria criteria = cv::TermCriteria( cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 30, 0.01);
00590
00591 int opticalFlowFlags = CV_LKFLOW_GET_MIN_EIGENVALS;
00592
00593 bool guiding = false;
00594 bool warping = false;
00595
00596 cv::Mat im1b;
00597 vector<cv::Point2f> pts1b;
00598
00599 vector<uchar> statusVec;
00600 vector<float> err;
00601
00602 cv::Mat mask, blank;
00603 blank = cv::Mat::ones(im1.size(), CV_8UC1);
00604 blank *= 255;
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 4); }
00622
00623
00624
00625 vector<cv::Point2f> originalPts, originalEstimates;
00626 originalPts.insert(originalPts.end(), pts1.begin(), pts1.end());
00627 originalEstimates.insert(originalEstimates.end(), pts2.begin(), pts2.end());
00628
00629
00630
00631
00632 if (pts2.size() == pts1.size()) {
00633 if (debugFlag) { printf("%s << guiding is set to TRUE.\n", __FUNCTION__); }
00634 guiding = true;
00635
00636 originalGuides.insert(originalGuides.end(), pts2.begin(), pts2.end());
00637 opticalFlowFlags += cv::OPTFLOW_USE_INITIAL_FLOW;
00638 } else {
00639 if (debugFlag) { printf("%s << guiding is maintained as FALSE.\n", __FUNCTION__); }
00640 }
00641
00642 if ((H12.rows != 0) && (pts2.size() == pts1.size())) {
00643
00644
00645
00646
00647
00648
00649
00650
00651 warping = true;
00652
00653
00654
00655
00656
00657 pts1b.insert(pts1b.end(), pts1.begin(), pts1.end());
00658 transformPoints(pts1b, H12);
00659 warpPerspective(im1, im1b, H12, im1.size());
00660
00661
00662
00663 warpPerspective(blank, mask, H12, blank.size());
00664
00665
00666 } else {
00667
00668
00669
00670
00671
00672
00673
00674 im1b = cv::Mat(im1);
00675
00676
00677
00678
00679
00680
00681 if (!guiding) {
00682 if (debugFlag) { printf("%s << Clearing second points vector...\n", __FUNCTION__); }
00683 pts2.clear();
00684 }
00685 }
00686
00687 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 5); }
00688
00689
00690
00691
00692 if (warping) {
00693 if (debugFlag) { printf("%s << (warped) Before. (%u, %u) (%u, %u) (%lu) (%u, %u)\n", __FUNCTION__, im1b.rows, im1b.cols, im2.rows, im2.cols, pts1b.size(), winSize.height, winSize.width); }
00694 cv::calcOpticalFlowPyrLK(im1b, im2, pts1b, pts2, statusVec, err, winSize, maxLevel, criteria, opticalFlowFlags, thresh);
00695 checkDistances(originalEstimates, pts2, statusVec, (double) distanceConstraint);
00696 if (debugFlag) { printf("%s << After.\n", __FUNCTION__); }
00697 markAbsentPoints(pts1b, pts2, statusVec, im1.size());
00698 } else {
00699 if (debugFlag) { printf("%s << (not-warped) Before. (%u, %u) (%u, %u) (%lu) (%u, %u)\n", __FUNCTION__, im1b.rows, im1b.cols, im2.rows, im2.cols, pts1.size(), winSize.height, winSize.width); }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719 cv::calcOpticalFlowPyrLK(im1b, im2, pts1, pts2, statusVec, err, winSize, maxLevel, criteria, opticalFlowFlags, thresh);
00720 checkDistances(originalEstimates, pts2, statusVec, (double) distanceConstraint);
00721 if (debugFlag) { printf("%s << After.\n", __FUNCTION__); }
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747 if (debugFlag) {
00748
00749 printf("%s << winSize = (%d, %d)\n", __FUNCTION__, winSize.width, winSize.height);
00750
00751 cv::Mat a, b;
00752
00753 displayKeyPoints(im2, pts1, a, CV_RGB(255,0,0), 0);
00754 displayKeyPoints(im2, pts2, b, CV_RGB(0,0,255), 0);
00755
00756 if (1) {
00757
00758 imshow("test1", a);
00759 cv::waitKey(1);
00760 imshow("test2", b);
00761 cv::waitKey(1);
00762
00763 printf("%s << After flow: %d good out of / %lu\n", __FUNCTION__, cv::countNonZero(statusVec), statusVec.size());
00764 }
00765
00766
00767
00768
00769
00770
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784 markAbsentPoints(pts1, pts2, statusVec, im1.size());
00785
00786 if (debugFlag) {
00787 printf("%s << After absent: %d\n", __FUNCTION__, cv::countNonZero(statusVec));
00788 }
00789
00790
00791 }
00792
00793 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 6); }
00794
00795
00796
00797
00798
00799 if (camData.Kx.rows != 0) {
00800 markEdgyTracks(pts2, statusVec, camData);
00801
00802
00803 }
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 7); }
00820
00821 if (warping) {
00822 if (debugFlag) { printf("%s << W: pts1.size() = %u [before filtering]\n", __FUNCTION__, pts1.size()); }
00823 if (debugFlag) { printf("%s << Debug (%d.%d) : (%u, %u)\n", __FUNCTION__, 7, 1, pts1.size(), pts2.size()); }
00824 filterVectors(pts1, pts2, statusVec, ((double) std::max(im1.rows, im1.cols)), true);
00825 if (debugFlag) { printf("%s << Debug (%d.%d)\n", __FUNCTION__, 7, 2); }
00826
00827 if (debugFlag) { printf("%s << Debug (%d.%d)\n", __FUNCTION__, 7, 2); }
00828
00829 if (0) {
00830
00831 cv::Mat im1x, im2x;
00832
00833
00834 im1.copyTo(im1x);
00835 im2.copyTo(im2x);
00836
00837 displayKeyPoints(im1, pts1, im1x, CV_RGB(255,0,0), 0);
00838 displayKeyPoints(im2x, pts2, im2x, CV_RGB(255,0,0), 0);
00839
00840
00841
00842 while (1) {
00843
00844 imshow("temp_disp", im1x);
00845 cv::waitKey(500);
00846 imshow("temp_disp", im2x);
00847 cv::waitKey(500);
00848
00849 }
00850 }
00851 } else {
00852 if (debugFlag) { printf("%s << pts1.size() = %u [before filtering]\n", __FUNCTION__, pts1.size()); }
00853
00854 if (debugFlag) { printf("%s << Debug (%d.%d)\n", __FUNCTION__, 7, 3); }
00855
00856 if (guiding) {
00857 filterVectors(pts1, pts2, statusVec, ((double) std::max(im1.rows, im1.cols)), true);
00858 } else {
00859 filterVectors(pts1, pts2, statusVec, ((double) distanceConstraint));
00860 }
00861
00862 if (debugFlag) { printf("%s << Debug (%d.%d)\n", __FUNCTION__, 7, 4); }
00863 if (debugFlag) { printf("%s << pts1.size() = %d [after filtering]\n", __FUNCTION__, pts1.size()); }
00864
00865 if (debugFlag) { printf("%s << Debug (%d.%d)\n", __FUNCTION__, 7, 4); }
00866
00867
00868
00869 if (0) {
00870
00871 cv::Mat im1x, im2x;
00872
00873
00874 cvtColor(im1b, im1x, CV_GRAY2RGB);
00875 cvtColor(im2, im2x, CV_GRAY2RGB);
00876
00877 displayKeyPoints(im1x, originalPts, im1x, CV_RGB(255,0,0), 0);
00878 displayKeyPoints(im2x, pts2, im2x, CV_RGB(255,0,0), 0);
00879
00880
00881
00882 while (1) {
00883
00884 imshow("temp_disp", im1b);
00885 cv::waitKey(1500);
00886 imshow("temp_disp", im2x);
00887 cv::waitKey(500);
00888
00889 }
00890 }
00891
00892 }
00893
00894 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 8); }
00895
00896
00897
00898
00899 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
00900 if (statusVec.at(iii) == 0) {
00901 lostIndices.push_back(iii);
00902 }
00903 }
00904
00905 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 9); }
00906
00907
00908
00909
00910 }
00911
00912
00913 void trackPoints2(const cv::Mat& im1, const cv::Mat& im2, vector<cv::Point2f>& pts1, vector<cv::Point2f>& pts2, int distanceConstraint, double thresh, vector<unsigned int>& lostIndices, const cv::Size patternSize, double& errorThreshold) {
00914
00915
00916 unsigned int corners = patternSize.width * patternSize.height;
00917
00918 bool debugFlag = false;
00919
00920 if (debugFlag) {
00921 printf("%s << ENTERED!\n", __FUNCTION__);
00922 }
00923
00924 if (pts1.size() == 0) {
00925 return;
00926 }
00927
00928 if ((distanceConstraint % 2) == 0) {
00929 distanceConstraint++;
00930 }
00931
00932 cv::Size winSize = cv::Size(distanceConstraint, distanceConstraint);
00933 int maxLevel = 3;
00934 cv::TermCriteria criteria = cv::TermCriteria( cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 30, 0.01);
00935
00936 cv::Mat im1b;
00937 cv::Mat blank;
00938
00939 vector<uchar> statusVec;
00940 vector<float> err;
00941
00942 blank = cv::Mat::ones(im1.size(), CV_8UC1);
00943 blank *= 255;
00944
00945
00946 vector<cv::Point2f> originalPts;
00947 originalPts.insert(originalPts.end(), pts1.begin(), pts1.end());
00948
00949 im1b = cv::Mat(im1);
00950
00951 pts2.clear();
00952 pts2.insert(pts2.end(), pts1.begin(), pts1.end());
00953
00954 int opticalFlowFlags = cv::OPTFLOW_USE_INITIAL_FLOW + CV_LKFLOW_GET_MIN_EIGENVALS;
00955
00956
00957 cv::calcOpticalFlowPyrLK(im1b, im2, pts1, pts2, statusVec, err, winSize, maxLevel, criteria, opticalFlowFlags, thresh);
00958
00959 if (corners != statusVec.size() || corners != err.size()){
00960 lostIndices.push_back(-1);
00961 }
00962
00963
00964 for (unsigned int iii = 0; iii < err.size(); iii++) {
00965
00966 if (err.at(iii) > errorThreshold && errorThreshold != 0.0){
00967
00968 lostIndices.push_back(-2);
00969 }
00970 }
00971
00972 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
00973 if (statusVec.at(iii) == 0) {
00974 lostIndices.push_back(iii);
00975 }
00976 }
00977
00978
00979 }
00980
00981 void markAbsentPoints(vector<cv::Point2f>&pts1, vector<cv::Point2f>&pts2, vector<uchar>&statusVec, cv::Size imSize) {
00982
00983 float buffer = 2.0;
00984
00985 #pragma omp parallel for
00986 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
00987
00988 if (statusVec.at(iii) != 0) {
00989
00990 if ((pts1.at(iii).x < buffer) || (pts1.at(iii).x > imSize.width - buffer)) {
00991 statusVec.at(iii) = 0;
00992 } else if ((pts2.at(iii).x < buffer) || (pts2.at(iii).x > imSize.width - buffer)) {
00993 statusVec.at(iii) = 0;
00994 } else if ((pts1.at(iii).y < buffer) || (pts1.at(iii).y > imSize.height - buffer)) {
00995 statusVec.at(iii) = 0;
00996 } else if ((pts2.at(iii).y < buffer) || (pts2.at(iii).y > imSize.height - buffer)) {
00997 statusVec.at(iii) = 0;
00998 }
00999
01000 }
01001
01002 }
01003
01004 }
01005
01006 bool constructPatch(cv::Mat& img, cv::Mat& patch, cv::Point2f& center, double radius, int cells) {
01007
01008
01009
01010 patch.release();
01011
01012 if ((cells % 2) == 0) {
01013 cells++;
01014 }
01015
01016 patch = cv::Mat::zeros(cells, cells, CV_64FC1);
01017
01018 int range = (cells-1)/2;
01019
01020 for (int iii = -range; iii <= +range; iii++) {
01021 for (int jjj = -range; jjj <= +range; jjj++) {
01022
01023 cv::Point2f currPt = cv::Point2f(center.x + ((double) iii)*radius, center.y + ((double) jjj)*radius);
01024
01025
01026
01027 if ((currPt.x <= 0.0) || (currPt.x >= ((double) img.cols)) || (currPt.y >= ((double) img.rows)) || (currPt.y <= 0.0)) {
01028 return false;
01029 }
01030
01031
01032 double val = getInterpolatedVal(img, currPt);
01033
01034 patch.at<double>(iii+range,jjj+range) = val;
01035
01036 }
01037 }
01038
01039
01040
01041 return true;
01042
01043 }
01044
01045
01046 void extendKeyPoints(cv::Mat& img, vector<cv::KeyPoint>& pts, bool updateStrength, bool updateLocation) {
01047
01048 if (updateLocation) {
01049
01050
01051 vector<cv::Point2f> candidates;
01052 cv::KeyPoint::convert(pts, candidates);
01053
01054 cv::cornerSubPix(img, candidates, cv::Size(1,1), cv::Size(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1));
01055
01056 #pragma omp parallel for
01057 for (unsigned int iii = 0; iii < candidates.size(); iii++) {
01058 pts.at(iii).pt = candidates.at(iii);
01059 }
01060
01061 }
01062
01063 if (updateStrength) {
01064
01065
01066 #pragma omp parallel for
01067 for (unsigned int iii = 0; iii < pts.size(); iii++) {
01068 double radius = ((double) pts.at(iii).size) / 2.0;
01069 double salience = estimateSalience(img, pts.at(iii).pt, radius);
01070 pts.at(iii).response = salience;
01071 }
01072
01073 }
01074
01075 }
01076
01077 double estimateSalience(cv::Mat& img, cv::Point2f& center, double radius) {
01078
01079
01080 double salience = 0.0;
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 if (((center.x - radius) < 0) || ((center.y - radius) < 0) || ((center.x + radius) >= img.cols) || ((center.y + radius) >= img.rows)) {
01091 return salience;
01092 }
01093
01094 cv::Mat patch;
01095 int patchSize = radius * 2;
01096 if ((patchSize % 2) == 0) {
01097
01098 }
01099
01100 constructPatch(img, patch, center, radius, patchSize);
01101
01102
01103 salience = getValueFromPatch(patch);
01104
01105
01106 return salience;
01107
01108 }
01109
01110 double getValueFromPatch(cv::Mat& patch) {
01111
01112 cv::Mat convertedPatch = cv::Mat::zeros(patch.size(), CV_32FC1);
01113
01114 #pragma omp parallel for
01115 for (int iii = 0; iii < patch.rows; iii++) {
01116 for (int jjj = 0; jjj < patch.cols; jjj++) {
01117 convertedPatch.at<float>(iii,jjj) = ((float) patch.at<double>(iii,jjj));
01118 }
01119 }
01120
01121 cv::Mat eigenMat;
01122 cornerMinEigenVal(convertedPatch, eigenMat, patch.rows, CV_SCHARR);
01123
01124 double eigenValue = 0.0, blankVal;
01125
01126 minMaxLoc(eigenMat, &blankVal, &eigenValue);
01127
01128
01129
01130
01131
01132
01133
01134
01135 return eigenValue;
01136
01137 }
01138
01139 void markUnrefinedPoints(vector<cv::Point2f>& pts, vector<uchar>&statusVec) {
01140
01141 if (pts.size() == 0) {
01142 return;
01143 }
01144
01145 #pragma omp parallel for
01146 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
01147
01148 if (statusVec.at(iii) != 0) {
01149
01150 if (((pts.at(iii).x - floor(pts.at(iii).x)) == 0.0) && ((pts.at(iii).y - floor(pts.at(iii).y)) == 0.0)) {
01151 statusVec.at(iii) = 0;
01152 }
01153
01154 }
01155 }
01156
01157 }
01158
01159
01160 void markBlandTracks(cv::Mat& img, vector<cv::Point2f>& pts, vector<uchar>& statusVec, double thresh) {
01161
01162 if (pts.size() == 0) {
01163 return;
01164 }
01165
01166 cv::Mat patch;
01167
01168 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
01169
01170 if (statusVec.at(iii) != 0) {
01171
01172 constructPatch(img, patch, pts.at(iii), 1.5);
01173
01174
01175 double salience = getValueFromPatch(patch);
01176
01177
01178
01179 if (salience < thresh) {
01180 statusVec.at(iii) = 0;
01181 }
01182
01183
01184 }
01185 }
01186
01187
01188 }
01189
01190 void filterBlandKeyPoints(cv::Mat& img, vector<cv::KeyPoint>& pts, double thresh) {
01191
01192 if (pts.size() == 0) {
01193 return;
01194 }
01195
01196 for (int iii = pts.size()-1; iii >= 0; iii--) {
01197
01198
01199
01200 if (pts.at(iii).response < thresh) {
01201 pts.erase(pts.begin() + iii);
01202 }
01203
01204 }
01205
01206 }
01207
01208 void markStationaryPoints(vector<cv::Point2f>&pts1, vector<cv::Point2f>&pts2, vector<uchar>&statusVec) {
01209
01210 #pragma omp parallel for
01211 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
01212
01213 if (statusVec.at(iii) != 0) {
01214
01215 double absDifference = pow(pow(pts1.at(iii).x - pts2.at(iii).x, 2.0) + pow(pts1.at(iii).y - pts2.at(iii).y, 2.0), 0.5);
01216
01217
01218
01219 if (absDifference == 0.0) {
01220 statusVec.at(iii) = 0;
01221 }
01222
01223 }
01224 }
01225
01226 }
01227
01228 void displayKeyPoints(const cv::Mat& image, const vector<cv::KeyPoint>& KeyPoints, cv::Mat& outImg, const cv::Scalar& color, int thickness, bool pointsOnly) {
01229
01230 bool randomColours = (color == cv::Scalar::all(-1));
01231
01232 cv::Scalar newColour;
01233
01234 if (!randomColours) {
01235 newColour = color;
01236 }
01237
01238 image.copyTo(outImg);
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253 cv::Point centerPt;
01254
01255 int radius, crossLength;
01256
01257 if (thickness == 0) {
01258 thickness = 1;
01259 }
01260
01261
01262 for (unsigned int i = 0; i < KeyPoints.size(); i++) {
01263
01264
01265
01266
01267 newColour = color;
01268
01269
01270
01271 centerPt = KeyPoints.at(i).pt;
01272
01273 centerPt.x *= 16.0;
01274 centerPt.y *=16.0;
01275
01276
01277
01278
01279
01280
01281
01282 radius = 16.0 * (KeyPoints.at(i).size/2.0);
01283
01284
01285 crossLength = 2 * 16.0;
01286
01287 if (pointsOnly) {
01288 circle(outImg, centerPt, 1, newColour, 2, CV_AA, 4);
01289 } else {
01290 if (radius > 0) {
01291 circle(outImg, centerPt, radius, newColour, thickness, CV_AA, 4);
01292 }
01293
01294 line(outImg, cv::Point(centerPt.x-crossLength, centerPt.y), cv::Point(centerPt.x+crossLength, centerPt.y), newColour, thickness, CV_AA, 4);
01295 line(outImg, cv::Point(centerPt.x, centerPt.y-crossLength), cv::Point(centerPt.x, centerPt.y+crossLength), newColour, thickness, CV_AA, 4);
01296
01297 }
01298
01299
01300
01301
01302
01303
01304
01305
01306 }
01307
01308 return;
01309
01310 }
01311
01312 void displayKeyPoints(const cv::Mat& image, const vector<cv::Point2f>& pts, cv::Mat& outImg, cv::Scalar color, int thickness, bool pointsOnly) {
01313
01314 bool randomColours = (color == cv::Scalar::all(-1));
01315
01316 cv::Scalar newColour;
01317
01318 if (!randomColours) {
01319 newColour = color;
01320 }
01321
01322 image.copyTo(outImg);
01323
01324 cv::Point centerPt;
01325
01326 if (thickness == 0) {
01327 thickness = 1;
01328 }
01329
01330 int crossLength;
01331
01332
01333 for (unsigned int i = 0; i < pts.size(); i++) {
01334
01335 centerPt.x = pts.at(i).x * 16.0;
01336 centerPt.y = pts.at(i).y * 16.0;
01337
01338
01339 crossLength = 2 * 16.0;
01340
01341 if (pointsOnly) {
01342 circle(outImg, centerPt, 1, color, 2, CV_AA, 4);
01343 } else {
01344 line(outImg, cv::Point(centerPt.x-crossLength, centerPt.y), cv::Point(centerPt.x+crossLength, centerPt.y), color, thickness, CV_AA, 4);
01345 line(outImg, cv::Point(centerPt.x, centerPt.y-crossLength), cv::Point(centerPt.x, centerPt.y+crossLength), color, thickness, CV_AA, 4);
01346 }
01347
01348
01349
01350
01351 }
01352
01353 return;
01354
01355 }
01356
01357 void sortKeyPoints(vector<cv::KeyPoint>& KeyPoints, unsigned int maxKeyPoints) {
01358 vector<cv::KeyPoint> sortedKeyPoints;
01359
01360 if (KeyPoints.size() <= 1) {
01361 return;
01362 }
01363
01364
01365 sortedKeyPoints.push_back(KeyPoints.at(0));
01366
01367 for (unsigned int i = 1; i < KeyPoints.size(); i++) {
01368
01369 unsigned int j = 0;
01370 bool hasBeenAdded = false;
01371
01372 while ((j < sortedKeyPoints.size()) && (!hasBeenAdded)) {
01373
01374 if (abs(KeyPoints.at(i).response) > abs(sortedKeyPoints.at(j).response)) {
01375 sortedKeyPoints.insert(sortedKeyPoints.begin() + j, KeyPoints.at(i));
01376
01377 hasBeenAdded = true;
01378 }
01379
01380 j++;
01381 }
01382
01383 if (!hasBeenAdded) {
01384 sortedKeyPoints.push_back(KeyPoints.at(i));
01385 }
01386
01387 }
01388
01389
01390
01391 KeyPoints.swap(sortedKeyPoints);
01392
01393 if (maxKeyPoints < KeyPoints.size()) {
01394 KeyPoints.erase(KeyPoints.begin()+maxKeyPoints, KeyPoints.end());
01395 }
01396
01397 return;
01398
01399 }
01400
01401 void sortMatches(vector<vector<cv::DMatch> >& matches1to2) {
01402 vector<vector<cv::DMatch> > matchesCpy, newMatches;
01403
01404 if (matches1to2.size() <= 1) {
01405 return;
01406 }
01407
01408 matchesCpy.assign(matches1to2.begin(), matches1to2.end());
01409
01410 while (matchesCpy.size() > 0) {
01411 double bestDistance = matchesCpy.at(0).at(0).distance;
01412 int bestIndex = 0;
01413
01414 for (unsigned int iii = 0; iii < matchesCpy.size(); iii++) {
01415
01416 if (matchesCpy.at(iii).at(0).distance <= bestDistance) {
01417 bestDistance = matchesCpy.at(iii).at(0).distance;
01418 bestIndex = iii;
01419 }
01420 }
01421
01422 newMatches.push_back(matchesCpy.at(bestIndex));
01423 matchesCpy.erase(matchesCpy.begin() + bestIndex);
01424 }
01425
01426 newMatches.swap(matches1to2);
01427 }
01428
01429 void filterMatches(vector<vector<cv::DMatch> >& matches1to2, double threshold) {
01430
01431 if (matches1to2.size() == 0) {
01432 return;
01433 }
01434
01435 int currIndex = matches1to2.size() - 1;
01436
01437 while (matches1to2.at(currIndex).at(0).distance > threshold) {
01438 currIndex--;
01439
01440 if (currIndex == -1) {
01441 matches1to2.clear();
01442 return;
01443 }
01444 }
01445
01446 if (currIndex < ((int) matches1to2.size() - 1)) {
01447 matches1to2.erase(matches1to2.begin() + currIndex + 1, matches1to2.end());
01448 }
01449
01450
01451 }
01452
01453 double distanceBetweenPoints(const cv::Point2f& pt1, const cv::Point2f& pt2) {
01454 double retVal;
01455
01456 retVal = pow(pow(pt1.x - pt2.x, 2.0) + pow(pt1.y - pt2.y, 2.0), 0.5);
01457
01458 return retVal;
01459
01460 }
01461
01462 double distanceBetweenPoints(const cv::KeyPoint& pt1, const cv::KeyPoint& pt2) {
01463 double retVal;
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474 retVal = pow(pow(pt1.pt.x - pt2.pt.x, 2.0) + pow(pt1.pt.y - pt2.pt.y, 2.0), 0.5);
01475
01476 return retVal;
01477 }
01478
01479 void constrainMatchingMatrix(cv::Mat& matchingMatrix, vector<cv::KeyPoint>& kp1, vector<cv::KeyPoint>& kp2, int distanceConstraint, double sizeConstraint) {
01480
01481
01482
01483 #pragma omp parallel for
01484 for (unsigned int iii = 0; iii < kp1.size(); iii++) {
01485 for (unsigned int jjj = 0; jjj < kp2.size(); jjj++) {
01486
01487
01488 int distanceBetween;
01489
01490 distanceBetween = (int) distanceBetweenPoints(kp1.at(iii), kp2.at(jjj));
01491
01492
01493 if (distanceBetween > distanceConstraint) {
01494 matchingMatrix.at<double>(iii,jjj) = -1;
01495 }
01496
01497
01498
01499 if (sizeConstraint != 0.0) {
01500 if (max(kp1.at(iii).size/kp2.at(jjj).size, kp2.at(jjj).size/kp1.at(iii).size) > (1.00 + sizeConstraint)) {
01501 matchingMatrix.at<double>(iii,jjj) = -1;
01502 }
01503 }
01504
01505 }
01506
01507
01508 }
01509
01510
01511 }
01512
01513 void twoWayPriorityMatching(cv::Mat& matchingMatrix, vector<vector<cv::DMatch> >& bestMatches, int mode) {
01514
01515 bestMatches.clear();
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528 bool rowsStillRemain = false;
01529 int remainingRows = 0;
01530
01531
01532
01533
01534 for (int iii = 0; iii < matchingMatrix.rows; iii++) {
01535 bool anyInThisRow = false;
01536 for (int jjj = 0; jjj < matchingMatrix.cols; jjj++) {
01537 if (matchingMatrix.at<double>(iii,jjj) >= 0) {
01538 rowsStillRemain = true;
01539 anyInThisRow = true;
01540 }
01541 }
01542
01543 if (anyInThisRow) {
01544 remainingRows++;
01545 }
01546
01547 }
01548
01549
01550
01551 while (rowsStillRemain) {
01552
01553 double bestScore = 9e99;
01554 int bestRow = -1, bestCol = -1;
01555
01556 for (int iii = 0; iii < matchingMatrix.rows; iii++) {
01557 for (int jjj = 0; jjj < matchingMatrix.cols; jjj++) {
01558 if ((matchingMatrix.at<double>(iii,jjj) <= bestScore) && (matchingMatrix.at<double>(iii,jjj) >= 0)) {
01559 bestScore = matchingMatrix.at<double>(iii,jjj);
01560 bestRow = iii;
01561 bestCol = jjj;
01562 }
01563 }
01564 }
01565
01566 if ((bestScore < 0) || (bestScore == 9e99)) {
01567 rowsStillRemain = false;
01568 break;
01569 }
01570
01571 matchingMatrix.at<double>(bestRow,bestCol) = -1.0;
01572
01573
01574 cv::DMatch currentMatch;
01575 vector<cv::DMatch> currentMatchVector;
01576
01577 currentMatch.queryIdx = bestRow;
01578 currentMatch.trainIdx = bestCol;
01579
01580 double secondScore = 9e99;
01581
01582
01583 for (int iii = 0; iii < matchingMatrix.rows; iii++) {
01584 if ((matchingMatrix.at<double>(iii,bestCol) <= secondScore) && (matchingMatrix.at<double>(iii,bestCol) >= 0)) {
01585 secondScore = matchingMatrix.at<double>(iii,bestCol);
01586
01587
01588 }
01589 matchingMatrix.at<double>(iii,bestCol) = -1;
01590 }
01591
01592 for (int iii = 0; iii < matchingMatrix.cols; iii++) {
01593 if ((matchingMatrix.at<double>(bestRow,iii) <= secondScore) && (matchingMatrix.at<double>(bestRow,iii) >= 0)) {
01594 secondScore = matchingMatrix.at<double>(bestRow,iii);
01595
01596
01597 }
01598 matchingMatrix.at<double>(bestRow,iii) = -1;
01599 }
01600
01601
01602 if (secondScore == 9e99) {
01603 secondScore = bestScore;
01604 }
01605
01606
01607
01608
01609 if (mode == MATCHING_MODE_NN) {
01610 currentMatch.distance = bestScore;
01611 } else if (mode == MATCHING_MODE_NNDR) {
01612 currentMatch.distance = bestScore / secondScore;
01613 } else if (mode == MATCHING_MODE_SVM) {
01614 double gradient = -1.42;
01615 currentMatch.distance = reweightDistanceWithLinearSVM(bestScore, (bestScore/secondScore), gradient);
01616 } else {
01617 currentMatch.distance = bestScore;
01618 }
01619
01620
01621
01622
01623 currentMatchVector.push_back(currentMatch);
01624 bestMatches.push_back(currentMatchVector);
01625
01626
01627 }
01628
01629
01630
01631
01632 }
01633
01634 double calcDistance(double dist, double ratio, double *coeffs) {
01635 double retVal = 0.0;
01636
01637 retVal = abs(coeffs[0] * dist - ratio + coeffs[2]) / sqrt(pow(coeffs[0], 2) + 1);
01638
01639 return retVal;
01640 }
01641
01642 double reweightDistanceWithLinearSVM(double dist, double ratio, double gradient) {
01643 double retVal = 0.0;
01644
01645 retVal = dist - (1.0 / gradient) * ratio;
01646
01647 return retVal;
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689 }
01690
01691 void createMatchingMatrix(cv::Mat& matchingMatrix, const cv::Mat& desc1, const cv::Mat& desc2) {
01692
01693 vector<vector<cv::DMatch> > matches1to2, matches2to1;
01694
01695 cv::Ptr<cv::DescriptorMatcher> dMatcher;
01696
01697 if (desc1.type() == CV_8UC1) {
01698 dMatcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
01699 } else if ((desc1.type() == CV_64FC1) || (desc1.type() == CV_32FC1)) {
01700 dMatcher = cv::DescriptorMatcher::create("BruteForce");
01701 } else {
01702 printf("%s << ERROR! desc1.type() (%d) unrecognized.\n", __FUNCTION__, desc1.type());
01703 }
01704
01705
01706
01707
01708 dMatcher->knnMatch( desc1, desc2, matches1to2, desc1.rows );
01709 dMatcher->knnMatch( desc2, desc1, matches2to1, desc2.rows );
01710
01711
01712
01713
01714
01715
01716
01717
01718 matchingMatrix = cv::Mat::zeros(matches1to2.size(), matches2to1.size(), CV_64FC1);
01719
01720 cv::Mat countMat = cv::Mat::zeros(matches1to2.size(), matches2to1.size(), CV_64FC1);
01721
01722
01723 for (unsigned int iii = 0; iii < matches1to2.size(); iii++) {
01724 for (unsigned int jjj = 0; jjj < matches1to2[iii].size(); jjj++) {
01725 matchingMatrix.at<double>(iii, matches1to2.at(iii).at(jjj).trainIdx) += matches1to2.at(iii).at(jjj).distance;
01726 countMat.at<double>(iii, matches1to2.at(iii).at(jjj).trainIdx) += 1.0;
01727 }
01728 }
01729
01730
01731 for (unsigned int iii = 0; iii < matches2to1.size(); iii++) {
01732 for (unsigned int jjj = 0; jjj < matches2to1[iii].size(); jjj++) {
01733 matchingMatrix.at<double>(matches2to1.at(iii).at(jjj).trainIdx, iii) += matches2to1.at(iii).at(jjj).distance;
01734 countMat.at<double>(matches2to1.at(iii).at(jjj).trainIdx, iii) += 1.0;
01735 }
01736 }
01737
01738
01739
01740
01741
01742
01743
01744 matchingMatrix /= 2.0;
01745
01746 }
01747
01748 void filterTrackedPoints(vector<uchar>& statusVec, vector<float>& err, double maxError) {
01749
01750 for (unsigned int iii = 0; iii < statusVec.size(); iii++) {
01751 if (err.at(iii) > maxError) {
01752 statusVec.at(iii) = 0;
01753 }
01754 }
01755
01756 }
01757
01758 void randomlyReducePoints(vector<cv::Point2f>& pts, int maxFeatures) {
01759
01760 srand (time(NULL) );
01761
01762 if (((int) pts.size()) <= maxFeatures) {
01763 return;
01764 }
01765
01766 int randIndex;
01767
01768 while (((int) pts.size()) > maxFeatures) {
01769 randIndex = rand() % pts.size();
01770 pts.erase(pts.begin() + randIndex);
01771 }
01772
01773 }
01774
01775 void checkDistances(vector<cv::Point2f>& pts1, vector<cv::Point2f>& pts2, vector<uchar>& statusVec, double distanceConstraint) {
01776
01777 double totalDist, xDist, yDist;
01778
01779 for (unsigned int iii = 0; iii < pts1.size(); iii++) {
01780 xDist = pts1.at(iii).x - pts2.at(iii).x;
01781 yDist = pts1.at(iii).y - pts2.at(iii).y;
01782 totalDist = pow((pow((xDist), 2.0) + pow((yDist), 2.0)), 0.5);
01783
01784 if (totalDist > distanceConstraint) {
01785 statusVec.at(iii) = 0;
01786 }
01787 }
01788
01789 }
01790
01791 void filterVectors(vector<cv::Point2f>& pts1, vector<cv::Point2f>& pts2, vector<uchar>& statusVec, double distanceConstraint, bool epipolarCheck) {
01792
01793 bool debugFlag = false;
01794
01795
01796 double totalDist, xDist, yDist;
01797
01798 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 1); }
01799
01800 for (int iii = statusVec.size()-1; iii >= 0; iii--) {
01801 if (statusVec.at(iii) == 0) {
01802 pts1.erase(pts1.begin() + iii);
01803 pts2.erase(pts2.begin() + iii);
01804 } else {
01805
01806 xDist = pts1.at(iii).x - pts2.at(iii).x;
01807 yDist = pts1.at(iii).y - pts2.at(iii).y;
01808 totalDist = pow((pow((xDist), 2.0) + pow((yDist), 2.0)), 0.5);
01809
01810
01811
01812 if (totalDist > distanceConstraint) {
01813
01814
01815
01816 pts1.erase(pts1.begin() + iii);
01817 pts2.erase(pts2.begin() + iii);
01818 }
01819 }
01820 }
01821
01822 if (debugFlag) { printf("%s << Debug (%d)\n", __FUNCTION__, 2); }
01823
01824
01825
01826
01827
01828 if ((epipolarCheck) && (pts1.size() > 0) && (pts2.size() > 0)) {
01829 cv::Mat F, matchesMask_F_matrix;
01830
01831 if ((pts1.size() > 4) && (pts2.size() > 4)) {
01832 F = findFundamentalMat(cv::Mat(pts1), cv::Mat(pts2), cv::FM_RANSAC, 1.00, 0.99, matchesMask_F_matrix);
01833 if (debugFlag) { printf("%s << Found.\n", __FUNCTION__); }
01834
01835 for (int iii = matchesMask_F_matrix.rows-1; iii >= 0; iii--) {
01836
01837 if (matchesMask_F_matrix.at<unsigned char>(iii,0) == 0) {
01838 pts1.erase(pts1.begin() + iii);
01839 pts2.erase(pts2.begin() + iii);
01840 }
01841 }
01842 } else {
01843 pts1.clear();
01844 pts2.clear();
01845 }
01846
01847
01848 }
01849
01850
01851 }
01852
01853 bool checkSufficientFeatureSpread(vector<cv::Point2f>& pts, cv::Size matSize, int minFeaturesInImage) {
01854
01855 cv::Mat countMat;
01856 int horizontalDivisions = 4, verticalDivisions = 3;
01857 countMat = cv::Mat::zeros(3, 4, CV_16UC1);
01858 int minPerSegment = minFeaturesInImage / (8 * horizontalDivisions * verticalDivisions);
01859
01860
01861
01862 for (unsigned int iii = 0; iii < pts.size(); iii++) {
01863 int r, c;
01864 r = (horizontalDivisions * pts.at(iii).x) / matSize.width;
01865 c = (verticalDivisions * pts.at(iii).y) / matSize.height;
01866 countMat.at<unsigned short>(r, c) += 1;
01867 }
01868
01869 int badSegments = 0;
01870
01871 for (int iii = 0; iii < countMat.rows; iii++) {
01872 for (int jjj = 0; jjj < countMat.cols; jjj++) {
01873 if (countMat.at<unsigned short>(iii, jjj) < minPerSegment) {
01874 badSegments++;
01875 }
01876 }
01877 }
01878
01879
01880
01881 if (badSegments > (horizontalDivisions * verticalDivisions / 2)) {
01882 return false;
01883 }
01884
01885 return true;
01886
01887 }
01888
01889 void drawMatchPaths(cv::Mat& src, cv::Mat& dst, vector<cv::Point2f>& kp1, vector<cv::Point2f>& kp2, const cv::Scalar& color) {
01890
01891 src.copyTo(dst);
01892 cv::Point a, b;
01893
01894 for (unsigned int iii = 0; iii < kp1.size(); iii++) {
01895
01896 a = cv::Point(kp1.at(iii).x * 16.0, kp1.at(iii).y * 16.0);
01897 b = cv::Point(kp2.at(iii).x * 16.0, kp2.at(iii).y * 16.0);
01898
01899 cv::line(dst, a, b, color, 1, CV_AA, 4);
01900
01901
01902
01903 }
01904 }
01905
01906 void drawMatchPaths(cv::Mat& src, cv::Mat& dst, vector<cv::KeyPoint>& kp1, vector<cv::KeyPoint>& kp2, vector<vector<cv::DMatch> >& matches1to2) {
01907
01908 cv::Point a, b;
01909
01910 for (unsigned int iii = 0; iii < matches1to2.size(); iii++) {
01911 for (unsigned int jjj = 0; jjj < matches1to2.at(iii).size(); jjj++) {
01912
01913
01914
01915
01916
01917
01918
01919 a = cv::Point(kp1.at(matches1to2.at(iii).at(jjj).queryIdx).pt.x * 16.0, kp1.at(matches1to2.at(iii).at(jjj).queryIdx).pt.y * 16.0);
01920 b = cv::Point(kp2.at(matches1to2.at(iii).at(jjj).trainIdx).pt.x * 16.0, kp2.at(matches1to2.at(iii).at(jjj).trainIdx).pt.y * 16.0);
01921
01922 line(dst, a, b, CV_RGB(0,0,255), 1, CV_AA, 4);
01923 circle(dst, b, 1, CV_RGB(255, 0, 0), 1, CV_AA, 4);
01924 }
01925 }
01926 }
01927
01928 void markEdgyTracks(vector<cv::Point2f>& pts, vector<uchar>& statusVec, cameraParameters& camData) {
01929
01930 vector<cv::Point2f> rpts;
01931
01932 float minBorderDist = 15.0;
01933
01934
01935 redistortPoints(pts, rpts, camData.Kx, camData.distCoeffs, camData.expandedCamMat);
01936
01937 cv::Mat tmpDisp;
01938
01939 tmpDisp = cv::Mat::zeros(camData.expandedSize, CV_8UC3);
01940
01941 cv::Mat testMat;
01942 displayKeyPoints(tmpDisp, rpts, tmpDisp, CV_RGB(0,255,0), 0);
01943
01944 unsigned int edgyMarks = 0;
01945
01946 float xDist, yDist, dist;
01947
01948 for (int iii = pts.size()-1; iii >= 0; iii--) {
01949
01950 xDist = min(((float) camData.expandedSize.width) - rpts.at(iii).x, rpts.at(iii).x);
01951 yDist = min(((float) camData.expandedSize.height) - rpts.at(iii).y, rpts.at(iii).y);
01952 dist = min(xDist, yDist);
01953
01954 if (dist < minBorderDist) {
01955
01956 if (statusVec.at(iii) != 0) {
01957 edgyMarks++;
01958 }
01959 statusVec.at(iii) = 0;
01960 rpts.erase(rpts.begin() + iii);
01961 }
01962
01963 }
01964
01965 displayKeyPoints(tmpDisp, rpts, tmpDisp, CV_RGB(0,0,255), 0);
01966
01967
01968
01969
01970
01971
01972
01973 }
01974
01975 double estimateStability(cv::Mat& img, cv::Point2f& center, double radius) {
01976 double stability = 0.0;
01977
01978 if (((center.x - radius) < 0) || ((center.y - radius) < 0) || ((center.x + radius) >= img.cols) || ((center.y + radius) >= img.rows)) {
01979
01980 return stability;
01981 }
01982
01983 cv::Mat patch;
01984 constructPatch(img, patch, center, radius, 15);
01985
01986 double minVal, maxVal;
01987 minMaxLoc(patch, &minVal, &maxVal);
01988
01989 double variance = getPatchVariance(patch);
01990
01991 cv::Mat largerMat;
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003 stability = 1 / variance;
02004
02005 return stability;
02006
02007 }
02008
02009 double getPatchVariance(const cv::Mat& patch) {
02010 double mean = 0.0;
02011 double sigma = 0.0;
02012
02013 for (int iii = 0; iii < patch.rows; iii++) {
02014 for (int jjj = 0; jjj < patch.cols; jjj++) {
02015 mean += patch.at<double>(iii,jjj) / ((double) (patch.rows * patch.cols));
02016 }
02017 }
02018
02019 for (int iii = 0; iii < patch.rows; iii++) {
02020 for (int jjj = 0; jjj < patch.cols; jjj++) {
02021
02022 sigma += pow((patch.at<double>(iii,jjj) - mean), 2.0) / ((double) (patch.rows * patch.cols));
02023 }
02024 }
02025
02026 sigma = pow(sigma, 0.5);
02027
02028 return sigma;
02029 }